Я не знаю никакой реальной сборки, но могу прочитать вывод GCC -S
для оценки фактических затрат на данный код C.
Этот вопрос не столько о профилировании и контрольных показателях, сколько об образовании. Мне нужно, чтобы кто-то объяснил мне, почему [1] фрагмент не быстрее второго.
Ну, привык думать: "Да, некоторые операции, такие как MUL, довольно дороги, но если одна сборка в X раз больше другой, она должна быть медленнее".
Это было верно, пока я не встретил этих двух:
unsigned char bytes[4] = {0, 0, 0, 5};
// 1
int32_t val = *((int32_t*)bytes);
/* produces:
leaq -16(%rbp), %rax
movl (%rax), %eax
movl %eax, -4(%rbp)
movl $0, %eax
*/
// 2
val = bytes[3] |
(bytes[2] << 8) |
(bytes[1] << 16) |
(bytes[0] << 24);
/* produces:
movzbl -13(%rbp), %eax
movzbl %al, %eax
movzbl -14(%rbp), %edx
movzbl %dl, %edx
sall $8, %edx
orl %eax, %edx
movzbl -15(%rbp), %eax
movzbl %al, %eax
sall $16, %eax
orl %eax, %edx
movzbl -16(%rbp), %eax
movzbl %al, %eax
sall $24, %eax
orl %edx, %eax
movl %eax, -4(%rbp)
movl $0, %eax
*/
И тесты показывают, что 2-й на 5-10% быстрее. Что здесь происходит?
Единственное существенное различие и "разум", которые я могу себе представить, - это LEAQ
- это что-то очень медленное.
Последние 2 строки идентичны, поэтому, возможно, цена MOV
настолько высока, что 1 дополнительный MOV
хуже, чем тонны инструкций.
Вот что я использовал для измерения времени выполнения:
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#define REPETITIONS 32
#define ITERATIONS 90000
#define CODE1 \
for (int i = 0; i < ITERATIONS; ++i) { \
val = *((int32_t*)bytes); \
}
#define CODE2 \
for (int i = 0; i < ITERATIONS; ++i) { \
val = bytes[3] | \
(bytes[2] << 8) | \
(bytes[1] << 16) | \
(bytes[0] << 24); \
}
int main(void) {
clock_t minTs = 999999999, ts;
unsigned char bytes[4] = {0, 0, 0, 5};
int32_t val;
for (int i = 0; i < REPETITIONS; ++i) {
ts = clock();
CODE1; // Or CODE2
ts = clock() - ts;
if (ts < minTs) minTs = ts;
}
printf("ts: %ld\n", minTs);
return val;
}
Обновить: как оказалось, результаты специфичны для аппаратного обеспечения, поэтому пока [1] работает медленнее на моем ноутбуке (x64 i5-4260U), он быстрее работает на моем ПК (но очень малой фракцией, например 5%).