STS MACL,R2 MOV.L R2,@R5 ADD #4,R5 MOV.L @R4+,R2 MOV.L @R6+,R1 MUL.L R2,R1 STS MACL,R2 MOV.L R2,@R5 ADD #4,R5 MOV.L @R4+,R2 MOV.L @R6+,R1 MUL.L R2,R1 STS MACL,R2 MOV.L R2,@R5 ADD #4,R5 MOV.L @R4+,R2 MOV.L @R6+,R1 MUL.L R2,R1 STS MACL,R2 MOV.L R2,@R5 BF/S L242 ADD #4,R5 RTS
LDS.L @R15+,MACL L243:
.DATA.W H'04B0 .DATA.L _a .DATA.L _b .DATA.L _c
MOV.L @R5+,R1 MUL.L R3,R1 STS MACL,R3 MOV.L R3,@R6 MOV.L @R4+,R3 ADD #4,R6 MOV.L @R5+,R1 MOV R4,R2 MUL.L R3,R1 ADD #32,R2 STS MACL,R3 MOV.L R3,@R6 ADD #4,R6 PREF @R2 MOV.L @R4+,R2 ADD #4,R7 MOV.L @R5+,R1 CMP/GE R0,R7 MUL.L R2,R1 STS MACL,R2 MOV.L R2,@R6 ADD #4,R6 MOV.L @R4+,R2 MOV.L @R5+,R1 MUL.L R2,R1 STS MACL,R2 MOV.L R2,@R6 BF/S L242 ADD #4,R6 RTS
LDS.L @R15+,MACL L243:
.DATA.W H’04B0 .DATA.L _a .DATA.L _b .DATA.L _c
■改善前後のコードサイズと実行速度
改善前 改善後1
(PREF1のみ)
改善後2
(PREF1,2)
コードサイズ 84byte 92byte 96byte
実行速度 91,327cycle 89,526cycle 84,696cycle
【注】測定条件はcpu=sh3に設定し、プログラムを外部メモリへロードし、外部メモリ へのアクセスサイクル数を16にて測定した。
3.9.2 タイリング
■ポイント
データアクセスに局所性を持たせてデータキャッシュミスを少なくすようなプログラミングを 行います。
言い換えれば、キャッシュがヒットしている状態で計算できるものは、先にしてしまうテクニ ックです。
■説明
簡単な例として、二つの配列、A、B に対する差分の総和をとる配列を作成する例を示します。
そこで、アクセスの順番を変えてプログラミングすることによって、データキャッシュミスを 削減するようなプログラミングをします。
■使用例
構造体は配列のメンバ、a,b,c,dに対し、
di=Σj bj-aj の計算を行う。
改善前ソースコード typedef struct { float a,b,c,d;
} data_t;
f(data_t data[], int n) {
data_t *p,*q;
data_t *p_end = &data[n];
data_t *q_end = p_end;
float a,d;
for (p = data; p < p_end; p++){
a = p->a;
d = 0.0f;
for (q = data; q < q_end; q++){
d += q->b -a;
} p->d=d;
} }
改善後ソースコード
#define STRIDE 512 typedef struct { float a,b,c,d;
} data_t;
f(data_t data[], int n) {
data_t *p,*q, *end=&data[n];
data_t *pp, *qq;
data_t *pp_end, *qq_end;
float a,d;
for (p = data; p < end; p = pp_end){
pp_end = p + STRIDE;
for (q = data; q < end; q = qq_end){
qq_end = q + STRIDE;
for (pp = p; pp < pp_end && pp
<end; pp++){
a = pp->a;
d = pp->d;
for (qq = q; qq < qq_end
&& qq < end; qq++){
d += qq->b -a;
}
p->d = d;
} } }
}改善後アセンブリ展開コード
MOV R4,R6 L245:
MOV R4,R5 FMOV.S @R6,FR5 CMP/HS R1,R5 BT/S L246 FMOV.S FR6,FR4 L247:
STS FPSCR,R3 MOV.L L248,R2 MOV #4,R0
FMOV.S @(R0,R5),FR3 ADD #16,R5 AND R2,R3 CMP/HS R1,R5 LDS R3,FPSCR FSUB FR5,FR3 BF/S L247 FADD FR3,FR4 L246:
MOV #12,R0 FMOV.S FR4,@(R0,R6) ADD #16,R6 L244:
CMP/HS R1,R6 BF L245 RTS
NOP L248:
.DATA.L H'FFE7FFFF .END
ADD R4,R7 MOV.W L259,R11 BRA L249 MOV R4,R13 L250:
MOV R13,R10 ADD R11,R10 BRA L251 MOV R4,R14 L252:
MOV R14,R1 ADD R11,R1 BRA L253 MOV R13,R6 L254:
MOV #12,R0 FMOV.S @R6,FR5 FMOV.S @(R0,R6),FR4 BRA L255
MOV R14,R5 L256:
STS FPSCR,R3 MOV.L L259+2,R2 MOV #4,R0
FMOV.S @(R0,R5),FR3 ADD #16,R5 AND R2,R3 LDS R3,FPSCR FSUB FR5,FR3 FADD FR3,FR4 L255:
CMP/HS R1,R5 BT L257 CMP/HS R7,R5 BF L256
L257:
MOV #12,R0 ADD #16,R6
FMOV.S FR4,@(R0,R13) L253:
CMP/HS R10,R6 BT L258 CMP/HS R7,R6 BF L254
L258:
MOV R1,R14 L251:
CMP/HS R7,R14 BF L252 MOV R10,R13 L249:
CMP/HS R7,R13 BF L250 MOV.L @R15+,R10 MOV.L @R15+,R11 MOV.L @R15+,R13 RTS
MOV.L @R15+,R14 L259:
.DATA.W H'2000 .DATA.L H'FFE7FFFF .END
■ 改善前後のコードサイズと実行速度 (SH-4)
改善前 改善後
コードサイズ 52byte 104byte 実行速度 1,486×106cycle 1,068×106cycle 【注】n=8192、STRIDE=512の場合
■改善前後のプログラム解説
改善前と後では、改善後の方がループが4重になった為、処理が複雑になり、コードサイズ
も大きくなります。ただし、このような処理をすることで、キャッシュミスによるオーバヘッド を削減することが可能です。よって、処理するデータが小さな場合には効果はありませんが、デ ータが大きい場合に効果があります。
改善前では、一つのデータdata[0]->dを求めるために、data[0]~data[n-1]までを順次参照します。
次に、data[1]->dを求めるために、再度、data[0]~data[n-1]を参照しようとしますが、配列dataの サイズが、キャッシュのサイズに比べ大きいときには、既に、data[0]の内容はキャッシュにはな くなっており、キャッシュミスを起こします。
大きな領域を順次参照していくため、同じデータの次の参照まで、キャッシュ中にデータが残 っていないことになります。
改善後のプログラムでは、小さな区間に分割してデータをアクセスするため、そのデータアク セスの間のキャッシュミスは少なくなります。計算の順番を換えて、キャッシュがヒットしてい る間に、別の計算もしてしまう手法です。