VFP Benchmark
- FPU 用のベンチマークソフト ARMv7A, ARMv8A (arm64), x86, x64(x86_64), MIPS32/MIPS64 対応 (ARM VFPv3, VFPv4, NEON, AArch64 NEON, SSE2, AVX1, MIPS-FPU)
- iOS 7.0〜
- Android 2.2~
- 無料、広告なし、必要権限は SDCARD への計測ログファイルの保存のみ
Link
概要
blog (ホイール欲しい ハンドル欲しい) で記事にしてきた vfp/neon の CPU 速度テストプログラムをアプリにしました。 過去のベンチマークの結果は こちら にまとめています。
もともとこのアプリが作られたきっかけは、Cortex-A8 ではスカラーの浮動小数点演算ユニット VFP の性能が著しく低かったことです。 fmuls, fadds, fmacs などの命令単位で速度を比較すれば一目瞭然で、VFP 命令を使うと他の CPU core の 1/5~1/10 程度の速度しか出ません。 Cortex-A8 では VFP の代わりに NEON 命令 vmul, vadd, vmla を使うことで十分な実行速度を保つことが分かりました。
このベンチマークアプリを使うと、命令単位で CPU core の浮動小数点演算速度やサイクル数を割り出すことができます。 プログラマがコード最適化の方針を決定したり、目標にすることができます。 アプリケーション最適化時のヒントとして活用してください。
またその結果から理論的なピーク値を割り出すことが可能です。 テスト結果を比較することで、演算ユニットのパイプライン構造などもある程度わかってくるかもしれません。 なお純粋に命令の速度を計測することが目的なので、コードはすべてオンキャッシュによる動作が前提となっています。
- モバイルデバイスの性能を確認する
- CPU の演算ユニットやパイプラインの特性を調べて最適化に利用する
- ピーク性能を調べて最適化の目標値にする
ストレージやメモリなど外部 I/O の影響を受けないので、実際のアプリケーションなど実用時の速度結果にはなりませんのでご注意ください。 このテストの結果とシステム全体の速度は必ずしも一致しません。
実際に VFP Benchmark で計測した結果は下記の通り。
注意点: 現在のバージョンでは非対称マルチコア CPU (Cortex-A15 + Cortex-A7 等) の場合、スレッド実行時の結果が正しいものになりませんのでご注意ください。
更新履歴
- 2019/06/01 v2.0 : console version。big.LITTLE 対応, Loop scale 対応, half-precision fp (fullhp) 対応
- 2015/07/12 v1.3.5 : x86/x64 FMA3 対応
- 2015/03/06 v1.3.4 : Android TV 対応
- 2015/01/18 v1.3.3 : Android 版で MIPS の FPU 命令に対応
- 2015/01/15 v1.3.2 : Android 2.2/2.3 対応
- 2014/11/30 v1.3.1 : Android 4.3 以前で動作しなくなっていたバグ修正。default loop 値の調整
- 2014/11/09 v1.3 : Android 64bit 対応 (arm64-v8a, x86_64, mips64 対応), iOS 版は最初から arm64 対応済み
- 2014/07/24 Wear : Android Wear 版追加
- 2014/07/22 v1.2 : Android 版 UI の変更
- 2014/01/28 v1.1 : Android 版 x86 SSE/AVX 対応, thread 実行時のメモリリーク修正
- 2014/01/18 v1.0 : 初期版
各テストの詳細
Test 項目
- FPU/SIMD single fp (32bit fp) single-thread
- FPU/SIMD double fp (64bit fp) single-thread
- Matrix 4×4 single-thread
- FPU/SIMD single fp (32bit fp) multi-thread
- FPU/SIMD double fp (64bit fp) multi-thread
- Matrix 4×4 multi-thread
FPU/SIMD Test
命令単位でひたすら意味のない演算しています。 各種 mul, add, multiply-add, fma (fused multiply-add) を個別に計測しています。
Arch | iOS | Android | cmd | FPU / SIMD | Scalar sp Instructions | Scalar dp Instructions | SIMD sp Instructions | SIMD dp Instructions |
---|---|---|---|---|---|---|---|---|
ARMv5TE | – | ◎ | – | – | – | – | – | – |
ARMv6 (armv6) | – | – | ◎ | VFPv2 | fmuls, fadds, fmacs | fmuld, faddd, fmacd | – | – |
ARMv7A | – | ◎ | – | VFPv3-D16 | fmuls, fadds, fmacs | fmuld, faddd, fmacd | – | – |
ARMv7A (armv7) | ◎ | ◎ | ◎ | VFPv3-D32 / NEON | fmuls, fadds, fmacs | fmuld, faddd, fmacd | vmul.f32, vadd.f32, vmla.f32 | – |
ARMv7A (armv7s) | ◎ | ◎ | ◎ | VFPv4-D32 / NEON | fmuls, fadds, fmacs, vfma.f32 | fmuld, faddd, fmacd, vfma.f64 | vmul.f32, vadd.f32, vmla.f32, vfma.f32 | – |
ARMv8A (arm64) | ◎ | ◎ | – | AArch64 / NEON | fmul s, fadd s, fmadd s | fmul d, fadd d, fmadd d | fmul.4s, fadd.4s, fmla.4s | fmul.2d, fadd.2d, fmla.2d |
x86 (IA-32) | – | ◎ | ◎ | SSE2 / AVX1 / FMA3 | mulss, addss, vfmaddss | mulsd, addsd, vfmaddsd | mulps, addps, vmulps, vaddps, vfmaddps | mulpd, addpd, vmulpd, vaddpd, vfmaddpd |
x64 (x86_64) | – | ◎ | ◎ | SSE2 / AVX1 / FMA3 | mulss, addss, vfmaddss | mulsd, addsd, vfmaddsd | mulps, addps, vmulps, vaddps, vfmaddps | mulpd, addpd, vmulpd, vaddpd, vfmaddpd |
MIPS32-R2 (mips) | – | ◎ | – | FPU | mul.s, add.s, madd.s | mul.d, add.d, madd.d | – | – |
MIPS64-R6 (mips64) | – | ◎ | – | FPU / PS / MSA | mul.s, add.s, madd.s | mul.d, add.d, madd.d | – | – |
Arch | arithmetic op | FMA |
---|---|---|
ARMv7A VFPv3/v4 | 3 operand | 3 operand (FMA3) |
ARMv7A NEON | 3 operand | 3 operand (FMA3) |
ARMv8A AArch64 FPU | 3 operand | 4 operand (FMA4) |
ARMv8A AArch64 NEON | 3 operand | 3 operand (FMA3) |
x86 / x64 | 3 operand | 3 operand (FMA3) |
MIPS32/MIPS64 | 3 operand | 4 operand (FMA4) |
- ARMv7A VFPv3 には fma がありません。逆に ARMv8A AArch64 (64bit) では fmadd/fmla が fma になります。
- SIMD (NEON) の倍精度演算(dp)は ARMv8A (AArch64) 以降の対応です。ARMv7A の NEON や ARMv8A の AArch32 では倍精度演算が出来ません。
- 2014/01/24 現在 ARMv8A に対応しているのは iOS 版だけとなります。
- x86/x64 の fma には未だ対応しておりません。その代わり加算器と乗算器を並列実行できるように mul/add の interleave に対応しています。
- x64 の内容は x86 同様ですがレジスタ数が多いためコードが異なっています。
- ARMv5TE では Matrix Test のみ実行できます。
- 現在 MIPS32/MIPS64 の Paired Single (PS), Mips SIMD Architecture (MSA) には非対応です。
blog 記事での Type-A と Type-B はそれぞれ n8 と ns4 に相当します。
ARM VFP (32bit x1) single fp 単精度浮動小数点演算
32bit scalar 演算です。 NEON 非搭載でも実行できます。ARMv7A では VFP の s register を使用。 ARMv8A (arm64) の場合もほぼ同等の命令で計測します。 ただし fmadd 積和命令は ARMv7A の VFP と違い 4 オペランドです。
ARM NEON (32bit x2) single fp 単精度浮動小数点演算
32bit x 2 の SIMD 演算です。ARMv7A では NEON の d register を使用。 ARMv8A (arm64) の場合は v register の .2s 演算命令になります。
ARM NEON (32bit x4) single fp 単精度浮動小数点演算
32bit x 4 の SIMD 演算です。ARMv7A では NEON の q register を使用。 ARMv8A (arm64) では v register に .4s 演算命令になります。
ARM VFP (64bit x1) double fp 倍精度浮動小数点演算
64bit scalar 演算です。 NEON 非搭載でも実行できます。 ARMv7A では VFP の d register を使用。 ARMv8A (arm64) でも同等の命令で演算します。 ただし fmadd 積和命令は ARMv7A の VFP と違い 4 オペランドになります。
ARM NEON (64bit x2) double fp 倍精度浮動小数点演算
64bit x 2 の SIMD 演算です。ARMv7A では 64bit (double float) の NEON 命令はありません。 ARMv8A (arm64) AArch64 では v register の .2d 演算命令となります。
x86/x64 SSE (32bit x1 ) single fp 単精度浮動小数点演算
SSE を使った scalar 演算です。 SSE は 2オペランドのソース破壊転送かつ x86 ではレジスタが少ないため、n8 を再現することができません。 命令の並びが他の CPU や AVX と異なります。
x86/x64 SSE (32bit x4 ) single fp 単精度浮動小数点演算
SSE を使った SIMD 演算です。 SSE は 2オペランドのソース破壊転送なのでテスト項目が異なります。
x86/x64 AVX (32bit x8 ) single fp 単精度浮動小数点演算
AVX を使った SIMD 演算です。 AVX は 3オペランドなので ARM NEON と同等のテスト内容となります。
x86/x64 SSE (64bit x1 ) double fp 倍精度浮動小数点演算
SSE を使った scalar 演算です。 SSE は 2オペランドのソース破壊転送なのでテスト項目が異なります
x86/x64 SSE (64bit x2 ) double fp 倍精度浮動小数点演算
SSE を使った SIMD 演算です。 SSE は 2オペランドのソース破壊転送なのでテスト項目が異なります。
x86/x64 AVX (64bit x4 ) double fp 倍精度浮動小数点演算
AVX を使った SIMD 演算です。 AVX は 3オペランドなので ARM NEON と同等のテスト内容となります。
n8
read register は常に同一です。 8 命令単位で write register を再利用します。
op s0, s8, s9 op s1, s8, s9 op s2, s8, s9 op s3, s8, s9 op s4, s8, s9 op s5, s8, s9 op s6, s8, s9 op s7, s8, s9
ns4
4命令単位の read 依存があります。
op s0, s8, s4 op s1, s8, s5 op s2, s8, s6 op s3, s8, s7 op s4, s8, s0 op s5, s8, s1 op s6, s8, s2 op s7, s8, s3
n1
入出力は固定ですが同じレジスタに書き込み続けます。 read していないので依存はありませんが、rename できない場合著しく効率が落ちることを想定しています。
op s0, s8, s9 op s0, s8, s9 op s0, s8, s9 op s0, s8, s9 op s0, s8, s9 op s0, s8, s9 op s0, s8, s9 op s0, s8, s9
n12
n8 を 12命令単位に増やしたもの。 pipeline が深くレイテンシが大きい場合に差が出ることを想定しています。 n12 の実行効率は高いですが、他のテストよりも命令数が 1.5 倍に増えるので実行時間は長くなります。 ARMv8A (arm64) AArch64 では、q ではなく v register になります。
op q0, q12, q13 op q1, q12, q13 op q2, q12, q13 op q3, q12, q13 op q4, q12, q13 op q5, q12, q13 op q6, q12, q13 op q7, q12, q13 op q8, q12, q13 op q9, q12, q13 op q10, q12, q13 op q11, q12, q13
Matrix 4x4 Test
完全にオンメモリで非現実的だった VFP/NEON Test と違い、 Matrix Test はメモリアクセスを伴う比較的現実味のあるテストを行います。
Matrix 4x4 C code
C++ 言語でそのまま演算しています。 標準の FPU(VFP) が用いられます。
このテストのみ armeabi/x86/mips すべての CPU で動作します。(armeabi は FPU 無し)
ARMv7A Matrix 4x4 NEON 128bit A
A は in-order な cpu では pipeline stoll が発生し、out-of-order な CPU よりも速度が落ちることを想定しています。
vldmia %0, {d0-d7} vldmia %1, {d8-d15} vmul.f32 q8,q0,d8[0] vmla.f32 q8,q1,d8[1] vmla.f32 q8,q2,d9[0] vmla.f32 q8,q3,d9[1] vstmia %2!, {d16,d17} vmul.f32 q8,q0,d10[0] vmla.f32 q8,q1,d10[1] vmla.f32 q8,q2,d11[0] vmla.f32 q8,q3,d11[1] vstmia %2!, {d16,d17} vmul.f32 q8,q0,d12[0] vmla.f32 q8,q1,d12[1] vmla.f32 q8,q2,d13[0] vmla.f32 q8,q3,d13[1] vstmia %2!, {d16,d17} vmul.f32 q8,q0,d14[0] vmla.f32 q8,q1,d14[1] vmla.f32 q8,q2,d15[0] vmla.f32 q8,q3,d15[1] vstmia %2!, {d16,d17}
ARMv7A Matrix 4x4 NEON 128bit B
B は interleave により実行効率が上がることを想定しています。 ただしメモリが遅ければあまり意味が無いかもしれません。
vldmia %0, {d0-d7} vldmia %1, {d8-d15} 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] vmla.f32 q8,q2,d9[0] vmla.f32 q9,q2,d11[0] vmla.f32 q10,q2,d13[0] vmla.f32 q11,q2,d15[0] vmla.f32 q8,q3,d9[1] vmla.f32 q9,q3,d11[1] vmla.f32 q10,q3,d13[1] vmla.f32 q11,q3,d15[1] vstmia %2, {d16-d23}
ARMv7A Matrix 4x4 NEON 128bit A FMA
ARMv7A (VFPv4) の FMA は scaler x vector ができないため vdup が挿入されています。(ARMv8A AArch64 arm64 では可能です) そのため vmla より命令数が大幅に増えています。
vldmia %0, {d0-d7} vldmia %1, {d8-d15} vmul.f32 q8,q0,d8[0] vdup.32 q9, d8[1] vfma.f32 q8,q1,q9 vdup.32 q10, d9[0] vfma.f32 q8,q2,q10 vdup.32 q11, d9[1] vfma.f32 q8,q3,q11 vstmia %2!, {d16,d17} vmul.f32 q8,q0,d10[0] vdup.32 q12, d10[1] vfma.f32 q8,q1,q12 vdup.32 q13, d11[0] vfma.f32 q8,q2,q13 vdup.32 q14, d11[1] vfma.f32 q8,q3,q14 vstmia %2!, {d16,d17} vmul.f32 q8,q0,d12[0] vdup.32 q9, d12[1] vfma.f32 q8,q1,q9 vdup.32 q10, d13[0] vfma.f32 q8,q2,q10 vdup.32 q11, d13[1] vfma.f32 q8,q3,q11 vstmia %2!, {d16,d17} vmul.f32 q8,q0,d14[0] vdup.32 q12, d14[1] vfma.f32 q8,q1,q12 vdup.32 q13, d15[0] vfma.f32 q8,q2,q13 vdup.32 q14, d15[1] vfma.f32 q8,q3,q14 vstmia %2!, {d16,d17}
ARMv7A Matrix 4x4 NEON 64bit A
128bit Quad ではなく 64bit (Double) 単位で演算を行っています。 64bit ALU の NEON と 128bit ALU の NEON で差が付く可能性を考慮しましたが 目立った差は検出されません。
vldmia %0, {d0-d7} vldmia %1, {d8-d15} vmul.f32 d16,d0,d8[0] vmul.f32 d17,d1,d8[0] vmla.f32 d16,d2,d8[1] vmla.f32 d17,d3,d8[1] vmla.f32 d16,d4,d9[0] vmla.f32 d17,d5,d9[0] vmla.f32 d16,d6,d9[1] vmla.f32 d17,d7,d9[1] vstmia %2!, {d16,d17} vmul.f32 d16,d0,d10[0] vmul.f32 d17,d1,d10[0] vmla.f32 d16,d2,d10[1] vmla.f32 d17,d3,d10[1] vmla.f32 d16,d4,d11[0] vmla.f32 d17,d5,d11[0] vmla.f32 d16,d6,d11[1] vmla.f32 d17,d7,d11[1] vstmia %2!, {d16,d17} vmul.f32 d16,d0,d12[0] vmul.f32 d17,d1,d12[0] vmla.f32 d16,d2,d12[1] vmla.f32 d17,d3,d12[1] vmla.f32 d16,d4,d13[0] vmla.f32 d17,d5,d13[0] vmla.f32 d16,d6,d13[1] vmla.f32 d17,d7,d13[1] vstmia %2!, {d16,d17} vmul.f32 d16,d0,d14[0] vmul.f32 d17,d1,d14[0] vmla.f32 d16,d2,d14[1] vmla.f32 d17,d3,d14[1] vmla.f32 d16,d4,d15[0] vmla.f32 d17,d5,d15[0] vmla.f32 d16,d6,d15[1] vmla.f32 d17,d7,d15[1] vstmia %2!, {d16,d17}
ARMv8A Matrix 4x4 NEON 128bit A
ARMv8A AArch64 (arm64) では命令もレジスタ名も異なります。 128bit (v/q) レジスタが倍増し、s(32bit), d(64bit), q(128bit) それぞれ 1 対 1 の対応となりました。 また s/d を複数要素まとめて扱う場合はレジスタ名が v になります。
ldp q0, q1, [%0] ldp q2, q3, [%0,#32] ldp q4, q5, [%1] ldp q6, q7, [%1,#32] fmul.4s v8, v0, v4[0] fmla.4s v8, v1, v4[1] fmla.4s v8, v2, v4[2] fmla.4s v8, v3, v4[3] str q8, [%2] fmul.4s v8, v0, v5[0] fmla.4s v8, v1, v5[1] fmla.4s v8, v2, v5[2] fmla.4s v8, v3, v5[3] str q8, [%2,#16] fmul.4s v8, v0, v6[0] fmla.4s v8, v1, v6[1] fmla.4s v8, v2, v6[2] fmla.4s v8, v3, v6[3] str q8, [%2,#32] fmul.4s v8, v0, v7[0] fmla.4s v8, v1, v7[1] fmla.4s v8, v2, v7[2] fmla.4s v8, v3, v7[3] str q8, [%2,#48]
ARMv8A Matrix 4x4 NEON 128bit B
ldp q0, q1, [%0] ldp q4, q5, [%1] ldp q6, q7, [%1,#32] fmul.4s v8, v0, v4[0] fmul.4s v9, v0, v5[0] fmul.4s v10, v0, v6[0] fmul.4s v11, v0, v7[0] ldp q2, q3, [%0,#32] fmla.4s v8, v1, v4[1] fmla.4s v9, v1, v5[1] fmla.4s v10, v1, v6[1] fmla.4s v11, v1, v7[1] fmla.4s v8, v2, v4[2] fmla.4s v9, v2, v5[2] fmla.4s v10, v2, v6[2] fmla.4s v11, v2, v7[2] fmla.4s v8, v3, v4[3] fmla.4s v9, v3, v5[3] fmla.4s v10, v3, v6[3] fmla.4s v11, v3, v7[3] stp q8, q9, [%2] stp q10, q11, [%2,#32]
x86/x64 Matrix 4x4 SSE 128bit A
SSE (SSE1) 命令のみ使用しています。 x64 では edx/eax/ecx の代わりに rdx/rax/rcx が用いられます。
レジスタが少ない、2オペランドの破壊転送、積和命令がない、scalar と vector の乗算ができないことから命令数がかなり多くなります。 x64 ではレジスタ数が 2倍になるので、下記の inline assembler code よりも C compiler の builtin/intrinsic の方が高速なコードが生成されるようです。
mov %[p3], %edx mov %[p1], %eax mov %[p2], %ecx movaps (%eax), %xmm4 movss (%ecx), %xmm1 shufps $0, %xmm1, %xmm1 mulps %xmm4, %xmm1 movaps 16(%eax), %xmm5 movss 4(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm5, %xmm0 addps %xmm0, %xmm1 movaps 32(%eax), %xmm6 movss 8(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm6, %xmm0 addps %xmm0, %xmm1 movaps 48(%eax), %xmm7 movss 12(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm7, %xmm0 addps %xmm0, %xmm1 movaps %xmm1, (%edx) movss 16(%ecx), %xmm1 shufps $0, %xmm1, %xmm1 mulps %xmm4, %xmm1 movss 20(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm5, %xmm0 addps %xmm0, %xmm1 movss 24(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm6, %xmm0 addps %xmm0, %xmm1 movss 28(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm7, %xmm0 addps %xmm0, %xmm1 movaps %xmm1, 16(%edx) movss 32(%ecx), %xmm1 shufps $0, %xmm1, %xmm1 mulps %xmm4, %xmm1 movss 36(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm5, %xmm0 addps %xmm0, %xmm1 movss 40(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm6, %xmm0 addps %xmm0, %xmm1 movss 44(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm7, %xmm0 addps %xmm0, %xmm1 movaps %xmm1, 32(%edx) movss 48(%ecx), %xmm1 shufps $0, %xmm1, %xmm1 mulps %xmm4, %xmm1 movss 52(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm5, %xmm0 addps %xmm0, %xmm1 movss 56(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm6, %xmm0 addps %xmm0, %xmm1 movss 60(%ecx), %xmm0 shufps $0, %xmm0, %xmm0 mulps %xmm7, %xmm0 addps %xmm0, %xmm1 movaps %xmm1, 48(%edx)
x86/x64 Matrix 4x4 AVX 256bit A
AVX (AVX1) の命令のみ使用しています。 x64 では edx/eax/ecx の代わりに rdx/rax/rcx が用いられます。
x86 ではレジスタが少ないですが、レジスタ長が倍なので比較的余裕があります。 2レーン使用し SSE の半分の命令数で 2倍の演算を行っています。 3 operand で非常に使いやすくなっています。 新しい FMA3/4 命令を用いるとさらに短いコードになります。
mov %[p3], %edx mov %[p1], %eax mov %[p2], %ecx vmovups (%eax), %xmm0 vmovups 16(%eax), %xmm1 vmovups 32(%eax), %xmm2 vmovups 48(%eax), %xmm3 vperm2f128 $0x00, %ymm0, %ymm0, %ymm0 vperm2f128 $0x00, %ymm1, %ymm1, %ymm1 vperm2f128 $0x00, %ymm2, %ymm2, %ymm2 vperm2f128 $0x00, %ymm3, %ymm3, %ymm3 vmovups (%ecx), %ymm4 vpermilps $0x00, %ymm4, %ymm5 vmulps %ymm0, %ymm5, %ymm6 vpermilps $0x55, %ymm4, %ymm5 vmulps %ymm1, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vpermilps $0xaa, %ymm4, %ymm5 vmulps %ymm2, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vpermilps $0xff, %ymm4, %ymm5 vmulps %ymm3, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vmovups %ymm6, (%edx) vmovups 32(%ecx), %ymm4 vpermilps $0x00, %ymm4, %ymm5 vmulps %ymm0, %ymm5, %ymm6 vpermilps $0x55, %ymm4, %ymm5 vmulps %ymm1, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vpermilps $0xaa, %ymm4, %ymm5 vmulps %ymm2, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vpermilps $0xff, %ymm4, %ymm5 vmulps %ymm3, %ymm5, %ymm5 vaddps %ymm5, %ymm6, %ymm6 vmovups %ymm6, 32(%edx)
multi-thread
上記の各テストを CPU core の数だけ並列に走らせます。
計測は各スレッドごとに行っているので、スレッド起動タイミングの差は含まれません。 そのため実用に則したベンチマークよりも、比較的理想に近い値が出ると考えられます。(つまり、あまりリアルじゃない)
NVIDIA の Tegra や Intel の TurboBoost など、 Single Thread 時に特別高いクロックで動作する CPU が存在しています。 この場合単純に Single Thread の結果を core 数倍しても正しい値にならないからです。