PowerPCのアライメントについて
前記事でPowerPCにおける条件分岐について簡単な実験を行ったが,もう一点つい気になってしまったことがある.アライメントのことである.PowerPCであろうとx86であろうと,アライメントは揃えるのは当然な話である.
PowerPCはRISCであり32-bitの場合4byteで固定されている.そのため「4byte」がキモなのかと思った.
実験としてはこれまた非常にシンプルで,4byteアライメントされているアクセスをひたすらするような関数と,アライメントされていないアクセスをひたすらするような関数の2つを用意して実行時間を計測した.
この実験を行うためのアセンブリプログラムは以下の通りである.行列の和を求めるシンプルな関数である.今回は1024x1024の行列の和を想定している.
add_matrix_aligned:
li 0, 1024
mulli 15, 0, 4
mullw 16, 15, 0
li 8, 0
add_outer_aligned:
li 9, 0
mtctr 0
add_inner_aligned:
add 10, 3, 8
add 11, 4, 8
lwzx 13, 10, 9
lwzx 14, 11, 9
add 13, 13, 14
add 12, 5, 8
stwx 13, 12, 9
addi 9, 9, 4
bdnz+ add_inner_aligned
add 8, 8, 15
cmpw 7, 8, 16
bne 7, add_outer_aligned
blr
アライメントされていない場合の関数に関しては"li 9, 0"の部分を"li 9, 2"として常に4+2のアドレスにアクセスするようにした.
このプログラムを100回ループした時の実行時間は以下の通りになった.alignedがアライメントされている方で,badがされていない方である.
$ ./add_matrix
add_matrix_aligned : 4.759800 [s]
add_matrix_bad : 5.624340 [s]
一目でわかるレベルにアライメントされていない方が実行時間が遅くなっていることが確認できた.
よりみち
行列和のアセンブリプログラムを書きながら,もうちょっとコードの長さを短く出来ないかなあと思ってついそのまま作ってみた.1024x1024の行列の和を想定しているから出来るコードではあるが,実行時間に変化があるかなと気になった.以下の通りである.
add_matrix_comp:
li 0, 1024
mullw 0, 0, 0
mtctr 0
li 8, 0
comp_loop:
lwzx 10, 3, 8
lwzx 11, 4, 8
add 10, 10, 11
stwx 10, 5, 8
addi 8, 8, 4
bdnz+ comp_loop
blr
命令数が19から11に減った.そしてそのまま実行してみた.add_matrix_compが上のコードである.
$ ./add_matrix
add_matrix_comp : 4.617402 [s]
add_matrix_aligned : 4.759102 [s]
add_matrix_bad : 5.638711 [s]
結局メモリ律速なプログラムではあるが,素直な実装よりも少しだけ速くなった.