※ 이 글은 오가사와라 히로유키(小笠原博之) 씨가 블로그에 적은 글을 번역한 것입니다. 사정에 따라 예고없이 삭제될 수 있으므로 양해부탁드립니다.
Nexus 10 CPU Cortex-A15의 부동소수점 연산속도
(원문 : 3DMark Android 版の結果から)
Nexus10을 입수하여 ARMv7A의 새로운 CPU core 3종류가 갖춰졌기에 Apple Swift, Qualcomm Krait, ARM Cortex-A15를 비교해보겠습니다. 동작 클럭이 가장 높다는 것도 있지만, Cortex-A15의 동작은 Swift보다도 고속이었습니다.
(1) (2) (3) (4) (5) (6) (7) iPad3 Nexus7 EVO 3D iPhone5 iPad4 HTL21 Nexus10 A5X Tegra3 MSM8660 A6 A6X APQ8064 Exynos5D ARM A9 ARM A9 Scorpion Swift Swift Krait ARM A15 1.0GHz 1.2GHz 1.2GHz 1.3GHz? 1.4GHz? 1.5GHz 1.7GHz VFPv3 VFPv3 VFPv3 VFPv4 VFPv4 VFPv4 VFPv4 ---------------------------------------------------------------------- a:m44 vmla_AQ 4.784 3.959 2.859 1.293 1.204 1.337 0.619 b:m44 vmla_BQ 2.408 2.002 1.136 1.359 1.266 0.931 0.569 c:m44 vmla_AD 4.781 3.980 3.053 1.669 1.554 1.889 0.557 d:m44 vmla_BD 2.406 2.003 1.434 1.329 1.238 1.532 0.568 A:m44 vfma_AQ ----- ----- ----- 1.632 1.519 1.882 0.746 B:m44 vfma_BQ ----- ----- ----- 1.594 1.484 0.695 0.840 e:fadds A 4.010 3.343 3.383 3.090 2.878 2.774 2.383 f:fmuls A 4.010 3.337 3.383 3.167 2.953 2.747 2.369 g:fmacs A 4.012 3.337 3.379 6.180 5.757 5.574 2.956 h:vfma.f32 A ----- ----- ----- 6.180 5.756 2.747 2.957 i:vadd.f32 DA 4.111 3.426 3.377 3.091 2.877 2.762 1.183 j:vmul.f32 DA 4.110 3.421 3.383 3.168 2.950 2.746 1.478 k:vmla.f32 DA 4.512 3.792 3.380 3.166 2.951 5.604 1.480 l:vadd.f32 QA 8.023 6.688 3.377 3.090 2.878 2.801 2.365 m:vmul.f32 QA 8.022 6.681 3.384 3.166 2.952 2.761 2.364 n:vmla.f32 QA 8.025 6.681 3.380 3.167 2.950 5.606 2.367 o:vfma.f32 DA ----- ----- ----- 3.167 2.494 2.833 1.479 p:fadds B 4.014 3.347 5.917 6.181 5.756 3.467 2.956 q:fmuls B 5.013 4.195 5.917 6.180 5.756 3.556 3.558 r:fmacs B 8.023 6.688 8.451 12.361 11.514 6.298 5.912 s:vfma.f32 B ----- ----- ----- 12.363 11.513 3.430 5.910 t:vadd.f32 DB 4.113 3.421 5.916 3.090 2.881 3.529 2.958 u:vmul.f32 DB 4.118 3.422 5.073 3.169 2.949 3.447 2.364 v:vmla.f32 DB 9.027 7.561 8.451 6.180 5.755 6.293 4.728 w:vadd.f32 QB 8.021 6.705 5.916 3.090 2.879 3.457 2.961 x:vmul.f32 QB 8.029 6.683 5.074 3.167 2.950 3.428 2.363 y:vmla.f32 QB 9.026 7.532 8.457 6.179 5.759 6.372 4.729 z:vfma.f32 DB ----- ----- ----- 6.181 5.755 3.437 4.730 ---------------------------------------------------------------------- ↑수치는 실행시간(초) 수치가 작을 수록 빠름 (1)=Apple iPad 3 A5X Cortex-A9 x2 1.0GHz VFPv3 i6.1 (2)=ASUS Nexus 7 Tegra 3 Cortex-A9 x4 1.2GHz VFPv3 A4.2 (3)=HTC EVO 3D ISW12HT MSM8660 Scorpion x2 1.2GHz VFPv3 A4.0 (4)=Apple iPhone 5 A6 Swift x2 1.3GHz? VFPv4 i6.1 (5)=Apple iPad 4 A6X Swift x2 1.4GHz? VFPv4 i6.1 (6)=HTC J butterfly HTL21 APQ8064 Krait x4 1.5GHz VFPv4 A4.1 (7)=Samsung Nexus 10 Exynos5D Cortex-A15 x2 1.7GHz VFPv4 A4.2
테스트 항목에 대한 자세한 내용은 아래를 참조(a:~z:)
iPad4/EVO 3D/Butterfly는 다시 측정해서 예전보다 수치가 올라가있습니다.
a:~d: 를 보면, 1.7GHz의 Cortex-A15는 Swift의 2배 가까운 수치입니다. 명령 단독으로도 효율이 올라가, Krait와 비교해도 64bit D(float2) 명령의 속도차는 클럭의 차이 이상입니다.
64bit D(float2)와 128bit Q(float4)에 차이가 있는 것을 보면, 아마도 Cortex-A15은 64bit 단위의 ALU가 2 파이프 존재하고 있는게 아닐까 합니다. 128bit Q(float4)의 속도는 Swift/Krait와 큰 차이가 없으므로 연산능력의 피크 속도 자체는 Swift/Krait와 동일한 듯 합니다. D, Q의 차가 없는 Scorpion/Swift/Krait는 128bit 단위라 생각할 수 있습니다.
(1)~(3) Cortex-A9/Scorpion의 a:~d:에서는 AQ/AD와 BQ/BD의 결과에 큰 차이가 납니다. 이것이 CPU 세대간의 차이로, (4)~(7)의 Swift/Krait/Cortex-A15에서는 명령순에 의존하지 않고 일정한 효율로 실행되고 있음을 알 수 있습니다.
이전에도 적었던 대로 Swift는 스칼라의 덧곱셈 명령만 느립니다. NEON의 벡터에서는 덧곱셈이라도 딱히 속도가 떨어지진 않으므로, 무언가 구조적인 이유에 의한 것이라 생각됩니다. 1
마찬가지로 Krait에도 귀찮은 패턴이 있습니다. ARM에서는 VFPv4 이후 FMA(Fused Multiply add) 명령이 추가되었습니다. Krait는 vfma(FMA)보다도 종래의 vmla 명령이 2배 가까이 느립니다. 반올림처리할 vmul + vadd 2로 전개될 가능성이 있습니다. 3
Krait 최적화
a:~d: 의 연산은 vmla를 사용하지만, Krait에서는 이 명령이 느립니다. vfma 4로 바꿈으로서 고속화할 가능성이 있기에 시험해봤습니다. 5
// A: mat44 neon_AQ의 vfma화 vmul.f32 q8, q0, d8[0] vlma.f32 q8, q1, d8[1] vlma.f32 q8, q2, d9[0] vlma.f32 q8, q3, d9[1] : ↓ vmul.f32 q8, q0, d8[0] vdup.f32 q9, d8[1] vfma.f32 q8, q1, q9 vdup.f32 q10, d9[0] vfma.f32 q8, q2, q10 vdup.f32 q11, d9[1] vfma.f32 q8, q3, q11 : // B: mat44 neon_AQ의 vfma화 vmul.f32 q8, q0, d8[0] vmul.f32 q9, q0, d10[0] vmul.f32 q10, q0, d12[0] vmul.f32 q11, q0, d14[0] vmla.f32 q8, q1, d8[1] vmla.f32 q9, q1, d10[1] vmla.f32 q10, q1, d12[1] vmla.f32 q11, q1, d14[1] : ↓ vmul.f32 q8, q0, d8[0] vmul.f32 q9, q0, d10[0] vmul.f32 q10, q0, d12[0] vmul.f32 q11, q0, d14[0] vdup.32 q12, d8[1] vdup.32 q13, d10[1] vdup.32 q14, d12[1] vdup.32 q15, d14[1] vfma.f32 q8, q1, q12 vfma.f32 q9, q1, q13 vfma.f32 q10, q1, q14 vfma.f32 q11, q1, q15 :
vfma는 vmla와 달리 vector * scalar가 안되므로 그냥 바꾸는 것만으로는 동작하지 않습니다. SSE와 마찬가지로 데이터 복사가 필요하므로 vdup를 삽입했습니다. 6
ARM A9 ARM A9 Scorpion Swift Swift Krait ARM A15 ---------------------------------------------------------------------- a:m44 vmla_AQ 4.784 3.959 2.859 1.293 1.204 1.337 0.619 b:m44 vmla_BQ 2.408 2.002 1.136 1.359 1.266 0.931 0.569 ↓ A:m44 vfma_AQ ----- ----- ----- 1.632 1.519 1.882 0.746 B:m44 vfma_BQ ----- ----- ----- 1.594 1.484 0.695 0.840
A: 는 상당히 느리지만 B: 는 효과가 있었습니다. 이 케이스에서는 Krait가 Cortex-A15을 넘어섰습니다.
예상대로 Swift, Cortex-A15에서는 역효과로, vdup가 늘어난 만큼 느려졌습니다.
참고로 vmla과 vfma는 반올림 타이밍이 다르므로 엄밀하게 말하자면 결과가 일치하지 않습니다. vfma 쪽은 오차가 적지만, C의 코드에서 보통으로 쓰면 fmacs가 되므로 검증코드에서 멋지게 assert에 걸렸습니다. 7