Использование rdtsc() в моей программе для получения количества тактов для операций с одним и двумя словами?
Теоретически стоимость сложения / вычитания двойного слова берется 2 раза за одно слово. Аналогично, соотношение затрат умножения одного слова к сложению принимается равным 3. Я написал следующую программу на C, использующую GCC на Ubuntu LTS 14.04, для проверки количества тактов на моей машине, Intel Sandy Bridge Corei5-2410M. Хотя в большинстве случаев программа возвращает 6 тактов для 128-битного сложения, но я выбрал лучший вариант. Я скомпилировал с помощью команды (gcc -o ow -O3 cost.c), и результат приведен ниже
32-bit Add: Clock cycles = 1 64-bit Add: Clock cycles = 1 64-bit Mult: Clock cycles = 2 128-bit Add: Clock cycles = 5
Программа выглядит следующим образом:
#define n 500
#define counter 50000
typedef uint64_t utype64;
typedef int64_t type64;
typedef __int128 type128;
__inline__ utype64 rdtsc() {
uint32_t lo, hi;
__asm__ __volatile__ ("xorl %%eax,%%eax \n cpuid"::: "%rax", "%rbx", "%rcx", "%rdx");
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (utype64)hi << 32 | lo;
}
int main(){
utype64 start, end;
type64 a[n], b[n], c[n];
type128 d[n], e[n], f[n];
int g[n], h[n];
unsigned short i, j;
srand(time(NULL));
for(i=0;i<n;i++){ g[i]=rand(); h[i]=rand(); b[i]=(rand()+2294967295); e[i]=(type128)(rand()+2294967295)*(rand()+2294967295);}
for(j=0;j<counter;j++){
start=rdtsc();
for(i=0;i<n;i++){ a[i]=(type64)g[i]+h[i]; }
end=rdtsc();
if((j+1)%5000 == 0)
printf("%lu-bit Add: Clock cycles = %lu \t", sizeof(g[0])*8, (end-start)/n);
start=rdtsc();
for(i=0;i<n;i++){ c[i]=a[i]+b[i]; }
end=rdtsc();
if((j+1)%5000 == 0)
printf("%lu-bit Add: Clock cycles = %lu \t", sizeof(a[0])*8, (end-start)/n);
start=rdtsc();
for(i=0;i<n;i++){ d[i]=(type128)c[i]*b[i]; }
end=rdtsc();
if((j+1)%5000 == 0)
printf("%lu-bit Mult: Clock cycles = %lu \t", sizeof(c[0])*8, (end-start)/n);
start=rdtsc();
for(i=0;i<n;i++){ f[i]=d[i]+e[i]; }
end=rdtsc();
if((j+1)%5000 == 0){
printf("%lu-bit Add: Clock cycles = %lu \n", sizeof(d[0])*8, (end-start)/n);
printf("f[%hu]= %ld %ld \n\n", i-7, (type64)(f[i-7]>>64), (type64)(f[i-7]));}
}
return 0;
}
В результате есть две вещи, которые меня беспокоят.
1) Может ли количество тактов для (64-битного) умножения стать 2?
2) Почему количество тактов для добавления двойных слов более чем в 2 раза превышает сложение отдельных слов?
Я в основном обеспокоен делом (2). Теперь возникает вопрос, что это из-за логики моей программы? Или это из-за оптимизации компилятора GCC?
1 ответ
Теоретически мы знаем, что сложение / вычитание двойного слова занимает 2 раза одного слова.
Нет, мы не
Аналогично, соотношение затрат умножения одного слова к сложению принимается равным 3 из-за быстрого целочисленного умножения ЦП.
Нет, это не так.
Вы не измеряете инструкции. Вы измеряете утверждения в своей программе. Которые могут иметь или не иметь никакого отношения к инструкциям вашего компилятора. Мой компилятор, например, после исправления вашего кода, чтобы он компилировался, векторизовал некоторые циклы. Добавление нескольких значений в инструкции. Длина первого цикла по-прежнему составляет 23 инструкции, и ваш код все равно сообщает о 1 цикле.
Современные (как и в последние 25 лет) процессоры не выполняют одну инструкцию за раз. Они будут иметь несколько инструкций в полете одновременно и могут выполнить их не по порядку.
Тогда у вас есть доступ к памяти. На вашем процессоре нет инструкций, которые могут взять значение из памяти, добавить его к другому значению из памяти и затем сохранить его в третьей ячейке памяти. Поэтому должно быть выполнено несколько инструкций. Кроме того, доступ к памяти стоит намного дороже, чем арифметические инструкции, что все, что касается памяти (если оно не попадает в кэш L1 все время), будет зависеть от времени доступа к памяти.
Кроме того, RDTSC может даже не возвращать фактическое количество циклов. Некоторые ЦП имеют переменную тактовую частоту, но при этом TSC продолжают работать с одинаковой частотой, независимо от того, насколько быстрым или медленным является ЦП, потому что TSC используется операционной системой для отсчета времени. Другие нет.
Таким образом, вы не измеряете то, что, по вашему мнению, измеряете, и тот, кто сказал вам, что эти вещи либо сильно упрощали, либо не видел документации по ЦП в течение двух десятилетий.