2015-07-18 5 views
1

Я хотел рассчитать разницу во времени выполнения при выполнении одного и того же кода внутри функции. Однако, к моему удивлению, иногда разница часов равна 0, когда я использую clock()/clock_t для таймера запуска и остановки. Означает ли это, что clock()/clock_t фактически не возвращает количество кликов процессора, затраченного на выполнение задачи?Измерение клещей процессора в C

После небольшого поиска мне показалось, что clock_gettime() возвращает более мелкозернистые результаты. И действительно, да, но вместо этого я получаю некоторое количество nano (?) Секунд. Это дает нам намек на разницу во времени выполнения, но вряд ли точно, насколько точно зависит от количества кликов. Что мне нужно сделать, чтобы это выяснить?

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

#define M_PI_DOUBLE (M_PI * 2) 

void rotatetest(const float *x, const float *c, float *result) { 
    float rotationfraction = *x/*c; 
    *result = M_PI_DOUBLE * rotationfraction; 
} 

int main() { 

    int i; 
    long test_total = 0; 
    int test_count = 1000000; 
    struct timespec test_time_begin; 
    struct timespec test_time_end; 

    float r = 50.f; 
    float c = 2 * M_PI * r; 
    float x = 3.f; 
    float result_inline = 0.f; 
    float result_function = 0.f; 

    for (i = 0; i < test_count; i++) { 
     clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &test_time_begin); 
     float rotationfraction = x/c; 
     result_inline = M_PI_DOUBLE * rotationfraction; 
     clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &test_time_end); 
     test_total += test_time_end.tv_nsec - test_time_begin.tv_nsec; 
    } 

    printf("Inline clocks %li, avg %f (result is %f)\n", test_total, test_total/(float)test_count,result_inline); 

    for (i = 0; i < test_count; i++) { 
     clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &test_time_begin); 
     rotatetest(&x, &c, &result_function); 
     clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &test_time_end); 
     test_total += test_time_end.tv_nsec - test_time_begin.tv_nsec; 
    } 

    printf("Function clocks %li, avg %f (result is %f)\n", test_total, test_total/(float)test_count, result_inline); 

    return 0; 
} 

Я использую GCC версии 4.8.4 на Linux 3.13.0-37-родовое (Linux Mint 16)

+0

Вы должны сообщить нам, какой OS/какой компилятор вы используете (GCC/Linux?). – BrunoLevy

+0

Разница в несколько наносекунд не является значимой, возможно, вы могли бы назвать свою функцию большим количеством раз (1 миллион) и измерить разницу таймингов. – BrunoLevy

+0

Я думаю, что я на самом деле уже, @BrunoLevy. Однако я добавил детали, спасибо. – lash

ответ

0

Прежде всего: Как уже упоминалось в комментариях, синхронизация одного хода выполнения одной за другой, вероятно, не принесет вам пользы. Если все спустится с холма, вызов для получения времени может занять больше времени, чем фактическое выполнение операции.

Пожалуйста, выполните несколько прогонов операции (включая фазу прогрева, чтобы все было заменено) и рассчитайте среднее время работы.

clock() не гарантирует монотонность. Это также не число процессорных кликов (независимо от того, что вы определяете это) программа запустилась. Лучший способ описать результат от clock(), вероятно, «- лучшая оценка усилия того времени, когда любой из ЦП потратил на расчет для текущего процесса». Для целей бенчмаркинга clock(), таким образом, в основном бесполезен.

Как per specification:

clock() функция возвращает наилучшее приближение об осуществлении к тому времени процессора, используемому в процессе с самого начала времени, зависящей от реализации, связанного только с процессом вызова.

И дополнительно

Для определения времени в секундах, возвращаемое значение по часам() должны быть разделены на величину макро CLOCKS_PER_SEC.

Итак, если вы звоните clock() чаще, чем разрешение, вам не повезло.

Для профилирования/бенчмаркинга вы должны --if возможно - использовать один из часов исполнения, доступных на современном оборудовании.Премьер-кандидаты, вероятно

Edit: Вопрос теперь ссылается CLOCK_PROCESS_CPUTIME_ID, который является способом Linux»разоблачения TSC.

Если какой-либо (или оба) доступны, зависит от аппаратного обеспечения, а также от конкретной операционной системы.

+0

Я предположил, что одним щелчком процессора будет, например, время, необходимое для выполнения инструкции по сборке «с EAX», но из чего вы указываете выше, я считаю, это не так просто? И как бы вы предложили мне проверить, доступен ли TSC через мой clock_gettime() с CLOCK_PROCESS_CPUTIME_ID? – lash

+1

На современном процессоре CISC может потребоваться множество «щелчков процессора», чтобы выполнить что-то вроде inc EAX, и он может выполнять множество инструкций EAX параллельно, поэтому в зависимости от того, что еще происходит, результаты будут меняться каждый раз, когда вы его запускаете. – Cobusve

+1

@lash: ['clock_getcpuclockid (pid, CLOCK_PROCESS_CPUTIME_ID)'] (http://man7.org/linux/man-pages/man3/clock_getcpuclockid.3.html) возвращает ненулевое значение, когда часы доступны. Я также не уверен, что если бы счетчик тиков действительно был бы полезен в современных многоядерных средах. Файловая страница Linux даже предупреждает, что в многопроцессорных средах значение часов может быть фиктивным. Кроме того, современные (и особенно многоядерные) процессоры не выполняют планирование заказа и имеют динамическую задержку команд, поэтому * 'inc% eax' принимает галочку *. – dhke

0

После прибегая к помощи немного я могу видеть, что функции часов() может быть использован в качестве стандартного механизма, чтобы найти фолиант, необходимое для исполнения, но имейте в виду, что время будет разной в разное время в зависимости от нагрузки процессора, Вы можете просто использовать приведенный ниже код для расчета

clock_t begin, end; 
double time_spent; 

begin = clock(); 
/* here, do your time-consuming job */ 
end = clock(); 
time_spent = (double)(end - begin)/CLOCKS_PER_SEC;