Я работаю над написанием нескольких алгоритмов 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-битное int со знаком ( 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
?
Ура! =)