【问题标题】:Getting the Timing of a Specific Part of Code in a Loop in C在 C 中的循环中获取特定代码部分的时序
【发布时间】:2018-12-03 04:35:10
【问题描述】:

问题描述

下面我有一个程序正在执行两个简单的加法和乘法运算。然后,我将这两个简单操作的总和存储在两个分别称为 total1 和 total2 的变量中。就计算而言,total2 将需要更多时间才能完全执行。按照我实现代码的方式,我目前正在对两个数学运算的整个模拟进行计时。

问题

是否可以单独计算 total1 和 total 2 的最终结果?我这样问是因为我希望以单独的方式获得 total1 和 total2 的具体时间。

任务目的

我完全意识到 long long 对内存来说是昂贵的,并且不是节省内存的最有效方法。此代码和问题的唯一目的是计时而不是代码优化。

C 代码

#include <stdio.h>
#include <time.h>

int main()
{

     long long total1 = 0, total2 = 0, i = 0;
     double simulation_time = 0;

     clock_t Start = clock();

     do
     {
          total1 += i + i; 
          total2 += i * i * i * i; 

          i++;

     } while (i < 1000000000);

     clock_t End = clock();

     printf("Total 1 = %u \n", total1);
     printf("Total 2 = %u \n", total2);

     simulation_time = (double)(End - Start) / CLOCKS_PER_SEC;
     printf("Runtime of Whole Simulation using clock_t: %f\n", simulation_time);


     return 0;
}

【问题讨论】:

  • 当在 Visual Studio 中查看此内容时,调试器告诉我所有变量都已被优化掉,所以请使用 no memory。只注册。 total1 += i + i; 的代码变成了一个单一的操作 lea rdi,[rdi+rbx*2] ,英特尔的手册可以告诉你在 PC 上只需要几分之一纳秒。你真的需要更仔细地衡量这个吗?

标签: c time do-while clock time.h


【解决方案1】:

您有两个想要分别计时的操作。第一个是i+i的积累,第二个是i*i*i*i的积累。

我假设您在 x86-64 上使用 GCC 和 -O2

如果我们注释掉total2,那么计算total1的生成程序集是:

  movabs rdx, 999999999000000000

聪明的编译器!它在编译时完成整个计算。所以那所花费的时间基本上是零。

如果我们改为注释掉 total1,则循环计算 total2 的程序集是:

.L2:
  mov rdx, rax
  imul rdx, rax       ; i squared
  add rax, 1
  imul rdx, rdx       ; i squared squared
  add rsi, rdx        ; accumulate
  cmp rax, 1000000000 ; loop condition
  jne .L2

与其尝试对单行代码进行微基准测试,我们可以参考 Agner Fog 的指令表:http://www.agner.org/optimize/instruction_tables.pdf

假设您使用的是 Intel Haswell,并手动进行了一些端口分配,表格告诉我们:

.L2:                  ; ports  cycles  latency
  mov rdx, rax        ; p0     0.25    1
  imul rdx, rax       ; p1     1       3
  add rax, 1          ; p0     0.25    1
  imul rdx, rdx       ; p1     1       3
  add rsi, rdx        ; p0     0.25    1
  cmp rax, 1000000000 ; p5     0.25    1
  jne .L2             ; p6     1-2

其中一些指令可能会重叠,因此每次迭代大约需要 3-4 个核心周期。在 3-4 GHz 处理器上,执行 10 亿次循环迭代大约需要 1 秒。

【讨论】:

    【解决方案2】:

    我不确定我是否理解您的问题,但要分别为每个操作计时,您只需创建两个单独的循环。

    #include <stdio.h>
    #include <time.h>
    
    int main()
    {
        long long total1 = 0, total2 = 0, i = 0, j = 1000000000;
        double simulation_time1, simulation_time2;
        clock_t Start, End;
    
        /* addition */
        Start = clock();
        do
        {
             total1 += i + i;
             i++;
        } while (i < j);
        End = clock();
        simulation_time1 = (double)(End - Start) / CLOCKS_PER_SEC;
    
        /* multiplication */
        Start = clock();
        do
        {
             total2 += i * i * i * i;
             i++;
        } while (i < j);
        End = clock();
        simulation_time2 = (double)(End - Start) / CLOCKS_PER_SEC;
    
        printf("Total 1 = %u \n", total1);
        printf("Total 2 = %u \n", total2);
        printf("Runtime of Whole Simulation: %f\n"
            "Runtime of Addition:         %f\n"
            "Runtime of Multiplication:   %f\n",
            simulation_time1 + simulation_time2,
            simulation_time1, simulation_time2);
    
        return 0;
    }
    

    【讨论】:

    • 这里的一个问题是(在第二个循环之前添加i = 0 之后)我得到Addition 0.23Multiplication 0.68。但在原始代码中,我总共得到0.68。那么我们测量的是什么?提示:在具有多个执行单元的 PC 上,add 和 mul 可能会并行执行。
    猜你喜欢
    • 2021-12-17
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2020-06-10
    相关资源
    最近更新 更多