2014-02-01 4 views
0

Я решил сделать тест, чтобы проверить, насколько быстро каждый тип C99, из любопытства.Почему int16 + int16 быстрее, чем int16 + int8?

Мой тест создает массив следующей структуры:

typedef struct 
{ 
    int x; 
    int y; 
    short spdx; 
    short spdy; 
    unsigned char type; 
} defaultTypes; 

Тогда я эта операция на все структуры, несколько раз, чтобы имитировать цикл обновления игры:

while(counter < ARRAY_MAX) 
{ 
    fastStruct[counter].x+=fastStruct[counter].spdx; 
    fastStruct[counter].y+=fastStruct[counter].spdy; 
    ++counter; 
} 

Я пытался несколько типов, таких как int_fast8_t и double.

Позже я решил проверить, что если бы я сделал переменную «spdx» больше? Поэтому я сделал версию, в которой переменные position (x, y) и скорости (spdx, spdy) являются int16_t

К моему удивлению, это СЛАБЫЕ, но только СЛИШКОМ быстрее, чем версия int16_t + int8_t, это было На 11% быстрее, чтобы быть более точным (сравнивается, например, с удвоениями, которые выполняют четверть скорости версии int16_t + int16_t).

Для большинства других отличий в скорости (поплавки медленнее, большие переменные медленнее и т. Д.) Я думаю, что знаю причины, но я не знаю, почему большая структура (16, 16, 16, 16, 8) БЫСТРО, чем меньшая (даже с отступом, 16, 16, 8, 8, 8).

Таким образом, почему int16_t + = int16_t на 11% быстрее, чем int16_t + = int8_t? Кто-то предположил, что это связано с целым продвижением, но я не уверен в этом.

Важное примечание (похоже, это влияет на результаты): Я скомпилировал это с помощью MingW, настроил 32-разрядный и работал на 64-разрядном бите x86 (я запускал только один раз, когда тестовый таргетинг был 64-разрядным, уверенный в своих результатах, но разрыв в производительности, по-видимому, составляет 2% вместо 11%)

+0

Можете ли вы выполнить разницу сгенерированного кода (например, сборку)? – cnicutar

+0

Любой рекомендованный инструмент, чтобы попробовать это? – speeder

+0

Вы можете получить 'gcc' для вывода сборки с использованием -S. Вы также можете использовать 'objdump', чтобы разобрать эльфа. – cnicutar

ответ

0

Я думаю, что ответ связан с тем, что ваши переменные подписаны. Для двух (подписанных) переменных с одним и тем же типом процессор может добавить их с помощью собственной инструкции. Однако, когда типы различны, даже самые разные, он должен преобразовывать один в другой. Это может поддерживаться или не поддерживаться аппаратными средствами, но это все же необходимый шаг. Подумайте, был ли ваш int16 равен 256, а ваш int8 был -1. Вы ожидали бы вернуть значение int16 257. Если бы процессор просто добавил битовые шаблоны вместе, то вы получили бы что-то совсем другое, потому что 8-битное представление -1 не совпадает с 16-битным представлением -1. Сначала он должен преобразовать 8-битное число в 16-битное число, а затем добавить их вместе.

Это то, что подразумевается под «целым продвижением»: компилятор распознает, что вары имеют разные типы и использует соответствующий код сборки для преобразования. Он «продвигает» int8 до int16 перед выполнением операции добавления.

Держу пари, если вы изменили их на неподписанные, разница в скорости исчезнет.

Смежные вопросы