12

我意识到这个问题不可能绝对回答,但我只是在了解大致数字:

给定一个合理大小的 C 程序(数千行代码),平均会生成多少条 ASM 指令。换句话说,现实的 C 与 ASM 指令比率是多少?随意做出假设,例如“使用当前的 x86 架构”。

我试图谷歌这件事,但我找不到任何东西。

附录:注意到这个问题带来了多少混乱,我觉得需要解释一下:我想通过这个答案知道,实际上是知道“3GHz”是什么意思。我完全清楚每赫兹的吞吐量因架构、硬件、缓存、总线速度和月球位置而有很大差异。

我不是在追求一个精确和科学的答案,而是一个可以放入可理解的尺度的经验答案。

这不是一个简单的地方答案(正如我注意到的那样),这是我最大的努力。我知道每行 C 的 ASM 结果行的数量取决于您在做什么。与- 我知道这i++一点不在同一个街区。sqrt(23.1)此外,无论我从 C 中得到什么 ASM,ASM 都会被解释为处理器内的各种微码集,这又取决于您运行的是 AMD、Intel 还是其他东西,以及它们各自的世代。我也知道这一点。

到目前为止,我得到的大致答案是我一直在追求的:一个足够大的项目平均每 1 行 ANSI-C 大约 2 行 x86 ASM。一旦流水线被填满并且给定足够大的样本,今天的处理器可能平均每个时钟周期大约有一个 ASM 命令。

4

8 回答 8

22

没有答案是可能的。像这样的语句int a;可能需要零个 asm 行。while 之类的语句a = call_is_inlined();可能需要 20 多行 asm 行。

您可以通过编译 ac 程序,然后启动objdump -Sd ./a.out. 它将混合显示 asm 和 C 代码,因此您可以看到为一条 C 行生成了多少 asm 行。例子:

测试.c

int get_int(int c);
int main(void) {
    int a = 1, b = 2;
    return getCode(a) + b;
}

$gcc -c -g test.c

$objdump -Sd ./test.o

00000000 <main>:
int get_int(int c);
int main(void) { /* here, the prologue creates the frame for main */
   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 f0                and    $0xfffffff0,%esp
   7:   ff 71 fc                pushl  -0x4(%ecx)
   a:   55                      push   %ebp
   b:   89 e5                   mov    %esp,%ebp
   d:   51                      push   %ecx
   e:   83 ec 14                sub    $0x14,%esp
    int a = 1, b = 2; /* setting up space for locals */
  11:   c7 45 f4 01 00 00 00    movl   $0x1,-0xc(%ebp)
  18:   c7 45 f8 02 00 00 00    movl   $0x2,-0x8(%ebp)
    return getCode(a) + b;
  1f:   8b 45 f4                mov    -0xc(%ebp),%eax
  22:   89 04 24                mov    %eax,(%esp)
  25:   e8 fc ff ff ff          call   26 <main+0x26>
  2a:   03 45 f8                add    -0x8(%ebp),%eax
} /* the epilogue runs, returning to the previous frame */
  2d:   83 c4 14                add    $0x14,%esp
  30:   59                      pop    %ecx
  31:   5d                      pop    %ebp
  32:   8d 61 fc                lea    -0x4(%ecx),%esp
  35:   c3                      ret
于 2008-12-01T17:04:48.423 回答
12

我不确定您所说的“C指令”是什么意思,也许是语句或行?当然,这会因多种因素而有很大差异,但是在查看了我自己的几个示例程序后,其中许多都接近 2-1 标记(每个 LOC 2 个汇编指令),我不知道这是什么意味着或如何可能有用。

gcc -S您可以通过要求编译器仅生成程序集(例如)或在已编译的可执行文件上使用反汇编程序(但无论如何您都需要源代码来比较它)来为任何特定的程序和实现组合自己弄清楚这一点) .

编辑

只是根据您对要完成的工作的澄清(了解现代处理器在一秒钟内可以执行多少行代码)对此进行扩展:

虽然现代处理器每秒可以运行 30 亿个周期,但这并不意味着它每秒可以执行 30 亿条指令。这里有一些要考虑的事情:

  • 许多指令需要多个周期才能执行(除法或浮点运算可能需要数十个周期才能执行)。
  • 大多数程序大部分时间都在等待内存访问、磁盘访问等。
  • 许多其他因素,包括操作系统开销(调度、系统调用等)也是限制因素。

但总的来说是的,处理器速度非常快,可以在短时间内完成惊人的事情。

于 2008-12-01T17:05:46.037 回答
4

那变化很大!如果他们试图提供粗略的转换,我不会相信任何人。

像这样的语句i++;可以翻译成一个INC AX.

包含许多参数的函数调用语句可以是数十条指令,因为堆栈是为调用设置的。

然后在那里添加编译器优化,它将以不同于您编写代码的方式组装您的代码,从而消除指令。

此外,一些指令在机器字边界上运行得更好,因此NOPs 将贯穿您的代码。

于 2008-12-01T17:00:17.170 回答
3

我认为您无法从您在这里尝试做的事情中得出任何关于实际应用程序性能的有用结论。除非“不精确”是指“在几个数量级之内”。

您只是过于笼统,并且您正在忽略缓存等,就好像它是次要的,而它很可能完全占主导地位。

如果您的应用程序足够大,以至于每个 loc 有一些平均指令,那么它也将足够大,可以考虑 I/O 或至少重要的 RAM 访问问题。

于 2008-12-01T18:37:05.540 回答
2

根据您的环境,您可以使用 Visual Studio 选项:/FAs

更多在这里

于 2008-12-01T18:08:29.247 回答
1

我不确定这是否真的有一个有用的答案。当然,您将不得不选择架构(如您所建议的那样)。

我会做什么:采用大小合理的 C 程序。给 gcc “-S” 选项并检查自己。它将生成汇编源代码,您可以自己计算该程序的比率。

于 2008-12-01T17:02:44.217 回答
1

RISC还是CISC?无论如何,C 中的指令是什么?

也就是说,在您非常具体地了解您正在使用的代码类型之前,您真的不知道以上几点。

您可以尝试查看有关装配优化和过去 30-40 年发生的硬件/软件干扰串扰的学术文献。在那里你可以找到一些关于你感兴趣的真实数据。(尽管我警告你,你最终可能会看到 C->PDP 数据而不是 C->IA-32 数据)。

于 2008-12-01T19:04:38.120 回答
1

您在其中一条评论中写道,您想知道 3GHz 是什么意思。

甚至 CPU 的频率也无所谓。现代 PC-CPU 大量交错和调度指令,它们获取和预取、缓存内存和指令,并且通常该缓存无效并被扔进垃圾箱。通过运行真实世界的性能基准,可以获得对处理能力的最佳解释。

于 2011-08-09T06:21:51.940 回答