Cortex-A53

(3ヶ月くらいまえに)携帯あたらしくしてCortex-A53(ただし KitKat なので32bit)にしたのだけど、全然性能はかってないのでなんかはかろうと思って

https://github.com/tanakamura/instruction-bench

のARM 版をつくった

https://github.com/tanakamura/ude-bench

今はまだコマンドラインでしか動かないので、Makefileなんかうまいこと修正して、できたinstbench を adb shell とかで動かしてなんとかしておいて。UIはそのうちなんとかすると思う…。

あと Raspi2(Cortex A7) 持ってて動かしてみたという人がいたら、結果なんらかの方法で送ってもらえると嬉しいです(もしかしたらperf_event_open無くて動かないかも)。


よく考えたら解説書いたことなかったので書いておくと、

loop:
    add r0, r0, r0
    add r0, r0, r0
    add r0, r0, r0
    ...
    add r0, r0, r0
    sub r10, 1
    bne loop

みたいなのを動かして、命令のレイテンシを、

loop:
    add r0, r0, r0
    add r0, r1, r1
    add r0, r2, r2
    ...
    add r0, r7, r7
    sub r10, 1
    bne loop

みたいなのを動かして、命令のスループットを計測する。


CPI、 IPC は同じ値を示してて、単なる逆数。直感的には、latency のときはCPI、throughput のときはIPCを見たほうが理解しやすいと思う。サイクル値は、パフォーマンスカウンタから読んでるので、省電力機能の影響は受けてないはず。


Cortex A53 だと、↓ だった。

== num_insn = 256 ==
 generic :                       add rd, rm, rn :         latency : CPI=    1.00, IPC=    1.00
 generic :                       add rd, rm, rn :      throughput : CPI=    0.51, IPC=    1.96
 generic :                       add rd, rm, rn :          rename : CPI=    0.51, IPC=    1.97
 generic :                      adds rd, rm, rn :         latency : CPI=    1.00, IPC=    1.00
 generic :                      adds rd, rm, rn :      throughput : CPI=    0.51, IPC=    1.97
 generic :                      adds rd, rm, rn :          rename : CPI=    0.51, IPC=    1.96
 generic :               add rd, rm, rn, lsl #4 :         latency : CPI=    2.00, IPC=    0.50
 generic :               add rd, rm, rn, lsl #4 :      throughput : CPI=    0.51, IPC=    1.97
 generic :               add rd, rm, rn, lsl #4 :          rename : CPI=    0.51, IPC=    1.96
 generic :                      add rd, rm, imm :         latency : CPI=    1.00, IPC=    1.00
 generic :                      add rd, rm, imm :      throughput : CPI=    0.51, IPC=    1.97
 generic :                      add rd, rm, imm :          rename : CPI=    0.51, IPC=    1.97
 generic :                       add rd, rm, pc :         latency : CPI=    1.01, IPC=    0.99
 generic :                       add rd, rm, pc :      throughput : CPI=    0.51, IPC=    1.96
 generic :                       add rd, rm, pc :          rename : CPI=    0.51, IPC=    1.97
 generic :                        add pc, pc, 0 :         latency : CPI=    4.52, IPC=    0.22
 generic :                       orr rd, rm, rn :         latency : CPI=    1.00, IPC=    1.00
 generic :                       orr rd, rm, rn :      throughput : CPI=    0.51, IPC=    1.97
 generic :                       orr rd, rm, rn :          rename : CPI=    0.51, IPC=    1.97
 generic :                       eor rd, rm, rn :         latency : CPI=    1.00, IPC=    1.00
 generic :                       eor rd, rm, rn :      throughput : CPI=    0.51, IPC=    1.97
 generic :                       eor rd, rm, rn :          rename : CPI=    0.51, IPC=    1.97
 generic :                       mul rd, rm, rs :         latency : CPI=    3.00, IPC=    0.33
 generic :                       mul rd, rm, rs :      throughput : CPI=    1.00, IPC=    1.00
 generic :                       mul rd, rm, rs :          rename : CPI=    1.00, IPC=    1.00
 generic :                   mla rd, rm, rs, rn :         latency : CPI=    3.00, IPC=    0.33
 generic :                   mla rd, rm, rs, rn :      throughput : CPI=    1.00, IPC=    1.00
 generic :                   mla rd, rm, rs, rn :          rename : CPI=    1.00, IPC=    1.00
 generic :                     ldr rt, [rn, rm] :         latency : CPI=    3.00, IPC=    0.33
 generic :                     ldr rt, [rn, rm] :      throughput : CPI=    1.00, IPC=    1.00
 generic :                     ldr rt, [rn, rm] :          rename : CPI=    1.00, IPC=    1.00
 generic :             ldr rt, [rn, rm, lsl #4] :         latency : CPI=    5.01, IPC=    0.20
 generic :             ldr rt, [rn, rm, lsl #4] :      throughput : CPI=    3.01, IPC=    0.33
 generic :             ldr rt, [rn, rm, lsl #4] :          rename : CPI=    3.01, IPC=    0.33
 generic :                         ldm rt, {r0} :      throughput : CPI=    1.01, IPC=    0.99
 generic :                         ldm rt, {r0} :          rename : CPI=    1.01, IPC=    0.99
 generic :                      ldm rt, {r0-r3} :      throughput : CPI=    2.01, IPC=    0.50
 generic :                      ldm rt, {r0-r3} :          rename : CPI=    2.01, IPC=    0.50
 generic :                      ldm rt, {r0-r7} :      throughput : CPI=    4.01, IPC=    0.25
 generic :                      ldm rt, {r0-r7} :          rename : CPI=    4.01, IPC=    0.25
 generic :                       ldrex rd, [rn] :      throughput : CPI=    3.00, IPC=    0.33
 generic :                       ldrex rd, [rn] :          rename : CPI=    3.00, IPC=    0.33
 generic :                   strex rd, rm, [rn] :      throughput : CPI=    3.00, IPC=    0.33
 generic :                   strex rd, rm, [rn] :          rename : CPI=    3.00, IPC=    0.33
 generic :  ldrex r0, [rn]; strex rd, r0, [rn]  :      throughput : CPI=   12.02, IPC=    0.08
 generic :  ldrex r0, [rn]; strex rd, r0, [rn]  :          rename : CPI=   12.02, IPC=    0.08
 generic :                     str rt, [rn, #0] :      throughput : CPI=    1.00, IPC=    1.00
 generic :                     str rt, [rn, #0] :          rename : CPI=    1.00, IPC=    1.00
 generic :                      {str->ldr}->... :         latency : CPI=    3.00, IPC=    0.33
 generic :                     {strb->ldr}->... :         latency : CPI=    3.00, IPC=    0.33
  neon64 :                     vadd.f32 d, d, d :         latency : CPI=    4.01, IPC=    0.25
  neon64 :                     vadd.f32 d, d, d :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                     vadd.f32 d, d, d :          rename : CPI=    0.51, IPC=    1.97
 neon128 :                     vadd.f32 q, q, q :         latency : CPI=    4.01, IPC=    0.25
 neon128 :                     vadd.f32 q, q, q :      throughput : CPI=    1.00, IPC=    1.00
 neon128 :                     vadd.f32 q, q, q :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                     vmul.f32 d, d, d :         latency : CPI=    4.01, IPC=    0.25
  neon64 :                     vmul.f32 d, d, d :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                     vmul.f32 d, d, d :          rename : CPI=    0.51, IPC=    1.96
 neon128 :                     vmul.f32 q, q, q :         latency : CPI=    4.01, IPC=    0.25
 neon128 :                     vmul.f32 q, q, q :      throughput : CPI=    1.01, IPC=    0.99
 neon128 :                     vmul.f32 q, q, q :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                     vmul.f32 d, d, d :         latency : CPI=    4.01, IPC=    0.25
  neon64 :                     vmul.f32 d, d, d :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                     vmul.f32 d, d, d :          rename : CPI=    0.51, IPC=    1.97
 neon128 :                     vmul.f32 q, q, q :         latency : CPI=    4.01, IPC=    0.25
 neon128 :                     vmul.f32 q, q, q :      throughput : CPI=    1.01, IPC=    0.99
 neon128 :                     vmul.f32 q, q, q :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                     vmla.f32 d, d, d :         latency : CPI=    4.01, IPC=    0.25
  neon64 :                     vmla.f32 d, d, d :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                     vmla.f32 d, d, d :          rename : CPI=    0.51, IPC=    1.97
 neon128 :                     vmla.f32 q, q, q :         latency : CPI=    4.01, IPC=    0.25
 neon128 :                     vmla.f32 q, q, q :      throughput : CPI=    1.01, IPC=    0.99
 neon128 :                     vmla.f32 q, q, q :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                      vld1.32 d, [rn] :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                      vld1.32 d, [rn] :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                      vld2.32 d, [rn] :      throughput : CPI=    1.01, IPC=    0.99
  neon64 :                      vld2.32 d, [rn] :          rename : CPI=    1.01, IPC=    0.99
 neon128 :                      vld4.32 q, [rn] :      throughput : CPI=    2.01, IPC=    0.50
 neon128 :                      vld4.32 q, [rn] :          rename : CPI=    2.01, IPC=    0.50
  neon64 :                      vst1.32 d, [rn] :      throughput : CPI=    1.00, IPC=    1.00
  neon64 :                      vst1.32 d, [rn] :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                      vst2.32 d, [rn] :      throughput : CPI=    1.01, IPC=    0.99
  neon64 :                      vst2.32 d, [rn] :          rename : CPI=    1.01, IPC=    0.99
 neon128 :                      vst4.32 q, [rn] :      throughput : CPI=    2.01, IPC=    0.50
 neon128 :                      vst4.32 q, [rn] :          rename : CPI=    2.01, IPC=    0.50
  neon64 :                    vcvt.f32.s32 d, d :      throughput : CPI=    0.51, IPC=    1.97
  neon64 :                    vcvt.f32.s32 d, d :          rename : CPI=    0.51, IPC=    1.97
 neon128 :                    vcvt.f32.s32 q, q :      throughput : CPI=    1.01, IPC=    0.99
 neon128 :                    vcvt.f32.s32 q, q :          rename : CPI=    1.01, IPC=    0.99
  neon64 :                    vcvt.s32.f32 d, d :      throughput : CPI=    0.51, IPC=    1.97
  neon64 :                    vcvt.s32.f32 d, d :          rename : CPI=    0.51, IPC=    1.97
 neon128 :                    vcvt.s32.f32 q, q :      throughput : CPI=    1.01, IPC=    0.99
 neon128 :                    vcvt.s32.f32 q, q :          rename : CPI=    1.01, IPC=    0.99

結構普通だなーという感じだけど(まあ今時のCPUなら普通なのが当然だが…)、いくらか気になる点は、


オペランドレジスタをシフトするとおそい。特にアドレスをシフトするとスループット1/3 になる。


vcvt.f32.s32 はレイテンシ1だがなんかの間違いな気がするがこんなもんだっけ…


throughput と rename のちがいは、

// throughput
loop:
    vadd.f32 d0, d1, d1
    vadd.f32 d0, d2, d2
    ...
    vadd.f32 d0, d8, d8
    sub r10, 1
    bne loop
// rename
loop:
    vadd.f32 d1, d1, d1
    vadd.f32 d2, d2, d2
    ...
    vadd.f32 d8, d8, d8
    sub r10, 1
    bne loop

なのだが、64bit neon だと、なぜかこれで性能が変わる。rename のほうはスループット2出るが、throughputのほうは出ない。

vmla.f32 q,q,q はスループット1出るが、vld.f32 q, [r] はスループット0.5。

あたりかな…


あと recp, rsqrt, zip, シフト全般などを追加したほうがいい気がする。(追加するの結構ダルいのでやらないかもしれない)

clminibench for Android

上のをUI作るまえに復習しようと思って、clminibench をちゃんとリリースしておいた。

https://play.google.com/store/apps/details?id=main.jp.Int.clminibench

作ったとき一緒に作った資料↓。

http://int.main.jp/txt/mali-chang.pdf

もう二年前の話か…ていうか、この時の記録を書いてない気がした。

主に、clEnqueueNDRangeKernel のレイテンシが 10usec なのか、100usec なのか知りたい人向けのベンチマークなので、あまり期待しないでね…

AndroidOpenCL icd に対応してなくて、libOpenCL.so の位置を自分で探さないといけないのだが、どこにも資料が無くて、一応、

  • /system/vendor/lib/libOpenCL.so
  • /system/vendor/lib/egl/libGLES_mali.so

のふたつはロードを試みてるが、それ以外に置いてあると動かない。


あと、int.main.jp を package 名にすると、int がキーワードだからビルドできないという悲しい話があった。

関東GPGPU勉強会 #2

というわけで、せっかくだから記録を書いておくと…覚えてるわけが無いのだった。(http://togetter.com/li/511911 多分こっちを見たほうが情報量がある)


このときは、Mali-T604 は19.0GFLOPSと書いてるのだけど、どこで見たか忘れたけど、72か74ぐらいが理論値らしい。ただ、この単純にmad4を並べた書きかたで出ないなら、どうやったら出るんだという気がする。



気になる記述としては、

http://community.arm.com/groups/arm-mali-graphics/blog/2013/05/13/flipping-the-flops--how-arm-measures-gpu-compute-performance

に、「sinとかcosに含まれる演算を計算性能に含めるのはセコいだろ(まあでもdot productのは含めてもいいかな…)(超意訳)」とか書いてあって、なんかdot() なら性能出るのかも、という気がした。たぶん、パイプライン上に複数の演算があって、特定の書きかたしたら、複数の演算が1cycleでできるようになってるとかなのではないかな…


しかしNexus10 のOpenCLはつぶされたのでもう確認できない。