Я работаю над написанием нескольких DSP-алгоритмов реального времени на Android, поэтому решил запрограммировать ARM прямо на ассемблере, чтобы максимально все оптимизировать и сделать математику максимально облегченной. Сначала я получал тесты скорости, которые не имели особого смысла, поэтому я начал читать об опасностях конвейера, возможностях двойной проблемы и так далее. Меня все еще озадачивают некоторые цифры, которые я получаю, поэтому я размещаю их здесь в надежде, что кто-нибудь сможет пролить свет на то, почему я получаю то, что получаю. В частности, меня интересует, почему NEON занимает разное количество времени для выполнения вычислений с разными типами данных, хотя он утверждает, что выполняет каждую операцию ровно за один цикл. Мои выводы таковы.
Я использую очень простой цикл для бенчмаркинга и запускаю его на 2 000 000 итераций. Вот моя функция:
hzrd_test:
@use received argument an number of iterations in a loop
mov r3 , r0
@come up with some simple values
mov r0, #1
mov r1, #2
@Initialize some NEON registers (Q0-Q11)
vmov.32 d0, r0, r1
vmov.32 d1, r0, r1
vmov.32 d2, r0, r1
...
vmov.32 d21, r0, r1
vmov.32 d22, r0, r1
vmov.32 d23, r0, r1
hzrd_loop:
@do some math
vadd.s32 q0, q0, q1
vadd.s32 q1, q0, q1
vadd.s32 q2, q0, q1
vadd.s32 q3, q0, q1
vadd.s32 q4, q0, q1
vadd.s32 q5, q0, q1
vadd.s32 q6, q0, q1
vadd.s32 q7, q0, q1
vadd.s32 q8, q0, q1
vadd.s32 q9, q0,s q1
vadd.s32 q10, q0, q1
vadd.s32 q11, q0, q1
@decrement loop counter, branch to loop again or return
subs r3, r3, #1
bne hzrd_loop
@return
mov r0, r3
mov pc, lr
Обратите внимание на операцию вычисления и тип данных, указанные как векторное сложение (vadd
) и 32-битное целое число со знаком (s32
). Эта операция завершается в течение определенного времени (см. таблицу результатов ниже). Согласно документу ARM Cortex-A8 и последующим страницам, почти все элементарная арифметическая операция в NEON должна выполняться за один цикл, но вот что я получаю:
vmul.f32 ~62ms vmul.u32 ~125ms vmul.s32 ~125ms vadd.f32 ~63ms vadd.u32 ~29ms vadd.s32 ~30ms
Я делаю их, просто заменяя операции и типы данных всего в приведенном выше цикле. Есть ли причина, по которой vadd.u32
в два раза быстрее, чем vadd.f32
, а vmul.f32
в два раза быстрее, чем vmul.u32
?
Ваше здоровье! знак равно