From 7bbe31b7427f0d849d83be071de7a69109029909 Mon Sep 17 00:00:00 2001 From: kerwinair Date: Fri, 21 Aug 2026 11:46:13 +0800 Subject: [PATCH 1/7] feat(vpto): add sdma_gm_gm with session-template expansion Add pto.sdma_gm_gm as a Layer-2 micro-op that copies between GM ranges from an ordinary AICore kernel. The session is a stack-local struct filled by pto.session_init from a host-written GM template; field layout is shared through AsyncSessionABI.h. A2/A3 post SQEs and ring the doorbell through UB with a byte-granular MTE store. Handwritten pto.st_dev is rejected on A2/A3; A5 may use it for the doorbell. A5 uses the engine for local copies and GET. Remote PUT on A5 is expanded to a chunked GM-to-UB-to-GM copy, because that generation cannot write remotely through SDMA. Runtime cases cover local, peer PUT, peer GET, and multicore transfers. Host workspace helpers stay in the test tree. ISA chapter 19 documents the current ops. The broader comm programming model stays in docs/designs/; URMA/RDMA, pointer remote attributes, and fused notify are not in the current IR. --- docs/designs/assets/fig1-topology.png | Bin 0 -> 581993 bytes docs/designs/assets/fig2-shared-memory.png | Bin 0 -> 244848 bytes docs/designs/vpto-comm-model-design.md | 168 +++++ docs/isa/micro-isa/18-special-scalar.md | 4 +- docs/isa/micro-isa/19-async-comm.md | 189 +++++ docs/vpto-spec.md | 5 +- include/PTO/IR/VPTOOps.td | 96 +++ include/PTO/Support/AsyncSessionABI.h | 417 +++++++++++ lib/PTO/IR/VPTO.cpp | 136 ++++ lib/PTO/Transforms/VPTOExpandWrapperOps.cpp | 544 +++++++++++++- lib/PTO/Transforms/VPTOLLVMEmitter.cpp | 193 ++++- .../Transforms/VPTOLLVMEmitterDispatcher.cpp | 29 +- test/comm/AsyncWorkspace.h | 678 ++++++++++++++++++ test/comm/HcclWindows.h | 270 +++++++ test/lit/vpto/aicore_ld_st_dev_invalid.pto | 14 +- test/lit/vpto/aicore_ld_st_dev_vpto_llvm.pto | 3 + test/lit/vpto/async_sdma_gm_gm.pto | 154 ++++ .../lit/vpto/async_sdma_gm_gm_a5_soft_put.pto | 139 ++++ test/lit/vpto/async_session_init.pto | 57 ++ .../async-comm/sdma-gm-gm-local/kernel.pto | 40 ++ .../async-comm/sdma-gm-gm-local/launch.cpp | 36 + .../async-comm/sdma-gm-gm-local/main.cpp | 232 ++++++ .../cases/async-comm/sdma-gm-gm-local/run.sh | 133 ++++ .../sdma-gm-gm-multicore/kernel.pto | 58 ++ .../sdma-gm-gm-multicore/launch.cpp | 36 + .../async-comm/sdma-gm-gm-multicore/main.cpp | 208 ++++++ .../async-comm/sdma-gm-gm-multicore/run.sh | 133 ++++ .../async-comm/sdma-gm-gm-peer-get/kernel.pto | 41 ++ .../async-comm/sdma-gm-gm-peer-get/launch.cpp | 37 + .../async-comm/sdma-gm-gm-peer-get/main.cpp | 296 ++++++++ .../async-comm/sdma-gm-gm-peer-get/run.sh | 140 ++++ .../async-comm/sdma-gm-gm-peer-put/kernel.pto | 40 ++ .../async-comm/sdma-gm-gm-peer-put/launch.cpp | 36 + .../async-comm/sdma-gm-gm-peer-put/main.cpp | 270 +++++++ .../async-comm/sdma-gm-gm-peer-put/run.sh | 132 ++++ 35 files changed, 4941 insertions(+), 23 deletions(-) create mode 100644 docs/designs/assets/fig1-topology.png create mode 100644 docs/designs/assets/fig2-shared-memory.png create mode 100644 docs/designs/vpto-comm-model-design.md create mode 100644 docs/isa/micro-isa/19-async-comm.md create mode 100644 include/PTO/Support/AsyncSessionABI.h create mode 100644 test/comm/AsyncWorkspace.h create mode 100644 test/comm/HcclWindows.h create mode 100644 test/lit/vpto/async_sdma_gm_gm.pto create mode 100644 test/lit/vpto/async_sdma_gm_gm_a5_soft_put.pto create mode 100644 test/lit/vpto/async_session_init.pto create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp create mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp create mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp create mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp create mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp create mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh diff --git a/docs/designs/assets/fig1-topology.png b/docs/designs/assets/fig1-topology.png new file mode 100644 index 0000000000000000000000000000000000000000..5e570cbbeaffd8af61aa06fbb90171918cae5972 GIT binary patch literal 581993 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:qbsH723IbANMLb=8X-y}txUqTSFahD}c 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≪b42t<| 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

` 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Ƒ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 z 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 cWZ7&&r9Xn-x(ac*> zYWy!>S&d70d{9Y46W_^S6oa0Fa!o!y?J(=%*{+N*Sk!G=!fi*agS-PDkIOg793*E~ zPCt4-`Y);o{5rniWPF6=2KM-=4_AZNHw7buHyVrG0Fcipp8r`UCPG{*oBFg}IW_uz zYN(J{khI6SrrT{`ox6RCxrJiI<7XSQs}u3 zZ}OYB|B9bl^u>a+EA8;kYX4oFryD65x^xnCxaID#iU#z4=V(VloTl*n@+%YSA|VadjfAZ@hMZTt%6T7F6F@j>}NSb$|m zSLo4aXxv{29qVEXhPG_U<5M15_q_k%Vmq(`yOPO1p_2JA?$^`)^>0Sk+S}WoQROr? zjk=A6P(uyv}&1Z9z?tV|1jbRS!+$y{Ok)YC2IzebT_JkARVgf0RH0ZC)Bf zee}R2rwnjzq|4AbCN^fQkQ-5}eq&e?a;jq|qT+(}?V`{({>z8c%cTTP($aip$>{2 z&og=AJG0VA@=fU9SQyeN|1jbC2o*GOzyIJ@-I|QpClg~j$*QGB(fPyK{HXoJM2@fC z3WTJCtPd;Be|_cevrHK{kI-T^fIh&@nzhhxui=RE;E7s9Sxcv%#n2lz<)n}Ss#XYT zm_&IAsn_0LpI$~zWc~Yt<{MX8MVF}~@VF-bj!zNfRD8(9pm}QWq4O1cfu3tQEH5LA4H%t@|8K!54)(!DR+Xf!ESOHvX@-a zuy@}POjS-k5kwd77V3gS#k_sPQOQ-dxYLl(X$`0y5O*W^Oow(0oL9Xq@mwY9-)8RS z0vC#DFij;%zwr?8R(zg2r^BYysAOj8FL+Js=Txul_fe05;sl`8>1YdPj?Me{K>fzI zGl#XS-Wz%RN($tCywG0O>09{rQvn^yR<4|q>W+WZ*^UmVBx~0$Fbd$Npl5$u&>K5= zkyTVFg}}#JRq{$Dvp*E`(qrwME_AL7a-LFCx^+U<0xiZ%Mb^vNorsGKY{#UK-l*2f z+)Z>87u+2ZObNCNySEB5f7YuA_Hk2AIZcgrFikmKCM~cC(&Z!fb(MXNqUG3`@clFZ zc{Z;x)(5k1cs~HKhq>jMhqr|*MNIlrW?t`XP*L;)G4#g9c%{{lenoC!Ta)Yh?CGGp zkc87i%U;Hy2bv6t!}Dxk6WF&4@&{$jd$(>p4)hX*SoK7CaE`uN+>dPJc^)TeDFc# z>Yj(fv)at~y3Duk$dmz4>K{VUkwCyK_9H3mDH=o|z|8VCB;8kodTgD*!7t{bu$caE zZW3#F(TkR~O}o^t^4*507@Mvr6M-;=a_C>|%l8p{kP2fIsn8;ahZzR(-P_T|9VM3g zRPaqPkR3@0Rz80=Hfg%Na5jiN*E_R)nD;`HrJ}z78FA+B((5s#^H(J6Q~gZUe_S$%5HNqI(Gs~;6GS)B z(v6bo4QIQE+WsNg0+`>*gmpcGqN1Wlg@Q=OaBzu>tqu+SsZxG?%3p6X?CWa$UqBsB zzkP5l>G_SKt+l&ZyoN#dRWpJ}%{96dk1PT{WRHzyR#)4sLlT_Gf~(sHOMIB9s}|Jv z9)vAI#B!KOf4XbfLTQA5$W~;-;{ZM6Ytw*@JkiLA|6y zZ^kB_W9qW|erXqIbj8Wyn7Jx`jQWQ}TTOXz-LcPTXbA81)C0t;O*iSz20ePxRzhpQ zrBjvsw29%=W}ey5rdNYJYUi5=qa$$;nvH&iwvFGCM;P_DCn+Sxb38CwsQ@ZJ}*%N}hxZV1FJEnz-8$ zzJWDqYvP;F;W&?&)T7O)i6v%1_LUFsr(!KDd$L^WvXvy>xYR{U8lYRvyXFH0HC)i@y87vtPN(ny?@*84TSoWt4v9ay{XdP%-TbEsE`-6 zp~>hsQ@1is2ALarlQA5#;o zjN-&Fb64Z>Y29Yb@{9_qFJJ63YjVXVOA(!yj-~$40&j5skCHRE=M&*QG#kd9UlbesZ@0yKy=^AbmF6QW6W(ulM+a8csP9y*{!mQLVs+HB zsaJ>K}TA@Tz_$rmW%-;B)}^<)}fkur*n+DUog>{ z@KcD%m7fzT#j4Q4){$SX+f}QlCbGg*Ms$f21%Vfumh{?-jYqmCR;N#hOndtGZ?ajx z6b%Q=V8w@@Cu&e6@9=t-MNk7lB0(z9Yqu=F32892gPAeSw7a(mL4)uZ;C&mW>Pjy_=W)hzy zU|#huRm-Y-xTxl!bvN15>(Mhw!qLWDYO=F4jRcseA{H>f19|HZk4O*#A zc9xB8Y*Wg;z~SKWfmJM|+3&6|N4a%o2V$QZJ!Wqm{ekaFeNaqpzCF0$CW=v2rsP1a zS2(k1S|MED0`@$MieD8<$f&*{EV}AwNxzqvr}lmsZsS4I1BSBsOX&e7!Z|^3SpAuRLNSUm|dvu=3Trr1;!$ zWvo%8+tO)I3zZgksaLDERQ`CcgEvz6X=XG7u897I^WDw-V4+Rz$dcKSsiDIwtQ;H* zP%k#oABwSBUAk6)nh4#0-JS@v$%+`p@iu_-NINlt&xE1dbcWH8CrV1lWU}*zp>;e{ z>CVOsO_|66&vfHN39i*q^_YdBsM9|<1~%KKhTqK)k^{apMRQ!Da5G!QYqfhWZr{5X zyeqwood*y%K-=IRI*NKXoW3H2f7(j{k-Xvrl2<5n4cfHuvS>Ta-J>0LsgM$6vLBJH ziFDKLDFM0GFwsG#@#COK0o4j?V_mcpKFK_wGPAGJWHWbo@U-jPN7H^5nJ8R)zxKe= z28l5CUM0K4TYb?PTWg(x+8Q`lp*_=Lj|!d;DA?J?qlgR3t28dCO~Q7|9e-+yNrGjXgP;$`>Em}Ly_CAolN!W{TJ_3~-v;WYh z#pB8QQPbSwE)M>pH}a__*Qm>=tWF&YkT2Op%NUTfFoeDdUOilA>g9ulhZlLRe+8N6 z89kl@&{k&3I@9e$OIb@9(NZSAXwf}7Or@(O1`w;NRhN+dxb2^AI8v4jP`V>5JFEuh z3%kXAW`tf$YXQJqZ(DO%k(a*xy{`L*U)`!S2TGtTh-k%_xrn&>+NDzd#2oA5)0N~K zO;+1ij?OXgK6@c!uo+&oy5+{%l)LIoRq>VGWv*qwtyiclVjU%eS*=9P*<+ByymDCS&5a{<9A)z zC3YDAgM?`}M8Lqfa1r7H(wm9>`!Vn!Voi+uv+F`F6|D!;v|Id2i*hMfrZMK|(}SW8 z7-CzKffjxmx@GV9T7;JapoLg7Pzj{D4)(*h6b(2)<5K84*Q57LS2?D1tej-G(34^q zf9B`c(gDyjqnwe&F*B2LAWT>gTA+LFpQR(3V zOfjD1mMPt8P{1wt;DDg`*Cf!5%Sb5mY8$LzmVr!w%Y2-qw$t`opr7TPzT;~UIa=U{O4OD_4l}BN12{y2Ab3e-hl(YDiZM^<_Aoy$JfX?>W+Vj zCBwQBIn(iWp$4i zkVr}nK^@WlKpTU8J{iwb4H+*m#<9Q_3C1T5M>%UyN%k7n&@WATf2}dyG(#`vZD=^p zWO~mJ^42y%STQf!2&*M`e@!eEp~jN}|GCW$9a}U)w>}pbN0sfC*<2oNxmxaV2aT76 z(KrQ7#)YN*hbBuFfum%gy?vwMSY-<~`{`Ku;?_|e&sRDo7 zz8Ji=_3KDw4)B40%k}V}sA3vV%U|KKPo+&_7Z8D^CI^0Y~m~u|pNCr#3`S9`QdQ~a5Zr>K#5Rz|$ zdQLyPipQ2+gT}OV?@SShWOr&VW)6VJiDw6z@zWjYt^pB;J0|Z; zm5;;?omZ4NQ#A(?q4@|UPub0@;xp~)+ODM3MhWvGkhF@Q6Ch28az`3m)Y3`Iiu&H(+8?)@)q@B?^(HmNkb?F8-kBPXVtgJCiR7kiOb+Xo z-gS`HKvTUux-C_G8|YZiv6vkqty$?};pGNpy+W1E+pqjv%+0@{8jL&w{pfd-bTb6> zW2&R)go^tdexip|a(%@MLz)U|AUcgOE!M3tmyG+yuMh0s#g2k3R_3lDO)^h__Rb>+ zYa%Q1CxUN-4Br5uV5iOX7MeDnqc3tJEg26t8c$8l7IvfFn0XDW)(qTRG^6XXA_7(Z z`1T@$HH+kyJ$2FcQDZ|7k7GI zK&Pw9V6yN^;@^*flizcETO8j`dK3wb?hN2Q7Glp_0UKNEr>kt&+BtwbJJCe#CA1Yl z6a(bs=NE~nK9Ck=Xc*S`Atc*-T4h%n-77Dicd{kC7;()v?c}p2O-wOt3~tW6r&TLj zN@~%{vH|I?rbwvnyoLW`4Esj}!jX~r1Wbm@Ge8|1Yf`e2<= zh71nShpJE9N9`Dh5-i7(ns%0OOyVuyTx@+|=3!s&-?-Nw^|5;?8N|QP1erYOMv#^v zfhd&EaH~Ye17x|K*L^3XT4T-9=gl}Ebjrn} zLr)A2n8#?9N88{FYy2Yk*x{+;D-BE)4`3!AT3v?Wk9PBc^Z|s2fv@wx%N2q&YLH3s0*TUXxm@n+efEq#M{h$>1{!D z5!AzbmEN&c93)*j<0lihb$SBl{6IcFUJuP*noDgJx2NFi7`0xOOn2vug|X;sdY;sG za4VYsi5lK{E<=L8!*foq+WB=j*X=PPUNhSGu4T^D2bd43TBXyfHX_MmTn=NhK;6Lmh*x zrZ;Cm({vC4LmX-|FOGK$0T1r_E&&yR%gLO*62{=cQAq@5nS*{ep8k5Rv!7}ZLz0l( z5C)z#aB~sqf}8dxb|}hjQJ3!YL{o{VTaoLhGDqqh?_SD}`a@S_IO8K0pKGj(j8-W6 zfmq_6O$!IfNRVYM?ep5;S89ei0~0qGVAU3pn3NbktGpW8(Zaz|INUJWg^ zfIWda(yV0Eciv7lPv7+;x#{K!^i*BHnt*ZWgcj(HDORxGj!U*6V2L)T7;f4@E-63- z(4!V(0Vd)VAcJt%7SA&_&c8B0Fw){<(BLnvS8IcW50}VV&rfZ@xJv?h7qdqR`42fN#b68laR_*5gsm6{(*A`e(1QL@G*!MiGF9MA zvNFtjNi*Wg?R z%n{!2rq#@hyD;tuun@U0JC;s1@{<$zj;e9;z@(O@64_9__4#(rcErkHEA1m)#-oIl zqjdY5m(+iZi8!@SJCl5?#1awTrhMiTxpCYs|ab)&J@~!DEcJ%8Rwd$ zPLB&t$)Ji!k>6N@)MeZ(W1#d-m2*` zOHIzE6Nprd7u{$Etp{`@_uoedh{M)n3A8bm&jYwd8t~EQxC*CpwW|sR+;S_a&uq@S zc1vOWr|xayM`oOfJ&95!=90*bGC|tW5!;I$BCIEzH?V{X4C!Zqv-pE$P=C;gPfEG? z#d~ZlY_xj_f)wUqFuM|zH9qQ(swrwO9efYH@=cgVpoHMuZI1)zf97(NSWCTZEHt{MT^$@{h^ zC8?EO3#Fu3aZq(N4foQtyDn8xw>4pobAvc zqtQZdytP$T>VG~34H^-U&+0rnL*g8nOE7Qo^B3R17WYO{T-0>xjGJ#PDe5QVgFX_39d zeANb0y+;<9bbTWN;Tb)hRl4!w{DVi2CPYX!<^4=+j>|^ z`0{j9;MK78cbHpWpp}=zs>Few8h^kTSIk`=l)YKuS73s`g8w`EUH1`wA&($Q#a7S0VtaPEM< zfXP+J4uD=uEWe4uqU3tNGc5b{!EaNuFAYDK=}y;-*NReu;SW9e8CVg4K$4;MCX?X+ zS$)u?>}(6@c)`yh7Y#As(sjIT#(1~hyS?>V(+pa%~gP%;Y^ zKYBp2Y)50Pv*(%Cwp{m-1=MolJ6zv?DT5A~xu~6W7KksKeXB8%%^k+Ksd1AM5bJNO@-TZ)USFrtU(qAwcF>_m# z9wzjT&1>&jKS3S8G3cVIa0Z}|pOKz*I;YQRT~#`w^fxJ8V3-}7|BEwacv$AE#VeDqQ-Ch z6Fgq@-_3b050&kArnz(-kt9%`)b~QY=q-;>KNHpSt(po@a!g`&^`8>hFJ44Aw-Evl^!fEcSUj!yWQ>pdMS|pg=^oko1rb{e}uiCOz(~qaZxzVAto2sQ^;=H zRZ;~+rYLUP^_Ac`U+%t!5c8cUfh^?X6F@PyW+UDx>T?}oBG9CE z-4Va&>4pY&a0L&GOV765BDc-W7KwUGz4+prT*51@gmJk9j9M2 z1)nO3tub!SYE+$v;y~nZ`x%D&@RK4J+exKQ{kbM5?i_z#?+%FWH`i^y&uPRQ+Cv1D zXtxSbC7hZ$+_3`&Ou38hS`x>d7CRP^Ol+#!R8236&2Hi6)tVi23Uja9(@dx_qA+Wl z(*6-!U;!bEVN9gzP4A)?Us>os)vQ*f*L!|@9mHdq7o?>ep2&p@6sQ!eI~MxKblqYE ze<6o^=GgnPgV}o9`9VR@TvbYabU9f8L;M2GJaEwh+@ct4O+Vd=DzpXm6z$Uxcb^8sP!h3~R_KY~t-a<`;7 zN)`ZZO~*$zsaQ}rB@03+D0s&Yd>dwJbqepKMD^)C*>VMzU|0dN<`X@(Zg2QT2#eI- z31vUR(8^mhmEo;Lf%A?1`zSWX+hpxk<$6Ol2K1V$oG;6Uzej^j?}{7KChna7pi33L zX0bC~Qat78EisV-=u2kwG25))yGWrIHh!J6u|1>Y*XDGzceJx0Yv__=Ch%dr6&iip}6vtw7K~*RUyvh_~UcW*<9$baYi1EMN|vjD&u};bcI<_9 zcKMz()my#@{tUMfHtF#ql^VOI_y|S)#ulrbe_Vy71*P3kmurXg3>X-mZ&rna^BSd( z0%$wN238^i@7T<=UT=t~(0Gm^X>Sz4Dm}Hcl|^ojA>cw53wQjdm|SarK~a0?Aj0{B za@j=ef#_Kj7}>!a0)M|Fu4$2KjWvZ7qJ~l#>bf=1Iz(wCO7_kq+O}4DWRboxGircf9iT=4rbYJt$nU9 ztRWo~1aT8BaVIGZcY2CGLHcL9;>9ER=lH+$C+MbTFsOB=YVtNTflZXtGM%)NY{~!t z5O(PiN*O^7-groSUQEoc0p45!3BHht-2yzkD72Jy#|g2ix%CK|PyW#uUe+v76nTX_ z^+y`6_R&QgP$Ge=!hBD#+E*8R3V6&ZrE7rNHug&-I81=!9;2ahy4q#d(z8EPcR;!7 z_-jURFOdruF97&w-=&vI#@$@%g#zs*^Ygm1-N`gaJt2jR)}X)s#8Vlx>@CFWh3uxU z6|{i&JsQ42lhE4r>3AWCEOC-q1E)Pip!5ZMIJK>!vS7`1}0N+{R<54l}%C+q& z^x9*EKBY7TPWKZ)Q$!TMzwPc=!4kAq6=~c4m+eFVLJj&a+y7CU#H)vp-QHwMPYHNq zhf(cmnyGjGe36tKG8f6D8WAoYSu9_V{mslJcx=?}hPc%sXL_9d|D$$~|JV9ZvZ{80 z-+|U&wcxAzdqWH84z*uy=n7(|&Hb0<(C&Mu3WJRWT&_EfCUW#w&he+RFcfLWRIeG6 z2OK>)IYK+p5CV2T9M*_b4SHR_&E;7iR0Oa#5GiQt$rHN&J9ivbD};82Y!~YF(K}7A zRA+J~Bu9eV#`GEOYu(ARABJlm31GRWbk(32<2VP-NXX`XUBBaFn&hXH-dFb%D(4T@ zwKav|0{6#)CKm~fWMr>dBk*e}o#(Feb(`#(mQ-?GRY?ieBUQgc9$^vA(xSAlV}_bM5yZZ_qct12JA{^cBr;L@<|nyuEq-G_cCRlaw$ zWF)TQ0M2dr^+TPo1AMZOop7b98K zdA2e7mCq)LK_UNcbQ{2aa%KMpDj?U`$ntLME3335hivzygt1JRD zS1_54iR=B0R&d%4t?=%yAM4da0i_bIBAqD@O@W{$p^zcfv8CC^PkleLy0=8oWWeNK zU&R7n^%Xp3uWYX`K7wqJ8$(4h?aeL!E*|x={lULqAJ9=0P7i&RasVU4(?NFc=DO>$ zhbeY;4~a}q!S4LSv8_C~jgM2+CIaG0E7;>z+yoBsC^$6{K0Vy&gYIy{N+Phg zcQrhqLZ%B$Y-!5ISb7NeUjFZXD`p6EWxXgs%>Vq*#bW%ILE(HVG9MU8yDz%KioVPP z9@I3Dn&~?~XaAa`Kfgsi zh<eT)UByc?vq-N~A`Yvx-fjj#6haKHX5r%jby5>6xqSfKyA-;g{6h;W!5 z2|T~_o3!^%lT0C{Nj1x6#WziUu*6(I;>35x3%_RpYXkfi>g42kkDWvM+v3aZ{V{vA zVX`12=)m8z6I?*WN|PzPLQ)}Q(?f0w7(6}Cl8@n33cPCI*ufHy)_@vl@BN!>dBEF; zS|VUV7GlcAVka9J>#g4>=6)RptK&1+TLEM)*n3~n;s!J z+nuUQrZE1m^9>-JU4eN~TQO6^7%(V{*kh=vsqO80lkLQzn*cF7+7(2j8~5$I$@9mF zJBSSqmK?4tB@2^K8WahtLqR3anhoF8Da4_B0NC`FdL-H^8XP5sB3(E2C z0P`!2l3gh(59)Q^6QP>l8OfK1s{~weWDCfu_%;RP{9d4g6(8jkov>)Y?XTKPH6VP? z)@8;q!!$98a$bppt6Gok@_e8&0Q{HV0r?FZkaViu2nKEK!M&!fDUR{ha@nFNg$sW! z!F@1uI|Uh0K>Fva!HcCM04kl~HJc6Oa{cY?8{i%dqC7;sS*#8!Nc-V;wBW+bL&m!A z&t(8FxU&>cgVaJFa-mshrj=g6VI_f@(P66z{8@e<$l+&TNwOX7vV+R>ZPbaNloLu* z>CWGG^UbbZFq|o?>v*>UE1ZjlhHE*6JgdSVEWi>uFC7os;Vr_4IbtE0>h4|{GWQc) zjuU;9#3g@(N#Jd&#&2#j;aGEs?6U9gxD(6wURzQJ0*}@E#|bMJ-HJ=@s1-zpWUweeQ=k1fJQGq=OZ$C?MZm0fDZR+4};2MI7?RN4?uT`JA6vy&oECuk7Lssx$K*XS-gsL(|t_cAX$KrVmdr?#X@NYf;=?{off2u(Z1Jou>{P^dsO1$!rZSQgDd z4V5iSYD>1UgXD2gbMcuzUJQIVW<6vA6)m)M)H7TPfrO`&_T>EDPO;w*#0}VFWfNrv zHFDv>bJZI|4sA>2r5@QS_bP?e3l@5c#1bAQ_$;XNGqz(MTn?kX><>ua-kKi}yX$ls z$THF1UhncjhTbkgSPpHqc+z};wA#OHqMCCjZ|u$yu^E+0qwbX716F~)D}9*IUaVcR z*7ij8f@VA+uIGq>m^E=Fv# zQH10`Si2zzt8hE0onq`7|7nWg`~A2OR`A}=MD#b}gi&u`AyySO@Y8}x+YE+cGwkL5 z``1rSLaDs>3zuUEMea~HgKwl&_Om9h_u8^O@W5P$QvJ2h9$u?vk1=)%ldht(HGo?^ zcdqx_v^VU?HiUt^Wn(;CAYB6vSid9nseHhrd?Q4iM^_8MR|$BWjs%e_O35xHju0xQ zpCZ3VY&T*L0G_1R=$~_%L!Cj(y!SKY4h*SE=_i65|HS4KchQ=!e;?4wmh>=`Nu2E_ z?O(8M-*;pTFkP!g4B5ebbsSutN+)(E{O-hiTb_v zNoq)}>MFThA|XNitP1rVPEMHn7in<0wE;M`5(;GCOTE~WFBKKuY3v=M#&6V_rVM@K zKK_(W3R1di`n^i0y@7p`F5lF--b+>;?0U1=2=*Nxm$s^xhTmZ{Vub9M;Zk}0^$iqQ zn${!B`@&e^A~~&MVnBR)*6@l_hE3OU<$hw!?x(2`% z{k=53{Gcsa9!%~2S5K08NQ+hpt{&%?4w{y|-EY280q7#N8HLTE#XdGA3;L5iyZ^X= z@v0a-f>Tfc0-dH^*Fyt(`(N=~=*^!E7ZoFG_I8iGo${!#U5JIjX@t$YGXsnWS>OG+ z(ucu1+%r`JS;%@Feigpw5u=T=x_cAMJo~oVMYKgXstq2fq#fS-B33#z0aJ_Fwn}+% ztI$UtH~y5gQ7Zp7bdW!g*&_7NA^-)3RIbAM1l~-v@MMkQ-n}5JGPsK|GhlRU1sj$i zE-s0d{Rhbr`(9|;?Om^+W4nKx^!M4P&{I*6>fw#0(NfOnT>@J@Ft^^etMCO6zP;?7 zY~B%s7>upOxL?GS6Z|uUyuhpg@rH3uQXUk^9|E`mT+k1aJ-_tl3jrNqJq-)ual@f+ zXa}KD_kA->6RBNInqbWp4yd`A21E&Ps_RPY|7O_$e)x~_&4$0aI@g0=Y(#t2IlVe%Yb*1Lo?e%w$Mr+7<-|xR-Uwp<6 zF$@j_ho8N6=6XVqS4nlr6mBhd7_ z&Ld;B;t20*X*GF-`u&^k%t%-~w6*}`lsvFNBbO)yUpsrl?p=ftKIDF(z?{ShEI~@# z+|uwz*>gwcJJ|jlFob)h4L^?MCn6*6YE|4GQ~e?2>H?j1+K z>;Lt~_CEDL`v8*v_e>(P|A|MoxX1kafFtwqf*ckyZt;2vyXZZTK6)fJHSD zNpgSJ0Ax3hA#Jfjs|o0nF%bJxR6VkOBNs4<0=0Kj#P+{xn=&5P{9et1XyAze)Y$B;Wqz6R;T|9(Hnu^BAupwAE{t}cE`3$I_1_UHS329P#F zWK4-E*}ytV0+ymi3oH-x+Ui9QWO)vBS3mdRm8hW*`&{Q7t0joB&p@wxx|NcisP z96#n4DU&kjhYD1+$auc`EBeo32jAkJpEsu_&90{hyGvz z-*5lh;V|FUuqrA!7Z~&#VcLD`g*DrZ&^wM|@>gDB+Ly$V+{8~ZirYE4cge{5eA@e(e^lHzH00Rf`rlXM1{c^9M6KNzN`+h6^QF3>=%%`L)$(LP; zuVjCbg}mu5@@ko?|5spWMI#53;jwoxe1{L>UiiMtle%ZjqB{gJ+YcXJ={|aZU#6*vi_1_nx1e)QsPN6XfZQpIFxBvgU=`)MV&pPTpRLv2 ze^ccSaTiKGB2g}SwuAlqTrr&_7SD%=9DKYc8`o~iIhU|^9>W~1F^=Ste|xI`pDVc8}p66ntCo> zf%P*XZ?&UFk>5%|9(mp78FF#g&b#e`Cu@&hf!qY)LZ7stZv`Yp8!Jftb@FtmXd?u~w&$j~w7Af3iV{glZL+ldmiZ{|cnBZL;EY za$b$PxPx_Sa;-K+F6d3;TA!hUZI3A%&5eI9_GLc>&zu}9ImUdON4<_)zRr`bN{df* z4pH1b(}{z4 zmX9v+b46=RlLAjek?U6^icG<}y(#D}aC3Ksapz3Gux&yRvA@@QvF-MKWA!A7iwsWW z>h_db*hzEj{1q~?1+U~N-7ys>rAfVzXjx9Nh{q1X!lYU)S;Mc~p^0fXmgBvx3$9VS zj6R?&Fxx#N$`}0MQH$aUbHW?b{bD8`U$7?#(Fw6oKR7pmH%e9&NF*e+snWJQm=ulCQnYGb zl1wYv(eRSDU=*#68$Py=Y&xs4B{O++@`lB$ZW`+ZvynHFj^6eY*kR?5cGch2Sw;Uh zw!SZJ_UX}) zoa91&sqEG#iiDm}TAB4MR?GZ+@R!ft$y-=NVw7McqdJDAV8ZM4lFjUzKwogqD6HwY zP)UHji?ih7+|NCTdZ29=wMMy{^bjl{iky5+lcjo>OoL{t%f)Jqz*z_3AkOT;l0Jml!sX{9sc-!PB zPfpR?wX+-bcs2BwtDl%CeqB_(p+K;qiBE96up>F?{NIzLs8(@rklOP&evR0lHb@Wlr7E22=*E(Qx0*TebT9}h`WaO!JU09^!u_crGAHaPib7I zyvUs6aVC28^^4nn2vmF108m4a=WzUAoel_VOb8XTO^{C0Tc7KT@Ul{SiORk$n)){rvSvG_y)MtR2O&#MC_g`~ zA6@M$&_B<@Ng}J8RZryqTYc>NL#Ix8|4b>-608~2jb{!Mx3bgpE+I=>qBMQ&+qIoH zB1QfayZFE?-Ug1ft10%&{ER9kn<9pO)un6SomhR{j}?DWND>1V}dyxb<)ch?k_!);x_$-77?cZayuyfPwQq#F1NUd5;2bU`{Wm_Il5GBlrlRqB5?h*7S zb8We-JGn5QD0kaVIl^&4W{cJv)Q*(mp1<5Vfl_%;RqwgZ-RjAhs&Ao)G^k*twR;+= zCoELJCvd*|Y1?ZQqSnYzSSV6!tfqdnI4G-=zeh!U17l)nrS`^UqG!VOD+7`E5u!WG zRQ$eBG}Y64z!HPHM4D&9*+t_#4upKa@_vrK5@I;FIOOB~rO4me>znU*dVW@gC}fsa zHBWIc?Pxm$87=H~jSBNK6JkLcz3}c&^6&YD!|o<&dpg#N}_V5hlX4)~KPRTPNmH-P4~BzZcCzPU)WWs^6U+uS4AG z>^yt-cv&`)+vQMqRIO~V*(Pt8)8eqQ)XvsIL}IbISYE_r@9Hdo*U;)fGOQHT>n3vFxIqV)74|U-U&-!>Rn`^Vgf7UBYtr z6}m@pJ@IHAnu*Y}de-WH^s>3}B)5@6R&CGoeG@S=eFrz4IkkSZbCQSJuBHcNJyI19 zsNdoQ^;_6p`<+-IAAT`oOKdY(WHz!UGxk{2@nE9g76&|`5)A1Xdc){@u17CsR$EU+ zb2-{S(*I<9fW(nTsEfi#XKOYDxyIc(Y7A-h#CY}cFA^IL za$8y_ytkQJeokhu&lxtH>&_AuvFD_i8)9Cp5QQKZCUrFN(rtrGeN|VIMs!c={_G81 z_1W~l5*p%0Fh0X979~|)1ZIt-nxE14suixJ+;rB;vFA39yx}#BU|7|7LJS$*Pz6ao zvzZzfjNkm8=}UhmLQ+g6exfl@JM#2Kiof4QJUJOh0d zv6paNx#ZD=Pav`F-(wZ73C)Xh^!Ms^IaZj*OfD!-zjuP)h}QeauQFC~pSbyDdzU_d z#KR=I4RYYtUy!79GRf4t=!&=1{ET2_ODl73Q)eBB(GQuRXD$v#WE+Qnh%5mi&+3up zYrh=t`#tU7E6s2mI{G@#Y^`}VC|$+QizRZYf!^h0gU z?-~{f}%8u{6pS3`&ygx;@X?lPdLB$RR z_)ay}iI!JY5|$PQoH8kMMJ@8g{x^|s1gy4|TH`0g)W6;Cww?GJkqACswJ2j=W7WoS zcqF6Bj|Ow<@}${!qPbi2r$(SempgzLX=KoE8P`S)^u;Php?iC4l5*E+XoR2irD@eh zBoFnO2c&fG4m1Iha6BcIU+tp^&(xyxtjNEb0)`VN~5tm`EOh0ON+=?_}k>OO>c zpR9O<-X})*5k;fCEstE_eH( zP;$nL`HACd|KS4EXjUhFpiJh>^fN5`Zw%}@|JWLk+iDx*!6tg^qXMbn#rH6(I^AAp zxODT0Ou<9D#c{is`qV1dqPyXQh6P)8NgZu5-S8=>plTh0$FPAV1%b^Z`NQZnnGTrM_?} zS^|qk|7-`;!AA%=@TFdOH0F3wCw1-cwyW{$+MNn&Z0z|q(%IYcy|rhswW~!_EVe2) z_m)td7=MY>@^h$vX)P+dGQ2J!JT)P_uC@dvT(m+L4CtF`rFM+$?twV%ix$&3au%79IpAzEgD|RSkK0XmXZH8CqJc-|V}+7O2Dn zl0PSJd%JK;hKj5!`V+C?^EM&e;6b;v|7D@Iw;qqtEzy+*wG%ar>QiV%R#og_HGW2# znN7z?@1^ZB8#HHByt?TYMO93FWeVLm@ zS)TsQhWx3%(u_2R1_tI%u#PN4r|50ZX#NEfsfdT?n%iQ0o`P=!76n)388$i6(?Dv1 zQ-~GMI~^i-IkH%JdkrQ1Rlu^zrjVqh9c>;Qhds&=-AGhEUECvZhshhZPtg=SD*SZp zOv7tG+bOIc{y9CJU4LPrTG&%Va!URD`pS|YgjjfR=1hvnl!9j>JUd*ttm}cS)~y3R z8xk`3#7l;Zp@5$#?6n7M=rlhrbd1MVW~uB(ONeiahV$XSIL&DCK|$%VtQY=O>JhKL z2Bvm%sh4ZmWm!&Km}|4tC0kK){7WS5w3gq zw5g-b&Lv(M8F>oFDN$6`K>v>C4y8ZLBzFl(hxRY3zw8P&73X{3t%XQ6n!pQWI{%aR z6`NJbarBcsWOg<pjW*I#HW& zF~?BY!pQVy#I+Y4l_YuJ(!z=-oDnAF_H*A6;{KMAxiXd=!&`6mn+To3Sn|ilriZ2- zKQOE)ILC3AG{kkmE>D>I-a4ag^u=v>hJU=>8oI_(-oN`QwQRa8N@V~pFoGBh4zo+Y z>1i1O0N(J72oPPJ5A~AHGJ!=ZFfAi-$9p~TK8gk@bRAfXuO8Wn^~(J|QDzkon-uX`<|K|=4(2lx_xUd;Na&&T4kyPK2!SZ%o~ zNggH-X$@|1EfMCn>ZR*d(|~=<=JdEKfz9Jk_|pxbc=6tXYcTNpt||& z$gK`(sQvgNfAL4N<+bi`h1#F5orG#rP?I=?fP6s#PU2ynK(X1VW1%;S^lT+8gW(dI zgvvW7LB4n}(hHDAe__}_oaCLCX4>NykGI-!{3zdQ3BBS<>2-RUB>4KK6qC?;A&ibb zJJvj{&Caz~8v3N-3BI&V!8KXxXKi$SuvWhJT@8J>ufvXn=w4OpMeO9*K1w7PWlDz(A1+}Qj6G0DjZ?I{Ht2X z>~vh7r;=PWncZ{G_ewsQVQjIMj*FK;_7d^nNpcZo6|0c+nRTUNWUF25F<9&l*+fGA zPG0?G!wNnP#UBSGM7zt(U;VVIB6V2b3YU6heMQ0WR^`m70EX1Rokd&0);+?ye!Jed zA#o?%753a8ViamG*ZjfGa7v_m!*SmjOk;M=8o|Y}WBox1h2@?T5-#R9a&1p=+S}S# zFRtc|?zFUd!&k=k7T=tN4R1vqL*1V`{1#K^ffE;AS>>8Pi<>w1SQj@jZ$Mmh^`F&F zNe$P02x{+)iL6^f%9+jX*3o#y=aZkjy&e|AY#;+q>=JTQhsfHsv>1!5~P!*GAh^^ zr(!#Bn4RbUC8jNXmgb5Q8^Eyjd>2%kStF@o=Zo zKm<2-smTFVxM6w{ryvH4N-Ci(2YMzDltZ7iz!S;F z6YrnpvD|3oAQ5y?bn#_=W(P+C=HGeR15Y|74GCOWgLDg+U%N3z+WG88DCQFo?Ce&X zs^+$B?&bc0+p@|_^pib&os_U}KFcVIa-;~#NmS;}r4w(>Rwv8RDDS)aMylpr{Wap@ zJ8D0Mc^F*-2;ZnRo^fDRu5D`(xF)A*&Df$`Tz#v8%yzaKF@VrleF?6JSbCX>${6`HGCvOT1xZ8L76i%(a6Kx5j({U>(WG2FHumK%2LJ^!sQX9tD{TgOCBtxivd9j&(pS0Q}y`6zKN` z#*9ddYCZYew);Xb+HIcm0o>~;MiZJaa-B=|ch9r*bUY?nT%$+dPhbx>7VKOV${~@y zzW$SL`shztICtwP&b>o4?Aw}dDK%g&lm+eOSUj5+h)y@%A~Zx>#6&-eGXB8fmt?Z> zPyf?A%Hch8Q6r}n4=&pF%$w!itXxx|mEj-MDv?1vl?YDN#>d}A`U*-7f z&hd$|sFnWJQy(R&iQqJm7UWS{<}Nb&^u@6#wE&12WHGJpQVmzPDzTGQ9yDjkEe+yax{ywK>fqj$%6J$kT@Ru% z(#!nP1k;%-3uE8xhc(uh*GaTrt6cu-x%KQbX%L~DI}*bfhZ1spPsQhqUq z!v9i3>Hjr>G%~1sVPQ!qV@dIitKajsfb>$?fkv#`W@LIM2^<&t8)eHFtZM8Qp=N2)Pg;y>qw=7zW2Pr-3bh7AYX2eDg)qaWi#QVoRz zHt5M8XqDs+lrp3Vdj5Qm9vyU}Th-&e zq2O9xqQ8ficMevQcrW|##s$B`znu)VP%1WVpM)QMeeX0!yS-Tyz_s7U&mfmEz?xsr z@25Ua@?`CftDkp8sZ2AI2iqE$a@T!lvjV0;ED^(RRy*3wfYGtPL>*a^-^5@h{h#H` zqodToVM}Ex-c!Sq4&&u&X=eqo*%Q?;0EJ) zSO0|(B!A*)0=tKvW90+@50sdqzwRU4899elY;3iS-SJTjTkq1UEjCJ`!-Bbblk?=C z_$`V-g+cM-@_H&Of_YyMRIO8+gNonZpEpSVexnItRvgZ3m&T%zl<`8w+4cRM8M)gz z;OWW|?kdC$CqU7(8J^ahLc_C!dmFzQReb&6ygcWWqkaN&^zZ@5&ClhKk+7MxRSL?G zGs1#Q%9KrKHhToMYN&UbFFvOvivMJoIK@0J_k3iGXDU`+D2w({$@7*wn~76RI1`Ew z<#S!e*;7F^zGC|NTQ2Gb$*vhY=Eb0V+_ex!FQ@T5Jvz`HjkKtHHl7zy1?%<&C&z-UfkEJ~r9gniP9^|}K z<$i+g7k(k*O?_CYDQUTP_37WCGGO)m-Y&Uf(Z9uYwCWcy+KM@+(E(}V#Q|PlN4pT%skgDI6=FLnh z(ryDeuF-OM9v*s@pGiV6$yj^*gL;%9;i8yp^S3_90DG&-`Y7VNQ2LQe+o|?D!?o;r zL@P<0CtMu1e(F1Yi4ZFg9kv{ystcdePO?+ZDP6`G&X&YFLJ>dXa|8Ch>FrL7JjSpr zzhVVEuN9i}9Y!&i6CdCtFqp`ZTMi0BW$ zUTk(1+#^= zQ5)Pt#WxJ1BI3(_7-v*z1242QW$qnIdn!fZaBRz$kWS2y{<2pTQ|<3{2A@|gNm}wp zseqV2qjUJcmMTI7kWw5mxlWW%9)?__knZB=Y-nC*4UOF|juMi4uZl?ws?^kdd|B*Fvgz?KI%G zbad67`qQ8M@gihF94fPFql6A%6jsEri`Kz<5^PXrsIzB60beT{HlVA>e-SpS8|?cg zqA(X}?8z(evbQ2~a?G0Ww{;X1QC9FgScjIX4whBCt&L1GZz|&rIym;zkVlzZ=jl6h zU<2yG2M7Fxl3;URMOI?nE|=}%Jbwze)%OfoEXcP--Z|?v1+Z8!BI?5*z^b5@F~U@? zwCcA~mG-KCdvwY4w}GP%XJ5HbheuC;g**bY_^bV7OK_eb#RBsZizO^N-4U!j1On@; z`wndX%BVYv59{NZLI!qSHKx$qvapORt>@usMn0nv1zeP$GL~a#?GlOEX|H|Z-cPgL ztCs|!PT$vjv>gfSx;IbXq91ZB+-9=Y6d)V8{=nMi-|UKKMX8&@=-6KtlfItavhIan z$5%NO@_{n9q+mqMpZ-+P)feL{;~l$i=4uKDp6+AQ4X19No)vWotG6^aeL4K`FVef+ zrit&|SGaXY37gLwPi+K${_Gv+-MKZ~XgRQWUo7olr(bDg(xouWgLcM!P)~oUN+3-y zYmgVcXVx#lpH=;KV6r|v^Fyt@-BE*p?~+_EWBtCBl`lkrcZ5&N>a$DsgLyL?!e!xS z8oL&Rr4C)q_ zZ`a@wdr>@qnT397_0YW3CWBM}vV(bL)yE2cpudg^OxU?NS+MhVcJ{Nc%Q=<_zuEGI z^#7R4>KX!Kb5_LAOoixT&kbgH+S!tv%Obg&bDjXF2S&*;@vNVRbK|Pi-EVt0xIA9X zcS3&x_%A22@%2)pB5bZv@2(&#nBJg@T8c_z52#B{|h4G#?Pg41xvDxMq43gaSG3y0fbuU?zlf!?Ju)Du+n84wHtV zzQI-F%rX^p+c)ER!PD7>{DM6c^Q3@UcexRR^PjAHG89Dg*=%0(f{F}UEhed6kq-EE zRgF;sn*gl!tfoF7YHmHuB5SR z+{@~j&a8DIe+MAZ6BZY3xiIY2wy_6uR;Xhk=m1Ik1%?61aN*po!%L`lRLb@grO$}U zi)nN!%kL%*Ox|Zz1)739R^a8^$hvC##65BKovX4I0efxL>tbT&uwcSf=qArLlcqH7 zE_FKpGA7lS{$JC%rsB|pdzh^x9u*1RLnHGhZZDhAl6E43`G(ptnpgdx5{V)Q&vQ&_ zdm9$)5SVW(gLhR#+%M20u=7<;PjL1|VcE%pbavj#_{h-xB(n~4g%s%2_ZWd zU|q@8`#&an*T%1NUG`fVAi5GRO6p(GHD7T9cRf7S{?z(erg;pYTp|J|>LSk!D#l3& zBr*PT8m%c7zC(_y+3ZDb=4$>OUxPz@dfiJEFAk_2q^aObE+0^@4zsX@PR@{MvZ*w%Nf zmy2s}Mju*VSRn;cBk@}{e6?fXDJuKcit&}vcyI|NLRgz=OZ};DkR&OWLc9!GrQCt9 zLy>+-;PF(BBNiEc&P1lt^XN_C`J~BeIh^X?aC=griAT^rjQ4#mvfxxj3ckK39%*(g z9#JeCevf2mq?bP-QC`I&@c6yg!q~b+m{+bCaf)SuApaC@!%}yqIrrJe0LtFWe5Es| z%Bsr#T@CcBrYQ*BZ5kSo*;%EO1WbI`6sTE5}A3_`}mw3h>v7#<)BV`)^HQD&+g`NWNB+= z|Leh0AV*BM(0N!#-B2ujPuC0Q9zNfdYBatSIjUEcZ)zIH>YW8JlR8fV%GEo><@K&S zCe4T8#ae&w_^`)RtI)?MLs?m-Odjf}cONQCDm%=?($cEYD@xBV9fvuH4=3H}IHd5f z35%d^ejCrB9Z>i1*tsgPCZA=)*E1g;r3CxwZhiDauw8Rh&){aaN#24H%y1|9Xg%cS zWx&21!zWwom$kDZBU5h4WCE~{soLQ@pB4@*sz+bS+`SUkG5*t@habAeSI6c&H8eEF zo~T8zSwFSql!8>5fAiIbg$dulDc-4*)uBE?&>bgz7c{`O>4UHVSR5sV{iuOPwQ)^M zm8SfFb=wnMof6PV3N0Qw#bB$A`s?I^BdGcv@j^j|O@GVwVY`~$m6I3(Q2q5Ebs>nX)) z77xOyh0g6G-mWUbfJJ|`6u();D+65)!j1-HR<1Oe^Su&`F>+op{+`@AwIc0t@7nR(XI2NCC!i$hJ=)MS`8NfOs-3OYugfH@Fon#U zwTAP*>&Y<_TYhM4Tly7V!*B`C%G=p}zU4jO0L^nqL(4g?{QVEjzqbJ8ql2ebWum&- z`_R+jn$>K^R_w8#qhYq~S`peA^-BVFxSTRCH_^GV!m>CZA8x5MA{BliH3$_oo0|X6 zo0^is2CX*ErcTnkB!l$x7Os<%sy2?+LI6K_csBX4kNsdyJ&%c zI8{v7BD3I~~Tr+F&tEgPhxo9?0IYxUBcXV+}Le#*Kjt_@PY4zIv1#ZKn* zP$rJZ(LT3Uf71QYZmEj$%2NwMynYk|OjTr&T}M=8FxRrEjNT``Ft5uBB1+ZHpj^}t z+pALMIQ%PUQ<@0eUxM2kg3wWqwhPee!h@{05U5SUSGd%PogvcId_n&6O4-BqX97r3 z=6$Y>r~5r`*e+o5dZLVu;sxU>9D;y+0BA}h(%{4L>n=}nSwHOHB|*)5;YI$< z&Q2p=MK0)dz(Rn07+gT5)M#RULALr|IgVyY<_|_L&|9z_Vy`~A1fZHdQ`Kv~Q(453 zNW(&~yEV764Lh1ZI-oq|_rH=O9joak|i0<-u%)7vV7~lQL!?(JPG(HM11*P#* z`pY3x6n9DxQJwvVGJzs%H@?`35!7Ebjf=f%+|tu&A>=N|t$iW4EdQ}NuOn`$xZ?A< zZkt715o>$6f{W!h-^Ld7oLSzQ9~+m2kC+~Xh>V(YFi1OP_2R?os zZ$&)vgYxb(b5oCr8rj`vp0OoZfBMe z2?`B`$9IBKQXsu4=d7xB(W$tnb7yg#nt-6SKTnDIK*bM{0a1Pnf$vM4=BImbQ%_gOYIFLNWFGuAhd@x9*nY z!ny-WpUCh(8PyaZnOD5>=miRdt~y$DT1xx<2qX?cD~JF3XqK)q2Z?qkv>? zVo{?jGzO3d%Z=`Ov1Y*D=Db{!?xwbkrZPl5TtJfpHjrTbu2H+U%%*1VX~)S!vIY=5tM1 zLgAu1icB1oRS(oV-+qTA>~X@bdD+KxUjbwU$WtzE(}i(Q_XRynNa~6A096==0NdVR zl!DsoYDJU>cbyyNv`?}h^_eV>eN#}Wcm?d`)@_O&f9I@5c4$S^&b=Pk&Sb@jtin+5 zhMVL6ddA`GnRTpWcg!^-G^*XF=^<2d@maXq4~F-GMNKYzfS~FRb}Zy$^d&5mdS{H2 zzj^q``}+4P3#qWPbDDkL!+!$Wf19$*o)@de**cipWJ)thA%L*h_myl>Z{R%=3f4t^ z4b!j1GFsr4N>qu@>_DFTe)rFT0Y`6noz8_A%18@-3C>{!aiGS58!6{kP138SG&;uq&?lFP`jY z%W1uYb}6{yJ{Ll)SAKN^sC3x%j)S^*!N;nIZzhs^Q&on+1@H4N-#+relipv|682R%?Nsi!)Gop z+7koxE)WgQD~-r`=H_NiZfu4GytJss^er~46sm&V!^neraVQHIPmxWD@ zB&~6hRzh+UMg`buR{d^0jWO-Q?ao>)?iw>O$YC5OAp9$QGpzlJr&e>}5@_5WnSRH{Y(eLo? z?Dt?Sp~60Fkl#NR%@~3qNBA~`*1wGh7(K4sr+R4^sm}Fr&8qy|wIg0(`TbVL0Th3? zz?`*`!fwk!$O0Z|VgdbX-FFkS?fPy`z-ivB+W!HqaUk$4*7K90%q919jjs6F6=-qF z94+S|YtPLc-sss#dl6)RvHJBjP(eb}H=StTS_u3qAIx(W_30G{RT=LhEahDY>%V#c zr2kjudh@#Xn1{g1UCtOEA}L%ONEfb;h>%i}yKT3;hCK{ad?!6q5_!jVcg4Zu^m z6|r&`Tin3Mdu(L_dsi%BjQuuHX-B65O72{hgV2WNwV*aWfEjdZUZJ2DUl#YCgWVgo z|IWOmK`fWjNKy>v6(|mt+nB<*D&!JX)P_F*$7N@~f(lXPtwE~C;q)3Y{r%{^I-shz zF5IqK6Cg!oG%S+s=3?LEBr`DfByv_25-$TX6~vvbnW!|=t zm4OtRIw5N$C1nDexs)~r(VDQ_b?o$3a*=-Z}px|faCwW?MUilK$msnK~KZ#9GAkx;qC{_00@)3VR&umE0!jGj0kL z@4Nvr-Df)UDBl?+=;!OQa`=K&I0G(GVC53t?9!8STf4osWoqh4nMZ(!v*jG;TsaK>K_W-5YEP|9i zfctRwm4V>GbxSAK=tj{m3}nH0b4mlYaw+u_aaa=WVu7eG{Jc|9Tw_&VBh2_FC@sDq z2!610788eYe{iHrky)(b#DK}uAycNz*%c{`Bm`03C4Sl584h28QZky`;jEqqto(|p z%RXcdbHVAx+Q136Ec{KCV;t=)wwfZh6S(NpKCAz z(%uabxrr&-U50Tlu+yObPk zddISUr&^_2Y9BX`USjD|SCZdz$FHeiCgedA(}Sr7*_HHzsSVgu1M-daUF*oT5o;GG z1Z%r|)s)@jkUHm06qBIQ1q%eAi+NDHW=Epw}d7h60sjW>; zdpYAc>y(a0Y`^#6&ihqh7XiI1f$P4&l1gJrwY|Rh@kbp|6oX=Zc|z@b9SixFBU6)& zexZd>C^?8($zE(Mk115IhxNM!1?qrH0j#Ry*-w6uTo;{c|Mz$La zkNMd1%xM#@W$Eo;m^TQZnm-y!W2c(G0pG>>pr?o78MQlXPu6XVz z;E%op{Dv#m2TX5eGVxM<_a|tLh z3a4UVML&)=BF=Wl0g~GM`bL;^RxQBdBjHVCuoY#l(*HYtkAJn%XX+M!DqGU!sVyJ1 zc4Y9w{mv1VxTV{(%i_mfd>@M$0&s&k;8h!TwZCS40=w1L7GlA4LjF3>aLu9uz?IGz zGcWUo_^Cbf3oT$sjnL2C=sACK-BzzS5u_u%`y)E|a1nQdgIjJI7Lb$}V_xZyf!Met z)1a!X+Uxj$mQwiXqD)DVtkV|n zgJtlF{uk{p`-}FcLH_fn<&AIr#0>=ljxTBAnlueix|JvI1EIcv~#+4`Nxj{&VP{Z_Z}Pv8lqYC z^9*8JjFL-Jt@6}Kp#W(@ybbWr%^Wu3T*WImeFQ}LQ^S#ww={|$|2?(4r%wq7snI~J zqorFN=I=80zR!660M_Nan&-dOx|bwh?Wtqt{sK56x{aU}v3B}Ampw-SKLxxw!)+IE z7n95J`Jj_z!7FO3rU0(-Amow%HXS-t^r6py+@YhWlZhD-BrGv89bKbXkC~W*9c{C@ zmGpciwRw2;)CS2sdAl`Tl|t4L3p8M_gT>yN9`Jaz^f~HqN84aW-pufzPTL#0Z*2ac z6<0OL_#9DCI>3IJoE9r|m|hQspsGdpMwCrSXGS1^El5AyR_@P_?>zD&z`YfTeINc> zqzD^#)+K5RW*OZ%5n0N9ONuFvRix5!gHZ*QW2koUU65>rlcc1JXa#(>v_8yl#k!vo zvp>%msza%ET45}pJR?`X1=I|vq!}VdeeiSF!UuFawuiS+fLnE4QD4-_S$~6M6q39_ z?Wy{|V&csT;}ROSjeW#{;fG0aw6sSBwMD?$*1N_JwYeFv0(9bvgw=B85q2&V?j!h9 z&3hmofIgn>>!H z%6|Xh0^lUR&dxH=7hi}B6-1oNRQFVYGDS)4U!knwbPQ91&wnuGQ&yE9Gl(@^xzh=8~1QgV3vR#oQm8 z{Qv~OGIxh9okd`P9Q1PL>rmmtqZ?@Vd^ykd*_hsgItRcGJMIvZs9#vWylp~L@26ZUgY#Uo@dS~3=Q6S zc=9{5T~6Y>jma>%p~*T8&YZvmFvpCl~JR zemTzXn#vb#O28Nsrw=IK0C%xGPAVOSAojV{hGn0)cEx7Mk5l%GkZX+$c_qL?i+vC3 z^(}Ux6y4e2%2xJ+`n=VNGSD#KiTO#CR{#VTo5d2rMbGz2?|v4I%>$v*AU=gN-k(PDN*dR}IXQixjj*Poy~ zqT1svk{Swte^}KSnAP5OsySHwz@t-|MzT#1POdB^9RsSr5T4{4*Lup3g#ymN2TQ~S zAdVb#F~r)|%-BfgE}zqE;5~(uCS34n`|?B72G>4*nQ-bKTz*lS;rWd4mj_wZeXrQp zob!#%XWTdMu>NR0GbE6_F5wq%BP#4bWGF^1^c zX9CE@>3-yDg`dgtna4L1j^YtRkofB20zsh?VlMD%hfI+^mhz+eb}@hLw5T8m4ZY_5 z5V;ePcurWtf3FmvtkB<0Ie%VC3T$k8wi53ugyyZNGKpbkLjOc$@-Hkg)Xi+8yNZih zIt(;lnAFy2z5F@*ktrlxRJVw~L*u!GVqxl`~@tS3N^wi;*$SEJ|m$yjR?24lqbWBEd#QxjR} zf1bv;CDUk*Dun)j4tv+%^gZ}f-^i91f_Dt9`k%MS#Fh<76;N4e>S1q^3*hvxW4x($ zi36VxhsqinvJ}EgL*bFLG3`ghdWWAsLDS*ygF{!*Ky7PLi{%nlN7wu+r2C_3T8k-8 zW*bhfGu#i-jR;zL0eB^@YcALk%xG+@2&aR|NHBBZNh&nSlZj^1ClKGyZpDELdRz z*VnOUH}UjHmo`x$TFp~TcNcYDJ}Z)W8VXys5T6I#_dSa1zxx2GpCXg^=0R$z#L?Zi zL+=f$1er<=g1RC9q+ezRUB~twzZEi?|5$BkGC9DC9~`l7p0{C+f~}3Op$c&$J{!{lHACd0vq$oS04X4|e~A zl-dq;7MWIY-`ABEuE%Ir|8xu0M5uN0?Q({yck8K7G^7`bJb)RS82yuZ>`$nB<@F4= zO0PcjW5zvor)m41l`icoCH?uuxreuOlm!JFW12>P$#nGdzO82IUo_(kztQlEi>ors@iB2m zbsX{UOA87<$jCpTVfgReyUPR|FrdLDf$2-l#>V+i&XsVU=ROQn-L__OCT?&ZlbqxE z8&8Wh%D?nAaxAw0LfwN$b{i9ZCXffX@gNri^y$?%e=obfet6DeTOGJ%w0*+A{|}t% zLJrsm2-0+pu$wSmc&dMV5>cZFUY>U6=Pj|%0Ty){8rWp+tu|va%3eTRJcuqkCvoFv zVBtx_qWg!vD3Ndu z;)SW9ByW;!yUz>6Bwaw0mbI2!;5?37y1gdS(&4!i+ue4xC*5G*w7s#51A%bb*MfOc zyYFNiLuDL|^!=-Z&j7dm#I9A)e>N&xvV2ZDP5el{+rpI*W&kfKYzsBLDlW<+slRkd zzs+#diDWqEYh zOlRH_B93LK<6EpHO4$d4SufRq2hn&hh-YccadTfHIThGH2(r^H*UI=;sChS`q!(OPArREN$}9e-ba$KB(tMfVYg8tEk!Wh{4n z6pxH6__ju!U;T+$*-l4u0ZXTDb$9>XyX&rx?n?>Ca5k~I*g{~u1H0a^x1Bz*6(9ew zQ|$e;oBZFhEHA|kDpm7u6ak07Rf8@RAadF@L)BkWnTA{ z=4Js|HABwdQnL@ox;XD*R$5Z{Z;RE>pQFw{bpr$BWv1g*h(&8+l^(w~(6^*oPl4$p z!*j+^hAcZBe-o$o+4KGr8G&07*|}w=C<0ovsjD{vy znC0&G-@9e$hz<>CacK>=-IJq6YMKj!8~=x`?~cdv3mbn*Q6x!1W(nD{Hzg}8J3HAs zJ6lN-nHiD2va|Qh-h1!8Wj@A(-?<<3ec#{bJ%98G_kHej?QyPi9ktEUIsDARxDubF~eGC*>PcV28{-!x-UpW+0`9)Z{hQ}{{5(St&2iYH)+lk!AE5!?x6aS zi8AS%hw%(smiEpXsxMTp0qasn+9~ck5;ATvkuf_Z%fr@byES5zk>lP=kp$E`43H30;`FxVU2 zP(Nvp1$xt-hr$F#WtB&d^*R|U-YcpY_4t_qyMtLC^~@SCBK(Jj)$8fuzP^((EXLD< zaxyK8uzM=-+TgsZqvpTqM7v_%2z_ulJdSnRhKJEjDdGBM+jK(G;BphS>{R8i`wtnZ zWs5Xq)t#HuF+p2_0%bxmt63dl7lu&^d5^`(HNN*>3?C7OM1pog@^ZiYR6}tJ@|O-s zv?bA#QbCKk!M_f`CwPTSYXTPxsty2Aod0uefp-~wS2x@^ECxq@eyP8H%t2s;JD;1k zm3ro+VQhCITK2g^7LrfPJAxPiRg`Yy7pJgc5H`>t1lYW>i=LS7tSUT=Qcg0hn8=bh zQO0+z`S5|L^iV8wu#dnC?}Vsg*S?}cm|z+FpBXW5_C?=&yx4A615W*2>Nv%5rtnF3 z8ql+;VZOQpm$?8MS~F+KwFcYu#g8bq&wb5DD`cu9{1`i00_-)M_V0&z2Uk@YybEUJ zghfcHDgG$3kK%r7bULv&vO=RR$zJif*t1>PQ{BRNlMY%XG&G`X+iLY@*yPgr!&3az zBZy0iA1?$j`NhwcC57%D21_R-18^-La7k(FGq|%qJB>iFo$u{~qE}=iFqojI{#*U~ z+q*vek{V@59Vre9Y*u5}IL5|4)b?f!$d zu>0j?^P2~_R^kyE{gb3_x+~L>sL7`Y5eJc6n6EFwmb_^A@rB&FPhWB> zYFg}stw)lBv9_eg0$srNmSfE)`ar!yRE?!K<~p+i`X71kl9uEoQ_~7itq;+FGk7Y; z--yUn$+S%pH51|av`I0~;^g;cav}%5vdgN-m2VtUy=Bjs_&Xzi*zE1-v?CuhuVHYu z(bKtI`%%$f;5VX%XSHI1jDugZ$SlDs?{^U%aJF3-7_ASL!9Bjt2cb0vZcZtWc6^!c z;w1HcNqyFN!in&&t8V1a!y=)AT+1uGU?B?2n3OB_7|j$tVXEL9 zI#PU*=ri*Z7N5@vj1hBDO9^~L&y&_SJ@}ve$E(PZ0o}$x!^qu zdKPYr!Mz_or;VVeT2QE|$C-r+d>2aP5JQw- zsPxOo^zu)ZAZ|Q#8mO!I`K!Q{S~){$2)C#W*ziXSod3{`rMLKi5j1nS>QS zS-6EBnT*%$&6k<_q-ySi9L;!JL-O&b=Iu8?8%yaWF$wnU({E?}2q{=}f5sNEfY;Ih zoEM+nTW4_PRqVT2MeyCye%r+=3k^zr{a#I%(VneI3{iBsAdae&ulu#x)O@nbqNf^N z)dh=(>1e3xJj$*ZR7xkd#_caPIA&kxJ7?1{iNT1KmVfjbR5~qpVY<8!UsY>@(Mh`v|;GtcUMwc2ZRKd%jp_TIIpJQ=Wm~8~-ae&-6lLLhp9v;zem?oTO zNYkRjk=2iJ}A*j@C6ZpGO!~^YXxWfj$_bV9LfG8<0@hT3fvv?Ig zu@Fglac=vN`bTi|B6RAS?pIJIK0Pt0m^%EiiHol7?8jee>%o=tG^~6|P|f=EqldYW z=u$mSk%-3jM-N|}Zn;V=l4XAL9?wzJh52XH$M&n^Z#w@j>kkZ+W_@dEXL>;!#-Bl_!7%(+M0ahJf7~0^3xex zEyNprGwb~+evK|Jvaa~$u*A8#Xa>e6yv%2gwR_RlvDj?5dL^UE3oqyxc+2a>@UE^5 z?cy&z;FiJV_s6($saV%Pd3%PKG!dnqu;iH5&4AFmmhz+~} zjY*Ov$?@e|I>C0PA@=PV8GLBbGDRkgWBM$0rms`*ma&NN8H0XPrD&Ua)ggo;_R3^sJw+B@2``O9K zQ*U$;YW5p3#COj2-O#Z_2(nct)aRGk;L}r^`bik{~OVo_RoU0G)e z@cd6oUNCM~Q@~eoi z3p9$0i5sKz{;#>Y9j;^b5H1MlJCExG+neE;y=}rQI`AtsWP=?_9`gTTP+h9->!Cq- z4z^{SYG{*bTh}EIYJT@$X16JZjpTqcFwI&5PVZc^+^$NNcnfSli`kAw_i*LDr6jsnNxDo=ODI`ms%o>noQ}n?GyOnxW8ubcbW$cD!}%n+cE4FH^VDa^2FkaSBC_zL~!}J@C~Lo%5i$GE3!i|I6gv zRJ>(ATaj^Ed^+MN=g!U+<)Q*{ za>R&B5?K$wGtuDSc+~`}|5+^aEo-U!Sab)89uNiV1WDUtVFs$gy#zYO3m;LvwVa-& zf1Zvj^6E$AkIFTiR28&cTg<2w^cc{Zm!ZocuxdcKNo!E}v=sZo>k7Mm;au81-rmC# zZWR;XTF$OASdYJJ*3>5_Fs`OD_KDyqQV(@rXbO$k5S}ZwtTEV4!V4dRlAZHtwW0u0e8w z+K0J+BPuA@Liu@AD|MZx1gm6Q8)%4w`9KvugNjlDUuSglg8yXJaOA)K?gMBV4El$H zz-Q5KgQ-W)nVWt5IJI`6>~lNEd7lp?K5Wn_?<-|Z?<6Vx2uqsC2RR!{qaJZ>q8|E~ z!;N~D$*Q?Kyw7m?JM|EBNgP zTJtG0Fg~;R8mg2dLZu>BZPRrDv`O?MbvjD`VW{ma{~uBGSmG{l_7k4v@3bC@l2=Am z?luWBGY#pX9QJnb($gBGB5*9qe^vk;-GfG~JhvOa^TwZ=$u$C?2|9*9qmfk&W?Y+g;TAk=zIjunaU9T9NpR7vF=klOG~B0YtRO# z_#bc=b*i;`F?`)R?lc*2tw5$MAjmY_LEiSPOfyW{AMUWjI2gbMNLkBiOw-aAdB(Xn zwuWNu5mfm;4a9*k2D1MXGW5=5^Y>e+I&SpXX6YGZGK_E6d-9Var6k)OKS>9Qf-P3i zEi;ve*>d&1!(dN$bEb?yw|f7)9&i>`uM<{%eE7~PT=RwFNPkX>Fk!Auv0=|iyzj0@ z)#*^zo9r5)V-4G=Q~Dtu^eL-fO)t5QS4Tz72_4ryH2brCt#_TVeR|X7c+e;_G zeq-!(>u`J8+)i{Gv$^cZ%lOZbUH;s_mrWD!9t7#oNW5&pK!4dcjEOn4vuEJP?+Vz- zyHGADU2EHTeJr2gh+@1^hP%MglNSh>{Zyh)?r}s*OP!hQwpiz1qp$bx)g-TtCU8tv zIaQtNhbk#jP+$_zbQigezdm_TN6`^Nte%czSieU~P%KpKY~ zRH(NH2Kqq4_VMP3>#xex;iO&bNX>V#9o;^!dANKiw~6kU>g&|ME{L-qCkm+@i|#vt371DQc-94Q;e@fGZ%Nwc@cl)j9X#|w_L*x6OAi)C7X*Y{?6 z)aKtuVcffYvM*nKAl`B1!_4+D{6x8#rwB{sy-(-wKy~tdBaPx)(&=~bG^gB7JH^_5 zjww7G1Uji``6;+%@qD}I_R0*O%-=#l}&(f2% z-o=6ve31Kf-Z*3_vsbtm6>QLjQ>4ktR|TB60%g)}bqcQG)MNP9fme!35q1Xwoqq#s z52Q1W(kI?KJUjK1nZR(_z^!->LLi{XR{bXTYt-`ikK`Oj>gR)9j_QsUW8N)yTQ_}- zJQ49XX?}}g=#@VbfuUR>F6E^C!C~DqeaiQpWwU24A`P+TDV~vc zUCsSjC>C{BWrf%COXX?>A0}blOZ>zQx|M!J>>)eDf)~0P4(yRhpjaJ@pZD0eatu}) ze3*NMBb&UrG&l?gGfap}Wx_MS3EeWaA`lMAjN~X*7Kw_zmXPb)iX?xr>OEO5i?0P@ z-jc1H(yXL}U=S5$MHZXo_3hr~s&rO4;lOn|np?q*Ck}8;kjmzTH)?PIE&*!zI(OyT zI$=jPZ8j5^7Kz*G47ae^G~zHzNv-UwuOZj^A;v++q=K0u|2b7bo+BE=V5Bp~$|3~k z;M=&rjVNUgajJcRe)R2i^h1+wkjT7@>+fF1bmi`rIIE~Wxy-_mVmwxYj5ELu3(4~_ zMy8`+>BYqPOi>IR%@8=GxXmMqbwdy}#{ zHZ^IvJy9`kzgDAP@1-E_f2J!hm{c5WAup>$yjG_KezvU#aIV!RoOHI@cR+eazwq?- z%8-w}#?jqUH-?hq#k4XEi4HB$9X_*MI+|ksGL~Qp1@Pew{NxzO-5H6{VVtDx5)Z60 z2Q8j~`v{dz!MaS(x4zx|I!(F))_SStu%(2Pm@2>X@nFaW?R}KHug^ zWWTw@W-DUrprT%f>QHWQup6q-)*zBG=(8Ki=G0b!b<-o$ZMwP7rHrw(U264XZSu_o z@8RD{6U6Vwc|kW=BOL^aKjSyeUuuIJtq1B)E@z1`TmD~P8Rj0p-(qBYXta}vspXTWHxozwa@V|@|qW&r{ z{C)b2jx)PIQ^9&`Q8m4v=G2W$7`cf8L77ic@5!>W*x4T=;FTR9Jx{B;seV!tu5&dC z?{F1#?A9Q>Xs9cgmxF9d0*ht&ZEM@>qoDl#CVB5bAJM^~6VkU~&)SGD8FSn#kk!~N z1ODN6*JNVuSPtelW7m)-b}Nu@?;{^2hne<=YVU`j!5z8RORL;Zmfz>+H%|7g9iWt* z2}g!vmSfmU)3YUTFubSN)U_S1Aew5K<>5aObbMYn|3=$FV7Fn^T(!_~ zYHw$CgI-Kr^9+Gw67BeegI_7ugR`nj($+du=~W-Y1GiI}cnqKZzP`Q*)%8lZu!PHy z3TC!?);aCtmbR#7)b21~yfN0K#Q_@kIsClHy0%|(ISW%keh&cpfy?JpatYUViI-g% zsM6@z^l`7Qc}fSO_1xYJvs%A78b9}pM}{$sgiqKyYB*1xL%3oC6(pf>rKWkTB*)*> zhCb0II(9pfo>;fhA2&D<(-NvKZ7Gc~(J z<_AnxLgMwVHpuk&)LHn64G}%`-_2lTF)JSWwz~VMB3W_}7hEk<+c9CW%USWJt)Zay zhSghX;2hHX??yT736tOZ3Nj|LWy@@aO?_vT1&cGwh~u_!y#%#}XAclSc~yWN2F5eV z+~SNiUS2A`t+4_v1R39Hsgn*z=CRB48p_!*=wbRImRLSK{KYb?9*sFVx88Orhf}?=xn|&LyGo#n*$jRWoNk zN-$c}N1hB+Uth$1saKUUiFX0AE&X|^$E)m0zEV$rjA(BDVwuj3 z>khSVRH*!^+v!)vlTy=y;LzYMi=T)=48QCq6ASHXH=Os0s`qyb{)1L5%=LBb zy9^Oh>3kKZ78S2Msg=LzKP}3^#OHWw)TrdZq(56aT{M>Zs<4C0t7Rr$L(7@Y-?w-@ z%h4cvkn3R7A0(+kkzmiQsyzW)uOBLE{!UZfUzD}}K48^dX|=e&sO!D|!blsN*WlSJ zv4cv|DnF2XnVcuOvm{^_FX)u?>dBD+yn9QTqXJ{WEG%kV!|t?ubw{>m{?BwOOG z^hobJap~c`XsJwli|XR$_>x>{651BAY-{i9O)98yiuKP?&_QCQ?OjvhB4H z$5d(s1gR7L+&##9X>I+%u8sQroM+OM34=PmL4ND_X^HV>Op8N}t?fA)KzVzoz)o-B z%nv)^bt42ukvick#2K-8%B~dA5f=7R9}tZ%hytkb95hsco6V|!{GoTtfZ3!-C%Bi5 zjZIqz4VjGvI50C^MP>05cEWr>41sM8~Al-@lsQ zvIM4BoWC2wdC_i{ZnTn0pH?`-m1AyKEVBa}a-I9CXYCxq)}lbUmd%O!fyc%&;_N)a z0L4JVsMn#uDz;uSM6&sloxz`dLyc3_yGyI*Aq2fF5niU>>%@uj3>pDZ{AK~+167sz za&JLA!P61Jx$M33E1h7m!N8PRbfQW$(if9l&$&~hw+8Vcan@19gYurS^`h)_{hR7 zdV4z(Jb*!N>olbbVpv6(8nWn$M!%3)Rg1nGfZ99GZ&WK+uvdIM9%gi}X7mpMG0 z@0shZHOz2!e7Ovxrj9*G5sT(NWbi^1JOtj$#oZb(sSAx)Oe86}cP3@5uScO;?Y8y_ zhxV)sgxaZjyWzGP7x`3h?PRt_kl@bMy8yUYa$ z)5>1oi-7mu6%qke6(G&p^3`i2*HU(`WZPK#cRsj!;f?cs^YPO0zlnXIt7DtDYEaps zKe#}U2^D0t{@w={=57CK9r}^>*TK(&3Ij*K^RklL<|!N7b+7oo$oq>Mh%(T|1wZ&l zLW|zEX;GI0C@8pL!wN-TzzUvkpRWfzPwz*My%KX)`i#+P5J3%blVPKs*XST2=~<)Z zm00qFlh3OlpHeXTA^6YpXjgI8C>sn)%9peTVUF<7g)|AP+>nKZmnfOO%=?)t$llc;t6WY zgcH`r_^x%KN`99nPZ5`rSNd6I>mWTBWZgaLX-Qd}(boD>Yu~%iv=lDy*=~;+X|XVO zZY{yGmedn>rdPhygSEU2mPSvId$Q)y2+|wYKi(Deq&53Ep)7G<227|Io7XT6AGPet zZ=m^-zMk3UJUwtz@^ft??GpMx*XETbXfBChnVYju#Cc`6+jqc@Vz>6+$Afqrj(OHoC}dAtf=YAq*^wr#*f7+yhr!G=vt@F0x7&r7<9iLBFW46daskGhE84 z3T0=01EQ`Us&WFpt$&bvD%hzZb)@ay>Oq7B`OJ(G_(D=r(=|_0DOCB_m``cI*KgP0 zeDd~&J`9amlt5{F(up9P98UYjw1{mvZOH`&5{BSxfFJ`LPC?Lc`Z6*~zbqlOp^rxS zNI0Umyu`X+DGJgQbndO~$&G@khm(iKHPh`YUnm;NIwak$jmgUIb)Ik^9$`!cNlFrV zeSVpF{D*YWTr1V@wcNY+dB0MzMP8+Lh-qyHf-2}+HppEAgN4|CG|8t@Jmk8d;a$I* z2|?1`ST|)sl`(;Ri1&399u$px7nYU#A5D0A3>p+`57eFDxMm%FJ;r|#k=MKEpftVq zPU3#2r+c8p%Nc+4*#L7D87X0vjgG4R$oqIiUzvOA za=8ni)uaWKq;-`*MZSWA7uQ?5`(5G%q$ZfGt@eJNxc9Zl&04XaCi|(&1qM_4#w901 zcX3i@nrcw0uRmb#dB>IftiV<)B8>&PZU3~Z={h@$zh@dHx#A?aAnDx|K7fN zi3#p|mnFUKevK_uP4N9N7YnCla1YDRCW?|#C2$4lCv3x(uX!8@8a51N3&kPc!N1ql zsW06%rb19>zYJK~N<4{M13$Q@VL}hlpQUZRj^?K`@%o$_Vm&T)bAcfKzK4GN3@7pa z-|AzBvVmXZp>vy)kBwPtZ_rrv^g!Ffk7>jGGs9;Ob9YO;mDWkRdK%1xLQNmOW}YU%vH! zEWVy@5cSzJHMwn3?($VZjDCgC#dY;4P&GXzm>8Js*`Kq{(#EEnMKkA^?0G>zZp?q! z>iE+)F+3YlmZStq|MQGwfg<|a#!`!K%zAjtE=J#dfrp(nG(TK)&x-}Zss&ZoOA>gj z9^GFwSBs;jzuTa@yqt|5x%i+`aO83)j2rLYSEQSIc)Aut7n790EoydiJ>{8hig!TZUQHa|Ch1LNZs+ZsB`n{e1Y3*B8D*1h7-5A^kUE{?$<}KC1E-p}8 zcZt!cd*?wj$mSd9bG-5GE1iT(PfXaZd`UWV8Z=2y|Aeieo0N<^M&N{n+;%IO=$lZv z{0O-Dv~wO*GwO@d(RlOG`HE{BFR&Vynk*5e1oqz3UqE^}VDglUs&0^oI;3uE(`aZ9 zibzg;MO;8fWo*>F#Rs;&Wk|oPZYy_k`i0LtU>|hYy~QAM!Nl%al4^>9MJ8q)$-;-n z9NrJUF;SMCCM3!Cril+yBl{*p>v7NeaCulF7DIM~v$(Td$QaxJ!A0oS>aDIC9ZKda zn4a1(S)pXy!&fR4yzjZlLIwcFWET}ZIIZX`hv z5)!XK-Nik^ZZ z(}}DCP-m}wZJwanz|BFzxX?wk*t5g-2k&TK$A5=jd{*L}ZToV6Hr0a?CGZi*+`4$u zm_j%HdIm{opQjDov;6WtT`cU=bE6g3BlJ|Gmp))~3!GEn!>iE17u{-hk&{5|K24GB zb-B;4*K6|S5)d2R`V_3_lap~!;OrSVj75}g!yN z+U3%l_|t(C@29HdxRB4}hu~XHT(I2JxB{=By_}d>zE%_q)aA+I2N$?mfO2}EYJkGI z%yi;io?C$l^3jczIxxO}ZcOpi%Zi;*UX(twr4w5u094Z^C4JjmXS`%`K~ZaHLtU93 zxB|)OQ3>cjObG8?mS+Atw*ed|U#aYeaywPW?H@e?xmMlU$4gYz6d$T8j?7?z3rLMd z4Ul)pLMyc)s;7b{F&@9jXZQT!**Zk4kwR}n^x)Fbn3DUaf!^E!7aGf9&@swdAkEVI z_dZ?5!nDnraDhwl27BJkey{0N1HHZfOo;vv`2QYcg?60O4z8vu zrm^(NN`Rdg;055)E7=%>o>t&IiIS>P4qQy#I9YXMe^22XK~L{U%X4VGf+!ut!!)WM zQd2Ncqm$OjIXW8O z`r3z%Wu_#`plG3{DX&Qr(KJ$(4IZza4-JYY-;8c=!i8S$Vxo=FY!82_Xk@m?>>6q^ z#Ctro^*ruEKME3qbD)p^@t7g;Z6Qht`l&dq9XkZ1zJXEv<6p4O_5#c_WtE;b&{Q@b zqKK5S2MerL#-OU;v%fvj(|R`3=$#?j|I9PgMA`7}Kb+@N0u!Rxv?rHNqmWJ>w(x?1 z+M93e;9>G@h7Fd@OJ(hTyWVBMjd>99D*D0T0aK)=(Ae|E)aQ%g|5-0Xvww?aLI>4# ziv{qPnRILnRBv;*-^vQ_510M{B`}T^BR}{o=NQd83=QaMkw* z(8(Ok7>oZZRI3gD<2H3A{%4?mm8`(Jn+G@vO7FX%Yo7!Pp11#$OQE{fQI{)EV8`;_;2jDAvFKshgSY+8=SqR$S-Lbqzp|y?2X!x?iZYot5PI@8BHZHiG`BIIZSe zCx$W?Apr6njcbP{thmr2i)uF zfwt{JpBaSZb8MNwU_IXt*xD(yqbZxef;ai*Y?f6m9BhRhuED6gyM$8Wyuck=Hh0jV zS52y~5C?ViURDuMdKo~O%Wa!lRGy0v{QqD75vL{i z=rt`OzC;@TP2k*R2x={UtP5tWY{{IIobK zv>(9{K(4Cv|NgKQIUw$>p#GB6D`+8ldf2eU7yVaQc2WAqA*FoYI}jESdRvJSi?gYn z4TT3VWvjOqO4mjmXhJI{KQqW0w&QUDx~_eeK&bWaM9!=3-wl`Idb@-GXLEmPX-P{A zQfJxieF$EJ1u%d&4ebH?V2RXQCK0XZAWJML(!4%VHnF|USM~@d=Dj`6vr2EV^bjaw z;<}o&Qk2_m)wcoCtstcH{6qRYBGxFkts4s_=(sfI^rm7Sv)&b4)D(iZ@vErZI_4RG zz~&7aRzzG3gfW2XJ5{K$I$Y;qo9n&dnd7S1b_4b5FpgtqZIOttdO6F7W!|rEwSeN-h%jr;y4(M$fmQ? z2Qa1~z!PjF3Su0imxzdkASRh$-5>F!V5aVp$tlNHc%}x)6~UKlYI*S!+YByfq5xMP zaKqMQXsDT{+|QZD=Ko`wVSpV$)Mi5F2&m2@B{`--b5gT zo$>ymn^g3#V#fNbe4qQIyytxZviRpl43J9$C2w5#-; z)JwxjXI&t0;!bl((i5jR)F{(cYa#@*;Qn8;7@;@BC|Ec&kAz^u>N4UQrD}>(ktC$B zMg4~gVh9yT8G=x8KY&R_{)aOP%-tqXz|pE=URXlw8vsMNb;WIL&i}_<(0d9^$^P@H z`E^vHF3bP;PxOC6Af;aiM8haP_QRKsjq5B4X)QNkZ{;;)a}1`}90h2Yrhtt2W$K=N zNDMO9UrHfAm%J}P3N(>Y0ML=|4j7{4JxKrc2n%6HrRC;U_$&&;?nG8dEGQ8_Nr#gI zp@MbQgnSQ=i?MkGabqdOjTK-PSU@G<#w#~>SXDwF0;WjxGRKi=?r6=1C)7GHLX*^% z^a6Bl^c0LMc&79f^M+nF7)#`^ZU;fHt`fw28uJfaU=9Tx-W@n`ad^qzbC;ZVHq}KcLw2)A3Ri21b zTt7tK(J}H7Ac>k1!nrC=Rk9vH&n*?eSc%_U@idhoU457=y6FwtwR(C<*a{0*knWZJ zJ%ZS_uqQV+F=*qu2KmwulG5Y=pu`{~&ZQ6$p@B>?EV=}iK#-2`|9-aTQ1BdoH@PX* zgC$6qMn^w!P$V#LrefFOPCJ1O7_o7Hnu8-XQ5lZ7!Of0T316Uvkt3PmVqru`E5OeU zC+>3^SzSH(m1{Hk`E%`aSeG;5nVrG=;=W_q$-L~g^=@#Vi@Tqh;AAvkDe+T^v#r_B z!d*2;8uEjsiV+|`0CWaDxpuTZ(->gkUFN?n_8hz24QOYtR8)zs2&NO$O_Xg-^AH}{ zREGfZhmjGNF9)&s@$fdqIz5|cZuBSNjkUi<90>uuEDQ*85AZCEj0M=qt1A8d{n)I- zH7}`vzFJO5Gd|5U2+dMc-Sk3Xbe{c$<;H*2eL!X3gVEIOG{;e3h1*)}oeVi3PjG>&VUX)Zm^9G`(mfiku`%`-%Qgf&M zX$?jJyeopV_c|Oa7EH8G||MHvv(Nn z$9n-39%;rx~qKy zoBrsC3bf21hZ!cPq3HQk?t6b0A-qODahwF0tmkVEY9a=bS|I?>TgXrBK%U6m1*4$$ zQS{)KN|~eJ=0-toP%Vu+?#ELRC*u>w`1+`#QxuQ@2JSuYpRsV$pIp(ybeS;gNv)8s zf&?-@C`7O6%JMVF;_OlYk6{!kO*oLp08Je|z7zbiaD5D%xf6`Q-|5~I9p=JxDYaf; zNq0N*xB-hWt!J#NJPujLbp08{vM?(EF~~T+1yXUr$T9&Ix(XqwXcB|G0HFVL-&AQ1 zi%z_0X`!{-qz4&UGU9u_QOt<-v;HR3NRo2vZ%@%+tirZ?En2QRtCO1+y203+r|LD~ z%|IG2AV*HC4^0a@6$aWTC@P9A)}k}9Hj~F5n6&`P&*O;Zk2k5AB)p@(c!Cx@Hwf%VNlfq+2+U3o`BKR zh73skFF%ps3(ZHWT}Oc0SX(4AOfQUq@w>ALaSF%dcSltcBBC#qs}#nZ z^Old6Z|u#|1>5Md_fl`0KWu-c#u1rYSO8oXK)LtVd3OXGf3xb;DR;iTj2Ubeb(-?v7@u{~<}={f{xN`?@vG{HN;b9DeT3rg1u z2yP-CU=s;|P5jeQI}=srgCntBYD4fe5mN6)NsZt0thTq|mD`fDk%}RtLpv+2YB8=% zMJBGNzq?gRO0Z##pMj{2MmxOQ;t;4X8Q4+8ofjQ<-8GxUx7o{tKAgFh@r1V39i<1z zFbwtsh>3dxq(0weU;`VGo0gtVZWuw4&dztzQ(G7G5y4`&G9NJr9P;+~WgkY}k)!Fv z$J}?3I-e3~z*q(d+kR4jX?%eM#Q`T{a{Sm-Zu*-AXPHc=IkeKand`k_&if637n9v2 z2II(&qb#*IgF9Co5I}H#yxojfw(E2p;6erylj1`IlREIwK!B&|Ef!htZ@N z$MpsYN=?nJouvH95|dY=oZ#zYWp0c7C#Aa^VZoF1-xud>F||s@okU=XEj2TIA$rGH zZXrscp+rL!U~$Taac3L6@817<_QYRRyAQ33{h)O85e(LJgKJntrGYRY8Y!+ocfp`# zfqToP0iOpm$?TYpmn=>+>QmxY9)I@Xv2XbX6j{`|R+VY};G|Zrv*tAzCT;lpmV>h+ z#X;>^Xv%vfT%QR8vXB!hfC*V4Umx~E6inFa7t4jZw;D2-Bri8zD#ZgH7qiw7mHc`1 z$DqM=#lS&GL=^T)bfPO~mVa+2Rp9-IA#fs@y@62xeiQf~WE8$3H8(jR*#o8Ul;P+I zaB6p@-J4=o`Q~|f$-8VQYD#Wbo z%JQWm!4!OioE<2_%!j~1P%Cg9)#>b%pj-YPxzn-A(9+!O2f)@*P~31m^j`O$kma21 z{>y!J3jcdl?_wJ*s`}Rcgn>GVCZv-=p-zKxAqp+cJT4E0{P(1QCIpI778+ zJ!f%|B2-sT*rIBoHp?Lj$VHQlBHBJ4qqEWEc1e=S{g5op*QMr0*909~NV%xp+P)*Y zgUh5iOOC(i<(An1u9$7V2P8s*p8CTCGZbYhbvbVT13ZY(A!} z8v0tU*g)&re*kmyZ<)*hr$lLauh(!Pb3piG!u^x@>R%PYxs1b6bC$_MZH58BLY%*qZeMoQRyREG^4V zQ>BbR4T#FS4|oFNz2GRf2bl+xH-aOJmfB);=3LibBUF8 zlaPM|0OT}D9LG!(a}SsmhSXmnli*219$H24Pm-0aeWzKB7^ep$tXixg>>D-8{e zR&>>))Zc2Z6Q8<;9yJ;Mdo}Kh7EaOHjS`eB`DHsQg&?1RC#M z0t%(F>ZEFUbDG$f&L4)2$aGhpV1#8#(5&?*yy?O3-LY=_M>D&}u2Se?;Z*k35rHi}jRg2?F~B8a`Ug0J3P@Rsm1k=MmK{BbwQFk`)-sXzYI0s)z90t}=sSpF zeIO0cZ%ee9;Pi2^O!cq@)WaSfG(8C@ef5%-E5w=Gu{pW1Z{y8H!Jk zL+%A4;-0k|KuR|kZLsi{EM(J z-CqmTlq`lq6~ZHft%tef$;m!I$`=}SAYIf4%sY*)9`VuD^WV+<&dy)+RPk92)q2-p z$yaLo&HdUXuy=sRG~x;7uX_yTBfz-h)smLh7!#vr`I|Y_dF{)G;D+1Z+_^7_MRprV zJ>JcoL}_V15a%FAS3`7k<(tKgnZ#Q2Lx-@Rw$HDz{u9KJp9gH~AjU}z#+ByW0qG%V z2#)?JGu&Ij99;>mIz&z~9z;!ASJ`aJRNepyw3A z2TOVt!+wJ72i4UGp-Xaum?pvxq`G+SAUL+!z@RQjCmoHG0;*itTZ%Vb#&s5e22!p%Lr%b1fqy;}=L1 zun`vdld#8%7G+^~+5N+xH^3hmz~AXtiT$(F%0(OrM>t*a%t!e$ygA|XIRrmObfXGN z{;yX!bIA=Y)CxDnX@)C`<|-QvOeYJVi+-VTT5pK*1(~{meu7+5;;%p-YfWm7uiW1d zc;z~Y!-7YrcBxB62nAnW;;&j3xSHJ;p{B;X{d!PjaGvFARw=33P_Btq^Qr6~)C*G# zyo%+cQGD4uyuCbRAEX_O0Ga_Z|6M@I@=m4kBW$Z=Os zPnc_XX3*x<-G$}XU-#GD{-zE)eU(@}v8ny_aPcR5s&&fP#aEd%?Ce5oP`mv8;qfy- z%+F5_+&{O!dieA5*!LFJIttJ)jm!t-rQ9az;yFjBds|3wu-@-0=i3j^XYW)c&jNiS zdQZC5z<@!s+)77?@F$be+z%@0CiaIn&zD9(MN8X)eZ%ASCEvU2fLke-fnP&B*wY^w zo0mZ+Qwnn4UP|h6`$Id{ zMVmCnh8}S!$3NW~=19g%FKmB6hh!TTF;Fk(i)i#4Bib_Q@diMazWdstQhWrI1)EKl zzJY;M6zj_OW*zQ%D188pfX{SvSVouBMCKg0fvfE}B>Q@IXlDl?*TT>Pk)_eWYgBt6 z3vHA@LyS~K_PfqoS25bl)#@gK$WJtjcUioa*J$>Q-aJNLD1&B6PN3P*-iB+-_nZVT z%rECJgOg}a1)#m4^B8^P>Mz9e2~&JC?M+cGlBe`1U~zsGddzbE z8B@)Zb~a{<%8tyK)u?ZYmxLCLbH1(ROj9M?7iS+kO^p z3pxmsNA7LNzT2LA3W6xRlye7_Y%eV>O*v~a_s#H8l&3HoMU<6wmeaV3i{pYpYlzoB z*HEx=@D-xeBKztUI%bbg4n2x04)v`&N(`?nE4SJmZ9A*pjeP%b;&dUnU}p!7=6?3j zZ^QY|Jtt^E{15nxHzOIi=&v&ST#|@5_<*eusG!86TE63GCx@+t^)kZAwUO2o%%xG5 z3zpzqXP{B}Z92Z)A4!{@wlW@TqPYkkdnbEM7a7b!Na4P{W#UI&f}NPhUs0;zbV#tu zz8=oyHt$y(|CwE_Lc8qBg=MOn6LhFgvsDYr9?dmtjBY3*8mqFu_MiU-Z8tSi-rUjs z7$|h?mCZ(2*co0F|8BFglu*~e-~uv`e5XwxFdwOW+a8LkW~Zd6Olo@!xKZ6^VeZC% z4pm|_n5#Hrh4LpnKtw5XlHGdZ>$osQ0YwSdFh|w$*vBjfMQOWpnyO~53D%EDjSgCj z2Md4z;W9fnSO97n$&`xPj3BwU^I;zI1*Uwdl_VS*JV1EW!yYuFB81e&^6`hkE^ zTR_D2yGmt6p4D@|!>|ybb--+-(tM}Gj0euTr3Pe)%8$Tmdn>_l@5vW;9VpC34l@bF zgCMc+MSMj?VnxD>_FsYtfH62M7}bl6L=R{fh9`F|+B#Qx^=7`{Q2I8l_E29n?29|F z4f%U9$v5n(&mv%w*9IM6^8^}qLqe2IM{^8DJ1R!)Hij!rI%`_elHDxq>;`_tp@7hd z+3NKfun{+6xpX_uT>&UWix8{jMab_>vn{5pUld?8CQ6N>hh-0!n=M9H)F;XAV6Kf? z&xAjmPKUHytZf_O+=k0|84gT&#Je0zylmYrvs)hKyHGJ?n0)(VW44j@ zFWQv@CiQy4;~M=5L0j;_8?l*+XC~YB7ZT~N^XY&s-@W-^EQyMWtn|U8c7X@h%58xm zEv3`G-RqHs>uL1M5rZXU0@+TkgC9Tson&CkF2kJzb_49cL8I$o=6HTZNdhK_U$_9A zvO>r3&0g}WU!(@65B8?dh$$R2FQ`g}@^qp{WI3>+EH;fEA*qoWcZ0l<$-A z;uzy8cX^(7TmNfntoELi_%YGda1be1c37zGto|R!_0-V|k4D7}NO|{i00NQ3D(m?*kW)Sl<}1PtVZ`{UL_-M(4-8r3q`ewHv0UM1!{ ztJ_3-dIKPnP0)0t%X!WLtd>0m4$ZX~2q}9>HX@y~%N9&`KgX~pg3G1(}E z40M4_KEcSv8}^Sro!gfa*;I-CcwekYQm|1{5@1gm%Z-K)mFbpbhPa`$dW-fIjy&sS zt+Y18rA?*->*Id{WpjMkOG{HEVVzBpv*9Ye*%F=`aUu<{2D2{W`m{j!KW83x!t-=4z1;|RSNU07W zg0Oimj;jWsug~(|&Bs+{TJB(C8T9l9lTyQ>hbX9{1)S4uqPq>zpN4#VW~leZxPZff zH7>--jVrN2NP!-&GBkB?(peTp=ly2ytAK`)*-L!&$}ugixliW(-_w;-s&>O!+!iEc_iYhffmLqyKrPNZpMO7T9DiCiQ`+09k0e(0vF2d0!pQj7amRXQ+g&Vnbhh!(Ob)BcZZ1Q zC{LW1U9!JZuxXeaexOpk@o2%1MXCay>}DpEWqLR|XAMeIIC7BdV0m~i543VxGH)j5 zHGaBXfL3J5)d|maTg)fESQ!4oDYw=i+okAKU^DtB<<}7D+b6ROWYzq@b8T4}){skU zvQ}^L!$^)(9?YRzmRjTvcsp1Pe|~6f^hS-XW%;@Mrp$#uVJyQmZEbHl@->LRSiI+q z`KP0F&)p!>Om(u3yoNcr+wXI)pIw z4_ENK8*ZrU>G@72l#vh@cBi_!I-B{SNuBfL$M`J&`{9Ob98=mlRhFpvr7rr2#me{S z1X#ZzYn!K5|AUg^=b69j(*2{j#AU*}vzM{9ttsJ4yF>1ddr?4v>F|hZmGJMW5>3_i zZgre@TXf6G_USink@A=fU2(oqU0l538s&sW`0tV$1}lNE5ORz1fdo%<9l9jmKP>vl zrsKzbPQKYhaCP817BYeh7KSbF6TlphR{0DZ^EhZ% z2+>-iadgDWh7C)1rn2PvyEp$GlMEb*oqThNZP`kep|5s)tVdF|KlglrCRe{Dl=My7 zbV-WsP29|y;dC3M8Civ`o5sm$?d zk+8M1FHgKN9-CM;zdy>~_h$0de3K<{r*b0JVJ4oh!R(Ez$s4^;NgtA&o{ou>U>$aO zS)aj_TvQYdnxqT$RbiE~kpGFvKJC$SsrNk~p;1+U$u(l!g|ir3k;<#Cu6o}Fb3o8X zOBAxWensWEPk#uX!+^km5aGkg74i0StX`araPxkb?>wJ+AJempd zW>PG=mNRKFFvNfid!q+7C`jMj;){aIf}6K7zArpkbBY)r7s(-fKU}f*NJU$dLDd>& zH@9l=0G>G9Q{k@RX0vbIi56no>fvV3Y=VY~Ahx3=RTA^6kWVI|$+cF8GXu$PQL?o6 z;WI0IQ;Fl9OpD0qJW@l)3@x^I>6$l0uQy6%fVqW`YQg@g-e&2bLON@eH{6h}>qg$@ z;Vv9H&4NJ$h4$^obufV_ah%qZ@NN5ipHpNd&m%ym)Ux$?=VOn)0_QK@X+yn0au-mY zFo3(7h;_0MlaU?+b1xmhWv6czakesX`V&`6)ON*%8U%oMI<9Wz!n!FL`pZ)*`T6|y zIKRMJ6gRs3ILeK?nuNI3n*wkN;W`tsmQKiA$781lUDt$^Ckz(j_WAN`*wwQqJKzj2 z%N;(VrU~cZcXk}!@$vU7^r9p39pCkgNDU9at;a<1H&QEK}c*1EwqayBuKJXVKl0F7sFOG)udACWw_B z{?D!M=Z8(bF$tZnankqn^wiUPwW-qLRH?(2cwdYUVfLJ-u_5^W-g&kp>ubDuH^ zIU}0jKxe%DPL{U61k%^Tw6hB52w^T|Xa6BtxgJZ!ZhQz`MBR)}m+HKMR9{Cp&YLlV zTGL60G{Dxdi4+DR+>DipJd^GZJ5ha;xaOtJSdDeJ3zYYZ7uCKgk*kD14OXhoB;M#| zvS>YdJ{`l{A>dN9Avz4XRMy@21o$zv%?&Ox5h4XXrTV3o;WOp|;~7w>UuTt2s(Wx!ZlZqmU;37=8rc54d7oS z1;b*NP_(8HBd!)e0A#(qd-B||isZsFIfaHGjSd<+h?uJFKT(fgtE=ldt3QlK`xFmH z_S6cgeLaGP;n`JMnWI(W>{+~8U+lc5AUt{pytuIcY^rqs$(XxQgh^z^TWS?s+rCWp zh+4LqP0aa~>;90i*nFTZgn(WU{wMr?p7yNGsM`hUYuarA8^O??-rh85*yEQWxCk%n zb8+Ul#QU7!ZAwcwl0NQhdB!ONlg$oC;`o;GD7-w1aBmpyO$^-m(tq~#hyEx?$vH38 zomyLM%DLjfLMf*ZoXR~y@*gWrNCI^I+a26x~469&sg4z z|Fe*XDvOuNTzAxioG#3(q6BkP;EiZiR*fV-$!V>71k<%p$p@BU#&=>f$Uv#h$_caW zU|<(HI@s{)Jj2_H+t{PxR{G}smpWa1m!|d2JbDjp*}XU7gs;D1;C%euTlHdEmjGO) zAaLhlBF81JIdSEz4-~(ynwEgLUFbTdKvA`?@7$fU#E3WdfwuAwg5`ZwFmyeW52ccs zfwnN}l~6uJbR1#dz;L$x&{F?rsHB9%=r;%<;OJUREpQ@zy}^~(a`GBIM`D~DD+YHNQmtlS=YCi z3}FEwuDk%qb2Q)Jful0fy5p_5rc^5FcEJo00Yx0o-I-EABaU3ITOARCbXbSfJ? zTv>`yS~UPa?0PocGTDPG!V?m5dGI@;beuEsW4Y;3SHja(2?cW#7jEgPpnP=aX{dE@1)GrX9Azds)r9CC;=D+QL^D~s z=a=Pl7`vmGedeaJc-2{byT;vkRhfkY$A1qiv&eiW0@TuemO|cNLpA%ay{0pL6sq`Y zCD`kIAZpOG*<)+2QM+L7*7)D_6XGSsB?=Uq{_Rr>#>#!Y{PbPYw0ET11uox_WNp7L zF&ztFEsBrVhws%&+XeZs*6w&%A(#%|_&Fumc>_&ll z`upb*lxz{+Zq#==@yd;jwe4CiJmH!b_uPjeNvAgf>3pC?17$F3Fd|wETHs{i`|gvqs4NwGo*e7i%VQ<9M;D=9to3OeHinRYyhgh3_k-(z!Dyvx6&}a z*>}d4-35|j@s?&*G?!>FRJlFJFw{Hh3Mv0g%rJ4sL6{vlY@Xs>71W=xNuD8|e4C+H zVTjV}gQBSXbYlS|PlMh`@8pVOkn?EOiR*%du8%g3t(l)5l&6p?w6$c~YPslpvW^V; zQGta`Um_X>5~`N2sh7E$3`$cPTo+#KoQE=5^EH}LCjuq8}2DZ8T!B^jt__NRSzD)oVvAn?(gTuUJ0iDKUD}WIWAC|topu0uRK#*)m2Xq1OtL#Fn!v6yL3rOF z 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 D>Bt^c+YN#;R_!B6{t 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
&x`dn^FIM|iS7F#pFu(t( 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 指针属性 +- `pto.comm_scope` +- `pto.urma_gm_gm`、`pto.rdma_gm_gm`、`pto.sdma_gm_l2c` +- 融合 `*_signal` / `*_counter` +- kick 返回 CQ 完成记录 + +对端地址目前就是普通 `!pto.ptr`,由 host 按 `windowsIn` 同偏移算好后 +作为 kernel 参数传入。A5 远端写需要 `{soft_put}`,该形态在 op 返回前完成拷贝。 + +## 1. 范式 + +采用 **PGAS / SHMEM** 式对称共享内存 + 单边访问:各 rank 共享段布局一致, +设备侧以「本端指针 + 目标 rank」读写对端同偏移数据,无需对端参与。 + +跨卡交换收敛为三件事:**寻址、搬运、显式同步**。Scale-up(节点内)与 +Scale-out(跨节点)只更换引擎与通路,不改变编程面。 + +![](assets/fig1-topology.png) + +一次通信分两阶段: + +- **Host 准备期**:建通信域、协商对称共享段、按需注册鉴权 MR、初始化异步引擎; + 随 launch 下发寻址上下文(只读)与引擎会话(有状态)。二者职责分离即可, + 字段级 ABI 不在本文展开。 +- **NPU 运行期**:kernel 内算址、发起搬运、用同步量或融合形态约定跨卡可见性。 + +```mermaid +flowchart LR + A["① Bootstrap
带外交换 root info"] --> B["② BuildComm
HCCL 建通信域"] + B --> C["③ 注册对称内存
Window / 鉴权 RMA MR
交换基址表 + token"] + B --> D["④ 逐引擎建 workspace
SDMA · URMA · RDMA
持久化于 device HBM"] + C --> E["CommDeviceContext
寻址上下文 · 只读"] + D --> F["引擎 workspace"] + F --> G["AsyncSession
有状态 · 引用 workspace"] + E --> K["launch 入参"] + G --> K + HC["CommContext
host only · 不下设备"] -.->|"X"| K +``` + +## 2. 共享内存与指针属性 + +跨卡地址空间一律 `gm`。远近与鉴权不另开地址空间,由可组合指针属性表达: + +| 形态 | 含义 | +|------|------| +| `!pto.ptr` | 本端、普通共享内存 | +| `!pto.ptr>` | 本端、已注册鉴权 RMA MR | +| `!pto.ptr` | 远端、普通共享内存 | +| `!pto.ptr, #pto.remote>` | 远端且已注册 | + +`#pto.remote` 管远近,`#pto.mr` 管鉴权;缺省分别为本端、未注册。 +同偏移算址由调用方用 `CommDeviceContext.windowsIn[]` 自行完成: + +```text +remote = windowsIn[peer] + (local − windowsIn[myRank]) +``` + +结果以 `pto.castptr` 等既有手段成型为 `!pto.ptr`(可与 +`#pto.mr` 组合)。不设专用 remap op。 + +![](assets/fig2-shared-memory.png) + +## 3. 完成与可见性(E2 / E3) + +| 事件 | 保证 | 观测 | +|------|------|------| +| **E2** | 本端 source 可复用 | 异步:轮询搬运返回的 CQ 完成记录;同步 MTE:指令/pipe 完成即成立 | +| **E3** | 对端可见本次 payload | 写远端同步量,或使用融合 `*_signal` / `*_counter` | + +E2 与 E3 相互独立:等到 E2 **不**代表对端可见。分离写法必须先到 E2 再发同步量; +融合形态同事务保证,对端观测到同步量即可读 payload。 + +```mermaid +sequenceDiagram + participant H as Host + participant D as rank i Kernel + participant Li as rank i 对称共享内存 + participant Rj as rank j 对称共享内存 + participant P as rank j Kernel + + H->>D: launch(寻址上下文, AsyncSession, 数据 buffer) + H->>P: launch(寻址上下文, AsyncSession, 数据 buffer) + D->>Li: 取得本端 payload / 同步量地址 + D->>D: windowsIn 同偏移算址 → #pto.remote 指针 + + alt 同步通路(MTE) + D->>Rj: 单边写 payload + Note over D,Rj: 返回即本端完成 + else 异步通路(DMA 引擎) + D->>Rj: kick 单边写 payload(不阻塞标量流) + D->>D: wait event → E2:本端源可复用 + end + + D->>Rj: 写 signal / atomic add counter → 发布 E3 + loop 同步量未满足 + P->>Rj: wait / test 本端 signal / counter + Rj-->>P: 未满足则继续轮询 + end + P->>Rj: 读取本端 payload + Rj-->>P: payload(已保证可见) +``` + +跨 rank E3 **不**复用 `cmo.cacheinvalid` / `fence.barrier_all`(核间粗栅栏)。 + +## 4. 同步量(内存约定,无新 op) + +跨 rank 同步量是对称段内用户自划的 `i32` 位置,不是专用指令族: + +| 用法 | 写者 | 发布 | +|------|------|------| +| **signal** | 单写者 | `stg` / `store` / 远端 `mte_ub_gm` | +| **counter** | 多写者汇合 | `atomic_add` | + +观测:本端 `dcci` + `ldg`;等待写成 IR 轮询。与片上 SC 信号量 +(`set_intra_core` 等)互不合并:核间用 SC,跨 rank 用 GM 同步量。 + +## 5. 融合搬运+同步 + +异步通路可将 E3 发布并进同一搬运事务:`*_gm_gm_signal` / `*_gm_gm_counter`。 +这是跨 rank 同步唯一新增的 mnemonic 族;独立发布仍用 §4 的普通访存。 +MTE 同步通路无融合形态。 + +## 6. `comm_scope` + +`comm_scope` 是 `section.vector` / `section.cube` 内的词法区域,给通信资源 +(session / 完成记录等)划寿命边界,并作为 sync 分析锚点。应对齐 +`pto.vecscope` 写在 `docs/vpto-spec.md` 的层级;本节暂存约定,后续迁入该处。 + +```mlir +pto.section.vector { + pto.vecscope { /* 计算 */ } + pto.comm_scope { + %dst = pto.castptr %remote_i64 : i64 -> !pto.ptr + %cq = pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + -> !pto.ptr + } +} +``` + +| 项 | 约定 | +|----|------| +| 位置 | `section.vector` / `section.cube`;**不**进入 `vecscope` | +| 职责 | 资源寿命边界 + Sync 分析锚点 | +| vs `vecscope` | 通信 kick、同步量读写、session、远端指针构造落在 `comm_scope` | +| 推断 | session/event 流可按 SSA 穿线推断;纯同步量流需显式书写 | +| cube | AIC 只发 GM↔GM kick 时 PlanMemory 锚点弱化;资源/Sync 锚点仍成立 | + +开放问题:出口是否默认强制 E2(与正确性正交,影响跨窗 overlap)。 + +## 7. 通路总览 + +| 通路 | 承载 | +|------|------| +| 同步远端 | 核内 MTE:`mte_gm_ub` / `mte_ub_gm` + `#pto.remote` | +| 异步 GM↔GM | SDMA / URMA / RDMA + session | +| 融合 notify | `*_gm_gm_signal` / `*_gm_gm_counter` | diff --git a/docs/isa/micro-isa/18-special-scalar.md b/docs/isa/micro-isa/18-special-scalar.md index a9d4370c0e..30c189a159 100644 --- a/docs/isa/micro-isa/18-special-scalar.md +++ b/docs/isa/micro-isa/18-special-scalar.md @@ -316,8 +316,8 @@ execution scope and cache-control contract are different. - no `l1cache` or `l2cache` policy attribute is accepted; - the op must appear in an ordinary AICore entry function, outside both a `pto.simt_entry` function and `pto.section.simt`; -- the supported target profile is A5 with CANN output version 9.0.0 official - or newer. +- `pto.ld_dev` is supported on A2/A3 and on A5 with CANN output version 9.0.0 + official or newer. `pto.st_dev` is A5-only with that same CANN profile. Both operations are non-atomic. They do not imply synchronization, memory ordering, cache invalidation, cache writeback, or an L2 cache policy. Programs diff --git a/docs/isa/micro-isa/19-async-comm.md b/docs/isa/micro-isa/19-async-comm.md new file mode 100644 index 0000000000..800a1e48e7 --- /dev/null +++ b/docs/isa/micro-isa/19-async-comm.md @@ -0,0 +1,189 @@ +# 19. Async Communication + +> **Category:** Asynchronous GM↔GM engine transfers +> **Pipelines:** SDMA engine kick from an ordinary AICore scalar stream + +This group copies a contiguous GM range through the SDMA engine. The kick does +not wait for the engine except where `{soft_put}` is documented below. The op +does not publish a completion record; local drain and cross-rank visibility are +arranged by the caller. + +This document describes: + +- `pto.session_init` +- `pto.sdma_gm_gm` + +There is no `mte_gm_gm`. Synchronous GM↔UB copies remain in +[2. DMA Copy Programming](02-dma-copy.md). + +These ops must sit in an ordinary AICore entry function. They are illegal +inside `pto.simt_entry` functions and `pto.section.simt`. + +--- + +## Session + +A session cannot be a kernel argument: only `pto.declare_struct` may produce a +`!pto.struct`. The host therefore writes a GM template, and the kernel declares +its own struct and fills it with `pto.session_init`. + +The session type is fixed: + +```mlir +!pto.struct +``` + +The template uses one 8-byte slot per field, in the same order. Narrow fields +occupy the low half of their slot. Each core fills its own copy, so a session +is per-core even when the template is shared and read-only. + +After the fill, a kernel may retune individual fields with `pto.struct_set`. +The channel group is field 4, which is how a multi-core launch gives each core +its own queue without the host naming the core. + +--- + +## Operation Summary + +| Operation | Purpose | +|-----------|---------| +| `pto.session_init` | Copy the host template into a stack-local session struct | +| `pto.sdma_gm_gm` | Kick a contiguous GM→GM copy through the session | + +--- + +### `pto.session_init` + +- **Purpose:** Fill `session` in place from the host-written GM template. +- **Syntax:** + + ```mlir + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + ``` + +- **Operands:** + + | Operand | Type | Description | + |---------|------|-------------| + | `%sess` | the 13-field session struct | Destination; written in place, no result | + | `%sess_gm` | `!pto.ptr` | Base of the host template | + +- **Results:** None. +- **Constraints:** + - `%sess` must use the session struct type above. + - `%sess_gm` must be a GM pointer. + - Must be outside SIMT entry functions and `pto.section.simt`. + - Must be inside an ordinary AICore `pto.kernel` function. +- **Semantics:** Copy each template slot into the corresponding struct field. + The caller keeps using the value `pto.declare_struct` produced. + +```text +for i in 0 .. 13: + session[i] = template_slot[i] +``` + +- **Example:** + + ```mlir + %sess = pto.declare_struct + -> !pto.struct + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + ``` + +--- + +### `pto.sdma_gm_gm` + +- **Purpose:** Copy `%nbytes` contiguous bytes from `%src` to `%dst` through + the SDMA engine attached to `%sess`. +- **Syntax:** + + ```mlir + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + {block_bytes = $block}? {channel_idx = $ch}? {soft_put}? + : !pto.ptr, !pto.ptr, i64, + !pto.struct + ``` + +- **Operands and attributes:** + + | Name | Type | Description | + |------|------|-------------| + | `%dst` | `!pto.ptr` | Destination range; may name peer memory by address | + | `%src` | `!pto.ptr` | Source range; may name peer memory by address | + | `%nbytes` | `i64` | Contiguous byte count | + | `session(%sess)` | the 13-field session struct | Required session | + | `block_bytes` | optional `i64` attr | Split size in bytes; omitted uses the session value | + | `channel_idx` | optional `i64` attr | Channel group for this kick; omitted uses the session value | + | `soft_put` | optional unit attr | A5 remote-write completion path; ignored on A2/A3 | + +- **Results:** None. +- **Constraints:** + - `%dst` and `%src` must be GM pointers. Element types need not match; the + transfer is counted in bytes. + - `%sess` must use the session struct type above. + - There is no stride or burst model. + - `block_bytes`, when present, must be positive and a multiple of 64. + - `channel_idx`, when present, must be less than 40. + - Must be outside SIMT entry functions and `pto.section.simt`. + - Must be inside an ordinary AICore `pto.kernel` function. +- **Semantics:** Post a copy of `%nbytes` bytes from `%src` to `%dst`. The + session supplies the engine connection, the default split, the channel group, + and the service class. Either pointer may address peer memory; peer-ness is + the numeric address, not a pointer attribute. + + Without `{soft_put}` the kick does not wait for the engine. Returning from + the kernel does not mean the destination is visible. The caller observes + completion by an agreed host-side check or a later sync object. + + `{soft_put}` is for a remote write on A5. That generation's engine does not + perform a remote write, so this attr makes the copy complete before the op + returns. A2/A3 ignore it and still post to the engine. + +```text +if soft_put and target is A5: + copy nbytes bytes from src to dst # finished when the op returns +else: + post the copy to the session's engine + return without waiting +``` + +- **Example (local copy):** + + ```mlir + %sess = pto.declare_struct + -> !pto.struct + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + ``` + +- **Example (A5 remote write):** + + ```mlir + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + ``` + +- **Example (per-core channel after init):** + + ```mlir + %bid = pto.get_block_idx + %bid32 = arith.trunci %bid : i64 to i32 + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + pto.struct_set %sess[4], %bid32 + : !pto.struct, i32 + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + ``` diff --git a/docs/vpto-spec.md b/docs/vpto-spec.md index 730cb0ecb8..f6156a3534 100644 --- a/docs/vpto-spec.md +++ b/docs/vpto-spec.md @@ -1336,6 +1336,7 @@ This section provides a categorized overview of all PTO micro Instruction operat | 16 | [Cube Matrix Multiply](isa/micro-isa/16-cube-matmul.md) | GM↔L1 (`l1`/cbuf) staging, L1 raw fill and L1 (`l1`)↔UB/BT/FB side moves, L1→L0A/L0B loads, L0C (`l0c`) matmul, and FIXPIPE MTE writeback | 20 | `pto.mte_gm_l1`, `pto.raw_fill_l1`, `pto.mte_l1_ub`, `pto.mte_gm_l1_frac`, `pto.mte_l1_bt`, `pto.mte_l1_fb`, `pto.mte_l1_l0a`, `pto.mte_l1_l0b`, `pto.mte_l1_l0a_mx`, `pto.mte_l1_l0b_mx`, `pto.mad`, `pto.mad_acc`, `pto.mad_bias`, `pto.mad_mx`, `pto.mad_mx_acc`, `pto.mad_mx_bias`, `pto.mte_l0c_l1`, `pto.mte_l0c_gm`, `pto.mte_l0c_ub` | | 17 | [SIMT Ops](isa/micro-isa/17-simt.md) | SIMT launch, thread/lane queries, vote/shuffle/redux, scalar memory, atomics, scalar math, conversion, entry synchronization, and state preservation | ~65 | `pto.store_vfsimt_info`, `pto.simt_launch`, `pto.get_tid_x`, `pto.get_laneid`, `pto.vote_*`, `pto.shuffle_*`, `pto.redux_*`, `pto.load`, `pto.store`, `pto.atomic_*`, `pto.convert`, `pto.syncthreads`, `pto.keep`, `pto.resume`, etc. | | 18 | [Special Scalar Operations](isa/micro-isa/18-special-scalar.md) | PTO scalar kernel queries, typed pointer/address calculation, scalar-pipeline memory, and ordinary AICore GM L1-bypass access | 10 | `pto.get_block_idx`, `pto.get_subblock_idx`, `pto.get_block_num`, `pto.get_subblock_num`, `pto.castptr`, `pto.addptr`, `pto.load_scalar`, `pto.store_scalar`, `pto.ld_dev`, `pto.st_dev` | +| 19 | [Async Comm](isa/micro-isa/19-async-comm.md) | Async GM↔GM SDMA copy; session filled from a host template | 2 | `pto.session_init`, `pto.sdma_gm_gm` | --- @@ -1361,6 +1362,7 @@ This section provides a categorized overview of all PTO micro Instruction operat | Contiguous Store | 3 | `pto.vsts` with `NORM_B8` / `NORM_B16` / `NORM_B32` dist | | Scatter | 3 | `pto.vscatter` | | Scalar GM access bypassing local L1 data cache | 18 | `pto.ld_dev`, `pto.st_dev` | +| GM→GM SDMA copy | 19 | `pto.sdma_gm_gm` | ### Compute Operations @@ -1393,7 +1395,8 @@ This section provides a categorized overview of all PTO micro Instruction operat ### Scalar & Control Operations Group 14 covers shared MLIR scalar arithmetic. Group 18 catalogs PTO scalar -queries, pointer/address operations, and scalar-memory operations. SIMT scalar +queries, pointer/address operations, and scalar-memory operations. Group 19 +covers session fill and GM↔GM SDMA copies. SIMT scalar operations remain in Group 17, while shared structured-control semantics remain in Group 15. diff --git a/include/PTO/IR/VPTOOps.td b/include/PTO/IR/VPTOOps.td index 6ec1ccabec..aec6cee06c 100644 --- a/include/PTO/IR/VPTOOps.td +++ b/include/PTO/IR/VPTOOps.td @@ -3822,4 +3822,100 @@ def PTO_VsturOp : PTO_VectorMicroOp<"vstur", [ }]; } +//===----------------------------------------------------------------------===// +// Async communication +//===----------------------------------------------------------------------===// +// +// Asynchronous GM->GM transfers driven by a DMA engine. The kick does not block +// the scalar stream; ordering against the transfer is the caller's job. +// +// The session operand is the config half of an async session: a stack-local +// struct whose field positions are fixed by PTO/Support/AsyncSessionABI.h. The +// mutable half (queue rings, post ids) stays in the workspace that the session's +// context field points at, because it must survive across kernel launches. + +def SessionInitOp : PTO_MicroOp<"session_init", [ + DeclareOpInterfaceMethods + ]> { + let summary = "Fill a session config struct from a template in GM."; + let description = [{ + Copy the session the host prepared at `template_gm` into `session`, field by + field. The struct is written in place, so this produces no result and the + caller keeps using the value `pto.declare_struct` gave it. + + This exists because a session cannot be handed to a kernel directly: a + stack-local struct may be neither a function argument nor the result of any + op other than `pto.declare_struct`. A kernel therefore declares its own and + fills it, and without this op that means spelling out one load and one store + per field at every entry point. + + The template holds one 8-byte slot per field, indexed the same way the + struct is, so the host writes it through the same field enumeration the + expansion reads it with. Narrow fields occupy the low half of their slot. + + Each core fills its own copy, so a session is per-core state even though the + template it came from is shared and read-only. + }]; + + let arguments = (ins + StructType:$session, + PTO_BufferType:$template_gm + ); + + let results = (outs); + + let hasVerifier = 1; + + let assemblyFormat = [{ + $session `,` $template_gm attr-dict + `:` qualified(type($session)) `,` type($template_gm) + }]; +} + +def SdmaGmGmOp : PTO_MicroOp<"sdma_gm_gm", [ + DeclareOpInterfaceMethods + ]> { + let summary = "Kick an asynchronous SDMA copy between two GM ranges."; + let description = [{ + Post a transfer of `nbytes` contiguous bytes from `src` to `dst` to the SDMA + engine and continue without waiting. Either side may name peer memory. + + There is no stride or burst model: the transfer is one contiguous range. + Splitting it across engine posts is driven by the session's block size, so a + caller that wants a specific split sets `block_bytes`. + + `channel_idx` selects a channel group other than the session default, which + is the block index. Two cores sharing a group would corrupt each other's + queue rings, so an explicit index has to be chosen with that in mind. + + Service class is not a per-post knob: it is fixed for the session when the + host builds it, since it describes how these transfers share the memory + system rather than what any one of them does. + + The op reads the channel descriptors and advances the queue tail in the + workspace, then rings the engine doorbell. Completion is not observable from + the op itself; the caller polls the agreed synchronization word. + }]; + + let arguments = (ins + PTO_BufferType:$destination, + PTO_BufferType:$source, + I64:$nbytes, + StructType:$session, + OptionalAttr:$block_bytes, + OptionalAttr:$channel_idx, + OptionalAttr:$soft_put + ); + + let results = (outs); + + let hasVerifier = 1; + + let assemblyFormat = [{ + $destination `,` $source `,` $nbytes `session` `(` $session `)` attr-dict + `:` type($destination) `,` type($source) `,` type($nbytes) `,` + qualified(type($session)) + }]; +} + #endif // MLIR_DIALECT_PTO_IR_VPTOOPS diff --git a/include/PTO/Support/AsyncSessionABI.h b/include/PTO/Support/AsyncSessionABI.h new file mode 100644 index 0000000000..cc90b065f2 --- /dev/null +++ b/include/PTO/Support/AsyncSessionABI.h @@ -0,0 +1,417 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +#ifndef PTO_SUPPORT_ASYNCSESSIONABI_H +#define PTO_SUPPORT_ASYNCSESSIONABI_H + +#include +#include + +// Layout contract shared by the host that populates an async workspace, the +// device code that reads it, and the compiler passes that generate that device +// code. Every hard-coded field position must come from here. +// +// The constants below fall into three groups that differ in who owns them, how +// often they change, and what can be done to catch a change. Keeping the groups +// apart is the point of this file's structure, because a check that suits one +// group is worthless for another. +// +// 1. Ours. The session config field order and the channel record layout are +// invented here; the host writes them, generated code reads them, and no +// outside party has to agree. Nothing can drift, so nothing is checked. +// +// 2. Foreign, produced elsewhere. The async workspace and its channel +// descriptors are written by the AICPU STARS query. We only read them, so +// the layout is not ours to fix and can move between CANN releases. It is +// therefore confined to the host, which reads it once at init, checks it +// against values it fed the query, and repacks into group 1. Generated +// code never sees it. +// +// 3. Hardware, per generation. The SQE is the DMA engine's queue entry +// format. It is fixed for a generation and changes only across them, which +// is what the a5/a2a3 split expresses. No check is possible at build or +// run time -- a wrong bit is simply wrong behaviour -- so the only +// assurance is running it on each generation's silicon. +// +// An async session splits in two, because one aggregate cannot serve both +// halves: +// +// - Config: immutable scalars, carried in a stack-local `!pto.struct` filled +// once per core at kernel entry so later reads cost no memory traffic. +// - Runtime: the queue tail/head pair, which tracks a hardware queue position +// and therefore has to survive across kernel launches; a stack copy would +// silently drop it. It stays where the engine keeps it, and the channel +// record names its address. +// +// `!pto.struct` also rejects array fields, which independently keeps the +// per-channel state out of the config struct. + +namespace mlir::pto::comm { + +//===----------------------------------------------------------------------===// +// Group 1: ours +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Session config struct +//===----------------------------------------------------------------------===// + +// Field positions in the session config struct, spelled in IR as +// !pto.struct +// and addressed by `pto.struct_get` / `pto.struct_set`. +// +// Pointers are carried as `i64` because `!pto.struct` rejects pointer fields; +// consumers cast back with `pto.castptr`. +enum class SessionField : int64_t { + // Base of the channel record table in GM, which the host builds at init. It + // is not the async workspace itself: the workspace holds the descriptors the + // STARS query wrote, in a layout owned elsewhere, and this points at the + // repacked view of them. + ContextGm = 0, + // Base of the UB scratch used for staging. Required wherever the doorbell is + // only reachable by MTE, since the tail has to pass through UB to get there. + TmpBufAddr = 1, + TmpBufSize = 2, + // Pipe event id for that staging. It is a session field rather than a fixed + // id so a kernel already using MTE3 events can keep the two apart. + SyncId = 3, + // Channel group owned by this core. Defaults to the block index, which is + // what makes the queue state per-core rather than shared. + ChannelIdx = 4, + // Channels in the group. Bounds the per-channel descriptor indexing. + ChannelNum = 5, + // Bytes per engine post; drives how one transfer splits into SQEs. + BlockBytes = 6, + CommBlockOffset = 7, + Engine = 8, + DestRankId = 9, + QpIdx = 10, + Flags = 11, + // Memory-system service class for the transfers this session posts, in the + // MPAM sense: it shapes priority and bandwidth share, not correctness. The + // host sets it when it builds the session, matching how the surrounding stack + // treats QoS as a property of the communication domain rather than of one + // transfer. It is deliberately independent of any QoS the domain itself was + // configured with, because these posts bypass that path and drive the queue + // directly. + Qos = 12, + NumFields = 13, +}; + +constexpr int64_t sessionFieldIndex(SessionField field) { + return static_cast(field); +} + +constexpr unsigned kSessionNumFields = + static_cast(SessionField::NumFields); + +enum class SessionEngine : uint32_t { + Sdma = 0, + Urma = 1, + Rdma = 2, +}; + +// Bits in SessionField::Flags. +constexpr uint32_t kSessionFlagValid = 1u << 0; + +//===----------------------------------------------------------------------===// +// Session template (GM) +//===----------------------------------------------------------------------===// +// +// What the host writes so a kernel does not have to spell its session out in +// constants. The kernel copies it into its own stack-local struct at entry, so +// this is a read-only initial value, not shared state: each core gets its own +// copy and may then diverge. +// +// The layout is one 8-byte slot per field, so an offset is the field index +// scaled and neither side needs a table. That wastes a few bytes on the 32-bit +// fields, which is irrelevant for a per-launch template and buys the property +// that matters: host and generated code address this through the same +// SessionField enum, so there is no second list of fields to keep in step. + +namespace session_tmpl { + +constexpr size_t kSlotBytes = 8; +constexpr size_t kBytes = kSessionNumFields * kSlotBytes; + +constexpr size_t slotOffset(SessionField field) { + return static_cast(sessionFieldIndex(field)) * kSlotBytes; +} + +// Fills the template by field rather than by position, so adding a field +// cannot silently shift the ones after it. Narrow fields are written into the +// low half of their slot, which is where a 32-bit load looks on a +// little-endian target. +class Builder { +public: + Builder &set(SessionField field, uint64_t value) { + slots_[sessionFieldIndex(field)] = value; + return *this; + } + + uint64_t get(SessionField field) const { + return slots_[sessionFieldIndex(field)]; + } + + const void *data() const { return slots_; } + static constexpr size_t bytes() { return kBytes; } + +private: + uint64_t slots_[kSessionNumFields] = {}; +}; + +} // namespace session_tmpl + +//===----------------------------------------------------------------------===// +// Channel record (64 bytes) +//===----------------------------------------------------------------------===// +// +// Everything a post needs about one channel, in a layout this project defines. +// The host fills the table at init from the descriptors the STARS query wrote, +// after checking them; generated code reads only this. +// +// The head and tail are held as addresses rather than copies because the engine +// reads and advances them in place. Resolving them here is what keeps the +// foreign descriptor layout out of generated code: a release that moves those +// fields changes two host-side address computations and nothing else. + +namespace channel { + +constexpr size_t kRecordBytes = 64; + +constexpr size_t kSqBaseOffset = 0; // uint64, SQE ring base +constexpr size_t kDoorbellOffset = 8; // uint64, doorbell register base +constexpr size_t kTailAddrOffset = 16; // uint64, address of the live tail +constexpr size_t kHeadAddrOffset = 24; // uint64, address of the live head +// Queue depth less one, so wrapping is a mask rather than a division. The +// depth is a power of two and the host rejects it otherwise, which is what +// makes the two equivalent. Dividing here would be worse than slow: the +// divisor is data read from memory, and a zero one stops the core with the +// stream never completing, which takes the card down with it. A mask of zero +// merely aims every post at slot zero. +constexpr size_t kSlotMaskOffset = 32; // uint32 +constexpr size_t kStreamIdOffset = 36; // uint32 +// 40..63 reserved. + +// Record for one channel of one group, relative to SessionField::ContextGm. +constexpr size_t recordOffset(unsigned channelIdx, unsigned channelNum, + unsigned channelInGroup) { + return (static_cast(channelIdx) * channelNum + channelInGroup) * + kRecordBytes; +} + +} // namespace channel + +//===----------------------------------------------------------------------===// +// Group 2: foreign, host-only +//===----------------------------------------------------------------------===// +// +// The async workspace as the AICPU STARS query leaves it. Read once at init, +// checked, and repacked into the channel records above. +// +// Nothing here may be used by a compiler pass or reach generated code. These +// positions are a CANN-release fact, not a hardware one, and they have already +// moved once; baking them into an instruction stream turns a future move into a +// wrong address at run time instead of a failed check at init. + +namespace workspace { + +// Most channels the query is asked for. Descriptors past what it actually +// populated are left as allocated, so a session must not index beyond the count +// the header below reports. +constexpr unsigned kMaxChannels = 40; +constexpr unsigned kSqDepth = 2048; +// Shortest transfer the engine accepts. +constexpr unsigned kMinTransferBytes = 64; + +// Flag-info header that precedes the channel table. It carries no version or +// magic, so it says nothing about the layout, but totalQueueNum does report how +// far the table was populated -- the one thing here that need not be assumed. +constexpr size_t kFlagInfoBytes = 64; +constexpr size_t kFlagInfoFlagOffset = 0; // uint32 +constexpr size_t kFlagInfoTotalQueueNumOffset = 4; // uint32 + +// Region the AICPU STARS query fills in: the flag-info header followed by the +// full channel table, padded out. The host must allocate at least this much, +// because the query writes the whole table regardless of how many channels a +// session ends up using. +constexpr size_t kContextBytes = 16 * 1024; + +// Per-group payload area that follows the context region. Nothing here is used +// by a plain transfer; it backs the flag/signal variants. It is still part of +// the allocation so the layout matches what the rest of the stack expects. +constexpr size_t kFlagPayloadBytesPerGroup = 512; + +constexpr size_t kTotalBytes = + kContextBytes + kMaxChannels * kFlagPayloadBytesPerGroup; + +//===----------------------------------------------------------------------===// +// Channel descriptor (64 bytes). Holds both the engine-facing queue geometry +// and the mutable head/tail pair. Head and tail are adjacent and are persisted +// together as one 64-bit store, tail in the high half. +//===----------------------------------------------------------------------===// + +constexpr size_t kChannelDescBytes = 64; + +constexpr size_t kChannelSqHeadOffset = 0; // uint32 +constexpr size_t kChannelSqTailOffset = 4; // uint32 +constexpr size_t kChannelSqBaseOffset = 8; // uint64, SQE ring base +constexpr size_t kChannelSqRegBaseOffset = 16; // uint64, doorbell address +constexpr size_t kChannelSqDepthOffset = 24; // uint32 +constexpr size_t kChannelSqIdOffset = 28; // uint32 +constexpr size_t kChannelCqIdOffset = 32; // uint32 +constexpr size_t kChannelLogicCqIdOffset = 36; // uint32 +constexpr size_t kChannelCqeAddrOffset = 40; // uint64 +constexpr size_t kChannelReportCqeNumOffset = 48; // uint32 +constexpr size_t kChannelStreamIdOffset = 52; // uint32 +constexpr size_t kChannelDevIdOffset = 56; // uint32 + +// Descriptor for one channel of one group, relative to SessionField::ContextGm. +constexpr size_t channelDescOffset(unsigned channelIdx, unsigned channelNum, + unsigned channelInGroup) { + return kFlagInfoBytes + + (static_cast(channelIdx) * channelNum + channelInGroup) * + kChannelDescBytes; +} + +} // namespace workspace + +//===----------------------------------------------------------------------===// +// Group 3: hardware, per generation +//===----------------------------------------------------------------------===// +// +// SDMA SQE (64 bytes). +// +// A post writes only the fields a memcpy needs; the rest of the slot is left as +// the host initialized it. +// +// The two generations share the slot size, the SQE type, the stream/task word, +// the credit position, and the address pair, but differ everywhere else that +// matters: A5 moved the transfer length to offset 48, where A2/A3 keeps a link +// type, and A2/A3 puts an `ie2` bit ahead of sssv in word 4, shifting the four +// address-attribute bits up by one. +// +// This is the one group with no automatic protection. A wrong bit produces +// wrong engine behaviour with nothing to catch it, so each generation's +// constants are only as good as a run on that generation's hardware. A2/A3 has +// had one; A5 has not. + +namespace sqe { + +constexpr size_t kBytes = 64; + +// Word 1: rtStreamId:16 | taskId:16 +constexpr size_t kWord1Offset = 4; +constexpr unsigned kRtStreamIdShift = 0; +constexpr unsigned kTaskIdShift = 16; + +// Word 3 holds the credit at the same position on both generations. +constexpr size_t kWord3Offset = 12; +constexpr unsigned kKernelCreditShift = 16; + +constexpr size_t kWord0Offset = 0; +constexpr size_t kWord4Offset = 16; + +// Address pair. Low and high halves are adjacent, so each address is one +// 64-bit store. +constexpr size_t kSrcAddrOffset = 32; +constexpr size_t kDstAddrOffset = 40; + +constexpr uint32_t kTypeSdma = 11; +constexpr unsigned kTypeShift = 0; +constexpr unsigned kOpcodeShift = 0; + +// Four bits on both generations, so the same session value is valid either way +// even though the field lives in a different word. The default matches what the +// reference SDMA implementation posts. +constexpr uint32_t kQosMask = 0xF; +constexpr uint32_t kQosDefault = 6; + +namespace a5 { + +// Word 0: type:6 | lock:1 | unlock:1 | ie:1 | preP:1 | postP:1 | wrCqe:1 | +// ptrMode:1 | rttMode:1 | headUpdate:1 | reserved0:1 | numBlocks:16 +constexpr unsigned kWrCqeShift = 11; +constexpr unsigned kNumBlocksShift = 16; + +// Word 4: opcode:8 | sssv:1 | dssv:1 | sns:1 | dns:1 | sro:1 | dro:1 | +// stride:2 | ie2:1 | compEn:1 | res4:14 +constexpr unsigned kSssvShift = 8; +constexpr unsigned kDssvShift = 9; +constexpr unsigned kSnsShift = 10; +constexpr unsigned kDnsShift = 11; + +constexpr size_t kLengthOffset = 48; + +// Word 5: sqeId:16 | mpamPartId:8 | mpamns:1 | pmg:2 | qos:4 | d2dOffsetFlag:1 +// +// QoS sits in a different word here than on A2/A3, where it shares word 4 with +// the address attributes. Nothing else in word 5 is written, so the whole word +// is the QoS field shifted into place. +constexpr size_t kWord5Offset = 20; +constexpr unsigned kQosShift = 27; + +constexpr uint32_t kKernelCreditDefault = 254; + +// Source and destination are both "secure, non-shareable" virtual addresses. +constexpr uint32_t kWord4Memcpy = + (1u << kSssvShift) | (1u << kDssvShift) | (1u << kSnsShift) | (1u << kDnsShift); + +// SDMA type, request a CQE, single block. +constexpr uint32_t kWord0Memcpy = + (kTypeSdma << kTypeShift) | (1u << kWrCqeShift); + +constexpr uint32_t kWord3Memcpy = kKernelCreditDefault << kKernelCreditShift; + +} // namespace a5 + +namespace a2a3 { + +// Word 0: type:6 | res1:10 | blockDim:16. There is no wrCqe bit here; the +// A2/A3 SQE reports completion without being asked. +constexpr unsigned kBlockDimShift = 16; + +// Word 4: opcode:8 | ie2:1 | sssv:1 | dssv:1 | sns:1 | dns:1 | qos:4 | +// sro:1 | dro:1 | partid:8 | mpam:1 | res6:4 +constexpr unsigned kIe2Shift = 8; +constexpr unsigned kSssvShift = 9; +constexpr unsigned kDssvShift = 10; +constexpr unsigned kSnsShift = 11; +constexpr unsigned kDnsShift = 12; +constexpr unsigned kQosShift = 13; + +constexpr size_t kLengthOffset = 28; + +// Byte 48 starts linkType:8 followed by three reserved bytes, so the whole +// word is written at once. +constexpr size_t kLinkTypeOffset = 48; +constexpr uint32_t kLinkTypeNone = 255; + +constexpr uint32_t kKernelCreditDefault = 240; + +// QoS is not folded in here: it comes from the session, so the expansion ors it +// into this word at run time. +constexpr uint32_t kWord4Memcpy = + (1u << kSssvShift) | (1u << kDssvShift) | (1u << kSnsShift) | + (1u << kDnsShift); + +constexpr uint32_t kWord0Memcpy = kTypeSdma << kTypeShift; + +constexpr uint32_t kWord3Memcpy = kKernelCreditDefault << kKernelCreditShift; + +} // namespace a2a3 + +// Doorbell address relative to the channel's sq_reg_base. +constexpr size_t kDoorbellOffsetA5 = 0; +constexpr size_t kDoorbellOffsetA2A3 = 8; + +} // namespace sqe + +} // namespace mlir::pto::comm + +#endif // PTO_SUPPORT_ASYNCSESSIONABI_H diff --git a/lib/PTO/IR/VPTO.cpp b/lib/PTO/IR/VPTO.cpp index fbbc92e232..687ba63f04 100644 --- a/lib/PTO/IR/VPTO.cpp +++ b/lib/PTO/IR/VPTO.cpp @@ -17,6 +17,7 @@ #include "PTO/Support/CodeConstants.h" #include "PTO/IR/PTO.h" #include "PTO/IR/PTOTypeUtils.h" +#include "PTO/Support/AsyncSessionABI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/SCF/IR/SCF.h" @@ -708,6 +709,121 @@ LogicalResult PTOStDevOp::verify() { getValue().getType()); } +// The config half of an async session. Field positions and widths are fixed by +// PTO/Support/AsyncSessionABI.h, because the expansion indexes them by position +// and the host fills the matching workspace layout. +static LogicalResult verifyAsyncSessionType(Operation *op, Type sessionType) { + auto structTy = dyn_cast(sessionType); + if (!structTy) + return op->emitOpError() << "requires a !pto.struct session operand"; + + ArrayRef fields = structTy.getFieldTypes(); + if (fields.size() != comm::kSessionNumFields) + return op->emitOpError() + << "session struct must have exactly " << comm::kSessionNumFields + << " fields to match the async session ABI, but has " + << fields.size(); + + auto expectWidth = [&](comm::SessionField field, + unsigned width) -> LogicalResult { + Type fieldTy = fields[comm::sessionFieldIndex(field)]; + auto intTy = dyn_cast(fieldTy); + if (!intTy || intTy.getWidth() != width) + return op->emitOpError() + << "session field " << comm::sessionFieldIndex(field) + << " must be i" << width << " per the async session ABI, but is " + << fieldTy; + return success(); + }; + + for (auto [field, width] : + {std::pair{comm::SessionField::ContextGm, 64u}, + std::pair{comm::SessionField::TmpBufAddr, 64u}, + std::pair{comm::SessionField::TmpBufSize, 32u}, + std::pair{comm::SessionField::SyncId, 32u}, + std::pair{comm::SessionField::ChannelIdx, 32u}, + std::pair{comm::SessionField::ChannelNum, 32u}, + std::pair{comm::SessionField::BlockBytes, 64u}, + std::pair{comm::SessionField::CommBlockOffset, 64u}, + std::pair{comm::SessionField::Engine, 32u}, + std::pair{comm::SessionField::DestRankId, 32u}, + std::pair{comm::SessionField::QpIdx, 32u}, + std::pair{comm::SessionField::Flags, 32u}, + std::pair{comm::SessionField::Qos, 32u}}) { + if (failed(expectWidth(field, width))) + return failure(); + } + return success(); +} + +static LogicalResult verifyAsyncTransferPtr(Operation *op, Type ptrType, + StringRef role) { + auto ptrTy = dyn_cast(ptrType); + if (!ptrTy) + return op->emitOpError() << role << " must be a !pto.ptr"; + if (ptrTy.getMemorySpace().getAddressSpace() != AddressSpace::GM) + return op->emitOpError() << role << " must be a GM pointer"; + return success(); +} + +LogicalResult SessionInitOp::verify() { + if (failed(verifyAsyncSessionType(getOperation(), getSession().getType()))) + return failure(); + if (failed(verifyAsyncTransferPtr(getOperation(), getTemplateGm().getType(), + "template"))) + return failure(); + + // The fill reads GM with pto.ld_dev, which a SIMT scope does not provide, and + // the session it fills is only usable by ops under the same restriction. + if (isInsideSimtExecutionScope(getOperation())) + return emitOpError() + << "must be outside pto.simt_entry functions and pto.section.simt"; + auto funcOp = getOperation()->getParentOfType(); + if (!funcOp || !pto::isPTOEntryFunction(funcOp)) + return emitOpError() + << "requires an enclosing ordinary AICore entry function"; + return success(); +} + +LogicalResult SdmaGmGmOp::verify() { + if (failed(verifyAsyncTransferPtr(getOperation(), getDestination().getType(), + "destination"))) + return failure(); + if (failed(verifyAsyncTransferPtr(getOperation(), getSource().getType(), + "source"))) + return failure(); + if (failed(verifyAsyncSessionType(getOperation(), getSession().getType()))) + return failure(); + + // The expansion posts to the queue with scalar GM stores and, on A5, rings the + // doorbell with pto.st_dev. None of that is legal under SIMT, so reject here + // rather than letting the expansion fail later with a less obvious diagnostic. + if (isInsideSimtExecutionScope(getOperation())) + return emitOpError() + << "must be outside pto.simt_entry functions and pto.section.simt"; + auto funcOp = getOperation()->getParentOfType(); + if (!funcOp || !pto::isPTOEntryFunction(funcOp)) + return emitOpError() + << "requires an enclosing ordinary AICore entry function"; + + if (auto blockBytes = getBlockBytes()) { + if (*blockBytes == 0) + return emitOpError() << "block_bytes must be positive"; + if (*blockBytes % comm::workspace::kMinTransferBytes != 0) + return emitOpError() << "block_bytes must be a multiple of " + << comm::workspace::kMinTransferBytes; + } + + // Only the first kMaxChannels descriptors are filled in; a group past that + // reads whatever the allocation happened to contain. + if (auto channelIdx = getChannelIdx()) { + if (*channelIdx >= comm::workspace::kMaxChannels) + return emitOpError() << "channel_idx must be less than " + << comm::workspace::kMaxChannels; + } + return success(); +} + LogicalResult ShuffleIdxOp::verify() { return verifyShuffleSemanticControl(getOperation(), getIndex().getType(), getWidthAttr(), "index"); @@ -852,6 +968,26 @@ void PTOStDevOp::getEffects( effects.emplace_back(MemoryEffects::Write::get(), &getPtrMutable()); } +void SessionInitOp::getEffects( + SmallVectorImpl> + &effects) { + effects.emplace_back(MemoryEffects::Read::get(), &getTemplateGmMutable()); + // Writing the session is what keeps this from being sunk past the posts that + // read it, or dropped when nothing appears to consume it. + effects.emplace_back(MemoryEffects::Write::get(), &getSessionMutable()); +} + +void SdmaGmGmOp::getEffects( + SmallVectorImpl> + &effects) { + effects.emplace_back(MemoryEffects::Read::get(), &getSourceMutable()); + effects.emplace_back(MemoryEffects::Write::get(), &getDestinationMutable()); + // The queue tail in the channel descriptor is read and advanced, so two posts + // on one session must not be reordered or dropped. + effects.emplace_back(MemoryEffects::Read::get(), &getSessionMutable()); + effects.emplace_back(MemoryEffects::Write::get(), &getSessionMutable()); +} + template static void getAtomicEffects( OpTy op, diff --git a/lib/PTO/Transforms/VPTOExpandWrapperOps.cpp b/lib/PTO/Transforms/VPTOExpandWrapperOps.cpp index 529c26b54b..f4166a768d 100644 --- a/lib/PTO/Transforms/VPTOExpandWrapperOps.cpp +++ b/lib/PTO/Transforms/VPTOExpandWrapperOps.cpp @@ -9,6 +9,7 @@ #include "PTO/Support/CodeConstants.h" #include "PTO/IR/PTO.h" #include "PTO/IR/PTOTypeUtils.h" +#include "PTO/Support/AsyncSessionABI.h" #include "PTO/Transforms/Passes.h" #include "mlir/Dialect/Arith/IR/Arith.h" @@ -2077,6 +2078,545 @@ struct ExpandAtomicConfigPattern } }; +//===----------------------------------------------------------------------===// +// Async SDMA post +//===----------------------------------------------------------------------===// + +namespace comm_abi = mlir::pto::comm; + +// Materialize a GM pointer to `elementType` at `baseAddr + byteOffset`. +// +// Descriptor and SQE fields sit at fixed byte offsets but have mixed widths, so +// each access folds its offset into the address and then loads or stores at +// element index zero. That keeps the element-offset operand of ld_dev/st_dev out +// of the picture, where a stale element size would silently move the access. +static Value gmFieldPointer(Location loc, PatternRewriter &rewriter, + Value baseAddr, int64_t byteOffset, + Type elementType) { + Value addr = baseAddr; + if (byteOffset != 0) { + Value offset = getI64Constant(loc, rewriter, byteOffset); + addr = rewriter.create(loc, addr, offset); + } + auto ptrType = pto::PtrType::get( + rewriter.getContext(), elementType, + pto::AddressSpaceAttr::get(rewriter.getContext(), pto::AddressSpace::GM)); + return rewriter.create(loc, ptrType, addr); +} + +static Value loadDevField(Location loc, PatternRewriter &rewriter, + Value baseAddr, int64_t byteOffset, + Type elementType) { + Value ptr = gmFieldPointer(loc, rewriter, baseAddr, byteOffset, elementType); + Value zero = rewriter.create(loc, 0); + return rewriter.create(loc, elementType, ptr, zero); +} + +static void storeDevField(Location loc, PatternRewriter &rewriter, + Value baseAddr, int64_t byteOffset, Value value) { + Value ptr = + gmFieldPointer(loc, rewriter, baseAddr, byteOffset, value.getType()); + Value zero = rewriter.create(loc, 0); + rewriter.create(loc, value, ptr, zero); +} + +// Descriptor and SQE writes go through an ordinary store, not st_dev. +// +// On 910B1 only the first handful of st_dev stores to HBM take effect and the +// rest are dropped, with barriers making no difference; an ordinary store lands +// every time. That is enough to disqualify st_dev here, since one post writes +// seven words per SQE. st_dev is still what rings the doorbell, which is a real +// device register rather than memory. +static void storeGmField(Location loc, PatternRewriter &rewriter, + Value baseAddr, int64_t byteOffset, Value value) { + Value ptr = + gmFieldPointer(loc, rewriter, baseAddr, byteOffset, value.getType()); + Value zero = rewriter.create(loc, 0); + rewriter.create(loc, ptr, zero, value); +} + +// A2/A3 rings the doorbell through UB instead of storing to it. +// +// sq_reg_base names a register rather than memory, and on this generation it +// only takes a value that arrives by MTE: st_dev has no effect there, and a +// scalar store to it faults the vector unit hard enough to leave the card in +// an unrecoverable RAS state. Staging the tail in UB and moving four bytes out +// is what the reference SDMA implementation does. +// +// The staging slot is the session's tmp_buf, which exists for exactly this. +static void ringDoorbellViaUb(Location loc, PatternRewriter &rewriter, + Value tmpBufAddr, Value syncId32, + Value doorbellAddr, int64_t byteOffset, + Value tail32) { + MLIRContext *ctx = rewriter.getContext(); + Type i32Type = rewriter.getI32Type(); + + auto ubPtrType = pto::PtrType::get( + ctx, i32Type, pto::AddressSpaceAttr::get(ctx, pto::AddressSpace::VEC)); + Value ubPtr = rewriter.create(loc, ubPtrType, tmpBufAddr); + Value zeroIdx = rewriter.create(loc, 0); + rewriter.create(loc, ubPtr, zeroIdx, tail32); + + // The scalar unit has to be done with the slot before MTE3 picks it up. The + // event id comes from the session so a caller who is already using MTE3 + // events elsewhere can keep this staging off them; a fixed id would collide + // silently. + auto pipe = [&](pto::PIPE p) { return pto::PipeAttr::get(ctx, p); }; + Value eventId = rewriter.create( + loc, rewriter.getIndexType(), syncId32); + rewriter.create(loc, pipe(pto::PIPE::PIPE_S), + pipe(pto::PIPE::PIPE_MTE3), eventId); + rewriter.create(loc, pipe(pto::PIPE::PIPE_S), + pipe(pto::PIPE::PIPE_MTE3), eventId); + + Value dbPtr = + gmFieldPointer(loc, rewriter, doorbellAddr, byteOffset, i32Type); + Value four = getI64Constant(loc, rewriter, 4); + Value one = getI64Constant(loc, rewriter, 1); + Value zero = getI64Constant(loc, rewriter, 0); + + // A doorbell takes one 32-bit write. The default c220 store carries its + // length in 32-byte blocks and would round these four bytes down to a + // transfer of nothing, leaving the engine waiting on a ring it was never + // told about, so this asks for the byte-granular path. + auto doorbellStore = rewriter.create( + loc, ubPtr, dbPtr, zero, one, four, zero, zero, zero); + doorbellStore->setAttr("vpto.byte_granular", rewriter.getUnitAttr()); +} + +// Those stores land in the data cache, and the engine reads memory, so the +// cache has to be pushed out before the doorbell is rung. One flush of the +// whole data cache covers every SQE of the post plus the descriptor, which is +// also what the reference SDMA implementation does. +static void writebackDataCache(Location loc, PatternRewriter &rewriter, + Value addr) { + Value ptr = gmFieldPointer(loc, rewriter, addr, 0, rewriter.getI8Type()); + rewriter.create( + loc, ptr, + pto::DcciCacheLineAttr::get(rewriter.getContext(), + pto::DcciCacheLine::ENTIRE_DATA_CACHE), + pto::DcciDstAttr{}); +} + +static Value getI32Constant(Location loc, PatternRewriter &rewriter, + int64_t value) { + return rewriter.create(loc, value, 32); +} + +// Read one session config field and widen it to i64 for address arithmetic. +static Value readSessionFieldI64(Location loc, PatternRewriter &rewriter, + Value session, comm_abi::SessionField field, + unsigned width) { + Type fieldType = rewriter.getIntegerType(width); + Value raw = rewriter.create( + loc, fieldType, session, + rewriter.getDenseI64ArrayAttr({comm_abi::sessionFieldIndex(field)})); + if (width == 64) + return raw; + return rewriter.create(loc, rewriter.getI64Type(), raw); +} + +// For fields that stay 32-bit all the way into an SQE word or an event id, +// where widening to i64 would only have to be undone. +static Value readSessionFieldI32(Location loc, PatternRewriter &rewriter, + Value session, comm_abi::SessionField field) { + return rewriter.create( + loc, rewriter.getI32Type(), session, + rewriter.getDenseI64ArrayAttr({comm_abi::sessionFieldIndex(field)})); +} + +// Expand a session fill into one load and one store per field. +// +// The template gives every field an 8-byte slot, so a field's address is its +// index scaled, and a narrow field is read at the base of its slot because the +// host wrote it into the low half. +struct ExpandSessionInitPattern : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(pto::SessionInitOp op, + PatternRewriter &rewriter) const override { + Location loc = op.getLoc(); + Value session = op.getSession(); + auto structType = cast(session.getType()); + + Value templateAddr = rewriter.create( + loc, rewriter.getI64Type(), op.getTemplateGm()); + + for (unsigned i = 0; i < comm_abi::kSessionNumFields; ++i) { + Type fieldType = structType.getFieldTypes()[i]; + const int64_t offset = + static_cast(i * comm_abi::session_tmpl::kSlotBytes); + Value value = loadDevField(loc, rewriter, templateAddr, offset, fieldType); + rewriter.create( + loc, session, rewriter.getDenseI64ArrayAttr({static_cast(i)}), + value); + } + + rewriter.eraseOp(op); + return success(); + } +}; + +// Expand one asynchronous SDMA post into descriptor reads, SQE writes, a +// release barrier, and a doorbell write. +// +// The transfer is split into at most `block_bytes` per SQE. Splitting runs as an +// scf.for whose trip count is only known at runtime, mirroring how the DMA +// wrapper ops expand their software loops. +// +// This version drives a single channel of the group. Spreading a post across the +// group is a scheduling policy on top of the same sequence and is left to a +// follow-up. +struct ExpandSdmaGmGmPattern : public OpRewritePattern { + ExpandSdmaGmGmPattern(MLIRContext *context, DmaArch dmaArch) + : OpRewritePattern(context), dmaArch(dmaArch) {} + + LogicalResult matchAndRewrite(pto::SdmaGmGmOp op, + PatternRewriter &rewriter) const override { + Location loc = op.getLoc(); + Value session = op.getSession(); + + // A5's engine will not PUT to a peer. The same kick becomes a synchronous + // GM→UB→GM copy, which is how the reference stack writes remotely there. + // Other generations ignore the attr and keep posting SQEs. + if (dmaArch == DmaArch::A5 && op.getSoftPutAttr()) + return expandA5SoftPut(op, rewriter); + + Value contextGm = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::ContextGm, 64); + Value commBlockOffset = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::CommBlockOffset, 64); + Value channelNum = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::ChannelNum, 32); + + // Service class is a session-wide property, so there is no per-post form to + // fall back from. + Value qos32 = readSessionFieldI32(loc, rewriter, session, + comm_abi::SessionField::Qos); + + // A per-post override wins over the session default for both knobs. + Value channelIdx; + if (auto attr = op.getChannelIdx()) + channelIdx = getI64Constant(loc, rewriter, *attr); + else + channelIdx = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::ChannelIdx, 32); + + Value blockBytes; + if (auto attr = op.getBlockBytes()) + blockBytes = getI64Constant(loc, rewriter, *attr); + else + blockBytes = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::BlockBytes, 64); + + // record = contextGm + (channelIdx * channelNum) * recordBytes + Value recordIndex = + rewriter.create(loc, channelIdx, channelNum); + Value recordBytes = getI64Constant( + loc, rewriter, + static_cast(comm_abi::channel::kRecordBytes)); + Value recordOffset = + rewriter.create(loc, recordIndex, recordBytes); + Value recordAddr = + rewriter.create(loc, contextGm, recordOffset); + + Type i32Type = rewriter.getI32Type(); + Type i64Type = rewriter.getI64Type(); + + Value sqBase = loadDevField(loc, rewriter, recordAddr, + comm_abi::channel::kSqBaseOffset, i64Type); + Value doorbellAddr = loadDevField( + loc, rewriter, recordAddr, comm_abi::channel::kDoorbellOffset, i64Type); + Value slotMask32 = loadDevField(loc, rewriter, recordAddr, + comm_abi::channel::kSlotMaskOffset, + i32Type); + Value streamId32 = loadDevField( + loc, rewriter, recordAddr, comm_abi::channel::kStreamIdOffset, i32Type); + + // The queue position stays where the engine keeps it, so the record hands + // over its address rather than a copy. + Value tailAddr = loadDevField(loc, rewriter, recordAddr, + comm_abi::channel::kTailAddrOffset, i64Type); + Value headAddr = loadDevField(loc, rewriter, recordAddr, + comm_abi::channel::kHeadAddrOffset, i64Type); + Value sqTail32 = loadDevField(loc, rewriter, tailAddr, 0, i32Type); + Value sqHead32 = loadDevField(loc, rewriter, headAddr, 0, i32Type); + Value sqHead = rewriter.create(loc, i64Type, sqHead32); + + Value slotMask = rewriter.create(loc, i64Type, slotMask32); + Value initialTail = rewriter.create(loc, i64Type, sqTail32); + + Value srcAddr = rewriter.create(loc, i64Type, op.getSource()); + Value dstAddr = + rewriter.create(loc, i64Type, op.getDestination()); + srcAddr = rewriter.create(loc, srcAddr, commBlockOffset); + dstAddr = rewriter.create(loc, dstAddr, commBlockOffset); + + // iterations = ceilDiv(nbytes, blockBytes) + // + // The block size can come from the session, so it is a runtime value that + // nothing has checked. Clamping it away from zero keeps a bad session to a + // wrong transfer: the trip count stays bounded by nbytes. Dividing by it + // raw would stop the core instead, and a core that never finishes takes the + // card with it. + Value nbytes = op.getNbytes(); + Value oneBlock = getI64Constant(loc, rewriter, 1); + blockBytes = rewriter.create(loc, blockBytes, oneBlock); + Value iterations = + rewriter.create(loc, nbytes, blockBytes); + Value iterationsIdx = rewriter.create( + loc, rewriter.getIndexType(), iterations); + Value zeroIdx = rewriter.create(loc, 0); + Value oneIdx = rewriter.create(loc, 1); + + // The tail advances once per SQE, so it is carried through the loop. + auto forOp = rewriter.create(loc, zeroIdx, iterationsIdx, oneIdx, + ValueRange{initialTail}); + { + OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPointToStart(forOp.getBody()); + Value iv = rewriter.create( + loc, i64Type, forOp.getInductionVar()); + Value tail = forOp.getRegionIterArg(0); + + Value chunkOffset = rewriter.create(loc, iv, blockBytes); + // The final chunk carries whatever is left of the transfer. + Value remaining = + rewriter.create(loc, nbytes, chunkOffset); + Value chunkBytes = + rewriter.create(loc, blockBytes, remaining); + + Value chunkSrc = + rewriter.create(loc, srcAddr, chunkOffset); + Value chunkDst = + rewriter.create(loc, dstAddr, chunkOffset); + + Value slot = rewriter.create(loc, tail, slotMask); + Value sqeBytes = getI64Constant( + loc, rewriter, static_cast(comm_abi::sqe::kBytes)); + Value slotOffset = rewriter.create(loc, slot, sqeBytes); + Value sqeAddr = rewriter.create(loc, sqBase, slotOffset); + + // The engine identifies a post by how far the queue has run ahead of + // what it has drained, so the task id is the outstanding depth. + Value taskId = rewriter.create(loc, tail, sqHead); + Value taskId32 = rewriter.create(loc, i32Type, taskId); + + writeMemcpySqe(loc, rewriter, sqeAddr, chunkSrc, chunkDst, chunkBytes, + streamId32, taskId32, qos32, dmaArch); + + Value one = getI64Constant(loc, rewriter, 1); + Value nextTail = rewriter.create(loc, tail, one); + nextTail = rewriter.create(loc, nextTail, slotMask); + rewriter.create(loc, ValueRange{nextTail}); + } + + Value finalTail = forOp.getResult(0); + Value finalTail32 = + rewriter.create(loc, i32Type, finalTail); + + // Publish only the tail. The head belongs to the engine, which advances it + // as it drains the queue, so writing back a head read before the SQE stores + // would roll that progress back. + storeGmField(loc, rewriter, tailAddr, 0, finalTail32); + + // Every SQE and the tail update must be visible to the engine before the + // doorbell tells it to look. + writebackDataCache(loc, rewriter, sqBase); + rewriter.create( + loc, pto::DsbMemAttr::get(rewriter.getContext(), pto::DsbMem::DDR)); + + // The doorbell is the one write that differs by generation. A5 takes it + // through st_dev, the device-register path it was meant for. A2/A3 accepts + // it only by MTE, so the tail goes out through UB there. + const int64_t doorbellOffset = dmaArch == DmaArch::A5 + ? comm_abi::sqe::kDoorbellOffsetA5 + : comm_abi::sqe::kDoorbellOffsetA2A3; + if (dmaArch == DmaArch::A5) { + storeDevField(loc, rewriter, doorbellAddr, doorbellOffset, finalTail32); + } else { + Value tmpBufAddr = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::TmpBufAddr, 64); + Value syncId32 = readSessionFieldI32(loc, rewriter, session, + comm_abi::SessionField::SyncId); + ringDoorbellViaUb(loc, rewriter, tmpBufAddr, syncId32, doorbellAddr, + doorbellOffset, finalTail32); + } + + rewriter.eraseOp(op); + return success(); + } + +private: + // A5 cannot post a remote write, so the bytes go through UB in chunks. + // The copy is finished when the op returns; there is no queue tail to poll. + static LogicalResult expandA5SoftPut(pto::SdmaGmGmOp op, + PatternRewriter &rewriter) { + Location loc = op.getLoc(); + MLIRContext *ctx = rewriter.getContext(); + Value session = op.getSession(); + + Value commBlockOffset = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::CommBlockOffset, 64); + Value syncId32 = readSessionFieldI32(loc, rewriter, session, + comm_abi::SessionField::SyncId); + Value tmpBufAddr = readSessionFieldI64( + loc, rewriter, session, comm_abi::SessionField::TmpBufAddr, 64); + + // Address arithmetic stays in i64. A same-type pto.castptr is illegal at + // emission, so do not go through offsetPointerByBytes once the pointers + // are already i8. + Type i64Type = rewriter.getI64Type(); + Value srcAddr = + rewriter.create(loc, i64Type, op.getSource()); + Value dstAddr = + rewriter.create(loc, i64Type, op.getDestination()); + srcAddr = rewriter.create(loc, srcAddr, commBlockOffset); + dstAddr = rewriter.create(loc, dstAddr, commBlockOffset); + + auto i8Type = rewriter.getI8Type(); + auto gmI8Type = pto::PtrType::get( + ctx, i8Type, pto::AddressSpaceAttr::get(ctx, pto::AddressSpace::GM)); + auto ubType = pto::PtrType::get( + ctx, i8Type, pto::AddressSpaceAttr::get(ctx, pto::AddressSpace::VEC)); + Value ub = rewriter.create(loc, ubType, tmpBufAddr); + + Value nbytes = op.getNbytes(); + Value chunkBytes = getI64Constant(loc, rewriter, 32768); + Value one = getI64Constant(loc, rewriter, 1); + chunkBytes = rewriter.create(loc, chunkBytes, one); + Value iterations = + rewriter.create(loc, nbytes, chunkBytes); + Value iterationsIdx = rewriter.create( + loc, rewriter.getIndexType(), iterations); + Value zeroIdx = rewriter.create(loc, 0); + Value oneIdx = rewriter.create(loc, 1); + Value zero64 = getI64Constant(loc, rewriter, 0); + Value falseBit = rewriter.create( + loc, rewriter.getI1Type(), rewriter.getBoolAttr(false)); + Value eventId = rewriter.create( + loc, rewriter.getIndexType(), syncId32); + auto pipe = [&](pto::PIPE p) { return pto::PipeAttr::get(ctx, p); }; + + auto forOp = rewriter.create(loc, zeroIdx, iterationsIdx, oneIdx); + { + OpBuilder::InsertionGuard guard(rewriter); + rewriter.setInsertionPointToStart(forOp.getBody()); + Value iv = rewriter.create( + loc, i64Type, forOp.getInductionVar()); + Value chunkOffset = rewriter.create(loc, iv, chunkBytes); + Value remaining = + rewriter.create(loc, nbytes, chunkOffset); + Value thisBytes = + rewriter.create(loc, chunkBytes, remaining); + Value chunkSrcAddr = + rewriter.create(loc, srcAddr, chunkOffset); + Value chunkDstAddr = + rewriter.create(loc, dstAddr, chunkOffset); + Value chunkSrc = + rewriter.create(loc, gmI8Type, chunkSrcAddr); + Value chunkDst = + rewriter.create(loc, gmI8Type, chunkDstAddr); + + rewriter.create( + loc, chunkSrc, ub, zero64, one, thisBytes, zero64, zero64, falseBit, + zero64, zero64, zero64); + rewriter.create(loc, pipe(pto::PIPE::PIPE_MTE2), + pipe(pto::PIPE::PIPE_MTE3), eventId); + rewriter.create(loc, pipe(pto::PIPE::PIPE_MTE2), + pipe(pto::PIPE::PIPE_MTE3), eventId); + rewriter.create(loc, ub, chunkDst, zero64, one, + thisBytes, zero64, zero64, zero64); + rewriter.create(loc, pipe(pto::PIPE::PIPE_MTE3), + pipe(pto::PIPE::PIPE_MTE2), eventId); + rewriter.create(loc, pipe(pto::PIPE::PIPE_MTE3), + pipe(pto::PIPE::PIPE_MTE2), eventId); + } + + rewriter.create( + loc, pto::DsbMemAttr::get(ctx, pto::DsbMem::DDR)); + rewriter.eraseOp(op); + return success(); + } + + // Write the fields a memcpy post needs. The remaining bytes of the slot keep + // whatever the host initialized them to. + static void writeMemcpySqe(Location loc, PatternRewriter &rewriter, + Value sqeAddr, Value src, Value dst, Value bytes, + Value streamId32, Value taskId32, Value qos32, + DmaArch dmaArch) { + const bool isA5 = dmaArch == DmaArch::A5; + + // Four bits wide on both generations, so a session value that does not fit + // is truncated rather than allowed to run into a neighbouring field. + Value qos = rewriter.create( + loc, qos32, getI32Constant(loc, rewriter, comm_abi::sqe::kQosMask)); + + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kWord0Offset, + getI32Constant(loc, rewriter, + isA5 ? comm_abi::sqe::a5::kWord0Memcpy + : comm_abi::sqe::a2a3::kWord0Memcpy)); + + // Word 1 pairs a 16-bit stream id with a 16-bit task id. Both arrive as 32 + // bits, so mask each before packing or one would run into the other. + Value halfMask = getI32Constant(loc, rewriter, 0xFFFF); + Value rtStreamId = rewriter.create(loc, streamId32, halfMask); + Value taskId = rewriter.create(loc, taskId32, halfMask); + Value taskIdShift = + getI32Constant(loc, rewriter, comm_abi::sqe::kTaskIdShift); + Value taskIdField = + rewriter.create(loc, taskId, taskIdShift); + Value word1 = rewriter.create(loc, rtStreamId, taskIdField); + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kWord1Offset, word1); + + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kWord3Offset, + getI32Constant(loc, rewriter, + isA5 ? comm_abi::sqe::a5::kWord3Memcpy + : comm_abi::sqe::a2a3::kWord3Memcpy)); + + // QoS shares word 4 with the address attributes on A2/A3, but lives in + // word 5 on A5, so only one of the two words carries it. + Value word4 = getI32Constant(loc, rewriter, + isA5 ? comm_abi::sqe::a5::kWord4Memcpy + : comm_abi::sqe::a2a3::kWord4Memcpy); + if (!isA5) { + Value qosField = rewriter.create( + loc, qos, + getI32Constant(loc, rewriter, comm_abi::sqe::a2a3::kQosShift)); + word4 = rewriter.create(loc, word4, qosField); + } + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kWord4Offset, word4); + + if (isA5) { + // Nothing else in word 5 is set for a memcpy post, so the QoS field is + // the whole word. + Value word5 = rewriter.create( + loc, qos, getI32Constant(loc, rewriter, comm_abi::sqe::a5::kQosShift)); + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::a5::kWord5Offset, + word5); + } + + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kSrcAddrOffset, src); + storeGmField(loc, rewriter, sqeAddr, comm_abi::sqe::kDstAddrOffset, dst); + + Value bytes32 = + rewriter.create(loc, rewriter.getI32Type(), bytes); + storeGmField(loc, rewriter, sqeAddr, + isA5 ? comm_abi::sqe::a5::kLengthOffset + : comm_abi::sqe::a2a3::kLengthOffset, + bytes32); + + // A2/A3 keeps a link type where A5 puts the length; an unlinked post has to + // say so explicitly. + if (!isA5) + storeGmField( + loc, rewriter, sqeAddr, comm_abi::sqe::a2a3::kLinkTypeOffset, + getI32Constant(loc, rewriter, comm_abi::sqe::a2a3::kLinkTypeNone)); + } + + DmaArch dmaArch; +}; + struct VPTOExpandWrapperOpsPass : public pto::impl::VPTOExpandWrapperOpsBase { using pto::impl::VPTOExpandWrapperOpsBase< @@ -2098,7 +2638,9 @@ struct VPTOExpandWrapperOpsPass RewritePatternSet patterns(&getContext()); patterns.add(std::make_unique(&getContext(), dmaArch)); patterns.add(std::make_unique(&getContext(), dmaArch)); - patterns.add(&getContext(), dmaArch)); + patterns.add +packCopyUbToGmCfgAlignV220(Operation *anchor, ValueRange operands) { + if (operands.size() != 8) + return failure(); + + OpBuilder builder(anchor); + builder.setInsertionPoint(anchor); + Location loc = anchor->getLoc(); + + auto getI64Operand = [&](unsigned idx) -> Value { + return castIntegerLikeTo(anchor, operands[idx], builder.getI64Type()); + }; + + Value sid = getI64Operand(2); + Value nBurst = getI64Operand(3); + Value lenBurst = getI64Operand(4); + if (!sid || !nBurst || !lenBurst) + return failure(); + + auto shl = [&](Value value, uint64_t amount) -> Value { + return builder.create(loc, value, + getI64Constant(builder, loc, amount)); + }; + auto bitOr = [&](Value lhs, Value rhs) -> Value { + return builder.create(loc, lhs, rhs); + }; + + Value cfg = sid; + cfg = bitOr(cfg, shl(nBurst, 4)); + cfg = bitOr(cfg, shl(lenBurst, 16)); + return cfg; +} + static FailureOr packCopyUbToGmCfgV220(Operation *anchor, ValueRange operands) { if (operands.size() != 8) @@ -5927,14 +5964,28 @@ class LowerCopyOpPattern final : public OpConversionPattern { } bool isC220 = march == "dav-c220-vec" || march == "dav-c220-cube"; + // The ordinary c220 UB->GM path carries its length in 32-byte units, so a + // transfer shorter than a block rounds down to nothing at all. Callers that + // need a byte-granular store, such as the 4-byte SDMA doorbell write, ask + // for the ALIGN intrinsic instead. + bool byteGranular = !isGmUb && isC220 && op->hasAttr("vpto.byte_granular"); + if (byteGranular) + calleeName = StringAttr::get(op.getContext(), + "llvm.hivm.MOV.UB.TO.OUT.ALIGN.b32.V220") + .getValue(); + bool useA3NonPadded = isC220 && isGmUb && !hasPadding; - bool useA3UbGm = isC220 && !isGmUb; + bool useA3UbGm = isC220 && !isGmUb && !byteGranular; bool useSingleConfig = useA3NonPadded || useA3UbGm; FailureOr config0 = failure(); FailureOr config1 = failure(); - if (useA3NonPadded) - { + if (byteGranular) { + config0 = packCopyUbToGmCfgAlignV220(op, adaptor.getOperands()); + // Only exercised with both strides at zero, which is all a single-burst + // store needs. + config1 = packCopyUbToGmConfig1(op, adaptor.getOperands()); + } else if (useA3NonPadded) { config0 = packCopyGmToUbCfgV220(op, adaptor.getOperands()); } else if (useA3UbGm) { config0 = packCopyUbToGmCfgV220(op, adaptor.getOperands()); @@ -13273,6 +13324,137 @@ class ConvertPtoStgOp final : public OpConversionPattern { LoweringState &state; }; +static std::string buildLdDevCalleeName(unsigned width) { + return "llvm.hivm.LD.DEV.u" + std::to_string(width) + ".GM"; +} + +static std::string buildStDevCalleeName(unsigned width) { + return "llvm.hivm.ST.DEV.u" + std::to_string(width); +} + +class ConvertPtoLdDevOp final : public OpConversionPattern { +public: + ConvertPtoLdDevOp(TypeConverter &typeConverter, MLIRContext *context, + LoweringState &state) + : OpConversionPattern(typeConverter, context), + state(state) {} + + LogicalResult + matchAndRewrite(pto::PTOLdDevOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + auto llvmPtrType = dyn_cast(adaptor.getPtr().getType()); + if (!llvmPtrType) + return rewriter.notifyMatchFailure(op, "expected LLVM pointer operand"); + + auto valueType = dyn_cast(op.getValue().getType()); + if (!valueType) + return rewriter.notifyMatchFailure(op, "expected integer result type"); + + Value offset = adaptor.getOffset(); + if (offset.getType().isIndex()) + offset = rewriter.create(op.getLoc(), + rewriter.getI64Type(), offset); + + Type convertedValueType = + getTypeConverter()->convertType(op.getValue().getType()); + if (!convertedValueType) + return rewriter.notifyMatchFailure(op, + "could not convert ld_dev result type"); + + Value elemPtr = adaptor.getPtr(); + if (!matchPattern(offset, m_Zero())) { + elemPtr = rewriter.create( + op.getLoc(), llvmPtrType, + normalizeGEPElementTypeForLLVMLowering(convertedValueType, rewriter), + adaptor.getPtr(), ValueRange{offset}); + } + + FailureOr gmPtr = reinterpretPointerToAddrSpace( + op, elemPtr, static_cast(pto::AddressSpace::GM)); + if (failed(gmPtr)) + return rewriter.notifyMatchFailure(op, "failed to map ld_dev GM pointer"); + + std::string calleeName = buildLdDevCalleeName(valueType.getWidth()); + Value intrinsicOffset = getI64Constant(rewriter, op.getLoc(), 0); + auto funcType = rewriter.getFunctionType( + TypeRange{gmPtr->getType(), rewriter.getI64Type()}, + TypeRange{rewriter.getI64Type()}); + auto call = rewriter.create( + op.getLoc(), calleeName, TypeRange{rewriter.getI64Type()}, + ValueRange{*gmPtr, intrinsicOffset}); + state.plannedDecls.push_back(PlannedDecl{calleeName, funcType}); + + Value result = call.getResult(0); + if (valueType.getWidth() < 64) + result = rewriter.create(op.getLoc(), convertedValueType, + result); + rewriter.replaceOp(op, result); + return success(); + } + +private: + LoweringState &state; +}; + +class ConvertPtoStDevOp final : public OpConversionPattern { +public: + ConvertPtoStDevOp(TypeConverter &typeConverter, MLIRContext *context, + LoweringState &state) + : OpConversionPattern(typeConverter, context), + state(state) {} + + LogicalResult + matchAndRewrite(pto::PTOStDevOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + auto llvmPtrType = dyn_cast(adaptor.getPtr().getType()); + if (!llvmPtrType) + return rewriter.notifyMatchFailure(op, "expected LLVM pointer operand"); + + auto valueType = dyn_cast(op.getValue().getType()); + if (!valueType) + return rewriter.notifyMatchFailure(op, "expected integer value type"); + + Value offset = adaptor.getOffset(); + if (offset.getType().isIndex()) + offset = rewriter.create(op.getLoc(), + rewriter.getI64Type(), offset); + + Value elemPtr = adaptor.getPtr(); + if (!matchPattern(offset, m_Zero())) { + elemPtr = rewriter.create( + op.getLoc(), llvmPtrType, + normalizeGEPElementTypeForLLVMLowering(adaptor.getValue().getType(), + rewriter), + adaptor.getPtr(), ValueRange{offset}); + } + + FailureOr gmPtr = reinterpretPointerToAddrSpace( + op, elemPtr, static_cast(pto::AddressSpace::GM)); + if (failed(gmPtr)) + return rewriter.notifyMatchFailure(op, "failed to map st_dev GM pointer"); + + Value payload = adaptor.getValue(); + if (valueType.getWidth() < 64) + payload = rewriter.create(op.getLoc(), + rewriter.getI64Type(), payload); + + std::string calleeName = buildStDevCalleeName(valueType.getWidth()); + Value intrinsicOffset = getI64Constant(rewriter, op.getLoc(), 0); + auto funcType = rewriter.getFunctionType( + TypeRange{rewriter.getI64Type(), gmPtr->getType(), + rewriter.getI64Type()}, + TypeRange{}); + rewriter.create(op.getLoc(), calleeName, TypeRange{}, + ValueRange{payload, *gmPtr, intrinsicOffset}); + state.plannedDecls.push_back(PlannedDecl{calleeName, funcType}); + rewriter.eraseOp(op); + return success(); + } + +private: + LoweringState &state; +}; + class ConvertVPTOTypedCarrierOp final : public ConversionPattern { public: ConvertVPTOTypedCarrierOp(TypeConverter &typeConverter, MLIRContext *context) @@ -13876,7 +14058,8 @@ static LogicalResult lowerVPTOTypes(ModuleOp module, llvm::raw_ostream &diagOS) }); target.addIllegalOp(); target.addDynamicallyLegalOp( [&](UnrealizedConversionCastOp op) { @@ -13904,7 +14087,7 @@ static LogicalResult lowerVPTOTypes(ModuleOp module, llvm::raw_ostream &diagOS) ConvertPtoStructGetOp, ConvertPtoStructSetOp, ConvertPtoStoreScalarOp>(typeConverter, context); patterns.add( + ConvertPtoStgOp, ConvertPtoLdDevOp, ConvertPtoStDevOp>( typeConverter, context, state); patterns.add(typeConverter, context); patterns.add(typeConverter, context); diff --git a/lib/PTO/Transforms/VPTOLLVMEmitterDispatcher.cpp b/lib/PTO/Transforms/VPTOLLVMEmitterDispatcher.cpp index 22fc492ed5..dddb756a21 100644 --- a/lib/PTO/Transforms/VPTOLLVMEmitterDispatcher.cpp +++ b/lib/PTO/Transforms/VPTOLLVMEmitterDispatcher.cpp @@ -20,32 +20,37 @@ static bool usesCANN900Lowering(const VPTOEmissionOptions &options) { options.cannVersion >= CANNVersion::release(mlir::pto::kValue9, 0, 0); } -static bool containsLdStDev(ModuleOp module) { +static bool containsOp(ModuleOp module, bool wantLdDev, bool wantStDev) { bool found = false; module.walk([&](Operation *op) { - if (isa(op)) { + if ((wantLdDev && isa(op)) || + (wantStDev && isa(op))) { found = true; } }); return found; } +// ld_dev is required on A2/A3 for SDMA descriptor reads. st_dev is A5-only: +// A2/A3 cannot use it to ring the SDMA doorbell, and stores through that path +// are not reliable on that generation. Other non-c220 targets still need the +// 9.0.0 official lowering; the 9.0.0-beta.1 intrinsic set has not been checked. static LogicalResult verifyLdStDevTarget(ModuleOp module, const VPTOEmissionOptions &options, llvm::raw_ostream &diagOS) { - if (!containsLdStDev(module) || usesCANN900Lowering(options)) { - return success(); - } - const bool isC220 = options.march == "dav-c220-vec" || options.march == "dav-c220-cube"; - if (isC220) { - diagOS << "VPTO LLVM emission failed: pto.ld_dev and pto.st_dev require " - "--pto-arch=a5\n"; - } else { - diagOS << "VPTO LLVM emission failed: pto.ld_dev and pto.st_dev require " - "CANN 9.0.0 or newer official lowering\n"; + if (isC220 && containsOp(module, false, true)) { + diagOS << "VPTO LLVM emission failed: pto.st_dev is not supported on A2/A3\n"; + return failure(); } + if (!containsOp(module, true, true) || isC220 || + usesCANN900Lowering(options)) { + return success(); + } + + diagOS << "VPTO LLVM emission failed: pto.ld_dev and pto.st_dev require " + "CANN 9.0.0 or newer official lowering\n"; return failure(); } diff --git a/test/comm/AsyncWorkspace.h b/test/comm/AsyncWorkspace.h new file mode 100644 index 0000000000..e08a335a98 --- /dev/null +++ b/test/comm/AsyncWorkspace.h @@ -0,0 +1,678 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +#ifndef PTO_TEST_COMM_ASYNCWORKSPACE_H +#define PTO_TEST_COMM_ASYNCWORKSPACE_H + +// Test scaffolding: builds the async workspace that pto.sdma_gm_gm reads. +// +// Not a shipped interface, and deliberately not under include/. PTOAS owns the +// layout contract in PTO/Support/AsyncSessionABI.h, which is what code +// generation emits against; producing the workspace belongs to the +// communication library. The supported way to get one is HCCL, which acquires +// channels per engine (HcclChannelAcquire with COMM_ENGINE_AIV) and hands back +// an engine context. This file exists so the device path could be exercised on +// hardware before that binding was written. +// +// What it does, since none of it can be computed on the host -- the queue ring +// base and the doorbell address are STARS facts only an AICPU query reports: +// +// 1. create one device-only stream per channel and collect its ids +// 2. allocate and zero the workspace in device memory +// 3. stage the stream table where the operator can read it +// 4. run aclnnShmemSdmaStarsQuery, which fills the channel descriptors +// 5. check those descriptors and repack them into channel records +// 6. hand the record table to the kernel as the session context +// +// Step 5 is what keeps the descriptor layout from reaching generated code. It +// is a CANN-release fact rather than a hardware one -- the pto headers have +// already moved it once -- so it is resolved here, once, where a change fails +// the check instead of producing a wrong address inside a kernel. +// +// Everything is resolved with dlopen, so a program that never constructs an +// AsyncWorkspace links and runs unchanged on a machine without a toolkit. +// +// Two caveats that make this unsuitable for shipping. The stream-table and +// operator-descriptor structs below are transcribed rather than included, so a +// layout change on the CANN side corrupts memory silently instead of failing to +// build; and rtStreamGetSqid, rtStreamGetCqid and rtGetDeviceInfo are runtime +// internals rather than public ACL. pto-isa carries a near-identical copy of +// all this in sdma_workspace_manager.hpp; both are readers of a format neither +// owns, which is why agreement between them proves nothing and the check in +// step 5 compares against values fed to the query instead. +// +// Requires CANN 9.0.0 or newer at run time, for aclnnShmemSdmaStarsQuery. That +// is stricter than the device code needs: the generated kernel itself compiles +// and runs under CANN 8.x. + +#if defined(__CCE_KT_TEST__) || defined(__CCE__) +#error "AsyncWorkspace.h is a host-only header and cannot be included in device code." +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include "PTO/Support/AsyncSessionABI.h" + +namespace mlir::pto::comm { + +namespace detail { + +// ACL values this header depends on, spelled out rather than included so the +// header stays free of CANN at build time. Taken from acl_rt.h / acl_base.h. +constexpr uint32_t kAclStreamFastLaunch = 0x00000001U; +constexpr uint32_t kAclStreamFastSync = 0x00000002U; +constexpr uint32_t kAclStreamDeviceUseOnly = 0x00000020U; +constexpr int32_t kAclStreamAttrFailureMode = 1; +constexpr int32_t kAclMemMallocHugeFirst = 0; +constexpr int32_t kAclMemcpyHostToDevice = 1; +constexpr int32_t kAclMemcpyDeviceToHost = 2; +constexpr int32_t kAclUint64 = 10; +constexpr int32_t kAclFormatND = 2; + +// rtGetDeviceInfo selector for the physical die id. +constexpr int32_t kInfoTypePhyDieId = 19; + +// One entry of the stream table the STARS query consumes. The operator matches +// on the exact size, so the padding is load-bearing. +struct HostStreamInfo { + uint64_t stream; + uint64_t ctx; + int32_t streamId; + uint32_t sqId; + uint32_t cqId; + uint32_t logicCqId; + uint64_t cqeAddr; + int32_t devId; + uint8_t reserved[20]; +}; +static_assert(sizeof(HostStreamInfo) == 64, "HostStreamInfo must be 64 bytes"); + +// Descriptor the operator reads to find the stream table and the workspace. +struct OpResInfo { + uint64_t size; + uint64_t streamsAddr; + uint64_t workspaceAddr; + uint8_t reserved[40]; +}; +static_assert(sizeof(OpResInfo) == 64, "OpResInfo must be 64 bytes"); + +} // namespace detail + +class AsyncWorkspace { +public: + AsyncWorkspace() = default; + ~AsyncWorkspace() { finalize(); } + + AsyncWorkspace(const AsyncWorkspace &) = delete; + AsyncWorkspace &operator=(const AsyncWorkspace &) = delete; + + // Builds the workspace for `channels` channels on the current device, which + // must already be selected with aclrtSetDevice. Returns false and leaves + // `error()` set on failure. + bool init(unsigned channels = workspace::kMaxChannels) { + if (inited_) + return true; + if (channels == 0 || channels > workspace::kMaxChannels) + return fail("channel count must be in [1, " + + std::to_string(workspace::kMaxChannels) + "]"); + + if (!loadSymbols() || !createStreams(channels) || !allocWorkspace() || + !stageStreamTable() || !runStarsQuery() || !validateAndRepack()) { + finalize(); + return false; + } + inited_ = true; + return true; + } + + void finalize() { + if (recordsDevice_) { + aclrtFree_(recordsDevice_); + recordsDevice_ = nullptr; + } + if (streamsDevice_) { + aclrtFree_(streamsDevice_); + streamsDevice_ = nullptr; + } + if (opResDevice_) { + aclrtFree_(opResDevice_); + opResDevice_ = nullptr; + } + if (workspaceDevice_) { + aclrtFree_(workspaceDevice_); + workspaceDevice_ = nullptr; + } + for (auto &s : streams_) { + if (s.stream) + aclrtDestroyStream_(reinterpret_cast(s.stream)); + } + streams_.clear(); + closeLibs(); + inited_ = false; + } + + // Pass this to the kernel as SessionField::ContextGm. It addresses the + // channel records this class builds, not the workspace the query wrote. + void *contextGm() const { return recordsDevice_; } + + // The workspace itself, which stays allocated because the live head and tail + // remain in it and the records point at them. + void *workspaceGm() const { return workspaceDevice_; } + + unsigned channelCount() const { + return static_cast(streams_.size()); + } + + // Channels the query reported populating, or 0 if it reported nothing. Only + // meaningful after a successful init. + uint32_t reportedQueueNum() const { return reportedQueueNum_; } + + const std::string &error() const { return error_; } + + // Reads one channel descriptor back to the host. Only useful for checking + // that the STARS query actually populated the table. + bool readChannelDescriptor(unsigned channelIdx, unsigned channelNum, + unsigned channelInGroup, + uint8_t (&out)[workspace::kChannelDescBytes]) { + if (!inited_) + return fail("workspace is not initialized"); + size_t offset = + workspace::channelDescOffset(channelIdx, channelNum, channelInGroup); + if (offset + workspace::kChannelDescBytes > workspace::kContextBytes) + return fail("channel descriptor lies outside the context region"); + void *src = static_cast(workspaceDevice_) + offset; + if (aclrtMemcpy_(out, sizeof(out), src, sizeof(out), + detail::kAclMemcpyDeviceToHost) != 0) + return fail("aclrtMemcpy of channel descriptor failed"); + return true; + } + + // Reads one channel record back, which is what a kernel sees for that + // channel. Only useful for checking that the table reached the device. + bool readChannelRecord(unsigned index, + uint8_t (&out)[comm::channel::kRecordBytes]) { + if (!inited_ || index >= streams_.size()) + return fail("no such channel record"); + void *src = static_cast(recordsDevice_) + + comm::channel::recordOffset(index, 1, 0); + if (aclrtMemcpy_(out, sizeof(out), src, sizeof(out), + detail::kAclMemcpyDeviceToHost) != 0) + return fail("aclrtMemcpy of channel record failed"); + return true; + } + +private: + // Checks what the query wrote and repacks it into the channel records. + // + // The check is exact rather than a plausibility test, because the query was + // handed the stream, sq, cq and device ids and echoes them back: a descriptor + // whose ids sit where they are expected is at the layout this build assumes, + // and one byte of drift breaks the match. Only the fields the query invents + // -- the ring base, the doorbell and the depth -- fall back to a range check. + bool validateAndRepack() { + const unsigned channels = static_cast(streams_.size()); + + uint8_t header[workspace::kFlagInfoBytes]; + if (!readWorkspace(0, header, sizeof(header))) + return fail("reading the workspace flag-info header failed"); + std::memcpy(&reportedQueueNum_, + header + workspace::kFlagInfoTotalQueueNumOffset, + sizeof(reportedQueueNum_)); + + // Trust the reported count when it is sane; a query that reports fewer + // channels than asked has populated fewer descriptors, and indexing past + // them would read the zeroed allocation. + if (reportedQueueNum_ != 0 && reportedQueueNum_ < channels) + return fail("the query populated " + std::to_string(reportedQueueNum_) + + " channels but " + std::to_string(channels) + + " were requested"); + + std::vector records(static_cast(channels) * + comm::channel::kRecordBytes, + 0); + + for (unsigned i = 0; i < channels; ++i) { + const size_t descOffset = + workspace::kFlagInfoBytes + + static_cast(i) * workspace::kChannelDescBytes; + uint8_t desc[workspace::kChannelDescBytes]; + if (!readWorkspace(descOffset, desc, sizeof(desc))) + return fail("reading channel descriptor " + std::to_string(i) + + " failed"); + + const detail::HostStreamInfo &want = streams_[i]; + if (!expectU32(desc, workspace::kChannelStreamIdOffset, + static_cast(want.streamId), "stream_id", i) || + !expectU32(desc, workspace::kChannelSqIdOffset, want.sqId, "sq_id", + i) || + !expectU32(desc, workspace::kChannelCqIdOffset, want.cqId, "cq_id", + i) || + !expectU32(desc, workspace::kChannelLogicCqIdOffset, want.logicCqId, + "logic_cq_id", i) || + !expectU32(desc, workspace::kChannelDevIdOffset, + static_cast(want.devId), "dev_id", i)) + return false; + + uint64_t sqBase = 0, sqRegBase = 0; + uint32_t sqDepth = 0, sqHead = 0, sqTail = 0; + std::memcpy(&sqBase, desc + workspace::kChannelSqBaseOffset, + sizeof(sqBase)); + std::memcpy(&sqRegBase, desc + workspace::kChannelSqRegBaseOffset, + sizeof(sqRegBase)); + std::memcpy(&sqDepth, desc + workspace::kChannelSqDepthOffset, + sizeof(sqDepth)); + std::memcpy(&sqHead, desc + workspace::kChannelSqHeadOffset, + sizeof(sqHead)); + std::memcpy(&sqTail, desc + workspace::kChannelSqTailOffset, + sizeof(sqTail)); + + if (sqBase == 0 || (sqBase & (workspace::kChannelDescBytes - 1)) != 0) + return fail("channel " + std::to_string(i) + " has sq_base " + + hex(sqBase) + ", which is not a usable ring base"); + if (sqRegBase == 0) + return fail("channel " + std::to_string(i) + " has no doorbell address"); + // The ring the engine actually uses is a power of two; generated code + // wraps with a mask. A5's STARS query on CANN 9.2.0 reports 2049 for a + // 2048-slot ring, so a count that is one past a power of two is taken as + // that ring rather than rejected. Any other non-power-of-two stays a + // hard error: masking it would land posts in the wrong slot. + uint32_t ringDepth = sqDepth; + if (ringDepth > 1 && (ringDepth & (ringDepth - 1)) != 0 && + ((ringDepth - 1) & (ringDepth - 2)) == 0) + ringDepth = sqDepth - 1; + if (ringDepth == 0 || (ringDepth & (ringDepth - 1)) != 0) + return fail("channel " + std::to_string(i) + " reports depth " + + std::to_string(sqDepth) + + ", which is not a power of two and cannot be masked"); + if (sqHead >= ringDepth || sqTail >= ringDepth) + return fail("channel " + std::to_string(i) + " starts with head " + + std::to_string(sqHead) + " tail " + std::to_string(sqTail) + + " outside a queue of " + std::to_string(ringDepth)); + + const uint64_t descGm = + reinterpret_cast(workspaceDevice_) + descOffset; + uint8_t *rec = records.data() + comm::channel::recordOffset(i, 1, 0); + const uint64_t tailAddr = descGm + workspace::kChannelSqTailOffset; + const uint64_t headAddr = descGm + workspace::kChannelSqHeadOffset; + const uint32_t streamId = static_cast(want.streamId); + const uint32_t slotMask = ringDepth - 1; + std::memcpy(rec + comm::channel::kSqBaseOffset, &sqBase, sizeof(sqBase)); + std::memcpy(rec + comm::channel::kDoorbellOffset, &sqRegBase, + sizeof(sqRegBase)); + std::memcpy(rec + comm::channel::kTailAddrOffset, &tailAddr, + sizeof(tailAddr)); + std::memcpy(rec + comm::channel::kHeadAddrOffset, &headAddr, + sizeof(headAddr)); + std::memcpy(rec + comm::channel::kSlotMaskOffset, &slotMask, + sizeof(slotMask)); + std::memcpy(rec + comm::channel::kStreamIdOffset, &streamId, + sizeof(streamId)); + } + + if (aclrtMalloc_(&recordsDevice_, records.size(), + detail::kAclMemMallocHugeFirst) != 0) + return fail("aclrtMalloc of the channel record table failed"); + if (aclrtMemcpy_(recordsDevice_, records.size(), records.data(), + records.size(), detail::kAclMemcpyHostToDevice) != 0) + return fail("aclrtMemcpy of the channel record table failed"); + return true; + } + + bool readWorkspace(size_t offset, void *out, size_t bytes) { + if (offset + bytes > workspace::kContextBytes) + return false; + void *src = static_cast(workspaceDevice_) + offset; + return aclrtMemcpy_(out, bytes, src, bytes, + detail::kAclMemcpyDeviceToHost) == 0; + } + + // Compares one echoed id, and on a mismatch says where the value did land, so + // a layout that shifted reports the shift instead of just a bad number. + bool expectU32(const uint8_t *desc, size_t offset, uint32_t want, + const char *what, unsigned channel) { + uint32_t got = 0; + std::memcpy(&got, desc + offset, sizeof(got)); + if (got == want) + return true; + + std::string where; + for (size_t probe = 0; probe + sizeof(uint32_t) <= workspace::kChannelDescBytes; + probe += sizeof(uint32_t)) { + uint32_t at = 0; + std::memcpy(&at, desc + probe, sizeof(at)); + if (at == want) + where += (where.empty() ? "" : ", ") + std::to_string(probe); + } + return fail( + "channel " + std::to_string(channel) + ": expected " + what + " " + + std::to_string(want) + " at descriptor offset " + + std::to_string(offset) + " but found " + std::to_string(got) + + (where.empty() + ? "; it appears nowhere in the descriptor, so the query did not " + "run as expected" + : "; it appears at offset " + where + + ", so the descriptor layout has moved")); + } + + static std::string hex(uint64_t v) { + char buf[32]; + std::snprintf(buf, sizeof(buf), "%#llx", + static_cast(v)); + return buf; + } + + using AclrtCreateStreamWithConfigFn = int32_t (*)(void **, uint32_t, uint32_t); + using AclrtDestroyStreamFn = int32_t (*)(void *); + using AclrtStreamGetIdFn = int32_t (*)(void *, int32_t *); + using AclrtGetCurrentContextFn = int32_t (*)(void **); + using AclrtGetDeviceFn = int32_t (*)(int32_t *); + using AclrtMallocFn = int32_t (*)(void **, size_t, int32_t); + using AclrtFreeFn = int32_t (*)(void *); + using AclrtMemsetFn = int32_t (*)(void *, size_t, int32_t, size_t); + using AclrtMemcpyFn = int32_t (*)(void *, size_t, const void *, size_t, + int32_t); + using AclrtSynchronizeStreamFn = int32_t (*)(void *); + using AclrtSetStreamAttributeFn = int32_t (*)(void *, int32_t, const void *); + + using RtStreamGetSqidFn = int32_t (*)(const void *, uint32_t *); + using RtStreamGetCqidFn = int32_t (*)(const void *, uint32_t *, uint32_t *); + using RtGetDeviceInfoFn = int32_t (*)(uint32_t, int32_t, int32_t, int64_t *); + + using AclCreateTensorFn = void *(*)(const int64_t *, uint64_t, int32_t, + const int64_t *, int64_t, int32_t, + const int64_t *, uint64_t, void *); + using AclDestroyTensorFn = int32_t (*)(void *); + using StarsQueryGetWsSizeFn = int32_t (*)(const void *, void *, uint64_t *, + void **); + using StarsQueryExecFn = int32_t (*)(void *, uint64_t, void *, void *); + + bool fail(const std::string &what) { + if (error_.empty()) + error_ = what; + return false; + } + + template + bool bind(Fn &slot, void *handle, const char *name) { + slot = reinterpret_cast(dlsym(handle, name)); + if (!slot) + return fail(std::string("dlsym ") + name + " failed"); + return true; + } + + bool loadSymbols() { + aclHandle_ = dlopen("libascendcl.so", RTLD_NOW | RTLD_GLOBAL); + if (!aclHandle_) + return fail(std::string("dlopen libascendcl.so failed: ") + dlerror()); + rtHandle_ = dlopen("libruntime.so", RTLD_NOW); + if (!rtHandle_) + return fail(std::string("dlopen libruntime.so failed: ") + dlerror()); + opapiHandle_ = dlopen("libopapi.so", RTLD_NOW); + if (!opapiHandle_) + return fail(std::string("dlopen libopapi.so failed: ") + dlerror()); + nnopHandle_ = dlopen("libnnopbase.so", RTLD_NOW | RTLD_GLOBAL); + if (!nnopHandle_) + return fail(std::string("dlopen libnnopbase.so failed: ") + dlerror()); + + return bind(aclrtCreateStreamWithConfig_, aclHandle_, + "aclrtCreateStreamWithConfig") && + bind(aclrtDestroyStream_, aclHandle_, "aclrtDestroyStream") && + bind(aclrtStreamGetId_, aclHandle_, "aclrtStreamGetId") && + bind(aclrtGetCurrentContext_, aclHandle_, "aclrtGetCurrentContext") && + bind(aclrtGetDevice_, aclHandle_, "aclrtGetDevice") && + bind(aclrtMalloc_, aclHandle_, "aclrtMalloc") && + bind(aclrtFree_, aclHandle_, "aclrtFree") && + bind(aclrtMemset_, aclHandle_, "aclrtMemset") && + bind(aclrtMemcpy_, aclHandle_, "aclrtMemcpy") && + bind(aclrtSynchronizeStream_, aclHandle_, + "aclrtSynchronizeStream") && + bind(aclrtSetStreamAttribute_, aclHandle_, + "aclrtSetStreamAttribute") && + bind(rtStreamGetSqid_, rtHandle_, "rtStreamGetSqid") && + bind(rtStreamGetCqid_, rtHandle_, "rtStreamGetCqid") && + bind(rtGetDeviceInfo_, rtHandle_, "rtGetDeviceInfo") && + bind(aclCreateTensor_, nnopHandle_, "aclCreateTensor") && + bind(aclDestroyTensor_, nnopHandle_, "aclDestroyTensor") && + bind(starsQueryGetWsSize_, opapiHandle_, + "aclnnShmemSdmaStarsQueryGetWorkspaceSize") && + bind(starsQueryExec_, opapiHandle_, "aclnnShmemSdmaStarsQuery"); + } + + void closeLibs() { + for (void **h : {&opapiHandle_, &nnopHandle_, &rtHandle_, &aclHandle_}) { + if (*h) { + dlclose(*h); + *h = nullptr; + } + } + } + + bool createStreams(unsigned channels) { + int32_t deviceId = -1; + if (aclrtGetDevice_(&deviceId) != 0) + return fail("aclrtGetDevice failed; call aclrtSetDevice first"); + + int64_t dieId = -1; + if (rtGetDeviceInfo_(static_cast(deviceId), 0, + detail::kInfoTypePhyDieId, &dieId) != 0) + return fail("rtGetDeviceInfo(die id) failed"); + + streams_.resize(channels); + for (unsigned i = 0; i < channels; ++i) { + detail::HostStreamInfo &info = streams_[i]; + std::memset(&info, 0, sizeof(info)); + + void *stream = nullptr; + if (aclrtCreateStreamWithConfig_(&stream, 0, + detail::kAclStreamDeviceUseOnly) != 0) + return fail("aclrtCreateStreamWithConfig failed on channel " + + std::to_string(i)); + info.stream = reinterpret_cast(stream); + + int32_t streamId = 0; + if (aclrtStreamGetId_(stream, &streamId) != 0) + return fail("aclrtStreamGetId failed on channel " + std::to_string(i)); + + uint32_t sqId = 0; + if (rtStreamGetSqid_(stream, &sqId) != 0) + return fail("rtStreamGetSqid failed on channel " + std::to_string(i)); + + uint32_t cqId = 0; + uint32_t logicCqId = 0; + if (rtStreamGetCqid_(stream, &cqId, &logicCqId) != 0) + return fail("rtStreamGetCqid failed on channel " + std::to_string(i)); + + void *ctx = nullptr; + if (aclrtGetCurrentContext_(&ctx) != 0) + return fail("aclrtGetCurrentContext failed on channel " + + std::to_string(i)); + + info.ctx = reinterpret_cast(ctx); + info.streamId = streamId; + info.sqId = sqId; + info.cqId = cqId; + info.logicCqId = logicCqId; + info.devId = static_cast(dieId); + } + return true; + } + + bool allocWorkspace() { + if (aclrtMalloc_(&workspaceDevice_, workspace::kTotalBytes, + detail::kAclMemMallocHugeFirst) != 0) + return fail("aclrtMalloc of the async workspace failed"); + // The kernel reads descriptors the query does not touch, so start from a + // known state rather than whatever the allocator returned. + if (aclrtMemset_(workspaceDevice_, workspace::kTotalBytes, 0, + workspace::kTotalBytes) != 0) + return fail("aclrtMemset of the async workspace failed"); + return true; + } + + bool stageStreamTable() { + size_t streamsBytes = streams_.size() * sizeof(detail::HostStreamInfo); + if (aclrtMalloc_(&streamsDevice_, streamsBytes, + detail::kAclMemMallocHugeFirst) != 0) + return fail("aclrtMalloc of the stream table failed"); + if (aclrtMemcpy_(streamsDevice_, streamsBytes, streams_.data(), + streamsBytes, detail::kAclMemcpyHostToDevice) != 0) + return fail("aclrtMemcpy of the stream table failed"); + + detail::OpResInfo opRes{}; + opRes.size = streams_.size(); + opRes.streamsAddr = reinterpret_cast(streamsDevice_); + opRes.workspaceAddr = reinterpret_cast(workspaceDevice_); + + if (aclrtMalloc_(&opResDevice_, sizeof(opRes), + detail::kAclMemMallocHugeFirst) != 0) + return fail("aclrtMalloc of the operator descriptor failed"); + if (aclrtMemcpy_(opResDevice_, sizeof(opRes), &opRes, sizeof(opRes), + detail::kAclMemcpyHostToDevice) != 0) + return fail("aclrtMemcpy of the operator descriptor failed"); + return true; + } + + // A device buffer plus the tensor that wraps it, released together. + struct TensorHandle { + void *data{nullptr}; + void *tensor{nullptr}; + }; + + bool makeScalarTensor(const std::vector &values, + TensorHandle &out) { + const int64_t shape = static_cast(values.size()); + const int64_t stride = 1; + size_t bytes = values.size() * sizeof(uint64_t); + + if (aclrtMalloc_(&out.data, bytes, detail::kAclMemMallocHugeFirst) != 0) + return fail("aclrtMalloc of a query tensor failed"); + if (aclrtMemcpy_(out.data, bytes, values.data(), bytes, + detail::kAclMemcpyHostToDevice) != 0) + return fail("aclrtMemcpy of a query tensor failed"); + + out.tensor = aclCreateTensor_(&shape, 1, detail::kAclUint64, &stride, 0, + detail::kAclFormatND, &shape, 1, out.data); + if (!out.tensor) + return fail("aclCreateTensor failed"); + return true; + } + + void releaseTensor(TensorHandle &handle) { + if (handle.tensor) { + aclDestroyTensor_(handle.tensor); + handle.tensor = nullptr; + } + if (handle.data) { + aclrtFree_(handle.data); + handle.data = nullptr; + } + } + + bool runStarsQuery() { + void *stream = nullptr; + if (aclrtCreateStreamWithConfig_(&stream, 0, + detail::kAclStreamFastLaunch | + detail::kAclStreamFastSync) != 0) + return fail("aclrtCreateStreamWithConfig for the query stream failed"); + + // Ask the runtime to report a failed query rather than tearing the process + // down, so a missing STARS backend surfaces as a return code. + uint32_t failureMode = 1; + aclrtSetStreamAttribute_(stream, detail::kAclStreamAttrFailureMode, + &failureMode); + + TensorHandle input; + TensorHandle output; + void *aclnnWs = nullptr; + bool ok = false; + + do { + if (!makeScalarTensor({reinterpret_cast(opResDevice_), + reinterpret_cast(workspaceDevice_)}, + input)) + break; + if (!makeScalarTensor({0}, output)) + break; + + uint64_t wsSize = 0; + void *executor = nullptr; + if (starsQueryGetWsSize_(input.tensor, output.tensor, &wsSize, + &executor) != 0) { + fail("aclnnShmemSdmaStarsQueryGetWorkspaceSize failed"); + break; + } + if (wsSize > 0 && aclrtMalloc_(&aclnnWs, wsSize, + detail::kAclMemMallocHugeFirst) != 0) { + fail("aclrtMalloc of the operator workspace failed"); + break; + } + if (starsQueryExec_(aclnnWs, wsSize, executor, stream) != 0) { + fail("aclnnShmemSdmaStarsQuery failed"); + break; + } + if (aclrtSynchronizeStream_(stream) != 0) { + fail("aclrtSynchronizeStream after the query failed"); + break; + } + ok = true; + } while (false); + + if (aclnnWs) + aclrtFree_(aclnnWs); + releaseTensor(input); + releaseTensor(output); + aclrtDestroyStream_(stream); + return ok; + } + + bool inited_{false}; + std::string error_; + uint32_t reportedQueueNum_{0}; + std::vector streams_; + void *recordsDevice_{nullptr}; + void *workspaceDevice_{nullptr}; + void *streamsDevice_{nullptr}; + void *opResDevice_{nullptr}; + + void *aclHandle_{nullptr}; + void *rtHandle_{nullptr}; + void *opapiHandle_{nullptr}; + void *nnopHandle_{nullptr}; + + AclrtCreateStreamWithConfigFn aclrtCreateStreamWithConfig_{nullptr}; + AclrtDestroyStreamFn aclrtDestroyStream_{nullptr}; + AclrtStreamGetIdFn aclrtStreamGetId_{nullptr}; + AclrtGetCurrentContextFn aclrtGetCurrentContext_{nullptr}; + AclrtGetDeviceFn aclrtGetDevice_{nullptr}; + AclrtMallocFn aclrtMalloc_{nullptr}; + AclrtFreeFn aclrtFree_{nullptr}; + AclrtMemsetFn aclrtMemset_{nullptr}; + AclrtMemcpyFn aclrtMemcpy_{nullptr}; + AclrtSynchronizeStreamFn aclrtSynchronizeStream_{nullptr}; + AclrtSetStreamAttributeFn aclrtSetStreamAttribute_{nullptr}; + + RtStreamGetSqidFn rtStreamGetSqid_{nullptr}; + RtStreamGetCqidFn rtStreamGetCqid_{nullptr}; + RtGetDeviceInfoFn rtGetDeviceInfo_{nullptr}; + + AclCreateTensorFn aclCreateTensor_{nullptr}; + AclDestroyTensorFn aclDestroyTensor_{nullptr}; + StarsQueryGetWsSizeFn starsQueryGetWsSize_{nullptr}; + StarsQueryExecFn starsQueryExec_{nullptr}; +}; + +} // namespace mlir::pto::comm + +#endif // PTO_TEST_COMM_ASYNCWORKSPACE_H diff --git a/test/comm/HcclWindows.h b/test/comm/HcclWindows.h new file mode 100644 index 0000000000..731d181410 --- /dev/null +++ b/test/comm/HcclWindows.h @@ -0,0 +1,270 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +#ifndef PTO_TEST_COMM_HCCLWINDOWS_H +#define PTO_TEST_COMM_HCCLWINDOWS_H + +// Test scaffolding: obtains the peer window table a remote transfer needs. +// +// A cross-device transfer needs an address on the far rank that the local DMA +// engine can resolve. Peer access is not enough -- measured on 910B1, an +// ordinary device pointer from another device is not reachable, and even a +// runtime device-to-device copy over such a pair hangs. The addresses that do +// work come from the communication domain, which is what sets up the +// translation, and HCCL hands them over as a window table. +// +// The route here is the one the reference stack uses: +// +// HcclGetCommName name the group behind an existing comm +// HcomGetL0TopoTypeEx reports the L0 topo; A5 often returns CUSTOM(5) +// rather than 1D mesh. The V2 tiling path still +// fills a CommDeviceContext-shaped window table. +// HcomGetCommHandleByGroup the handle the allocator wants +// HcclAllocComResourceByTiling +// on mesh, returns a device CommDeviceContext +// +// None of those four are declared in a public CANN header, and the tiling +// struct is an internal layout transcribed here, so this is a test aid and not +// something to ship. The supported call for this, HcclSymWinGetPeerPointer, is +// declared in hccl_sym_win.h but exported by no library in CANN 9.0.0; once it +// works, all of this collapses into one call. + +#if defined(__CCE_KT_TEST__) || defined(__CCE__) +#error "HcclWindows.h is a host-only header and cannot be included in device code." +#endif + +#include +#include +#include +#include +#include + +#include + +#include "acl/acl.h" +#include "hccl/hccl.h" +#include "hccl/hccl_types.h" + +namespace mlir::pto::comm { + +//===----------------------------------------------------------------------===// +// HCCL entry points used here but not declared in any public header +//===----------------------------------------------------------------------===// +// +// These live behind libhccl on CANN 9.0.0, but 9.2.0 moved them into a +// dependency that lld will not pull in through -lhccl. Resolve them the same +// way AsyncWorkspace does: look in the already-loaded HCCL stack first, then +// in the libraries that have carried them across releases. + +using HcclAllocComResourceByTilingFn = HcclResult (*)(HcclComm, void *, void *, + void **); +using HcomGetCommHandleByGroupFn = HcclResult (*)(const char *, HcclComm *); +using HcomGetL0TopoTypeExFn = HcclResult (*)(const char *, uint32_t *, + uint32_t); + +namespace hccl_win { + +constexpr uint32_t kTopoMesh = 0b1u; +constexpr uint32_t kIsNotSetDevice = 0; +constexpr uint32_t kMaxRankNum = 64; +constexpr uint32_t kGroupNameSize = 128; +constexpr uint32_t kAlgConfigSize = 128; +constexpr uint32_t kMaxCcTilingNum = 8; + +// Internal HCCL tiling layout. Field order and the constants below are what the +// allocator expects; they come from the reference implementation and are not +// derivable from anything public. +struct Mc2InitTilingInner { + uint32_t version; + uint32_t mc2HcommCnt; + uint32_t offset[kMaxCcTilingNum]; + uint8_t debugMode; + uint8_t preparePosition; + uint16_t queueNum; + uint16_t commBlockNum; + uint8_t devType; + char reserved[17]; +}; + +struct Mc2cCTilingInner { + uint8_t skipLocalRankCopy; + uint8_t skipBufferWindowCopy; + uint8_t stepSize; + uint8_t version; + char reserved[9]; + uint8_t commEngine; + uint8_t srcDataType; + uint8_t dstDataType; + char groupName[kGroupNameSize]; + char algConfig[kAlgConfigSize]; + uint32_t opType; + uint32_t reduceType; +}; + +struct Mc2CommConfigV2 { + Mc2InitTilingInner init; + Mc2cCTilingInner inner; +}; + +inline void fillDefaultTiling(Mc2CommConfigV2 &tiling, const char *groupName) { + std::memset(&tiling, 0, sizeof(tiling)); + tiling.init.version = 100U; + tiling.init.mc2HcommCnt = 1U; + tiling.init.commBlockNum = 48U; + tiling.init.devType = 4U; + tiling.init.offset[0] = + static_cast(offsetof(Mc2CommConfigV2, inner)); + tiling.inner.opType = 18U; + tiling.inner.commEngine = 3U; + tiling.inner.version = 1U; + if (groupName != nullptr) { + std::strncpy(tiling.inner.groupName, groupName, kGroupNameSize - 1); + tiling.inner.groupName[kGroupNameSize - 1] = '\0'; + } + std::strncpy(tiling.inner.algConfig, "BatchWrite=level0:fullmesh", + kAlgConfigSize - 1); + tiling.inner.algConfig[kAlgConfigSize - 1] = '\0'; +} + +} // namespace hccl_win + +//===----------------------------------------------------------------------===// +// Window table +//===----------------------------------------------------------------------===// + +// What the allocator leaves in device memory on a mesh topology. windowsIn[r] +// is this rank's address for rank r's inbound window, which is exactly what a +// remote transfer names as its destination. +struct CommDeviceContext { + uint64_t workSpace; + uint64_t workSpaceSize; + uint32_t rankId; + uint32_t rankNum; + uint64_t winSize; + uint64_t windowsIn[hccl_win::kMaxRankNum]; + uint64_t windowsOut[hccl_win::kMaxRankNum]; +}; + +class HcclWindows { +public: + // Collective across the ranks of `comm`, so every rank has to call it, and in + // a single-process run that means one thread per rank. + bool init(HcclComm comm, void *stream) { + if (!loadSymbols()) + return false; + + char group[hccl_win::kGroupNameSize] = {}; + if (HcclGetCommName(comm, group) != HCCL_SUCCESS) + return fail("HcclGetCommName failed"); + + if (hcomGetL0TopoTypeEx_(group, &topo_, hccl_win::kIsNotSetDevice) != + HCCL_SUCCESS) + return fail("HcomGetL0TopoTypeEx failed"); + + HcclComm handle = nullptr; + if (hcomGetCommHandleByGroup_(group, &handle) != HCCL_SUCCESS || + handle == nullptr) + return fail("HcomGetCommHandleByGroup failed"); + + hccl_win::Mc2CommConfigV2 tiling{}; + hccl_win::fillDefaultTiling(tiling, group); + + void *devCtx = nullptr; + const HcclResult hret = + hcclAllocComResourceByTiling_(handle, stream, &tiling, &devCtx); + if (hret != HCCL_SUCCESS || devCtx == nullptr) + return fail("HcclAllocComResourceByTiling failed: " + + std::to_string(static_cast(hret))); + + if (aclrtMemcpy(&context_, sizeof(context_), devCtx, sizeof(context_), + ACL_MEMCPY_DEVICE_TO_HOST) != ACL_SUCCESS) + return fail("reading the window table back failed"); + + if (context_.rankNum == 0 || context_.rankNum > hccl_win::kMaxRankNum) + return fail("window table reports rankNum " + + std::to_string(context_.rankNum) + " (topo " + + std::to_string(topo_) + ")"); + if (context_.rankId >= context_.rankNum) + return fail("window table reports rankId " + + std::to_string(context_.rankId) + " of " + + std::to_string(context_.rankNum) + " (topo " + + std::to_string(topo_) + ")"); + for (uint32_t r = 0; r < context_.rankNum; ++r) { + if (context_.windowsIn[r] == 0) + return fail("windowsIn[" + std::to_string(r) + "] is empty (topo " + + std::to_string(topo_) + ")"); + } + + deviceContext_ = devCtx; + valid_ = true; + return true; + } + + const CommDeviceContext &context() const { return context_; } + + // Address of rank `rank`'s inbound window, as this rank must name it. + uint64_t window(uint32_t rank) const { + return rank < context_.rankNum ? context_.windowsIn[rank] : 0; + } + + uint64_t windowBytes() const { return context_.winSize; } + uint32_t rankId() const { return context_.rankId; } + uint32_t rankNum() const { return context_.rankNum; } + uint32_t topo() const { return topo_; } + + // Owned by HCCL; nothing to free here. + void *deviceContext() const { return deviceContext_; } + + bool valid() const { return valid_; } + const std::string &error() const { return error_; } + +private: + bool fail(std::string message) { + error_ = std::move(message); + return false; + } + + template + bool bind(Fn &slot, const char *name) { + if (slot) + return true; + slot = reinterpret_cast(dlsym(RTLD_DEFAULT, name)); + if (slot) + return true; + static const char *kLibs[] = {"libhccl.so", "libhcom.so", "libhccl_plf.so", + "libhccl_heterog.so"}; + for (const char *lib : kLibs) { + void *handle = dlopen(lib, RTLD_NOW | RTLD_GLOBAL); + if (!handle) + continue; + slot = reinterpret_cast(dlsym(handle, name)); + if (slot) + return true; + } + return fail(std::string("dlsym ") + name + " failed"); + } + + bool loadSymbols() { + return bind(hcomGetL0TopoTypeEx_, "HcomGetL0TopoTypeEx") && + bind(hcomGetCommHandleByGroup_, "HcomGetCommHandleByGroup") && + bind(hcclAllocComResourceByTiling_, "HcclAllocComResourceByTiling"); + } + + CommDeviceContext context_{}; + void *deviceContext_ = nullptr; + bool valid_ = false; + uint32_t topo_{0}; + std::string error_; + HcomGetL0TopoTypeExFn hcomGetL0TopoTypeEx_{nullptr}; + HcomGetCommHandleByGroupFn hcomGetCommHandleByGroup_{nullptr}; + HcclAllocComResourceByTilingFn hcclAllocComResourceByTiling_{nullptr}; +}; + +} // namespace mlir::pto::comm + +#endif // PTO_TEST_COMM_HCCLWINDOWS_H diff --git a/test/lit/vpto/aicore_ld_st_dev_invalid.pto b/test/lit/vpto/aicore_ld_st_dev_invalid.pto index fcd403473a..5073cd1d72 100644 --- a/test/lit/vpto/aicore_ld_st_dev_invalid.pto +++ b/test/lit/vpto/aicore_ld_st_dev_invalid.pto @@ -13,7 +13,7 @@ // RUN: not ptoas --pto-arch=a5 --pto-backend=vpto %t/helper.pto -o %t/helper.o 2>&1 | FileCheck %s --check-prefix=HELPER // RUN: not ptoas --pto-arch=a5 --pto-backend=vpto %t/policy.pto -o %t/policy.o 2>&1 | FileCheck %s --check-prefix=POLICY // RUN: not ptoas --pto-arch=a5 --cann-output-version=9.0.0-beta.1 --pto-backend=vpto --emit-vpto-llvm-ir %t/target.pto -o - 2>&1 | FileCheck %s --check-prefix=BETA -// RUN: not ptoas --pto-arch=a3 --cann-output-version=9.0.0 --pto-backend=vpto --emit-vpto-llvm-ir %t/target.pto -o - 2>&1 | FileCheck %s --check-prefix=A3 +// RUN: not ptoas --pto-arch=a3 --pto-backend=vpto --emit-vpto-llvm-ir %t/a3_st_dev.pto -o - 2>&1 | FileCheck %s --check-prefix=A3 // SIMT: 'pto.ld_dev' op must be outside pto.simt_entry functions and pto.section.simt // UB: 'pto.st_dev' op requires GM pointer @@ -21,7 +21,7 @@ // HELPER: 'pto.ld_dev' op requires an enclosing ordinary AICore entry function // POLICY: 'pto.ld_dev' op does not accept l1cache or l2cache policy attributes // BETA: pto.ld_dev and pto.st_dev require CANN 9.0.0 or newer official lowering -// A3: pto.ld_dev and pto.st_dev require --pto-arch=a5 +// A3: pto.st_dev is not supported on A2/A3 //--- simt.pto module attributes {pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind} { @@ -71,6 +71,16 @@ module attributes {pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind} { + func.func @a3_st_dev(%gm: !pto.ptr) attributes {pto.aicore} { + %c0 = arith.constant 0 : index + %value = arith.constant 1 : i32 + pto.st_dev %value, %gm[%c0] : !pto.ptr, i32 + return + } +} + //--- policy.pto module attributes {pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind} { func.func @policy(%gm: !pto.ptr) attributes {pto.aicore} { diff --git a/test/lit/vpto/aicore_ld_st_dev_vpto_llvm.pto b/test/lit/vpto/aicore_ld_st_dev_vpto_llvm.pto index a93bc49712..ea1b355d3c 100644 --- a/test/lit/vpto/aicore_ld_st_dev_vpto_llvm.pto +++ b/test/lit/vpto/aicore_ld_st_dev_vpto_llvm.pto @@ -7,6 +7,9 @@ // See LICENSE in the root of the software repository for the full text of the License. // RUN: ptoas --cann-output-version=9.0.0 --pto-arch=a5 --pto-backend=vpto --emit-vpto-llvm-ir %s -o - 2>&1 | FileCheck %s +// A2/A3 must not emit ST.DEV. SDMA doorbell coverage for that split is in +// async_sdma_gm_gm.pto; A2/A3 rejection of pto.st_dev is in +// aicore_ld_st_dev_invalid.pto. module attributes {pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind} { func.func @aicore_ld_st_dev( diff --git a/test/lit/vpto/async_sdma_gm_gm.pto b/test/lit/vpto/async_sdma_gm_gm.pto new file mode 100644 index 0000000000..89c78dc974 --- /dev/null +++ b/test/lit/vpto/async_sdma_gm_gm.pto @@ -0,0 +1,154 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// RUN: ptoas --pto-arch=a5 --pto-backend=vpto --emit-vpto --mlir-print-ir-before=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ROUNDTRIP +// RUN: ptoas --pto-arch=a5 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=EXPAND +// RUN: ptoas --pto-arch=a5 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=SQE-A5 +// RUN: ptoas --pto-arch=a3 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=SQE-A2A3 --implicit-check-not=pto.st_dev --implicit-check-not="arith.constant 3840 : i32" + +// The session config struct is built in the kernel from the pointer the host +// passes in, because a stack-local struct cannot be a kernel argument. Only the +// immutable scalars live here; the queue tail stays where the engine keeps it +// so it survives across launches, and the channel record names its address. + +module attributes {"pto.target_arch" = "a5", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_probe(%dst: !pto.ptr, + %src: !pto.ptr, + %ws: !pto.ptr) attributes {pto.kernel} { + %c0 = arith.constant 0 : index + %nbytes = arith.constant 4096 : i64 + // Ordinary AICore entry functions read GM scalars with ld_dev; pto.ldg is + // restricted to SIMT scopes. + %ctx = pto.ld_dev %ws[%c0] : !pto.ptr -> i64 + + %z64 = arith.constant 0 : i64 + %z32 = arith.constant 0 : i32 + %one32 = arith.constant 1 : i32 + %qos = arith.constant 6 : i32 + %block = arith.constant 1048576 : i64 + + %sess = pto.declare_struct + -> !pto.struct + + pto.struct_set %sess[0], %ctx + : !pto.struct, i64 + pto.struct_set %sess[1], %z64 + : !pto.struct, i64 + pto.struct_set %sess[2], %z32 + : !pto.struct, i32 + pto.struct_set %sess[3], %z32 + : !pto.struct, i32 + pto.struct_set %sess[4], %z32 + : !pto.struct, i32 + pto.struct_set %sess[5], %one32 + : !pto.struct, i32 + pto.struct_set %sess[6], %block + : !pto.struct, i64 + pto.struct_set %sess[7], %z64 + : !pto.struct, i64 + pto.struct_set %sess[8], %z32 + : !pto.struct, i32 + pto.struct_set %sess[9], %z32 + : !pto.struct, i32 + pto.struct_set %sess[10], %z32 + : !pto.struct, i32 + pto.struct_set %sess[11], %one32 + : !pto.struct, i32 + + // 12 qos: the service class these posts run at, fixed for the session. + pto.struct_set %sess[12], %qos + : !pto.struct, i32 + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} + +// ROUNDTRIP-LABEL: func.func @sdma_gm_gm_probe( +// ROUNDTRIP: pto.declare_struct +// ROUNDTRIP: pto.sdma_gm_gm %{{.*}}, %{{.*}}, %{{.*}} session(%{{.*}}) + +// The kick disappears, replaced by channel-record reads, a split loop that +// writes one SQE per block, a release barrier, and the doorbell store. +// +// The SQE words and the queue tail go out as ordinary stores on both +// generations, matching the reference SDMA implementation. What makes them +// visible to the engine is the cache flush and barrier that follow, so the +// order of those three is what this pins down. This run targets A5, where the +// doorbell is an st_dev. +// EXPAND-LABEL: func.func @sdma_gm_gm_probe( +// EXPAND-NOT: pto.sdma_gm_gm +// EXPAND: pto.struct_get %{{.*}}[0] +// EXPAND: pto.ld_dev +// EXPAND: scf.for +// EXPAND: pto.store +// EXPAND: scf.yield +// EXPAND: pto.store +// EXPAND: pto.dcci +// EXPAND: pto.dsb +// EXPAND: pto.st_dev + +// The SQE layout is not shared across generations, so the packed word values +// and the length position pin down which branch ran. A5 sets wrCqe in word 0, +// carries credit 254, puts sssv..dns at bit 8, and writes the length at byte 48. +// +// Service class comes from the session on both generations, but lands in a +// different word: A5 gives it a word of its own at byte 20, shifted to bit 27, +// while A2/A3 ors it into word 4 at bit 13. Reading field 12 and shifting by +// the generation's amount is what tells the two apart, since neither value is a +// constant the pass can fold. These share the group above because constants are +// hoisted to the top of the function, which leaves their relative order up to +// the builder. +// SQE-A5-DAG: arith.constant 2059 : i32 +// SQE-A5-DAG: arith.constant 16646144 : i32 +// SQE-A5-DAG: arith.constant 3840 : i32 +// SQE-A5-DAG: arith.constant 48 : i64 +// SQE-A5-DAG: arith.constant 27 : i32 +// SQE-A5-DAG: arith.constant 20 : i64 +// SQE-A5-DAG: pto.struct_get %{{.*}}[12] +// SQE-A5-NOT: arith.constant 7680 : i32 + +// A2/A3 has no wrCqe bit, uses credit 240, shifts sssv..dns up one bit to make +// room for ie2, keeps the length at byte 28, and has to declare the post +// unlinked because byte 48 holds a link type there. Word 4 is 7680 without the +// service class, which is ored in on top of it. +// SQE-A2A3-DAG: arith.constant 11 : i32 +// SQE-A2A3-DAG: arith.constant 15728640 : i32 +// SQE-A2A3-DAG: arith.constant 7680 : i32 +// SQE-A2A3-DAG: arith.constant 28 : i64 +// SQE-A2A3-DAG: arith.constant 255 : i32 +// SQE-A2A3-DAG: arith.constant 13 : i32 +// SQE-A2A3-DAG: pto.struct_get %{{.*}}[12] + +// The doorbell is the other thing that splits by generation, and it is the one +// place the two do not merely differ in bit layout. sq_reg_base names a +// register, not memory: A5 reaches it with st_dev, while A2/A3 takes it only +// from MTE, so the tail is staged in the session's tmp_buf and moved out four +// bytes at a time. Neither an st_dev nor a scalar store to that address works +// on A2/A3, and the store faults the vector unit hard enough to leave the card +// in an unrecoverable RAS state. That st_dev never appears on A2/A3, and that +// A5's word 4 never leaks into it, is enforced for the whole output by the +// implicit-check-not on the RUN line above. +// +// byte_granular is what makes those four bytes survive: the default c220 store +// counts its length in 32-byte blocks, so a four-byte doorbell write rounds +// down to a transfer of nothing and the engine is never told the ring moved. +// +// The event guarding that staging is the session's, not a fixed one, so it uses +// the dyn form of the flag ops. A kernel that already drives MTE3 events can +// then keep them apart from this one. +// SQE-A2A3: pto.struct_get %{{.*}}[1] +// SQE-A2A3: pto.struct_get %{{.*}}[3] +// SQE-A2A3: pto.castptr %{{.*}} : i64 -> !pto.ptr +// SQE-A2A3: pto.store %{{.*}}, %{{.*}} : !pto.ptr, i32 +// SQE-A2A3: pto.set_flag_dyn[, +// SQE-A2A3: pto.wait_flag_dyn[, +// SQE-A2A3: pto.copy_ubuf_to_gm {{.*}}{vpto.byte_granular} diff --git a/test/lit/vpto/async_sdma_gm_gm_a5_soft_put.pto b/test/lit/vpto/async_sdma_gm_gm_a5_soft_put.pto new file mode 100644 index 0000000000..5584a7b157 --- /dev/null +++ b/test/lit/vpto/async_sdma_gm_gm_a5_soft_put.pto @@ -0,0 +1,139 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// RUN: ptoas --pto-arch=a5 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=A5 +// RUN: ptoas --pto-arch=a3 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=A3 + +// A5 cannot PUT through the engine. {soft_put} turns the kick into a +// GM→UB→GM copy. A2/A3 ignores the attr and still posts SQEs. + +module attributes {"pto.target_arch" = "a5", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_soft_put(%dst: !pto.ptr, + %src: !pto.ptr, + %ws: !pto.ptr) attributes {pto.kernel} { + %c0 = arith.constant 0 : index + %nbytes = arith.constant 4096 : i64 + %ctx = pto.ld_dev %ws[%c0] : !pto.ptr -> i64 + + %z64 = arith.constant 0 : i64 + %z32 = arith.constant 0 : i32 + %one32 = arith.constant 1 : i32 + %qos = arith.constant 6 : i32 + %block = arith.constant 1048576 : i64 + + %sess = pto.declare_struct + -> !pto.struct + + pto.struct_set %sess[0], %ctx + : !pto.struct, i64 + pto.struct_set %sess[1], %z64 + : !pto.struct, i64 + pto.struct_set %sess[2], %z32 + : !pto.struct, i32 + pto.struct_set %sess[3], %z32 + : !pto.struct, i32 + pto.struct_set %sess[4], %z32 + : !pto.struct, i32 + pto.struct_set %sess[5], %one32 + : !pto.struct, i32 + pto.struct_set %sess[6], %block + : !pto.struct, i64 + pto.struct_set %sess[7], %z64 + : !pto.struct, i64 + pto.struct_set %sess[8], %z32 + : !pto.struct, i32 + pto.struct_set %sess[9], %z32 + : !pto.struct, i32 + pto.struct_set %sess[10], %z32 + : !pto.struct, i32 + pto.struct_set %sess[11], %one32 + : !pto.struct, i32 + pto.struct_set %sess[12], %qos + : !pto.struct, i32 + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } + + // Peer kernels use i8 endpoints and a runtime byte count. A same-type + // pto.castptr is illegal at emission, so this function is the shape that + // used to fail VPTO validation. + func.func @sdma_gm_gm_soft_put_i8(%dst: !pto.ptr, + %src: !pto.ptr, + %ws: !pto.ptr, + %nbytes: i64) attributes {pto.kernel} { + %c0 = arith.constant 0 : index + %ctx = pto.ld_dev %ws[%c0] : !pto.ptr -> i64 + + %z64 = arith.constant 0 : i64 + %z32 = arith.constant 0 : i32 + %one32 = arith.constant 1 : i32 + %qos = arith.constant 6 : i32 + %block = arith.constant 1048576 : i64 + + %sess = pto.declare_struct + -> !pto.struct + + pto.struct_set %sess[0], %ctx + : !pto.struct, i64 + pto.struct_set %sess[1], %z64 + : !pto.struct, i64 + pto.struct_set %sess[2], %z32 + : !pto.struct, i32 + pto.struct_set %sess[3], %z32 + : !pto.struct, i32 + pto.struct_set %sess[4], %z32 + : !pto.struct, i32 + pto.struct_set %sess[5], %one32 + : !pto.struct, i32 + pto.struct_set %sess[6], %block + : !pto.struct, i64 + pto.struct_set %sess[7], %z64 + : !pto.struct, i64 + pto.struct_set %sess[8], %z32 + : !pto.struct, i32 + pto.struct_set %sess[9], %z32 + : !pto.struct, i32 + pto.struct_set %sess[10], %z32 + : !pto.struct, i32 + pto.struct_set %sess[11], %one32 + : !pto.struct, i32 + pto.struct_set %sess[12], %qos + : !pto.struct, i32 + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} + +// A5-LABEL: func.func @sdma_gm_gm_soft_put( +// A5-NOT: pto.sdma_gm_gm +// A5: pto.copy_gm_to_ubuf +// A5: pto.set_flag_dyn[, +// A5: pto.wait_flag_dyn[, +// A5: pto.copy_ubuf_to_gm +// A5-NOT: pto.st_dev +// A5-LABEL: func.func @sdma_gm_gm_soft_put_i8( +// A5-NOT: pto.sdma_gm_gm +// A5: pto.copy_gm_to_ubuf +// A5: pto.copy_ubuf_to_gm + +// A3 still posts the engine path; the attr is A5-only. +// A3-LABEL: func.func @sdma_gm_gm_soft_put( +// A3-NOT: pto.sdma_gm_gm +// A3: pto.store +// A3: pto.copy_ubuf_to_gm +// A3-LABEL: func.func @sdma_gm_gm_soft_put_i8( +// A3-NOT: pto.sdma_gm_gm +// A3: pto.store diff --git a/test/lit/vpto/async_session_init.pto b/test/lit/vpto/async_session_init.pto new file mode 100644 index 0000000000..e719d185a2 --- /dev/null +++ b/test/lit/vpto/async_session_init.pto @@ -0,0 +1,57 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// RUN: ptoas --pto-arch=a3 --pto-backend=vpto --emit-vpto --mlir-print-ir-before=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=ROUNDTRIP +// RUN: ptoas --pto-arch=a3 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=EXPAND + +// A session cannot reach a kernel as an argument, so the host leaves its values +// in GM and the kernel copies them into a struct it declares itself. Without +// this op that copy is one load and one store per field, written out at every +// entry point. + +module attributes {"pto.target_arch" = "a3", pto.kernel_kind = #pto.kernel_kind} { + func.func @session_init_probe(%dst: !pto.ptr, + %src: !pto.ptr, + %tmpl: !pto.ptr) attributes {pto.kernel} { + %nbytes = arith.constant 4096 : i64 + + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %tmpl + : !pto.struct, + !pto.ptr + + // A field may still be retuned after the copy, which is what makes the + // template a default rather than the whole story. + %grp = arith.constant 2 : i32 + pto.struct_set %sess[4], %grp + : !pto.struct, i32 + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} + +// ROUNDTRIP: pto.session_init %{{.*}}, %{{.*}} : !pto.struct, !pto.ptr + +// The op is gone and every field has been copied. Slots are eight bytes wide +// regardless of field width, so the offsets run 0, 8, 16 ... and a narrow field +// is read at the base of its slot rather than packed against its neighbour. +// EXPAND-NOT: pto.session_init +// EXPAND-DAG: arith.constant 8 : i64 +// EXPAND-DAG: arith.constant 16 : i64 +// EXPAND-DAG: arith.constant 96 : i64 + +// Field 0 is 64-bit and field 2 is 32-bit; both are read with ld_dev because a +// comm kernel is an ordinary entry function, where ldg is not available. +// EXPAND: pto.ld_dev %{{.*}} : !pto.ptr -> i64 +// EXPAND: pto.struct_set %{{.*}}[0] diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto new file mode 100644 index 0000000000..312df29eac --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto @@ -0,0 +1,40 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-local +// target_ops: pto.sdma_gm_gm, pto.session_init +// scenarios: single-device, local GM->GM, one channel, block splitting +// ----------------------------------------------------------------------------- +// +// One core copies between two local GM buffers. The host polls the destination, +// because returning from the kernel does not mean the engine has drained. +// +// Every session value comes from the template the host wrote, including the +// block size, so the kernel says nothing about how the transfer is split. That +// is what lets the host sweep splits without rebuilding this. + +module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_local(%dst: !pto.ptr, + %src: !pto.ptr, + %sess_gm: !pto.ptr, + %nbytes: i64) attributes {pto.kernel} { + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp new file mode 100644 index 0000000000..a89c562b77 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-local +// target_ops: pto.sdma_gm_gm +// scenarios: single-device, local GM->GM, one channel, one block +// ----------------------------------------------------------------------------- +#ifndef __VEC_SCOPE__ +#define __VEC_SCOPE__ +#endif + +#include + +#ifndef __CPU_SIM +#include "acl/acl.h" +#endif + +extern "C" __global__ [aicore] void sdma_gm_gm_local(__gm__ int8_t *dst, + __gm__ int8_t *src, + __gm__ int8_t *sessionGm, + int64_t nbytes); + +// A single block: the session owns one channel group, and a second core would +// race it on the same queue ring. +void LaunchSdmaGmGmLocal(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream) { + sdma_gm_gm_local<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, + (__gm__ int8_t *)src, + (__gm__ int8_t *)sessionGm, nbytes); +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp new file mode 100644 index 0000000000..dc0fd6bf26 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp @@ -0,0 +1,232 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-local +// target_ops: pto.sdma_gm_gm +// scenarios: single-device, local GM->GM, one channel, block splitting +// ----------------------------------------------------------------------------- +// +// The kernel returning only means the doorbell was written; the engine drains +// the queue on its own schedule. So the destination is polled rather than read +// once, and the queue tail is reported either way: a tail that advanced with a +// destination that never changed points at the engine, while a tail that +// stayed at zero points at the post itself. +// +// The same transfer is repeated at several block sizes. Correct data alone +// would not show that splitting happened, since one oversized entry moves the +// same bytes, so each round also checks that the tail advanced by exactly the +// number of entries the split implies. The sizes cover the divisible case, a +// case where the last entry is short, and one small enough to fill a good part +// of the ring. + +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl.h" + +#include "AsyncWorkspace.h" + +using mlir::pto::comm::AsyncWorkspace; +namespace workspace = mlir::pto::comm::workspace; + +void LaunchSdmaGmGmLocal(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream); + +namespace { + +constexpr size_t kTransferBytes = 4096; +constexpr int kPollTimeoutMs = 2000; +constexpr unsigned kChannels = 1; + +// Every size is a multiple of 64, the smallest transfer the engine accepts. +const size_t kBlockSizes[] = {4096, 1024, 1536, 128}; + +#define ACL_CHECK(expr) \ + do { \ + const aclError _ret = (expr); \ + if (_ret != ACL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + const char *_recent = aclGetRecentErrMsg(); \ + if (_recent != nullptr && _recent[0] != '\0') \ + std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ + return 1; \ + } \ + } while (0) + +uint32_t readSqTail(AsyncWorkspace &ws) { + uint8_t raw[workspace::kChannelDescBytes]; + if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) + return 0xFFFFFFFFU; + uint32_t tail; + std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); + return tail; +} + +} // namespace + +int main(int argc, char **argv) { + const int deviceId = + argc > 1 ? std::atoi(argv[1]) + : (std::getenv("ACL_DEVICE_ID") + ? std::atoi(std::getenv("ACL_DEVICE_ID")) + : 0); + + ACL_CHECK(aclInit(nullptr)); + ACL_CHECK(aclrtSetDevice(deviceId)); + + aclrtStream stream = nullptr; + ACL_CHECK(aclrtCreateStream(&stream)); + + AsyncWorkspace ws; + if (!ws.init(kChannels)) { + std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", + ws.error().c_str()); + return 1; + } + std::printf("workspace %p, sq_tail before post = %u\n", ws.contextGm(), + readSqTail(ws)); + + // What the kernel will read for channel 0. Printing it here separates a bad + // table from a bad read of a good one, which are the two ways a post can go + // wrong before the engine is ever involved. + { + uint8_t rec[mlir::pto::comm::channel::kRecordBytes]; + if (ws.readChannelRecord(0, rec)) { + namespace ch = mlir::pto::comm::channel; + uint64_t sqBase, doorbell, tailAddr, headAddr; + uint32_t slotMask, streamId; + std::memcpy(&sqBase, rec + ch::kSqBaseOffset, sizeof(sqBase)); + std::memcpy(&doorbell, rec + ch::kDoorbellOffset, sizeof(doorbell)); + std::memcpy(&tailAddr, rec + ch::kTailAddrOffset, sizeof(tailAddr)); + std::memcpy(&headAddr, rec + ch::kHeadAddrOffset, sizeof(headAddr)); + std::memcpy(&slotMask, rec + ch::kSlotMaskOffset, sizeof(slotMask)); + std::memcpy(&streamId, rec + ch::kStreamIdOffset, sizeof(streamId)); + std::printf("record 0: sq_base=%#" PRIx64 " doorbell=%#" PRIx64 + " tail@%#" PRIx64 " head@%#" PRIx64 " slot_mask=%u" + " stream=%u\n", + sqBase, doorbell, tailAddr, headAddr, slotMask, streamId); + } + } + + std::vector pattern(kTransferBytes); + for (size_t i = 0; i < kTransferBytes; ++i) + pattern[i] = static_cast((i * 31 + 7) & 0xFF); + + void *srcDevice = nullptr; + void *dstDevice = nullptr; + ACL_CHECK(aclrtMalloc(&srcDevice, kTransferBytes, ACL_MEM_MALLOC_HUGE_FIRST)); + ACL_CHECK(aclrtMalloc(&dstDevice, kTransferBytes, ACL_MEM_MALLOC_HUGE_FIRST)); + ACL_CHECK(aclrtMemcpy(srcDevice, kTransferBytes, pattern.data(), + kTransferBytes, ACL_MEMCPY_HOST_TO_DEVICE)); + + // The session the kernel will copy in. Everything the kernel knows about the + // transfer beyond its size comes from here, so a different split is a + // different template rather than a different kernel. + namespace comm = mlir::pto::comm; + void *sessionDevice = nullptr; + ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, + ACL_MEM_MALLOC_HUGE_FIRST)); + + std::printf("posting %zu bytes: src=%p dst=%p session=%p\n", kTransferBytes, + srcDevice, dstDevice, sessionDevice); + + int rc = 0; + std::vector readback(kTransferBytes); + + for (size_t i = 0; i < sizeof(kBlockSizes) / sizeof(kBlockSizes[0]); ++i) { + const size_t block = kBlockSizes[i]; + const uint32_t wantEntries = + static_cast((kTransferBytes + block - 1) / block); + + comm::session_tmpl::Builder tmpl; + tmpl.set(comm::SessionField::ContextGm, + reinterpret_cast(ws.contextGm())) + .set(comm::SessionField::ChannelIdx, 0) + .set(comm::SessionField::ChannelNum, 1) + .set(comm::SessionField::BlockBytes, block) + .set(comm::SessionField::Engine, + static_cast(comm::SessionEngine::Sdma)) + .set(comm::SessionField::Flags, comm::kSessionFlagValid) + .set(comm::SessionField::Qos, comm::sqe::kQosDefault); + ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, + tmpl.data(), comm::session_tmpl::kBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + + ACL_CHECK(aclrtMemset(dstDevice, kTransferBytes, 0, kTransferBytes)); + const uint32_t tailBefore = readSqTail(ws); + + LaunchSdmaGmGmLocal(static_cast(dstDevice), + static_cast(srcDevice), + static_cast(sessionDevice), + static_cast(kTransferBytes), stream); + ACL_CHECK(aclrtSynchronizeStream(stream)); + + bool matched = false; + int elapsedMs = 0; + const auto start = std::chrono::steady_clock::now(); + while (elapsedMs < kPollTimeoutMs) { + ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, dstDevice, + kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); + if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { + matched = true; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + elapsedMs = static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count()); + } + + // The tail is what separates "moved the bytes" from "moved them the way it + // was asked to": the same data arrives either way, but only a real split + // leaves this many entries behind. + const uint32_t tailAfter = readSqTail(ws); + const uint32_t posted = tailAfter - tailBefore; + const bool ok = matched && posted == wantEntries; + + std::printf("block %5zu -> %u entries (want %u), data %s %s\n", block, + posted, wantEntries, matched ? "match" : "MISMATCH", + ok ? "OK" : "FAIL"); + std::fflush(stdout); + + if (!ok) { + if (!matched) { + size_t changed = 0; + for (size_t b = 0; b < kTransferBytes; ++b) + if (readback[b] != 0) + ++changed; + std::fprintf(stderr, + " destination did not match within %d ms " + "(%zu of %zu bytes non-zero)\n", + kPollTimeoutMs, changed, kTransferBytes); + } + rc = 1; + break; + } + } + + if (rc == 0) + std::printf("PASS: every split posted the entries it implies\n"); + + aclrtFree(srcDevice); + aclrtFree(dstDevice); + aclrtFree(sessionDevice); + ws.finalize(); + aclrtDestroyStream(stream); + aclrtResetDevice(deviceId); + aclFinalize(); + return rc; +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh new file mode 100755 index 0000000000..b2711d9569 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# Build and run the local GM->GM SDMA case. +# +# This does not go through run_host_vpto_validation.sh because that script +# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because +# the host program needs the PTOAS include path for AsyncWorkspace.h. +# +# Requires CANN 9.0.0 at run time: the workspace setup calls +# aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. +# +# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [device] +# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [device] +set -euo pipefail + +CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" + +# The build tree is often outside the repo, so try the usual places and say +# which ones were tried rather than reporting only the default. +resolve_ptoas() { + if [[ -n "${PTOAS_BIN:-}" ]]; then + echo "${PTOAS_BIN}" + return + fi + local candidates=() + [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") + candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") + local onpath + onpath="$(command -v ptoas 2>/dev/null || true)" + [[ -n "${onpath}" ]] && candidates+=("${onpath}") + for c in "${candidates[@]}"; do + if [[ -x "${c}" ]]; then + echo "${c}" + return + fi + done + echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 + printf ' %s\n' "${candidates[@]}" >&2 + exit 1 +} + +PTOAS_BIN="$(resolve_ptoas)" +ARCH="${ARCH:-a3}" +AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" +# Only the vec/cube suffix is dropped for the launch object's arch flag. +# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. +AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" +AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" +OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" +DEVICE_ID="${1:-0}" + +: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" +BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" + +command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } + +mkdir -p "${OUT_DIR}" +echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" + +echo "== 1/4 kernel fatobj" +"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ + "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" + +echo "== 2/4 launch object" +"${BISHENG_BIN}" \ + -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ + -Xhost-start -Xhost-end \ + -mllvm -cce-aicore-stack-size=0x8000 \ + -mllvm -cce-aicore-function-stack-size=0x8000 \ + -mllvm -cce-aicore-record-overflow=true \ + -mllvm -cce-aicore-addr-transform \ + -mllvm -cce-aicore-dcci-insert-for-scalar=false \ + --cce-aicore-arch="${AICORE_ARCH_BASE}" \ + -DREGISTER_BASE -std=c++17 \ + -Wno-macro-redefined -Wno-ignored-attributes \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -I "${ASCEND_HOME_PATH}/pkg_inc" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ + "${CASE_DIR}/launch.cpp" \ + -o "${OUT_DIR}/launch.o" + +echo "== 3/4 kernel shared library" +"${BISHENG_BIN}" \ + -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ + -shared -Wl,-soname,libsdma_gm_gm_local_kernel.so \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/libsdma_gm_gm_local_kernel.so" \ + "${OUT_DIR}/kernel.fatobj.o" \ + "${OUT_DIR}/launch.o" \ + -Wl,--no-as-needed -lruntime + +echo "== 4/4 host executable" +"${BISHENG_BIN}" \ + -xc++ -std=c++17 \ + "${CASE_DIR}/main.cpp" \ + -I "${CASE_DIR}" \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -L "${OUT_DIR}" \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${OUT_DIR}" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/sdma_gm_gm_local" \ + -lsdma_gm_gm_local_kernel \ + -Wl,--allow-shlib-undefined -lruntime \ + -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase + +# Building is safe anywhere; running needs a card. Splitting the two lets a +# change be checked for compile errors without putting a device at risk. +if [ -n "${BUILD_ONLY:-}" ]; then + echo "== build only, skipping the run" + exit 0 +fi + +echo "== run on device ${DEVICE_ID}" +cd "${OUT_DIR}" +# A kernel that never returns holds the device until the process dies, and +# suspending the shell leaves it held. Kill the run instead, hard if it will +# not go, so a failed case costs a case rather than a card. +set +e +LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ + timeout --signal=KILL "${RUN_TIMEOUT:-60}" ./sdma_gm_gm_local "${DEVICE_ID}" +rc=$? +set -e +if [ "${rc}" -eq 137 ]; then + echo "== killed after ${RUN_TIMEOUT:-60}s; device ${DEVICE_ID} may need a reset" >&2 +fi +exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto new file mode 100644 index 0000000000..3e131b160c --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto @@ -0,0 +1,58 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-multicore +// target_ops: pto.sdma_gm_gm, pto.session_init +// scenarios: single-device, local GM->GM, one channel group per core +// ----------------------------------------------------------------------------- +// +// Every core posts its own slice through its own channel group, which is the +// arrangement the channel index exists for: two cores sharing a group would +// interleave writes into one queue ring and corrupt each other's entries. +// +// The core id picks both the slice and the group, so the two stay aligned +// without the host having to describe the mapping. Everything else in the +// session comes from the host's template, which is why only one field is +// written here. + +module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_multicore(%dst: !pto.ptr, + %src: !pto.ptr, + %sess_gm: !pto.ptr, + %chunk: i64) attributes {pto.kernel} { + %bid = pto.get_block_idx + %bid32 = arith.trunci %bid : i64 to i32 + + // Slice base for this core. Both sides move by the same amount, so the + // destination mirrors the source. + %off = arith.muli %bid, %chunk : i64 + %src_i64 = pto.castptr %src : !pto.ptr -> i64 + %dst_i64 = pto.castptr %dst : !pto.ptr -> i64 + %my_src_i64 = arith.addi %src_i64, %off : i64 + %my_dst_i64 = arith.addi %dst_i64, %off : i64 + %my_src = pto.castptr %my_src_i64 : i64 -> !pto.ptr + %my_dst = pto.castptr %my_dst_i64 : i64 -> !pto.ptr + + %sess = pto.declare_struct -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + // The template cannot name the core, so the one field that differs per core + // is written after the copy. Everything else stays as the host set it. + pto.struct_set %sess[4], %bid32 : !pto.struct, i32 + + pto.sdma_gm_gm %my_dst, %my_src, %chunk session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp new file mode 100644 index 0000000000..acbc24a623 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-multicore +// target_ops: pto.sdma_gm_gm +// scenarios: single-device, local GM->GM, one channel group per core +// ----------------------------------------------------------------------------- +#ifndef __VEC_SCOPE__ +#define __VEC_SCOPE__ +#endif + +#include + +#ifndef __CPU_SIM +#include "acl/acl.h" +#endif + +extern "C" __global__ [aicore] void sdma_gm_gm_multicore( + __gm__ int8_t *dst, __gm__ int8_t *src, __gm__ int8_t *sessionGm, + int64_t chunkBytes); + +// One block per channel group. The workspace has to have been built with at +// least this many channels, or a core would index past the record table. +void LaunchSdmaGmGmMulticore(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t chunkBytes, uint32_t blocks, + void *stream) { + sdma_gm_gm_multicore<<>>( + (__gm__ int8_t *)dst, (__gm__ int8_t *)src, (__gm__ int8_t *)sessionGm, + chunkBytes); +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp new file mode 100644 index 0000000000..2444168a67 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp @@ -0,0 +1,208 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-multicore +// target_ops: pto.sdma_gm_gm +// scenarios: single-device, local GM->GM, one channel group per core +// ----------------------------------------------------------------------------- +// +// Correct data would not by itself show that the cores stayed on separate +// queues: one core doing all the work, or several sharing a ring and happening +// not to collide, both produce the same bytes. So the check is per channel -- +// every group must have advanced by exactly one entry. A group that moved by +// more took someone else's post, and a group that did not move at all was +// never used. +// +// Each core's slice carries a distinct byte pattern, so a mismatch also says +// which core's transfer went wrong rather than only that something did. + +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl.h" + +#include "AsyncWorkspace.h" + +using mlir::pto::comm::AsyncWorkspace; +namespace workspace = mlir::pto::comm::workspace; + +void LaunchSdmaGmGmMulticore(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t chunkBytes, uint32_t blocks, void *stream); + +namespace { + +constexpr unsigned kCores = 4; +constexpr size_t kChunkBytes = 1024; +constexpr size_t kTotalBytes = kCores * kChunkBytes; +constexpr int kPollTimeoutMs = 2000; + +#define ACL_CHECK(expr) \ + do { \ + const aclError _ret = (expr); \ + if (_ret != ACL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + const char *_recent = aclGetRecentErrMsg(); \ + if (_recent != nullptr && _recent[0] != '\0') \ + std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ + return 1; \ + } \ + } while (0) + +uint32_t readSqTail(AsyncWorkspace &ws, unsigned channel) { + uint8_t raw[workspace::kChannelDescBytes]; + if (!ws.readChannelDescriptor(0, kCores, channel, raw)) + return 0xFFFFFFFFU; + uint32_t tail; + std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); + return tail; +} + +} // namespace + +int main(int argc, char **argv) { + const int deviceId = + argc > 1 ? std::atoi(argv[1]) + : (std::getenv("ACL_DEVICE_ID") + ? std::atoi(std::getenv("ACL_DEVICE_ID")) + : 0); + + ACL_CHECK(aclInit(nullptr)); + ACL_CHECK(aclrtSetDevice(deviceId)); + + aclrtStream stream = nullptr; + ACL_CHECK(aclrtCreateStream(&stream)); + + AsyncWorkspace ws; + if (!ws.init(kCores)) { + std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", + ws.error().c_str()); + return 1; + } + + std::vector tailBefore(kCores); + for (unsigned c = 0; c < kCores; ++c) + tailBefore[c] = readSqTail(ws, c); + + std::printf("workspace %p, %u channel groups\n", ws.contextGm(), kCores); + for (unsigned c = 0; c < kCores; ++c) { + uint8_t rec[mlir::pto::comm::channel::kRecordBytes]; + if (!ws.readChannelRecord(c, rec)) + continue; + namespace ch = mlir::pto::comm::channel; + uint64_t sqBase, doorbell; + uint32_t streamId; + std::memcpy(&sqBase, rec + ch::kSqBaseOffset, sizeof(sqBase)); + std::memcpy(&doorbell, rec + ch::kDoorbellOffset, sizeof(doorbell)); + std::memcpy(&streamId, rec + ch::kStreamIdOffset, sizeof(streamId)); + std::printf(" group %u: sq_base=%#" PRIx64 " doorbell=%#" PRIx64 + " stream=%u tail=%u\n", + c, sqBase, doorbell, streamId, tailBefore[c]); + } + + // A distinct pattern per slice, so a wrong slice is visible as the wrong + // core's data rather than as generic corruption. + std::vector pattern(kTotalBytes); + for (unsigned c = 0; c < kCores; ++c) + for (size_t i = 0; i < kChunkBytes; ++i) + pattern[c * kChunkBytes + i] = + static_cast(((i * 31 + 7) ^ (c * 0x5B)) & 0xFF); + + void *srcDevice = nullptr; + void *dstDevice = nullptr; + ACL_CHECK(aclrtMalloc(&srcDevice, kTotalBytes, ACL_MEM_MALLOC_HUGE_FIRST)); + ACL_CHECK(aclrtMalloc(&dstDevice, kTotalBytes, ACL_MEM_MALLOC_HUGE_FIRST)); + ACL_CHECK(aclrtMemcpy(srcDevice, kTotalBytes, pattern.data(), kTotalBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + ACL_CHECK(aclrtMemset(dstDevice, kTotalBytes, 0, kTotalBytes)); + + // One template for every core. The channel group is the only thing that + // differs, and the kernel writes that itself from its core id. + namespace comm = mlir::pto::comm; + void *sessionDevice = nullptr; + ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, + ACL_MEM_MALLOC_HUGE_FIRST)); + { + comm::session_tmpl::Builder tmpl; + tmpl.set(comm::SessionField::ContextGm, + reinterpret_cast(ws.contextGm())) + .set(comm::SessionField::ChannelNum, 1) + .set(comm::SessionField::BlockBytes, kChunkBytes) + .set(comm::SessionField::Engine, + static_cast(comm::SessionEngine::Sdma)) + .set(comm::SessionField::Flags, comm::kSessionFlagValid) + .set(comm::SessionField::Qos, comm::sqe::kQosDefault); + ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, + tmpl.data(), comm::session_tmpl::kBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + } + + std::printf("posting %u slices of %zu bytes: src=%p dst=%p session=%p\n", + kCores, kChunkBytes, srcDevice, dstDevice, sessionDevice); + + LaunchSdmaGmGmMulticore(static_cast(dstDevice), + static_cast(srcDevice), + static_cast(sessionDevice), + static_cast(kChunkBytes), kCores, stream); + ACL_CHECK(aclrtSynchronizeStream(stream)); + + std::vector readback(kTotalBytes); + bool matched = false; + int elapsedMs = 0; + const auto start = std::chrono::steady_clock::now(); + while (elapsedMs < kPollTimeoutMs) { + ACL_CHECK(aclrtMemcpy(readback.data(), kTotalBytes, dstDevice, kTotalBytes, + ACL_MEMCPY_DEVICE_TO_HOST)); + if (std::memcmp(readback.data(), pattern.data(), kTotalBytes) == 0) { + matched = true; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + elapsedMs = static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count()); + } + + int rc = 0; + for (unsigned c = 0; c < kCores; ++c) { + const uint32_t after = readSqTail(ws, c); + const uint32_t posted = after - tailBefore[c]; + + size_t badBytes = 0; + for (size_t i = 0; i < kChunkBytes; ++i) + if (readback[c * kChunkBytes + i] != pattern[c * kChunkBytes + i]) + ++badBytes; + + const bool ok = posted == 1 && badBytes == 0; + std::printf("group %u: %u entry (want 1), %zu bad bytes %s\n", c, posted, + badBytes, ok ? "OK" : "FAIL"); + if (!ok) + rc = 1; + } + + if (rc == 0 && matched) + std::printf("PASS: every core posted through its own group\n"); + else if (rc == 0) + std::printf("PASS (late): data settled after %d ms\n", elapsedMs); + + aclrtFree(srcDevice); + aclrtFree(dstDevice); + aclrtFree(sessionDevice); + ws.finalize(); + aclrtDestroyStream(stream); + aclrtResetDevice(deviceId); + aclFinalize(); + return rc; +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh new file mode 100755 index 0000000000..835fcf3875 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh @@ -0,0 +1,133 @@ +#!/bin/bash +# Build and run the multicore GM->GM SDMA case, one channel group per core. +# +# This does not go through run_host_vpto_validation.sh because that script +# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because +# the host program needs the PTOAS include path for AsyncWorkspace.h. +# +# Requires CANN 9.0.0 at run time: the workspace setup calls +# aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. +# +# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [device] +# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [device] +set -euo pipefail + +CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" + +# The build tree is often outside the repo, so try the usual places and say +# which ones were tried rather than reporting only the default. +resolve_ptoas() { + if [[ -n "${PTOAS_BIN:-}" ]]; then + echo "${PTOAS_BIN}" + return + fi + local candidates=() + [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") + candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") + local onpath + onpath="$(command -v ptoas 2>/dev/null || true)" + [[ -n "${onpath}" ]] && candidates+=("${onpath}") + for c in "${candidates[@]}"; do + if [[ -x "${c}" ]]; then + echo "${c}" + return + fi + done + echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 + printf ' %s\n' "${candidates[@]}" >&2 + exit 1 +} + +PTOAS_BIN="$(resolve_ptoas)" +ARCH="${ARCH:-a3}" +AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" +# Only the vec/cube suffix is dropped for the launch object's arch flag. +# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. +AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" +AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" +OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" +DEVICE_ID="${1:-0}" + +: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" +BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" + +command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } + +mkdir -p "${OUT_DIR}" +echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" + +echo "== 1/4 kernel fatobj" +"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ + "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" + +echo "== 2/4 launch object" +"${BISHENG_BIN}" \ + -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ + -Xhost-start -Xhost-end \ + -mllvm -cce-aicore-stack-size=0x8000 \ + -mllvm -cce-aicore-function-stack-size=0x8000 \ + -mllvm -cce-aicore-record-overflow=true \ + -mllvm -cce-aicore-addr-transform \ + -mllvm -cce-aicore-dcci-insert-for-scalar=false \ + --cce-aicore-arch="${AICORE_ARCH_BASE}" \ + -DREGISTER_BASE -std=c++17 \ + -Wno-macro-redefined -Wno-ignored-attributes \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -I "${ASCEND_HOME_PATH}/pkg_inc" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ + "${CASE_DIR}/launch.cpp" \ + -o "${OUT_DIR}/launch.o" + +echo "== 3/4 kernel shared library" +"${BISHENG_BIN}" \ + -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ + -shared -Wl,-soname,libsdma_gm_gm_multicore_kernel.so \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/libsdma_gm_gm_multicore_kernel.so" \ + "${OUT_DIR}/kernel.fatobj.o" \ + "${OUT_DIR}/launch.o" \ + -Wl,--no-as-needed -lruntime + +echo "== 4/4 host executable" +"${BISHENG_BIN}" \ + -xc++ -std=c++17 \ + "${CASE_DIR}/main.cpp" \ + -I "${CASE_DIR}" \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -L "${OUT_DIR}" \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${OUT_DIR}" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/sdma_gm_gm_multicore" \ + -lsdma_gm_gm_multicore_kernel \ + -Wl,--allow-shlib-undefined -lruntime \ + -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase + +# Building is safe anywhere; running needs a card. Splitting the two lets a +# change be checked for compile errors without putting a device at risk. +if [ -n "${BUILD_ONLY:-}" ]; then + echo "== build only, skipping the run" + exit 0 +fi + +echo "== run on device ${DEVICE_ID}" +cd "${OUT_DIR}" +# A kernel that never returns holds the device until the process dies, and +# suspending the shell leaves it held. Kill the run instead, hard if it will +# not go, so a failed case costs a case rather than a card. +set +e +LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ + timeout --signal=KILL "${RUN_TIMEOUT:-60}" ./sdma_gm_gm_multicore "${DEVICE_ID}" +rc=$? +set -e +if [ "${rc}" -eq 137 ]; then + echo "== killed after ${RUN_TIMEOUT:-60}s; device ${DEVICE_ID} may need a reset" >&2 +fi +exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto new file mode 100644 index 0000000000..32794be04c --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto @@ -0,0 +1,41 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-get +// target_ops: pto.sdma_gm_gm, pto.session_init +// scenarios: two-device, peer GM->local GM, one channel, block splitting +// ----------------------------------------------------------------------------- +// +// Rank 0 reads rank 1's window. There is no `{soft_put}`: A5's engine will +// GET from a peer, so this kick posts SQEs the same way a local copy does. +// The peer-put counterpart needs the attr because that generation cannot write +// remotely through the engine. +// +// The session comes from a template the host wrote, which is also where the +// workspace address lives, so the kernel names neither. + +module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_peer_get(%dst: !pto.ptr, + %src: !pto.ptr, + %sess_gm: !pto.ptr, + %nbytes: i64) attributes {pto.kernel} { + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp new file mode 100644 index 0000000000..1f20f0eb60 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-get +// target_ops: pto.sdma_gm_gm +// scenarios: two-device, peer GM->local GM, one channel, block splitting +// ----------------------------------------------------------------------------- +#ifndef __VEC_SCOPE__ +#define __VEC_SCOPE__ +#endif + +#include + +#ifndef __CPU_SIM +#include "acl/acl.h" +#endif + +extern "C" __global__ [aicore] void sdma_gm_gm_peer_get(__gm__ int8_t *dst, + __gm__ int8_t *src, + __gm__ int8_t *sessionGm, + int64_t nbytes); + +// A single block: the session owns one channel group, and a second core would +// race it on the same queue ring. +void LaunchSdmaGmGmPeerGet(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream) { + sdma_gm_gm_peer_get<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, + (__gm__ int8_t *)src, + (__gm__ int8_t *)sessionGm, + nbytes); +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp new file mode 100644 index 0000000000..d6ec7ca024 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp @@ -0,0 +1,296 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-get +// target_ops: pto.sdma_gm_gm +// scenarios: two-device, peer GM->local GM, one channel, block splitting +// ----------------------------------------------------------------------------- +// +// Rank 0 posts a GET from rank 1's window into its own. A5's engine can read +// a peer, so this kick posts SQEs: the tail must advance, and the destination +// is polled because returning from the kernel does not mean the engine has +// drained. sdma-gm-gm-peer-put uses `{soft_put}` and leaves the tail at zero. +// +// The same transfer is repeated at several block sizes, matching +// sdma-gm-gm-local: data alone would not show that splitting happened. +// +// Both endpoints sit in the HCCL window, because that is the memory a remote +// transfer can name. Rank 1 writes its own window, rank 0 names that range +// through its peer view, and rank 0 reads its own destination, so a pass +// cannot be explained by the bytes already sitting on the near device. + +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl.h" +#include "hccl/hccl.h" + +#include "AsyncWorkspace.h" +#include "HcclWindows.h" + +using mlir::pto::comm::AsyncWorkspace; +using mlir::pto::comm::HcclWindows; +namespace workspace = mlir::pto::comm::workspace; + +void LaunchSdmaGmGmPeerGet(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream); + +namespace { + +constexpr size_t kTransferBytes = 4096; +constexpr unsigned kChannels = 1; +constexpr unsigned kRanks = 2; + +// Every size is a multiple of 64, the smallest transfer the engine accepts. +const size_t kBlockSizes[] = {4096, 1024, 1536, 128}; + +// The engine can queue behind other work, and this machine is shared, so the +// window is wide enough that a slow completion is not read as a failure. +constexpr int kPollTimeoutMsDefault = 30000; + +#define ACL_CHECK(expr) \ + do { \ + const aclError _ret = (expr); \ + if (_ret != ACL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + const char *_recent = aclGetRecentErrMsg(); \ + if (_recent != nullptr && _recent[0] != '\0') { \ + std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ + } \ + return 1; \ + } \ + } while (0) + +#define HCCL_CHECK(expr) \ + do { \ + const HcclResult _ret = (expr); \ + if (_ret != HCCL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +uint32_t readSqTail(AsyncWorkspace &ws) { + uint8_t raw[workspace::kChannelDescBytes]; + if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) { + return 0xFFFFFFFFU; + } + uint32_t tail; + std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); + return tail; +} + +struct Rank { + int32_t device = -1; + aclrtStream stream = nullptr; + HcclWindows windows; + bool ok = false; +}; + +// One per rank, on its own thread: ACL binds a device per thread, and the +// domain build has to be entered by both ranks at once. +void setupRank(Rank *rank, HcclComm comm) { + if (aclrtSetDevice(rank->device) != ACL_SUCCESS) { + return; + } + if (aclrtCreateStream(&rank->stream) != ACL_SUCCESS) { + return; + } + if (!rank->windows.init(comm, rank->stream)) { + std::fprintf(stderr, "[ERROR] device %d window setup failed: %s\n", + rank->device, rank->windows.error().c_str()); + return; + } + rank->ok = true; +} + +} // namespace + +int main(int argc, char **argv) { + int32_t devices[kRanks] = {0, 1}; + if (argc > 2) { + devices[0] = std::atoi(argv[1]); + devices[1] = std::atoi(argv[2]); + } + const int pollTimeoutMs = std::getenv("SDMA_POLL_TIMEOUT_MS") + ? std::atoi(std::getenv("SDMA_POLL_TIMEOUT_MS")) + : kPollTimeoutMsDefault; + + std::printf("case: async-comm/sdma-gm-gm-peer-get direction=GET\n"); + std::printf("ranks: 0 -> device %d, 1 -> device %d\n", devices[0], + devices[1]); + + ACL_CHECK(aclInit(nullptr)); + // HcclCommInitAll reads the calling thread's current device even though it + // opens all of them, and fails outright if none is set. + ACL_CHECK(aclrtSetDevice(devices[0])); + + HcclComm comms[kRanks] = {nullptr, nullptr}; + HCCL_CHECK(HcclCommInitAll(kRanks, devices, comms)); + + Rank ranks[kRanks]; + for (unsigned r = 0; r < kRanks; ++r) { + ranks[r].device = devices[r]; + } + { + std::thread t0(setupRank, &ranks[0], comms[0]); + std::thread t1(setupRank, &ranks[1], comms[1]); + t0.join(); + t1.join(); + } + for (unsigned r = 0; r < kRanks; ++r) { + if (!ranks[r].ok) { + std::fprintf(stderr, "[ERROR] rank %u setup failed\n", r); + return 1; + } + } + + const uint64_t windowBytes = ranks[0].windows.windowBytes(); + std::printf("window %" PRIu64 " bytes, rank0 sees: own %#" PRIx64 + ", peer %#" PRIx64 "\n", + windowBytes, ranks[0].windows.window(0), + ranks[0].windows.window(1)); + std::printf("rank1 sees: own %#" PRIx64 ", peer %#" PRIx64 "\n", + ranks[1].windows.window(1), ranks[1].windows.window(0)); + if (windowBytes < kTransferBytes) { + std::fprintf(stderr, "[ERROR] window smaller than the transfer\n"); + return 1; + } + + // Payload lives on rank 1. Rank 0 names it through its peer view and writes + // into its own window. + ACL_CHECK(aclrtSetDevice(devices[1])); + void *farSrc = reinterpret_cast(ranks[1].windows.window(1)); + std::vector pattern(kTransferBytes); + for (size_t i = 0; i < kTransferBytes; ++i) { + pattern[i] = static_cast((i * 31 + 7) & 0xFF); + } + ACL_CHECK(aclrtMemcpy(farSrc, kTransferBytes, pattern.data(), kTransferBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + + ACL_CHECK(aclrtSetDevice(devices[0])); + void *src = reinterpret_cast(ranks[0].windows.window(1)); + void *dst = reinterpret_cast(ranks[0].windows.window(0)); + + AsyncWorkspace ws; + if (!ws.init(kChannels)) { + std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", + ws.error().c_str()); + return 1; + } + std::printf("workspace %p, sq_tail before post = %u\n", ws.contextGm(), + readSqTail(ws)); + std::printf("posting %zu bytes: src=%p (dev %d) dst=%p (dev %d)\n", + kTransferBytes, src, devices[1], dst, devices[0]); + + namespace comm = mlir::pto::comm; + void *sessionDevice = nullptr; + ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, + ACL_MEM_MALLOC_HUGE_FIRST)); + + int rc = 0; + std::vector readback(kTransferBytes); + const size_t nBlocks = sizeof(kBlockSizes) / sizeof(kBlockSizes[0]); + for (size_t i = 0; i < nBlocks; ++i) { + const size_t block = kBlockSizes[i]; + const uint32_t wantEntries = + static_cast((kTransferBytes + block - 1) / block); + + comm::session_tmpl::Builder tmpl; + tmpl.set(comm::SessionField::ContextGm, + reinterpret_cast(ws.contextGm())) + .set(comm::SessionField::ChannelIdx, 0) + .set(comm::SessionField::ChannelNum, 1) + .set(comm::SessionField::BlockBytes, block) + .set(comm::SessionField::Engine, + static_cast(comm::SessionEngine::Sdma)) + .set(comm::SessionField::Flags, comm::kSessionFlagValid) + .set(comm::SessionField::Qos, comm::sqe::kQosDefault); + ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, + tmpl.data(), comm::session_tmpl::kBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + + ACL_CHECK(aclrtMemset(dst, kTransferBytes, 0, kTransferBytes)); + const uint32_t tailBefore = readSqTail(ws); + + LaunchSdmaGmGmPeerGet(static_cast(dst), + static_cast(src), + static_cast(sessionDevice), + static_cast(kTransferBytes), + ranks[0].stream); + ACL_CHECK(aclrtSynchronizeStream(ranks[0].stream)); + + bool matched = false; + int elapsedMs = 0; + const auto start = std::chrono::steady_clock::now(); + while (elapsedMs < pollTimeoutMs) { + ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, dst, + kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); + if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { + matched = true; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + elapsedMs = static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count()); + } + + const uint32_t tailAfter = readSqTail(ws); + const uint32_t posted = tailAfter - tailBefore; + const bool ok = matched && posted == wantEntries; + std::printf("block %5zu -> %u entries (want %u), data %s %s\n", block, + posted, wantEntries, matched ? "match" : "MISMATCH", + ok ? "OK" : "FAIL"); + std::fflush(stdout); + + if (!ok) { + if (!matched) { + size_t changed = 0; + for (size_t b = 0; b < kTransferBytes; ++b) { + if (readback[b] != 0) { + ++changed; + } + } + std::fprintf(stderr, + " destination did not match within %d ms " + "(%zu of %zu bytes non-zero)\n", + pollTimeoutMs, changed, kTransferBytes); + } + rc = 1; + break; + } + } + + if (rc == 0) { + std::printf("PASS: every split posted the entries it implies\n"); + } + + ws.finalize(); + aclrtFree(sessionDevice); + for (unsigned r = 0; r < kRanks; ++r) { + if (ranks[r].stream != nullptr) { + aclrtSetDevice(ranks[r].device); + aclrtDestroyStream(ranks[r].stream); + } + HcclCommDestroy(comms[r]); + } + aclrtResetDevice(devices[0]); + aclrtResetDevice(devices[1]); + aclFinalize(); + return rc; +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh new file mode 100755 index 0000000000..6faed98699 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh @@ -0,0 +1,140 @@ +#!/bin/bash +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# +# Build and run the cross-device peer-GM -> local-GM SDMA GET case. +# +# This does not go through run_host_vpto_validation.sh because that script +# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because +# the host program needs the PTOAS include path for AsyncWorkspace.h. +# +# Needs two visible devices, and CANN 9.0.0 at run time: the workspace setup +# calls aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. +# +# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [dev0] [dev1] +# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [dev0] [dev1] +set -euo pipefail + +CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" + +# The build tree is often outside the repo, so try the usual places and say +# which ones were tried rather than reporting only the default. +resolve_ptoas() { + if [[ -n "${PTOAS_BIN:-}" ]]; then + echo "${PTOAS_BIN}" + return + fi + local candidates=() + [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") + candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") + local onpath + onpath="$(command -v ptoas 2>/dev/null || true)" + [[ -n "${onpath}" ]] && candidates+=("${onpath}") + for c in "${candidates[@]}"; do + if [[ -x "${c}" ]]; then + echo "${c}" + return + fi + done + echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 + printf ' %s\n' "${candidates[@]}" >&2 + exit 1 +} + +PTOAS_BIN="$(resolve_ptoas)" +ARCH="${ARCH:-a3}" +AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" +# Only the vec/cube suffix is dropped for the launch object's arch flag. +# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. +AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" +AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" +OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" +DEVICE0="${1:-0}" +DEVICE1="${2:-1}" + +: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" +BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" + +command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } + +mkdir -p "${OUT_DIR}" +echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" + +echo "== 1/4 kernel fatobj" +"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ + "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" + +echo "== 2/4 launch object" +"${BISHENG_BIN}" \ + -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ + -Xhost-start -Xhost-end \ + -mllvm -cce-aicore-stack-size=0x8000 \ + -mllvm -cce-aicore-function-stack-size=0x8000 \ + -mllvm -cce-aicore-record-overflow=true \ + -mllvm -cce-aicore-addr-transform \ + -mllvm -cce-aicore-dcci-insert-for-scalar=false \ + --cce-aicore-arch="${AICORE_ARCH_BASE}" \ + -DREGISTER_BASE -std=c++17 \ + -Wno-macro-redefined -Wno-ignored-attributes \ + -I "${ASCEND_HOME_PATH}/include" \ + -I "${ASCEND_HOME_PATH}/pkg_inc" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ + "${CASE_DIR}/launch.cpp" \ + -o "${OUT_DIR}/launch.o" + +echo "== 3/4 kernel shared library" +"${BISHENG_BIN}" \ + -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ + -shared -Wl,-soname,libsdma_gm_gm_peer_get_kernel.so \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/libsdma_gm_gm_peer_get_kernel.so" \ + "${OUT_DIR}/kernel.fatobj.o" \ + "${OUT_DIR}/launch.o" \ + -Wl,--no-as-needed -lruntime + +echo "== 4/4 host executable" +"${BISHENG_BIN}" \ + -xc++ -std=c++17 \ + "${CASE_DIR}/main.cpp" \ + -I "${CASE_DIR}" \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -L "${OUT_DIR}" \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${OUT_DIR}" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/sdma_gm_gm_peer_get" \ + -lsdma_gm_gm_peer_get_kernel \ + -Wl,--allow-shlib-undefined -lruntime \ + -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase -lhccl -lpthread + +# Building is safe anywhere; running needs a card. Splitting the two lets a +# change be checked for compile errors without putting a device at risk. +if [ -n "${BUILD_ONLY:-}" ]; then + echo "== build only, skipping the run" + exit 0 +fi + +echo "== run GET on devices ${DEVICE1} -> ${DEVICE0}" +cd "${OUT_DIR}" +# A kernel that never returns holds both devices until the process dies, and +# suspending the shell leaves them held. Kill the run instead, hard if it will +# not go, so a failed case costs a case rather than a card. +set +e +LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ + timeout --signal=KILL "${RUN_TIMEOUT:-90}" ./sdma_gm_gm_peer_get "${DEVICE0}" "${DEVICE1}" +rc=$? +set -e +if [ "${rc}" -eq 137 ]; then + echo "== killed after ${RUN_TIMEOUT:-90}s; devices ${DEVICE0}/${DEVICE1} may need a reset" >&2 +fi +exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto new file mode 100644 index 0000000000..235acd4e8c --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto @@ -0,0 +1,40 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-put +// target_ops: pto.sdma_gm_gm, pto.session_init +// scenarios: two-device, GM->peer GM, one channel, one block +// ----------------------------------------------------------------------------- +// +// Identical to sdma-gm-gm-local except for where the destination points, and +// `{soft_put}` so A5 can complete a remote write: that generation's engine +// will not PUT, so the expansion stages through UB. A2/A3 ignore the attr. +// +// The session comes from a template the host wrote, which is also where the +// workspace address lives, so the kernel names neither. + +module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { + func.func @sdma_gm_gm_peer_put(%dst: !pto.ptr, + %src: !pto.ptr, + %sess_gm: !pto.ptr, + %nbytes: i64) attributes {pto.kernel} { + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp new file mode 100644 index 0000000000..c5ade0eeef --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-put +// target_ops: pto.sdma_gm_gm +// scenarios: two-device, GM->peer GM, one channel, one block +// ----------------------------------------------------------------------------- +#ifndef __VEC_SCOPE__ +#define __VEC_SCOPE__ +#endif + +#include + +#ifndef __CPU_SIM +#include "acl/acl.h" +#endif + +extern "C" __global__ [aicore] void sdma_gm_gm_peer_put(__gm__ int8_t *dst, + __gm__ int8_t *src, + __gm__ int8_t *sessionGm, + int64_t nbytes); + +// A single block: the session owns one channel group, and a second core would +// race it on the same queue ring. +void LaunchSdmaGmGmPeerPut(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream) { + sdma_gm_gm_peer_put<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, + (__gm__ int8_t *)src, + (__gm__ int8_t *)sessionGm, nbytes); +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp new file mode 100644 index 0000000000..f128cbf72d --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp @@ -0,0 +1,270 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// ----------------------------------------------------------------------------- +// case: async-comm/sdma-gm-gm-peer-put +// target_ops: pto.sdma_gm_gm +// scenarios: two-device, GM->peer GM, one channel, one block +// ----------------------------------------------------------------------------- +// +// Cross-device version of sdma-gm-gm-local: rank 0 posts a transfer into rank +// 1's memory. A5 cannot PUT through the engine, so the kernel marks the kick +// `{soft_put}` and the expansion stages the write through UB. A2/A3 posts SQEs. +// +// Both endpoints sit in the HCCL window, because that is the memory a remote +// transfer can name; an ordinary device pointer from the far device does not +// work even for a runtime copy. Rank 0 writes to its view of rank 1's window +// and rank 1 reads its own, so a pass cannot be explained by the bytes staying +// on the near device. +// +// Two ranks in one process, one thread each, because building the domain is +// collective and a single thread would block in the first call. + +#include +#include +#include +#include +#include +#include +#include + +#include "acl/acl.h" +#include "hccl/hccl.h" + +#include "AsyncWorkspace.h" +#include "HcclWindows.h" + +using mlir::pto::comm::AsyncWorkspace; +using mlir::pto::comm::HcclWindows; +namespace workspace = mlir::pto::comm::workspace; + +void LaunchSdmaGmGmPeerPut(int8_t *dst, int8_t *src, int8_t *sessionGm, + int64_t nbytes, void *stream); + +namespace { + +constexpr size_t kTransferBytes = 4096; +constexpr unsigned kChannels = 1; +constexpr unsigned kRanks = 2; + +// The engine can queue behind other work, and this machine is shared, so the +// window is wide enough that a slow completion is not read as a failure. +constexpr int kPollTimeoutMsDefault = 30000; + +#define ACL_CHECK(expr) \ + do { \ + const aclError _ret = (expr); \ + if (_ret != ACL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + const char *_recent = aclGetRecentErrMsg(); \ + if (_recent != nullptr && _recent[0] != '\0') \ + std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ + return 1; \ + } \ + } while (0) + +#define HCCL_CHECK(expr) \ + do { \ + const HcclResult _ret = (expr); \ + if (_ret != HCCL_SUCCESS) { \ + std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ + (int)_ret, __FILE__, __LINE__); \ + return 1; \ + } \ + } while (0) + +uint32_t readSqTail(AsyncWorkspace &ws) { + uint8_t raw[workspace::kChannelDescBytes]; + if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) + return 0xFFFFFFFFU; + uint32_t tail; + std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); + return tail; +} + +struct Rank { + int32_t device = -1; + aclrtStream stream = nullptr; + HcclWindows windows; + bool ok = false; +}; + +// One per rank, on its own thread: ACL binds a device per thread, and the +// domain build has to be entered by both ranks at once. +void setupRank(Rank *rank, HcclComm comm) { + if (aclrtSetDevice(rank->device) != ACL_SUCCESS) + return; + if (aclrtCreateStream(&rank->stream) != ACL_SUCCESS) + return; + if (!rank->windows.init(comm, rank->stream)) { + std::fprintf(stderr, "[ERROR] device %d window setup failed: %s\n", + rank->device, rank->windows.error().c_str()); + return; + } + rank->ok = true; +} + +} // namespace + +int main(int argc, char **argv) { + int32_t devices[kRanks] = {0, 1}; + if (argc > 2) { + devices[0] = std::atoi(argv[1]); + devices[1] = std::atoi(argv[2]); + } + const int pollTimeoutMs = std::getenv("SDMA_POLL_TIMEOUT_MS") + ? std::atoi(std::getenv("SDMA_POLL_TIMEOUT_MS")) + : kPollTimeoutMsDefault; + + std::printf("case: async-comm/sdma-gm-gm-peer-put direction=PUT\n"); + std::printf("ranks: 0 -> device %d, 1 -> device %d\n", devices[0], + devices[1]); + + ACL_CHECK(aclInit(nullptr)); + // HcclCommInitAll reads the calling thread's current device even though it + // opens all of them, and fails outright if none is set. + ACL_CHECK(aclrtSetDevice(devices[0])); + + HcclComm comms[kRanks] = {nullptr, nullptr}; + HCCL_CHECK(HcclCommInitAll(kRanks, devices, comms)); + + Rank ranks[kRanks]; + for (unsigned r = 0; r < kRanks; ++r) + ranks[r].device = devices[r]; + { + std::thread t0(setupRank, &ranks[0], comms[0]); + std::thread t1(setupRank, &ranks[1], comms[1]); + t0.join(); + t1.join(); + } + for (unsigned r = 0; r < kRanks; ++r) { + if (!ranks[r].ok) { + std::fprintf(stderr, "[ERROR] rank %u setup failed\n", r); + return 1; + } + } + + const uint64_t windowBytes = ranks[0].windows.windowBytes(); + std::printf("window %" PRIu64 " bytes, rank0 sees: own %#" PRIx64 + ", peer %#" PRIx64 "\n", + windowBytes, ranks[0].windows.window(0), + ranks[0].windows.window(1)); + std::printf("rank1 sees: own %#" PRIx64 ", peer %#" PRIx64 "\n", + ranks[1].windows.window(1), ranks[1].windows.window(0)); + if (windowBytes < kTransferBytes) { + std::fprintf(stderr, "[ERROR] window smaller than the transfer\n"); + return 1; + } + + ACL_CHECK(aclrtSetDevice(devices[0])); + void *src = reinterpret_cast(ranks[0].windows.window(0)); + void *dst = reinterpret_cast(ranks[0].windows.window(1)); + + std::vector pattern(kTransferBytes); + for (size_t i = 0; i < kTransferBytes; ++i) + pattern[i] = static_cast((i * 31 + 7) & 0xFF); + ACL_CHECK(aclrtMemcpy(src, kTransferBytes, pattern.data(), kTransferBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + + ACL_CHECK(aclrtSetDevice(devices[1])); + void *farSide = reinterpret_cast(ranks[1].windows.window(1)); + ACL_CHECK(aclrtMemset(farSide, kTransferBytes, 0, kTransferBytes)); + + ACL_CHECK(aclrtSetDevice(devices[0])); + + AsyncWorkspace ws; + if (!ws.init(kChannels)) { + std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", + ws.error().c_str()); + return 1; + } + std::printf("PUT: workspace %p, sq_tail before post = %u\n", ws.contextGm(), + readSqTail(ws)); + + // The session the kernel copies in. The workspace address rides in it, so + // the kernel takes no separate workspace argument. + namespace comm = mlir::pto::comm; + void *sessionDevice = nullptr; + ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, + ACL_MEM_MALLOC_HUGE_FIRST)); + { + comm::session_tmpl::Builder tmpl; + tmpl.set(comm::SessionField::ContextGm, + reinterpret_cast(ws.contextGm())) + .set(comm::SessionField::ChannelIdx, 0) + .set(comm::SessionField::ChannelNum, 1) + .set(comm::SessionField::BlockBytes, 1u << 20) + .set(comm::SessionField::Engine, + static_cast(comm::SessionEngine::Sdma)) + .set(comm::SessionField::Flags, comm::kSessionFlagValid) + .set(comm::SessionField::Qos, comm::sqe::kQosDefault); + ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, + tmpl.data(), comm::session_tmpl::kBytes, + ACL_MEMCPY_HOST_TO_DEVICE)); + } + + std::printf("posting %zu bytes: src=%p (dev %d) dst=%p (dev %d)\n", + kTransferBytes, src, devices[0], dst, devices[1]); + + LaunchSdmaGmGmPeerPut(static_cast(dst), static_cast(src), + static_cast(sessionDevice), + static_cast(kTransferBytes), ranks[0].stream); + ACL_CHECK(aclrtSynchronizeStream(ranks[0].stream)); + + const uint32_t tailAfter = readSqTail(ws); + std::printf("kernel returned, sq_tail after post = %u\n", tailAfter); + + ACL_CHECK(aclrtSetDevice(devices[1])); + std::vector readback(kTransferBytes); + bool matched = false; + int elapsedMs = 0; + const auto start = std::chrono::steady_clock::now(); + while (elapsedMs < pollTimeoutMs) { + ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, farSide, + kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); + if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { + matched = true; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + elapsedMs = static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now() - start) + .count()); + } + + int rc = 0; + if (matched) { + std::printf("PASS: peer destination matched after %d ms\n", elapsedMs); + } else { + size_t changed = 0; + for (size_t i = 0; i < kTransferBytes; ++i) + if (readback[i] != 0) + ++changed; + std::fprintf(stderr, + "FAIL: peer destination did not match within %d ms " + "(%zu of %zu bytes non-zero, sq_tail %u)\n", + pollTimeoutMs, changed, kTransferBytes, tailAfter); + rc = 1; + } + + ACL_CHECK(aclrtSetDevice(devices[0])); + ws.finalize(); + for (unsigned r = 0; r < kRanks; ++r) { + if (ranks[r].stream != nullptr) { + aclrtSetDevice(ranks[r].device); + aclrtDestroyStream(ranks[r].stream); + } + HcclCommDestroy(comms[r]); + } + aclrtResetDevice(devices[0]); + aclrtResetDevice(devices[1]); + aclFinalize(); + return rc; +} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh new file mode 100755 index 0000000000..14c4143709 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh @@ -0,0 +1,132 @@ +#!/bin/bash +# Build and run the cross-device GM->peer GM SDMA case. +# +# This does not go through run_host_vpto_validation.sh because that script +# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because +# the host program needs the PTOAS include path for AsyncWorkspace.h. +# +# Needs two visible devices, and CANN 9.0.0 at run time: the workspace setup +# calls aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. +# +# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [dev0] [dev1] +# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [dev0] [dev1] +set -euo pipefail + +CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" + +# The build tree is often outside the repo, so try the usual places and say +# which ones were tried rather than reporting only the default. +resolve_ptoas() { + if [[ -n "${PTOAS_BIN:-}" ]]; then + echo "${PTOAS_BIN}" + return + fi + local candidates=() + [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") + candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") + local onpath + onpath="$(command -v ptoas 2>/dev/null || true)" + [[ -n "${onpath}" ]] && candidates+=("${onpath}") + for c in "${candidates[@]}"; do + if [[ -x "${c}" ]]; then + echo "${c}" + return + fi + done + echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 + printf ' %s\n' "${candidates[@]}" >&2 + exit 1 +} + +PTOAS_BIN="$(resolve_ptoas)" +ARCH="${ARCH:-a3}" +AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" +# Only the vec/cube suffix is dropped for the launch object's arch flag. +# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. +AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" +AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" +OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" +DEVICE0="${1:-0}" +DEVICE1="${2:-1}" + +: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" +BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" + +command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } + +mkdir -p "${OUT_DIR}" +echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" + +echo "== 1/4 kernel fatobj" +"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ + "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" + +echo "== 2/4 launch object" +"${BISHENG_BIN}" \ + -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ + -Xhost-start -Xhost-end \ + -mllvm -cce-aicore-stack-size=0x8000 \ + -mllvm -cce-aicore-function-stack-size=0x8000 \ + -mllvm -cce-aicore-record-overflow=true \ + -mllvm -cce-aicore-addr-transform \ + -mllvm -cce-aicore-dcci-insert-for-scalar=false \ + --cce-aicore-arch="${AICORE_ARCH_BASE}" \ + -DREGISTER_BASE -std=c++17 \ + -Wno-macro-redefined -Wno-ignored-attributes \ + -I "${ASCEND_HOME_PATH}/include" \ + -I "${ASCEND_HOME_PATH}/pkg_inc" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ + -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ + "${CASE_DIR}/launch.cpp" \ + -o "${OUT_DIR}/launch.o" + +echo "== 3/4 kernel shared library" +"${BISHENG_BIN}" \ + -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ + -shared -Wl,-soname,libsdma_gm_gm_peer_put_kernel.so \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/libsdma_gm_gm_peer_put_kernel.so" \ + "${OUT_DIR}/kernel.fatobj.o" \ + "${OUT_DIR}/launch.o" \ + -Wl,--no-as-needed -lruntime + +echo "== 4/4 host executable" +"${BISHENG_BIN}" \ + -xc++ -std=c++17 \ + "${CASE_DIR}/main.cpp" \ + -I "${CASE_DIR}" \ + -I "${REPO_ROOT}/include" \ + -I "${REPO_ROOT}/test/comm" \ + -I "${ASCEND_HOME_PATH}/include" \ + -L "${OUT_DIR}" \ + -L "${ASCEND_HOME_PATH}/lib64" \ + -Wl,-rpath,"${OUT_DIR}" \ + -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ + -o "${OUT_DIR}/sdma_gm_gm_peer_put" \ + -lsdma_gm_gm_peer_put_kernel \ + -Wl,--allow-shlib-undefined -lruntime \ + -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase -lhccl -lpthread + +# Building is safe anywhere; running needs a card. Splitting the two lets a +# change be checked for compile errors without putting a device at risk. +if [ -n "${BUILD_ONLY:-}" ]; then + echo "== build only, skipping the run" + exit 0 +fi + +echo "== run PUT on devices ${DEVICE0} -> ${DEVICE1}" +cd "${OUT_DIR}" +# A kernel that never returns holds both devices until the process dies, and +# suspending the shell leaves them held. Kill the run instead, hard if it will +# not go, so a failed case costs a case rather than a card. +set +e +LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ + timeout --signal=KILL "${RUN_TIMEOUT:-90}" ./sdma_gm_gm_peer_put "${DEVICE0}" "${DEVICE1}" +rc=$? +set -e +if [ "${rc}" -eq 137 ]; then + echo "== killed after ${RUN_TIMEOUT:-90}s; devices ${DEVICE0}/${DEVICE1} may need a reset" >&2 +fi +exit "${rc}" From 84a51047a03a47b635bf333b0d7a572ad2a179dc Mon Sep 17 00:00:00 2001 From: kerwinair Date: Wed, 26 Aug 2026 22:36:46 +0800 Subject: [PATCH 2/7] feat(ptodsl): let @pto.jit link host C++ into the kernel library PTODSL built a kernel's shared library from two inputs it generated itself, the launch code and the ptoas-produced kernel object. A kernel whose host side already exists in C++ had no way in, leaving only two bad options: reimplement the C++ in Python, or ship it as a second library the caller loads separately and keeps in step by hand. native_options names host C++ sources to compile and link into the same library, the include directories they need, and the libraries to link against. Host source contents are digested into the build's cache key, so editing one rebuilds rather than silently reusing. Sources are compiled as host code, reusing the host flags that already existed here but were never wired up. compiled.native_library() reaches the result. Library loading moves out of LaunchHandle so one loaded library is shared by every launch handle over a specialization and by callers looking for a host symbol. Paths resolve against the declaring file, as source= already does. Unknown keys, library names that are really paths or flags, and include_dirs without host_sources are all rejected when the decorator runs. Co-authored-by: Cursor --- .../03-kernel-entry-and-subkernels.md | 66 ++++ ptodsl/ptodsl/_jit.py | 17 + ptodsl/ptodsl/_kernel_compilation.py | 25 +- ptodsl/ptodsl/_native_options.py | 184 +++++++++ ptodsl/ptodsl/_runtime/__init__.py | 3 +- ptodsl/ptodsl/_runtime/launch.py | 33 +- ptodsl/ptodsl/_runtime/native_build.py | 108 +++++- ptodsl/ptodsl/_tracing/module_builder.py | 3 + ptodsl/tests/test_native_build_options.py | 365 ++++++++++++++++++ 9 files changed, 791 insertions(+), 13 deletions(-) create mode 100644 ptodsl/ptodsl/_native_options.py create mode 100644 ptodsl/tests/test_native_build_options.py diff --git a/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md b/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md index fb46df33f5..7ba2daf0a1 100644 --- a/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md +++ b/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md @@ -251,6 +251,72 @@ compiled[grid, stream](A.ctypes.data, O.ctypes.data, 4, 128) **Only `entry=True` kernels support `.compile()` and `[grid, stream]` launch.** Calling `.compile()` on an `entry=False` module raises an error. +### Host C++ in the kernel's library: `native_options` + +PTODSL builds a kernel into a shared library from two inputs it generates itself: +the launch code and the ptoas-produced kernel object. When a kernel's host side +already exists in C++ — a resource setup helper, an ABI the device code shares +with a host header — that closed set leaves only bad options: reimplement the C++ +in Python, or ship it as a second library the caller loads separately and keeps +in step by hand. + +`native_options` opens the build up. It names host C++ sources to compile and +link into the same library: + +```python +@pto.jit( + name="my_kernel", + target="a3", + mode="explicit", + native_options={ + # Compiled as host C++ and linked into this kernel's library. + "host_sources": ["MyHostHelper.cpp"], + # Include directories for those sources. + "include_dirs": [".", "../../include"], + # Extra link inputs; bare library names, as for -l. + "link_libraries": ["dl"], + "library_dirs": ["/opt/mylib/lib"], + }, +) +def my_kernel(buf: pto.ptr(pto.f32, "gm")): + ... +``` + +Then reach the host entry points through the library the build produced: + +```python +compiled = my_kernel.compile() +lib = compiled.native_library() # a ctypes.CDLL +lib.my_host_setup() # a symbol from MyHostHelper.cpp +compiled[grid, stream](buf) +``` + +Rules worth knowing: + +- **Relative paths resolve against the declaring file**, not the working + directory, so a kernel keeps building wherever it is invoked from. This is the + same rule `source=` uses. +- **Host sources are part of the build's identity.** Their contents are digested + into the cache key, so editing one rebuilds the library instead of silently + reusing the old one. +- **Host sources are compiled as host code**, with `-xc++` and no AI-core arch — + not as device code. They cannot contain kernel code. +- **`link_libraries` takes bare names.** Pass `"dl"`, not `"-ldl"` or a path to a + `.so`; directories belong in `library_dirs`, which also become rpath entries so + the library is found again at load time. +- **Undefined symbols remain an error.** The link keeps `-Wl,--no-undefined`, so a + library you forgot to name fails the build rather than the first launch. +- **`include_dirs` requires `host_sources`.** On its own it would apply to + nothing, so it is rejected rather than quietly ignored. +- Unknown keys are rejected when the decorator runs, not at build time. + +`native_library()` and `native_library_path()` are only for reaching host symbols; +launching needs neither. Both build the specialization if it is not built yet, and +both share one loaded library with every launch handle over that specialization. + +For a worked example, see `test/comm/` in the repository: a host helper that owns +an ABI shared with the device code, linked into the kernel that uses it. + ### Loading an existing PTO file Use `source=` when the kernel implementation already exists as hand-written PTO diff --git a/ptodsl/ptodsl/_jit.py b/ptodsl/ptodsl/_jit.py index ec5f4baa8a..4893bfd267 100644 --- a/ptodsl/ptodsl/_jit.py +++ b/ptodsl/ptodsl/_jit.py @@ -21,6 +21,7 @@ ) from ._kernel_compilation import CompiledKernelHandle, KernelCompiler from ._kernel_signature import parse_jit_kernel_signature +from ._native_options import normalize_native_options from ._tracing import ( KernelModuleSpec, ModuleArtifact, @@ -231,6 +232,7 @@ def jit( insert_sync: bool | None = None, ast_rewrite: bool | None = None, frontend_options: Mapping | None = None, + native_options: Mapping | None = None, source: str | None = None, ): """ @@ -258,6 +260,14 @@ def jit( frontend_options: Reserved structured frontend options. Currently supports ``ast_rewrite`` and ``rewrite_part={"control_flow"}``. + native_options: + Host-side additions to the native build, for a kernel whose + host side already exists in C++. Supports ``host_sources`` + (C++ files compiled and linked into the kernel's shared + library), ``include_dirs`` for those sources, and + ``link_libraries`` / ``library_dirs`` for the link. Relative + paths resolve against the declaring file. Host sources are part + of the build's identity, so editing one rebuilds the library. source: Optional filesystem path to a PTO IR source file. When provided, PTODSL keeps the Python signature as the host ABI @@ -298,6 +308,11 @@ def decorator(fn): source_file = inspect.getsourcefile(fn) or inspect.getfile(fn) except (OSError, TypeError): source_file = None + normalized_native_options = normalize_native_options( + native_options, + declaring_file=source_file, + function_name=fn_name, + ) kernel_kind_explicit = kernel_kind is not _DEFAULT_KERNEL_KIND_SENTINEL effective_kernel_kind = kernel_kind if kernel_kind_explicit else _DEFAULT_KERNEL_KIND compiler = KernelCompiler( @@ -315,6 +330,7 @@ def decorator(fn): source_file=source_file, source_line=getattr(fn.__code__, "co_firstlineno", None), jit_source=source, + native_options=normalized_native_options, ), kernel_signature, fn, @@ -374,6 +390,7 @@ def __ptodsl_cache_signature__(self): module_spec.mode, module_spec.kernel_kind, module_spec.kernel_kind_explicit, + module_spec.native_options, ) def _build_default_module(self): diff --git a/ptodsl/ptodsl/_kernel_compilation.py b/ptodsl/ptodsl/_kernel_compilation.py index 60a589534f..c2b5f69dfb 100644 --- a/ptodsl/ptodsl/_kernel_compilation.py +++ b/ptodsl/ptodsl/_kernel_compilation.py @@ -16,7 +16,7 @@ kernel_module_compile_error, kernel_module_launch_error, ) -from ._runtime.launch import LaunchHandle, parse_launch_spec +from ._runtime.launch import LaunchHandle, build_and_load_native_library, parse_launch_spec from ._source_loader import SourceModuleLoader from ._tracing import ModuleArtifact, SignatureTracingRuntime @@ -39,6 +39,9 @@ def __init__( self._constexpr_bindings = dict(constexpr_bindings) self._module_spec = module_spec self._kernel_signature = kernel_signature + # Set on the first native build; shared by every launch handle over this + # specialization and by native_library(). + self._native_library_cache = None @property def specialization_key(self): @@ -57,6 +60,26 @@ def kernel_module_graph(self): """Return traced kernel-module import/dependency metadata for this build.""" return self.build_metadata().get("kernel_module_graph") + def native_library(self): + """Build this specialization if needed and return the loaded shared library. + + Launching does not need this. It is how a caller reaches a symbol that + ``@pto.jit(native_options={"host_sources": ...})`` compiled into the same + library, so host setup a kernel depends on can live in C++ next to the + kernel rather than in a separately built library. + """ + if self._module_spec.entry is False: + raise kernel_module_launch_error(self._py_name) + library, _path, _symbol = build_and_load_native_library(self) + return library + + def native_library_path(self): + """Build this specialization if needed and return its shared library path.""" + if self._module_spec.entry is False: + raise kernel_module_launch_error(self._py_name) + _library, path, _symbol = build_and_load_native_library(self) + return path + def __getitem__(self, launch_spec): if self._module_spec.entry is False: raise kernel_module_launch_error(self._py_name) diff --git a/ptodsl/ptodsl/_native_options.py b/ptodsl/ptodsl/_native_options.py new file mode 100644 index 0000000000..fc9bcc6971 --- /dev/null +++ b/ptodsl/ptodsl/_native_options.py @@ -0,0 +1,184 @@ +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +"""Host-side additions to the native build of one ``@pto.jit`` kernel. + +PTODSL builds a kernel into a shared library by compiling generated launch code +and the ptoas-produced kernel object, then linking the two. That is a closed set, +which is a problem for a kernel whose host side already exists in C++: the only +ways in were to reimplement it in Python or to ship it as a second library the +caller loads separately. + +``native_options`` opens that up. It names host C++ sources to compile and link +into the same library, the include directories they need, and the libraries to +link against. Those sources become part of the build's identity, so editing one +rebuilds the library rather than silently reusing it. + +The public surface is a plain mapping, matching ``frontend_options`` on the same +decorator. It is normalized here into a frozen, hashable record, because +``KernelModuleSpec`` is frozen and the build cache compares these values. +""" + +from __future__ import annotations + +from collections.abc import Mapping +from dataclasses import dataclass +from pathlib import Path + +_SUPPORTED_NATIVE_OPTION_KEYS = frozenset( + {"host_sources", "include_dirs", "link_libraries", "library_dirs"} +) + +# A library name goes onto the link line as -lNAME. Anything that could be read +# as a second argument, a path, or a flag is rejected rather than pasted. +_FORBIDDEN_LIBRARY_CHARS = frozenset({"/", "\\", " ", "\t", "\n", "\r", '"', "'", ";", "&", "|", "$"}) + + +@dataclass(frozen=True) +class NativeBuildOptions: + """Resolved host-side additions to one kernel's native build.""" + + host_sources: tuple[Path, ...] = () + include_dirs: tuple[Path, ...] = () + link_libraries: tuple[str, ...] = () + library_dirs: tuple[Path, ...] = () + + def is_empty(self) -> bool: + return not ( + self.host_sources or self.include_dirs or self.link_libraries or self.library_dirs + ) + + +EMPTY_NATIVE_OPTIONS = NativeBuildOptions() + + +def _require_path_sequence(key: str, value) -> tuple[str, ...]: + """Accept one path or an iterable of paths, and reject anything else clearly.""" + if isinstance(value, (str, Path)): + return (str(value),) + if isinstance(value, (bytes, bytearray)): + raise TypeError(f"@pto.jit native_options[{key!r}] must be str or os.PathLike, not bytes") + try: + items = list(value) + except TypeError as exc: + raise TypeError( + f"@pto.jit native_options[{key!r}] must be a path or an iterable of paths" + ) from exc + resolved = [] + for item in items: + if not isinstance(item, (str, Path)): + raise TypeError( + f"@pto.jit native_options[{key!r}] entries must be str or os.PathLike, " + f"got {type(item).__name__}" + ) + text = str(item) + if not text: + raise ValueError(f"@pto.jit native_options[{key!r}] contains an empty path") + resolved.append(text) + return tuple(resolved) + + +def _resolve_against(base_dir: Path | None, raw: str) -> Path: + """Anchor a relative path at the file that declared the kernel. + + Relative to the declaring module rather than the process working directory, + so a kernel keeps building wherever it is invoked from. This is the rule + ``@pto.jit(source=...)`` already uses for its IR path. + """ + candidate = Path(raw).expanduser() + if candidate.is_absolute() or base_dir is None: + return candidate.resolve() + return (base_dir / candidate).resolve() + + +def _normalize_paths(key: str, value, *, base_dir: Path | None) -> tuple[Path, ...]: + resolved = [] + for raw in _require_path_sequence(key, value): + path = _resolve_against(base_dir, raw) + if path not in resolved: + resolved.append(path) + return tuple(resolved) + + +def _normalize_libraries(value) -> tuple[str, ...]: + names = [] + for raw in _require_path_sequence("link_libraries", value): + # -l takes a bare name; the caller means library_dirs if they have a path. + bad = sorted(_FORBIDDEN_LIBRARY_CHARS.intersection(raw)) + if bad: + raise ValueError( + f"@pto.jit native_options['link_libraries'] entry {raw!r} contains " + f"unsupported characters {bad!r}; pass a bare library name such as 'dl' " + "and put directories in native_options['library_dirs']" + ) + if raw.startswith("-"): + raise ValueError( + f"@pto.jit native_options['link_libraries'] entry {raw!r} looks like a linker " + "flag; pass a bare library name such as 'dl'" + ) + if raw not in names: + names.append(raw) + return tuple(names) + + +def normalize_native_options( + native_options: Mapping | None, + *, + declaring_file: str | None = None, + function_name: str | None = None, +) -> NativeBuildOptions: + """Validate the public mapping and resolve it against the declaring file. + + Paths are resolved but not required to exist: a kernel is often declared + before its host sources are generated, and the build reports a missing source + with the command that needed it. + """ + if native_options is None: + return EMPTY_NATIVE_OPTIONS + if not isinstance(native_options, Mapping): + raise TypeError("@pto.jit native_options must be a mapping when provided") + + unknown = set(native_options) - _SUPPORTED_NATIVE_OPTION_KEYS + if unknown: + raise ValueError( + f"@pto.jit native_options has unsupported keys: {sorted(unknown)!r}; " + f"supported keys are {sorted(_SUPPORTED_NATIVE_OPTION_KEYS)!r}" + ) + + base_dir = Path(declaring_file).resolve().parent if declaring_file else None + + options = NativeBuildOptions( + host_sources=_normalize_paths( + "host_sources", native_options.get("host_sources", ()), base_dir=base_dir + ), + include_dirs=_normalize_paths( + "include_dirs", native_options.get("include_dirs", ()), base_dir=base_dir + ), + link_libraries=_normalize_libraries(native_options.get("link_libraries", ())), + library_dirs=_normalize_paths( + "library_dirs", native_options.get("library_dirs", ()), base_dir=base_dir + ), + ) + + # Include and library directories only mean something for sources being + # compiled or symbols being linked. Accepting them alone would silently do + # nothing, which is worth a diagnostic rather than a quiet no-op. + if options.include_dirs and not options.host_sources: + where = f" for {function_name}" if function_name else "" + raise ValueError( + f"@pto.jit native_options['include_dirs'] was set without 'host_sources'{where}; " + "include directories apply to the host sources this option compiles" + ) + + return options + + +__all__ = [ + "EMPTY_NATIVE_OPTIONS", + "NativeBuildOptions", + "normalize_native_options", +] diff --git a/ptodsl/ptodsl/_runtime/__init__.py b/ptodsl/ptodsl/_runtime/__init__.py index a83ab9eaff..dc87c808eb 100644 --- a/ptodsl/ptodsl/_runtime/__init__.py +++ b/ptodsl/ptodsl/_runtime/__init__.py @@ -7,10 +7,11 @@ # See LICENSE in the root of the software repository for the full text of the License. """Private runtime helpers for ``@pto.jit`` launch.""" -from .launch import LaunchHandle +from .launch import LaunchHandle, build_and_load_native_library from .native_build import build_native_library __all__ = [ "LaunchHandle", + "build_and_load_native_library", "build_native_library", ] diff --git a/ptodsl/ptodsl/_runtime/launch.py b/ptodsl/ptodsl/_runtime/launch.py index d6e5c26402..79fe64a26f 100644 --- a/ptodsl/ptodsl/_runtime/launch.py +++ b/ptodsl/ptodsl/_runtime/launch.py @@ -108,6 +108,29 @@ def _marshal_launch_args(kernel_signature, args): return marshaled +def build_and_load_native_library(compiled: CompiledKernelHandle): + """Build this specialization if needed and return ``(library, path, symbol)``. + + The loaded library is cached on the compiled handle. Several launch handles + over one specialization share it, and so does a caller reaching past the + launch entry for a symbol that ``native_options['host_sources']`` contributed. + """ + cached = getattr(compiled, "_native_library_cache", None) + if cached is not None: + return cached + + lib_path, launch_symbol = build_native_library( + py_name=compiled._py_name, + module_spec=compiled._module_spec, + kernel_signature=compiled._kernel_signature, + mlir_text=compiled.mlir_text(), + specialization_key=compiled.specialization_key, + ) + loaded = (ctypes.CDLL(str(lib_path)), lib_path, launch_symbol) + compiled._native_library_cache = loaded + return loaded + + class LaunchHandle: """Callable launch binding returned by ``compiled[grid, stream]``.""" @@ -124,14 +147,7 @@ def _ensure_launch_fn(self): if self._launch_fn is not None: return - lib_path, launch_symbol = build_native_library( - py_name=self._compiled._py_name, - module_spec=self._compiled._module_spec, - kernel_signature=self._compiled._kernel_signature, - mlir_text=self._compiled.mlir_text(), - specialization_key=self._compiled.specialization_key, - ) - lib = ctypes.CDLL(str(lib_path)) + lib, _lib_path, launch_symbol = build_and_load_native_library(self._compiled) fn = getattr(lib, launch_symbol) fn.argtypes = _launch_argtypes(self._compiled._kernel_signature) fn.restype = None @@ -174,5 +190,6 @@ def parse_launch_spec(launch_spec) -> tuple[int, object]: __all__ = [ "LaunchHandle", + "build_and_load_native_library", "parse_launch_spec", ] diff --git a/ptodsl/ptodsl/_runtime/native_build.py b/ptodsl/ptodsl/_runtime/native_build.py index 9bbe588575..56c4f883c1 100644 --- a/ptodsl/ptodsl/_runtime/native_build.py +++ b/ptodsl/ptodsl/_runtime/native_build.py @@ -20,6 +20,7 @@ is_native_build_current, write_manifest, ) +from .._native_options import EMPTY_NATIVE_OPTIONS, NativeBuildOptions from .codegen import generate_launch_cpp, launch_symbol_name from .toolchain import ( aicore_arch_for_kernel_kind, @@ -86,6 +87,37 @@ def _source_ptoas_overrides(module_spec) -> dict: return {"backend": module_spec.backend} +def _native_options_of(module_spec) -> NativeBuildOptions: + """Read the kernel's host-side build additions, defaulting to none. + + Read defensively because a module spec reaches this layer from several + frontends, and one that predates the option should build as it always did. + """ + return getattr(module_spec, "native_options", None) or EMPTY_NATIVE_OPTIONS + + +def _host_source_config_lines(native_options: NativeBuildOptions) -> list[str]: + """Cache identity for the host sources compiled into the library. + + Both the path and the file's contents, because a host source is an input to + this build like the MLIR is. Digesting the path alone would reuse a library + built from an older version of the same file, which is the failure mode a + caller iterating on a shim would hit first. + + A source that cannot be read yields no digest instead of an error: the build + reports the missing file with the command that needed it, and this function + only decides whether the previous build still counts. + """ + lines = [f"include_dir={path}" for path in native_options.include_dirs] + for source in native_options.host_sources: + try: + digest = _content_digest(source.read_text(encoding="utf-8")) + except OSError: + digest = "unreadable" + lines.append(f"host_source={source}:{digest}") + return lines + + def _compile_config_text( *, module_spec, @@ -102,12 +134,13 @@ def _compile_config_text( f"pto_level={effective_pto_level}", f"backend={ptoas_overrides.get('backend')}", "enable_tile_op_expand=True", + *_host_source_config_lines(_native_options_of(module_spec)), ] ) -def _host_compile_flags() -> list[str]: - return common_include_flags() + [ +def _host_compile_flags(include_dirs: tuple[Path, ...] = ()) -> list[str]: + return common_include_flags() + [f"-I{path}" for path in include_dirs] + [ "-std=gnu++17", "-O2", "-Wno-macro-redefined", @@ -170,12 +203,66 @@ def _compile_launch_cpp( ) +def _host_object_path(cache_dir: Path, index: int, source: Path) -> Path: + """Object path for one extra host source. + + Indexed as well as named, because two sources in different directories may + share a stem and would otherwise overwrite each other's object. + """ + return cache_dir / f"host_{index}_{source.stem}.o" + + +def _compile_host_sources( + native_options: NativeBuildOptions, + cache_dir: Path, +) -> list[Path]: + """Compile each ``native_options['host_sources']`` entry to an object file.""" + if not native_options.host_sources: + return [] + + # Every source is checked before the toolchain is resolved, so a mistyped + # path reports itself rather than whichever environment variable the + # compiler lookup happens to want first. The paths were resolved against the + # declaring file, so naming one in full is the useful part of the message. + missing = [source for source in native_options.host_sources if not source.is_file()] + if missing: + listed = ", ".join(str(path) for path in missing) + raise FileNotFoundError( + f"@pto.jit native_options['host_sources'] does not exist: {listed}" + ) + + bisheng = resolve_bisheng() + flags = _host_compile_flags(native_options.include_dirs) + objects = [] + for index, source in enumerate(native_options.host_sources): + host_object = _host_object_path(cache_dir, index, source) + _run([bisheng, *flags, "-c", str(source), "-o", str(host_object)]) + objects.append(host_object) + return objects + + +def _extra_link_flags(native_options: NativeBuildOptions) -> list[str]: + """Library search paths and library names contributed by ``native_options``. + + Each search path also becomes an rpath entry, matching how the CANN runtime + directories are added: a caller who had to name a directory to link against + needs it found again at load time. + """ + flags: list[str] = [] + for lib_dir in native_options.library_dirs: + flags.extend([f"-L{lib_dir}", f"-Wl,-rpath,{lib_dir}"]) + flags.extend(f"-l{name}" for name in native_options.link_libraries) + return flags + + def _link_shared_library( launch_object: Path, kernel_object: Path, shared_library: Path, *, kernel_kind: str | None, + host_objects: list[Path] | None = None, + extra_link_flags: list[str] | None = None, ) -> None: bisheng = resolve_bisheng() soname = shared_library.name @@ -192,7 +279,13 @@ def _link_shared_library( str(shared_library), str(launch_object), str(kernel_object), + *[str(path) for path in host_objects or []], *runtime_library_flags(sim_mode=sim_mode), + # After the runtime flags, so a host source may depend on a runtime + # symbol. -Wl,--no-undefined is on, so anything still unresolved here + # is a missing entry in native_options rather than a load-time + # surprise. + *(extra_link_flags or []), ] ) @@ -210,8 +303,12 @@ def _native_build_config(module_spec): effective_pto_level=effective_pto_level, ptoas_overrides=ptoas_overrides, ) + native_options = _native_options_of(module_spec) + extra_link_flags = _extra_link_flags(native_options) sim_mode = bool(os.environ.get("MSPROF_SIMULATOR_MODE")) - link_config_text = "\n".join(runtime_library_flags(sim_mode=sim_mode)) + link_config_text = "\n".join( + runtime_library_flags(sim_mode=sim_mode) + extra_link_flags + ) return { "insert_sync": effective_insert_sync, "pto_level": effective_pto_level, @@ -238,11 +335,16 @@ def _compile_native_artifacts(artifacts, module_spec, *, effective_insert_sync, target_arch=module_spec.target_arch, export_macro=f"{module_spec.function_name}_EXPORTS", ) + native_options = _native_options_of(module_spec) + extra_link_flags = _extra_link_flags(native_options) + host_objects = _compile_host_sources(native_options, artifacts.cache_dir) _link_shared_library( launch_object, artifacts.kernel_object, artifacts.shared_library, kernel_kind=module_spec.kernel_kind, + host_objects=host_objects, + extra_link_flags=extra_link_flags, ) diff --git a/ptodsl/ptodsl/_tracing/module_builder.py b/ptodsl/ptodsl/_tracing/module_builder.py index 7d3e851a0c..7e453008d4 100644 --- a/ptodsl/ptodsl/_tracing/module_builder.py +++ b/ptodsl/ptodsl/_tracing/module_builder.py @@ -15,6 +15,8 @@ from ptoas.mlir.dialects import func from ptoas.mlir.ir import Attribute, InsertionPoint, Module, Operation, StringAttr, UnitAttr +from .._native_options import EMPTY_NATIVE_OPTIONS, NativeBuildOptions + class ModuleStyle(str, Enum): """Supported top-level PTODSL module layouts.""" @@ -40,6 +42,7 @@ class KernelModuleSpec: source_file: str | None = None source_line: int | None = None jit_source: str | None = None + native_options: NativeBuildOptions = EMPTY_NATIVE_OPTIONS def _build_flat_aicore_module(spec: KernelModuleSpec, arg_types): diff --git a/ptodsl/tests/test_native_build_options.py b/ptodsl/tests/test_native_build_options.py new file mode 100644 index 0000000000..101a2f8e8e --- /dev/null +++ b/ptodsl/tests/test_native_build_options.py @@ -0,0 +1,365 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +"""``@pto.jit(native_options=...)`` normalization and native-build wiring. + +Everything here runs without a toolchain: the option layer is pure Python, and +the build layer is exercised by capturing the commands it would run. +""" + +import tempfile +import types +import unittest +from pathlib import Path +from unittest import mock + +from ptodsl._native_options import ( + EMPTY_NATIVE_OPTIONS, + NativeBuildOptions, + normalize_native_options, +) +from ptodsl._runtime import native_build + + +class NormalizeNativeOptionsTest(unittest.TestCase): + def test_none_and_empty_mapping_are_empty(self): + self.assertIs(normalize_native_options(None), EMPTY_NATIVE_OPTIONS) + self.assertTrue(normalize_native_options({}).is_empty()) + + def test_relative_paths_resolve_against_the_declaring_file(self): + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir).resolve() + declaring = root / "pkg" / "kernel.py" + declaring.parent.mkdir(parents=True) + declaring.touch() + + options = normalize_native_options( + {"host_sources": ["shim.cpp", "../other/helper.cpp"], "include_dirs": "inc"}, + declaring_file=str(declaring), + ) + + self.assertEqual( + options.host_sources, + (root / "pkg" / "shim.cpp", root / "other" / "helper.cpp"), + ) + self.assertEqual(options.include_dirs, (root / "pkg" / "inc",)) + + def test_absolute_paths_are_kept(self): + with tempfile.TemporaryDirectory() as temp_dir: + absolute = Path(temp_dir).resolve() / "shim.cpp" + options = normalize_native_options( + {"host_sources": [absolute]}, + declaring_file="/somewhere/else/kernel.py", + ) + self.assertEqual(options.host_sources, (absolute,)) + + def test_a_single_path_does_not_have_to_be_wrapped_in_a_list(self): + options = normalize_native_options({"host_sources": "/tmp/shim.cpp"}) + self.assertEqual(options.host_sources, (Path("/tmp/shim.cpp").resolve(),)) + + def test_duplicate_entries_collapse(self): + options = normalize_native_options( + {"host_sources": ["/tmp/a.cpp", "/tmp/a.cpp"], "link_libraries": ["dl", "dl"]} + ) + self.assertEqual(len(options.host_sources), 1) + self.assertEqual(options.link_libraries, ("dl",)) + + def test_options_are_hashable_so_a_kernel_spec_stays_frozen(self): + options = normalize_native_options( + {"host_sources": ["/tmp/a.cpp"], "link_libraries": ["dl"]} + ) + self.assertEqual(hash(options), hash(options)) + self.assertEqual(options, normalize_native_options( + {"host_sources": ["/tmp/a.cpp"], "link_libraries": ["dl"]} + )) + + def test_unknown_keys_are_rejected_and_named(self): + with self.assertRaises(ValueError) as caught: + normalize_native_options({"host_source": ["/tmp/a.cpp"]}) + self.assertIn("host_source", str(caught.exception)) + self.assertIn("host_sources", str(caught.exception)) + + def test_non_mapping_is_rejected(self): + with self.assertRaises(TypeError): + normalize_native_options(["/tmp/a.cpp"]) + + def test_library_names_reject_paths_and_flags(self): + for bad in ("/usr/lib/libdl.so", "-ldl", "dl; rm -rf /", "my lib"): + with self.assertRaises(ValueError, msg=f"{bad!r} should be rejected"): + normalize_native_options({"link_libraries": [bad]}) + + def test_library_dirs_do_not_have_to_accompany_host_sources(self): + # Linking against a prebuilt library needs no source of our own. + options = normalize_native_options( + {"link_libraries": ["dl"], "library_dirs": ["/opt/lib"]} + ) + self.assertEqual(options.link_libraries, ("dl",)) + self.assertEqual(options.library_dirs, (Path("/opt/lib"),)) + + def test_include_dirs_without_host_sources_is_rejected(self): + # They would apply to nothing, so a quiet no-op is worse than an error. + with self.assertRaises(ValueError) as caught: + normalize_native_options({"include_dirs": ["/opt/include"]}, function_name="k") + self.assertIn("host_sources", str(caught.exception)) + + def test_empty_path_is_rejected(self): + with self.assertRaises(ValueError): + normalize_native_options({"host_sources": [""]}) + + def test_wrong_entry_type_is_rejected(self): + with self.assertRaises(TypeError): + normalize_native_options({"host_sources": [123]}) + + +def _module_spec(native_options=EMPTY_NATIVE_OPTIONS): + return types.SimpleNamespace( + function_name="k", + target_arch="a3", + kernel_kind="vector", + mode="explicit", + backend="vpto", + insert_sync=None, + jit_source=None, + native_options=native_options, + ) + + +class HostSourceCacheIdentityTest(unittest.TestCase): + """Editing a host source has to invalidate the cached library.""" + + def _config_text(self, options): + return native_build._compile_config_text( + module_spec=_module_spec(options), + effective_insert_sync=False, + effective_pto_level="level3", + ptoas_overrides={"backend": "vpto"}, + ) + + def test_no_options_leaves_the_config_text_unchanged(self): + text = self._config_text(EMPTY_NATIVE_OPTIONS) + self.assertNotIn("host_source=", text) + self.assertIn("target_arch=a3", text) + + def test_editing_a_host_source_changes_the_config_text(self): + with tempfile.TemporaryDirectory() as temp_dir: + source = Path(temp_dir) / "shim.cpp" + source.write_text("int a() { return 1; }\n", encoding="utf-8") + options = NativeBuildOptions(host_sources=(source,)) + + before = self._config_text(options) + source.write_text("int a() { return 2; }\n", encoding="utf-8") + after = self._config_text(options) + + self.assertIn(str(source), before) + self.assertNotEqual(before, after) + + def test_an_unreadable_host_source_is_recorded_rather_than_raising(self): + options = NativeBuildOptions(host_sources=(Path("/nonexistent/shim.cpp"),)) + self.assertIn("unreadable", self._config_text(options)) + + def test_include_dirs_take_part_in_the_identity(self): + base = NativeBuildOptions(host_sources=(Path("/tmp/a.cpp"),)) + with_inc = NativeBuildOptions( + host_sources=(Path("/tmp/a.cpp"),), include_dirs=(Path("/opt/inc"),) + ) + self.assertNotEqual(self._config_text(base), self._config_text(with_inc)) + + def test_a_module_spec_without_the_option_still_builds(self): + legacy = types.SimpleNamespace( + function_name="k", target_arch="a3", kernel_kind="vector", mode="explicit", + backend="vpto", insert_sync=None, jit_source=None, + ) + self.assertIs(native_build._native_options_of(legacy), EMPTY_NATIVE_OPTIONS) + + +class KernelModuleSpecTest(unittest.TestCase): + def test_the_spec_carries_the_options_and_stays_frozen(self): + from ptodsl._tracing import KernelModuleSpec + + options = NativeBuildOptions(host_sources=(Path("/tmp/a.cpp"),)) + spec = KernelModuleSpec( + function_name="k", target_arch="a3", kernel_kind="vector", native_options=options + ) + self.assertIs(spec.native_options, options) + self.assertIs(native_build._native_options_of(spec), options) + with self.assertRaises(Exception): + spec.native_options = EMPTY_NATIVE_OPTIONS + + def test_a_spec_without_the_option_defaults_to_none_of_it(self): + from ptodsl._tracing import KernelModuleSpec + + spec = KernelModuleSpec(function_name="k", target_arch="a3", kernel_kind="vector") + self.assertTrue(spec.native_options.is_empty()) + + +class JitDecoratorSurfaceTest(unittest.TestCase): + """The decorator kwarg has to reach the spec, and reject bad input early.""" + + SOURCE = ( + 'module attributes {pto.target_arch = "a3"} {\n' + " func.func @native_option_probe(%arg0: !pto.ptr)" + " attributes {pto.kernel} {\n" + " return\n" + " }\n" + "}\n" + ) + + def _kernel(self, native_options): + from ptodsl import pto + + @pto.jit( + name="native_option_probe", + target="a3", + backend="vpto", + mode="explicit", + source=self.SOURCE, + native_options=native_options, + ) + def native_option_probe(buf: pto.ptr(pto.f32, "gm")): + pass + + return native_option_probe + + def test_options_reach_the_cache_signature(self): + kernel = self._kernel({"host_sources": ["shim.cpp"], "link_libraries": ["dl"]}) + options = kernel.__ptodsl_cache_signature__()[9] + self.assertEqual(options.link_libraries, ("dl",)) + self.assertEqual(len(options.host_sources), 1) + # Resolved against this test file, which is what the option promises. + self.assertEqual(options.host_sources[0], Path(__file__).resolve().parent / "shim.cpp") + + def test_omitting_the_option_changes_nothing(self): + kernel = self._kernel(None) + self.assertTrue(kernel.__ptodsl_cache_signature__()[9].is_empty()) + + def test_a_bad_option_is_rejected_at_decoration_time(self): + with self.assertRaises(ValueError): + self._kernel({"host_sourcez": ["shim.cpp"]}) + + +class ExtraLinkFlagsTest(unittest.TestCase): + def test_no_options_contributes_nothing(self): + self.assertEqual(native_build._extra_link_flags(EMPTY_NATIVE_OPTIONS), []) + + def test_library_dirs_become_search_paths_and_rpaths(self): + options = NativeBuildOptions( + link_libraries=("dl", "m"), library_dirs=(Path("/opt/lib"),) + ) + self.assertEqual( + native_build._extra_link_flags(options), + ["-L/opt/lib", "-Wl,-rpath,/opt/lib", "-ldl", "-lm"], + ) + + def test_search_paths_precede_the_libraries_that_need_them(self): + flags = native_build._extra_link_flags( + NativeBuildOptions(link_libraries=("custom",), library_dirs=(Path("/opt/lib"),)) + ) + self.assertLess(flags.index("-L/opt/lib"), flags.index("-lcustom")) + + +class HostSourceCompileTest(unittest.TestCase): + def test_no_host_sources_runs_no_compiler(self): + with mock.patch.object(native_build, "_run") as run: + objects = native_build._compile_host_sources( + EMPTY_NATIVE_OPTIONS, Path("/tmp/cache") + ) + self.assertEqual(objects, []) + run.assert_not_called() + + def test_a_missing_host_source_is_named_before_the_toolchain_is_resolved(self): + # Deliberately without stubbing the toolchain: a mistyped path must report + # itself, not whichever environment variable the compiler lookup wants. + options = NativeBuildOptions(host_sources=(Path("/nonexistent/shim.cpp"),)) + with mock.patch.object(native_build, "_run") as run: + with self.assertRaises(FileNotFoundError) as caught: + native_build._compile_host_sources(options, Path("/tmp/cache")) + self.assertIn("/nonexistent/shim.cpp", str(caught.exception)) + run.assert_not_called() + + def test_each_source_is_compiled_as_host_c_plus_plus_with_its_include_dirs(self): + with tempfile.TemporaryDirectory() as temp_dir: + cache_dir = Path(temp_dir) / "cache" + source = Path(temp_dir) / "shim.cpp" + source.write_text("int a() { return 1; }\n", encoding="utf-8") + options = NativeBuildOptions( + host_sources=(source,), include_dirs=(Path("/opt/inc"),) + ) + + with mock.patch.object(native_build, "resolve_bisheng", return_value="bisheng"): + with mock.patch.object( + native_build, "common_include_flags", return_value=["-I/cann/include"] + ): + with mock.patch.object(native_build, "_run") as run: + objects = native_build._compile_host_sources(options, cache_dir) + + self.assertEqual(run.call_count, 1) + cmd = run.call_args[0][0] + self.assertEqual(cmd[0], "bisheng") + # Host code, not device code: no -xcce and no aicore arch. + self.assertIn("-xc++", cmd) + self.assertNotIn("-xcce", cmd) + self.assertFalse([arg for arg in cmd if arg.startswith("--cce-aicore-arch")]) + self.assertIn("-I/opt/inc", cmd) + self.assertIn("-I/cann/include", cmd) + self.assertIn("-fPIC", cmd) + self.assertEqual(cmd[-4:], ["-c", str(source), "-o", str(objects[0])]) + + def test_sources_sharing_a_stem_get_distinct_objects(self): + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + first = root / "a" / "shim.cpp" + second = root / "b" / "shim.cpp" + for path in (first, second): + path.parent.mkdir(parents=True) + path.write_text("int a() { return 1; }\n", encoding="utf-8") + options = NativeBuildOptions(host_sources=(first, second)) + + with mock.patch.object(native_build, "resolve_bisheng", return_value="bisheng"): + with mock.patch.object(native_build, "common_include_flags", return_value=[]): + with mock.patch.object(native_build, "_run"): + objects = native_build._compile_host_sources(options, root / "cache") + + self.assertEqual(len(set(objects)), 2) + + +class LinkLineTest(unittest.TestCase): + def _link(self, **kwargs): + with mock.patch.object(native_build, "resolve_bisheng", return_value="bisheng"): + with mock.patch.object( + native_build, "runtime_library_flags", return_value=["-lruntime"] + ): + with mock.patch.object(native_build, "_run") as run: + native_build._link_shared_library( + Path("/c/launch.o"), + Path("/c/kernel.o"), + Path("/c/libk.so"), + kernel_kind="vector", + **kwargs, + ) + return run.call_args[0][0] + + def test_without_options_the_link_line_is_unchanged(self): + cmd = self._link() + self.assertEqual(cmd[-3:], ["/c/launch.o", "/c/kernel.o", "-lruntime"]) + + def test_host_objects_are_linked_and_extra_flags_come_last(self): + cmd = self._link( + host_objects=[Path("/c/host_0_shim.o")], + extra_link_flags=["-L/opt/lib", "-ldl"], + ) + self.assertIn("/c/host_0_shim.o", cmd) + # The host object precedes the libraries that resolve its references. + self.assertLess(cmd.index("/c/host_0_shim.o"), cmd.index("-ldl")) + self.assertLess(cmd.index("-lruntime"), cmd.index("-ldl")) + self.assertEqual(cmd[-2:], ["-L/opt/lib", "-ldl"]) + # Undefined symbols stay an error, so a missing entry fails the build. + self.assertIn("-Wl,--no-undefined", cmd) + + +if __name__ == "__main__": + unittest.main() From 4e061f79a11697151e3276505b88f9d1b6f227e1 Mon Sep 17 00:00:00 2001 From: kerwinair Date: Wed, 26 Aug 2026 22:37:22 +0800 Subject: [PATCH 3/7] test(vpto): move async-comm ST cases onto the PTODSL framework Review asked that new ST cases use the PTODSL test framework rather than per-case C++ and shell harnesses. Four directories of kernel.pto, launch.cpp, main.cpp and run.sh become one Python file. Only the A5 {soft_put} form of pto.sdma_gm_gm moves, and that is the whole constraint: it expands to a synchronous GM->UB->GM copy, so the transfer is done when the kernel returns and the result is an ordinary golden comparison. The engine form posts SQEs and rings a doorbell, so its destination is polled rather than read once, which no golden harness expresses. It also only takes effect on A5; a2/a3 ignore the attribute and post SQEs instead, so these cases are A5-only by construction rather than by preference. The four cases share two kernels and differ mostly in the session template the host writes, which is the point: the transfer is described by session data, not by the kernel. Multicore needs more than one block, so golden_output_case gains a grid parameter. The engine path keeps a spike under test/comm/ rather than a case, because what is unproven there is not the transfer but whether an async workspace can attach to the device and context torch_npu set up, whether memory it allocates is addressable by a harness-launched kernel, and whether an engine-filled destination is observable. It stays out of test/vpto/cases/ so the validation runner does not pick up something needing a CANN 9.0 toolkit, and it has no skip path, because a spike that quietly passes when it could not run answers nothing. AsyncWorkspaceShim.cpp is what lets Python drive that without a second copy of the session ABI: every field position and slot width stays in AsyncSessionABI.h, and the shim takes named values and returns an opaque byte image. It rides into the kernel's own library through native_options, so there is one build and one artifact. HcclWindows.h goes away with the C++ cases that were its only caller. The IR shapes these kernels rely on are pinned in a lit case as well, since the Python cases only run where a device or simulator is available. Co-authored-by: Cursor --- test/comm/AsyncWorkspaceShim.cpp | 213 ++++++++++ test/comm/HcclWindows.h | 270 ------------- test/comm/README.md | 154 ++++++++ test/comm/async_workspace.py | 269 +++++++++++++ test/comm/build_async_shim.sh | 59 +++ test/comm/spike_sdma_gm_gm_engine.py | 372 ++++++++++++++++++ test/dsl-st/README.md | 6 + test/dsl-st/common.py | 12 +- .../async_sdma_gm_gm_a5_soft_put_session.pto | 86 ++++ .../async-comm/sdma-gm-gm-local/kernel.pto | 40 -- .../async-comm/sdma-gm-gm-local/launch.cpp | 36 -- .../async-comm/sdma-gm-gm-local/main.cpp | 232 ----------- .../cases/async-comm/sdma-gm-gm-local/run.sh | 133 ------- .../sdma-gm-gm-multicore/kernel.pto | 58 --- .../sdma-gm-gm-multicore/launch.cpp | 36 -- .../async-comm/sdma-gm-gm-multicore/main.cpp | 208 ---------- .../async-comm/sdma-gm-gm-multicore/run.sh | 133 ------- .../async-comm/sdma-gm-gm-peer-get/kernel.pto | 41 -- .../async-comm/sdma-gm-gm-peer-get/launch.cpp | 37 -- .../async-comm/sdma-gm-gm-peer-get/main.cpp | 296 -------------- .../async-comm/sdma-gm-gm-peer-get/run.sh | 140 ------- .../async-comm/sdma-gm-gm-peer-put/kernel.pto | 40 -- .../async-comm/sdma-gm-gm-peer-put/launch.cpp | 36 -- .../async-comm/sdma-gm-gm-peer-put/main.cpp | 270 ------------- .../async-comm/sdma-gm-gm-peer-put/run.sh | 132 ------- test/vpto/cases/async-comm/sdma_gm_gm.py | 261 ++++++++++++ 26 files changed, 1430 insertions(+), 2140 deletions(-) create mode 100644 test/comm/AsyncWorkspaceShim.cpp delete mode 100644 test/comm/HcclWindows.h create mode 100644 test/comm/README.md create mode 100644 test/comm/async_workspace.py create mode 100755 test/comm/build_async_shim.sh create mode 100644 test/comm/spike_sdma_gm_gm_engine.py create mode 100644 test/lit/vpto/async_sdma_gm_gm_a5_soft_put_session.pto delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp delete mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp delete mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp delete mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp delete mode 100644 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp delete mode 100755 test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh create mode 100644 test/vpto/cases/async-comm/sdma_gm_gm.py diff --git a/test/comm/AsyncWorkspaceShim.cpp b/test/comm/AsyncWorkspaceShim.cpp new file mode 100644 index 0000000000..dfe698f8cb --- /dev/null +++ b/test/comm/AsyncWorkspaceShim.cpp @@ -0,0 +1,213 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// A C entry surface over AsyncWorkspace, so a Python test can drive the engine +// path without a second copy of the session ABI. +// +// The point of this file is what it does not expose. Every field position, slot +// width and default in AsyncSessionABI.h stays on this side: a caller asks for a +// session by naming values, never offsets, and gets back an opaque byte image. +// Nothing here hands out a struct layout for a caller to mirror, because a +// mirrored layout is exactly the second list of fields that header exists to +// prevent. +// +// It also stays free of CANN headers. AsyncWorkspace resolves everything by +// dlopen, so this translation unit compiles with a plain host C++ compiler and +// needs only -ldl at link time; the toolkit is required to run, not to build. +// +// One workspace per process, addressed as a singleton. A test process needs one, +// the queue state it wraps is per-device, and a handle would add a parameter to +// every call while buying nothing. Cleanup rides on the static's destructor, so +// a caller that exits without calling finalize still releases the device memory +// and streams. + +#include +#include +#include + +#include "AsyncWorkspace.h" + +namespace { + +using mlir::pto::comm::AsyncWorkspace; +namespace comm = mlir::pto::comm; + +// Function-local rather than a namespace-scope object, so construction order +// across translation units never matters. +AsyncWorkspace &workspace() { + static AsyncWorkspace ws; + return ws; +} + +// Separate from AsyncWorkspace::error() so a shim-level rejection, such as a +// short output buffer, reads back through the same call as a workspace failure. +std::string &lastError() { + static std::string error; + return error; +} + +int fail(const char *what) { + lastError() = what; + return -1; +} + +} // namespace + +extern "C" { + +// --- lifecycle --------------------------------------------------------------- + +// Build the workspace for `channels` channels on the currently selected device. +// Returns 0 on success, -1 with pto_async_ws_error() set otherwise. +// +// The device must already be selected. Under the PTODSL ST harness that is +// torch_npu's doing, which is the arrangement this shim exists to test: the +// workspace has to attach to a device and context someone else set up. +int pto_async_ws_init(unsigned channels) { + lastError().clear(); + if (!workspace().init(channels)) { + lastError() = workspace().error(); + return -1; + } + return 0; +} + +void pto_async_ws_finalize() { + lastError().clear(); + workspace().finalize(); +} + +// Valid until the next call into this shim, which may overwrite the buffer. +// Callers are expected to copy it, as a ctypes c_char_p restype does. +const char *pto_async_ws_error() { + if (!lastError().empty()) { + return lastError().c_str(); + } + return workspace().error().c_str(); +} + +// --- what the kernel needs --------------------------------------------------- + +// SessionField::ContextGm, or 0 before a successful init. +// +// A device address has to cross this boundary as an integer, which is the same +// reason AsyncSessionABI.h carries pointers as i64: the session struct rejects +// pointer fields. It stays opaque either way -- it is produced here, consumed by +// pto_async_session_pack, and never interpreted by the caller. +uint64_t pto_async_ws_context_gm() { + return reinterpret_cast(workspace().contextGm()); +} + +unsigned pto_async_ws_channel_count() { return workspace().channelCount(); } + +// Channels the STARS query reported populating, which bounds what a session may +// index however many channels were asked for. +uint32_t pto_async_ws_reported_queue_num() { + return workspace().reportedQueueNum(); +} + +// --- observation ------------------------------------------------------------- + +// The live queue tail for one channel, or -1 on failure so a caller can tell a +// failed read from a tail that legitimately reads zero. +// +// This is the only way to see that a post happened the way it was asked to. +// Correct data at the destination says the bytes moved; one oversized entry +// moves the same bytes as a correct split, and only the tail separates them. +long long pto_async_ws_sq_tail(unsigned channel_idx, unsigned channel_num) { + static_assert(comm::workspace::kChannelSqTailOffset + sizeof(uint32_t) <= + comm::workspace::kChannelDescBytes, + "the queue tail must lie inside one channel descriptor"); + + lastError().clear(); + uint8_t desc[comm::workspace::kChannelDescBytes]; + if (!workspace().readChannelDescriptor(channel_idx, channel_num, 0, desc)) { + lastError() = workspace().error(); + return -1; + } + uint32_t tail = 0; + std::memcpy(&tail, desc + comm::workspace::kChannelSqTailOffset, + sizeof(tail)); + return static_cast(tail); +} + +// --- session template -------------------------------------------------------- + +// How large a buffer pto_async_session_pack needs. Asked for rather than +// assumed, so the slot width stays a fact of the C++ header. +uint32_t pto_async_session_bytes() { return comm::session_tmpl::kBytes; } + +// Values and limits a caller would otherwise hard-code. +uint32_t pto_async_session_qos_default() { return comm::sqe::kQosDefault; } + +uint32_t pto_async_ws_min_transfer_bytes() { + return comm::workspace::kMinTransferBytes; +} + +uint32_t pto_async_ws_max_channels() { return comm::workspace::kMaxChannels; } + +// Build one session image into `out`, which must hold at least +// pto_async_session_bytes() bytes. Returns 0 on success, -1 otherwise. +// +// Arguments are named values rather than a struct on purpose: a struct would +// have a layout the caller has to agree with, which is the duplication this shim +// avoids. ContextGm comes from the live workspace, and Engine and Flags have +// only one sensible value here, so none of the three is a parameter. +// +// tmp_buf_addr and sync_id matter on A2/A3, where the doorbell is reachable only +// by MTE and the tail therefore goes out through UB. A5 writes it with st_dev +// and reads neither. +int pto_async_session_pack(void *out, uint32_t out_bytes, uint32_t channel_idx, + uint32_t channel_num, uint64_t block_bytes, + uint64_t tmp_buf_addr, uint32_t tmp_buf_size, + uint32_t sync_id, uint64_t comm_block_offset, + uint32_t qos, uint32_t dest_rank_id) { + // The destination bound is checked below; this is the source side. + static_assert(comm::session_tmpl::Builder::bytes() == + comm::session_tmpl::kBytes, + "the builder must hold exactly one session template"); + + lastError().clear(); + if (out == nullptr) { + return fail("session output buffer is null"); + } + if (out_bytes < comm::session_tmpl::kBytes) { + return fail("session output buffer is shorter than the session template"); + } + + // A zero block size would make the engine expansion's trip count degenerate. + // It clamps the value at run time rather than dividing by it, so this is a + // caller error to report here instead of a wrong transfer to discover later. + if (block_bytes == 0) { + return fail("session block_bytes must be non-zero"); + } + if (channel_num == 0) { + return fail("session channel_num must be non-zero"); + } + + comm::session_tmpl::Builder tmpl; + tmpl.set(comm::SessionField::ContextGm, pto_async_ws_context_gm()) + .set(comm::SessionField::TmpBufAddr, tmp_buf_addr) + .set(comm::SessionField::TmpBufSize, tmp_buf_size) + .set(comm::SessionField::SyncId, sync_id) + .set(comm::SessionField::ChannelIdx, channel_idx) + .set(comm::SessionField::ChannelNum, channel_num) + .set(comm::SessionField::BlockBytes, block_bytes) + .set(comm::SessionField::CommBlockOffset, comm_block_offset) + .set(comm::SessionField::Engine, + static_cast(comm::SessionEngine::Sdma)) + .set(comm::SessionField::DestRankId, dest_rank_id) + .set(comm::SessionField::QpIdx, 0) + .set(comm::SessionField::Flags, comm::kSessionFlagValid) + .set(comm::SessionField::Qos, qos); + + std::memcpy(out, tmpl.data(), comm::session_tmpl::kBytes); + return 0; +} + +} // extern "C" diff --git a/test/comm/HcclWindows.h b/test/comm/HcclWindows.h deleted file mode 100644 index 731d181410..0000000000 --- a/test/comm/HcclWindows.h +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -#ifndef PTO_TEST_COMM_HCCLWINDOWS_H -#define PTO_TEST_COMM_HCCLWINDOWS_H - -// Test scaffolding: obtains the peer window table a remote transfer needs. -// -// A cross-device transfer needs an address on the far rank that the local DMA -// engine can resolve. Peer access is not enough -- measured on 910B1, an -// ordinary device pointer from another device is not reachable, and even a -// runtime device-to-device copy over such a pair hangs. The addresses that do -// work come from the communication domain, which is what sets up the -// translation, and HCCL hands them over as a window table. -// -// The route here is the one the reference stack uses: -// -// HcclGetCommName name the group behind an existing comm -// HcomGetL0TopoTypeEx reports the L0 topo; A5 often returns CUSTOM(5) -// rather than 1D mesh. The V2 tiling path still -// fills a CommDeviceContext-shaped window table. -// HcomGetCommHandleByGroup the handle the allocator wants -// HcclAllocComResourceByTiling -// on mesh, returns a device CommDeviceContext -// -// None of those four are declared in a public CANN header, and the tiling -// struct is an internal layout transcribed here, so this is a test aid and not -// something to ship. The supported call for this, HcclSymWinGetPeerPointer, is -// declared in hccl_sym_win.h but exported by no library in CANN 9.0.0; once it -// works, all of this collapses into one call. - -#if defined(__CCE_KT_TEST__) || defined(__CCE__) -#error "HcclWindows.h is a host-only header and cannot be included in device code." -#endif - -#include -#include -#include -#include -#include - -#include - -#include "acl/acl.h" -#include "hccl/hccl.h" -#include "hccl/hccl_types.h" - -namespace mlir::pto::comm { - -//===----------------------------------------------------------------------===// -// HCCL entry points used here but not declared in any public header -//===----------------------------------------------------------------------===// -// -// These live behind libhccl on CANN 9.0.0, but 9.2.0 moved them into a -// dependency that lld will not pull in through -lhccl. Resolve them the same -// way AsyncWorkspace does: look in the already-loaded HCCL stack first, then -// in the libraries that have carried them across releases. - -using HcclAllocComResourceByTilingFn = HcclResult (*)(HcclComm, void *, void *, - void **); -using HcomGetCommHandleByGroupFn = HcclResult (*)(const char *, HcclComm *); -using HcomGetL0TopoTypeExFn = HcclResult (*)(const char *, uint32_t *, - uint32_t); - -namespace hccl_win { - -constexpr uint32_t kTopoMesh = 0b1u; -constexpr uint32_t kIsNotSetDevice = 0; -constexpr uint32_t kMaxRankNum = 64; -constexpr uint32_t kGroupNameSize = 128; -constexpr uint32_t kAlgConfigSize = 128; -constexpr uint32_t kMaxCcTilingNum = 8; - -// Internal HCCL tiling layout. Field order and the constants below are what the -// allocator expects; they come from the reference implementation and are not -// derivable from anything public. -struct Mc2InitTilingInner { - uint32_t version; - uint32_t mc2HcommCnt; - uint32_t offset[kMaxCcTilingNum]; - uint8_t debugMode; - uint8_t preparePosition; - uint16_t queueNum; - uint16_t commBlockNum; - uint8_t devType; - char reserved[17]; -}; - -struct Mc2cCTilingInner { - uint8_t skipLocalRankCopy; - uint8_t skipBufferWindowCopy; - uint8_t stepSize; - uint8_t version; - char reserved[9]; - uint8_t commEngine; - uint8_t srcDataType; - uint8_t dstDataType; - char groupName[kGroupNameSize]; - char algConfig[kAlgConfigSize]; - uint32_t opType; - uint32_t reduceType; -}; - -struct Mc2CommConfigV2 { - Mc2InitTilingInner init; - Mc2cCTilingInner inner; -}; - -inline void fillDefaultTiling(Mc2CommConfigV2 &tiling, const char *groupName) { - std::memset(&tiling, 0, sizeof(tiling)); - tiling.init.version = 100U; - tiling.init.mc2HcommCnt = 1U; - tiling.init.commBlockNum = 48U; - tiling.init.devType = 4U; - tiling.init.offset[0] = - static_cast(offsetof(Mc2CommConfigV2, inner)); - tiling.inner.opType = 18U; - tiling.inner.commEngine = 3U; - tiling.inner.version = 1U; - if (groupName != nullptr) { - std::strncpy(tiling.inner.groupName, groupName, kGroupNameSize - 1); - tiling.inner.groupName[kGroupNameSize - 1] = '\0'; - } - std::strncpy(tiling.inner.algConfig, "BatchWrite=level0:fullmesh", - kAlgConfigSize - 1); - tiling.inner.algConfig[kAlgConfigSize - 1] = '\0'; -} - -} // namespace hccl_win - -//===----------------------------------------------------------------------===// -// Window table -//===----------------------------------------------------------------------===// - -// What the allocator leaves in device memory on a mesh topology. windowsIn[r] -// is this rank's address for rank r's inbound window, which is exactly what a -// remote transfer names as its destination. -struct CommDeviceContext { - uint64_t workSpace; - uint64_t workSpaceSize; - uint32_t rankId; - uint32_t rankNum; - uint64_t winSize; - uint64_t windowsIn[hccl_win::kMaxRankNum]; - uint64_t windowsOut[hccl_win::kMaxRankNum]; -}; - -class HcclWindows { -public: - // Collective across the ranks of `comm`, so every rank has to call it, and in - // a single-process run that means one thread per rank. - bool init(HcclComm comm, void *stream) { - if (!loadSymbols()) - return false; - - char group[hccl_win::kGroupNameSize] = {}; - if (HcclGetCommName(comm, group) != HCCL_SUCCESS) - return fail("HcclGetCommName failed"); - - if (hcomGetL0TopoTypeEx_(group, &topo_, hccl_win::kIsNotSetDevice) != - HCCL_SUCCESS) - return fail("HcomGetL0TopoTypeEx failed"); - - HcclComm handle = nullptr; - if (hcomGetCommHandleByGroup_(group, &handle) != HCCL_SUCCESS || - handle == nullptr) - return fail("HcomGetCommHandleByGroup failed"); - - hccl_win::Mc2CommConfigV2 tiling{}; - hccl_win::fillDefaultTiling(tiling, group); - - void *devCtx = nullptr; - const HcclResult hret = - hcclAllocComResourceByTiling_(handle, stream, &tiling, &devCtx); - if (hret != HCCL_SUCCESS || devCtx == nullptr) - return fail("HcclAllocComResourceByTiling failed: " + - std::to_string(static_cast(hret))); - - if (aclrtMemcpy(&context_, sizeof(context_), devCtx, sizeof(context_), - ACL_MEMCPY_DEVICE_TO_HOST) != ACL_SUCCESS) - return fail("reading the window table back failed"); - - if (context_.rankNum == 0 || context_.rankNum > hccl_win::kMaxRankNum) - return fail("window table reports rankNum " + - std::to_string(context_.rankNum) + " (topo " + - std::to_string(topo_) + ")"); - if (context_.rankId >= context_.rankNum) - return fail("window table reports rankId " + - std::to_string(context_.rankId) + " of " + - std::to_string(context_.rankNum) + " (topo " + - std::to_string(topo_) + ")"); - for (uint32_t r = 0; r < context_.rankNum; ++r) { - if (context_.windowsIn[r] == 0) - return fail("windowsIn[" + std::to_string(r) + "] is empty (topo " + - std::to_string(topo_) + ")"); - } - - deviceContext_ = devCtx; - valid_ = true; - return true; - } - - const CommDeviceContext &context() const { return context_; } - - // Address of rank `rank`'s inbound window, as this rank must name it. - uint64_t window(uint32_t rank) const { - return rank < context_.rankNum ? context_.windowsIn[rank] : 0; - } - - uint64_t windowBytes() const { return context_.winSize; } - uint32_t rankId() const { return context_.rankId; } - uint32_t rankNum() const { return context_.rankNum; } - uint32_t topo() const { return topo_; } - - // Owned by HCCL; nothing to free here. - void *deviceContext() const { return deviceContext_; } - - bool valid() const { return valid_; } - const std::string &error() const { return error_; } - -private: - bool fail(std::string message) { - error_ = std::move(message); - return false; - } - - template - bool bind(Fn &slot, const char *name) { - if (slot) - return true; - slot = reinterpret_cast(dlsym(RTLD_DEFAULT, name)); - if (slot) - return true; - static const char *kLibs[] = {"libhccl.so", "libhcom.so", "libhccl_plf.so", - "libhccl_heterog.so"}; - for (const char *lib : kLibs) { - void *handle = dlopen(lib, RTLD_NOW | RTLD_GLOBAL); - if (!handle) - continue; - slot = reinterpret_cast(dlsym(handle, name)); - if (slot) - return true; - } - return fail(std::string("dlsym ") + name + " failed"); - } - - bool loadSymbols() { - return bind(hcomGetL0TopoTypeEx_, "HcomGetL0TopoTypeEx") && - bind(hcomGetCommHandleByGroup_, "HcomGetCommHandleByGroup") && - bind(hcclAllocComResourceByTiling_, "HcclAllocComResourceByTiling"); - } - - CommDeviceContext context_{}; - void *deviceContext_ = nullptr; - bool valid_ = false; - uint32_t topo_{0}; - std::string error_; - HcomGetL0TopoTypeExFn hcomGetL0TopoTypeEx_{nullptr}; - HcomGetCommHandleByGroupFn hcomGetCommHandleByGroup_{nullptr}; - HcclAllocComResourceByTilingFn hcclAllocComResourceByTiling_{nullptr}; -}; - -} // namespace mlir::pto::comm - -#endif // PTO_TEST_COMM_HCCLWINDOWS_H diff --git a/test/comm/README.md b/test/comm/README.md new file mode 100644 index 0000000000..9fb66dbf60 --- /dev/null +++ b/test/comm/README.md @@ -0,0 +1,154 @@ +# Async communication host helpers + +Host-side support for `pto.sdma_gm_gm` and the session template a kernel loads +with `pto.session_init`. + +| File | Role | +| --- | --- | +| `AsyncWorkspace.h` | Builds the async workspace: streams, the AICPU STARS query, and the channel record table a kernel reads. Resolves every CANN symbol with `dlopen`. | +| `AsyncWorkspaceShim.cpp` | `extern "C"` surface over that header, so Python can drive it without a second copy of the session ABI. | +| `async_workspace.py` | `ctypes` wrapper over the shim. | +| `spike_sdma_gm_gm_engine.py` | The engine-path spike described below. | +| `build_async_shim.sh` | Standalone build of the shim into `build/libpto_async_shim.so`. Not needed by the spike, which gets the shim through the kernel build; useful to check the shim compiles on a machine with no card. | + +## How the shim reaches Python + +The spike does not build or load a separate library. It lists the shim in its +kernel declaration: + +```python +@pto.jit( + name="sdma_gm_gm_engine", + native_options={ + "host_sources": ["AsyncWorkspaceShim.cpp"], + "include_dirs": [".", "../../include"], + "link_libraries": ["dl"], + }, + ... +) +``` + +PTODSL compiles that as host C++ and links it into the kernel's own shared +library, so `compiled.native_library()` hands back one library carrying both the +launch entry and the shim. One build, one artifact, and the shim's contents are +part of the build's cache key — editing it rebuilds rather than silently reusing. +See `ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md`, "Host C++ in the +kernel's library". + +## Why a shim rather than a Python port + +Every session field index, slot width, SQE constant and channel-record offset +lives in `include/PTO/Support/AsyncSessionABI.h`, and the expansion in +`lib/PTO/Transforms/VPTOExpandWrapperOps.cpp` reads them from there. A Python +test that filled a session template by index would be a second, unchecked copy +of that layout, and the header exists specifically to keep there from being two. + +So the shim takes named values and returns an opaque byte image. It asks the C++ +side how large a session template is; it never says. `async_workspace.py` +contains no offsets at all, and adding a session field cannot silently break it. + +The shim needs no CANN headers or libraries to build, because `AsyncWorkspace` +resolves the toolkit at run time through `dlopen`. `-ldl` is the only link +dependency, so it compiles on a machine with no driver and no card. + +## The engine-path spike + +`test/vpto/cases/async-comm/sdma_gm_gm.py` covers the A5 `{soft_put}` form of +`pto.sdma_gm_gm` as an ordinary golden ST case. It can do that because +`{soft_put}` expands to a synchronous GM→UB→GM copy: the transfer is finished +when the kernel returns. + +The engine form is not like that. The kernel writes SQEs, publishes the queue +tail and rings a doorbell; the SDMA engine moves the bytes afterwards. Running it +under the PTODSL ST harness needs three things to be true, and none of them can +be checked without a card: + +1. `AsyncWorkspace` can attach to the device and context `torch_npu` already set + up, rather than needing to own `aclrtSetDevice` itself. +2. Memory the workspace allocates through the runtime is addressable by a kernel + the harness launched, so a raw device address can be handed over inside a + session template. +3. A destination the engine fills can be observed from the harness, which + synchronizes the kernel and knows nothing about the engine. + +`spike_sdma_gm_gm_engine.py` is what answers that. It is deliberately not under +`test/vpto/cases/`: `run_host_vpto_validation.sh` discovers and runs every `.py` +in that tree, and a case needing a hand-built shim and a CANN 9.0 toolkit would +fail the whole validation run everywhere else. It also has no skip path, because +a spike that quietly passes when it could not run answers nothing. + +If all three hold, the engine path needs no change to the ST framework, and the +C++ and shell harness these cases used to require has nothing left to do. If one +fails, the spike reports which. + +### Running it + +Requires CANN ≥ 9.0.0 for `aclnnShmemSdmaStarsQuery`, a real device, and a +`torch_npu` the harness can import. The shim is built as part of the kernel, so +there is no separate build step. + +`PTO_ASYNC_ARCH` has to name the generation of the card, and both are worth +running: the three assumptions above are generation-independent, but the doorbell +is not, so A5 and A2/A3 exercise different final writes. + +```bash +PTO_ASYNC_ARCH=a5 python3 test/comm/spike_sdma_gm_gm_engine.py +PTO_ASYNC_ARCH=a3 python3 test/comm/spike_sdma_gm_gm_engine.py +``` + +Start with A5. It is where `AsyncWorkspace` has already been through a live STARS +query — the 2049-for-2048 ring workaround in `AsyncWorkspace.h` was observed +there on CANN 9.2.0 — and the A2/A3 doorbell path is the one that can take a card +down if the sequence is wrong. + +To check that the shim itself compiles without a card or a kernel: + +```bash +test/comm/build_async_shim.sh +``` + +Useful before touching a card: + +```bash +PTO_ASYNC_ARCH=a5 python3 test/comm/spike_sdma_gm_gm_engine.py --list # case names +PTO_ASYNC_ARCH=a5 python3 test/comm/spike_sdma_gm_gm_engine.py --emit-mlir # the kernel, no device needed +``` + +Knobs: + +| Variable | Default | Meaning | +| --- | --- | --- | +| `PTO_ASYNC_ARCH` | **none, required** | `a2`, `a3` or `a5` — the generation of the card being pointed at. The doorbell is the one part of the post that differs: A2/A3 reaches it only by MTE and stages the tail in UB, A5 writes it with `st_dev` at a different offset. Deliberately not defaulted, because a store aimed at `sq_reg_base` the wrong way can leave an A2/A3 card in an unrecoverable RAS state. `a2` and `a3` generate the same code. | +| `PTO_ASYNC_POLL_TIMEOUT_MS` | `2000` | How long to wait for the engine to drain before calling the destination wrong. | +| `PTO_ASYNC_SHIM` | `test/comm/build/libpto_async_shim.so` | Shim path, for a caller loading a standalone build rather than taking it from a kernel library. | +| `CXX` | `g++` | Host compiler for `build_async_shim.sh`. | + +### What each case separates + +All four run the same kernel and differ only in the session template the host +writes, which is the point: the transfer is described by session data, not by the +kernel. `block_bytes` is what splits one transfer into SQEs, so it decides how +many entries the queue should gain. + +| Case | Transfer | Entries | +| --- | --- | --- | +| `single_entry` | 4096 bytes in 4096-byte blocks | 1 | +| `even_split` | 4096 bytes in 1024-byte blocks | 4 | +| `ragged_tail` | 4096 bytes in 1536-byte blocks | 3, the last one short | +| `comm_block_offset` | 2048 bytes at offset 2048 of an 8 KiB buffer | 1 | + +Each case checks the queue tail as well as the data. Correct bytes at the +destination only say the transfer happened; one oversized entry moves the same +bytes as a correct split, and the tail is what separates them. A correct entry +count with an unfilled destination is reported differently from a wrong entry +count, because the first means the kernel did its part and the engine did not. + +### If the spike passes + +Promoting it is a rename into `test/vpto/cases/async-comm/`; the shim needs no +step in `run_host_vpto_validation.sh`, because the kernel build already carries +it. After that, the two-device window shapes in `test/lit/vpto/async_*.pto` become +the next thing to give a runtime case. That needs `HcclWindows.h`, which went away +with the C++ cases that were its only caller; it comes back through the same shim +pattern and the same `native_options` entry, so nothing here has to change to +accommodate it. diff --git a/test/comm/async_workspace.py b/test/comm/async_workspace.py new file mode 100644 index 0000000000..d211acc18e --- /dev/null +++ b/test/comm/async_workspace.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +"""ctypes access to the AsyncWorkspace shim, for engine-path ST cases. + +This module deliberately contains no session field indices, slot widths, SQE +constants or channel-record offsets. Every one of those stays in +``include/PTO/Support/AsyncSessionABI.h`` and is reached through +``AsyncWorkspaceShim.cpp``, so this file cannot drift from the ABI: it asks the +shim how large a session template is and hands it named values to fill one. +""" + +from __future__ import annotations + +import ctypes +import os +from pathlib import Path + +import numpy as np + +_DEFAULT_LIB_RELPATH = Path("build") / "libpto_async_shim.so" +_LIB_PATH_ENV = "PTO_ASYNC_SHIM" + +# The A2/A3 doorbell stages one 32-bit word in UB before an MTE store carries it +# out. Only the address reaches the expansion today, but reserving a whole +# 32-byte block keeps the staging clear of anything a kernel puts next to it. +DOORBELL_STAGE_BYTES = 32 + + +class AsyncWorkspaceError(RuntimeError): + """A shim call failed, or the shim library could not be loaded.""" + + +def _shim_library_path(explicit: str | os.PathLike[str] | None = None) -> Path: + """Resolve the shim library path from an argument, the environment, or the default.""" + raw = explicit if explicit is not None else os.environ.get(_LIB_PATH_ENV) + if raw: + candidate = Path(raw).expanduser().resolve() + source = f"{_LIB_PATH_ENV}={raw}" if explicit is None else f"library_path={raw}" + else: + candidate = (Path(__file__).resolve().parent / _DEFAULT_LIB_RELPATH).resolve() + source = "default location" + if not candidate.is_file(): + raise AsyncWorkspaceError( + f"AsyncWorkspace shim not found at {candidate} ({source}); " + "build it with test/comm/build_async_shim.sh" + ) + return candidate + + +def _bind_signatures(lib: ctypes.CDLL) -> None: + """Declare every shim entry point, so ctypes never guesses a width.""" + lib.pto_async_ws_init.argtypes = [ctypes.c_uint] + lib.pto_async_ws_init.restype = ctypes.c_int + + lib.pto_async_ws_finalize.argtypes = [] + lib.pto_async_ws_finalize.restype = None + + lib.pto_async_ws_error.argtypes = [] + lib.pto_async_ws_error.restype = ctypes.c_char_p + + lib.pto_async_ws_context_gm.argtypes = [] + lib.pto_async_ws_context_gm.restype = ctypes.c_uint64 + + lib.pto_async_ws_channel_count.argtypes = [] + lib.pto_async_ws_channel_count.restype = ctypes.c_uint + + lib.pto_async_ws_reported_queue_num.argtypes = [] + lib.pto_async_ws_reported_queue_num.restype = ctypes.c_uint32 + + lib.pto_async_ws_sq_tail.argtypes = [ctypes.c_uint, ctypes.c_uint] + lib.pto_async_ws_sq_tail.restype = ctypes.c_longlong + + for getter in ( + lib.pto_async_session_bytes, + lib.pto_async_session_qos_default, + lib.pto_async_ws_min_transfer_bytes, + lib.pto_async_ws_max_channels, + ): + getter.argtypes = [] + getter.restype = ctypes.c_uint32 + + lib.pto_async_session_pack.argtypes = [ + ctypes.c_void_p, # out + ctypes.c_uint32, # out_bytes + ctypes.c_uint32, # channel_idx + ctypes.c_uint32, # channel_num + ctypes.c_uint64, # block_bytes + ctypes.c_uint64, # tmp_buf_addr + ctypes.c_uint32, # tmp_buf_size + ctypes.c_uint32, # sync_id + ctypes.c_uint64, # comm_block_offset + ctypes.c_uint32, # qos + ctypes.c_uint32, # dest_rank_id + ] + lib.pto_async_session_pack.restype = ctypes.c_int + + +class AsyncWorkspace: + """One async workspace on the device the caller has already selected. + + The device must be selected before ``init``. Under the PTODSL ST harness + that is torch_npu's doing, and whether a workspace can attach to a context + someone else created is the assumption these cases exist to check. + + The shim can arrive two ways. Pass ``library`` to use one already loaded, + which is how a kernel that listed the shim in + ``@pto.jit(native_options={"host_sources": ...})`` reaches it: the shim is + inside the kernel's own library, so there is one build and one artifact. + Pass ``library_path``, or neither, to load a standalone build from + ``build_async_shim.sh`` instead, which needs no kernel and so is also how the + shim gets exercised on a machine with no card. + """ + + def __init__( + self, + library_path: str | os.PathLike[str] | None = None, + *, + library: ctypes.CDLL | None = None, + ) -> None: + if library is not None and library_path is not None: + raise AsyncWorkspaceError("pass either library or library_path, not both") + if library is not None: + self._library_path: Path | None = None + self._lib: ctypes.CDLL = library + else: + self._library_path = _shim_library_path(library_path) + self._lib = ctypes.CDLL(str(self._library_path)) + self._channels: int = 0 + self._inited: bool = False + _bind_signatures(self._lib) + + # --- lifecycle ----------------------------------------------------------- + + def init(self, channels: int = 1) -> None: + if channels <= 0: + raise AsyncWorkspaceError(f"channel count must be positive, got {channels}") + limit = self.max_channels + if channels > limit: + raise AsyncWorkspaceError(f"channel count {channels} exceeds the shim limit {limit}") + if self._lib.pto_async_ws_init(ctypes.c_uint(channels)) != 0: + raise AsyncWorkspaceError(f"AsyncWorkspace init failed: {self._error()}") + self._channels = channels + self._inited = True + + def finalize(self) -> None: + if not self._inited: + return + self._lib.pto_async_ws_finalize() + self._channels = 0 + self._inited = False + + def _error(self) -> str: + raw = self._lib.pto_async_ws_error() + if raw is None: + return "no error reported" + return raw.decode("utf-8", errors="replace") + + def _require_inited(self) -> None: + if not self._inited: + raise AsyncWorkspaceError("workspace is not initialized; call init() first") + + # --- properties ---------------------------------------------------------- + + @property + def library_path(self) -> Path | None: + """Where the shim was loaded from, or None when it came in already loaded.""" + return self._library_path + + @property + def context_gm(self) -> int: + """SessionField::ContextGm, opaque here and only ever passed back to the shim.""" + self._require_inited() + return int(self._lib.pto_async_ws_context_gm()) + + @property + def channel_count(self) -> int: + self._require_inited() + return int(self._lib.pto_async_ws_channel_count()) + + @property + def reported_queue_num(self) -> int: + """Channels the STARS query reported populating, which bounds valid channel indices.""" + self._require_inited() + return int(self._lib.pto_async_ws_reported_queue_num()) + + @property + def session_bytes(self) -> int: + return int(self._lib.pto_async_session_bytes()) + + @property + def qos_default(self) -> int: + return int(self._lib.pto_async_session_qos_default()) + + @property + def min_transfer_bytes(self) -> int: + """Shortest transfer the engine accepts, so a block size below it is invalid.""" + return int(self._lib.pto_async_ws_min_transfer_bytes()) + + @property + def max_channels(self) -> int: + return int(self._lib.pto_async_ws_max_channels()) + + # --- observation --------------------------------------------------------- + + def sq_tail(self, channel_idx: int = 0, channel_num: int = 1) -> int: + """The live queue tail for one channel. + + Reading this before and after a launch is what separates "moved the + bytes" from "moved them the way the split implies": one oversized entry + transfers the same bytes as a correct split, and only the tail differs. + """ + self._require_inited() + tail = int(self._lib.pto_async_ws_sq_tail(ctypes.c_uint(channel_idx), ctypes.c_uint(channel_num))) + if tail < 0: + raise AsyncWorkspaceError(f"reading the queue tail failed: {self._error()}") + return tail + + # --- session template ---------------------------------------------------- + + def pack_session( + self, + *, + block_bytes: int, + channel_idx: int = 0, + channel_num: int = 1, + tmp_buf_addr: int = 0, + tmp_buf_size: int = DOORBELL_STAGE_BYTES, + sync_id: int = 0, + comm_block_offset: int = 0, + qos: int | None = None, + dest_rank_id: int = 0, + ) -> np.ndarray: + """Return the session image the kernel loads with ``pto.session_init``. + + The shim fills it, so the field order and slot width never appear here. + ``ContextGm`` is taken from this workspace and is not a parameter. + """ + self._require_inited() + size = self.session_bytes + image = np.zeros(size, dtype=np.uint8) + rc = self._lib.pto_async_session_pack( + image.ctypes.data_as(ctypes.c_void_p), + ctypes.c_uint32(size), + ctypes.c_uint32(channel_idx), + ctypes.c_uint32(channel_num), + ctypes.c_uint64(block_bytes), + ctypes.c_uint64(tmp_buf_addr), + ctypes.c_uint32(tmp_buf_size), + ctypes.c_uint32(sync_id), + ctypes.c_uint64(comm_block_offset), + ctypes.c_uint32(self.qos_default if qos is None else qos), + ctypes.c_uint32(dest_rank_id), + ) + if rc != 0: + raise AsyncWorkspaceError(f"packing the session template failed: {self._error()}") + return image + + +__all__ = [ + "AsyncWorkspace", + "AsyncWorkspaceError", + "DOORBELL_STAGE_BYTES", +] diff --git a/test/comm/build_async_shim.sh b/test/comm/build_async_shim.sh new file mode 100755 index 0000000000..5156506f44 --- /dev/null +++ b/test/comm/build_async_shim.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. +# +# Build the host shim over AsyncWorkspace as a shared library that the PTODSL ST +# harness loads with ctypes. +# +# No CANN headers or libraries are needed to build this: AsyncWorkspace resolves +# every toolkit symbol with dlopen, so the only link dependency is -ldl. The +# toolkit is required to run the result, not to produce it, which means this +# builds on a machine with no driver and no card. +# +# test/comm/build_async_shim.sh [output_dir] +# +# Environment: +# CXX host C++ compiler; defaults to g++ + +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +OUT_DIR="${1:-${SCRIPT_DIR}/build}" +CXX_BIN="${CXX:-g++}" +LIB_NAME="libpto_async_shim.so" + +if ! command -v -- "${CXX_BIN}" >/dev/null 2>&1; then + echo "error: host C++ compiler not found: ${CXX_BIN} (override with CXX=)" >&2 + exit 1 +fi + +mkdir -p "${OUT_DIR}" + +# AsyncSessionABI.h comes from include/, AsyncWorkspace.h from this directory. +cxx_args=( + -std=c++17 + -O2 + -Wall + -Wextra + -fPIC + -shared + "-I${REPO_ROOT}/include" + "-I${SCRIPT_DIR}" + "${SCRIPT_DIR}/AsyncWorkspaceShim.cpp" + -o "${OUT_DIR}/${LIB_NAME}" + -Wl,-z,relro + -Wl,-z,now + -Wl,-z,noexecstack + -ldl +) + +"${CXX_BIN}" "${cxx_args[@]}" + +echo "built ${OUT_DIR}/${LIB_NAME}" diff --git a/test/comm/spike_sdma_gm_gm_engine.py b/test/comm/spike_sdma_gm_gm_engine.py new file mode 100644 index 0000000000..4461de6dbf --- /dev/null +++ b/test/comm/spike_sdma_gm_gm_engine.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +# ---------------------------------------------------------------------------- +# spike: sdma_gm_gm, engine path +# target_ops: pto.session_init, pto.sdma_gm_gm +# scenarios: SDMA engine post, SQE split, ragged tail, session-driven offset +# ---------------------------------------------------------------------------- +# +# The engine form of pto.sdma_gm_gm: the kernel writes SQEs, publishes the queue +# tail and rings a doorbell, and the SDMA engine moves the bytes afterwards. Its +# {soft_put} sibling in sdma_gm_gm.py is a synchronous copy and needs none of +# that, which is why the two are separate files rather than separate cases. +# +# This is a spike, and what it is really checking is not the transfer. The IR is +# pinned in test/lit/vpto and the data path is covered by the {soft_put} cases; +# what is unproven is whether the engine path can run under the PTODSL ST harness +# at all. Three assumptions have to hold together, and none is checkable offline: +# +# 1. AsyncWorkspace can attach to the device and context torch_npu already set +# up, instead of needing to own aclrtSetDevice itself. +# 2. Memory the workspace allocates through the runtime is addressable by a +# kernel this harness launched, so a raw device address can be handed over +# inside a session template. +# 3. A destination the engine fills can be observed from the harness, which +# synchronizes the kernel and knows nothing about the engine. +# +# If all three hold, the engine path needs no framework change and the C++ and +# shell harness these cases used to need has nothing left to do. If one fails, +# this file is where it shows up, and the failure says which. +# +# The host side comes along in the kernel's own shared library. AsyncWorkspaceShim +# is listed in native_options below, so PTODSL compiles and links it beside the +# generated launch code, and this file reaches it through +# compiled.native_library(). One build, one artifact, and the shim is part of the +# build's identity: editing it rebuilds rather than silently reusing. +# +# Requires CANN >= 9.0.0 for the AICPU STARS query and a real device. There is no +# skip path: a spike that quietly passes when it could not run would defeat its +# own purpose. +# +# Which is why it lives here and not under test/vpto/cases/async-comm/ next to its +# {soft_put} sibling. run_host_vpto_validation.sh discovers every .py in that tree +# and runs it, and a case needing a 9.0 toolkit would fail the whole validation +# run on every machine without one. Promoting it once the three assumptions above +# are confirmed is a rename, and that should be a deliberate step rather than +# something a spike does on its way in. Run it directly, naming the generation of +# the card it is pointed at: +# +# PTO_ASYNC_ARCH=a5 python3 test/comm/spike_sdma_gm_gm_engine.py +# PTO_ASYNC_ARCH=a3 python3 test/comm/spike_sdma_gm_gm_engine.py + +from __future__ import annotations + +import os +from pathlib import Path +import sys +import time + +import numpy as np + + +def _bootstrap_paths() -> None: + """Put test/dsl-st and test/comm on sys.path, wherever this file is checked out.""" + here = Path(__file__).resolve() + for candidate in here.parents: + common_dir = candidate / "test" / "dsl-st" + comm_dir = candidate / "test" / "comm" + if (common_dir / "common.py").exists(): + sys.path.insert(0, str(common_dir)) + sys.path.insert(0, str(comm_dir)) + return + raise RuntimeError("Unable to locate test/dsl-st/common.py from spike_sdma_gm_gm_engine.py") + + +_bootstrap_paths() + +from async_workspace import DOORBELL_STAGE_BYTES, AsyncWorkspace +from common import auto_main +from ptodsl import pto + + +SEED = 31 + +# The doorbell is the one part of the post that differs by generation, so the +# arch is a knob rather than a constant. A2/A3 reaches it only by MTE and stages +# the tail in UB; A5 writes it with st_dev, at a different offset. Everything +# else is shared, and the compiler draws no distinction between a2 and a3. +# +# Required rather than defaulted. This is the only thing here that decides which +# card the result may be run on, and getting it wrong is not a benign mistake: on +# A2/A3 a store aimed at sq_reg_base the wrong way faults the vector unit hard +# enough to leave the card in an unrecoverable RAS state. A card that has to be +# reset because a variable was unset is worth one line of typing. +_SUPPORTED_ARCHES = ("a2", "a3", "a5") +ARCH = os.environ.get("PTO_ASYNC_ARCH") +if ARCH is None: + raise RuntimeError( + "PTO_ASYNC_ARCH must name the generation of the card this will run on, one of " + f"{_SUPPORTED_ARCHES}. There is no default: the doorbell sequence differs " + "between A2/A3 and A5, and posting the wrong one at a card can leave it in " + "an unrecoverable state." + ) +if ARCH not in _SUPPORTED_ARCHES: + raise RuntimeError(f"PTO_ASYNC_ARCH must be one of {_SUPPORTED_ARCHES}, got {ARCH!r}") + +# How long to wait for the engine to drain. The harness synchronizes the kernel, +# which returns once the doorbell is rung, so the destination is still being +# written when the check starts. +POLL_TIMEOUT_MS = int(os.environ.get("PTO_ASYNC_POLL_TIMEOUT_MS", "2000")) +POLL_INTERVAL_S = 0.001 + +# One channel, index zero. A group wide enough to spread a post across is a +# scheduling policy the expansion does not implement yet, and the tail read has +# to name the same geometry the session did. +CHANNEL_IDX = 0 +CHANNEL_NUM = 1 + +# UB base for the A2/A3 doorbell staging. UB is private to a core and these +# kernels touch nothing else in it, so the bottom of the buffer is free. +UB_STAGE_ADDR = 0 + +# Pipe event id for that staging, chosen so it cannot collide: these kernels +# raise no other MTE3 event. +DOORBELL_SYNC_ID = 0 + +_SESSION_TYPE = "!pto.struct" + +# The destination is the last pointer so the harness allocates it as the output +# buffer. Copy direction is still dst <- src. +ENGINE_SOURCE = f"""module attributes {{pto.target_arch = "{ARCH}", pto.kernel_kind = #pto.kernel_kind}} {{ + func.func @sdma_gm_gm_engine( + %src: !pto.ptr, %sess_gm: !pto.ptr, + %dst: !pto.ptr, %nbytes: i64) attributes {{pto.kernel}} {{ + %sess = pto.declare_struct -> {_SESSION_TYPE} + pto.session_init %sess, %sess_gm + : {_SESSION_TYPE}, !pto.ptr + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) + : !pto.ptr, !pto.ptr, i64, {_SESSION_TYPE} + return + }} +}} +""" + + +@pto.jit( + name="sdma_gm_gm_engine", + target=ARCH, + backend="vpto", + mode="explicit", + source=ENGINE_SOURCE, + native_options={ + # Paths resolve against this file. AsyncWorkspace.h sits beside the shim; + # AsyncSessionABI.h, which owns every field position the shim uses, comes + # from the repository include tree. + "host_sources": ["AsyncWorkspaceShim.cpp"], + "include_dirs": [".", "../../include"], + # AsyncWorkspace resolves the CANN runtime with dlopen rather than linking + # it, so this is the shim's only link dependency. + "link_libraries": ["dl"], + }, +) +def sdma_gm_gm_engine( + src: pto.ptr(pto.i8, "gm"), + sess_gm: pto.ptr(pto.i8, "gm"), + dst: pto.ptr(pto.i8, "gm"), + nbytes: pto.i64, +): + pass + + +_workspace: AsyncWorkspace | None = None + + +def workspace() -> AsyncWorkspace: + """The process-wide workspace, built on first use. + + Built lazily rather than at import: --list and --emit-mlir run before the + harness selects a device, and neither should need a card. + + Compiling here is what makes the shim reachable, since it lives in the + library this call produces. The harness compiles the same kernel again before + it launches; that hits the specialization cache and returns this same handle, + so the library is built once. + """ + global _workspace + if _workspace is None: + compiled = sdma_gm_gm_engine.compile() + ws = AsyncWorkspace(library=compiled.native_library()) + ws.init(channels=CHANNEL_NUM) + reported = ws.reported_queue_num + if reported <= CHANNEL_IDX: + raise RuntimeError( + f"the STARS query reported {reported} populated channels, " + f"which does not cover channel {CHANNEL_IDX}" + ) + print( + f"async workspace ready: arch={ARCH} " + f"library={compiled.native_library_path()} " + f"channels={ws.channel_count} reported={reported}" + ) + _workspace = ws + return _workspace + + +def make_source(nbytes: int) -> np.ndarray: + rng = np.random.default_rng(SEED) + return rng.integers(0, 256, size=nbytes, dtype=np.uint8) + + +def _tail_delta(before: int, after: int) -> int: + """SQEs posted between two tail reads. + + The expansion masks the tail into the ring on every entry, so a delta is only + a count while the ring did not wrap. These cases post single digits into a + ring thousands of entries deep, so a wrap here means something else is wrong + and is worth reporting rather than folding away. + """ + if after < before: + raise AssertionError( + f"the queue tail moved backwards, from {before} to {after}; " + "the ring wrapped or another writer is sharing the channel" + ) + return after - before + + +def _poll_for_match(device_output, golden: np.ndarray) -> tuple[np.ndarray, float]: + """Read the destination back until it matches the golden or the deadline passes.""" + started = time.monotonic() + deadline = started + POLL_TIMEOUT_MS / 1000.0 + actual = device_output.cpu().numpy() + while not np.array_equal(actual, golden): + if time.monotonic() >= deadline: + break + time.sleep(POLL_INTERVAL_S) + actual = device_output.cpu().numpy() + return actual, time.monotonic() - started + + +def engine_case( + name: str, + *, + buffer_bytes: int, + nbytes: int, + block_bytes: int, + comm_block_offset: int = 0, +): + """One engine transfer, described by the session the host writes for it. + + ``block_bytes`` is what splits the transfer into SQEs, so it is the knob that + decides how many entries the queue should gain. ``comm_block_offset`` shifts + both endpoints, so the moved window keeps its position in the buffer. + """ + if comm_block_offset + nbytes > buffer_bytes: + raise RuntimeError( + f"case {name!r} would move past the end of the buffer: " + f"{comm_block_offset} + {nbytes} > {buffer_bytes}" + ) + want_entries = -(-nbytes // block_bytes) + tail_chunk = nbytes - (want_entries - 1) * block_bytes + + def make_case(): + ws = workspace() + floor = ws.min_transfer_bytes + # Both the full block and the short last one become an engine transfer, + # so either being under the floor is a broken case rather than a finding. + if block_bytes < floor or tail_chunk < floor: + raise RuntimeError( + f"case {name!r} splits into chunks of {block_bytes} and {tail_chunk} bytes, " + f"below the {floor}-byte engine minimum" + ) + + src = make_source(buffer_bytes) + session = ws.pack_session( + block_bytes=block_bytes, + channel_idx=CHANNEL_IDX, + channel_num=CHANNEL_NUM, + tmp_buf_addr=UB_STAGE_ADDR, + tmp_buf_size=DOORBELL_STAGE_BYTES, + sync_id=DOORBELL_SYNC_ID, + comm_block_offset=comm_block_offset, + ) + + # Everything outside the moved window stays zero. A session read that + # dropped CommBlockOffset would copy from the base and shift the window, + # which shows up here rather than as a byte count that still adds up. + golden = np.zeros(buffer_bytes, dtype=np.uint8) + window = slice(comm_block_offset, comm_block_offset + nbytes) + golden[window] = src[window] + + out = np.zeros(buffer_bytes, dtype=np.uint8) + expected = { + "golden": golden, + "tail_before": ws.sq_tail(CHANNEL_IDX, CHANNEL_NUM), + } + return [src, session, out], expected, [nbytes] + + def check_case(device_inputs, expected): + actual, waited_s = _poll_for_match(device_inputs[-1], expected["golden"]) + entries = _tail_delta( + expected["tail_before"], workspace().sq_tail(CHANNEL_IDX, CHANNEL_NUM) + ) + matched = np.array_equal(actual, expected["golden"]) + + # Report the post before the data. A correct entry count with an unfilled + # destination means the kernel did its part and the engine did not, which + # is a different failure from an entry count that never matched. + if entries != want_entries: + raise AssertionError( + f"{name}: expected {want_entries} SQEs for {nbytes} bytes in " + f"{block_bytes}-byte blocks, the queue tail gained {entries}" + + ("" if matched else "; the destination did not match either") + ) + if not matched: + differing = int(np.count_nonzero(actual != expected["golden"])) + first = int(np.flatnonzero(actual != expected["golden"])[0]) + raise AssertionError( + f"{name}: {want_entries} SQEs were posted, but after {waited_s * 1000:.0f}ms " + f"{differing} of {actual.size} bytes still differ, first at byte {first}" + ) + + return { + "name": name, + "kernel": sdma_gm_gm_engine, + "make_case": make_case, + "check": check_case, + } + + +CASES = [ + # One SQE. The shortest post that exercises the record read, the SQE write, + # the tail publish and the doorbell together. + engine_case( + "sdma_gm_gm_engine_single_entry", + buffer_bytes=4096, + nbytes=4096, + block_bytes=4096, + ), + # An even split, so the loop runs more than once and every entry is full. + engine_case( + "sdma_gm_gm_engine_even_split", + buffer_bytes=4096, + nbytes=4096, + block_bytes=1024, + ), + # A block size that does not divide the transfer: two full entries and a + # short one. The tail entry has to carry what is left rather than a full + # block, which would run past the end of the buffer. + engine_case( + "sdma_gm_gm_engine_ragged_tail", + buffer_bytes=4096, + nbytes=4096, + block_bytes=1536, + ), + # The session, not the kernel, decides where the transfer lands. + engine_case( + "sdma_gm_gm_engine_comm_block_offset", + buffer_bytes=8192, + nbytes=2048, + block_bytes=2048, + comm_block_offset=2048, + ), +] + + +auto_main(globals()) diff --git a/test/dsl-st/README.md b/test/dsl-st/README.md index 442ba361d0..63e11f998c 100644 --- a/test/dsl-st/README.md +++ b/test/dsl-st/README.md @@ -130,6 +130,10 @@ auto_main(globals()) - 如果输出 dtype 需要和 golden 分开控制,可以显式指定 - `output_index` - 默认比较最后一个 tensor;如果不是最后一个,改这里 +- `grid` + - launch 的 block 数,默认 `1` + - 只有真的要覆盖多核行为(例如 kernel 里用 `pto.get_block_idx` 分片)才需要改 + - 此时 golden 要按“所有 block 合起来的结果”来写 - `rtol` / `atol` - 浮点结果建议显式写;位级结果一般用 `0.0` @@ -149,6 +153,8 @@ auto_main(globals()) - `make_case()` - `check(device_inputs, expected)` +自定义 case dict 里同样可以带 `"grid"`;不写就是 `1`。 + ## 当前参考用例 可以直接参考: diff --git a/test/dsl-st/common.py b/test/dsl-st/common.py index 422d8a9830..b4d0a96ff9 100644 --- a/test/dsl-st/common.py +++ b/test/dsl-st/common.py @@ -67,6 +67,7 @@ def golden_output_case( output_dtype=None, output_index: int = -1, launch_args=None, + grid: int = 1, rtol: float = 1e-5, atol: float = 1e-5, ): @@ -99,6 +100,7 @@ def check_case(device_inputs, golden): return { "name": name, "kernel": kernel, + "grid": grid, "make_case": make_case, "check": check_case, } @@ -190,6 +192,12 @@ def run_cases(cases: list[dict], *, emit_mlir_fn=None, argv=None) -> int: f"DSL ST case {name!r} make_case() must return 2 or 3 values, got {len(made_case)}" ) + grid = case.get("grid", 1) + if not isinstance(grid, int) or grid <= 0: + raise RuntimeError( + f"DSL ST case {name!r} grid must be a positive integer, got {grid!r}" + ) + device_inputs = [torch.from_numpy(array).to(_DEVICE) for array in inputs] stream = npu_stream(torch) @@ -198,12 +206,12 @@ def run_cases(cases: list[dict], *, emit_mlir_fn=None, argv=None) -> int: compile_s = time.perf_counter() - t0 t0 = time.perf_counter() - compiled[1, stream](*device_inputs, *launch_args) + compiled[grid, stream](*device_inputs, *launch_args) torch.npu.synchronize() launch_s = time.perf_counter() - t0 case["check"](device_inputs, expected) - print(f"PASS {name} compile={compile_s:.3f}s launch={launch_s:.3f}s") + print(f"PASS {name} grid={grid} compile={compile_s:.3f}s launch={launch_s:.3f}s") print("All cases passed.") return 0 diff --git a/test/lit/vpto/async_sdma_gm_gm_a5_soft_put_session.pto b/test/lit/vpto/async_sdma_gm_gm_a5_soft_put_session.pto new file mode 100644 index 0000000000..de569a9700 --- /dev/null +++ b/test/lit/vpto/async_sdma_gm_gm_a5_soft_put_session.pto @@ -0,0 +1,86 @@ +// Copyright (c) 2026 Huawei Technologies Co., Ltd. +// This program is free software, you can redistribute it and/or modify it under the terms and conditions of +// CANN Open Software License Agreement Version 2.0 (the "License"). +// Please refer to the License for details. You may not use this file except in compliance with the License. +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// See LICENSE in the root of the software repository for the full text of the License. + +// RUN: ptoas --pto-arch=a5 --pto-backend=vpto --emit-vpto --mlir-print-ir-after=vpto-expand-wrapper-ops %s -o /dev/null 2>&1 | FileCheck %s + +// The two kernel shapes the PTODSL ST case ships +// (test/vpto/cases/async-comm/sdma_gm_gm.py). That case only runs where a +// device or simulator is available, so the shapes are pinned here as well. +// +// Both take their session from a host template instead of spelling the fields +// out, which the existing A5 {soft_put} coverage does not: async_session_init +// pairs pto.session_init with the A2/A3 engine path, and +// async_sdma_gm_gm_a5_soft_put builds its session by hand. + +module attributes {"pto.target_arch" = "a5", pto.kernel_kind = #pto.kernel_kind} { + func.func @soft_put_from_template(%src: !pto.ptr, + %sess_gm: !pto.ptr, + %dst: !pto.ptr, + %nbytes: i64) attributes {pto.kernel} { + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } + + // Per-core slicing through the session rather than the pointers: every core + // loads the same template and then retunes CommBlockOffset, which the + // expansion applies to both endpoints. + func.func @soft_put_per_core_offset(%src: !pto.ptr, + %sess_gm: !pto.ptr, + %dst: !pto.ptr, + %chunk: i64) attributes {pto.kernel} { + %sess = pto.declare_struct + -> !pto.struct + + pto.session_init %sess, %sess_gm + : !pto.struct, + !pto.ptr + + %bid = pto.get_block_idx + %off = arith.muli %bid, %chunk : i64 + pto.struct_set %sess[7], %off + : !pto.struct, i64 + + pto.sdma_gm_gm %dst, %src, %chunk session(%sess) {soft_put} + : !pto.ptr, !pto.ptr, i64, + !pto.struct + + return + } +} + +// The template load survives as one ld_dev per field, and the transfer becomes +// the GM->UB->GM copy. No doorbell is written, because nothing was posted. +// CHECK-LABEL: func.func @soft_put_from_template( +// CHECK-NOT: pto.session_init +// CHECK: pto.ld_dev +// CHECK: pto.struct_set %{{.*}}[0] +// CHECK-NOT: pto.sdma_gm_gm +// CHECK: pto.copy_gm_to_ubuf +// CHECK: pto.copy_ubuf_to_gm +// CHECK-NOT: pto.st_dev + +// The retuned offset is what the expansion reads back, so the block query has +// to reach field 7 before the copy is formed. +// CHECK-LABEL: func.func @soft_put_per_core_offset( +// CHECK: pto.get_block_idx +// CHECK: pto.struct_set %{{.*}}[7] +// CHECK: pto.struct_get %{{.*}}[7] +// CHECK-NOT: pto.sdma_gm_gm +// CHECK: pto.copy_gm_to_ubuf +// CHECK: pto.copy_ubuf_to_gm +// CHECK-NOT: pto.st_dev diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto deleted file mode 100644 index 312df29eac..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-local/kernel.pto +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-local -// target_ops: pto.sdma_gm_gm, pto.session_init -// scenarios: single-device, local GM->GM, one channel, block splitting -// ----------------------------------------------------------------------------- -// -// One core copies between two local GM buffers. The host polls the destination, -// because returning from the kernel does not mean the engine has drained. -// -// Every session value comes from the template the host wrote, including the -// block size, so the kernel says nothing about how the transfer is split. That -// is what lets the host sweep splits without rebuilding this. - -module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { - func.func @sdma_gm_gm_local(%dst: !pto.ptr, - %src: !pto.ptr, - %sess_gm: !pto.ptr, - %nbytes: i64) attributes {pto.kernel} { - %sess = pto.declare_struct - -> !pto.struct - - pto.session_init %sess, %sess_gm - : !pto.struct, - !pto.ptr - - pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) - : !pto.ptr, !pto.ptr, i64, - !pto.struct - - return - } -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp deleted file mode 100644 index a89c562b77..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-local/launch.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-local -// target_ops: pto.sdma_gm_gm -// scenarios: single-device, local GM->GM, one channel, one block -// ----------------------------------------------------------------------------- -#ifndef __VEC_SCOPE__ -#define __VEC_SCOPE__ -#endif - -#include - -#ifndef __CPU_SIM -#include "acl/acl.h" -#endif - -extern "C" __global__ [aicore] void sdma_gm_gm_local(__gm__ int8_t *dst, - __gm__ int8_t *src, - __gm__ int8_t *sessionGm, - int64_t nbytes); - -// A single block: the session owns one channel group, and a second core would -// race it on the same queue ring. -void LaunchSdmaGmGmLocal(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream) { - sdma_gm_gm_local<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, - (__gm__ int8_t *)src, - (__gm__ int8_t *)sessionGm, nbytes); -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp deleted file mode 100644 index dc0fd6bf26..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-local/main.cpp +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-local -// target_ops: pto.sdma_gm_gm -// scenarios: single-device, local GM->GM, one channel, block splitting -// ----------------------------------------------------------------------------- -// -// The kernel returning only means the doorbell was written; the engine drains -// the queue on its own schedule. So the destination is polled rather than read -// once, and the queue tail is reported either way: a tail that advanced with a -// destination that never changed points at the engine, while a tail that -// stayed at zero points at the post itself. -// -// The same transfer is repeated at several block sizes. Correct data alone -// would not show that splitting happened, since one oversized entry moves the -// same bytes, so each round also checks that the tail advanced by exactly the -// number of entries the split implies. The sizes cover the divisible case, a -// case where the last entry is short, and one small enough to fill a good part -// of the ring. - -#include -#include -#include -#include -#include -#include -#include - -#include "acl/acl.h" - -#include "AsyncWorkspace.h" - -using mlir::pto::comm::AsyncWorkspace; -namespace workspace = mlir::pto::comm::workspace; - -void LaunchSdmaGmGmLocal(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream); - -namespace { - -constexpr size_t kTransferBytes = 4096; -constexpr int kPollTimeoutMs = 2000; -constexpr unsigned kChannels = 1; - -// Every size is a multiple of 64, the smallest transfer the engine accepts. -const size_t kBlockSizes[] = {4096, 1024, 1536, 128}; - -#define ACL_CHECK(expr) \ - do { \ - const aclError _ret = (expr); \ - if (_ret != ACL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - const char *_recent = aclGetRecentErrMsg(); \ - if (_recent != nullptr && _recent[0] != '\0') \ - std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ - return 1; \ - } \ - } while (0) - -uint32_t readSqTail(AsyncWorkspace &ws) { - uint8_t raw[workspace::kChannelDescBytes]; - if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) - return 0xFFFFFFFFU; - uint32_t tail; - std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); - return tail; -} - -} // namespace - -int main(int argc, char **argv) { - const int deviceId = - argc > 1 ? std::atoi(argv[1]) - : (std::getenv("ACL_DEVICE_ID") - ? std::atoi(std::getenv("ACL_DEVICE_ID")) - : 0); - - ACL_CHECK(aclInit(nullptr)); - ACL_CHECK(aclrtSetDevice(deviceId)); - - aclrtStream stream = nullptr; - ACL_CHECK(aclrtCreateStream(&stream)); - - AsyncWorkspace ws; - if (!ws.init(kChannels)) { - std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", - ws.error().c_str()); - return 1; - } - std::printf("workspace %p, sq_tail before post = %u\n", ws.contextGm(), - readSqTail(ws)); - - // What the kernel will read for channel 0. Printing it here separates a bad - // table from a bad read of a good one, which are the two ways a post can go - // wrong before the engine is ever involved. - { - uint8_t rec[mlir::pto::comm::channel::kRecordBytes]; - if (ws.readChannelRecord(0, rec)) { - namespace ch = mlir::pto::comm::channel; - uint64_t sqBase, doorbell, tailAddr, headAddr; - uint32_t slotMask, streamId; - std::memcpy(&sqBase, rec + ch::kSqBaseOffset, sizeof(sqBase)); - std::memcpy(&doorbell, rec + ch::kDoorbellOffset, sizeof(doorbell)); - std::memcpy(&tailAddr, rec + ch::kTailAddrOffset, sizeof(tailAddr)); - std::memcpy(&headAddr, rec + ch::kHeadAddrOffset, sizeof(headAddr)); - std::memcpy(&slotMask, rec + ch::kSlotMaskOffset, sizeof(slotMask)); - std::memcpy(&streamId, rec + ch::kStreamIdOffset, sizeof(streamId)); - std::printf("record 0: sq_base=%#" PRIx64 " doorbell=%#" PRIx64 - " tail@%#" PRIx64 " head@%#" PRIx64 " slot_mask=%u" - " stream=%u\n", - sqBase, doorbell, tailAddr, headAddr, slotMask, streamId); - } - } - - std::vector pattern(kTransferBytes); - for (size_t i = 0; i < kTransferBytes; ++i) - pattern[i] = static_cast((i * 31 + 7) & 0xFF); - - void *srcDevice = nullptr; - void *dstDevice = nullptr; - ACL_CHECK(aclrtMalloc(&srcDevice, kTransferBytes, ACL_MEM_MALLOC_HUGE_FIRST)); - ACL_CHECK(aclrtMalloc(&dstDevice, kTransferBytes, ACL_MEM_MALLOC_HUGE_FIRST)); - ACL_CHECK(aclrtMemcpy(srcDevice, kTransferBytes, pattern.data(), - kTransferBytes, ACL_MEMCPY_HOST_TO_DEVICE)); - - // The session the kernel will copy in. Everything the kernel knows about the - // transfer beyond its size comes from here, so a different split is a - // different template rather than a different kernel. - namespace comm = mlir::pto::comm; - void *sessionDevice = nullptr; - ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, - ACL_MEM_MALLOC_HUGE_FIRST)); - - std::printf("posting %zu bytes: src=%p dst=%p session=%p\n", kTransferBytes, - srcDevice, dstDevice, sessionDevice); - - int rc = 0; - std::vector readback(kTransferBytes); - - for (size_t i = 0; i < sizeof(kBlockSizes) / sizeof(kBlockSizes[0]); ++i) { - const size_t block = kBlockSizes[i]; - const uint32_t wantEntries = - static_cast((kTransferBytes + block - 1) / block); - - comm::session_tmpl::Builder tmpl; - tmpl.set(comm::SessionField::ContextGm, - reinterpret_cast(ws.contextGm())) - .set(comm::SessionField::ChannelIdx, 0) - .set(comm::SessionField::ChannelNum, 1) - .set(comm::SessionField::BlockBytes, block) - .set(comm::SessionField::Engine, - static_cast(comm::SessionEngine::Sdma)) - .set(comm::SessionField::Flags, comm::kSessionFlagValid) - .set(comm::SessionField::Qos, comm::sqe::kQosDefault); - ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, - tmpl.data(), comm::session_tmpl::kBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - - ACL_CHECK(aclrtMemset(dstDevice, kTransferBytes, 0, kTransferBytes)); - const uint32_t tailBefore = readSqTail(ws); - - LaunchSdmaGmGmLocal(static_cast(dstDevice), - static_cast(srcDevice), - static_cast(sessionDevice), - static_cast(kTransferBytes), stream); - ACL_CHECK(aclrtSynchronizeStream(stream)); - - bool matched = false; - int elapsedMs = 0; - const auto start = std::chrono::steady_clock::now(); - while (elapsedMs < kPollTimeoutMs) { - ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, dstDevice, - kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); - if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { - matched = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - elapsedMs = static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count()); - } - - // The tail is what separates "moved the bytes" from "moved them the way it - // was asked to": the same data arrives either way, but only a real split - // leaves this many entries behind. - const uint32_t tailAfter = readSqTail(ws); - const uint32_t posted = tailAfter - tailBefore; - const bool ok = matched && posted == wantEntries; - - std::printf("block %5zu -> %u entries (want %u), data %s %s\n", block, - posted, wantEntries, matched ? "match" : "MISMATCH", - ok ? "OK" : "FAIL"); - std::fflush(stdout); - - if (!ok) { - if (!matched) { - size_t changed = 0; - for (size_t b = 0; b < kTransferBytes; ++b) - if (readback[b] != 0) - ++changed; - std::fprintf(stderr, - " destination did not match within %d ms " - "(%zu of %zu bytes non-zero)\n", - kPollTimeoutMs, changed, kTransferBytes); - } - rc = 1; - break; - } - } - - if (rc == 0) - std::printf("PASS: every split posted the entries it implies\n"); - - aclrtFree(srcDevice); - aclrtFree(dstDevice); - aclrtFree(sessionDevice); - ws.finalize(); - aclrtDestroyStream(stream); - aclrtResetDevice(deviceId); - aclFinalize(); - return rc; -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh deleted file mode 100755 index b2711d9569..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-local/run.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/bash -# Build and run the local GM->GM SDMA case. -# -# This does not go through run_host_vpto_validation.sh because that script -# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because -# the host program needs the PTOAS include path for AsyncWorkspace.h. -# -# Requires CANN 9.0.0 at run time: the workspace setup calls -# aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. -# -# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [device] -# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [device] -set -euo pipefail - -CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" - -# The build tree is often outside the repo, so try the usual places and say -# which ones were tried rather than reporting only the default. -resolve_ptoas() { - if [[ -n "${PTOAS_BIN:-}" ]]; then - echo "${PTOAS_BIN}" - return - fi - local candidates=() - [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") - candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") - local onpath - onpath="$(command -v ptoas 2>/dev/null || true)" - [[ -n "${onpath}" ]] && candidates+=("${onpath}") - for c in "${candidates[@]}"; do - if [[ -x "${c}" ]]; then - echo "${c}" - return - fi - done - echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 - printf ' %s\n' "${candidates[@]}" >&2 - exit 1 -} - -PTOAS_BIN="$(resolve_ptoas)" -ARCH="${ARCH:-a3}" -AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" -# Only the vec/cube suffix is dropped for the launch object's arch flag. -# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. -AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" -AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" -OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" -DEVICE_ID="${1:-0}" - -: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" -BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" - -command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } - -mkdir -p "${OUT_DIR}" -echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" - -echo "== 1/4 kernel fatobj" -"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ - "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" - -echo "== 2/4 launch object" -"${BISHENG_BIN}" \ - -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ - -Xhost-start -Xhost-end \ - -mllvm -cce-aicore-stack-size=0x8000 \ - -mllvm -cce-aicore-function-stack-size=0x8000 \ - -mllvm -cce-aicore-record-overflow=true \ - -mllvm -cce-aicore-addr-transform \ - -mllvm -cce-aicore-dcci-insert-for-scalar=false \ - --cce-aicore-arch="${AICORE_ARCH_BASE}" \ - -DREGISTER_BASE -std=c++17 \ - -Wno-macro-redefined -Wno-ignored-attributes \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -I "${ASCEND_HOME_PATH}/pkg_inc" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ - "${CASE_DIR}/launch.cpp" \ - -o "${OUT_DIR}/launch.o" - -echo "== 3/4 kernel shared library" -"${BISHENG_BIN}" \ - -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ - -shared -Wl,-soname,libsdma_gm_gm_local_kernel.so \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/libsdma_gm_gm_local_kernel.so" \ - "${OUT_DIR}/kernel.fatobj.o" \ - "${OUT_DIR}/launch.o" \ - -Wl,--no-as-needed -lruntime - -echo "== 4/4 host executable" -"${BISHENG_BIN}" \ - -xc++ -std=c++17 \ - "${CASE_DIR}/main.cpp" \ - -I "${CASE_DIR}" \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -L "${OUT_DIR}" \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${OUT_DIR}" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/sdma_gm_gm_local" \ - -lsdma_gm_gm_local_kernel \ - -Wl,--allow-shlib-undefined -lruntime \ - -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase - -# Building is safe anywhere; running needs a card. Splitting the two lets a -# change be checked for compile errors without putting a device at risk. -if [ -n "${BUILD_ONLY:-}" ]; then - echo "== build only, skipping the run" - exit 0 -fi - -echo "== run on device ${DEVICE_ID}" -cd "${OUT_DIR}" -# A kernel that never returns holds the device until the process dies, and -# suspending the shell leaves it held. Kill the run instead, hard if it will -# not go, so a failed case costs a case rather than a card. -set +e -LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ - timeout --signal=KILL "${RUN_TIMEOUT:-60}" ./sdma_gm_gm_local "${DEVICE_ID}" -rc=$? -set -e -if [ "${rc}" -eq 137 ]; then - echo "== killed after ${RUN_TIMEOUT:-60}s; device ${DEVICE_ID} may need a reset" >&2 -fi -exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto deleted file mode 100644 index 3e131b160c..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/kernel.pto +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-multicore -// target_ops: pto.sdma_gm_gm, pto.session_init -// scenarios: single-device, local GM->GM, one channel group per core -// ----------------------------------------------------------------------------- -// -// Every core posts its own slice through its own channel group, which is the -// arrangement the channel index exists for: two cores sharing a group would -// interleave writes into one queue ring and corrupt each other's entries. -// -// The core id picks both the slice and the group, so the two stay aligned -// without the host having to describe the mapping. Everything else in the -// session comes from the host's template, which is why only one field is -// written here. - -module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { - func.func @sdma_gm_gm_multicore(%dst: !pto.ptr, - %src: !pto.ptr, - %sess_gm: !pto.ptr, - %chunk: i64) attributes {pto.kernel} { - %bid = pto.get_block_idx - %bid32 = arith.trunci %bid : i64 to i32 - - // Slice base for this core. Both sides move by the same amount, so the - // destination mirrors the source. - %off = arith.muli %bid, %chunk : i64 - %src_i64 = pto.castptr %src : !pto.ptr -> i64 - %dst_i64 = pto.castptr %dst : !pto.ptr -> i64 - %my_src_i64 = arith.addi %src_i64, %off : i64 - %my_dst_i64 = arith.addi %dst_i64, %off : i64 - %my_src = pto.castptr %my_src_i64 : i64 -> !pto.ptr - %my_dst = pto.castptr %my_dst_i64 : i64 -> !pto.ptr - - %sess = pto.declare_struct -> !pto.struct - - pto.session_init %sess, %sess_gm - : !pto.struct, - !pto.ptr - - // The template cannot name the core, so the one field that differs per core - // is written after the copy. Everything else stays as the host set it. - pto.struct_set %sess[4], %bid32 : !pto.struct, i32 - - pto.sdma_gm_gm %my_dst, %my_src, %chunk session(%sess) - : !pto.ptr, !pto.ptr, i64, - !pto.struct - - return - } -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp deleted file mode 100644 index acbc24a623..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/launch.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-multicore -// target_ops: pto.sdma_gm_gm -// scenarios: single-device, local GM->GM, one channel group per core -// ----------------------------------------------------------------------------- -#ifndef __VEC_SCOPE__ -#define __VEC_SCOPE__ -#endif - -#include - -#ifndef __CPU_SIM -#include "acl/acl.h" -#endif - -extern "C" __global__ [aicore] void sdma_gm_gm_multicore( - __gm__ int8_t *dst, __gm__ int8_t *src, __gm__ int8_t *sessionGm, - int64_t chunkBytes); - -// One block per channel group. The workspace has to have been built with at -// least this many channels, or a core would index past the record table. -void LaunchSdmaGmGmMulticore(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t chunkBytes, uint32_t blocks, - void *stream) { - sdma_gm_gm_multicore<<>>( - (__gm__ int8_t *)dst, (__gm__ int8_t *)src, (__gm__ int8_t *)sessionGm, - chunkBytes); -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp deleted file mode 100644 index 2444168a67..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/main.cpp +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-multicore -// target_ops: pto.sdma_gm_gm -// scenarios: single-device, local GM->GM, one channel group per core -// ----------------------------------------------------------------------------- -// -// Correct data would not by itself show that the cores stayed on separate -// queues: one core doing all the work, or several sharing a ring and happening -// not to collide, both produce the same bytes. So the check is per channel -- -// every group must have advanced by exactly one entry. A group that moved by -// more took someone else's post, and a group that did not move at all was -// never used. -// -// Each core's slice carries a distinct byte pattern, so a mismatch also says -// which core's transfer went wrong rather than only that something did. - -#include -#include -#include -#include -#include -#include -#include - -#include "acl/acl.h" - -#include "AsyncWorkspace.h" - -using mlir::pto::comm::AsyncWorkspace; -namespace workspace = mlir::pto::comm::workspace; - -void LaunchSdmaGmGmMulticore(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t chunkBytes, uint32_t blocks, void *stream); - -namespace { - -constexpr unsigned kCores = 4; -constexpr size_t kChunkBytes = 1024; -constexpr size_t kTotalBytes = kCores * kChunkBytes; -constexpr int kPollTimeoutMs = 2000; - -#define ACL_CHECK(expr) \ - do { \ - const aclError _ret = (expr); \ - if (_ret != ACL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - const char *_recent = aclGetRecentErrMsg(); \ - if (_recent != nullptr && _recent[0] != '\0') \ - std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ - return 1; \ - } \ - } while (0) - -uint32_t readSqTail(AsyncWorkspace &ws, unsigned channel) { - uint8_t raw[workspace::kChannelDescBytes]; - if (!ws.readChannelDescriptor(0, kCores, channel, raw)) - return 0xFFFFFFFFU; - uint32_t tail; - std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); - return tail; -} - -} // namespace - -int main(int argc, char **argv) { - const int deviceId = - argc > 1 ? std::atoi(argv[1]) - : (std::getenv("ACL_DEVICE_ID") - ? std::atoi(std::getenv("ACL_DEVICE_ID")) - : 0); - - ACL_CHECK(aclInit(nullptr)); - ACL_CHECK(aclrtSetDevice(deviceId)); - - aclrtStream stream = nullptr; - ACL_CHECK(aclrtCreateStream(&stream)); - - AsyncWorkspace ws; - if (!ws.init(kCores)) { - std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", - ws.error().c_str()); - return 1; - } - - std::vector tailBefore(kCores); - for (unsigned c = 0; c < kCores; ++c) - tailBefore[c] = readSqTail(ws, c); - - std::printf("workspace %p, %u channel groups\n", ws.contextGm(), kCores); - for (unsigned c = 0; c < kCores; ++c) { - uint8_t rec[mlir::pto::comm::channel::kRecordBytes]; - if (!ws.readChannelRecord(c, rec)) - continue; - namespace ch = mlir::pto::comm::channel; - uint64_t sqBase, doorbell; - uint32_t streamId; - std::memcpy(&sqBase, rec + ch::kSqBaseOffset, sizeof(sqBase)); - std::memcpy(&doorbell, rec + ch::kDoorbellOffset, sizeof(doorbell)); - std::memcpy(&streamId, rec + ch::kStreamIdOffset, sizeof(streamId)); - std::printf(" group %u: sq_base=%#" PRIx64 " doorbell=%#" PRIx64 - " stream=%u tail=%u\n", - c, sqBase, doorbell, streamId, tailBefore[c]); - } - - // A distinct pattern per slice, so a wrong slice is visible as the wrong - // core's data rather than as generic corruption. - std::vector pattern(kTotalBytes); - for (unsigned c = 0; c < kCores; ++c) - for (size_t i = 0; i < kChunkBytes; ++i) - pattern[c * kChunkBytes + i] = - static_cast(((i * 31 + 7) ^ (c * 0x5B)) & 0xFF); - - void *srcDevice = nullptr; - void *dstDevice = nullptr; - ACL_CHECK(aclrtMalloc(&srcDevice, kTotalBytes, ACL_MEM_MALLOC_HUGE_FIRST)); - ACL_CHECK(aclrtMalloc(&dstDevice, kTotalBytes, ACL_MEM_MALLOC_HUGE_FIRST)); - ACL_CHECK(aclrtMemcpy(srcDevice, kTotalBytes, pattern.data(), kTotalBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - ACL_CHECK(aclrtMemset(dstDevice, kTotalBytes, 0, kTotalBytes)); - - // One template for every core. The channel group is the only thing that - // differs, and the kernel writes that itself from its core id. - namespace comm = mlir::pto::comm; - void *sessionDevice = nullptr; - ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, - ACL_MEM_MALLOC_HUGE_FIRST)); - { - comm::session_tmpl::Builder tmpl; - tmpl.set(comm::SessionField::ContextGm, - reinterpret_cast(ws.contextGm())) - .set(comm::SessionField::ChannelNum, 1) - .set(comm::SessionField::BlockBytes, kChunkBytes) - .set(comm::SessionField::Engine, - static_cast(comm::SessionEngine::Sdma)) - .set(comm::SessionField::Flags, comm::kSessionFlagValid) - .set(comm::SessionField::Qos, comm::sqe::kQosDefault); - ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, - tmpl.data(), comm::session_tmpl::kBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - } - - std::printf("posting %u slices of %zu bytes: src=%p dst=%p session=%p\n", - kCores, kChunkBytes, srcDevice, dstDevice, sessionDevice); - - LaunchSdmaGmGmMulticore(static_cast(dstDevice), - static_cast(srcDevice), - static_cast(sessionDevice), - static_cast(kChunkBytes), kCores, stream); - ACL_CHECK(aclrtSynchronizeStream(stream)); - - std::vector readback(kTotalBytes); - bool matched = false; - int elapsedMs = 0; - const auto start = std::chrono::steady_clock::now(); - while (elapsedMs < kPollTimeoutMs) { - ACL_CHECK(aclrtMemcpy(readback.data(), kTotalBytes, dstDevice, kTotalBytes, - ACL_MEMCPY_DEVICE_TO_HOST)); - if (std::memcmp(readback.data(), pattern.data(), kTotalBytes) == 0) { - matched = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - elapsedMs = static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count()); - } - - int rc = 0; - for (unsigned c = 0; c < kCores; ++c) { - const uint32_t after = readSqTail(ws, c); - const uint32_t posted = after - tailBefore[c]; - - size_t badBytes = 0; - for (size_t i = 0; i < kChunkBytes; ++i) - if (readback[c * kChunkBytes + i] != pattern[c * kChunkBytes + i]) - ++badBytes; - - const bool ok = posted == 1 && badBytes == 0; - std::printf("group %u: %u entry (want 1), %zu bad bytes %s\n", c, posted, - badBytes, ok ? "OK" : "FAIL"); - if (!ok) - rc = 1; - } - - if (rc == 0 && matched) - std::printf("PASS: every core posted through its own group\n"); - else if (rc == 0) - std::printf("PASS (late): data settled after %d ms\n", elapsedMs); - - aclrtFree(srcDevice); - aclrtFree(dstDevice); - aclrtFree(sessionDevice); - ws.finalize(); - aclrtDestroyStream(stream); - aclrtResetDevice(deviceId); - aclFinalize(); - return rc; -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh deleted file mode 100755 index 835fcf3875..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-multicore/run.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/bash -# Build and run the multicore GM->GM SDMA case, one channel group per core. -# -# This does not go through run_host_vpto_validation.sh because that script -# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because -# the host program needs the PTOAS include path for AsyncWorkspace.h. -# -# Requires CANN 9.0.0 at run time: the workspace setup calls -# aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. -# -# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [device] -# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [device] -set -euo pipefail - -CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" - -# The build tree is often outside the repo, so try the usual places and say -# which ones were tried rather than reporting only the default. -resolve_ptoas() { - if [[ -n "${PTOAS_BIN:-}" ]]; then - echo "${PTOAS_BIN}" - return - fi - local candidates=() - [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") - candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") - local onpath - onpath="$(command -v ptoas 2>/dev/null || true)" - [[ -n "${onpath}" ]] && candidates+=("${onpath}") - for c in "${candidates[@]}"; do - if [[ -x "${c}" ]]; then - echo "${c}" - return - fi - done - echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 - printf ' %s\n' "${candidates[@]}" >&2 - exit 1 -} - -PTOAS_BIN="$(resolve_ptoas)" -ARCH="${ARCH:-a3}" -AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" -# Only the vec/cube suffix is dropped for the launch object's arch flag. -# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. -AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" -AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" -OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" -DEVICE_ID="${1:-0}" - -: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" -BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" - -command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } - -mkdir -p "${OUT_DIR}" -echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" - -echo "== 1/4 kernel fatobj" -"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ - "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" - -echo "== 2/4 launch object" -"${BISHENG_BIN}" \ - -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ - -Xhost-start -Xhost-end \ - -mllvm -cce-aicore-stack-size=0x8000 \ - -mllvm -cce-aicore-function-stack-size=0x8000 \ - -mllvm -cce-aicore-record-overflow=true \ - -mllvm -cce-aicore-addr-transform \ - -mllvm -cce-aicore-dcci-insert-for-scalar=false \ - --cce-aicore-arch="${AICORE_ARCH_BASE}" \ - -DREGISTER_BASE -std=c++17 \ - -Wno-macro-redefined -Wno-ignored-attributes \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -I "${ASCEND_HOME_PATH}/pkg_inc" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ - "${CASE_DIR}/launch.cpp" \ - -o "${OUT_DIR}/launch.o" - -echo "== 3/4 kernel shared library" -"${BISHENG_BIN}" \ - -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ - -shared -Wl,-soname,libsdma_gm_gm_multicore_kernel.so \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/libsdma_gm_gm_multicore_kernel.so" \ - "${OUT_DIR}/kernel.fatobj.o" \ - "${OUT_DIR}/launch.o" \ - -Wl,--no-as-needed -lruntime - -echo "== 4/4 host executable" -"${BISHENG_BIN}" \ - -xc++ -std=c++17 \ - "${CASE_DIR}/main.cpp" \ - -I "${CASE_DIR}" \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -L "${OUT_DIR}" \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${OUT_DIR}" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/sdma_gm_gm_multicore" \ - -lsdma_gm_gm_multicore_kernel \ - -Wl,--allow-shlib-undefined -lruntime \ - -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase - -# Building is safe anywhere; running needs a card. Splitting the two lets a -# change be checked for compile errors without putting a device at risk. -if [ -n "${BUILD_ONLY:-}" ]; then - echo "== build only, skipping the run" - exit 0 -fi - -echo "== run on device ${DEVICE_ID}" -cd "${OUT_DIR}" -# A kernel that never returns holds the device until the process dies, and -# suspending the shell leaves it held. Kill the run instead, hard if it will -# not go, so a failed case costs a case rather than a card. -set +e -LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ - timeout --signal=KILL "${RUN_TIMEOUT:-60}" ./sdma_gm_gm_multicore "${DEVICE_ID}" -rc=$? -set -e -if [ "${rc}" -eq 137 ]; then - echo "== killed after ${RUN_TIMEOUT:-60}s; device ${DEVICE_ID} may need a reset" >&2 -fi -exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto deleted file mode 100644 index 32794be04c..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/kernel.pto +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-get -// target_ops: pto.sdma_gm_gm, pto.session_init -// scenarios: two-device, peer GM->local GM, one channel, block splitting -// ----------------------------------------------------------------------------- -// -// Rank 0 reads rank 1's window. There is no `{soft_put}`: A5's engine will -// GET from a peer, so this kick posts SQEs the same way a local copy does. -// The peer-put counterpart needs the attr because that generation cannot write -// remotely through the engine. -// -// The session comes from a template the host wrote, which is also where the -// workspace address lives, so the kernel names neither. - -module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { - func.func @sdma_gm_gm_peer_get(%dst: !pto.ptr, - %src: !pto.ptr, - %sess_gm: !pto.ptr, - %nbytes: i64) attributes {pto.kernel} { - %sess = pto.declare_struct - -> !pto.struct - - pto.session_init %sess, %sess_gm - : !pto.struct, - !pto.ptr - - pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) - : !pto.ptr, !pto.ptr, i64, - !pto.struct - - return - } -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp deleted file mode 100644 index 1f20f0eb60..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/launch.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-get -// target_ops: pto.sdma_gm_gm -// scenarios: two-device, peer GM->local GM, one channel, block splitting -// ----------------------------------------------------------------------------- -#ifndef __VEC_SCOPE__ -#define __VEC_SCOPE__ -#endif - -#include - -#ifndef __CPU_SIM -#include "acl/acl.h" -#endif - -extern "C" __global__ [aicore] void sdma_gm_gm_peer_get(__gm__ int8_t *dst, - __gm__ int8_t *src, - __gm__ int8_t *sessionGm, - int64_t nbytes); - -// A single block: the session owns one channel group, and a second core would -// race it on the same queue ring. -void LaunchSdmaGmGmPeerGet(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream) { - sdma_gm_gm_peer_get<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, - (__gm__ int8_t *)src, - (__gm__ int8_t *)sessionGm, - nbytes); -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp deleted file mode 100644 index d6ec7ca024..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/main.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-get -// target_ops: pto.sdma_gm_gm -// scenarios: two-device, peer GM->local GM, one channel, block splitting -// ----------------------------------------------------------------------------- -// -// Rank 0 posts a GET from rank 1's window into its own. A5's engine can read -// a peer, so this kick posts SQEs: the tail must advance, and the destination -// is polled because returning from the kernel does not mean the engine has -// drained. sdma-gm-gm-peer-put uses `{soft_put}` and leaves the tail at zero. -// -// The same transfer is repeated at several block sizes, matching -// sdma-gm-gm-local: data alone would not show that splitting happened. -// -// Both endpoints sit in the HCCL window, because that is the memory a remote -// transfer can name. Rank 1 writes its own window, rank 0 names that range -// through its peer view, and rank 0 reads its own destination, so a pass -// cannot be explained by the bytes already sitting on the near device. - -#include -#include -#include -#include -#include -#include -#include - -#include "acl/acl.h" -#include "hccl/hccl.h" - -#include "AsyncWorkspace.h" -#include "HcclWindows.h" - -using mlir::pto::comm::AsyncWorkspace; -using mlir::pto::comm::HcclWindows; -namespace workspace = mlir::pto::comm::workspace; - -void LaunchSdmaGmGmPeerGet(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream); - -namespace { - -constexpr size_t kTransferBytes = 4096; -constexpr unsigned kChannels = 1; -constexpr unsigned kRanks = 2; - -// Every size is a multiple of 64, the smallest transfer the engine accepts. -const size_t kBlockSizes[] = {4096, 1024, 1536, 128}; - -// The engine can queue behind other work, and this machine is shared, so the -// window is wide enough that a slow completion is not read as a failure. -constexpr int kPollTimeoutMsDefault = 30000; - -#define ACL_CHECK(expr) \ - do { \ - const aclError _ret = (expr); \ - if (_ret != ACL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - const char *_recent = aclGetRecentErrMsg(); \ - if (_recent != nullptr && _recent[0] != '\0') { \ - std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ - } \ - return 1; \ - } \ - } while (0) - -#define HCCL_CHECK(expr) \ - do { \ - const HcclResult _ret = (expr); \ - if (_ret != HCCL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - return 1; \ - } \ - } while (0) - -uint32_t readSqTail(AsyncWorkspace &ws) { - uint8_t raw[workspace::kChannelDescBytes]; - if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) { - return 0xFFFFFFFFU; - } - uint32_t tail; - std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); - return tail; -} - -struct Rank { - int32_t device = -1; - aclrtStream stream = nullptr; - HcclWindows windows; - bool ok = false; -}; - -// One per rank, on its own thread: ACL binds a device per thread, and the -// domain build has to be entered by both ranks at once. -void setupRank(Rank *rank, HcclComm comm) { - if (aclrtSetDevice(rank->device) != ACL_SUCCESS) { - return; - } - if (aclrtCreateStream(&rank->stream) != ACL_SUCCESS) { - return; - } - if (!rank->windows.init(comm, rank->stream)) { - std::fprintf(stderr, "[ERROR] device %d window setup failed: %s\n", - rank->device, rank->windows.error().c_str()); - return; - } - rank->ok = true; -} - -} // namespace - -int main(int argc, char **argv) { - int32_t devices[kRanks] = {0, 1}; - if (argc > 2) { - devices[0] = std::atoi(argv[1]); - devices[1] = std::atoi(argv[2]); - } - const int pollTimeoutMs = std::getenv("SDMA_POLL_TIMEOUT_MS") - ? std::atoi(std::getenv("SDMA_POLL_TIMEOUT_MS")) - : kPollTimeoutMsDefault; - - std::printf("case: async-comm/sdma-gm-gm-peer-get direction=GET\n"); - std::printf("ranks: 0 -> device %d, 1 -> device %d\n", devices[0], - devices[1]); - - ACL_CHECK(aclInit(nullptr)); - // HcclCommInitAll reads the calling thread's current device even though it - // opens all of them, and fails outright if none is set. - ACL_CHECK(aclrtSetDevice(devices[0])); - - HcclComm comms[kRanks] = {nullptr, nullptr}; - HCCL_CHECK(HcclCommInitAll(kRanks, devices, comms)); - - Rank ranks[kRanks]; - for (unsigned r = 0; r < kRanks; ++r) { - ranks[r].device = devices[r]; - } - { - std::thread t0(setupRank, &ranks[0], comms[0]); - std::thread t1(setupRank, &ranks[1], comms[1]); - t0.join(); - t1.join(); - } - for (unsigned r = 0; r < kRanks; ++r) { - if (!ranks[r].ok) { - std::fprintf(stderr, "[ERROR] rank %u setup failed\n", r); - return 1; - } - } - - const uint64_t windowBytes = ranks[0].windows.windowBytes(); - std::printf("window %" PRIu64 " bytes, rank0 sees: own %#" PRIx64 - ", peer %#" PRIx64 "\n", - windowBytes, ranks[0].windows.window(0), - ranks[0].windows.window(1)); - std::printf("rank1 sees: own %#" PRIx64 ", peer %#" PRIx64 "\n", - ranks[1].windows.window(1), ranks[1].windows.window(0)); - if (windowBytes < kTransferBytes) { - std::fprintf(stderr, "[ERROR] window smaller than the transfer\n"); - return 1; - } - - // Payload lives on rank 1. Rank 0 names it through its peer view and writes - // into its own window. - ACL_CHECK(aclrtSetDevice(devices[1])); - void *farSrc = reinterpret_cast(ranks[1].windows.window(1)); - std::vector pattern(kTransferBytes); - for (size_t i = 0; i < kTransferBytes; ++i) { - pattern[i] = static_cast((i * 31 + 7) & 0xFF); - } - ACL_CHECK(aclrtMemcpy(farSrc, kTransferBytes, pattern.data(), kTransferBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - - ACL_CHECK(aclrtSetDevice(devices[0])); - void *src = reinterpret_cast(ranks[0].windows.window(1)); - void *dst = reinterpret_cast(ranks[0].windows.window(0)); - - AsyncWorkspace ws; - if (!ws.init(kChannels)) { - std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", - ws.error().c_str()); - return 1; - } - std::printf("workspace %p, sq_tail before post = %u\n", ws.contextGm(), - readSqTail(ws)); - std::printf("posting %zu bytes: src=%p (dev %d) dst=%p (dev %d)\n", - kTransferBytes, src, devices[1], dst, devices[0]); - - namespace comm = mlir::pto::comm; - void *sessionDevice = nullptr; - ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, - ACL_MEM_MALLOC_HUGE_FIRST)); - - int rc = 0; - std::vector readback(kTransferBytes); - const size_t nBlocks = sizeof(kBlockSizes) / sizeof(kBlockSizes[0]); - for (size_t i = 0; i < nBlocks; ++i) { - const size_t block = kBlockSizes[i]; - const uint32_t wantEntries = - static_cast((kTransferBytes + block - 1) / block); - - comm::session_tmpl::Builder tmpl; - tmpl.set(comm::SessionField::ContextGm, - reinterpret_cast(ws.contextGm())) - .set(comm::SessionField::ChannelIdx, 0) - .set(comm::SessionField::ChannelNum, 1) - .set(comm::SessionField::BlockBytes, block) - .set(comm::SessionField::Engine, - static_cast(comm::SessionEngine::Sdma)) - .set(comm::SessionField::Flags, comm::kSessionFlagValid) - .set(comm::SessionField::Qos, comm::sqe::kQosDefault); - ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, - tmpl.data(), comm::session_tmpl::kBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - - ACL_CHECK(aclrtMemset(dst, kTransferBytes, 0, kTransferBytes)); - const uint32_t tailBefore = readSqTail(ws); - - LaunchSdmaGmGmPeerGet(static_cast(dst), - static_cast(src), - static_cast(sessionDevice), - static_cast(kTransferBytes), - ranks[0].stream); - ACL_CHECK(aclrtSynchronizeStream(ranks[0].stream)); - - bool matched = false; - int elapsedMs = 0; - const auto start = std::chrono::steady_clock::now(); - while (elapsedMs < pollTimeoutMs) { - ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, dst, - kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); - if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { - matched = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - elapsedMs = static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count()); - } - - const uint32_t tailAfter = readSqTail(ws); - const uint32_t posted = tailAfter - tailBefore; - const bool ok = matched && posted == wantEntries; - std::printf("block %5zu -> %u entries (want %u), data %s %s\n", block, - posted, wantEntries, matched ? "match" : "MISMATCH", - ok ? "OK" : "FAIL"); - std::fflush(stdout); - - if (!ok) { - if (!matched) { - size_t changed = 0; - for (size_t b = 0; b < kTransferBytes; ++b) { - if (readback[b] != 0) { - ++changed; - } - } - std::fprintf(stderr, - " destination did not match within %d ms " - "(%zu of %zu bytes non-zero)\n", - pollTimeoutMs, changed, kTransferBytes); - } - rc = 1; - break; - } - } - - if (rc == 0) { - std::printf("PASS: every split posted the entries it implies\n"); - } - - ws.finalize(); - aclrtFree(sessionDevice); - for (unsigned r = 0; r < kRanks; ++r) { - if (ranks[r].stream != nullptr) { - aclrtSetDevice(ranks[r].device); - aclrtDestroyStream(ranks[r].stream); - } - HcclCommDestroy(comms[r]); - } - aclrtResetDevice(devices[0]); - aclrtResetDevice(devices[1]); - aclFinalize(); - return rc; -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh deleted file mode 100755 index 6faed98699..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-get/run.sh +++ /dev/null @@ -1,140 +0,0 @@ -#!/bin/bash -# Copyright (c) 2026 Huawei Technologies Co., Ltd. -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of -# CANN Open Software License Agreement Version 2.0 (the "License"). -# Please refer to the License for details. You may not use this file except in compliance with the License. -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -# See LICENSE in the root of the software repository for the full text of the License. -# -# Build and run the cross-device peer-GM -> local-GM SDMA GET case. -# -# This does not go through run_host_vpto_validation.sh because that script -# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because -# the host program needs the PTOAS include path for AsyncWorkspace.h. -# -# Needs two visible devices, and CANN 9.0.0 at run time: the workspace setup -# calls aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. -# -# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [dev0] [dev1] -# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [dev0] [dev1] -set -euo pipefail - -CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" - -# The build tree is often outside the repo, so try the usual places and say -# which ones were tried rather than reporting only the default. -resolve_ptoas() { - if [[ -n "${PTOAS_BIN:-}" ]]; then - echo "${PTOAS_BIN}" - return - fi - local candidates=() - [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") - candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") - local onpath - onpath="$(command -v ptoas 2>/dev/null || true)" - [[ -n "${onpath}" ]] && candidates+=("${onpath}") - for c in "${candidates[@]}"; do - if [[ -x "${c}" ]]; then - echo "${c}" - return - fi - done - echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 - printf ' %s\n' "${candidates[@]}" >&2 - exit 1 -} - -PTOAS_BIN="$(resolve_ptoas)" -ARCH="${ARCH:-a3}" -AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" -# Only the vec/cube suffix is dropped for the launch object's arch flag. -# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. -AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" -AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" -OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" -DEVICE0="${1:-0}" -DEVICE1="${2:-1}" - -: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" -BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" - -command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } - -mkdir -p "${OUT_DIR}" -echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" - -echo "== 1/4 kernel fatobj" -"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ - "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" - -echo "== 2/4 launch object" -"${BISHENG_BIN}" \ - -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ - -Xhost-start -Xhost-end \ - -mllvm -cce-aicore-stack-size=0x8000 \ - -mllvm -cce-aicore-function-stack-size=0x8000 \ - -mllvm -cce-aicore-record-overflow=true \ - -mllvm -cce-aicore-addr-transform \ - -mllvm -cce-aicore-dcci-insert-for-scalar=false \ - --cce-aicore-arch="${AICORE_ARCH_BASE}" \ - -DREGISTER_BASE -std=c++17 \ - -Wno-macro-redefined -Wno-ignored-attributes \ - -I "${ASCEND_HOME_PATH}/include" \ - -I "${ASCEND_HOME_PATH}/pkg_inc" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ - "${CASE_DIR}/launch.cpp" \ - -o "${OUT_DIR}/launch.o" - -echo "== 3/4 kernel shared library" -"${BISHENG_BIN}" \ - -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ - -shared -Wl,-soname,libsdma_gm_gm_peer_get_kernel.so \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/libsdma_gm_gm_peer_get_kernel.so" \ - "${OUT_DIR}/kernel.fatobj.o" \ - "${OUT_DIR}/launch.o" \ - -Wl,--no-as-needed -lruntime - -echo "== 4/4 host executable" -"${BISHENG_BIN}" \ - -xc++ -std=c++17 \ - "${CASE_DIR}/main.cpp" \ - -I "${CASE_DIR}" \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -L "${OUT_DIR}" \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${OUT_DIR}" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/sdma_gm_gm_peer_get" \ - -lsdma_gm_gm_peer_get_kernel \ - -Wl,--allow-shlib-undefined -lruntime \ - -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase -lhccl -lpthread - -# Building is safe anywhere; running needs a card. Splitting the two lets a -# change be checked for compile errors without putting a device at risk. -if [ -n "${BUILD_ONLY:-}" ]; then - echo "== build only, skipping the run" - exit 0 -fi - -echo "== run GET on devices ${DEVICE1} -> ${DEVICE0}" -cd "${OUT_DIR}" -# A kernel that never returns holds both devices until the process dies, and -# suspending the shell leaves them held. Kill the run instead, hard if it will -# not go, so a failed case costs a case rather than a card. -set +e -LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ - timeout --signal=KILL "${RUN_TIMEOUT:-90}" ./sdma_gm_gm_peer_get "${DEVICE0}" "${DEVICE1}" -rc=$? -set -e -if [ "${rc}" -eq 137 ]; then - echo "== killed after ${RUN_TIMEOUT:-90}s; devices ${DEVICE0}/${DEVICE1} may need a reset" >&2 -fi -exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto deleted file mode 100644 index 235acd4e8c..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/kernel.pto +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-put -// target_ops: pto.sdma_gm_gm, pto.session_init -// scenarios: two-device, GM->peer GM, one channel, one block -// ----------------------------------------------------------------------------- -// -// Identical to sdma-gm-gm-local except for where the destination points, and -// `{soft_put}` so A5 can complete a remote write: that generation's engine -// will not PUT, so the expansion stages through UB. A2/A3 ignore the attr. -// -// The session comes from a template the host wrote, which is also where the -// workspace address lives, so the kernel names neither. - -module attributes {pto.target_arch = "a3", pto.kernel_kind = #pto.kernel_kind} { - func.func @sdma_gm_gm_peer_put(%dst: !pto.ptr, - %src: !pto.ptr, - %sess_gm: !pto.ptr, - %nbytes: i64) attributes {pto.kernel} { - %sess = pto.declare_struct - -> !pto.struct - - pto.session_init %sess, %sess_gm - : !pto.struct, - !pto.ptr - - pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {soft_put} - : !pto.ptr, !pto.ptr, i64, - !pto.struct - - return - } -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp deleted file mode 100644 index c5ade0eeef..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/launch.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-put -// target_ops: pto.sdma_gm_gm -// scenarios: two-device, GM->peer GM, one channel, one block -// ----------------------------------------------------------------------------- -#ifndef __VEC_SCOPE__ -#define __VEC_SCOPE__ -#endif - -#include - -#ifndef __CPU_SIM -#include "acl/acl.h" -#endif - -extern "C" __global__ [aicore] void sdma_gm_gm_peer_put(__gm__ int8_t *dst, - __gm__ int8_t *src, - __gm__ int8_t *sessionGm, - int64_t nbytes); - -// A single block: the session owns one channel group, and a second core would -// race it on the same queue ring. -void LaunchSdmaGmGmPeerPut(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream) { - sdma_gm_gm_peer_put<<<1, nullptr, stream>>>((__gm__ int8_t *)dst, - (__gm__ int8_t *)src, - (__gm__ int8_t *)sessionGm, nbytes); -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp deleted file mode 100644 index f128cbf72d..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/main.cpp +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2026 Huawei Technologies Co., Ltd. -// This program is free software, you can redistribute it and/or modify it under the terms and conditions of -// CANN Open Software License Agreement Version 2.0 (the "License"). -// Please refer to the License for details. You may not use this file except in compliance with the License. -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. -// See LICENSE in the root of the software repository for the full text of the License. - -// ----------------------------------------------------------------------------- -// case: async-comm/sdma-gm-gm-peer-put -// target_ops: pto.sdma_gm_gm -// scenarios: two-device, GM->peer GM, one channel, one block -// ----------------------------------------------------------------------------- -// -// Cross-device version of sdma-gm-gm-local: rank 0 posts a transfer into rank -// 1's memory. A5 cannot PUT through the engine, so the kernel marks the kick -// `{soft_put}` and the expansion stages the write through UB. A2/A3 posts SQEs. -// -// Both endpoints sit in the HCCL window, because that is the memory a remote -// transfer can name; an ordinary device pointer from the far device does not -// work even for a runtime copy. Rank 0 writes to its view of rank 1's window -// and rank 1 reads its own, so a pass cannot be explained by the bytes staying -// on the near device. -// -// Two ranks in one process, one thread each, because building the domain is -// collective and a single thread would block in the first call. - -#include -#include -#include -#include -#include -#include -#include - -#include "acl/acl.h" -#include "hccl/hccl.h" - -#include "AsyncWorkspace.h" -#include "HcclWindows.h" - -using mlir::pto::comm::AsyncWorkspace; -using mlir::pto::comm::HcclWindows; -namespace workspace = mlir::pto::comm::workspace; - -void LaunchSdmaGmGmPeerPut(int8_t *dst, int8_t *src, int8_t *sessionGm, - int64_t nbytes, void *stream); - -namespace { - -constexpr size_t kTransferBytes = 4096; -constexpr unsigned kChannels = 1; -constexpr unsigned kRanks = 2; - -// The engine can queue behind other work, and this machine is shared, so the -// window is wide enough that a slow completion is not read as a failure. -constexpr int kPollTimeoutMsDefault = 30000; - -#define ACL_CHECK(expr) \ - do { \ - const aclError _ret = (expr); \ - if (_ret != ACL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - const char *_recent = aclGetRecentErrMsg(); \ - if (_recent != nullptr && _recent[0] != '\0') \ - std::fprintf(stderr, "[ERROR] RecentErrMsg: %s\n", _recent); \ - return 1; \ - } \ - } while (0) - -#define HCCL_CHECK(expr) \ - do { \ - const HcclResult _ret = (expr); \ - if (_ret != HCCL_SUCCESS) { \ - std::fprintf(stderr, "[ERROR] %s failed: %d (%s:%d)\n", #expr, \ - (int)_ret, __FILE__, __LINE__); \ - return 1; \ - } \ - } while (0) - -uint32_t readSqTail(AsyncWorkspace &ws) { - uint8_t raw[workspace::kChannelDescBytes]; - if (!ws.readChannelDescriptor(0, kChannels, 0, raw)) - return 0xFFFFFFFFU; - uint32_t tail; - std::memcpy(&tail, raw + workspace::kChannelSqTailOffset, sizeof(tail)); - return tail; -} - -struct Rank { - int32_t device = -1; - aclrtStream stream = nullptr; - HcclWindows windows; - bool ok = false; -}; - -// One per rank, on its own thread: ACL binds a device per thread, and the -// domain build has to be entered by both ranks at once. -void setupRank(Rank *rank, HcclComm comm) { - if (aclrtSetDevice(rank->device) != ACL_SUCCESS) - return; - if (aclrtCreateStream(&rank->stream) != ACL_SUCCESS) - return; - if (!rank->windows.init(comm, rank->stream)) { - std::fprintf(stderr, "[ERROR] device %d window setup failed: %s\n", - rank->device, rank->windows.error().c_str()); - return; - } - rank->ok = true; -} - -} // namespace - -int main(int argc, char **argv) { - int32_t devices[kRanks] = {0, 1}; - if (argc > 2) { - devices[0] = std::atoi(argv[1]); - devices[1] = std::atoi(argv[2]); - } - const int pollTimeoutMs = std::getenv("SDMA_POLL_TIMEOUT_MS") - ? std::atoi(std::getenv("SDMA_POLL_TIMEOUT_MS")) - : kPollTimeoutMsDefault; - - std::printf("case: async-comm/sdma-gm-gm-peer-put direction=PUT\n"); - std::printf("ranks: 0 -> device %d, 1 -> device %d\n", devices[0], - devices[1]); - - ACL_CHECK(aclInit(nullptr)); - // HcclCommInitAll reads the calling thread's current device even though it - // opens all of them, and fails outright if none is set. - ACL_CHECK(aclrtSetDevice(devices[0])); - - HcclComm comms[kRanks] = {nullptr, nullptr}; - HCCL_CHECK(HcclCommInitAll(kRanks, devices, comms)); - - Rank ranks[kRanks]; - for (unsigned r = 0; r < kRanks; ++r) - ranks[r].device = devices[r]; - { - std::thread t0(setupRank, &ranks[0], comms[0]); - std::thread t1(setupRank, &ranks[1], comms[1]); - t0.join(); - t1.join(); - } - for (unsigned r = 0; r < kRanks; ++r) { - if (!ranks[r].ok) { - std::fprintf(stderr, "[ERROR] rank %u setup failed\n", r); - return 1; - } - } - - const uint64_t windowBytes = ranks[0].windows.windowBytes(); - std::printf("window %" PRIu64 " bytes, rank0 sees: own %#" PRIx64 - ", peer %#" PRIx64 "\n", - windowBytes, ranks[0].windows.window(0), - ranks[0].windows.window(1)); - std::printf("rank1 sees: own %#" PRIx64 ", peer %#" PRIx64 "\n", - ranks[1].windows.window(1), ranks[1].windows.window(0)); - if (windowBytes < kTransferBytes) { - std::fprintf(stderr, "[ERROR] window smaller than the transfer\n"); - return 1; - } - - ACL_CHECK(aclrtSetDevice(devices[0])); - void *src = reinterpret_cast(ranks[0].windows.window(0)); - void *dst = reinterpret_cast(ranks[0].windows.window(1)); - - std::vector pattern(kTransferBytes); - for (size_t i = 0; i < kTransferBytes; ++i) - pattern[i] = static_cast((i * 31 + 7) & 0xFF); - ACL_CHECK(aclrtMemcpy(src, kTransferBytes, pattern.data(), kTransferBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - - ACL_CHECK(aclrtSetDevice(devices[1])); - void *farSide = reinterpret_cast(ranks[1].windows.window(1)); - ACL_CHECK(aclrtMemset(farSide, kTransferBytes, 0, kTransferBytes)); - - ACL_CHECK(aclrtSetDevice(devices[0])); - - AsyncWorkspace ws; - if (!ws.init(kChannels)) { - std::fprintf(stderr, "[ERROR] AsyncWorkspace::init failed: %s\n", - ws.error().c_str()); - return 1; - } - std::printf("PUT: workspace %p, sq_tail before post = %u\n", ws.contextGm(), - readSqTail(ws)); - - // The session the kernel copies in. The workspace address rides in it, so - // the kernel takes no separate workspace argument. - namespace comm = mlir::pto::comm; - void *sessionDevice = nullptr; - ACL_CHECK(aclrtMalloc(&sessionDevice, comm::session_tmpl::kBytes, - ACL_MEM_MALLOC_HUGE_FIRST)); - { - comm::session_tmpl::Builder tmpl; - tmpl.set(comm::SessionField::ContextGm, - reinterpret_cast(ws.contextGm())) - .set(comm::SessionField::ChannelIdx, 0) - .set(comm::SessionField::ChannelNum, 1) - .set(comm::SessionField::BlockBytes, 1u << 20) - .set(comm::SessionField::Engine, - static_cast(comm::SessionEngine::Sdma)) - .set(comm::SessionField::Flags, comm::kSessionFlagValid) - .set(comm::SessionField::Qos, comm::sqe::kQosDefault); - ACL_CHECK(aclrtMemcpy(sessionDevice, comm::session_tmpl::kBytes, - tmpl.data(), comm::session_tmpl::kBytes, - ACL_MEMCPY_HOST_TO_DEVICE)); - } - - std::printf("posting %zu bytes: src=%p (dev %d) dst=%p (dev %d)\n", - kTransferBytes, src, devices[0], dst, devices[1]); - - LaunchSdmaGmGmPeerPut(static_cast(dst), static_cast(src), - static_cast(sessionDevice), - static_cast(kTransferBytes), ranks[0].stream); - ACL_CHECK(aclrtSynchronizeStream(ranks[0].stream)); - - const uint32_t tailAfter = readSqTail(ws); - std::printf("kernel returned, sq_tail after post = %u\n", tailAfter); - - ACL_CHECK(aclrtSetDevice(devices[1])); - std::vector readback(kTransferBytes); - bool matched = false; - int elapsedMs = 0; - const auto start = std::chrono::steady_clock::now(); - while (elapsedMs < pollTimeoutMs) { - ACL_CHECK(aclrtMemcpy(readback.data(), kTransferBytes, farSide, - kTransferBytes, ACL_MEMCPY_DEVICE_TO_HOST)); - if (std::memcmp(readback.data(), pattern.data(), kTransferBytes) == 0) { - matched = true; - break; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - elapsedMs = static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now() - start) - .count()); - } - - int rc = 0; - if (matched) { - std::printf("PASS: peer destination matched after %d ms\n", elapsedMs); - } else { - size_t changed = 0; - for (size_t i = 0; i < kTransferBytes; ++i) - if (readback[i] != 0) - ++changed; - std::fprintf(stderr, - "FAIL: peer destination did not match within %d ms " - "(%zu of %zu bytes non-zero, sq_tail %u)\n", - pollTimeoutMs, changed, kTransferBytes, tailAfter); - rc = 1; - } - - ACL_CHECK(aclrtSetDevice(devices[0])); - ws.finalize(); - for (unsigned r = 0; r < kRanks; ++r) { - if (ranks[r].stream != nullptr) { - aclrtSetDevice(ranks[r].device); - aclrtDestroyStream(ranks[r].stream); - } - HcclCommDestroy(comms[r]); - } - aclrtResetDevice(devices[0]); - aclrtResetDevice(devices[1]); - aclFinalize(); - return rc; -} diff --git a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh b/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh deleted file mode 100755 index 14c4143709..0000000000 --- a/test/vpto/cases/async-comm/sdma-gm-gm-peer-put/run.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/bash -# Build and run the cross-device GM->peer GM SDMA case. -# -# This does not go through run_host_vpto_validation.sh because that script -# hard-codes --cce-aicore-arch=dav-c310 and this case targets c220, and because -# the host program needs the PTOAS include path for AsyncWorkspace.h. -# -# Needs two visible devices, and CANN 9.0.0 at run time: the workspace setup -# calls aclnnShmemSdmaStarsQuery, which earlier toolkits do not ship. -# -# PTOAS_BUILD_DIR=... ARCH=a3 AICORE_ARCH=dav-c220-vec ./run.sh [dev0] [dev1] -# PTOAS_BUILD_DIR=... ARCH=a5 AICORE_ARCH=dav-c310-vec ./run.sh [dev0] [dev1] -set -euo pipefail - -CASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "${CASE_DIR}/../../../../.." && pwd)" - -# The build tree is often outside the repo, so try the usual places and say -# which ones were tried rather than reporting only the default. -resolve_ptoas() { - if [[ -n "${PTOAS_BIN:-}" ]]; then - echo "${PTOAS_BIN}" - return - fi - local candidates=() - [[ -n "${PTOAS_BUILD_DIR:-}" ]] && candidates+=("${PTOAS_BUILD_DIR}/tools/ptoas/ptoas") - candidates+=("${REPO_ROOT}/build/tools/ptoas/ptoas") - local onpath - onpath="$(command -v ptoas 2>/dev/null || true)" - [[ -n "${onpath}" ]] && candidates+=("${onpath}") - for c in "${candidates[@]}"; do - if [[ -x "${c}" ]]; then - echo "${c}" - return - fi - done - echo "ptoas not found; set PTOAS_BIN or PTOAS_BUILD_DIR. Tried:" >&2 - printf ' %s\n' "${candidates[@]}" >&2 - exit 1 -} - -PTOAS_BIN="$(resolve_ptoas)" -ARCH="${ARCH:-a3}" -AICORE_ARCH="${AICORE_ARCH:-dav-c220-vec}" -# Only the vec/cube suffix is dropped for the launch object's arch flag. -# Only the vec/cube suffix is dropped. `%-*` would turn dav-c310 into dav. -AICORE_ARCH_BASE="${AICORE_ARCH%-vec}" -AICORE_ARCH_BASE="${AICORE_ARCH_BASE%-cube}" -OUT_DIR="${OUT_DIR:-${CASE_DIR}/build}" -DEVICE0="${1:-0}" -DEVICE1="${2:-1}" - -: "${ASCEND_HOME_PATH:?source your CANN set_env.sh first}" -BISHENG_BIN="${BISHENG_BIN:-${ASCEND_HOME_PATH}/bin/bisheng}" - -command -v "${BISHENG_BIN}" >/dev/null 2>&1 || { echo "bisheng not found: ${BISHENG_BIN}" >&2; exit 1; } - -mkdir -p "${OUT_DIR}" -echo "== arch ${ARCH} / ${AICORE_ARCH}, toolkit ${ASCEND_HOME_PATH}" - -echo "== 1/4 kernel fatobj" -"${PTOAS_BIN}" --pto-arch "${ARCH}" --pto-backend=vpto \ - "${CASE_DIR}/kernel.pto" -o "${OUT_DIR}/kernel.fatobj.o" - -echo "== 2/4 launch object" -"${BISHENG_BIN}" \ - -c -fPIC -xcce -fenable-matrix --cce-aicore-enable-tl \ - -Xhost-start -Xhost-end \ - -mllvm -cce-aicore-stack-size=0x8000 \ - -mllvm -cce-aicore-function-stack-size=0x8000 \ - -mllvm -cce-aicore-record-overflow=true \ - -mllvm -cce-aicore-addr-transform \ - -mllvm -cce-aicore-dcci-insert-for-scalar=false \ - --cce-aicore-arch="${AICORE_ARCH_BASE}" \ - -DREGISTER_BASE -std=c++17 \ - -Wno-macro-redefined -Wno-ignored-attributes \ - -I "${ASCEND_HOME_PATH}/include" \ - -I "${ASCEND_HOME_PATH}/pkg_inc" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/profiling" \ - -I "${ASCEND_HOME_PATH}/pkg_inc/runtime/runtime" \ - "${CASE_DIR}/launch.cpp" \ - -o "${OUT_DIR}/launch.o" - -echo "== 3/4 kernel shared library" -"${BISHENG_BIN}" \ - -fPIC -Wl,-z,relro -Wl,-z,now --cce-fatobj-link \ - -shared -Wl,-soname,libsdma_gm_gm_peer_put_kernel.so \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/libsdma_gm_gm_peer_put_kernel.so" \ - "${OUT_DIR}/kernel.fatobj.o" \ - "${OUT_DIR}/launch.o" \ - -Wl,--no-as-needed -lruntime - -echo "== 4/4 host executable" -"${BISHENG_BIN}" \ - -xc++ -std=c++17 \ - "${CASE_DIR}/main.cpp" \ - -I "${CASE_DIR}" \ - -I "${REPO_ROOT}/include" \ - -I "${REPO_ROOT}/test/comm" \ - -I "${ASCEND_HOME_PATH}/include" \ - -L "${OUT_DIR}" \ - -L "${ASCEND_HOME_PATH}/lib64" \ - -Wl,-rpath,"${OUT_DIR}" \ - -Wl,-rpath,"${ASCEND_HOME_PATH}/lib64" \ - -o "${OUT_DIR}/sdma_gm_gm_peer_put" \ - -lsdma_gm_gm_peer_put_kernel \ - -Wl,--allow-shlib-undefined -lruntime \ - -lstdc++ -lascendcl -lm -lc_sec -ldl -lnnopbase -lhccl -lpthread - -# Building is safe anywhere; running needs a card. Splitting the two lets a -# change be checked for compile errors without putting a device at risk. -if [ -n "${BUILD_ONLY:-}" ]; then - echo "== build only, skipping the run" - exit 0 -fi - -echo "== run PUT on devices ${DEVICE0} -> ${DEVICE1}" -cd "${OUT_DIR}" -# A kernel that never returns holds both devices until the process dies, and -# suspending the shell leaves them held. Kill the run instead, hard if it will -# not go, so a failed case costs a case rather than a card. -set +e -LD_LIBRARY_PATH="${OUT_DIR}:${ASCEND_HOME_PATH}/lib64:${LD_LIBRARY_PATH:-}" \ - timeout --signal=KILL "${RUN_TIMEOUT:-90}" ./sdma_gm_gm_peer_put "${DEVICE0}" "${DEVICE1}" -rc=$? -set -e -if [ "${rc}" -eq 137 ]; then - echo "== killed after ${RUN_TIMEOUT:-90}s; devices ${DEVICE0}/${DEVICE1} may need a reset" >&2 -fi -exit "${rc}" diff --git a/test/vpto/cases/async-comm/sdma_gm_gm.py b/test/vpto/cases/async-comm/sdma_gm_gm.py new file mode 100644 index 0000000000..5f468d59f3 --- /dev/null +++ b/test/vpto/cases/async-comm/sdma_gm_gm.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +# ----------------------------------------------------------------------------- +# case: async-comm/sdma_gm_gm +# target_ops: pto.session_init, pto.sdma_gm_gm +# scenarios: A5 {soft_put} GM->UB->GM, chunk tail, session-driven offset, multicore +# ----------------------------------------------------------------------------- +# +# Only the A5 {soft_put} form of pto.sdma_gm_gm is exercised here, and that is +# deliberate. That expansion is a synchronous GM->UB->GM copy, so the transfer +# is complete when the kernel returns and the result is an ordinary golden +# comparison. The engine form instead posts SQEs and rings a doorbell, which +# needs an async workspace from the AICPU STARS query and a destination that is +# polled rather than read once; neither fits a golden ST harness. The engine +# path and the two-device window shapes stay in test/lit/vpto/async_*.pto. +# +# What the four cases separate is not four kernels but four things the +# expansion has to get right. Three of them share one kernel and differ only in +# the session template the host writes, which is the point: the transfer is +# described by session data, not by the kernel. + +from pathlib import Path +import sys + +import numpy as np + + +def _bootstrap_dsl_st_common() -> None: + here = Path(__file__).resolve() + for candidate in here.parents: + common_dir = candidate / "test" / "dsl-st" + if (common_dir / "common.py").exists(): + sys.path.insert(0, str(common_dir)) + return + raise RuntimeError("Unable to locate test/dsl-st/common.py from sdma_gm_gm.py") + + +_bootstrap_dsl_st_common() + +from common import auto_main, golden_output_case +from ptodsl import pto + + +SEED = 29 + +# Staging chunk the A5 {soft_put} expansion uses per iteration. It is fixed in +# the expansion rather than read from SessionField::BlockBytes, so a transfer +# longer than this is what makes the copy loop run more than once. +SOFT_PUT_CHUNK_BYTES = 32768 + +# Field slots and their values match include/PTO/Support/AsyncSessionABI.h. +# The template is one 8-byte slot per field, so a uint64 array indexed by the +# SessionField value is the whole layout. +_SESSION_FIELDS = 13 +_TMP_BUF_ADDR = 1 +_TMP_BUF_SIZE = 2 +_SYNC_ID = 3 +_CHANNEL_IDX = 4 +_CHANNEL_NUM = 5 +_BLOCK_BYTES = 6 +_COMM_BLOCK_OFFSET = 7 +_ENGINE = 8 +_FLAGS = 11 +_QOS = 12 + +_ENGINE_SDMA = 0 +_FLAG_VALID = 1 +_QOS_DEFAULT = 6 + +# UB base for the staging buffer. Nothing else in these kernels touches UB, and +# UB is private to a core, so every block can stage at the same address. +_UB_TMP_ADDR = 0 + +_SESSION_TYPE = ( + "!pto.struct" +) + +# The destination is the last pointer so the harness can allocate it as the +# golden output. Copy direction is still dst <- src. +SOFT_PUT_SOURCE = f"""module attributes {{pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind}} {{ + func.func @sdma_gm_gm_soft_put( + %src: !pto.ptr, %sess_gm: !pto.ptr, + %dst: !pto.ptr, %nbytes: i64) attributes {{pto.kernel}} {{ + %sess = pto.declare_struct -> {_SESSION_TYPE} + pto.session_init %sess, %sess_gm + : {_SESSION_TYPE}, !pto.ptr + pto.sdma_gm_gm %dst, %src, %nbytes session(%sess) {{soft_put}} + : !pto.ptr, !pto.ptr, i64, {_SESSION_TYPE} + return + }} +}} +""" + +# Each core takes one slice by overwriting SessionField::CommBlockOffset after +# the template load. The offset is written into the session rather than folded +# into the pointers because that is the field the expansion applies to both +# endpoints, so a core that read the template but failed to diverge lands on +# slice zero and is visible as a hole in the destination. +MULTICORE_SOURCE = f"""module attributes {{pto.target_arch = "a5", pto.kernel_kind = #pto.kernel_kind}} {{ + func.func @sdma_gm_gm_soft_put_multicore( + %src: !pto.ptr, %sess_gm: !pto.ptr, + %dst: !pto.ptr, %chunk: i64) attributes {{pto.kernel}} {{ + %sess = pto.declare_struct -> {_SESSION_TYPE} + pto.session_init %sess, %sess_gm + : {_SESSION_TYPE}, !pto.ptr + %bid = pto.get_block_idx + %off = arith.muli %bid, %chunk : i64 + pto.struct_set %sess[{_COMM_BLOCK_OFFSET}], %off : {_SESSION_TYPE}, i64 + pto.sdma_gm_gm %dst, %src, %chunk session(%sess) {{soft_put}} + : !pto.ptr, !pto.ptr, i64, {_SESSION_TYPE} + return + }} +}} +""" + + +@pto.jit( + name="sdma_gm_gm_soft_put", + target="a5", + backend="vpto", + mode="explicit", + source=SOFT_PUT_SOURCE, +) +def sdma_gm_gm_soft_put( + src: pto.ptr(pto.i8, "gm"), + sess_gm: pto.ptr(pto.i8, "gm"), + dst: pto.ptr(pto.i8, "gm"), + nbytes: pto.i64, +): + pass + + +@pto.jit( + name="sdma_gm_gm_soft_put_multicore", + target="a5", + backend="vpto", + mode="explicit", + source=MULTICORE_SOURCE, +) +def sdma_gm_gm_soft_put_multicore( + src: pto.ptr(pto.i8, "gm"), + sess_gm: pto.ptr(pto.i8, "gm"), + dst: pto.ptr(pto.i8, "gm"), + chunk: pto.i64, +): + pass + + +def session_template(*, comm_block_offset: int = 0, sync_id: int = 0): + """Host-written session template, as one uint64 slot per SessionField.""" + slots = np.zeros(_SESSION_FIELDS, dtype=np.uint64) + # SessionField::ContextGm stays zero: it names the channel record table, and + # {soft_put} posts nothing, so no record is ever read. The engine path is + # what needs a real workspace address there. + slots[_TMP_BUF_ADDR] = _UB_TMP_ADDR + slots[_TMP_BUF_SIZE] = SOFT_PUT_CHUNK_BYTES + slots[_SYNC_ID] = sync_id + slots[_CHANNEL_IDX] = 0 + slots[_CHANNEL_NUM] = 1 + slots[_BLOCK_BYTES] = SOFT_PUT_CHUNK_BYTES + slots[_COMM_BLOCK_OFFSET] = comm_block_offset + slots[_ENGINE] = _ENGINE_SDMA + slots[_FLAGS] = _FLAG_VALID + slots[_QOS] = _QOS_DEFAULT + return slots.view(np.uint8).copy() + + +def make_source(nbytes: int): + rng = np.random.default_rng(SEED) + return rng.integers(0, 256, size=nbytes, dtype=np.uint8) + + +def whole_buffer_case(name, *, buffer_bytes, grid=1, kernel=sdma_gm_gm_soft_put): + """A transfer that ends up covering the whole destination buffer.""" + + def make_inputs(): + return [make_source(buffer_bytes), session_template()] + + def make_expected(src, _sess): + return src.copy() + + return golden_output_case( + name, + kernel, + inputs=make_inputs, + expected=make_expected, + # The trailing scalar is nbytes for the single-core kernel and the + # per-core chunk for the multicore one; both are bytes moved per launch + # of one block. + launch_args=lambda src, _sess: [int(src.size) // grid], + grid=grid, + rtol=0.0, + atol=0.0, + ) + + +def offset_case(name, *, buffer_bytes, offset, nbytes): + """A transfer displaced by SessionField::CommBlockOffset on both endpoints.""" + + def make_inputs(): + return [ + make_source(buffer_bytes), + session_template(comm_block_offset=offset), + ] + + def make_expected(src, _sess): + # The offset applies to source and destination alike, so the moved + # window keeps its position and everything outside it stays zero. A + # session read that dropped the field would copy from the base instead + # and shift the window, which this catches. + expected = np.zeros_like(src) + expected[offset : offset + nbytes] = src[offset : offset + nbytes] + return expected + + return golden_output_case( + name, + sdma_gm_gm_soft_put, + inputs=make_inputs, + expected=make_expected, + launch_args=[nbytes], + rtol=0.0, + atol=0.0, + ) + + +CASES = [ + # One staging iteration: the shortest thing that proves the template load, + # the UB round trip, and the MTE2/MTE3 handshake fit together. + whole_buffer_case("sdma_gm_gm_soft_put_single_chunk", buffer_bytes=4096), + # Two full chunks plus a short one, so the loop trip count is above one and + # the tail iteration is clamped to what is left rather than a full chunk. + whole_buffer_case( + "sdma_gm_gm_soft_put_chunk_tail", + buffer_bytes=2 * SOFT_PUT_CHUNK_BYTES + 1024, + ), + # The session, not the kernel, decides where the transfer lands. + offset_case( + "sdma_gm_gm_soft_put_comm_block_offset", + buffer_bytes=8192, + offset=2048, + nbytes=4096, + ), + # Four cores, four disjoint slices, one shared template. The destination is + # only whole if every core resolved its own offset. + whole_buffer_case( + "sdma_gm_gm_soft_put_multicore", + buffer_bytes=16384, + grid=4, + kernel=sdma_gm_gm_soft_put_multicore, + ), +] + + +auto_main(globals()) From 2aeba0675cad7ed7121f91cf981299a9c1623490 Mon Sep 17 00:00:00 2001 From: kerwinair Date: Thu, 27 Aug 2026 12:05:11 +0800 Subject: [PATCH 4/7] fix(ptodsl): keep native_options tests importable without ptoas.mlir The option and command-line tests do not need MLIR bindings; importing launch/codegen at package load time made collection fail on machines that have not built PTOAS yet. Co-authored-by: Cursor --- ptodsl/ptodsl/_runtime/__init__.py | 27 ++++++++++++++++++++--- ptodsl/ptodsl/_runtime/native_build.py | 3 ++- ptodsl/tests/test_native_build_options.py | 7 ++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/ptodsl/ptodsl/_runtime/__init__.py b/ptodsl/ptodsl/_runtime/__init__.py index dc87c808eb..ff1f688dc0 100644 --- a/ptodsl/ptodsl/_runtime/__init__.py +++ b/ptodsl/ptodsl/_runtime/__init__.py @@ -5,13 +5,34 @@ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. # See LICENSE in the root of the software repository for the full text of the License. -"""Private runtime helpers for ``@pto.jit`` launch.""" +"""Private runtime helpers for ``@pto.jit`` launch. -from .launch import LaunchHandle, build_and_load_native_library -from .native_build import build_native_library +Launch code talks to MLIR types. Native-build helpers do not. Keep this +package lazy so a test or caller that only wants command construction does +not need ``ptoas.mlir`` bindings. +""" + +from importlib import import_module __all__ = [ "LaunchHandle", "build_and_load_native_library", "build_native_library", ] + +_EXPORTS = { + "LaunchHandle": (".launch", "LaunchHandle"), + "build_and_load_native_library": (".launch", "build_and_load_native_library"), + "build_native_library": (".native_build", "build_native_library"), +} + + +def __getattr__(name): + try: + module_name, attr_name = _EXPORTS[name] + except KeyError as exc: + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc + module = import_module(module_name, __name__) + value = getattr(module, attr_name) + globals()[name] = value + return value diff --git a/ptodsl/ptodsl/_runtime/native_build.py b/ptodsl/ptodsl/_runtime/native_build.py index 56c4f883c1..158b3bd338 100644 --- a/ptodsl/ptodsl/_runtime/native_build.py +++ b/ptodsl/ptodsl/_runtime/native_build.py @@ -21,7 +21,6 @@ write_manifest, ) from .._native_options import EMPTY_NATIVE_OPTIONS, NativeBuildOptions -from .codegen import generate_launch_cpp, launch_symbol_name from .toolchain import ( aicore_arch_for_kernel_kind, common_include_flags, @@ -378,6 +377,8 @@ def build_native_library( specialization_key, ) -> tuple[Path, str]: """Build or reuse the shared library for one compiled specialization.""" + from .codegen import generate_launch_cpp, launch_symbol_name + ir_function_name = module_spec.function_name artifacts = artifact_paths(py_name, ir_function_name, specialization_key) launch_symbol = launch_symbol_name(ir_function_name) diff --git a/ptodsl/tests/test_native_build_options.py b/ptodsl/tests/test_native_build_options.py index 101a2f8e8e..8ed3b3aa1d 100644 --- a/ptodsl/tests/test_native_build_options.py +++ b/ptodsl/tests/test_native_build_options.py @@ -12,6 +12,7 @@ the build layer is exercised by capturing the commands it would run. """ +import importlib.util import tempfile import types import unittest @@ -25,6 +26,10 @@ ) from ptodsl._runtime import native_build +# KernelModuleSpec and @pto.jit pull MLIR bindings. The rest of this file +# only inspects option records and captured compiler command lines. +_HAS_PTOAS_MLIR = importlib.util.find_spec("ptoas.mlir") is not None + class NormalizeNativeOptionsTest(unittest.TestCase): def test_none_and_empty_mapping_are_empty(self): @@ -177,6 +182,7 @@ def test_a_module_spec_without_the_option_still_builds(self): self.assertIs(native_build._native_options_of(legacy), EMPTY_NATIVE_OPTIONS) +@unittest.skipUnless(_HAS_PTOAS_MLIR, "needs ptoas.mlir bindings") class KernelModuleSpecTest(unittest.TestCase): def test_the_spec_carries_the_options_and_stays_frozen(self): from ptodsl._tracing import KernelModuleSpec @@ -197,6 +203,7 @@ def test_a_spec_without_the_option_defaults_to_none_of_it(self): self.assertTrue(spec.native_options.is_empty()) +@unittest.skipUnless(_HAS_PTOAS_MLIR, "needs ptoas.mlir bindings") class JitDecoratorSurfaceTest(unittest.TestCase): """The decorator kwarg has to reach the spec, and reject bad input early.""" From 47b92c92dde5518f886e4086205819afd8102f8d Mon Sep 17 00:00:00 2001 From: kerwinair Date: Thu, 27 Aug 2026 15:06:46 +0800 Subject: [PATCH 5/7] fix(test): keep engine-spike jit annotations as live objects from __future__ import annotations turned pto.ptr(...) into strings, so @pto.jit rejected the same entry ABI the soft_put ST already uses. Co-authored-by: Cursor --- test/comm/spike_sdma_gm_gm_engine.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/comm/spike_sdma_gm_gm_engine.py b/test/comm/spike_sdma_gm_gm_engine.py index 4461de6dbf..411806631b 100644 --- a/test/comm/spike_sdma_gm_gm_engine.py +++ b/test/comm/spike_sdma_gm_gm_engine.py @@ -55,8 +55,10 @@ # # PTO_ASYNC_ARCH=a5 python3 test/comm/spike_sdma_gm_gm_engine.py # PTO_ASYNC_ARCH=a3 python3 test/comm/spike_sdma_gm_gm_engine.py - -from __future__ import annotations +# +# Do not add ``from __future__ import annotations``. ``@pto.jit`` reads the +# entry annotations at decoration time and needs the live ``pto.ptr`` objects, +# not their string forms. import os from pathlib import Path From afbe5aee766c4d1a2212bf42c08fcf60499d3aea Mon Sep 17 00:00:00 2001 From: kerwinair Date: Thu, 27 Aug 2026 15:09:50 +0800 Subject: [PATCH 6/7] fix(ptodsl): link libstdc++ when host C++ is part of the kernel library bisheng --cce-fatobj-link does not pull the C++ runtime, so a host source that uses std::string failed the kernel .so with undefined cxx11 symbols. Co-authored-by: Cursor --- .../user_guide/03-kernel-entry-and-subkernels.md | 3 ++- ptodsl/ptodsl/_runtime/native_build.py | 4 ++++ ptodsl/tests/test_native_build_options.py | 14 ++++++++++++++ test/comm/README.md | 6 ++++-- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md b/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md index 7ba2daf0a1..83c598dc3c 100644 --- a/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md +++ b/ptodsl/docs/user_guide/03-kernel-entry-and-subkernels.md @@ -303,7 +303,8 @@ Rules worth knowing: not as device code. They cannot contain kernel code. - **`link_libraries` takes bare names.** Pass `"dl"`, not `"-ldl"` or a path to a `.so`; directories belong in `library_dirs`, which also become rpath entries so - the library is found again at load time. + the library is found again at load time. Host sources also pull `-lstdc++`, + because `bisheng --cce-fatobj-link` does not add the C++ runtime by itself. - **Undefined symbols remain an error.** The link keeps `-Wl,--no-undefined`, so a library you forgot to name fails the build rather than the first launch. - **`include_dirs` requires `host_sources`.** On its own it would apply to diff --git a/ptodsl/ptodsl/_runtime/native_build.py b/ptodsl/ptodsl/_runtime/native_build.py index 158b3bd338..97365695f0 100644 --- a/ptodsl/ptodsl/_runtime/native_build.py +++ b/ptodsl/ptodsl/_runtime/native_build.py @@ -251,6 +251,10 @@ def _extra_link_flags(native_options: NativeBuildOptions) -> list[str]: for lib_dir in native_options.library_dirs: flags.extend([f"-L{lib_dir}", f"-Wl,-rpath,{lib_dir}"]) flags.extend(f"-l{name}" for name in native_options.link_libraries) + # bisheng --cce-fatobj-link does not pull the C++ runtime. Host C++ objects + # that use std::string, operator new, or static guards need it on the line. + if native_options.host_sources and "stdc++" not in native_options.link_libraries: + flags.append("-lstdc++") return flags diff --git a/ptodsl/tests/test_native_build_options.py b/ptodsl/tests/test_native_build_options.py index 8ed3b3aa1d..637ae1dd1f 100644 --- a/ptodsl/tests/test_native_build_options.py +++ b/ptodsl/tests/test_native_build_options.py @@ -268,6 +268,20 @@ def test_search_paths_precede_the_libraries_that_need_them(self): ) self.assertLess(flags.index("-L/opt/lib"), flags.index("-lcustom")) + def test_host_sources_pull_libstdcxx(self): + flags = native_build._extra_link_flags( + NativeBuildOptions(host_sources=(Path("/tmp/shim.cpp"),), link_libraries=("dl",)) + ) + self.assertEqual(flags, ["-ldl", "-lstdc++"]) + + def test_explicit_libstdcxx_is_not_duplicated(self): + flags = native_build._extra_link_flags( + NativeBuildOptions( + host_sources=(Path("/tmp/shim.cpp"),), link_libraries=("dl", "stdc++") + ) + ) + self.assertEqual(flags, ["-ldl", "-lstdc++"]) + class HostSourceCompileTest(unittest.TestCase): def test_no_host_sources_runs_no_compiler(self): diff --git a/test/comm/README.md b/test/comm/README.md index 9fb66dbf60..51cd5ace5e 100644 --- a/test/comm/README.md +++ b/test/comm/README.md @@ -48,8 +48,10 @@ side how large a session template is; it never says. `async_workspace.py` contains no offsets at all, and adding a session field cannot silently break it. The shim needs no CANN headers or libraries to build, because `AsyncWorkspace` -resolves the toolkit at run time through `dlopen`. `-ldl` is the only link -dependency, so it compiles on a machine with no driver and no card. +resolves the toolkit at run time through `dlopen`. `-ldl` is the only library +the shim names; the kernel build also links `-lstdc++` because the fat-object +link does not pull the C++ runtime. It still compiles on a machine with no +driver and no card. ## The engine-path spike From 1a66b020d9d7819db70f8c605511473d1bb22308 Mon Sep 17 00:00:00 2001 From: kerwinair Date: Mon, 31 Aug 2026 17:10:27 +0800 Subject: [PATCH 7/7] feat(ptodsl): expose session_init and sdma_gm_gm on the Python surface Review asked for a PTODSL API and manual next to the ISA chapter, so kernels can author the ops in explicit mode instead of embedding MLIR. Co-authored-by: Cursor --- docs/isa/micro-isa/19-async-comm.md | 11 ++ ptodsl/docs/user_guide/01-introduction.md | 1 + .../user_guide/04-type-system-and-buffer.md | 3 + .../docs/user_guide/07-data-movement-ops.md | 122 +++++++++++++++++- ptodsl/ptodsl/_ops.py | 3 + ptodsl/ptodsl/_ops_mte.py | 110 +++++++++++++++- ptodsl/ptodsl/_types.py | 14 +- ptodsl/ptodsl/pto.py | 3 +- .../tests/support/docs_fragment_fixtures.py | 12 ++ ptodsl/tests/test_async_comm.py | 85 ++++++++++++ 10 files changed, 360 insertions(+), 4 deletions(-) create mode 100644 ptodsl/tests/test_async_comm.py diff --git a/docs/isa/micro-isa/19-async-comm.md b/docs/isa/micro-isa/19-async-comm.md index 800a1e48e7..d19d33c4c2 100644 --- a/docs/isa/micro-isa/19-async-comm.md +++ b/docs/isa/micro-isa/19-async-comm.md @@ -187,3 +187,14 @@ else: : !pto.ptr, !pto.ptr, i64, !pto.struct ``` + +--- + +## PTODSL + +PTODSL explicit mode exposes the same two operations as `pto.session_init` and +`pto.sdma_gm_gm`. The session type is `pto.async_session_type()`. A session still +cannot be a kernel argument: the host writes the GM template, and the kernel +declares its own struct then fills it. See +[7.7 GM↔GM SDMA](../../../ptodsl/docs/user_guide/07-data-movement-ops.md#77-gmgm-sdma-ptosession_init-and-ptosdma_gm_gm) +in the PTODSL user guide. diff --git a/ptodsl/docs/user_guide/01-introduction.md b/ptodsl/docs/user_guide/01-introduction.md index b7fd37a578..c1bcb867cb 100644 --- a/ptodsl/docs/user_guide/01-introduction.md +++ b/ptodsl/docs/user_guide/01-introduction.md @@ -64,6 +64,7 @@ Python Wrapper L0 user-facing wrapper (NumPy, torch-npu, pure Pyth │ └─ backend="emitc" EmitC backend, mode="auto" only ├─ Tile Ops tile.load, tile.store, tile.add, ... ├─ MTE Ops mte_load / mte_store / mte_gm_ub / ... + ├─ Async GM↔GM session_init / sdma_gm_gm ├─ @pto.tileop matrix products (mad, mte_l1_l0a, mte_l0c_ub, ...) ├─ @pto.tileop row-wise vector math (vlds, vadd, vexp, vsts, ...) └─ @pto.simt scalar-like compute (lds, sts, pointwise blends, ...) diff --git a/ptodsl/docs/user_guide/04-type-system-and-buffer.md b/ptodsl/docs/user_guide/04-type-system-and-buffer.md index f6471030f1..afc9b66a79 100644 --- a/ptodsl/docs/user_guide/04-type-system-and-buffer.md +++ b/ptodsl/docs/user_guide/04-type-system-and-buffer.md @@ -115,6 +115,9 @@ Python `int` literals can initialize integer and floating-point fields; Python ` Structs cannot be used as `@pto.jit`, `@pto.tileop`, or `@pto.simt` parameters, or as `pto.for_(...).carry(...)` state. A struct declared outside an ordinary `pto.for_` may be read and mutated inside that loop. Struct values also cannot be returned, yielded, or passed as function arguments from their declaring scope. +`pto.async_session_type()` is the 13-field session used by `pto.session_init` and +`pto.sdma_gm_gm`. See [7.7 GM↔GM SDMA](07-data-movement-ops.md#77-gmgm-sdma-ptosession_init-and-ptosdma_gm_gm). + ## 4.2 Vector register type Vector registers hold a fixed 256-byte payload. `pto.vreg(dtype)` infers the element count automatically: diff --git a/ptodsl/docs/user_guide/07-data-movement-ops.md b/ptodsl/docs/user_guide/07-data-movement-ops.md index b378212f36..2d96366bba 100644 --- a/ptodsl/docs/user_guide/07-data-movement-ops.md +++ b/ptodsl/docs/user_guide/07-data-movement-ops.md @@ -1,6 +1,6 @@ # 7. Data Movement Operations -This chapter covers every operation that moves data between memory spaces in PTODSL — tile-level transfers, DMA micro-instructions, vector loads and stores, and cube data movement. Operations are organized by abstraction level: tile ops for auto mode, DMA orchestration for explicit mode, vector memory ops on the SIMD unit, and cube memory ops on the Cube unit. +This chapter covers every operation that moves data between memory spaces in PTODSL — tile-level transfers, DMA micro-instructions, vector loads and stores, cube data movement, and GM↔GM engine copies. Operations are organized by abstraction level: tile ops for auto mode, DMA orchestration for explicit mode, vector memory ops on the SIMD unit, cube memory ops on the Cube unit, and session-driven GM↔GM copies. ## 7.1 Tile-level movement: tile.load and tile.store @@ -1600,3 +1600,123 @@ def vector_consumer( c2v.free(entry, split=0) pto.tile.store(b_tile, b_part) ``` + +## 7.7 GM↔GM SDMA: `pto.session_init` and `pto.sdma_gm_gm` + +These two operations copy a contiguous GM range through the SDMA engine. They +are explicit-mode only, must sit in an ordinary AICore `@pto.jit` body, and are +illegal inside `@pto.simt` or `pto.section.simt`. There is no stride or burst +model: the transfer is one contiguous byte count. + +A session cannot be a kernel argument. The host writes a GM template; the kernel +declares its own struct with `pto.async_session_type()` and fills it with +`pto.session_init`. Field order and widths match the ISA chapter +[19. Async Communication](../../../../docs/isa/micro-isa/19-async-comm.md). After +the fill, `pto.struct_set` may retune a field. Field 4 is the channel group: a +multi-core launch gives each core its own queue by writing that field rather +than by having the host name the core. + +The kick does not wait for the engine except when `soft_put=True` on A5. The +operation does not publish a completion record; local drain and cross-rank +visibility are arranged by the caller. + +#### `pto.async_session_type() -> StructTypeDescriptor` + +**Description**: The 13-field session type +`!pto.struct`. +Use it with `pto.declare_struct`. + +#### `pto.session_init(session, template_gm) -> None` + +**Description**: Copy the host template into `session` in place. The caller keeps +using the value `pto.declare_struct` produced. Each core fills its own copy, so +a session is per-core even when the template is shared and read-only. + +**Parameters**: + +| Parameter | Type | Description | +|-----------|------|-------------| +| `session` | the 13-field session struct | Destination; written in place | +| `template_gm` | `PtrType` in GM | Base of the host template | + +**Returns**: None. + +**Constraints**: `session` must be `pto.async_session_type()`. `template_gm` must +be a GM pointer. Explicit mode only. + +#### `pto.sdma_gm_gm(destination, source, nbytes, *, session, block_bytes=None, channel_idx=None, soft_put=False) -> None` + +**Description**: Copy `nbytes` contiguous bytes from `source` to `destination` +through the session. Either pointer may address peer memory; peer-ness is the +numeric address, not a pointer attribute. Element types need not match; the +transfer is counted in bytes. + +When `block_bytes` is omitted, the split size comes from the session. When +`channel_idx` is omitted, the channel group comes from the session. `soft_put` +is for a remote write on A5: that generation's engine does not perform a remote +write, so this flag makes the copy complete before the call returns. A2/A3 +ignore it and still post to the engine. + +Without `soft_put`, returning from the kernel does not mean the destination is +visible. The caller observes completion by an agreed host-side check or a later +sync object. + +```text +if soft_put and target is A5: + copy nbytes bytes from source to destination # finished when the call returns +else: + post the copy to the session's engine + return without waiting +``` + +**Parameters**: + +| Parameter | Type | Description | +|-----------|------|-------------| +| `destination` | `PtrType` in GM | Destination range | +| `source` | `PtrType` in GM | Source range | +| `nbytes` | `i64` | Contiguous byte count | +| `session` | the 13-field session struct | Required session | +| `block_bytes` | static `int` or `None` | Split size in bytes; omitted uses the session value | +| `channel_idx` | static `int` or `None` | Channel group for this kick; omitted uses the session value | +| `soft_put` | `bool` | A5 remote-write completion path; default `False` | + +**Returns**: None. + +**Constraints**: + +- `destination` and `source` must be GM pointers. +- `session` must be `pto.async_session_type()`. +- `block_bytes`, when present, must be a positive multiple of 64. +- `channel_idx`, when present, must be in `[0, 39]`. +- Explicit mode only; ordinary AICore entry, not SIMT. + +**Example (local copy):** + + +```python +sess = pto.declare_struct(pto.async_session_type()) +pto.session_init(sess, sess_gm) +pto.sdma_gm_gm(dst, src, nbytes, session=sess) +``` + +**Example (A5 remote write):** + + +```python +sess = pto.declare_struct(pto.async_session_type()) +pto.session_init(sess, sess_gm) +pto.sdma_gm_gm(dst, src, nbytes, session=sess, soft_put=True) +``` + +**Example (per-core channel after init):** + + +```python +sess = pto.declare_struct(pto.async_session_type()) +pto.session_init(sess, sess_gm) +# Field 4 is the channel group. A Python int or an i32 SSA value is legal; +# pto.get_block_idx() is i64 and must be narrowed first. +pto.struct_set(sess, 4, 0) +pto.sdma_gm_gm(dst, src, nbytes, session=sess) +``` diff --git a/ptodsl/ptodsl/_ops.py b/ptodsl/ptodsl/_ops.py index 7308f1682c..1e1de4a2ff 100644 --- a/ptodsl/ptodsl/_ops.py +++ b/ptodsl/ptodsl/_ops.py @@ -575,6 +575,8 @@ mte_ub_l1, mte_ub_ub, raw_fill_l1, + sdma_gm_gm, + session_init, set_atomic_add, set_atomic_bf16, set_atomic_f16, @@ -687,6 +689,7 @@ __all__ = [ "const", "declare_struct", "struct_get", "struct_set", + "session_init", "sdma_gm_gm", "castptr", "addptr", "vlds", "vldas", "vldus", "vldsx2", "vsts", "vstsx2", "init_align", diff --git a/ptodsl/ptodsl/_ops_mte.py b/ptodsl/ptodsl/_ops_mte.py index 79a987998f..3d29858d4b 100644 --- a/ptodsl/ptodsl/_ops_mte.py +++ b/ptodsl/ptodsl/_ops_mte.py @@ -5,7 +5,7 @@ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. # See LICENSE in the root of the software repository for the full text of the License. -"""Data-movement ops: MTE transfers, mad, accumulator-store attributes.""" +"""Data-movement ops: MTE transfers, async GM copies, mad, accumulator-store attributes.""" from functools import wraps import warnings @@ -45,6 +45,7 @@ wrap_surface_value, ) from ._types import ( + _ASYNC_SESSION_FIELD_WIDTHS, _is_struct_type, _isinstance_pto_type, _materialize_integer_literal, @@ -79,6 +80,9 @@ VectorType, ) +from ._ops_core import ( + _require_struct_value, +) from ._ops_common import ( _coerce_i1, _coerce_i32, @@ -529,6 +533,110 @@ def _require_pto_ptr_operand(value, *, context: str): return raw_value +def _require_gm_ptr(ptr_value, *, context: str): + raw_ptr = unwrap_surface_value(ptr_value) + try: + ptr_type = _pto.PtrType(raw_ptr.type) + except Exception as exc: + raise TypeError(f"{context} requires a typed PTO pointer") from exc + gm_space = _pto.AddressSpaceAttr.get(_pto.AddressSpace.GM) + if ptr_type.memory_space != gm_space: + raise TypeError(f"{context} requires a GM pointer, got {raw_ptr.type}") + return raw_ptr + + +def _require_async_session(session, *, op_name: str): + raw_session, struct_type = _require_struct_value(session, op_name=op_name) + fields = tuple(struct_type.field_types) + if len(fields) != len(_ASYNC_SESSION_FIELD_WIDTHS): + raise TypeError( + f"{op_name}: session must have {len(_ASYNC_SESSION_FIELD_WIDTHS)} fields " + f"to match the async session type, but has {len(fields)}" + ) + for index, (field, width) in enumerate(zip(fields, _ASYNC_SESSION_FIELD_WIDTHS)): + if not IntegerType.isinstance(field) or IntegerType(field).width != width: + raise TypeError( + f"{op_name}: session field {index} must be i{width}, got {field}" + ) + return raw_session + + +def _optional_static_i64_attr( + value, + *, + context: str, + minimum: int | None = None, + maximum: int | None = None, + alignment: int | None = None, +): + if value is None: + return None + if isinstance(value, bool) or not isinstance(value, int): + raise TypeError(f"{context} expects a static int or None, got {value!r}") + if minimum is not None and value < minimum: + raise ValueError(f"{context} expects a value >= {minimum}, got {value}") + if maximum is not None and value > maximum: + raise ValueError(f"{context} expects a value <= {maximum}, got {value}") + if alignment is not None and value % alignment != 0: + raise ValueError( + f"{context} expects a multiple of {alignment} bytes, got {value}" + ) + return IntegerAttr.get(IntegerType.get_signless(64), value) + + +@_explicit_mode_only("pto.session_init(...)") +def session_init(session, template_gm): + """Fill ``session`` in place from the host-written GM template.""" + raw_session = _require_async_session(session, op_name="pto.session_init(...)") + raw_template = _require_gm_ptr(template_gm, context="pto.session_init(...) template") + _pto.SessionInitOp(raw_session, raw_template) + + +@_explicit_mode_only("pto.sdma_gm_gm(...)") +def sdma_gm_gm( + destination, + source, + nbytes, + *, + session, + block_bytes=None, + channel_idx=None, + soft_put=False, +): + """Kick a contiguous GM→GM copy through the session.""" + if not isinstance(soft_put, bool): + raise TypeError("pto.sdma_gm_gm(...): soft_put expects a bool") + raw_dst = _require_gm_ptr(destination, context="pto.sdma_gm_gm(...) destination") + raw_src = _require_gm_ptr(source, context="pto.sdma_gm_gm(...) source") + raw_session = _require_async_session(session, op_name="pto.sdma_gm_gm(...)") + attrs = {} + block_bytes_attr = _optional_static_i64_attr( + block_bytes, + context="pto.sdma_gm_gm(...) block_bytes", + minimum=1, + alignment=64, + ) + channel_idx_attr = _optional_static_i64_attr( + channel_idx, + context="pto.sdma_gm_gm(...) channel_idx", + minimum=0, + maximum=39, + ) + if block_bytes_attr is not None: + attrs["block_bytes"] = block_bytes_attr + if channel_idx_attr is not None: + attrs["channel_idx"] = channel_idx_attr + if soft_put: + attrs["soft_put"] = UnitAttr.get() + _pto.SdmaGmGmOp( + raw_dst, + raw_src, + _coerce_i64(nbytes, context="pto.sdma_gm_gm(...) nbytes"), + raw_session, + **attrs, + ) + + @_explicit_mode_only("pto.mte_load(...)") def mte_load(source, destination, l2_cache_ctl, len_burst, *, nburst, loops=None, pad=None): """ diff --git a/ptodsl/ptodsl/_types.py b/ptodsl/ptodsl/_types.py index 70dd2d56f5..d58cba6457 100644 --- a/ptodsl/ptodsl/_types.py +++ b/ptodsl/ptodsl/_types.py @@ -598,6 +598,18 @@ def struct_type(*field_types) -> _StructDescriptor: return _StructDescriptor(field_types) +# Field widths of the async-comm session, matching docs/isa/micro-isa/19-async-comm.md. +_ASYNC_SESSION_FIELD_WIDTHS = (64, 64, 32, 32, 32, 32, 64, 64, 32, 32, 32, 32, 32) + + +def async_session_type() -> _StructDescriptor: + """Return the 13-field session type used by ``pto.session_init`` / ``pto.sdma_gm_gm``.""" + fields = [] + for width in _ASYNC_SESSION_FIELD_WIDTHS: + fields.append(int64 if width == 64 else int32) + return struct_type(*fields) + + def vmi_vreg_type(lanes: int, elem) -> _VMIVRegDescriptor: """Return a lazy descriptor for ``!pto.vmi.vreg``.""" return _VMIVRegDescriptor(lanes, elem) @@ -714,7 +726,7 @@ def part_tensor_view_type_from_dims(dims, elem) -> Type: "si8", "si16", "si32", "si64", "ui8", "ui16", "ui32", "ui64", "index", - "ptr", "vreg_type", "vec_type", "mask_type", "struct_type", + "ptr", "vreg_type", "vec_type", "mask_type", "struct_type", "async_session_type", "vmi_vreg_type", "vmi_mask_type", "tile_buf_type", "tensor_view_type", "tensor_view_type_from_dims", "part_tensor_view_type", "part_tensor_view_type_from_dims", diff --git a/ptodsl/ptodsl/pto.py b/ptodsl/ptodsl/pto.py index 78ecd05493..1a982327bc 100644 --- a/ptodsl/ptodsl/pto.py +++ b/ptodsl/ptodsl/pto.py @@ -34,7 +34,7 @@ si8, si16, si32, si64, ui8, ui16, ui32, ui64, index, - ptr, vreg_type, vec_type, mask_type, struct_type, + ptr, vreg_type, vec_type, mask_type, struct_type, async_session_type, _resolve, ) from ._builtin_vector import Vec # noqa: F401 @@ -87,6 +87,7 @@ from ._ops import ( # noqa: F401 const, declare_struct, struct_get, struct_set, + session_init, sdma_gm_gm, get_op_attr, castptr, addptr, vlds, vldas, vldus, vldsx2, vsts, vstsx2, diff --git a/ptodsl/tests/support/docs_fragment_fixtures.py b/ptodsl/tests/support/docs_fragment_fixtures.py index fcd185e847..cb8fd7c968 100644 --- a/ptodsl/tests/support/docs_fragment_fixtures.py +++ b/ptodsl/tests/support/docs_fragment_fixtures.py @@ -1147,6 +1147,18 @@ def data_movement_grouped_dma_ptrs_probe(): {SNIPPET_PLACEHOLDER} """ ), + "data_movement.async_comm": _fixture( + f""" + @pto.jit(target="a5", mode="explicit") + def data_movement_async_comm_probe( + src: pto.ptr(pto.i8, "gm"), + sess_gm: pto.ptr(pto.i8, "gm"), + dst: pto.ptr(pto.i8, "gm"), + nbytes: pto.i64, + ): + {SNIPPET_PLACEHOLDER} + """ + ), "data_movement.low_precision_vector_memory": _fixture( f""" @pto.jit(target="a5", mode="explicit") diff --git a/ptodsl/tests/test_async_comm.py b/ptodsl/tests/test_async_comm.py new file mode 100644 index 0000000000..49e8d877f8 --- /dev/null +++ b/ptodsl/tests/test_async_comm.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 Huawei Technologies Co., Ltd. +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of +# CANN Open Software License Agreement Version 2.0 (the "License"). +# Please refer to the License for details. You may not use this file except in compliance with the License. +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +# See LICENSE in the root of the software repository for the full text of the License. + +import unittest + +from ptodsl import _types, pto +from ptodsl._context import make_context +from ptoas.mlir.ir import InsertionPoint, Location, Module + + +@pto.jit(target="a5", mode="explicit") +def sdma_gm_gm_surface_kernel( + src: pto.ptr(pto.i8, "gm"), + sess_gm: pto.ptr(pto.i8, "gm"), + dst: pto.ptr(pto.i8, "gm"), + nbytes: pto.i64, +): + sess = pto.declare_struct(pto.async_session_type()) + pto.session_init(sess, sess_gm) + pto.sdma_gm_gm(dst, src, nbytes, session=sess) + pto.sdma_gm_gm(dst, src, nbytes, session=sess, soft_put=True, block_bytes=64, channel_idx=0) + + +class AsyncCommSurfaceTest(unittest.TestCase): + def test_public_namespace_exports_the_surface(self): + for name in ("async_session_type", "session_init", "sdma_gm_gm"): + with self.subTest(name=name): + self.assertTrue(hasattr(pto, name), name) + self.assertIn("async_session_type", _types.__all__) + + def test_async_session_type_matches_the_isa_layout(self): + with make_context() as ctx, Location.unknown(ctx): + resolved = pto.async_session_type().resolve() + self.assertEqual( + str(resolved), + "!pto.struct", + ) + + def test_surface_emits_session_init_and_sdma_gm_gm(self): + text = sdma_gm_gm_surface_kernel.compile().mlir_text() + self.assertIn("pto.session_init", text) + self.assertIn("pto.sdma_gm_gm", text) + self.assertIn("soft_put", text) + self.assertIn("block_bytes = 64", text) + self.assertIn("channel_idx = 0", text) + + with make_context() as ctx: + module = Module.parse(text, ctx) + module.operation.verify() + + def test_rejects_wrong_session_and_pointer_spaces(self): + with make_context() as ctx, Location.unknown(ctx): + module = Module.create() + with InsertionPoint(module.body): + sess = pto.declare_struct(pto.async_session_type()) + other = pto.declare_struct(pto.struct_type(pto.i32)) + gm = pto.ptr(pto.i8, "gm") + ub = pto.ptr(pto.i8, "ub") + # Materialize dummy SSA pointers via castptr so the helpers see values. + zero = pto.const(0, dtype=pto.i64) + gm_ptr = pto.castptr(zero, gm) + ub_ptr = pto.castptr(zero, ub) + + with self.assertRaisesRegex(TypeError, "13 fields"): + pto.session_init(other, gm_ptr) + with self.assertRaisesRegex(TypeError, "GM pointer"): + pto.session_init(sess, ub_ptr) + with self.assertRaisesRegex(TypeError, "GM pointer"): + pto.sdma_gm_gm(ub_ptr, gm_ptr, 64, session=sess) + with self.assertRaisesRegex(ValueError, "multiple of 64"): + pto.sdma_gm_gm(gm_ptr, gm_ptr, 64, session=sess, block_bytes=32) + with self.assertRaisesRegex(ValueError, "<= 39"): + pto.sdma_gm_gm(gm_ptr, gm_ptr, 64, session=sess, channel_idx=40) + with self.assertRaisesRegex(TypeError, "soft_put"): + pto.sdma_gm_gm(gm_ptr, gm_ptr, 64, session=sess, soft_put=1) + + +if __name__ == "__main__": + unittest.main()