Скорость печати ()
Я немного повеселился на языке Си с библиотекой time.h, пытаясь измерить количество тактов некоторых основных функций, просто чтобы выяснить, насколько они быстрыми на самом деле. Я использовал функцию clock(). В этом случае я измерял функцию printf().
Посмотрите на мою программу:
#include <stdio.h>
#include <time.h>
void main()
{
const int LIMIT = 2000;
const int LOOP = 20;
int results[LOOP];
for(int i=0; i<LOOP; i++)
{
int j;
clock_t time01 = clock();
for(j=1; j<LIMIT; j++)
{
printf("a");
}
clock_t time02 = clock();
results[i] = (int) (time02 - time01);
}
for(int i=0; i<LOOP; i++)
{
printf("\nCLOCK TIME: %d.", results[i]);
}
getchar();
}
Программа просто в 20 раз превышает количество тактов в 2000 раз, называемое функцией printf("a").
Странная вещь, которую я не понимаю, это результат. Я получаю большую часть времени, даже когда делаю другие тесты, случайным образом две группы результатов:
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 31.
CLOCK TIME: 47.
CLOCK TIME: 31.
Я не понимаю, как именно компилятор обрабатывает эту функцию. Я полагаю, что есть некоторый тест для символа %, но это не будет иметь значения. Больше похоже на то, что компилятор что-то делает в памяти... (?) Кто-нибудь знает точный фон компиляции этого кода или почему появляется такое различие, упомянутое выше? Или хотя бы какая-нибудь ссылка, которая мне поможет?
Спасибо.
3 ответа
Я могу придумать как минимум две возможные причины:
- Ваши часы имеют ограниченное разрешение.
printf
иногда будет очищать свой буфер.
Некоторые компиляторы (в частности, последние версии gcc
в последних дистрибутивах Linux при оптимизации с -O2
) умеют оптимизировать printf("a")
в коде очень похож на putchar(
)
Но большую часть времени проводит в ядре, делая write
системный вызов.
Справочная страница clock
сказал, что это возвращает
аппроксимация времени процессора, используемого программой
Это приближение основано на известном счетчике меток времени. Как говорится в википедии:
Подсчитывает количество циклов с момента сброса
К сожалению, в настоящее время этот счетчик может варьироваться между ядрами.
Не ожидается, что счетчики меток времени нескольких процессоров на одной материнской плате будут синхронизированы.
Так что будьте осторожны, чтобы заблокировать ваш код на определенном процессоре, иначе вы будете продолжать получать странные результаты. И так как вы, кажется, ищете точные результаты, вы можете использовать этот код вместо clock
вызов:
uint64_t rdtsc(void) {
uint32_t lo, hi;
__asm__ __volatile__ ( // serialize
"xorl %%eax,%%eax \n cpuid"
::: "%rax", "%rbx", "%rcx", "%rdx");
/* We cannot use "=A", since this would use %rax on x86_64 and return only the lower 32bits of the TSC */
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}