Ce diaporama a bien été signalé.
Le téléchargement de votre SlideShare est en cours. ×

PBL1-v1-008j.pptx

Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Prochain SlideShare
PBL1-v1-011j.pptx
PBL1-v1-011j.pptx
Chargement dans…3
×

Consultez-les par la suite

1 sur 14 Publicité

PBL1-v1-008j.pptx

Télécharger pour lire hors ligne

IMAX3: Amazing Dataflow-Centric CGRA and its Applications
I present this slide to all hungry engineers who are tired of CPU, GPU, FPGA, tensor core, AI core, who want some challenging one with no black box inside, and who want to improve by themselves.

IMAX3: Amazing Dataflow-Centric CGRA and its Applications
I present this slide to all hungry engineers who are tired of CPU, GPU, FPGA, tensor core, AI core, who want some challenging one with no black box inside, and who want to improve by themselves.

Publicité
Publicité

Plus De Contenu Connexe

Similaire à PBL1-v1-008j.pptx (20)

Publicité

Plus récents (20)

PBL1-v1-008j.pptx

  1. 1. CPU GPU Ultimate CGRA w/ high-speed compiler CGRA for Energy-efficient Cryptography Beyond-Neuromorphic Systems Non-Deterministic Computing 1 ナレータ VOICEVOX:もち子(cv 明日葉よもぎ) はらぺこエンジニアに贈るCGRAの世界2022 (8. 疎行列計算とソート編) スパコンからIoTまで 省エネ社会に AI+BCだけじゃない超効率計算手法 20220202
  2. 2. 20220202 2 A*B ⇒ C A*BT ⇒ C A*BT (疎行列) ⇒ C A*BT (圧縮表現) ⇒ C 疎行列の行列積
  3. 3. 従来:CGRA演算は縦方向 20220202 3 IMAX:縦の圧縮は無意味なので横方向に演算 疎行列の行列積
  4. 4. 20220202 4 疎行列積和 マージソート 1 1.0 2 2.0 3 3.0 11 4.0 12 5.0 13 6.0 配列A 配列B 2 1.0 3 2.0 4 3.0 9 4.0 10 5.0 11 6.0 要素番号と値の組 1 a1 2 a2 3 s3 11 a11 12 a12 13 a13 入力A 入力B 2 b2 3 b3 4 b4 9 b9 10 b10 11 b11 値と付加情報(ポインタなど)の組 疎行列とソートには、デュアルアドレス同調機能が便利
  5. 5. 20220202 5 疎行列とソートには、デュアルアドレス同調機能が便利
  6. 6. 4段パイプライン浮動小数点演算器+メモリ参照(LD+ST) ⑩+⑪+初回初期値C出力レジスタ⇒演算器入力REG 以降、累算 演算器3段結果⇒演算器入力REG 演算器入力REG⇒演算器初段結果⇒演算器2段結果 ⇒演算器3段結果⇒演算器入力REGへ戻る累算リング 4段パイプラインAアドレス計算データフロー ①Aアドレス入力REG⇒②0/8加算出力⇒⑦通過 ⇒⑨通過⇒先頭へ戻るアドレス累算リング 4段パイプラインBアドレス計算データフロー ①Bアドレス入力REG⇒②0/8加算出力⇒⑦通過 ⇒⑨通過⇒先頭へ戻るアドレス累算リング 4段パイプラインAデータ参照フロー ⑤B組およびA組index比較+0/8加算出力 ⇒⑥A先頭オフセット加算結果⇒⑧Aマスク結果 ⇒④Aメモリ出力⇒先頭 4段パイプラインBデータ参照フロー ⑤B組およびA組index比較+0/8加算出力 ⇒⑥B先頭オフセット加算結果⇒⑧Bマスク結果 ⇒③Bメモリ出力⇒先頭 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑨ ① ② ⑤ ⑥ ⑦ ⑧ ① ① ② ② ⑦ ⑦ ⑨ ⑨ ⑤ ⑧ ⑤ ⑥ ⑥ ⑧ ④ ③ ⑩ ⑪ オフセット加算 アドレスマスク操作 読み出し結果 B42 読み出し結果 A00 B,A行列のベースアドレス C02へのストア 20220202 6 4列多重化CGRAに5本のデータ流を埋め込む
  7. 7. mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); 20220202 7 4列多重化CGRAに5本のデータ流を埋め込む
  8. 8. mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); 20220202 8 4列多重化CGRAに10本のデータ流を埋め込む
  9. 9. 20220202 9 void emax6sc_pth_imax_02(struct sc_param *param) { Ull CHIP, LOOP0=param->LOOP0, LOOP1=param->LOOP1; Ull INIT1[4], INIT0[4]; Uint uLOOP[4]; for (CHIP=0; CHIP<1; CHIP++) { /* unit2 */ uLOOP[CHIP]=LOOP1*LOOP0; } while (1) { for (CHIP=0; CHIP<1; CHIP++) if (uLOOP[CHIP]) break; if (CHIP==1) break; for (CHIP=0; CHIP<1; CHIP++) { if (uLOOP[CHIP]==0) continue; if ((2 && SCBR[1].enq[CHIP]==SCBR[1].deq[CHIP]) || (2<17 && SCBR[2].enq[CHIP]!=SCBR[2].deq[CHIP])) continue; INIT1[CHIP]=(uLOOP[CHIP]>LOOP1*LOOP0-LOOP0); INIT0[CHIP]=(uLOOP[CHIP]-(uLOOP[CHIP]/LOOP0*LOOP0)==0); SCBR[1].deq[CHIP] = 1-SCBR[1].deq[CHIP]; { SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6]; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][3] = SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2]; } { Ull base, offs, adr, mexdist, load64; static int emax6_unaligned_load_valid; static Ull emax6_unaligned_load_high; base = (!(0&1)||INIT0[CHIP]) ? ((0&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][0]) : SCM1[2].awoo[CHIP][0]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM1[2].o[CHIP][0], 12); mexdist = INIT0[CHIP] ? 0 : 0; SCM1[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][0]); adr = (Uint)(SCM1[2].awoo[CHIP][0] + offs); SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] = (Ull)*(Uint*)(adr&~3LL)<<32 | (Ull)*(Uint*)(adr&~3LL); SCM1[2].d[CHIP][0] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1]; } { Ull base, offs, adr, mexdist, load64; static int emax6_unaligned_load_valid; static Ull emax6_unaligned_load_high; base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM1[2].b[CHIP][2]) : SCM1[2].awoo[CHIP][2]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM1[2].o[CHIP][2], 13); mexdist = INIT0[CHIP] ? 0 : 8; SCM1[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM1[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM0[2].d[CHIP][2]>>32)!=0xffffffff && (SCM1[2].d[CHIP][2]>>32)<=(SCM0[2].d[CHIP][2]>>32))?mexdist:0); adr = (Uint)(SCM1[2].awoo[CHIP][2] + offs); load64 = *(Ull*)(adr&~7LL); if ((adr&7) == 0) SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64; else if (!emax6_unaligned_load_valid) { /* BR[][][1] */ emax6_unaligned_load_valid = 1; emax6_unaligned_load_high = load64; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = load64 >> (adr&7)*8; } else { /* BR[][][0] */ emax6_unaligned_load_valid = 0; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8; } base = (!(1&1)||INIT0[CHIP]) ? ((1&2)?SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][2]) : SCM0[2].awoo[CHIP][2]; offs = eam(1 ? SCBR[1].r[CHIP][SCBR[2].enq[CHIP]][2] : SCM0[2].o[CHIP][2], 12); mexdist = INIT0[CHIP] ? 0 : 8; SCM0[2].awoo[CHIP][2] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][2])+(INIT0[CHIP]?0:((SCM1[2].d[CHIP][2]>>32)!=0xffffffff && (SCM1[2].d[CHIP][2]>>32)>=(SCM0[2].d[CHIP][2]>>32))?mexdist:0); adr = (Uint)(SCM0[2].awoo[CHIP][2] + offs); load64 = *(Ull*)(adr&~7LL); if ((adr&7) == 0) SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64; else if (!emax6_unaligned_load_valid) { /* BR[][][1] */ emax6_unaligned_load_valid = 1; emax6_unaligned_load_high = load64; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = load64 >> (adr&7)*8; } else { /* BR[][][0] */ emax6_unaligned_load_valid = 0; SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8] = emax6_unaligned_load_high << (8-(adr&7))*8 | load64 >> (adr&7)*8; } SCM1[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9]; SCM0[2].d[CHIP][2] = SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8]; } { union { Uint i; float f; } f3, f2, f1, f0; Ull t3, t2, t1, t0, ex1, ex2, ex3, ex4, ex5, c1, c0, ex1_outd, ex2_outd; ex1 = exm(!1||(INIT1[CHIP]&&INIT0[CHIP])||((1&1)&&INIT0[CHIP]) ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][1] : SCAR[2].r[CHIP][0], 0); ex2 = exm(((1&2)&&!INIT0[CHIP]) ? 0 : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][9], 0); ex3 = exm(SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][8], 0); f1.i = (Uint)(ex1); f2.i = (Uint)(ex2>>32); f3.i = (Uint)(ex3>>32); if (f2.i != -1 && f2.i == f3.i) { f2.i = (Uint)(ex2); f3.i = (Uint)(ex3); f0.f = f1.f + (f2.f * f3.f); } else { f0.f = f1.f; } t0 = f0.i; ex1_outd = t0; ex2_outd = ex1_outd; SCAR[2].r[CHIP][0] = ex2_outd; } { Ull cs0, cs1, cs2, cs3, cex, base, offs, adr, mexdist; cex = 3; base = (!(2&1)||INIT0[CHIP]) ? ((2&2)?SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][0]:SCM0[2].b[CHIP][0]) : SCM0[2].awoo[CHIP][0]; offs = eam(0 ? SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6] : SCM0[2].o[CHIP][0], 14); mexdist = INIT0[CHIP] ? 0 : 0; SCM0[2].awoo[CHIP][0] = (Ull)(INIT0[CHIP]?base:SCM0[2].awoo[CHIP][0]); adr = (Uint)(SCM0[2].awoo[CHIP][0] + offs); if (cex &1) *(Uint*)(adr&~3LL) = (1==1? SCAR[2].r[CHIP][0] : SCBR[2].r[CHIP][SCBR[2].enq[CHIP]][6]); } uLOOP[CHIP]--; SCBR[2].enq[CHIP] = 1-SCBR[2].enq[CHIP]; } } } 上のIMAXコードは4サイクルで全体を実行 逆コンパイルしC言語に戻すと以下の複雑さ 多機能を無理なくデータパスに収容してこそCGRAは高効率 mex(OP_CMPA_LE, &b0[h], INIT0?b:b0[h], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mex(OP_CMPA_GE, &a0[h][CHIP], INIT0?a[h][CHIP]:a0[h][CHIP], INIT0?0:8, BR[r][2][1], BR[r][2][0]); mop(OP_LDR, 3, &BR[r][2][1], b0[h], bofs, MSK_W1, b, 2*LP*RMGRP, 0, 0, NULL, 2*LP*RMGRP); mop(OP_LDR, 3, &BR[r][2][0], a0[h][CHIP], bofs, MSK_W0, a[h][CHIP], 2*LP, 0, 0, NULL, 2*LP); mop(OP_LDWR, 1, &c00, c0[h][CHIP], oofs, MSK_W0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); exe(OP_CFMA, &c00, INIT0?c00:c00, EXP_H3210, BR[r][2][1], EXP_H3210, BR[r][2][0], EXP_H3210, OP_NOP, 00); mop(OP_STWR, 1, &c00, oofs, c0[h][CHIP], MSK_D0, c[h][CHIP], RMGRP, 0, 1, NULL, RMGRP); IMAXコードと逆コンパイル結果の比較
  10. 10. ① ① ② ② ⑦ ⑦ ⑨ ⑨ ⑤ ⑧ ⑤ ⑥ ⑥ ⑧ ④ ③ ⑩ ⑪ オフセット加算 アドレスマスク操作 読み出し結果 B42 読み出し結果 A00 疎行列と同様、読み出し結果の大小関係に従い、 1次元配列内の異なるアドレスA,Bの片側を更新 後続ユニットにアドレスA,Bと、2つの読み出し データを送り、アドレスとデータの各々の大小関 係に従い、いずれかのデータをストアすることに より、LogN段のソートのうち、1段分を実現 ソート全体のLogN段のうち、1段分の ソート結果をローカルメモリにストア ストア先アドレスは単調増加 同時に後続ユニットが、前回の実行結果を前段の ローカルメモリから読み出し、LogN段の次段以降 を担当する。全体として、ローカルメモリをダブル バッファとするパイプライン実行が可能となる。 マージソートの作り方 20220202 10
  11. 11. マージソートの作り方 #define sort_core0(r, rp1, x, MASK_M, In, BE8) ¥ exe(OP_NOP, &AR[r][1], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#1 dmy */¥ exe(OP_ADD, &i, L8, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_AND, MASK_M, OP_NOP, 0LL); /* stage#1 i = L8&M */¥ exe(OP_NOP, &AR[rp1][3], 0LL, EXP_H3210, 0LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#2 dmy */¥ exe(OP_ADD, &base, In, EXP_H3210, i, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL) /* stage#2 baseJ = &In[i], baseK = &In[i+BE] */ #define sort_core1(r, rp1, x, In, Ilen, BE8, Buf, Out, Olen) ¥ mex(OP_CMPA_LE, &J[x], INIT0?0LL:J[x], INIT0?0LL:8LL, OP_CMPA_GE, &K[x], INIT0?BE8:K[x], INIT0?0LL:8LL, BE8, BR[r][3][1], BR[r][3][0]); /* stage#3 */¥ mop(OP_LDR, 3, &BR[r][3][1], J[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[2]確定 LD実行はcol2*//* stage#3 */¥ mop(OP_LDR, 3, &BR[r][3][0], K[x], base, MSK_D0, In, Ilen, 0, 0, NULL, Ilen);/*LMM[1]間借り LD実行はcol2*//* stage#3 */¥ exe(OP_CMP_LT, &cc0, J[x], EXP_H1010, BE8, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* J[x]<BE8 */ /* stage#4 */¥ exe(OP_CMP_LT, &cc1, K[x], EXP_H1010, BE8*2, EXP_H1010, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* K[x]<BE8 */ /* stage#4 */¥ exe(OP_CMP_LT, &cc2, BR[r][3][1], EXP_H3232, BR[r][3][0], EXP_H3232, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0);/* *J<*K */ /* stage#4 */¥ cex(OP_CEXE, &ex0, 0, cc2, cc1, cc0, 0x00a2); /* if (( cc2 && cc1 && cc0) || (!cc1 && cc0)) 7,5,1 0x00a2 *//* stage#5 */¥ mop(OP_STR, ex0, &BR[r][3][1], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen);/*LMM[1]間借り LD実行はcol2*//* stage#5 */¥ cex(OP_CEXE, &ex1, 0, cc2, cc1, cc0, 0x004c); /* if ((!cc2 && cc1 && cc0) || ( cc1 && !cc0)) 6,3,2 0x004c *//* stage#5 */¥ mop(OP_STR, ex1, &BR[r][3][0], Buf, L8, MSK_W0, Out, Olen, 0, 0, NULL, Olen) /*LMM[1]間借り LD実行はcol2*//* stage#5 */ for (Pipeline=0; Pipeline<NumBits; Pipeline++) { for (Lmmrotate=0; Lmmrotate<NumBits*2; Lmmrotate++) Buf[Lmmrotate] = &pseudoLMM[NumSamples*((Lmmrotate+NumBits*2-Pipeline)%(NumBits*2))]; //EMAX5A begin pipeline mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT0=1,LOOP0=NumSamples,L8=0LL<<32|(0-8LL)&0xffffffff; LOOP0--; INIT0=0) { /* NumSamples<=4096 */ exe(OP_ADD, &L8, L8, EXP_H3210, 0LL<<32|8LL, EXP_H3210, 0LL, EXP_H3210, OP_NOP, 0LL, OP_NOP, 0LL); /* stage#0 */ #if (H==256) sort_core0( 1, 2, 0, 0xfffffffffffffff0LL, In, 8LL); /* stage#1-2 */ sort_core1( 3, 4, 0, In, NumSamples2, 8LL, Buf[0], Buf[1], 0LL); /* stage#3-5 */ sort_core0( 3, 4, 1, 0xffffffffffffffe0LL, Buf[1], 16LL); /* stage#3-4 */ sort_core1( 5, 6, 1, Buf[1], 0LL, 16LL, Buf[2], Buf[3], 0LL); /* stage#5-7 */ sort_core0( 5, 6, 2, 0xffffffffffffffc0LL, Buf[3], 32LL); /* stage#5-6 */ sort_core1( 7, 8, 2, Buf[3], 0LL, 32LL, Buf[4], Buf[5], 0LL); /* stage#7-9 */ sort_core0( 7, 8, 3, 0xffffffffffffff80LL, Buf[5], 64LL); /* stage#7-8 */ sort_core1( 9, 10, 3, Buf[5], 0LL, 64LL, Buf[6], Buf[7], 0LL); /* stage#9-11 */ sort_core0( 9, 10, 4, 0xffffffffffffff00LL, Buf[7], 128LL); /* stage#9-10 */ sort_core1(11, 12, 4, Buf[7], 0LL, 128LL, Buf[8], Buf[9], 0LL); /* stage#11-13 */ sort_core0(11, 12, 5, 0xfffffffffffffe00LL, Buf[9], 256LL); /* stage#11-12 */ sort_core1(13, 14, 5, Buf[9], 0LL, 256LL, Buf[10], Buf[11],0LL); /* stage#13-15 */ sort_core0(13, 14, 6, 0xfffffffffffffc00LL, Buf[11], 512LL); /* stage#13-14 */ sort_core1(15, 16, 6, Buf[11], 0LL, 512LL, Buf[12], Buf[13],0LL); /* stage#15-17 */ sort_core0(15, 16, 7, 0xfffffffffffff800LL, Buf[13], 1024LL); /* stage#15-16 */ sort_core1(17, 18, 7, Buf[13], 0LL, 1024LL, Out, Out, NumSamples2); /* stage#17-19 */ #endif } //EMAX5A end } //EMAX5A drain_dirty_lmm } 20220202 11
  12. 12. 疎行列と同様、 読み出し結果の 大小関係に従い、 1次元配列内の 異なるアドレス A,Bの片側を更 新 後続ユニットにアドレスA,Bと、2つの読み出しデータを送り、アドレスとデータの各々の大小関 係に従い、いずれかのデータをストアすることにより、LogN段のソートのうち、1段分を実現 ストア先アドレスは単調増加 ソート全体のLogN段のうち、1段分のソート結果をローカルメモリにストア アドレスA アドレスB データB データA 疎行列と同様、 読み出し結果の 大小関係に従い、 1次元配列内の 異なるアドレス A,Bの片側を更 新 同一物理メモリ上で、計算結果を次に渡す マージソートのコンパイル結果 20220202 12
  13. 13. おまけ。疎行列圧縮 count0 = 0; for (row=0; row<M1; row++) { for (col=0; col<M2; col++) { if (A32_0[row*M2+col] == 0) continue; if (count0 >= M1*M2) continue; A32_P[count0].d = A32_0[row*M2+col]; A32_P[count0].x = row*M2+col; count0++; } } *Bas1P = B32_P-1; /* end of B32_0 */ for (i=0; i<M1; i+=RMGRP) { r1 = (Ull)(i*M2-1)<<32; ibase0 = B32_0+i*M2; itop0 = B32_0+i*M2; itop1 = itop0+RMGRP*M2; obase0 = *Bas1P; /* end of B32_0 */ otop1 = otop0; otop0 = *Bas1P+8; /* top of B32_P */ //with-prefetch/post-drain //EMAX5A begin imax mapdist=0 for (CHIP=0; CHIP<NCHIP; CHIP++) { for (INIT1=1,LOOP1=RMGRP,rofs=0; LOOP1--; INIT1=0) { for (INIT0=1,LOOP0=M2,cofs=0; LOOP0--; INIT0=0) { mop(OP_LDWR, 1, &r0, ibase0++, 0, MSK_D0, itop0, M2*RMGRP, 0, 0, itop1, M2*RMGRP); exe(OP_ADD, &r1, r1, EXP_H3210, 0x100000000LL, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_NOP, &std, r1, EXP_H3210, 0, EXP_H3210, 0, EXP_H3210, OP_OR, r0, OP_NOP, 0LL); exe(OP_CMP_EQ, &cc0, r0, EXP_H1010, 0x00000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_CMP_EQ, &cc1, r0, EXP_H1010, 0x80000000LL, EXP_H1010, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_NOP, &cc2, cc0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_OR, cc1, OP_NOP, 0LL); exe(OP_CMOV, &oofs, cc2, EXP_H3210, 0, EXP_H3210, 8, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); exe(OP_ADD, &obase0, obase0, EXP_H3210, oofs, EXP_H3210, 0, EXP_H3210, OP_NOP, 0, OP_NOP, 0LL); mop(OP_STR, 3, &obase0, Bas1P, 0, MSK_D0, Bas1P, 2, 0, 0, NULL, 2); exe(OP_NOP, &AR[5][0], 0, EXP_H3210, 0, EXP_H3210, 0, EXP_H1010, OP_NOP, 0, OP_NOP, 0LL); cex(OP_CEXE, &ex0, 0, 0, 0, cc2, 0x0001); mop(OP_STR, ex0, &std, obase0, 0, MSK_D0, otop0, LP*2*RMGRP, 0, 0, otop1, LP*2*RMGRP); } } } //EMAX5A end //EMAX5A drain_dirty_lmm } 20220202 13
  14. 14. 20220202 14 今回のおさらい

Notes de l'éditeur

  • 様々なアプリケーションを取りあげて、アイマックスのポテンシャルを説明するシリーズです。第8回は、そ行列計算とソートです。
  • 最近では、圧縮されたそ行列を扱うプログラムも増えてきました。対応できるCGRAしか生き残れません。
  • アイマックスでは、みつ行列積は縦方向に、そ行列積は横方向にマッピングします。こんな感じで、自在に対応することができます。
  • そ行列計算でも、マージソートでも、データを比較して、大小関係に基づいて、次に見るメモリアドレスを変更する機能が必要です。うえのそぎょうれつは、要素の左に要素番号、右にあたいが入っています。あたいがゼロの要素は、掛け算しても無駄なので、このようなあっしゅく形式を使って、メモリと計算時間を節約します。要素番号が同じもの同士をさがして、掛け算するためには、メモリからロードした要素番号を比較して、小さいほうを先に進める機能が必要です。下のマージソートでは、要素の左にあたい、右に付加情報がはいっています。この場合も、あたいを比較して、小さいほうを出力して、アドレスを先に進める機能が必要です。
  • ふつうのCGRAには望むべくもない機能です。でも、アイマックスには、各ユニットの、デュアルポートローカルメモリに、そ行列にも、マージソートにも使える、デュアルアドレス同調機能がついています。これは、5個、または、10個のリングデータパスを、知恵の輪のように組み合わせて、最大性能を出す仕掛けです。もし、理解できたら、あなたも、すごいCGRAを開発できることでしょう。
  • これは、5個のリングデータパスを組み合わせた、そ行列計算のデータフローです。一度に1要素を計算できる、簡単なほうです。
  • 実際のコードは、上のように書きます。タイミングチャートは下の図です。タイミングチャートの横軸は時間を、縦軸はアイマックス内部のレジスタやメモリの名前をあらわしていて、同じ時間に2つ重なっていたら、それは実行できないコードです。時間軸上の波形は1クロックずつ仕切られていて、アイマックスは、この単位で動作します。コードの色と、チャート中の色が対応しています。これを見ると、矛盾なくアイマックスが動作すること、また、ハードウェアが休むことなく動作していることがわかります。でも、まだ隙間があります。
  • ということで、プログラムを上のように書きなおすと、10個のリングデータパスに増えて、スループットが2倍になります。これで、ハードウェアがめいっぱい動作します。
  • 参考までに、5個のリングデータパスを組み合わせた、上の7行のコードは、アイマックスでは、4サイクルでパイプライン実行します。60ユニットを使うと、さらに60倍の性能です。下は、同じプログラムをノイマン型コンピュータ向けに自動変換、つまり、逆コンパイルしたプログラムです。とても長いプログラムになりました。これは4サイクルでは到底実行できません。アイマックスは、多くの機能をコンパクトかつ巧妙にデータパスに埋め込んで、効率良く計算する仕組みであることがわかります。単に、CGRAにしたからできるというものではありません。例えるなら、ノイマン型コンピュータは都心の有名大型デパート、ふつうのCGRAはコンビニ、アイマックスは秋葉原高架下の超高密度電気街といったところです。
  • 次は、マージソートです。そ行列の場合、1つのユニットで行列積計算を完結できました。マージソートの場合は、次のユニットと組み合わせて、ソート結果をストアします。そ行列のデータフローに、少し足すだけで、マージソートのできあがりです。
  • プログラムは、こういう具合に書きます。今までの使い方と違って、中間の、ソート結果を書き込むローカルメモリは、外部メモリとのやりとりは行わず、ユニット間で、ダブルバッファの役割を果たします。赤字部分は、条件付きストアを使って、ソートしている部分です。3つのCMPと、3つの比較結果を巧妙に組み合わせて、コンパクトなコードにしています。どうしてこれで、マージソートができるのか、自分で、よく考えましょう。
  • コンパイル結果です。2つのユニットで、N要素のマージソート1段分を実行します。ソート結果は、後続のユニットが受け取り、次のN要素のソートを実行します。つまり、計算量、オーダーNログNのマージソートを、ろぐN段のユニットでパイプライン実行していることになります。アイマックスのマージソートの計算速度は、オーダーNということですね。28ユニットを使うと4096要素、64ユニットを使うと、理論上は10億要素までソートできます。理論上といったのは、ローカルメモリも16ギガバイトあればということです。実際には、128KBくらいなので、今のプログラムのままでは、1万6千要素が限界です。
  • おまけ。アイマックスは、0を含む密行列を、圧縮形式に変換することもできます。赤枠は、CPUのコード、左は、アイマックスのコードです。赤字部分の比較結果を使って、青字の条件付きストアを実行することで、行列を圧縮します。同時に、緑のストアは、圧縮後の要素数を出力します。
  • 今回は、そ行列計算とマージソートを題材に、デュアルアドレス同調機能と、ローカルメモリのダブルバッファ機能を説明しました。では、今回はここまでです。おつかれさま。

×