Получение времени определенной части кода в цикле в C - PullRequest
0 голосов
/ 24 июня 2018

Описание проблемы

Ниже у меня есть программа, которая выполняет две простые операции сложения и умножения. Затем я сохраняю сумму этих двух простых операций в двух соответствующих переменных, называемых total1 и total2. С точки зрения вычислений total2 займет больше времени для полного выполнения. То, как я реализовал код, я сейчас синхронизирую всю симуляцию обеих математических операций.

Вопрос

Можно ли рассчитывать только конечный результат итогового 1 и итогового 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;
}

Ответы [ 2 ]

0 голосов
/ 24 июня 2018

У вас есть две операции, которые вы хотите проводить отдельно. Первое накопление i+i, а второе накопление i*i*i*i.

Я предполагаю, что вы используете GCC на x86-64 с -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

Вместо того, чтобы пытаться микробенчмировать отдельные строки кода, мы можем обратиться к таблицам инструкций Агнера Фога: 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 ГГц для выполнения одного миллиарда итераций цикла потребуется около 1 секунды.

0 голосов
/ 24 июня 2018

Я не уверен, что понимаю вашу проблему, но чтобы рассчитать каждую операцию отдельно, вам просто нужно сделать два отдельных цикла.

#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;
}
...