私は Android でいくつかのリアルタイム DSP アルゴリズムを作成する作業を行っているため、可能な限りすべてを最適化し、数学を最大限に軽量化するために、ARM をアセンブリで直接プログラムすることにしました。最初はあまり意味のない速度ベンチマークを取得していたので、パイプラインの危険性や二重発行機能などについて読み始めました。取得している数字のいくつかにまだ困惑しているので、誰かが私が取得した理由を明らかにしてくれることを期待してここに投稿しています. 特に、NEON が各操作を正確に 1 サイクルで実行すると主張しているにもかかわらず、異なるデータ型で計算を実行するのに異なる時間がかかる理由に興味があります。私の調査結果は次のとおりです。
私はベンチマークに非常に単純なループを使用しており、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
vector add ( vadd
) および signed 32-bit int ( s32
) として指定された計算操作とデータ型に注目してください。この操作は一定時間内に完了します (以下の結果表を参照)。この ARM Cortex-A8 ドキュメントと次のページによると、NEON のほとんどすべての基本的な算術演算は 1 サイクルで完了するはずですが、私が得ているものは次のとおりです。
vmul.f32 ~62ms vmul.u32 ~125ms vmul.s32 ~125ms vadd.f32 ~63ms vadd.u32 ~29ms vadd.s32 ~30ms
上記のループ内のすべての操作とデータ型を単純に置き換えることで、それらを実行します。よりも 2 倍速く、よりvadd.u32
2 倍速い理由はありvadd.f32
ますか?vmul.f32
vmul.u32
乾杯!= )