diff --git a/.gitattributes b/.gitattributes index 60063c7f9b9e1314d7b9c8e32b199c08446e5c99..b8e4915c68dd29c5b8c320741c97168dd628860d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -714,3 +714,499 @@ cache/processed_dataset/tmpqwuifpar filter=lfs diff=lfs merge=lfs -text cache/processed_dataset/tmpyumlszml filter=lfs diff=lfs merge=lfs -text cache/processed_dataset/tmph_sxw2t9 filter=lfs diff=lfs merge=lfs -text cache/processed_dataset/tmpo2pgb4q7 filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpn6ru3cva filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpvyr_zj73 filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpj5c90n6b filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpt_jtk13w filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpf3h690je filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpyqrsxp1k filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpm3rwp93n filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmp7i456vd6 filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmpc8l05iq6 filter=lfs diff=lfs merge=lfs -text +cache/processed_dataset/tmppt1vhjn7 filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-sft-random-anchor/03-25-02:55:47/diff/qwen3-8b-sft-random-anchor.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-sft/03-25-03:18:08/diff/qwen3-8b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-sft/03-24-02:34:07/diff/qwen3-8b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-sft/03-18-15:34:53/diff/qwen3-8b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-sft/03-23-21:38:24/diff/qwen3-8b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-32b-sft/03-30-15:26:18/diff/qwen3-32b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/docs/spec_bundle/public/logo.ico filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-32b-sft/03-31-00:00:26/diff/qwen3-32b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-8b-dflash-64gpu/03-26-21:09:50/diff/qwen3-8b-dflash-64gpu.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/docs/_static/imgs/specbundle-logo.png filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-32b-sft/03-30-15:37:57/diff/qwen3-32b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/RUN/qwen3-32b-sft/03-30-13:31:08/diff/qwen3-32b-sft.diff filter=lfs diff=lfs merge=lfs -text +syxin_old/Specforge/tests/test_modeling/test_target/test_sglang_backend/images/demo.jpeg filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/train_dflash_lora.log filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/train_dflash_lora.log filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/assets/acknowledgements.png filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/assets/logo.ico filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/assets/logo.png filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpsaud7inh filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpo340xjlj filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpc8k1wpao filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpwokpzxbw filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpl94c7jxi filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpgszlo7oq filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpinvido_z filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpqpwxjunu filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpei5ah9j_ filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpdrvr46bq filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp8uie6nur filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpwq89ng3z filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp1olkr9hg filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpluqfik5a filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp1bg64fz1 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpstdi1exz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp12qwgf9o filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp3zlhgr3y filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp8mzly0vz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp4mtyrhf4 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpo7jb0q89 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpy2x5wfyd filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpfwb2ckp1 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpqs4xxvi3 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp_7409t7u filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmptqvqvpdk filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpdof5i3di filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpu_vaznd1 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp01so9qky filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpn3tpi7x_ filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp2rghitts filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpky8ztc3l filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp5_v0vecp filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpzyqafx5e filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpgr9rw0_h filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpe_yqe1zz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp_c37vzra filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpb5ufd_3k filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp_1rdxt81 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmplx6mijvc filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpu7s66cjj filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpqjqf7u2l filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpfuuhammv filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpfbj_hvmg filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpyhujpj1h filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpwvln4iw8 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpaswc6t6a filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpj1355egn filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpzrflqnck filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpdbim2npk filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp31b6467g filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp1e9_w76a filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp7ap84b3p filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpkx1kbis9 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpk5b32oqt filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpcv0d9wzf filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmph93s_2g1 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp_f0wuxqs filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpjccpfqmi filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpruq5gh5h filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmp839oymis filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpmu8bav05 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/processed_dataset/tmpfz9hw9rn filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/docs/spec_bundle/public/logo.ico filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/7mutgynsdwo6mdvomsqtknzze2dms3p7jpyytzv57pmiysfzeoi filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/docs/_static/imgs/specbundle-logo.png filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/tests/test_modeling/test_target/test_sglang_backend/images/demo.jpeg filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/assets/logo.png filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/assets/logo.ico filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/assets/acknowledgements.png filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ie/fiewkam5s7tpgfnsnrf3ayj3pyf4c53rle7lim2whvqknxjvi3so/3nem6zwnv256cocmodc6wrvlolrx7iseqnvigwtx33tsq2cfzx2 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/lj/fljjn5o6yhgalxerilsjssfuctvvsbjivhyj4s77f4gl7hsgu6px/wdjvlpvmja3nlgla33sismftlk7vytuj7gygjhgzgogtdged7na filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/jfea23gku4yhakqmgavb5xucs2xsfmutdw2mtxtebhcm2vccxrs filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/l6haafig2ocrjlh5jvafvjnnusnfutfmpkejvmgawo542o3u2h3 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/q4dkpcnp66xtouoevwchuv5u5m6ahvmi5w7uvt2hv6nsmrph6xa filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ur/furegr7cnnouau5apv575ga6yeaeaoyxtyi75xwolnjgrklub7pk/kxxtbo6x7i4hrjcm54na72qsazuthc42izqix3a5w2tronyf7ll filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/bqcfmo26ipizieje35jzj3p77l3tamkajdwru37qtzywjwia32d filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/cq/fcq7y7ognlkp6mglgv4dto7rtv2ucev4kwlzqkzfsdektpwroch5/lokxdmwuz6dfo2dywr2emse3yei4vdvxzauxmxedvnd7ibmuiiy filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/lvmozut4mz4puj6rgr3k5y3co2km4ljyehjcaw2o3sjs6ahbfih filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/3r/f3rynbog3ty5tokp7ne5gzlcad2dsp2tdt3xfazjqievpsue24yi/yw3coy32vnorw4tloixata33pzwfkqzvi7gqw4c5ljbvvk4f55j filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/eo/feonriuqattorpyq7qydqtulxbq7viikup5gk2jfkwgn4jo4t3da/yqijcwsdh7szltsgww52htt54towwgkfezt3swuvxh6frqxf6yc filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ia/fial3pyfgpr6yu6rbb4ngfj2efqoptjkzbc5xkgspdgqmqwwtvoz/oiskhzuq6nfzog7awbvlsclh7xt2pfl4badcs5paxngueg3x2to filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/nfsjgw27web6fb5zbkynso5h33xkux3mhozbmivsv74havau77j filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/2t/f2tyfv76cdkhvqiwg2bhtaj5k2bhjbgofjye4bj4zdbzwpp75ist/tjzlo4yrtts7fjzp7w6hv35v2goffyedasp3stcmgqb2o45n5vw filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/cm/fcmuvpflnpx57jjci3fvuwipestyowfk5cygrs5zkn4kju27jklg/gecl4oarfzflfmmqc4olmobba72uoz7rx2yixalfjtdla6ka25v filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rupwxc3oob37htdzmh5rbnfmm2ds7sitswph7v4g6s6pgylyqx/nuw4czyp4quhocn3rd5zh5cnzhk47qwi3p4tbzen3opshfn76nb filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/tp/ftpa47eenzh2y37qv3oxjuo2h2ddd4xzh7lsojdgohxyce6z5bhh/tofa3kmoquvdbbv32vkns3dcydq4rmtryzs55bjkrnotsrrckpe filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/mjwarexf623xgk5xjmz2u6ohk432kj4cilavbtlrqki5uip47ug filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rmkq2tmgi2e3jettmvqroo34bdljlach5zxzke2iesw5lvsw2f/y457u3akysyuggxtftzemzods7yz5wdvkm37z6kxq5monwe2rt3 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/yb/fybhxidrrihf3vhks4wuv6jrwfcpuwx725brem7ufc7tsomyka3w/cgopmtn75c65zo7hrmnr3bfjqjus7d5i5kvnqiq5hwetbqynn62 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/xw/fxwcwpkv4ldzgd7lvvizht2avytq32qqfgf6folnvcmtky7waomn/2nq5xoncppb4wjqp36rtrpvrvpacey7qnx4kpgheswbkrf2swjg filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/lp/flpce5hrjkeamjxahwtiwsrl5ezmzkl4waozen7lvwaqkajp7ib3/dh77wgbhyvaoyqmhd3ik6y3uaozvree5j54bvp7pwmruwkd6hy6 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/3b/f3bzwnfpglfx5lgj5z72xpxl6ct57dgp35fmrra6jkcgqup2f73r/wnhxolcactcqpkweti6kcm4cswi42uqna433darknma7obu7dty filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/vwomrl6y54ugwc5ufyr6szgk3glqd2fifx4i4wsyof2ehuzytz5 filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/6naimkcsh74lxihunjqbffnofd6jp57iwfeo5a7v3uuhhuzy5rd filter=lfs diff=lfs merge=lfs -text +progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/jhc6zp252pqoyff7uiqsdkvrakwalhkt6v4q22bycsog7pdskqz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpqpwxjunu filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpl94c7jxi filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpsaud7inh filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpo340xjlj filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpc8k1wpao filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpgszlo7oq filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpwokpzxbw filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpei5ah9j_ filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpwq89ng3z filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpdrvr46bq filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpinvido_z filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp8uie6nur filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpluqfik5a filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp1olkr9hg filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpstdi1exz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp1bg64fz1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp12qwgf9o filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp3zlhgr3y filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpy2x5wfyd filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpo7jb0q89 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp8mzly0vz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp4mtyrhf4 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpfwb2ckp1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpqjqf7u2l filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpu7s66cjj filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmplx6mijvc filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpfuuhammv filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpfbj_hvmg filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpxzf5tfs9 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpwvln4iw8 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp6wp8_bfz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmplr1d0pbd filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpyhujpj1h filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpv8xdp85p filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpaswc6t6a filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpjp0seuji filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpghrphlfd filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp0h3c1gwr filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpj1355egn filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpo3nudsla filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpqs4xxvi3 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmptj9k8ln1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpi_zlx6tj filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpofiedrhp filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpoftc3flv filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpo7o8udng filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_7409t7u filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpsykkhwag filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmptqvqvpdk filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpdof5i3di filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpndtuj2n8 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpaha5jma4 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpu_vaznd1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp3sts976q filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_76bulc_ filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp01so9qky filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpky8ztc3l filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp2rghitts filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpzyqafx5e filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpn3tpi7x_ filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp5_v0vecp filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpe4nf2zns filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpbdk_etgi filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpgr9rw0_h filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_c37vzra filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpb5ufd_3k filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpdbim2npk filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_1rdxt81 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpe_yqe1zz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp31b6467g filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp7ap84b3p filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpkx1kbis9 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp6fzwc_9i filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp1e9_w76a filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpzrflqnck filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmph93s_2g1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpk5b32oqt filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpcv0d9wzf filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpnf1xv0v2 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_f0wuxqs filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpjccpfqmi filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpmu8bav05 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpfz9hw9rn filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpruq5gh5h filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp839oymis filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp63npd7ym filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpyvnh9pse filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp9wttwm6t filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpicvvi414 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpcyc3tt25 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmplij7ouu8 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp2dv4hduz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpiqh2jriw filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmph2q3gygm filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp_ffbik5a filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpm9ca334x filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpco2q4qoj filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpa508x4ze filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp9w_1gkdb filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpqkt5jm8t filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmplybow6c1 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp8jeu5nng filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp7qa4dv1o filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp5ohq_16m filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpxbmp3uq0 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpzc3wkb46 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmphnnjjotg filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpglpc56el filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpxk7g3wl5 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmp0o0ec5hl filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/6WXRZJRQGRS3D7MVO5SVYMR4F4MLAF4VTB7C2SHACGFYJMY4NEJQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/processed_dataset/tmpd48uryj7 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/0/AHPM575T53TM4HQV4V5KZ3N4M7T2LI4QARYVBJ2FDLAYM7HYU2GA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/EEGOTORDQJ74TDV6XJVAMQZ7E4UU3DBKQIHKSZRLTWFKTHFOOBLQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/PRBQJBNZOLZFMT2AEWRJDPNOUNXSJWSQCNEHKHEMORI73QJVR6NA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/VIWMGOGS6RUP3ZJWMRBPDHBYYKBOZ43UVHGE4CWWPM4U5F2JJ7BA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/TBXXVBGY7UF7OEH7RASYAJMOLF44SCN5DDUSRWDYATGILBUOQIEA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/XSE7P2TJCSCJU4RIGUJ3P36IWHKDIG7MU2LGQTFDAGIVC677DH3A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/DYWW2BIUJCLXNNGAONUQESWDDDUJJKHTFJ2ZAG44H2OVU2QXS5VA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/XVCYZ2MT4MD5AXS3ND3O5PR7BOVQSX4DTTBY2BSA3ZO5WI5Z34QQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/JYX4GK2BP7KTYXHIDAFN5JFDGUL5VJ5KENA3W23PLOMEDKS6NEWQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/HEL2V2TGTTQAZIA4Z6YTLN37YHB3NOHT42672XT6QOAKCALQLPVA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/3l/f3lggduzv5pwulwseetm4wwdiderllahjshwpod3jfhbjdcmd6yt/ajq4hk2uyrdnhtb7luarwz5khpzaipefnotdifkwlwann2cdnwm filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/3fwi4brh2p3anlprrfllgzin3wvy4gzp2pn6bul2vtxxgmgdh6y filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/wz/fwzmf5l4gyt56dkjxwl5xoirzqqypidknvqkycjdabxr23ezebeb/xrsmps3tltlxfvft23w7eeow4jzwsyrumfjxybmqynlymnvs6ei filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/w5q3rsxtn2tzqbjvs4d776srueplh42a7l2j6jltgwq452rwtmu filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/docs/spec_bundle/public/logo.ico filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/vj/fvjfjft7d6mo6v37umkszch3htlazwqe7e52o6lrvwkkz3lw6wyk/hcmylcee2flky2isv5y4z46z2kr7n6666gzl5qw3rfuqbz6qova filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/q6lr5t6lrzm3kjbg7m2jlcyzljenwuyjv5wyyef3jt2oqfyigpn filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/docs/_static/imgs/specbundle-logo.png filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/eb/febaryantvlm6i2jih2ze7cfhxe7icwidoj72pogfovczxo3zbuw/57itk2igg24eo3yh3ivnrjwqtxza3ecpgpra6lhgiqd2dd5f73w filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/bmaks7dbsdlk7bgt5sigxtxyk7ltijhs3ghstlz3zaitczi76vm filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/wu/fwubrvhvgdtams45z2xkpp3u2ajvgzhip62jpdgn2syy3kvplhlk/x5alss7uk3eguh6t5izxaqpkgymsqpy46uhuu54v7rfi5xvfwk2 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/o2/fo26te7t3oshxa674c52lzjedmytpzr4slolgnqt32tklhc65ydz/wnm43z2nmgfvtm4ch76el2xnkzdko3aant5mb23svaviq7yakod filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/3wqg7mzts7n6nz34xe6c4egb6g4hlxchd3ribvwcx6ahv4cwgrx filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/hpi3s6uzbzjqx4pnx42mkhcf7ux374gaq3tawxbspxxh6h27dsy filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ig/fig44juv4tjlo3l5cwx4hhzdllqc2ouhpkivltmpw23drnzrvrp7/7uqoqee55jaq3h6uryiwcuoxwojslgqe4etecsjdafaixeyh7kz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/xm/fxmkiw56bdl4kzy3fp7dzbbqsukmfq3pmkvw56w6hrflwa4blgpm/vdpjpb5qrgqidv4fa3gscsoicwr37y6lgtcabds5txk3go24izx filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/m5/fm5swdd67jpmjm2nduj3j3l6q4ubwbfasci3sljom5gr6fortwxn/y6z6hp4mpuutvywh7n37vvb6wwbqoeehb4psgehly3uh5tviull filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ym/fympkqo6hxovnotwgugq4d2hhnqoid5pxffnoa4nku7cxs5uvazh/r4shmei73tssgyiqta3wmrk2flgtqi3otrrdsz6vweo6w7wq3wu filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/qg/fqgkekhf4m7vmri4ew5v3jufxenpvtb2hnaaodulm4d7ohbbc2c5/gvvpef5dp63zfmoghewiponfb4evle45gf2cp55jjfs4gbzljs7 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/exlebcsez7wjsgpeavs6uok5kfd5prixp5poeo3fwx7rfzagtjm filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/y2/fy2wi7wdwwppm5lgqiwqi4u3yylezkc7owdmacir4jxwgm23l6gb/lkuluxl3usdoarwbrb5lfah2hm6pnqctsjellpwrqlx24gx5p5w filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/7j/f7jcvdbb2n5ul3vmi2bzdd226v4uh5wvgamslrt4pea3ibhajdfj/alkgoghh4ogayw7omi5jrqhy5eoqh4k73ak22ny63ls6fadptpq filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvlte35ajgkob7uec6c5kswyiithjqgw7qttbr2zkd27p5o5phx/6ns6yqvl7uybplheykfjip6vme47ftdgwxkbijerswchee5ig6s filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/tnv6pghqtdbkuwwujswnwbvuubf4g22fb26jlhduynoq4ec26vl filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/vpvs2qkk525pfre24vao542e5mw2reoxotvqkpnnkonj4a6iwyt filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/6e/f6efmj4hhzzathgrxll47wrs57idlkcw6hdituq5thcawharusgk/booxl4wexwlalbvnsinhbwycja2t63kfimny2h4twlwuf4wgrcy filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/__pycache__/server_args.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/mem_cache/__pycache__/memory_pool.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/model_executor/__pycache__/model_runner.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/model_loader/__pycache__/loader.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/managers/__pycache__/schedule_batch.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/managers/__pycache__/tokenizer_manager.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +sglang/python/sglang/srt/managers/__pycache__/scheduler.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq filter=lfs diff=lfs merge=lfs -text +progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh filter=lfs diff=lfs merge=lfs -text diff --git a/cache/hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow b/cache/hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1819c146d414ee1fbc794003caff0692f158fcb8 --- /dev/null +++ b/cache/hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4c52a3bca898cea212d97349d7cafba4c5708d78c9c18110460a2580fe82c41 +size 383573872 diff --git a/cache/processed_dataset/tmp7i456vd6 b/cache/processed_dataset/tmp7i456vd6 new file mode 100644 index 0000000000000000000000000000000000000000..a906793bbd3e6679e0c7245ec86272f36331b902 --- /dev/null +++ b/cache/processed_dataset/tmp7i456vd6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b2d97c36271b384d69f89a69b3e16de1a95243428300bd89602d3e7417cb96eb +size 229547936 diff --git a/cache/processed_dataset/tmpc8l05iq6 b/cache/processed_dataset/tmpc8l05iq6 new file mode 100644 index 0000000000000000000000000000000000000000..8422693c1e968a9087775705d6c70c4c962bb3ed --- /dev/null +++ b/cache/processed_dataset/tmpc8l05iq6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03fb93c4eb5d3c8a57de49997f9efba80dd25b24e5a1e9f761cd9d47eaf52fce +size 200697552 diff --git a/cache/processed_dataset/tmpf3h690je b/cache/processed_dataset/tmpf3h690je new file mode 100644 index 0000000000000000000000000000000000000000..94fd286cf73589b193cdba22faf5314fae86a0f4 --- /dev/null +++ b/cache/processed_dataset/tmpf3h690je @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf6ecee476617dcb6712989449380400a688020c4ec070b9b38ae63748024ec2 +size 199026688 diff --git a/cache/processed_dataset/tmpj5c90n6b b/cache/processed_dataset/tmpj5c90n6b new file mode 100644 index 0000000000000000000000000000000000000000..91bd8ca7d43316883f23071a5346fe91d0d5a15f --- /dev/null +++ b/cache/processed_dataset/tmpj5c90n6b @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:893ea56f808c116d313e3d10ae3f7f677bcbd7d40161e300f18b33f228bd49dd +size 260199576 diff --git a/cache/processed_dataset/tmpm3rwp93n b/cache/processed_dataset/tmpm3rwp93n new file mode 100644 index 0000000000000000000000000000000000000000..e7b8fc3fd7bb22071505cad4749a5aa2f7afd1d2 --- /dev/null +++ b/cache/processed_dataset/tmpm3rwp93n @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b980ebf5eea9894e3189950c51f142f7219582903739084304dc4f6b5a90f11 +size 244945320 diff --git a/cache/processed_dataset/tmpn6ru3cva b/cache/processed_dataset/tmpn6ru3cva new file mode 100644 index 0000000000000000000000000000000000000000..d3a29b8c34903393a90797e4ca7e73b76f16f90d --- /dev/null +++ b/cache/processed_dataset/tmpn6ru3cva @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a87e142fc81ef90d276a4fbfdf88ffee7ede50ca74310095ff1f39bc0d34bf65 +size 200493104 diff --git a/cache/processed_dataset/tmppt1vhjn7 b/cache/processed_dataset/tmppt1vhjn7 new file mode 100644 index 0000000000000000000000000000000000000000..1b2381f877cac510397e66db89c9c31161cb1818 --- /dev/null +++ b/cache/processed_dataset/tmppt1vhjn7 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d9f5d422f9602a6076aaa7062bb6f36cfc3ac5d8c89940e678c674e2ca6d9a35 +size 213663688 diff --git a/cache/processed_dataset/tmpt_jtk13w b/cache/processed_dataset/tmpt_jtk13w new file mode 100644 index 0000000000000000000000000000000000000000..a975ab46905236bb0f6076385972488fb1b3a0ba --- /dev/null +++ b/cache/processed_dataset/tmpt_jtk13w @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c9d25821ea7dec3ab99fbf93d597d1469f0f78e04fb93543f783114768ddb64 +size 231688256 diff --git a/cache/processed_dataset/tmpvyr_zj73 b/cache/processed_dataset/tmpvyr_zj73 new file mode 100644 index 0000000000000000000000000000000000000000..8422693c1e968a9087775705d6c70c4c962bb3ed --- /dev/null +++ b/cache/processed_dataset/tmpvyr_zj73 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03fb93c4eb5d3c8a57de49997f9efba80dd25b24e5a1e9f761cd9d47eaf52fce +size 200697552 diff --git a/cache/processed_dataset/tmpyqrsxp1k b/cache/processed_dataset/tmpyqrsxp1k new file mode 100644 index 0000000000000000000000000000000000000000..c68aa8a6202c38bfe44069c2f9941af609849fe8 --- /dev/null +++ b/cache/processed_dataset/tmpyqrsxp1k @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a6fc9d521f143de18a1178830d173527f5341d99afa136eaacd2efaf02cf73f9 +size 198593600 diff --git a/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00002-of-00004.arrow b/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00002-of-00004.arrow new file mode 100644 index 0000000000000000000000000000000000000000..f2827961a6fb673d71d25eac4ed3d9d453ba5c50 --- /dev/null +++ b/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00002-of-00004.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e7610d98372c92d224e065009b02a5dcab03fa4ed7eb06ab9fb9e788683a6db +size 502423632 diff --git a/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00003-of-00004.arrow b/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00003-of-00004.arrow new file mode 100644 index 0000000000000000000000000000000000000000..b33ba778b9316b411c6116eacd42f097f61a0571 --- /dev/null +++ b/cache/specforge_hf_datasets/json/default-0d1ce9129502772a/0.0.0/52e895adb2834720923967f8c77ff09923a16bd5e2feac52b85c2791e4ae9a18/json-train-00003-of-00004.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ffc2ef2237eaa76b04018063a4c3da0883c9c201f92809bd6c1b4e3cfc351147 +size 397726752 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/cache-f5d498361a6179cf.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/cache-f5d498361a6179cf.arrow new file mode 100644 index 0000000000000000000000000000000000000000..71e065813fc02f45cc02ff192b4e9833a05c8879 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/cache-f5d498361a6179cf.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7da225ef3693c95dac9390a70cb77c922fbe6685a1bd1a29c2e5b809e794784 +size 6667256 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..09faaa89a4c92fc22622bd6c4af183307806d794 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:618b364c726771597e4647c2b9bbcd09903b12981798ebe361c0cbbbe6e3fcaf +size 582024520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..44d41b99ad7e82c351d8cb4e48ee022a85e82302 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d266ca7c9206a50dcdb568e9add4ef3d05a776d103bb329d7cf7a44c0a20744 +size 589172104 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..d264b911d72ad2d5058306e396a8aa9237a4af86 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:191d458a911abce21a1dd418de7d6a4beb6ac65f2342e1a4f32c1b6cf4fda5ee +size 584427016 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8159aaf0e39116369eeec08e8d581edae580c1fb --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26c71cba85285ccc0013a72eb2a149db89b83573c69695c0c9fb0e26bcaba068 +size 586016520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..de9a6a74ee4f556fb6004c8f8d14315dedaa02fd --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:929a1dd67583cf96c1a6410b265415fc3ab9e474de88a58e94fdb8634f6d9e33 +size 569573952 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..14149a5c3428a360e0b12bb27a7f942e897924d5 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56febaeef3cd3826a91ed09ebc22b09fc6c10e8c301ddaa8786b9f220cc39320 +size 585567288 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1819c146d414ee1fbc794003caff0692f158fcb8 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/05739817f2623ade/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4c52a3bca898cea212d97349d7cafba4c5708d78c9c18110460a2580fe82c41 +size 383573872 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..09faaa89a4c92fc22622bd6c4af183307806d794 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:618b364c726771597e4647c2b9bbcd09903b12981798ebe361c0cbbbe6e3fcaf +size 582024520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..44d41b99ad7e82c351d8cb4e48ee022a85e82302 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d266ca7c9206a50dcdb568e9add4ef3d05a776d103bb329d7cf7a44c0a20744 +size 589172104 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8159aaf0e39116369eeec08e8d581edae580c1fb --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26c71cba85285ccc0013a72eb2a149db89b83573c69695c0c9fb0e26bcaba068 +size 586016520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..de9a6a74ee4f556fb6004c8f8d14315dedaa02fd --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:929a1dd67583cf96c1a6410b265415fc3ab9e474de88a58e94fdb8634f6d9e33 +size 569573952 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..14149a5c3428a360e0b12bb27a7f942e897924d5 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/1508750ffa3e5770/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56febaeef3cd3826a91ed09ebc22b09fc6c10e8c301ddaa8786b9f220cc39320 +size 585567288 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1819c146d414ee1fbc794003caff0692f158fcb8 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/6f09ac7f105d6442/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4c52a3bca898cea212d97349d7cafba4c5708d78c9c18110460a2580fe82c41 +size 383573872 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/785dc79f2cc830cc/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/785dc79f2cc830cc/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1819c146d414ee1fbc794003caff0692f158fcb8 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/785dc79f2cc830cc/nemotron-code_alpaca-qwen3-8b-800_k-train-00006-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f4c52a3bca898cea212d97349d7cafba4c5708d78c9c18110460a2580fe82c41 +size 383573872 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..44d41b99ad7e82c351d8cb4e48ee022a85e82302 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d266ca7c9206a50dcdb568e9add4ef3d05a776d103bb329d7cf7a44c0a20744 +size 589172104 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8159aaf0e39116369eeec08e8d581edae580c1fb --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26c71cba85285ccc0013a72eb2a149db89b83573c69695c0c9fb0e26bcaba068 +size 586016520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..14149a5c3428a360e0b12bb27a7f942e897924d5 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/cd6d1d1fcb1efac4/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56febaeef3cd3826a91ed09ebc22b09fc6c10e8c301ddaa8786b9f220cc39320 +size 585567288 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/cache-8aa5c7bd2d0eb16a.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/cache-8aa5c7bd2d0eb16a.arrow new file mode 100644 index 0000000000000000000000000000000000000000..da8af1014ff35ebdb2e376c17b87a609371c0c77 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/cache-8aa5c7bd2d0eb16a.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0208107a39cd2f7cb0798767dbfaf5ee2b65e9b0504a789149b8ba5c85266d96 +size 6667256 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..09faaa89a4c92fc22622bd6c4af183307806d794 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00000-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:618b364c726771597e4647c2b9bbcd09903b12981798ebe361c0cbbbe6e3fcaf +size 582024520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..44d41b99ad7e82c351d8cb4e48ee022a85e82302 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00001-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d266ca7c9206a50dcdb568e9add4ef3d05a776d103bb329d7cf7a44c0a20744 +size 589172104 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..d264b911d72ad2d5058306e396a8aa9237a4af86 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00002-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:191d458a911abce21a1dd418de7d6a4beb6ac65f2342e1a4f32c1b6cf4fda5ee +size 584427016 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8159aaf0e39116369eeec08e8d581edae580c1fb --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00003-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:26c71cba85285ccc0013a72eb2a149db89b83573c69695c0c9fb0e26bcaba068 +size 586016520 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..de9a6a74ee4f556fb6004c8f8d14315dedaa02fd --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00004-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:929a1dd67583cf96c1a6410b265415fc3ab9e474de88a58e94fdb8634f6d9e33 +size 569573952 diff --git a/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow new file mode 100644 index 0000000000000000000000000000000000000000..14149a5c3428a360e0b12bb27a7f942e897924d5 --- /dev/null +++ b/cache/specforge_hf_datasets/nemotron-code_alpaca-qwen3-8b-800_k/default/0.0.0/fe1fbc8359f643e5/nemotron-code_alpaca-qwen3-8b-800_k-train-00005-of-00007.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56febaeef3cd3826a91ed09ebc22b09fc6c10e8c301ddaa8786b9f220cc39320 +size 585567288 diff --git a/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/aime_2024-train.arrow b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/aime_2024-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8d8e2cab6923cc9af39a4edfc0584112c5e002d4 --- /dev/null +++ b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/aime_2024-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c4dc97e685f2992dcc2313e595bcde057e14b9f2681890e766f93afcd5e9886b +size 140840 diff --git a/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-92f1678ec37e4020.arrow b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-92f1678ec37e4020.arrow new file mode 100644 index 0000000000000000000000000000000000000000..e08f0a6d7e196e6028c39ed30add505858ac7182 --- /dev/null +++ b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-92f1678ec37e4020.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c74d2f0e1a2540b53569637189dffbf6c6b21fcf1ae5e41670e8f5dd9c6bb420 +size 153576 diff --git a/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-bc2a645bcf791b9e.arrow b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-bc2a645bcf791b9e.arrow new file mode 100644 index 0000000000000000000000000000000000000000..880861d764df34e72f2ecb8e56f528d33270ded3 --- /dev/null +++ b/datasets/HuggingFaceH4___aime_2024/default/0.0.0/2fe88a2f1091d5048c0f36abc874fb997b3dd99a/cache-bc2a645bcf791b9e.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7676f35f4556ef2967e22afe3b141b3d793110923787f7fc507a903ed7a78760 +size 153576 diff --git a/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-1a3e2744ae2e441d.arrow b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-1a3e2744ae2e441d.arrow new file mode 100644 index 0000000000000000000000000000000000000000..17d850e5a1bc3865f942aac17c8ea147f8594282 --- /dev/null +++ b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-1a3e2744ae2e441d.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45cfc6973c3408a4fad66edbb216e8ddebd3513f629260a08044a8fdeaf6cd98 +size 4448 diff --git a/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-34e13cacf2ebe3aa.arrow b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-34e13cacf2ebe3aa.arrow new file mode 100644 index 0000000000000000000000000000000000000000..59601a3f1f37772e7f4770f588410f74701877ea --- /dev/null +++ b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-34e13cacf2ebe3aa.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc63c661207104a2d8feaea2a7fb548f036c1d26f14f9638de15afcab7dbe580 +size 539328 diff --git a/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-9d6e905bffffcc02.arrow b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-9d6e905bffffcc02.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8653be8f6773f8aaea8b39db1d1570ed6584d154 --- /dev/null +++ b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/cache-9d6e905bffffcc02.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:188b7ed849537e48566c4b90ff1c9d9523994e5c281bc3107cf0f68b7a9e38a9 +size 539328 diff --git a/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/math-500-test.arrow b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/math-500-test.arrow new file mode 100644 index 0000000000000000000000000000000000000000..0b4afa18a8dd7cd04bddbd0048d79cf16566ad17 --- /dev/null +++ b/datasets/HuggingFaceH4___math-500/default/0.0.0/6e4ed1a2a79af7d8630a6b768ec859cb5af4d3be/math-500-test.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff2663846092b986df3026f53904030cbaf8e061c9f978d319a7bd86b3a04ea4 +size 401544 diff --git a/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-5df493b096fe3342.arrow b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-5df493b096fe3342.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1ce892c7820cf8e3086930b1c18f18342bbeb4fb --- /dev/null +++ b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-5df493b096fe3342.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c07da2addc9d12cf66c84ff8daf82c3e0474856ec54b5769711ed7eecde855db +size 80472 diff --git a/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-7e280d73495c0e4e.arrow b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-7e280d73495c0e4e.arrow new file mode 100644 index 0000000000000000000000000000000000000000..081c601d6c3d2fd84e14b53e03bbe1482700ca6d --- /dev/null +++ b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/cache-7e280d73495c0e4e.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1969fb331c376c3892975b8e8289f08df78ab4ac6ed0bf5f386c1197bee82c77 +size 80472 diff --git a/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/mt_bench_prompts-train.arrow b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/mt_bench_prompts-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..77ec77b27cb64754a7bad25272ac2809b068e398 --- /dev/null +++ b/datasets/HuggingFaceH4___mt_bench_prompts/default/0.0.0/e3a795c5e9a82ee40611c416b8a7786c73198991/mt_bench_prompts-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38a168b9c52845c343110124841c251cc1c7d6f31bee8dea01c31d2b0a9e849e +size 46776 diff --git a/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/aime_2025-train.arrow b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/aime_2025-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..e683afecd67219cb970a8201528304dd8a8ea430 --- /dev/null +++ b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/aime_2025-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e63212c6a8689c1168c88d0d81189e3e76f34bac741f38fa486aa09a3e69da7 +size 18056 diff --git a/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-098d9a04aaa8f936.arrow b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-098d9a04aaa8f936.arrow new file mode 100644 index 0000000000000000000000000000000000000000..e381f11bbba6e217f529e225874527a4f4c77dd0 --- /dev/null +++ b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-098d9a04aaa8f936.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c1572df322a6f43f8ac862c76d26b23c4040649bf918d6d66aa9d103f2af725 +size 36576 diff --git a/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-d16e3a61cfbb7c95.arrow b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-d16e3a61cfbb7c95.arrow new file mode 100644 index 0000000000000000000000000000000000000000..4b00ec12e9b6554025992d6e257985e36e411593 --- /dev/null +++ b/datasets/MathArena___aime_2025/default/0.0.0/beca2d7875cf92cdac07acefbccad3c4d16e2916/cache-d16e3a61cfbb7c95.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03c9c908c1532345fb19997d102b0274d68997fae3590508b3d4accbcaf5bbe9 +size 36576 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K-sampled/data/train-00000-of-00001.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K-sampled/data/train-00000-of-00001.parquet new file mode 100644 index 0000000000000000000000000000000000000000..bffa1b9e3beca73571413dded1301c0c27badafc --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K-sampled/data/train-00000-of-00001.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1f7c5b6775e20ca54f2929a77c756276e91c3b17badcd81338a70a5929aa934 +size 433784138 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00000-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00000-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..9370fe65705a6460806e5692dcfdeee8467e8c48 --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00000-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3fcf997158822d2a5ae919346face72a687644f3903df6e57dad46fe4a5c26bd +size 224464598 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00001-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00001-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..f55c1ea5c76d681bf671712307fba13cb4e0feee --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00001-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ef05d8a14a9cc8d9d0bcccd71550a8f5e642eea5c86ff9c95877563ff503c4fd +size 225477668 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00002-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00002-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..5c399a34cca15a027c9416ffaec5cb585a2c0bb0 --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00002-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:703801b7d2f23a5f56d7ab091df7b2906bf3818cf39b942b74470e1a04cb20f7 +size 224536154 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00003-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00003-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..b61f69822fa8131a624bdde0eddfd2b474397f6f --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00003-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8227736fded5461051a6b298bcd0a4fe4447c4186ea3b667a751526bad44d927 +size 224887383 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00004-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00004-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..fc9d5abb69db99a4dd466025eabe29741a897b64 --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00004-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b420379bf3da273521e25dd31712f1c3173c8dbdfc42a94e6183702f3984942f +size 224684194 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00005-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00005-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..fb6be9ef827599bcb1a3507917fbe60011aa965d --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00005-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3aa207517757ea64f46be314482552748826336290ccd1ffced651ab91b416bd +size 225549790 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00006-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00006-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..3511a63610059acb51718578c8585d72c1889df6 --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00006-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:491fc8ae8b60e8d82e0212e0ed7785aa698d991e6cdce1c8741e8f883c83ee4e +size 224557238 diff --git a/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00007-of-00008.parquet b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00007-of-00008.parquet new file mode 100644 index 0000000000000000000000000000000000000000..dc616fcbc17a8978b87c037b77fdda122a7c7cf0 --- /dev/null +++ b/datasets/Nemotron-CodeAlpaca-qwen3-8b-800K/data/train-00007-of-00008.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fda126bc4cee80a4c4d71fdc90dc16531b974f78e81affd60544462341ff9e5c +size 224450794 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-031288cfa98091fc.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-031288cfa98091fc.arrow new file mode 100644 index 0000000000000000000000000000000000000000..4419584abc2bff564dab52ae237ec85cf9044eb4 --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-031288cfa98091fc.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad262f54a52a4e9a8d732b239b09c8eddd41923df8e824c4ab42652921059abb +size 2504 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-8946c8973a65d390.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-8946c8973a65d390.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5092203e9035242d914c5b824fe7ede870ba504e --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-8946c8973a65d390.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:310343b40eae73f5f9faaa6e6466cb61712b22d44b0b8bbae1e46cd9a1e14494 +size 158976 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-ccaa8a4e7a992efd.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-ccaa8a4e7a992efd.arrow new file mode 100644 index 0000000000000000000000000000000000000000..42d2947ca5d7f86d12f9d334cbd1f3dd260458c1 --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/cache-ccaa8a4e7a992efd.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c16499aeffa4d0de6926d6f89ed183171455cdf0ec8a029d8fc5d29ad7d8437c +size 158976 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-prompt.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-prompt.arrow new file mode 100644 index 0000000000000000000000000000000000000000..6dfa80a2e4637422e892d639050e8dc713637ae3 --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-prompt.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7004d238f9498bfced3c43ce07ef62d45db62621a21583eeadbb28e62144611b +size 4928 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-test.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-test.arrow new file mode 100644 index 0000000000000000000000000000000000000000..f661a014de998ec2ff24e46e289a293ca6f194df --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-test.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c9863a9ff3f38516ecc59837f0cbdd0eca9bc3b474c2eb6d2d29f0449c30f1b +size 134240 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-train.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1c9777fb80b2282c61edf4983254ecc718147181 --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea47447396ce3a7dfa90b0a2d3654f93f7a42b36365edd37f35596227a3cd26a +size 64992 diff --git a/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-validation.arrow b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-validation.arrow new file mode 100644 index 0000000000000000000000000000000000000000..67d23336e9797b4d33c8daafa6ec19a9d644235d --- /dev/null +++ b/datasets/google-research-datasets___mbpp/sanitized/0.0.0/4bb6404fdc6cacfda99d4ac4205087b89d32030c/mbpp-validation.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4e1513fd6073efeefc2fff2cbc9bbe6b7eee76c15ea81f376291968e0c38fbd +size 21584 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-33a0b840f1aa1004.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-33a0b840f1aa1004.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8cdccb6fbe834f44c46f3bb0907e49fb2ba7ff0b --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-33a0b840f1aa1004.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f171da87317d5acab3c1567725dc316df4e14c137a449e56ec0955274739dd4e +size 9032 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-7045207c5ed1f0fe.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-7045207c5ed1f0fe.arrow new file mode 100644 index 0000000000000000000000000000000000000000..6f497b4f72db3621bf2b1e26fe827f89888c5161 --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/cache-7045207c5ed1f0fe.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1650240ce639d192d346ef748d8129d4607b9a3cd27a277aa35a0198765593d5 +size 1941624 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00000-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00000-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..4845afaa5ec5c951f8a4d9e5ed31899aabeefa69 --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00000-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:699240682b0e392adee94f127778bdb27e7422647eada8d59d4043d9cb790c5b +size 503203360 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00001-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00001-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8149511f12d0fac08a18888db807266f7a928314 --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00001-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01eb93bf598eff94c5e0f9f9c7b83d22b992747a48823ba3a182b455d639b99b +size 546791920 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00002-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00002-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..7c25a0579f71c6a0066ab54df14bd36051fc276b --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00002-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e1e7d18c07ebf87266283a0b6f1ef53661a4fa85b7f21640054a8e07d4a38878 +size 522245968 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00003-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00003-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..e7656f303013b453ee33cdc649ff728a9d16058f --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00003-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d926aaae7678b729fa9931e85bfd8274792e24d919420def3d32334399959e0e +size 501481056 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00004-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00004-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..53190f1bc164ae2ca9203781a1753ca74467a3cf --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00004-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2532466b438851d4facdcfe0553826b448765bf75260d1890d3adf95d306f8f8 +size 500426896 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00005-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00005-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..80607f3eadb73be9a3d727d0b559997ba10f1ebc --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00005-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f081cd4dd379964ed291df141cf4fed86bc4c60f49bea2815e9f70f6417976d7 +size 525836040 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00006-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00006-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5f63728608473c522ecd9d295ca40aa0bee6b90c --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00006-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8c634ac26d737b4ab37111d43b562ff2e01a71dbdd1c29ad7d7bcbcfb22d1c5 +size 506767280 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00007-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00007-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..3c1d195de13140a9c1b6c251e5108292339d3e6b --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00007-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81cfc2d1c21b0871ecd53ed7d918fbf5198f34e1cc4f6c9eb5011602ef0799ec +size 513350336 diff --git a/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00008-of-00009.arrow b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00008-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..b15c64bb873360785a33bc87dd9026b83609c463 --- /dev/null +++ b/datasets/json/default-3ab01998402731b9/0.0.0/911f53f3a8bbb79dd3d2b0c0d747d5e4ad3e32a9a44df7ed4ff47427ea2b3d71/json-test-00008-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f7b42031dc448fbace286dba4bcb3198e38905ccacbfb4cd89754bf841c688f +size 365718312 diff --git a/datasets/livecodebench_local/cache-1a45653bd9b058bd.arrow b/datasets/livecodebench_local/cache-1a45653bd9b058bd.arrow new file mode 100644 index 0000000000000000000000000000000000000000..f3db53a9919a01ba43152c6ecf46b1419f3d7d3c --- /dev/null +++ b/datasets/livecodebench_local/cache-1a45653bd9b058bd.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b746fec797856ce770fe94b826ec5247b03ef9245e75ccbf0c019330852f2f3d +size 1556360 diff --git a/datasets/livecodebench_local/data-00000-of-00009.arrow b/datasets/livecodebench_local/data-00000-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..ffbb2ddafe6276d21be143beb5f3943cd973094f --- /dev/null +++ b/datasets/livecodebench_local/data-00000-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69fc098d8c04bfea7193d333a261d7d912213e81acd586bfadc0597865a95be4 +size 76056728 diff --git a/datasets/livecodebench_local/data-00001-of-00009.arrow b/datasets/livecodebench_local/data-00001-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5158e60e821d9f30ed12191deac32d4c9c690428 --- /dev/null +++ b/datasets/livecodebench_local/data-00001-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b98d578ebe1f5b72dfed535d678be2109114cf6681f21cb9b977cdfaf56b3261 +size 367105496 diff --git a/datasets/livecodebench_local/data-00002-of-00009.arrow b/datasets/livecodebench_local/data-00002-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..3ee94e8ac00b4a5cc843616632c5200d21dcca97 --- /dev/null +++ b/datasets/livecodebench_local/data-00002-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bad01778e037b3352559275d4c34f422021556acc07c3786e88f8852f22b522d +size 563982376 diff --git a/datasets/livecodebench_local/data-00003-of-00009.arrow b/datasets/livecodebench_local/data-00003-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1b97b2a915276a63fdf9001ec10e54c08cba251d --- /dev/null +++ b/datasets/livecodebench_local/data-00003-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:16e9c8615fac5825a6285b64e86076cc558310b82c3a9edb6fc03a46336552db +size 915183360 diff --git a/datasets/livecodebench_local/data-00004-of-00009.arrow b/datasets/livecodebench_local/data-00004-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..b01afea5dfb544a4ceee9c8306258fd79c876b77 --- /dev/null +++ b/datasets/livecodebench_local/data-00004-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0a396dfb40d4df977f76f6ea9a8f29ef9f042d81e971af32492b827829e17a1a +size 644244464 diff --git a/datasets/livecodebench_local/data-00005-of-00009.arrow b/datasets/livecodebench_local/data-00005-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..88500ac054b221c23019cbac5feb24623de8647f --- /dev/null +++ b/datasets/livecodebench_local/data-00005-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:759c99fcea7b8ad95abf0e1c37f37ffacd9652da854ed19d44bc58354759c486 +size 1214279368 diff --git a/datasets/livecodebench_local/data-00006-of-00009.arrow b/datasets/livecodebench_local/data-00006-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..a2246d8a9aef4a2db542061d93a896b5ceee39ef --- /dev/null +++ b/datasets/livecodebench_local/data-00006-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:07f4ff5796fbdb4ba651ea432088c333bec164bfa9ed0dff650b4ba68baf7abe +size 522766136 diff --git a/datasets/livecodebench_local/data-00007-of-00009.arrow b/datasets/livecodebench_local/data-00007-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..b217073986d5819186b1d919891ebf8dae376e1b --- /dev/null +++ b/datasets/livecodebench_local/data-00007-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3460e596e526f87d1bc74d2f5ea609360e7c22dd0543fb6d421c268b0676c068 +size 84461112 diff --git a/datasets/livecodebench_local/data-00008-of-00009.arrow b/datasets/livecodebench_local/data-00008-of-00009.arrow new file mode 100644 index 0000000000000000000000000000000000000000..83b93e412cd5a9336ed733b0bf373189e0fb5528 --- /dev/null +++ b/datasets/livecodebench_local/data-00008-of-00009.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:053f149f29b9ab00b51d74cf174a6c5cc72dee4fb7e4c7caa76710868b8b2307 +size 97607008 diff --git a/datasets/mtbench/data/gpt4_pair-00000-of-00001-c0b431264a82ddc0.parquet b/datasets/mtbench/data/gpt4_pair-00000-of-00001-c0b431264a82ddc0.parquet new file mode 100644 index 0000000000000000000000000000000000000000..a0343a02a039e3aafdc414c48bd1e4b90ac8a21c --- /dev/null +++ b/datasets/mtbench/data/gpt4_pair-00000-of-00001-c0b431264a82ddc0.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:57068327ffb5f8fddb15fedbbfe40b26fe862da2326331e5cf64a42320a00e71 +size 649996 diff --git a/datasets/mtbench/data/human-00000-of-00001-25f4910818759289.parquet b/datasets/mtbench/data/human-00000-of-00001-25f4910818759289.parquet new file mode 100644 index 0000000000000000000000000000000000000000..6dc05bf0260259ccfbdb0a1327af4b318a390eb0 --- /dev/null +++ b/datasets/mtbench/data/human-00000-of-00001-25f4910818759289.parquet @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4877bc46a40929f4082c3c79593700fb897b1d6c7f4c473032694a01322f5769 +size 738612 diff --git a/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-4af9050230f1559b.arrow b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-4af9050230f1559b.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5275878970fc5f87b037fa99b78bcba18c228612 --- /dev/null +++ b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-4af9050230f1559b.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e625771edb7cb92627bb9c774152df3f4cd16a625017e925c40b7ab01f1b41eb +size 1135792 diff --git a/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-54633c4d1659caf0.arrow b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-54633c4d1659caf0.arrow new file mode 100644 index 0000000000000000000000000000000000000000..c540dcd4ff14b8ecec83963c90ccb0c9621cdabd --- /dev/null +++ b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-54633c4d1659caf0.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:276325f785d2971ccd78e024c323b3a90eea67cf42167539fe2523361b560644 +size 11144 diff --git a/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-c22a5d12979a8dea.arrow b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-c22a5d12979a8dea.arrow new file mode 100644 index 0000000000000000000000000000000000000000..bf3b9d6201d3d27a7c9d02b318808b6fca690d9a --- /dev/null +++ b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/cache-c22a5d12979a8dea.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c921098f5acb041c74ba7ec06f5b6419cb2948581480b0b43f6ced5d74285cb3 +size 1135792 diff --git a/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-test.arrow b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-test.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5ee59eb3900e3ebd64d0bf2d549cf53b49031f6b --- /dev/null +++ b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-test.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:45965b000311d1550e5619b60b5bf31cf76edebfd8b8eddc62a876fbf8c9be95 +size 714584 diff --git a/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-train.arrow b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..1a2d79b5695c9b04a1b3f3f3b3d97ca66d3ab5a2 --- /dev/null +++ b/datasets/openai___gsm8k/main/0.0.0/cc7b047b6e5bb11b4f1af84efc572db110a51b3c/gsm8k-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6146bca074f4c6c5e07de7e96cc968adab3833dbdafeda21830f27558eea3d9b +size 3965528 diff --git a/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-1694c035a9739f22.arrow b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-1694c035a9739f22.arrow new file mode 100644 index 0000000000000000000000000000000000000000..0faa66792f801bd3a5c5ca96fec2b93d32d751b2 --- /dev/null +++ b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-1694c035a9739f22.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f8ea1761bcaea96ccee9b46892b7804d2cf856fcdddd48a9a973a4249c479901 +size 286896 diff --git a/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-3147e3946d46a594.arrow b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-3147e3946d46a594.arrow new file mode 100644 index 0000000000000000000000000000000000000000..b658fee5cdbbb9e0a51f76475cbc6b1d807e5d0c --- /dev/null +++ b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-3147e3946d46a594.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0eb821194dfff7e5131f00fa25d67e0e1601b01cb2ba866bf32a78749d8dacb1 +size 1760 diff --git a/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-957d2f886716cbd3.arrow b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-957d2f886716cbd3.arrow new file mode 100644 index 0000000000000000000000000000000000000000..7e0f2f6a5d8f33fe33c34fb520a62fdd41343b33 --- /dev/null +++ b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/cache-957d2f886716cbd3.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:615b1572b27db70f6661b10d6c80fb1dd3c326f2dc633fd4ddc9aa018a72f48e +size 286896 diff --git a/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/openai_humaneval-test.arrow b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/openai_humaneval-test.arrow new file mode 100644 index 0000000000000000000000000000000000000000..2948fd38b4bc54bc55fe7e5a888a8b44b28eef97 --- /dev/null +++ b/datasets/openai___openai_humaneval/openai_humaneval/0.0.0/7dce6050a7d6d172f3cc5c32aa97f52fa1a2e544/openai_humaneval-test.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f52943a6aa89b8d973a477910be07b0d41e31f6c3df276a61db6164910cb223d +size 195528 diff --git a/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-2b4e04a9fccfef42.arrow b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-2b4e04a9fccfef42.arrow new file mode 100644 index 0000000000000000000000000000000000000000..13951666421455cb9f409aa8d491780d6c9653df --- /dev/null +++ b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-2b4e04a9fccfef42.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d4258e30171b2c10312be163632178dd68c50e5a6e472e4902671aecb6dc53d2 +size 4042600 diff --git a/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-33858223a05b94d9.arrow b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-33858223a05b94d9.arrow new file mode 100644 index 0000000000000000000000000000000000000000..c4fffa7aea91f58a3758d6c92a382d564885ebf4 --- /dev/null +++ b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-33858223a05b94d9.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:510ffbf0df2cae5dcab86a1633988c6ac46ba2f2efff18e0c92ba43613d421a2 +size 4042600 diff --git a/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-a1e40a1c9bb9cc65.arrow b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-a1e40a1c9bb9cc65.arrow new file mode 100644 index 0000000000000000000000000000000000000000..645600749b27206c3bc06c1c159cf255ac7cecf3 --- /dev/null +++ b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/cache-a1e40a1c9bb9cc65.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64845502fb40e0f7b2f6f3030c2452263f28ffc4375bab472ddcead2e95d3333 +size 2848 diff --git a/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-dev.arrow b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-dev.arrow new file mode 100644 index 0000000000000000000000000000000000000000..ef37f55715621b6c1d9f929855e4fa5d3de89842 --- /dev/null +++ b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-dev.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d3324fb60356445f0ab1136db702ec6921c40b88ae155297edd7e0f18031663 +size 234624 diff --git a/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-test.arrow b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-test.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5cc4c6d783b5072ef747c83a6eacf6c64802bd0d --- /dev/null +++ b/datasets/princeton-nlp___swe-bench_lite/default/0.0.0/6ec7bb89b9342f664a54a6e0a6ea6501d3437cc2/swe-bench_lite-test.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b77fa3036c06219715a35e8088fee13b0b87bc957052546c3270caf38a325627 +size 3523312 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/alpaca-train.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/alpaca-train.arrow new file mode 100644 index 0000000000000000000000000000000000000000..5a7bdae37cfa9c5d768b9cdc1b87d993d6780eac --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/alpaca-train.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f45103036ed651f4c06d0a3c3e0fb7d53acb3074ed5c8e804a69c1efc1cea794 +size 46230248 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-014b9507e3ff0e2d.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-014b9507e3ff0e2d.arrow new file mode 100644 index 0000000000000000000000000000000000000000..6c1a881f27578c1e6e34e90aabf019790cebfa18 --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-014b9507e3ff0e2d.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d374470a324b1df683fedc9f0bb14cd3706fe7457436cb4b554c1c78d8fbc13 +size 423952 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-28c23a5e1a3f3bd6.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-28c23a5e1a3f3bd6.arrow new file mode 100644 index 0000000000000000000000000000000000000000..79c7e0e9a71fde3766735d9f6e25e8f972b40136 --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-28c23a5e1a3f3bd6.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0ecdd87063bc88f9058d2b2fe8cfea48c388a6afa9d45ba9041f4343b13d026 +size 55846944 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-5d022d506c46f97b.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-5d022d506c46f97b.arrow new file mode 100644 index 0000000000000000000000000000000000000000..e28e0a2f093cafd468094ffbaeba552c5c3e0639 --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-5d022d506c46f97b.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d1da126f3cdc15eedf78d9392aa3d5358756a15bbe156e051aa381ee579c4e7 +size 50933096 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-b6df9b70fbb8fe8a.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-b6df9b70fbb8fe8a.arrow new file mode 100644 index 0000000000000000000000000000000000000000..6b9e1f035fd007c2fccdd19126e559325b31fce0 --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-b6df9b70fbb8fe8a.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a16bd11e2ee1a606a610a80b57ad9499bb1d25c02c50d1e0020237b2454d2c6c +size 55846944 diff --git a/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-c2c97753d16540ef.arrow b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-c2c97753d16540ef.arrow new file mode 100644 index 0000000000000000000000000000000000000000..31b150285e9ca941f2918aadeeb3ec0b517201cc --- /dev/null +++ b/datasets/tatsu-lab___alpaca/default/0.0.0/dce01c9b08f87459cf36a430d809084718273017/cache-c2c97753d16540ef.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e1d4ff6d1b4f1932441c9427626d11fafef22530cfbf988c881ca39301be01c +size 50933096 diff --git a/progress/SpecForge/assets/acknowledgements.png b/progress/SpecForge/assets/acknowledgements.png new file mode 100644 index 0000000000000000000000000000000000000000..f732e05cd20323f32ab54cd690c55f997bfa68c9 --- /dev/null +++ b/progress/SpecForge/assets/acknowledgements.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4e5890a0b7e11dae887e67c59f58d75530912ed010f22c511fab3a93d17ef2c +size 382844 diff --git a/progress/SpecForge/assets/logo.ico b/progress/SpecForge/assets/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dfee01264af823a48c4558a6c806a062be0c669 --- /dev/null +++ b/progress/SpecForge/assets/logo.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9857743362a074a6856e89dfcc6a93018012260053dee332f3c60163a46bc4f3 +size 264254 diff --git a/progress/SpecForge/assets/logo.png b/progress/SpecForge/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eaca99e9e514c6fde2b194ea33e3019fa0427f23 --- /dev/null +++ b/progress/SpecForge/assets/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10dd0f59cdb12935d2ba6f9aad133a53b7fe790effab4a8d000c4800053af883 +size 315793 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 b/progress/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 new file mode 100644 index 0000000000000000000000000000000000000000..24b8aeb8fb6615a328f0dc1e9f7bfc0b6366c0f8 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfd461808f462c1c50a255ec2f220e83f31d82fdcbf215026f7ca5cfa9a6567d +size 1800738 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/3l/f3lggduzv5pwulwseetm4wwdiderllahjshwpod3jfhbjdcmd6yt/ajq4hk2uyrdnhtb7luarwz5khpzaipefnotdifkwlwann2cdnwm b/progress/SpecForge/cache/compiled_kernels/fxgraph/3l/f3lggduzv5pwulwseetm4wwdiderllahjshwpod3jfhbjdcmd6yt/ajq4hk2uyrdnhtb7luarwz5khpzaipefnotdifkwlwann2cdnwm new file mode 100644 index 0000000000000000000000000000000000000000..cbaf5c7298a5158c8bbc1109ed4bac8ac5684623 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/3l/f3lggduzv5pwulwseetm4wwdiderllahjshwpod3jfhbjdcmd6yt/ajq4hk2uyrdnhtb7luarwz5khpzaipefnotdifkwlwann2cdnwm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0261c3ab54c446d3cc3f5d011b67aa3bf2043c856ba63415565d80d6e8436d99 +size 13017035 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b b/progress/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b new file mode 100644 index 0000000000000000000000000000000000000000..728a34e8ad696b90d19251fabed2422865b5903c --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0ca35d64e3ed0ddcef2f34bedde0d761694feb4c18176d45b68999f320cb682 +size 1738196 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz b/progress/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz new file mode 100644 index 0000000000000000000000000000000000000000..0434f3825335e3e583a959243c9d902effee6878 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5efe8cb815d5e899ee74759989e8c98f6ec85afde37f5dd6fe9120b1dbc490f2 +size 1638866 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/hpi3s6uzbzjqx4pnx42mkhcf7ux374gaq3tawxbspxxh6h27dsy b/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/hpi3s6uzbzjqx4pnx42mkhcf7ux374gaq3tawxbspxxh6h27dsy new file mode 100644 index 0000000000000000000000000000000000000000..04ee4360e28044cf4b9581849c50c5fd0dd05a23 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/hpi3s6uzbzjqx4pnx42mkhcf7ux374gaq3tawxbspxxh6h27dsy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bd1b97a990e530bf1edbf34c51c45fd2fbff0c086e60b5c327dee7f1f5f1cb0 +size 1800143 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/vpvs2qkk525pfre24vao542e5mw2reoxotvqkpnnkonj4a6iwyt b/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/vpvs2qkk525pfre24vao542e5mw2reoxotvqkpnnkonj4a6iwyt new file mode 100644 index 0000000000000000000000000000000000000000..6f61cdc600dbe595bf520a01a5b95a848b8084ac --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/5j/f5jlsb72qzuctziwcm6hbjezhn4bcc5ehkuytuavb4mdpf2pay3d/vpvs2qkk525pfre24vao542e5mw2reoxotvqkpnnkonj4a6iwyt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abeb2d414aeebaf2c49ae540eef344eb2da891d774eb053dad539a9e03c8b626 +size 13017081 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/6e/f6efmj4hhzzathgrxll47wrs57idlkcw6hdituq5thcawharusgk/booxl4wexwlalbvnsinhbwycja2t63kfimny2h4twlwuf4wgrcy b/progress/SpecForge/cache/compiled_kernels/fxgraph/6e/f6efmj4hhzzathgrxll47wrs57idlkcw6hdituq5thcawharusgk/booxl4wexwlalbvnsinhbwycja2t63kfimny2h4twlwuf4wgrcy new file mode 100644 index 0000000000000000000000000000000000000000..872ccb1a80887bdded4993e0dcd681d312b43fd6 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/6e/f6efmj4hhzzathgrxll47wrs57idlkcw6hdituq5thcawharusgk/booxl4wexwlalbvnsinhbwycja2t63kfimny2h4twlwuf4wgrcy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b9d75f2c4bd960586ad921a70db0248353f6d45431b8d1f93b2ed42f2c688b1 +size 1735110 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb b/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb new file mode 100644 index 0000000000000000000000000000000000000000..1759f5231f20c8350b6b77aa440ef9cedbad5554 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:705e35486a893c46317c014211bd8cd92c09134226fa297830d8bd9362d7ee43 +size 1709535 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh b/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh new file mode 100644 index 0000000000000000000000000000000000000000..c10cf03012e9f21c9f67333510924432f6ce1934 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:239e31c26c93a6b6d9ea55a20f77bd79cac50934d870dba3600d8599a8e1e5cf +size 1800741 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s b/progress/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s new file mode 100644 index 0000000000000000000000000000000000000000..274dcb56a1639079899e8fbe3a4ff03df6553a2f --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9817e698d05c4e9402827adcc70c06244955de75732d90b3f025a5e7cac29ea4 +size 1800737 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/7j/f7jcvdbb2n5ul3vmi2bzdd226v4uh5wvgamslrt4pea3ibhajdfj/alkgoghh4ogayw7omi5jrqhy5eoqh4k73ak22ny63ls6fadptpq b/progress/SpecForge/cache/compiled_kernels/fxgraph/7j/f7jcvdbb2n5ul3vmi2bzdd226v4uh5wvgamslrt4pea3ibhajdfj/alkgoghh4ogayw7omi5jrqhy5eoqh4k73ak22ny63ls6fadptpq new file mode 100644 index 0000000000000000000000000000000000000000..309a6d16702e818ce28f726e1af088c3370c60ac --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/7j/f7jcvdbb2n5ul3vmi2bzdd226v4uh5wvgamslrt4pea3ibhajdfj/alkgoghh4ogayw7omi5jrqhy5eoqh4k73ak22ny63ls6fadptpq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02d46718e7e38c0c5bee623a98c0f8e91d03f15fd815ad371edae5e2806f9be1 +size 1805674 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/3fwi4brh2p3anlprrfllgzin3wvy4gzp2pn6bul2vtxxgmgdh6y b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/3fwi4brh2p3anlprrfllgzin3wvy4gzp2pn6bul2vtxxgmgdh6y new file mode 100644 index 0000000000000000000000000000000000000000..0067a86cba5cb964eb356e01fd0cf756c9385a0a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/3fwi4brh2p3anlprrfllgzin3wvy4gzp2pn6bul2vtxxgmgdh6y @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d96c8e0627d3f606adf18956b3650dddab8e1b2fd3dbe0d17aacef7330c33fb1 +size 1800134 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/q6lr5t6lrzm3kjbg7m2jlcyzljenwuyjv5wyyef3jt2oqfyigpn b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/q6lr5t6lrzm3kjbg7m2jlcyzljenwuyjv5wyyef3jt2oqfyigpn new file mode 100644 index 0000000000000000000000000000000000000000..6040b8152b1b394b48f9133903aa6f6d11ed33f3 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/q6lr5t6lrzm3kjbg7m2jlcyzljenwuyjv5wyyef3jt2oqfyigpn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:87971ecfcb8e59b52426fb34958b195a48db5309af6d8c10bb4cf4e8170833da +size 13017033 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/w5q3rsxtn2tzqbjvs4d776srueplh42a7l2j6jltgwq452rwtmu b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/w5q3rsxtn2tzqbjvs4d776srueplh42a7l2j6jltgwq452rwtmu new file mode 100644 index 0000000000000000000000000000000000000000..a1c1bd053aee870b9fc20e823db2ac0684573a67 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ap/fappzftatydvrylzifvvvmowwnbsvv62bghnot54mrojjg43gzz7/w5q3rsxtn2tzqbjvs4d776srueplh42a7l2j6jltgwq452rwtmu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b761b8caf36ea79805359707fffa51a11eb3f340faf49f257335a1ceea369b28 +size 7658283 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl b/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl new file mode 100644 index 0000000000000000000000000000000000000000..01b39d4fb3170943f5104ed502fff83f18e5745d --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:512263766c633ebc037b1775ee395627e9607a72e4f80798b987c1700455c156 +size 1800735 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq b/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq new file mode 100644 index 0000000000000000000000000000000000000000..921b60d97a1c5f53f97858d3666a3dd23edc1aaf --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b9219444372df2ac749dfb5b4e471a5b924a504c0dc10fbbc6a9893d601e4a0 +size 13041080 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n b/progress/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n new file mode 100644 index 0000000000000000000000000000000000000000..1c7bdc1f37d9a18d688c2ef7acc9ecdf291386db --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ad78211317c1e2322aae3330a21dcd902223426129234d88331c7b4f562cedb +size 1638189 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/eb/febaryantvlm6i2jih2ze7cfhxe7icwidoj72pogfovczxo3zbuw/57itk2igg24eo3yh3ivnrjwqtxza3ecpgpra6lhgiqd2dd5f73w b/progress/SpecForge/cache/compiled_kernels/fxgraph/eb/febaryantvlm6i2jih2ze7cfhxe7icwidoj72pogfovczxo3zbuw/57itk2igg24eo3yh3ivnrjwqtxza3ecpgpra6lhgiqd2dd5f73w new file mode 100644 index 0000000000000000000000000000000000000000..5d9d8d8c746a925c2333386d59a224c58e8f1207 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/eb/febaryantvlm6i2jih2ze7cfhxe7icwidoj72pogfovczxo3zbuw/57itk2igg24eo3yh3ivnrjwqtxza3ecpgpra6lhgiqd2dd5f73w @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:efd135690636b8476f07da2ad8a6d09df20d904f33e20f2ce64407a18fa5feed +size 1738849 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 b/progress/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 new file mode 100644 index 0000000000000000000000000000000000000000..a2bfc408463609ab2e63fa2bf613ab98a2086594 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c063197a1e8b2f84e9125e8569bf4c72ec0ea80582a0b6418c6846bf88caf574 +size 1807783 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz b/progress/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz new file mode 100644 index 0000000000000000000000000000000000000000..aa5dddf6d33ab61b8f42ae12c04cc1a35629b0cd --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a969b93c6894c51c30f9926360aec162e3ea6275ffbedffbf8864fc878f3cd33 +size 1738709 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov b/progress/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov new file mode 100644 index 0000000000000000000000000000000000000000..616a12ef2c9d8ea83b733037c7a62342e88b5ea3 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69fee0e79ad972e000c14e7b87cb9123a86985e9d3b49dceb9db1e2caf58abab +size 1610811 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ig/fig44juv4tjlo3l5cwx4hhzdllqc2ouhpkivltmpw23drnzrvrp7/7uqoqee55jaq3h6uryiwcuoxwojslgqe4etecsjdafaixeyh7kz b/progress/SpecForge/cache/compiled_kernels/fxgraph/ig/fig44juv4tjlo3l5cwx4hhzdllqc2ouhpkivltmpw23drnzrvrp7/7uqoqee55jaq3h6uryiwcuoxwojslgqe4etecsjdafaixeyh7kz new file mode 100644 index 0000000000000000000000000000000000000000..e0dac66b04d9c433fd03cc216da2d578ec33801c --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ig/fig44juv4tjlo3l5cwx4hhzdllqc2ouhpkivltmpw23drnzrvrp7/7uqoqee55jaq3h6uryiwcuoxwojslgqe4etecsjdafaixeyh7kz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd20e8109dea410d9fd48e116151d7b393259a04e12641492301408b9307fab3 +size 1824347 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/bmaks7dbsdlk7bgt5sigxtxyk7ltijhs3ghstlz3zaitczi76vm b/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/bmaks7dbsdlk7bgt5sigxtxyk7ltijhs3ghstlz3zaitczi76vm new file mode 100644 index 0000000000000000000000000000000000000000..12390e8fc3e5212a86974dd694972b6efa3a3497 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/bmaks7dbsdlk7bgt5sigxtxyk7ltijhs3ghstlz3zaitczi76vm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b00a97c6190d6af84d3ec906bcef857d73424f2d98f29af3bc81131651ff559 +size 1800147 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/tnv6pghqtdbkuwwujswnwbvuubf4g22fb26jlhduynoq4ec26vl b/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/tnv6pghqtdbkuwwujswnwbvuubf4g22fb26jlhduynoq4ec26vl new file mode 100644 index 0000000000000000000000000000000000000000..29e7c40749381df24710cbf8dcf8f41346064e69 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/jk/fjkjpgwuaivl2zabutpg4hnsjhcgannnl7zwtp73eoupvtrssmdr/tnv6pghqtdbkuwwujswnwbvuubf4g22fb26jlhduynoq4ec26vl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b6be798f098c2aa5ad44cacdb06b4a04bc36b450ebc959c74c35d0e105af556 +size 13017075 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 b/progress/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 new file mode 100644 index 0000000000000000000000000000000000000000..ff441d3f0a7d116022d04a81b739694cb45c24a3 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bae6882982864e37bd420dad09f89c0aab0a7782c2b63b13ceb62f551e52cf7 +size 1751060 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz b/progress/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz new file mode 100644 index 0000000000000000000000000000000000000000..fde2d7ad01696b39daa270f8216439818551078d --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8cc920b21d02130d637554878bd8fa79964aecf84daff42316d82d910307acb2 +size 1804750 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h b/progress/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h new file mode 100644 index 0000000000000000000000000000000000000000..72f8df0de80d812a4c21b9d5becdeb48d3b0af70 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c07a6d4e35d58ac9e3ec67d92bd4a112d2a7a538ce0eaff56cae1b72efa8a74f +size 1822002 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/m5/fm5swdd67jpmjm2nduj3j3l6q4ubwbfasci3sljom5gr6fortwxn/y6z6hp4mpuutvywh7n37vvb6wwbqoeehb4psgehly3uh5tviull b/progress/SpecForge/cache/compiled_kernels/fxgraph/m5/fm5swdd67jpmjm2nduj3j3l6q4ubwbfasci3sljom5gr6fortwxn/y6z6hp4mpuutvywh7n37vvb6wwbqoeehb4psgehly3uh5tviull new file mode 100644 index 0000000000000000000000000000000000000000..13d3ecfa0bcf982ed8df8e38489fde2c3b61c8df --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/m5/fm5swdd67jpmjm2nduj3j3l6q4ubwbfasci3sljom5gr6fortwxn/y6z6hp4mpuutvywh7n37vvb6wwbqoeehb4psgehly3uh5tviull @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7b3e3bf8c7d293ae2c7fb77fad43eb5830710870f1f2310ebc6e87ecea8a2d7 +size 1800131 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/o2/fo26te7t3oshxa674c52lzjedmytpzr4slolgnqt32tklhc65ydz/wnm43z2nmgfvtm4ch76el2xnkzdko3aant5mb23svaviq7yakod b/progress/SpecForge/cache/compiled_kernels/fxgraph/o2/fo26te7t3oshxa674c52lzjedmytpzr4slolgnqt32tklhc65ydz/wnm43z2nmgfvtm4ch76el2xnkzdko3aant5mb23svaviq7yakod new file mode 100644 index 0000000000000000000000000000000000000000..99707eb85180a1ab214bc2b56cc7acefb3c18585 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/o2/fo26te7t3oshxa674c52lzjedmytpzr4slolgnqt32tklhc65ydz/wnm43z2nmgfvtm4ch76el2xnkzdko3aant5mb23svaviq7yakod @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b359cde74d618b59b3823ffc45eaed5646a76c006cfac0eb72a82a887f005386 +size 1805704 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy b/progress/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy new file mode 100644 index 0000000000000000000000000000000000000000..33e7540345755f5041fa59ae9c65585793d3f862 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:959dabbf97448d968c1368807bef4430043f5829653e6f4e1d52cfa58e48a5f1 +size 1821994 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc b/progress/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc new file mode 100644 index 0000000000000000000000000000000000000000..288e49b064d04e995182438dafa2b878ada4f51e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7151bc6048b7ceb5a36605075955e031b533042be5ca407f4275e7228c1fd505 +size 1738501 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln b/progress/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln new file mode 100644 index 0000000000000000000000000000000000000000..8da39563e4b29b1356f8c2238e6b8cb8f0718436 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bcc0d7c502d16ae8a69c207c4accd3d7e3a86577175e0b55a2f1ca5096daadb +size 1807798 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw b/progress/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw new file mode 100644 index 0000000000000000000000000000000000000000..8cfc7595c43fc50b9be6d73c4a1c9d8be7073a29 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77784ddf3985eaa5484a0f47d8efb5ade7107a2483f1669d216858a1c4cc30ac +size 1743042 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso b/progress/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso new file mode 100644 index 0000000000000000000000000000000000000000..5183df43dc88d7a3361b04a6158283fbb99f8032 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e9a5e805bfb2ddbdb73efe4fdd2b8249af9e9f019ba414cd0c1ddd18e58249c +size 1751153 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/qg/fqgkekhf4m7vmri4ew5v3jufxenpvtb2hnaaodulm4d7ohbbc2c5/gvvpef5dp63zfmoghewiponfb4evle45gf2cp55jjfs4gbzljs7 b/progress/SpecForge/cache/compiled_kernels/fxgraph/qg/fqgkekhf4m7vmri4ew5v3jufxenpvtb2hnaaodulm4d7ohbbc2c5/gvvpef5dp63zfmoghewiponfb4evle45gf2cp55jjfs4gbzljs7 new file mode 100644 index 0000000000000000000000000000000000000000..8dd6a59810820609532af0120a6d53ebadb47dcd --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/qg/fqgkekhf4m7vmri4ew5v3jufxenpvtb2hnaaodulm4d7ohbbc2c5/gvvpef5dp63zfmoghewiponfb4evle45gf2cp55jjfs4gbzljs7 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:356af217a37fb792b1c6392c87b9a50f0955939d317427f7a94965c3072b4cbe +size 1733397 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn b/progress/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn new file mode 100644 index 0000000000000000000000000000000000000000..c07103198ebfa53d5287287452a88389ae3c0f5e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e66221dbf95127d08ad771f7bfbd38c986003af1f05e333f69dd16d0e4c038db +size 1737821 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs b/progress/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs new file mode 100644 index 0000000000000000000000000000000000000000..ca129ae09972a831836d893d082cfa783c75572a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5daa941058d0d7522ac12b0774aeabafc4d57f2d94334c5f7d684074952e4565 +size 1738004 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr b/progress/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr new file mode 100644 index 0000000000000000000000000000000000000000..32717014aea22ef9b1b874235c16d98b03f05162 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c5e5508ffa909eda9ee68ae48fae7a4b9bd2bfbf0e8fad7e406a414ffb21b22 +size 1638861 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep b/progress/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep new file mode 100644 index 0000000000000000000000000000000000000000..546e9b56f91601f0d1629fbd18b36a2e8946fd92 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f8bf7ddca372f5aba595c1fddf35547ca118f5428c8681124e9c0a89e64311e +size 1804644 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r b/progress/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r new file mode 100644 index 0000000000000000000000000000000000000000..3bf94de420742c472549d58ef886bbe2682f2d5c --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56a68b629c462de2e7fb3ce604b5b5cc477ae84121f00da13fcedec3e372e723 +size 1738704 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/3wqg7mzts7n6nz34xe6c4egb6g4hlxchd3ribvwcx6ahv4cwgrx b/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/3wqg7mzts7n6nz34xe6c4egb6g4hlxchd3ribvwcx6ahv4cwgrx new file mode 100644 index 0000000000000000000000000000000000000000..3c8076f7225359eb1af617a882292c9acf073f5a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/3wqg7mzts7n6nz34xe6c4egb6g4hlxchd3ribvwcx6ahv4cwgrx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dda06fb33397dbe6e77cb93c2e10c1f1b875dc471ee280d6c2bf807af056346e +size 1800123 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/exlebcsez7wjsgpeavs6uok5kfd5prixp5poeo3fwx7rfzagtjm b/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/exlebcsez7wjsgpeavs6uok5kfd5prixp5poeo3fwx7rfzagtjm new file mode 100644 index 0000000000000000000000000000000000000000..c2e8813950929a6e28a6580cdc1cb4338cd8c1ac --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/us/fus474itd7qe654s4jkj7r3xr4flfmej2zftuk5yzwsrhlb3q6f6/exlebcsez7wjsgpeavs6uok5kfd5prixp5poeo3fwx7rfzagtjm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:25d6408a44cfec9919e40565ea395d5147d7c5177f5ee23b65b5ff12e4069a59 +size 7658271 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a b/progress/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a new file mode 100644 index 0000000000000000000000000000000000000000..d68b568a709f6c312c53a692f2b9d0c09909f33c --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:376cfeb7af4a78866c2c19a72438fa088acc205a2ec8168a402a8a7bf3079f81 +size 1709292 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/vj/fvjfjft7d6mo6v37umkszch3htlazwqe7e52o6lrvwkkz3lw6wyk/hcmylcee2flky2isv5y4z46z2kr7n6666gzl5qw3rfuqbz6qova b/progress/SpecForge/cache/compiled_kernels/fxgraph/vj/fvjfjft7d6mo6v37umkszch3htlazwqe7e52o6lrvwkkz3lw6wyk/hcmylcee2flky2isv5y4z46z2kr7n6666gzl5qw3rfuqbz6qova new file mode 100644 index 0000000000000000000000000000000000000000..48a7ec931c8f3ba70dbcd1080abbfe54bb06d059 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/vj/fvjfjft7d6mo6v37umkszch3htlazwqe7e52o6lrvwkkz3lw6wyk/hcmylcee2flky2isv5y4z46z2kr7n6666gzl5qw3rfuqbz6qova @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3899858884d156ac6912af71ccf3d9d2a3f6fbdef1b2bec2db896900e7d07541 +size 13017061 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca b/progress/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca new file mode 100644 index 0000000000000000000000000000000000000000..874e620bab55c5b3a440c5d91a7c8409af2db2f0 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50fa9d521acd0dbc0c291d2f2139d35213d52bbcdcac2ff60b96e14446b73880 +size 1821861 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/wu/fwubrvhvgdtams45z2xkpp3u2ajvgzhip62jpdgn2syy3kvplhlk/x5alss7uk3eguh6t5izxaqpkgymsqpy46uhuu54v7rfi5xvfwk2 b/progress/SpecForge/cache/compiled_kernels/fxgraph/wu/fwubrvhvgdtams45z2xkpp3u2ajvgzhip62jpdgn2syy3kvplhlk/x5alss7uk3eguh6t5izxaqpkgymsqpy46uhuu54v7rfi5xvfwk2 new file mode 100644 index 0000000000000000000000000000000000000000..c81b52b24deba688e3a171714fd616cae558efcc --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/wu/fwubrvhvgdtams45z2xkpp3u2ajvgzhip62jpdgn2syy3kvplhlk/x5alss7uk3eguh6t5izxaqpkgymsqpy46uhuu54v7rfi5xvfwk2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf40b94bf456c86a1fd3ea337041ea3619283f1cf50f4a7795fc4a8edea5b2b5 +size 1803241 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/wz/fwzmf5l4gyt56dkjxwl5xoirzqqypidknvqkycjdabxr23ezebeb/xrsmps3tltlxfvft23w7eeow4jzwsyrumfjxybmqynlymnvs6ei b/progress/SpecForge/cache/compiled_kernels/fxgraph/wz/fwzmf5l4gyt56dkjxwl5xoirzqqypidknvqkycjdabxr23ezebeb/xrsmps3tltlxfvft23w7eeow4jzwsyrumfjxybmqynlymnvs6ei new file mode 100644 index 0000000000000000000000000000000000000000..01b0c66ce9fccebd75321dd13b1732ba0003cda7 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/wz/fwzmf5l4gyt56dkjxwl5xoirzqqypidknvqkycjdabxr23ezebeb/xrsmps3tltlxfvft23w7eeow4jzwsyrumfjxybmqynlymnvs6ei @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bc64c7cb735cd772d4b3d6edf211d6e27369623461537c0590c3578636b2f111 +size 13017050 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 b/progress/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 new file mode 100644 index 0000000000000000000000000000000000000000..26576705ff179b6cd429bad6b99ba4767153c339 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:290f8307e87058629bcbda07e56ebbdfb4b15472d2a259ac7d996a32291be37b +size 13041048 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/xm/fxmkiw56bdl4kzy3fp7dzbbqsukmfq3pmkvw56w6hrflwa4blgpm/vdpjpb5qrgqidv4fa3gscsoicwr37y6lgtcabds5txk3go24izx b/progress/SpecForge/cache/compiled_kernels/fxgraph/xm/fxmkiw56bdl4kzy3fp7dzbbqsukmfq3pmkvw56w6hrflwa4blgpm/vdpjpb5qrgqidv4fa3gscsoicwr37y6lgtcabds5txk3go24izx new file mode 100644 index 0000000000000000000000000000000000000000..dba3022dc582d12603a8ce048dcffae1cad9bb39 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/xm/fxmkiw56bdl4kzy3fp7dzbbqsukmfq3pmkvw56w6hrflwa4blgpm/vdpjpb5qrgqidv4fa3gscsoicwr37y6lgtcabds5txk3go24izx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8de9787b089a081d78506cd2149c815a3bfe3cb34c4008e5d9dd5b33b5c466f +size 1736766 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u b/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u new file mode 100644 index 0000000000000000000000000000000000000000..233f5362213960adfb37958d85fc8b6d2f645d22 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04f801ed2a9227b3ac899f652cbe2a73ba4d4656778b6a4bb55ab2f500cfffa9 +size 1751152 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvlte35ajgkob7uec6c5kswyiithjqgw7qttbr2zkd27p5o5phx/6ns6yqvl7uybplheykfjip6vme47ftdgwxkbijerswchee5ig6s b/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvlte35ajgkob7uec6c5kswyiithjqgw7qttbr2zkd27p5o5phx/6ns6yqvl7uybplheykfjip6vme47ftdgwxkbijerswchee5ig6s new file mode 100644 index 0000000000000000000000000000000000000000..18008f1bd5a92a3a5f666d89caa75522fe3269a9 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvlte35ajgkob7uec6c5kswyiithjqgw7qttbr2zkd27p5o5phx/6ns6yqvl7uybplheykfjip6vme47ftdgwxkbijerswchee5ig6s @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f365ec42abfd3017ace4c28a943fd56139f2cc66b5d414249195847213a837a5 +size 1800484 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/y2/fy2wi7wdwwppm5lgqiwqi4u3yylezkc7owdmacir4jxwgm23l6gb/lkuluxl3usdoarwbrb5lfah2hm6pnqctsjellpwrqlx24gx5p5w b/progress/SpecForge/cache/compiled_kernels/fxgraph/y2/fy2wi7wdwwppm5lgqiwqi4u3yylezkc7owdmacir4jxwgm23l6gb/lkuluxl3usdoarwbrb5lfah2hm6pnqctsjellpwrqlx24gx5p5w new file mode 100644 index 0000000000000000000000000000000000000000..728bfc923b4f6daa495e036f6bb0df40c29df673 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/y2/fy2wi7wdwwppm5lgqiwqi4u3yylezkc7owdmacir4jxwgm23l6gb/lkuluxl3usdoarwbrb5lfah2hm6pnqctsjellpwrqlx24gx5p5w @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5aa8ba5d7ba486e046c1887ab280fa3b3cf6c0539248b5bed182efae1afd7f6d +size 1803243 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/ym/fympkqo6hxovnotwgugq4d2hhnqoid5pxffnoa4nku7cxs5uvazh/r4shmei73tssgyiqta3wmrk2flgtqi3otrrdsz6vweo6w7wq3wu b/progress/SpecForge/cache/compiled_kernels/fxgraph/ym/fympkqo6hxovnotwgugq4d2hhnqoid5pxffnoa4nku7cxs5uvazh/r4shmei73tssgyiqta3wmrk2flgtqi3otrrdsz6vweo6w7wq3wu new file mode 100644 index 0000000000000000000000000000000000000000..55ec1980f17bd33c8b166771097b9105142367a3 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/ym/fympkqo6hxovnotwgugq4d2hhnqoid5pxffnoa4nku7cxs5uvazh/r4shmei73tssgyiqta3wmrk2flgtqi3otrrdsz6vweo6w7wq3wu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f2476111fdce5236110983766455a2acd38236e9c623967d5b11deb7ed0dda8 +size 1822001 diff --git a/progress/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe b/progress/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe new file mode 100644 index 0000000000000000000000000000000000000000..09ca8a6050f707b55a38cf5a2ae7c67da06b72b7 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:057747a6865136b021e647087a2164a15b0ef23c45ebc1892ce2fe29fda9e148 +size 1709486 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..2671cd447e8f9c031eb19792c5f45eece3c70b44 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69908e13133d104c5d114d4e01cb4b2d36ac7871162d14a7ef8b1289ecc88be7 +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..700574794c869da4a7d846810dac4171bb239c17 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6f04c186cbc8f5c7b670aea4cd29ace0c41469d640fd1537dab78df2f7e3937 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dda0c94205d35ad16247f7716d09430687953f44 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92c587ba7ea7317a29be4825206e60d3ca61bca8e7be2e1de93dc5a125b78051 +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/6WXRZJRQGRS3D7MVO5SVYMR4F4MLAF4VTB7C2SHACGFYJMY4NEJQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/6WXRZJRQGRS3D7MVO5SVYMR4F4MLAF4VTB7C2SHACGFYJMY4NEJQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..86ca8ab01118d8268c4b925ecf773c9a0bbbde12 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/6WXRZJRQGRS3D7MVO5SVYMR4F4MLAF4VTB7C2SHACGFYJMY4NEJQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdfc43e9a65b43cdb1ab6003bdb486b60ccd7aa1012be602f4985bcfefe36584 +size 173280 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d9df6ba1e6b21b1decd33a17a859967aace25ac8 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bd9879cb44e0ff819e89a3317fd62ae0d497c8f1e97f9f818391a7553674c4f +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e31e97b4f596402ec9a4c7d24fd4024b9436458e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:83d080f8b38dc188775a3aaac871f50b631a2fdff2ab421d6d8e1a8269b1a492 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/AHPM575T53TM4HQV4V5KZ3N4M7T2LI4QARYVBJ2FDLAYM7HYU2GA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/AHPM575T53TM4HQV4V5KZ3N4M7T2LI4QARYVBJ2FDLAYM7HYU2GA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1a144910c7b4642186c215175077d0258e86c6e9 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/AHPM575T53TM4HQV4V5KZ3N4M7T2LI4QARYVBJ2FDLAYM7HYU2GA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ad90fa3c179e86baaa6e6a4c77d939b16f883c75507be48091285213fa27f97 +size 175184 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..40047e9d068f3a2ebce5867f55499086c6798d32 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7958989025beeebfaa6cb30b22ea8161a481ad8262af35958cb2e34abd2a2648 +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1c411a22ddd997c6d5ab23a614111ca2a9dae299 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b60ef9dc3fe552f20ab5cd48c1a1b85ebf1dc4e16870380458152a9a7a7ce4e +size 174160 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9b3b04e5c19aaebc006d8f8ee704b25afaf7c6d0 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cb4e7856edaade12a654f7866321b4051622fa0ab8d098f42cc661bc4b5cfbe +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..623670e80983224df660eec24dffd8f0bc394c12 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fe3a8bfc3ae3712b0e155b2c18a127dddf6a5dfeaf5138957bebf20141c052b +size 1752928 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ec278f613e603814e4c04b83b3e977d25b73913c --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84f42c017b2d6ded6717aa39151f7e716dd750168ff283f8423df439b90348ed +size 403080 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ba85885c22c1dd1794022df85878a1d8484e4073 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15ca9e1de4aef8a24335f4d7180887aee4f17b19b17c08f428ebb03292d2449f +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f037496fb9796e7724b66653ca611a6ccfff488a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f08563cc05f21f823f0d7729e457ad25ff8f2c63961339df354d78afac0e1dd1 +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d8c231999bbae13e3e2be935ed01fc513a37144e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a0c4ffd5a86442813d3b633c52f0e67dde3a2b0fbabbb8e25f081c70e74d558 +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..bba866fd581d38557ca9bcff7db60fed0d87d9c7 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b2d1d3db62b9a3a48379d446f7532d8a38cc4100b7485aa29a10c2a2a46951c +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..00d07782081fdb488bac65c676946cc7685c7b9e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddaab87750dd4226d655928ea52ef1214a8b4754e3a77d0e263e80c8254ca30d +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..92130115125c937f6ad864d133ff6a74635e8f57 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:867714535f33b94be79241341ccfb8117d7d3cf15e12e18fcda7e4603420ba6e +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..8c2b675041034d50d08cd63322c7afd3a409188e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fa09d7ccf04c23d4e16b7b02bca73700fd0b248bc70580aa406ee55c90de7e2 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/EEGOTORDQJ74TDV6XJVAMQZ7E4UU3DBKQIHKSZRLTWFKTHFOOBLQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/EEGOTORDQJ74TDV6XJVAMQZ7E4UU3DBKQIHKSZRLTWFKTHFOOBLQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b4128086d5e7a44d5b93220a584aa4c10d3c2f4b --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/EEGOTORDQJ74TDV6XJVAMQZ7E4UU3DBKQIHKSZRLTWFKTHFOOBLQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3ff404a5796109fd6bacd1d203ca79427f822f52679e51b5e7403cec8884af7 +size 173280 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..52526d47c4778ff8e0098c7c0207fbb93ba24b58 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f2b74ea714bc139497227d09ff8839ecaef8e72721b09c498188d2d91c87a73c +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..7cdac2ca9ce38fba28045b13c162a8d4bd2b9b62 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:509cfd7fd459815804cd514c9ff89b927185e82b48a6401f4bb02a8665cfceef +size 143952 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..97c864a074fc913f64e845acedd0990290b550de --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4e2320a36cbfeaa3e715b2a26581b859bfa35c4da796e142bef265691bf8546 +size 327048 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d2fe27475ba3b91abbbbe4427b02641780ec61ab --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92dbf2b48d35c147f3269f7b2251eec4f0713fbaed844e46b9da891a9a6cf753 +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/PRBQJBNZOLZFMT2AEWRJDPNOUNXSJWSQCNEHKHEMORI73QJVR6NA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/PRBQJBNZOLZFMT2AEWRJDPNOUNXSJWSQCNEHKHEMORI73QJVR6NA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..713cd16acfa0b16c8926af7b75af22b8cc7b29f0 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/PRBQJBNZOLZFMT2AEWRJDPNOUNXSJWSQCNEHKHEMORI73QJVR6NA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7adf59693d4bfa3228e65c574941d3adb64ba485b2b52e01f9f24a77f9ec37a2 +size 173520 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..4234f3f61d264ec46bc17b074546a78dc4e980b2 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cc1df8b1fbdf976ec4fa63c17144582370e9b05d8d8493cb09cf44f1cce4137 +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..14879c2ab396ca986af278fadbb1010b6c0ad8a5 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:195c9de024180aaea3a8ae93f06a3a305afc9e3ca47b98ac938a875881ba71a0 +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..bb5a3215ea9ae49619b813fbbe29329318bfe6cc --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5acb596e3ed3297180e684bd17017a7576d1eeadbf2f1aa2670934857d51079 +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0072bbb54d647e2e04494a037e1c6bdaaf69a0ad --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abbaecadb60e572029b83ae062e7e054d486a662226111d78132a8c9c6358c3a +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..c408a68fdf9c549400b94c0963deec45604dc5a8 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae53043a633e61fccf97e73e25eafb7990d0c921e6550ba4629c52f3092347ff +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..34b762db2902ac59dc18c55ae777bbfc31a43afb --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cefe573071432680f65e8bd9cd263b7d5444ab7c446a3f78a3a03e957bd50df8 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e4297e6960f464d794e497af229b0c3b5d2980fa --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c90e3daf0cf3cd7d100d6269f655aa81d1b73f4031178681a0f109e11c23b585 +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f96211c1f7cf3fea5cd05d6b10d4021a74aa7331 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9600b3cb86abad1717f52d2eae20a266f203d0e7862f1850b989b6e3cd7660e9 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b943bb4eb6c69fb5459c8ce05ea3a83fefc64e17 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db9a230821e65e8457c93beaae3c514cd83d343aa6ffe4aa19ef8b7be19a3da3 +size 174160 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..4b4ff51cd6210fd663c618d30f4f2c2e104db39a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e10adf4c456df3685c2663e9a93046d040cda09999fe02f52ac3c4a187221fc +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..cbb75e02e968b653de83dbc19c9fd6f43a843699 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eaecc86e085931be8768a8bc096b1d1004a35ef24907bd09f36c4a615fa9e214 +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/TBXXVBGY7UF7OEH7RASYAJMOLF44SCN5DDUSRWDYATGILBUOQIEA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/TBXXVBGY7UF7OEH7RASYAJMOLF44SCN5DDUSRWDYATGILBUOQIEA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1953438834364d3871940c47504b108767620730 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/TBXXVBGY7UF7OEH7RASYAJMOLF44SCN5DDUSRWDYATGILBUOQIEA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3f5e91665c647b3b7f68ef2a09311bd4d9f47f11a0886e9aa4d6371c9eefa56 +size 174544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e8a9ce041a8eb3b2fac908bbaa45c0695cbcd0a5 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0f32ce7663d78ca2cf6f377bc255d80ed13d3f79881b77020c954107654ed19 +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..53b31bde8ca46d270dcca7b35dfacebda6f31ee8 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e1081a370d761fb92df8c79d3a7dac46e3af6c43e37c6e305e505b41e804957 +size 403848 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..aa9b284c234bf0c764a81948cbb4263377bf5df1 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:772e85f6ad5dae5fbac6a6d86383ecdd8d4f5e3b9920df813a16d452cce86f6b +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ba003af45936b5c73655e70895488b1fca34f971 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f39c9575e1f00817bbdddec15c36aa39a20bfca6ce84fd78462086213c7cf550 +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..431e49b964ca5e1e426344f9f1e4f9b2bccc74f7 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a59fd32b75b1bd7ff56a1764e7355bacde1d67221c4849830caa067326280c89 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0e15cac2288008b7c1e9f8a488ad7ffc77d7a382 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43f6b67ba9e2f8e86c78ddd74928b12630ac5a65f8f1c2b8a97d7b618e900385 +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b80960f5c55c9b4d2703f1a37d92b7b3f9eb8ec6 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:20b7d7e546407543458575acc5604e03b87d902bbc0248b2fa7ab8c2a6242f11 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/DYWW2BIUJCLXNNGAONUQESWDDDUJJKHTFJ2ZAG44H2OVU2QXS5VA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/DYWW2BIUJCLXNNGAONUQESWDDDUJJKHTFJ2ZAG44H2OVU2QXS5VA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..5420567cf17b11bba608588ea6b730fc721c2462 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/DYWW2BIUJCLXNNGAONUQESWDDDUJJKHTFJ2ZAG44H2OVU2QXS5VA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67cc8097c5f6d272457b5202c8ebf4151cb087994280c37d4264f353c88f33de +size 1667792 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d607c94ab41b4fde14b23e8619668457db5e4d50 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7224f2b4439bec77ec6c5c968076d7b0932c4cc03b7ddf69c655a60a771a3ce +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b7b4a9942ff03badf1442e10c3870903f8398ed7 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2d712f97651d47dd1f2f7b7f9738be5c6f49b7ea3f6c60955ac902063700243 +size 174160 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..085378e26d550917891e9d98294b3e1371e452b5 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d64c4dd843b8eeec27cba44201e3afc84405f25a3668eab209698ec8ca1c27b +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f60e80e77c3dfd70c6d599fc01af4e7067f1282d --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb44ea81fba3ba33ac3aa7b10460a6a54c7e693fc149b38ca3a578136c3a5101 +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..cf708a6f02f2bc5bc376c38ec14f526f38b0ce22 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcda9e4f6f98dc3fc5ab38111c644ab8a0ae58f4a338dadd323081c6282cd286 +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0afab8a9777df704c222b035261b903d6e1ed013 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7d58383ffa04ef8b43aa10cc41307df165cce180b4aa2f1e13069eaf01aac0a +size 403080 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9db878720a85ee9e1bb8699607f756686a959192 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce260f1cfb7a716a019ce435926a000f44456cc90367024b156f9ab1328c8294 +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..64a0012f9fadfbca9dedbb7b67d61aa194120e8a --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea1fd41f54ef74df42e4ec363f451de1c1ca17c055a130c2b52fffec657e5c2a +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..3c7837fed172a54a13bd80dd48af6ef243949230 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bb675987f8e53a01bb0df1faeb545f2a7a98b5147cc3d1fb4ff25aa38a8ab5f +size 174672 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b7f6be1911ed5f36fcf1021b59fefb623a52c4ee --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4561e1a1975435b3adc84edf632266379bf4ac7ebc7a3cfffa68b704e3e81c3 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..544b18ebef55ec276fca76c619a102968dec74fd --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c76ba755e085e19a4b3f10135ad7340b002176f24dc52c1895e2c7eda4bfd780 +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..c7fbe7a6472db4cbf83ed9c3b0e39b0868f73570 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1c169efd313d8ae6764e7bba2f0884a5351139fb0d5382e2f403e8171bb37ae +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..5c8d1a2968101ac54e9601a616c9742e2b8e06b6 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cc9b4d95b46eb464de7b4786e8c49ec6239647eec096f608554d111f1d695fd +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..87959cd9093870e94f5760f66cd519ceb28d9455 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:823a85e5b38f5c1d6b2cd352cf91c1f0b4316eca62d9d821fac444da3a44cfcd +size 403720 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..c7ec0fd762ce35861e42a9d12596cad44485d6f6 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd2716f99b3800339934d9475b444b270b34914d70d231555db6f6b18e36fdce +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..21ecc0f51c46072f91329662a113dcbd1ca011b5 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0312ac6a382a111fa6c44b1e0a80cda85121e6bfebfcbb193128da4a3897044f +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b4376e20912bc11fef008c258343cc0a29a12996 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2eec24018999f8bcece3babe91b31a765c5522fa452c4b49f3854c45fb43dffa +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/4/VIWMGOGS6RUP3ZJWMRBPDHBYYKBOZ43UVHGE4CWWPM4U5F2JJ7BA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/4/VIWMGOGS6RUP3ZJWMRBPDHBYYKBOZ43UVHGE4CWWPM4U5F2JJ7BA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..bb4de390531ee81d21ec73dee162a0dc067b28ea --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/4/VIWMGOGS6RUP3ZJWMRBPDHBYYKBOZ43UVHGE4CWWPM4U5F2JJ7BA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:736e5a76bc73762bef03215976ecf381b4746a2a17bdce50c38afcd49391abc7 +size 175312 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..60fbf45f1959535aed80ae3cebec0fc2689ede91 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01490ba535afc05ee334d448ed47cab3259b31295dc7c47e528e9c2d8838208f +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..2b55730e5fdaab0274b87e6e86ee3d33231ecfa1 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12df001221bbfdbfb9d6dd333a7f0561cf551c9926496bb035d8978594ae94b4 +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..af223b8a3c5aa0bed6719a744f3a99b91e9cd4a0 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1d0011d73a793edad00e0991603df931f0c739fd83d2c7bd8ff43288e0f8d20 +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a3aaa95bdfbc48106bebdbd91efddef2b905b57f --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28ff9a53513102f0334a686b55869fb1235d6bacd81f3411dd06c9b8eb312ba4 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..4657417bc006314888b449baeccd6c51dab772d4 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:726dbef7970ca53a3904b933d43664eefaffef6ed47c788ef494005c34ce85d4 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ad43033253e93f88362dd15d69e6474e7b7cc289 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d14bf5b96a750c64d0173b31e148b4d277c4ba58ea0a1475900ede3726405f8f +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f06675dc89539d721df747c50eaab1f1a489236d --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f238b24a1022ddfc9ed5cdc14dafa9237f09c50347eb3e3a4f723c130325dac9 +size 143952 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0431177ed8fe1656997c0f45faa4369fdf101441 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fe6ed16faccc00fa8eff816a625f08f2b44d172dab172146b74f3bf5a8cff36 +size 327048 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b182d32f541452dc7cf8a1ebfa550eab91e90430 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f0526e18691cf4f8a4fc9d35ff7bdb0823db932bcdfc6ee8ee5f324fca1fb39 +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e0b3cbe7d002cc8a1d68b4c445ead6249668167d --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9948d74681deb6f79caabf7994165422ec1351a6df78d29dcc973984aec00ad +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dd78d2f6463167dc75c73d301ae4559cd7e55ab8 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb0d866dd9d6ec111e4d778c5bcde2b262e650468af26bda5a56a80baaf5f3fe +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/5/XSE7P2TJCSCJU4RIGUJ3P36IWHKDIG7MU2LGQTFDAGIVC677DH3A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/5/XSE7P2TJCSCJU4RIGUJ3P36IWHKDIG7MU2LGQTFDAGIVC677DH3A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..945bee1c2e8a44f6e2ee97a36df9124d2567f5ff --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/5/XSE7P2TJCSCJU4RIGUJ3P36IWHKDIG7MU2LGQTFDAGIVC677DH3A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de424d6e28145962d451906184e96ef432eb1a31423a8280fcfdfb1576c58b42 +size 174160 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..7b9324ee119e1e4c3602a8a6fc82b0aeb632d353 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8af8bdf9fc75186a002199f7e26bc1aba864f7e663ce8b732534fdd2df620791 +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d9063f11b490e7b871287a325dee3987d8cccc53 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0796bf5d011ca48f60e8078c3ad0f7448c4396f346e34af7de1f3ee7e0757be1 +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..47f192eb42daa633e78ab64d6c3f045e7bdba6b2 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bafae213c6c4c04b4b2c8e7bb12fb940c6a03e039b466875350620dd43ced56 +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b59d6f2f3894d7f333a6eb3b3bb9810644d1d4dc --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7dcc28abeeefac0837cb9f945fc1b54c3a9e62c1dceeb6a561ab2b311f92aa41 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e8aa93d1402b62432c334a40ec1eae55e6d68319 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ba64552a61c25e061ffbad049f5aca9205a4ad9abb2c067b19459fdac99d1d7 +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..42da51333c15b137dd8df19ad7076c3a828f3977 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d87fdc459fec75eecfaf0b41ab720d40dba6ea2f59e65ba84eb26654042b3ca3 +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a1e9af17c43203070c351781f41a5bb0f354cef2 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61c0e2161c5f1faeaabc9d2d727785a3e0c2288f09f842bccd453c8219f6b346 +size 402056 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dbcaf1fb5a458569019f5b64cdcf91884a120b7b --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3637eeb67c7a7131210e6e3de7317c89719269074aeac31140c634ccf9d627a8 +size 174160 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0028ffe2d63f6c9775f5df9c49b7fd46942ac598 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cc6fa6c42b7acb451951acf22773704ad56e8ebb188ac0d79c4bc54e61728f4 +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..548b8dfd3003d48807280f7b853a156f439f8e94 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ec30c0da734e5621dbcc3e10c0a82f537529bbbf5a8739daa7ba60cbd9aa12c +size 1752928 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d38ce9e4238cb6e533f7b1f72f3275a4c83fd7f6 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1d36aba443ad1b262714c6030636b152e3833845bf9a89435927d41d707ba543 +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a948284eea993025adab1a38760a9cc26147a623 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de25dad900afc814c092819616712b1df58ff625de2f02eda01e35eeec54fefd +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..60672cc7d48f5e74f5be4bbf1a52e1576a5c38ce --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c37055c52a45bca095a807af95ee39ecd9570b5d642da437a7b896399ad6139b +size 1752792 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/6/XVCYZ2MT4MD5AXS3ND3O5PR7BOVQSX4DTTBY2BSA3ZO5WI5Z34QQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/6/XVCYZ2MT4MD5AXS3ND3O5PR7BOVQSX4DTTBY2BSA3ZO5WI5Z34QQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..5b7a4b4fab525b4e52fed94b3e9f0f68b59c1cdf --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/6/XVCYZ2MT4MD5AXS3ND3O5PR7BOVQSX4DTTBY2BSA3ZO5WI5Z34QQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e29fc91d464d221f5938cceaa19430438d663b42c7c4db4138e9a0a68660747 +size 170320 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..8206c6911dc372b59777eed9643287f4e3b12268 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d55e59e6fad153629a5b03cfe5a2ced32c43016aa1ce40b67785f0fe7aff35bd +size 173416 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0afe78d518a2c14900e7e61c8bf736ad5f12cb37 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9a692d3fc249c555705e89fc4f6e5d62c0e0c1e0116237faffcc80b55db1d62 +size 3318360 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..308f164ba01bb85475101b61163af940f5c6f861 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ea725e37a89db43a1a5e6c4a58be8d71ea5e258151d75a2c20621faecd52467 +size 463272 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..6d17b29e3b580c9fb56344710c20bdd2e8df49ff --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/AAE26XPY472QBTOITVLGTEZPFUFYYF4ERAT7W7AUASWW6QXG6OAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3458059ec7ea697748cbb8618f38a8ef252fc8380d6a434d817a251bf59ab2d4 +size 173152 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1f68b06cb727f645be8147fbb41e45c657b8b954 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09214a998818470130b01a045e4c984ed47907942163812313f2c4b4bab3e47f +size 173520 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..31ff31ae2c20e7e1f2680b753735912dbaf05999 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/HBK2DBMTACDGZDSOT5QLNDBD7IE3LGCNVWAICYL4KIYOXULISB6A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eeb5bd498188efdafc73a8bfbcec3b97b97c129f82df7b38494a0b366b6458d2 +size 173544 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/HEL2V2TGTTQAZIA4Z6YTLN37YHB3NOHT42672XT6QOAKCALQLPVA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/HEL2V2TGTTQAZIA4Z6YTLN37YHB3NOHT42672XT6QOAKCALQLPVA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..360c568c832d5e34a4a7765ccfd259cd8ff1fbf0 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/HEL2V2TGTTQAZIA4Z6YTLN37YHB3NOHT42672XT6QOAKCALQLPVA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d8c6a1f0dfc8ac4c6f041b4884ffc238a8ccf75bac8a14b04655ffd1e1216920 +size 173520 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9eb0973a01565bda9aa813dd26ef12adac2bc952 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94d2239a474c76076dcff4de4b1bbb416d4267273eeccde745723c82b668f44d +size 463264 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/JYX4GK2BP7KTYXHIDAFN5JFDGUL5VJ5KENA3W23PLOMEDKS6NEWQ/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/JYX4GK2BP7KTYXHIDAFN5JFDGUL5VJ5KENA3W23PLOMEDKS6NEWQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ec4aea9db80f036ea7e3b71e5137616657970476 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/JYX4GK2BP7KTYXHIDAFN5JFDGUL5VJ5KENA3W23PLOMEDKS6NEWQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa770160f61d2fd7d4774768b981492fb2b34cad197b37cf777069a31ce65e26 +size 173280 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0d8eaf2c1da9c5096b15373cc4aac3e702e6d973 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:892fd11e6233e00f61ff01fcc97a907ea46a43177a04f3cf0e98dc3082fefd66 +size 462480 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d91d222722284fbf6d0398f3724d24b55f768e14 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/PZZUDQM7OADBRVVFX6J47YLUXAMZZZ532EBFDR2Z5BH7VQ2G63RA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d702209357b338b23f29c73ca01c0f68de6748a8acfd8995c97f12869ab03d9 +size 1752928 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a57e8820aa9dda0aa30308f9c12e9fcc4a1420c3 --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/SS24AATZGHYM3EPSWQJNQZLPNDNZRUUCTFR2RLOH7Y4C2SEVHIJA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5540776897de8c3056537669f4f6826b78e75c209768cc0f4b15d2dd6309aac6 +size 3318496 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..493a6653780d4dd205de6d40de8b67c7da20220e --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04d02a11a4b38e94afa062eda0881f22990045151fddb2c74bf7731ed28de99b +size 173144 diff --git a/progress/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin b/progress/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dacbbc92266bdedffe6bcf8952b0011e5fc7b92f --- /dev/null +++ b/progress/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5adbf7ecac22edb443a90cc6f8c0ab171e7862cc235d6f7a1993d3a316c3cfa3 +size 404232 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f1111b32b66e2ddf659940ddf2b3761566de33ca --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:132c886d625765401f3e019cc5959ad247ec441c4b51e9e155bf0a46914357b9 +size 735721400 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..907ce655f1a2dd49722e752b6004b175d84340eb --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a2b9099b787b4d3acf78e2d5fa6fb38aecb31ab69b231a15e9ed86b7da7ee0f +size 735557744 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9f0b7da6a3bd3d76f4f7a42d94a0776b7b9413e8 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f999001c24e33174fd773268591ae3681b02d02a651fb57bd8d09f9005ab6352 +size 735095872 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6da1a2c9e03052a4fa96f57fc6bcd40d120bb211 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63ac28124314c75a11231f97948b2b0280c44b2b94b9ca06ead8b3e10969e1b5 +size 732256888 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..575592eb174f034ad074c48f8c6a233f3275aef3 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:297731c4c092a56c5b15b20afd7e1cfcdc8fe0e6389e1ebf83caf9dc036f3c55 +size 733823872 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..96cf85d36ccc757d03a9be9c213aa7bb7183fe98 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:721081d3411c964927b3cef05bef704ac00ef37d4fc166078c840bf79e935530 +size 735340496 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3334996ace7267af0098f8034aa4e79ac365f1da --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5966bb10e2b0de0d52439f258947a7750f4a6deb5647ebb81cca47ab7391e880 +size 736955496 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1f96e14d4d4b65fbf70674cc9b5a7520c4fd2981 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c6c4003f88c3717d190f3cb99bfe24f1e5363392d6b7df24216d0df4b01144f +size 737732272 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b552c287ca623c4690b0b4cf4d8496428f2e5514 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c00e288b4bc7f2662ac1085c1bba556b0b373f33134a75aa3e961fef7d67cbc +size 731997528 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cf64c6f0d6b3a6162fb545766e27c59c78764d22 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e86e86424896fd1cdb40d2fadb007fa1be7aa189757ba49a2a2e5963266916ba +size 734300776 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..00d5bfab07aa01e8fa24a716b12d5d143b488a80 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:639abb78f011e69cd47a321e3c6d6bae9a6428d5d29a70c8ec20030b7fec4245 +size 732017816 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7ae90fbc654a4c5691bb40c02e3359bf4823588b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d69c8c94eccfb1f9cd9def566dc6782281675604171ea31d3c0f76d56434ba62 +size 733279896 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0647f948edb000d70a864286f72990317fdf9cd1 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c23b266c83cbab92268d32038a1f257d35b64f94e850a64903ee35ec4f281b46 +size 734685704 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9c79ad4ce7966812f08e7f2e4880a84cc1f426be --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb741a13f6f8359cd9b86302eeec12d5e10403e7ddaf642bd4e71701dd6032ec +size 732961272 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..86e298197a85ef454e04ce36c095e4dd66587c95 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:930d0c3705341a9cbc9666416baaefc1e0f99867955bcacb610553c510a1fa64 +size 732441392 diff --git a/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ff860383c7a31e6c379908e28c16af0d17fcbda1 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08c4fbfaa28d67217d43a96be17c486803d6f5378b6e079559b678ed4ab480e5 +size 733167752 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00000_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00000_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..56c960ce285b3633c605070bffd60584a2e1e73a --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00000_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47bfa13b10e3594c4863ac1e54190bbec4b0377763bb13e3247d2ddeebc02b40 +size 735721400 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00001_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00001_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..a51e2a65127f02a8216f5a2e7600a68d56917b2c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00001_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddcc1ce4c782756071d6b0a02f38aca26b6052a9a8a4131717b88c257c98d056 +size 735557744 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00002_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00002_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b751786a9acfdaa4a525f4e960e861bda9d434ed --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00002_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:191b33db0781ee4145271e98e8e79cb8bd961e6864618bb9c071eda2139e38cc +size 735095872 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00003_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00003_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0f4b30e9772d270bbe28ad701232ad15ea00cbf1 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00003_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df89e81b21984a4801e09df6848095e351cb918c9d37a78557dce07572e4a3bb +size 732256888 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00004_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00004_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..aec3367abf41301c44faaff75b8121d99feaf8b0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00004_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a88796784d6b33c705eb6748d7a10f2c2a8d4f096ab24a7d60af900b3393241c +size 733823872 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00005_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00005_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2ebd35761daac36caae618806126fa63b8e5cf04 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00005_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3386196d9e1859371b6a25410f554fc06d8eafdfb583a3aecb51c2ffb3497e92 +size 735340496 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00006_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00006_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5c958dba00c5123a5062a37165d0821914219008 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00006_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:855ab1b28c2074e8f9795253e3eb99d7f49b0c4c05899df5546117cbc3d39bb8 +size 736955496 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00007_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00007_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..a34d3491232917b1162a4bc347dc078ab739b3b7 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00007_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:527684a230b880a8defd29fd558396962775f43bd7e0853c6bf1725adf010f6a +size 737732272 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00008_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00008_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..85b21b73615af94f38a0c569800ea6906f22831c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00008_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50b4ffbbb8907716380b347df2a4d82f431f8a95c4fbec53186637a99bc42e7d +size 731997528 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00009_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00009_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..2e55750c4477f713e9d77c625b3d404f2b1902b7 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00009_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb82ddf6bcbcce5895015c710164df0bf92b0524fc8388cec2616e66a1b07683 +size 734300776 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00010_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00010_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..a594a279e4e37dde8924a9aeb00b0edc0cf865ff --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00010_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e339916a9e5a9c5b137d1e916c4ed84e01f0bc12319afb0af0df3551daaec5c8 +size 732017816 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00011_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00011_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..fe63f3b29c6e19d55bc389490260d3a2ea823486 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00011_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f3807e35e5b6fcd58f25ab554732847f2194b896faa376243170277a5c4b46e +size 733279896 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00012_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00012_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..810a7ec864f178d270d0669af55d7860efc76606 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00012_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7b4c093eb19c9dec77c3d1ceadd63f1af431cc8ef9cf73fe970089b78094c3f4 +size 734685704 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00013_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00013_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..32d6ca4b781b0f5ed9411fac8fde70c9d4fd2acd --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00013_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd14946bb4049d3d52e7c49358ae0ea3fd941173e3f18876aa67dc79d08a1cd2 +size 732961272 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00014_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00014_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1309af1d3052465867e323bfe4f94cac446433ee --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00014_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d81d3745bf5eac16f03a01eb9dd5f4e4519dde351956704c162e91ff44e9059a +size 732441392 diff --git a/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00015_of_00016.pkl b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00015_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0ecfbdf0d92b18ad2820614314d400a06867fa77 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/b2b7bdc9eb8a4170c0d33f03d2bf640b_00015_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3053e4ba2be224e1830909bd2f4c6994d58edf5bbffe9c710c00e52b6cb49e18 +size 733167752 diff --git a/progress/SpecForge/cache/processed_dataset/cache-316c3a1fe7a6e6fd.arrow b/progress/SpecForge/cache/processed_dataset/cache-316c3a1fe7a6e6fd.arrow new file mode 100644 index 0000000000000000000000000000000000000000..ed947ce34e103a3bc5bc255704bd962389698c86 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-316c3a1fe7a6e6fd.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fbd71bf2ad7650e1bd2eeea86f2f52b4a601045fc843771d4e4a5a2657bcb2f6 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow b/progress/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow new file mode 100644 index 0000000000000000000000000000000000000000..897af2c3b069371f2129e5205ae92ddeda375cf6 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1db1d3dedad9e7690adaba29a0dfa584d691cda9850556d9a1ef397073392d9 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-556d928a3ad40fa1.arrow b/progress/SpecForge/cache/processed_dataset/cache-556d928a3ad40fa1.arrow new file mode 100644 index 0000000000000000000000000000000000000000..6cb3f4e1e1598fd4c5186bd9df2c9d0785cf3231 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-556d928a3ad40fa1.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f295574d2c42b2e49a2dbe90da52ed21b5a5c37f425e92de850dd7bcd128cd65 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-5c73f9cc755ec578.arrow b/progress/SpecForge/cache/processed_dataset/cache-5c73f9cc755ec578.arrow new file mode 100644 index 0000000000000000000000000000000000000000..95e3e6bef171a8d6a4e8108ec183d8d90453f7cc --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-5c73f9cc755ec578.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d337f7578b5d665ae7b8b9199a5cdf36a8b66e7576cde95dd601fff50433bd6 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow b/progress/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8cd53932a5731bd13ba675852c8987491d8deca9 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aaeda730f17c6c7ecb3025d26f88b92975cced394fc2c7366c0df5d35668490 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow b/progress/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow new file mode 100644 index 0000000000000000000000000000000000000000..eb7a83cc67d41abfac390721eabba7bbe2444bb5 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d790acddc26d55d56e7c17be8f8b22d6c6c570a2faafba2589a030fa4fbd3517 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow b/progress/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow new file mode 100644 index 0000000000000000000000000000000000000000..3fdb7a88291f37bb02abbbbc81b4502ba763e8ab --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf708743744631848d2791290ed5ba7c526fde8b85025afcad213f6315c7bf4b +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow b/progress/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow new file mode 100644 index 0000000000000000000000000000000000000000..35455d51b0e9c05b815b9a2f2a8f5a999526a206 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac4a97457a59253f5f897550abc8e49b3bec59f74ba42319ea0685da21d396a8 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-c0e749602007e32c.arrow b/progress/SpecForge/cache/processed_dataset/cache-c0e749602007e32c.arrow new file mode 100644 index 0000000000000000000000000000000000000000..50e37c1af2615288fc106a7ed378a2418b91d1f0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-c0e749602007e32c.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:31c0bf5e52c134213ec81b1e9d534bfe0701531d69e35855fc8ea532281a97c6 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow b/progress/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow new file mode 100644 index 0000000000000000000000000000000000000000..0b960ae32f8f2789f15e383ad3da43f266a16570 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5120a4fe4250bd6a7b44e910a4e879616ba231f99ee73e51ac5302571e5504f8 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-e79f74cc0defbdc3.arrow b/progress/SpecForge/cache/processed_dataset/cache-e79f74cc0defbdc3.arrow new file mode 100644 index 0000000000000000000000000000000000000000..a8fb3db2bc86291a4bc2fed9af1d6d060f230136 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-e79f74cc0defbdc3.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8dcadb224c77413483ae92c43cae2889c99c52236ce38b91f2b40cac7fb2440 +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/cache-f21c20c54d1c2b68.arrow b/progress/SpecForge/cache/processed_dataset/cache-f21c20c54d1c2b68.arrow new file mode 100644 index 0000000000000000000000000000000000000000..3fe12eabccf69bfb2c4cf46c97084b1ce5d7783c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/cache-f21c20c54d1c2b68.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:070127a9ab51eb320dabab9160bb9fbf8777cb80056d8426f62894dbdd979e1c +size 6459120 diff --git a/progress/SpecForge/cache/processed_dataset/tmp01so9qky b/progress/SpecForge/cache/processed_dataset/tmp01so9qky new file mode 100644 index 0000000000000000000000000000000000000000..d79ef286ba6226980d1f7f15e67fe56c3199e4bf --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp01so9qky @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db6615f9753c47f5b2085cfc74066f52a579018064107871e743ddf74dbd50c1 +size 14008256 diff --git a/progress/SpecForge/cache/processed_dataset/tmp0h3c1gwr b/progress/SpecForge/cache/processed_dataset/tmp0h3c1gwr new file mode 100644 index 0000000000000000000000000000000000000000..b4c8a7165325caff54005cc69ba2423b43b72baf --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp0h3c1gwr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:808ca2a9985298161917fd85ea968aa3df088e82c94baa2dc7a33c302f2e2932 +size 518059464 diff --git a/progress/SpecForge/cache/processed_dataset/tmp0o0ec5hl b/progress/SpecForge/cache/processed_dataset/tmp0o0ec5hl new file mode 100644 index 0000000000000000000000000000000000000000..66a05145e661f981c13ff5db9156f11eb4fa611b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp0o0ec5hl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9912e2b40824906f3b1e5b9e7e78010f2efaed0163d13b8d8e7613c08af42fa5 +size 501623472 diff --git a/progress/SpecForge/cache/processed_dataset/tmp12qwgf9o b/progress/SpecForge/cache/processed_dataset/tmp12qwgf9o new file mode 100644 index 0000000000000000000000000000000000000000..3ea302681f0a88ed1d9dfb80fe634affe36cc7be --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp12qwgf9o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:535d6454c289db1a6140314706ad6715a321c9fa046fd1169273178316bd4d68 +size 14469240 diff --git a/progress/SpecForge/cache/processed_dataset/tmp1bg64fz1 b/progress/SpecForge/cache/processed_dataset/tmp1bg64fz1 new file mode 100644 index 0000000000000000000000000000000000000000..85656573bdc51f9d3ee682d29eb4206f13380036 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp1bg64fz1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:850016fc63d602c65a5a97cbdd4e6bce0955507dfe01a8fcb72c18ce8ba36b5c +size 27985920 diff --git a/progress/SpecForge/cache/processed_dataset/tmp1e9_w76a b/progress/SpecForge/cache/processed_dataset/tmp1e9_w76a new file mode 100644 index 0000000000000000000000000000000000000000..04717103f7ba340a819e1427d282f93c1701d85b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp1e9_w76a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ff1b9c9bedd9867155f90452c530fe455d998636d7e6fdfbc8e4d7cff7abff4 +size 14309592 diff --git a/progress/SpecForge/cache/processed_dataset/tmp1olkr9hg b/progress/SpecForge/cache/processed_dataset/tmp1olkr9hg new file mode 100644 index 0000000000000000000000000000000000000000..32e01064951a44831d3a9d14fde5db509fb4666a --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp1olkr9hg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60e7b092412b38c3bbd43a8704042519e012e177878f5e27d41feb2eede2e65e +size 14610104 diff --git a/progress/SpecForge/cache/processed_dataset/tmp2dv4hduz b/progress/SpecForge/cache/processed_dataset/tmp2dv4hduz new file mode 100644 index 0000000000000000000000000000000000000000..1c0b81ca0b6f901807b9e27f18f44ac6c174e811 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp2dv4hduz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3693010bb9a95e1e7a4f3b59637c60b7da3bdc21d80545873e5ffde7f5d9b6ad +size 488831656 diff --git a/progress/SpecForge/cache/processed_dataset/tmp2rghitts b/progress/SpecForge/cache/processed_dataset/tmp2rghitts new file mode 100644 index 0000000000000000000000000000000000000000..e794c77eb97d5cb195e4152e26d201e02c2d5244 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp2rghitts @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff8234c074f61444a34be85fc081dd97b8bc02d0b9a8338ac33e09bbe6068ddd +size 14208160 diff --git a/progress/SpecForge/cache/processed_dataset/tmp31b6467g b/progress/SpecForge/cache/processed_dataset/tmp31b6467g new file mode 100644 index 0000000000000000000000000000000000000000..1e2d4670bb4d78f0ea39438936fc928d4e00c96c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp31b6467g @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21691227b89f0dbccbbb58054a584d4aa14cd70f895c6064fe58326d9414df02 +size 14685448 diff --git a/progress/SpecForge/cache/processed_dataset/tmp3sts976q b/progress/SpecForge/cache/processed_dataset/tmp3sts976q new file mode 100644 index 0000000000000000000000000000000000000000..2d292d2cd76581f63b1289f3a88de458e44dfe97 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp3sts976q @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff6f95a5558c0e3e94fb7e5cbb9eb1183fe9dbf0c625084d262a7838de9563ab +size 531568008 diff --git a/progress/SpecForge/cache/processed_dataset/tmp3zlhgr3y b/progress/SpecForge/cache/processed_dataset/tmp3zlhgr3y new file mode 100644 index 0000000000000000000000000000000000000000..f30e0213ea72a0076584ba098c1b1a95b2380714 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp3zlhgr3y @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d532983ff065b8a6b5f8ca8c22e5e6afb38b4490a7889b920b69b0b32f75186f +size 14305088 diff --git a/progress/SpecForge/cache/processed_dataset/tmp4mtyrhf4 b/progress/SpecForge/cache/processed_dataset/tmp4mtyrhf4 new file mode 100644 index 0000000000000000000000000000000000000000..00bb26f18ea66b3af2fc480c63188e5ad9a32925 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp4mtyrhf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b67abcb711547061f6e9063dc8f65815698bf2c23d77a6a4344ea827a5cc1505 +size 14390160 diff --git a/progress/SpecForge/cache/processed_dataset/tmp5_v0vecp b/progress/SpecForge/cache/processed_dataset/tmp5_v0vecp new file mode 100644 index 0000000000000000000000000000000000000000..fb4d0062678b3527bd890688efabf9dd6c94e4bb --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp5_v0vecp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c283619f14142c3078b9ee768f67b4389b1d8bfbadcc8743bbc434ccd7f79c7a +size 14299264 diff --git a/progress/SpecForge/cache/processed_dataset/tmp5ohq_16m b/progress/SpecForge/cache/processed_dataset/tmp5ohq_16m new file mode 100644 index 0000000000000000000000000000000000000000..6e6ce25e1ef73b805a2c3b849a864a51080f2543 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp5ohq_16m @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a100f08f82b472412a3a6d351767466e329a20c1f1a24fd37636a44f2d04a5dd +size 460554904 diff --git a/progress/SpecForge/cache/processed_dataset/tmp63npd7ym b/progress/SpecForge/cache/processed_dataset/tmp63npd7ym new file mode 100644 index 0000000000000000000000000000000000000000..23c7866d7059907b606e42bff86df32f4d11e6ce --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp63npd7ym @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:042b6eda84e1d55baa69c169fce104afb097c636f09d87919674d5b21b00d4b7 +size 486895376 diff --git a/progress/SpecForge/cache/processed_dataset/tmp6fzwc_9i b/progress/SpecForge/cache/processed_dataset/tmp6fzwc_9i new file mode 100644 index 0000000000000000000000000000000000000000..5e1c81887298d3fbcbf94341b046850a3170480d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp6fzwc_9i @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b21e31c1a2af88479394c654951c05152cac02d33130471a03d2a685c0704a0 +size 487033200 diff --git a/progress/SpecForge/cache/processed_dataset/tmp6wp8_bfz b/progress/SpecForge/cache/processed_dataset/tmp6wp8_bfz new file mode 100644 index 0000000000000000000000000000000000000000..d7879e613e16a4666903cfcac0233af3fdd634ae --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp6wp8_bfz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:142074e7d6789fbd3f4bd0bd4a6729b03efc9063b9346901c16ce98325acb10f +size 488972088 diff --git a/progress/SpecForge/cache/processed_dataset/tmp7ap84b3p b/progress/SpecForge/cache/processed_dataset/tmp7ap84b3p new file mode 100644 index 0000000000000000000000000000000000000000..8a6494ff40fefa08e23029d3ae4da8db905dd6a1 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp7ap84b3p @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f7fe14827200349ce37068031d15a72a1c7827b129331c137c39be888cd41f7 +size 14549528 diff --git a/progress/SpecForge/cache/processed_dataset/tmp7qa4dv1o b/progress/SpecForge/cache/processed_dataset/tmp7qa4dv1o new file mode 100644 index 0000000000000000000000000000000000000000..628fe944118d8fc0e32e9c710d9a3427c013492f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp7qa4dv1o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a442cfdabb7b59c9afcde255f9bde9034a078b55e83f4822d61468e5d2a57d5 +size 461518336 diff --git a/progress/SpecForge/cache/processed_dataset/tmp839oymis b/progress/SpecForge/cache/processed_dataset/tmp839oymis new file mode 100644 index 0000000000000000000000000000000000000000..c9be5317d347f4988383041606dc97795e371a3e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp839oymis @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65eda2476c3315b8459176862b2cac66674fe47bff1cb39a8be29ea46c3c870b +size 14418328 diff --git a/progress/SpecForge/cache/processed_dataset/tmp8jeu5nng b/progress/SpecForge/cache/processed_dataset/tmp8jeu5nng new file mode 100644 index 0000000000000000000000000000000000000000..9ec00a2cc9ad4fab0ae53eb52dac3046a34778ac --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp8jeu5nng @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fbd03e016559ae8edba3681550ae5c67486ab86eebb500c114e90875fee0408 +size 474376768 diff --git a/progress/SpecForge/cache/processed_dataset/tmp8mzly0vz b/progress/SpecForge/cache/processed_dataset/tmp8mzly0vz new file mode 100644 index 0000000000000000000000000000000000000000..d78709cfd5da53c6ce9c80dfc687c9594dd2bc6e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp8mzly0vz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:026d9317135af7923defc111961718a758c0083c064c320d0b829915b1281a7c +size 14213152 diff --git a/progress/SpecForge/cache/processed_dataset/tmp8uie6nur b/progress/SpecForge/cache/processed_dataset/tmp8uie6nur new file mode 100644 index 0000000000000000000000000000000000000000..3a94da8d44d4c3d93c9b35016ef4245475264e74 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp8uie6nur @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:831744c4048a87dc92965b0dddba06eeb705660db620669043d9ccf74da41a37 +size 13645392 diff --git a/progress/SpecForge/cache/processed_dataset/tmp9w_1gkdb b/progress/SpecForge/cache/processed_dataset/tmp9w_1gkdb new file mode 100644 index 0000000000000000000000000000000000000000..df944ee0f4ab3435fe6d3ac543cb2158acb8e0d2 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp9w_1gkdb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cce8a63ba03fc9e2ca1a2a5da98e4185e0a5503a338e485d24dff1228366ae1 +size 472701720 diff --git a/progress/SpecForge/cache/processed_dataset/tmp9wttwm6t b/progress/SpecForge/cache/processed_dataset/tmp9wttwm6t new file mode 100644 index 0000000000000000000000000000000000000000..9bcb5e6fa36e4269322fa24f728ecb018f0d2132 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp9wttwm6t @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63f3a5f7b9c72771c0adab6482104702815a15a3b01e3b35db5216b5054df020 +size 501732552 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_1rdxt81 b/progress/SpecForge/cache/processed_dataset/tmp_1rdxt81 new file mode 100644 index 0000000000000000000000000000000000000000..4872c14aebec93de6714255530e565a70eb5ef3c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_1rdxt81 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:187cf4c9b1f448699c206b06befbfc8edfb36ba8bd89aef30dc210fa4bef6177 +size 14507192 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_7409t7u b/progress/SpecForge/cache/processed_dataset/tmp_7409t7u new file mode 100644 index 0000000000000000000000000000000000000000..73581aabc40ef4c7d65cbce180ef2e5f11517921 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_7409t7u @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64232b7b419a87af2a4a1066369bdb20e0ac6b7f964e9ca49ef61e3476d8dcfe +size 14234528 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_76bulc_ b/progress/SpecForge/cache/processed_dataset/tmp_76bulc_ new file mode 100644 index 0000000000000000000000000000000000000000..d9c8157a7ba2e3fb854ffc3328c6515f76dccbcf --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_76bulc_ @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dd0868bdfb33109353ef0e76a39dc6a7a3553eeae01033b7191656f48083240f +size 475854248 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_c37vzra b/progress/SpecForge/cache/processed_dataset/tmp_c37vzra new file mode 100644 index 0000000000000000000000000000000000000000..857469eb0bd860d5bb700b2a7199084e2fd7c2d6 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_c37vzra @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38d0bcc8b6725f30240ffc98717a2eb4032a175384924ed35dcbd9efb369de08 +size 14435592 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_f0wuxqs b/progress/SpecForge/cache/processed_dataset/tmp_f0wuxqs new file mode 100644 index 0000000000000000000000000000000000000000..77417cb675c159fe2048c368141d6e8371e020a0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_f0wuxqs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e0970132d41db6e79d32214280ddcdadf3e634d58049b6f48b47b1c376fcc7e +size 14120112 diff --git a/progress/SpecForge/cache/processed_dataset/tmp_ffbik5a b/progress/SpecForge/cache/processed_dataset/tmp_ffbik5a new file mode 100644 index 0000000000000000000000000000000000000000..10ca950be4dc8917fd99591207f79e0024cde211 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmp_ffbik5a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09c2e2707f28ffbdd990312640e43ca705014019ffc5c1c8060199c81ab4eb8f +size 486056424 diff --git a/progress/SpecForge/cache/processed_dataset/tmpa508x4ze b/progress/SpecForge/cache/processed_dataset/tmpa508x4ze new file mode 100644 index 0000000000000000000000000000000000000000..996fbdce74c8e100642f5e6717c16c3b5c71e56d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpa508x4ze @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:139da899c7495ebc2d99be30f05743e58b1d7af033369b90fbf2e96113ace54f +size 516713944 diff --git a/progress/SpecForge/cache/processed_dataset/tmpaha5jma4 b/progress/SpecForge/cache/processed_dataset/tmpaha5jma4 new file mode 100644 index 0000000000000000000000000000000000000000..bc40d0833389341a0a54b9dd041fe919abfca14f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpaha5jma4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03ac3452414897c7ba7c0f30ae3df647657735a99fe24b02c66c57d62f6b6948 +size 472640136 diff --git a/progress/SpecForge/cache/processed_dataset/tmpaswc6t6a b/progress/SpecForge/cache/processed_dataset/tmpaswc6t6a new file mode 100644 index 0000000000000000000000000000000000000000..9d9cd57143a382efe1599d7b32f7d00bfc1ca560 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpaswc6t6a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e48377fdcbd661adcecdf4a212c58a0bb2bd2358b4158f78bcd9b5eb209b0d48 +size 14128576 diff --git a/progress/SpecForge/cache/processed_dataset/tmpb5ufd_3k b/progress/SpecForge/cache/processed_dataset/tmpb5ufd_3k new file mode 100644 index 0000000000000000000000000000000000000000..d2519aa3cc7a07dbd63d21c5c442a7a3317300f6 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpb5ufd_3k @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93c58e0177cb18a21a7dbbf16cc10c6e90f59cc3a491445ec64dd058aef6e0e7 +size 14375008 diff --git a/progress/SpecForge/cache/processed_dataset/tmpbdk_etgi b/progress/SpecForge/cache/processed_dataset/tmpbdk_etgi new file mode 100644 index 0000000000000000000000000000000000000000..96abed7f69dd9cb75957a4c6f110131b013d793a --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpbdk_etgi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce27ba4484509b09a3a98a939735b5291ae432f6a17c4fe1207168bd9e5f6a1a +size 487033200 diff --git a/progress/SpecForge/cache/processed_dataset/tmpc8k1wpao b/progress/SpecForge/cache/processed_dataset/tmpc8k1wpao new file mode 100644 index 0000000000000000000000000000000000000000..32817148393655f0e0d65e1d87e6e80bcc2ade4f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpc8k1wpao @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:170e85a998af0fc7cf916d3541090dce8480b695bf03b0e96da7961aa6606681 +size 14232504 diff --git a/progress/SpecForge/cache/processed_dataset/tmpco2q4qoj b/progress/SpecForge/cache/processed_dataset/tmpco2q4qoj new file mode 100644 index 0000000000000000000000000000000000000000..9d26a4d08a10c4f9da0d4f3fb5bb1635de9baa2d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpco2q4qoj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b8ef6b71ae10364880354f1396f613a30ee7fe69bfa4850596e90a93b8f45ac1 +size 501623472 diff --git a/progress/SpecForge/cache/processed_dataset/tmpcv0d9wzf b/progress/SpecForge/cache/processed_dataset/tmpcv0d9wzf new file mode 100644 index 0000000000000000000000000000000000000000..62e0781c69865e78a4c9aef5589d5814b5953b7d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpcv0d9wzf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e548789b824fc02508aaaf05fab42f7ffc47965a90181707f640e6fc8dbf3b8a +size 14575760 diff --git a/progress/SpecForge/cache/processed_dataset/tmpcyc3tt25 b/progress/SpecForge/cache/processed_dataset/tmpcyc3tt25 new file mode 100644 index 0000000000000000000000000000000000000000..e265465c75dc57b2906fa81e02ebc6d381930e4b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpcyc3tt25 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68c0832a4ade3e7759d607c7acd7e52af04591e41edb5986f0a07253dfce7fb8 +size 472701720 diff --git a/progress/SpecForge/cache/processed_dataset/tmpd48uryj7 b/progress/SpecForge/cache/processed_dataset/tmpd48uryj7 new file mode 100644 index 0000000000000000000000000000000000000000..b3a52d1fa9af99b28ccdc905f0048ce042ea553f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpd48uryj7 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97d3844307498a418315eae4cd732cedfded53546b5dcd32db387250dfbb2874 +size 515036456 diff --git a/progress/SpecForge/cache/processed_dataset/tmpdbim2npk b/progress/SpecForge/cache/processed_dataset/tmpdbim2npk new file mode 100644 index 0000000000000000000000000000000000000000..8a35eff8200c1dbeff9382553849e4377775597e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpdbim2npk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b7d33855d7d9d61cd886d3c906b06df1ef4a23aaadd0e38c4caec8a16caa36d +size 14694400 diff --git a/progress/SpecForge/cache/processed_dataset/tmpdof5i3di b/progress/SpecForge/cache/processed_dataset/tmpdof5i3di new file mode 100644 index 0000000000000000000000000000000000000000..c64fd0a2957f5e6ab3569026a392136fba9c6c2e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpdof5i3di @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b8d465005bcbe007f75fbfc40d052755a43339e5d1e5725960cc5d0fb8f0a09 +size 14838328 diff --git a/progress/SpecForge/cache/processed_dataset/tmpdrvr46bq b/progress/SpecForge/cache/processed_dataset/tmpdrvr46bq new file mode 100644 index 0000000000000000000000000000000000000000..7d7ebb61f43847a6d2950f63eeebd17b6335ab57 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpdrvr46bq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7954aaecbf8c55b01f14b00bca050e7e3fa294af5056564ae341bb86944288f2 +size 14471528 diff --git a/progress/SpecForge/cache/processed_dataset/tmpe4nf2zns b/progress/SpecForge/cache/processed_dataset/tmpe4nf2zns new file mode 100644 index 0000000000000000000000000000000000000000..c286eb4d97d72d59f12ac94e6fd66c9ab108dd32 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpe4nf2zns @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0d065afe26e219d664f5623c807307595ef54dc1b8669a586c2b2d925ad6ecfc +size 489368576 diff --git a/progress/SpecForge/cache/processed_dataset/tmpe_yqe1zz b/progress/SpecForge/cache/processed_dataset/tmpe_yqe1zz new file mode 100644 index 0000000000000000000000000000000000000000..5df8b760ceeb0071dcb52f32bd843d145b5dddae --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpe_yqe1zz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:621aecec64a2d05c8d1a38c678757888302dc82d36604261e1cb5c4ab7919140 +size 14125832 diff --git a/progress/SpecForge/cache/processed_dataset/tmpei5ah9j_ b/progress/SpecForge/cache/processed_dataset/tmpei5ah9j_ new file mode 100644 index 0000000000000000000000000000000000000000..085ed4d37397aa6a75bc08724c9da0279033cf41 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpei5ah9j_ @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:494498607bed3a91a834928a1f80b46e3f941fb5f219a72915b3551a1b54d230 +size 14201920 diff --git a/progress/SpecForge/cache/processed_dataset/tmpfbj_hvmg b/progress/SpecForge/cache/processed_dataset/tmpfbj_hvmg new file mode 100644 index 0000000000000000000000000000000000000000..21774f85d51670bf903f550170478236cc9de2f0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpfbj_hvmg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1200d98242813cde1971641f3003efb206d9b32e073f8455775627de1eaf1fcf +size 14697016 diff --git a/progress/SpecForge/cache/processed_dataset/tmpfuuhammv b/progress/SpecForge/cache/processed_dataset/tmpfuuhammv new file mode 100644 index 0000000000000000000000000000000000000000..27b2a68296e49ee51006bd81d87b954abe456ffe --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpfuuhammv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0dc4c385c82a5171eee984bd5036f0316b9d3174a90c5cb927d4cc8f30e302e +size 14949680 diff --git a/progress/SpecForge/cache/processed_dataset/tmpfwb2ckp1 b/progress/SpecForge/cache/processed_dataset/tmpfwb2ckp1 new file mode 100644 index 0000000000000000000000000000000000000000..71e87a58651d19ea4d9f292ce6d084444b6f9c50 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpfwb2ckp1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3ee6965e2ce70f29fd7a3fb54c5fe0cbc0dcfcfa3e2e8bd545dd59fc0d8bb3c +size 14296152 diff --git a/progress/SpecForge/cache/processed_dataset/tmpfz9hw9rn b/progress/SpecForge/cache/processed_dataset/tmpfz9hw9rn new file mode 100644 index 0000000000000000000000000000000000000000..4d89fba6ce3f538ba57b502434d50a38f99193dd --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpfz9hw9rn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:83c5a15aa88ad5d05e870dbd691ed399e232448866a5b1dc36b6e5810ea9a980 +size 28418544 diff --git a/progress/SpecForge/cache/processed_dataset/tmpghrphlfd b/progress/SpecForge/cache/processed_dataset/tmpghrphlfd new file mode 100644 index 0000000000000000000000000000000000000000..c7b62a0fe402fbe66a98e7eb13b4d62009820607 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpghrphlfd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b732b8c8b4bc5b03e76b818480560ae14ff4f55fb69bf849c7adbfcfad626a66 +size 489368576 diff --git a/progress/SpecForge/cache/processed_dataset/tmpglpc56el b/progress/SpecForge/cache/processed_dataset/tmpglpc56el new file mode 100644 index 0000000000000000000000000000000000000000..542276133ba7fb5494aec2a76a1569cda49a0088 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpglpc56el @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c03f71686600f2a2dac9e61b2ba6857356d5fb062dedfbacf870865432322d19 +size 457286272 diff --git a/progress/SpecForge/cache/processed_dataset/tmpgr9rw0_h b/progress/SpecForge/cache/processed_dataset/tmpgr9rw0_h new file mode 100644 index 0000000000000000000000000000000000000000..4c7ba5edac6ef33ce3d33067001ccef4316476c9 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpgr9rw0_h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a36f169e73c9e16e49514fe0a3ead45f69208927930231533a102e51a895f67 +size 14559528 diff --git a/progress/SpecForge/cache/processed_dataset/tmpgszlo7oq b/progress/SpecForge/cache/processed_dataset/tmpgszlo7oq new file mode 100644 index 0000000000000000000000000000000000000000..a1557a92c6c4f699d4200de783920a5f4ac362d7 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpgszlo7oq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:315988bf5b6e683b3a5270a73d064b9d4d76b112a7d0b2f27b8221420af3615e +size 14329432 diff --git a/progress/SpecForge/cache/processed_dataset/tmph2q3gygm b/progress/SpecForge/cache/processed_dataset/tmph2q3gygm new file mode 100644 index 0000000000000000000000000000000000000000..cc332ca94c3de5b1f87796fccae600cb5ed817fc --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmph2q3gygm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7f105a84e27e16fc3a26618e0ba566e6b2c4b64f1a04fede99c9aeb4daec489 +size 472899832 diff --git a/progress/SpecForge/cache/processed_dataset/tmph93s_2g1 b/progress/SpecForge/cache/processed_dataset/tmph93s_2g1 new file mode 100644 index 0000000000000000000000000000000000000000..786d5351bf1f28648cfa032430b3a24f56751fc4 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmph93s_2g1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1174bee728f89020c9d1ebc98eb4770dc8e86e49d26bcaaa1cd6976d707ecbf0 +size 14203256 diff --git a/progress/SpecForge/cache/processed_dataset/tmphnnjjotg b/progress/SpecForge/cache/processed_dataset/tmphnnjjotg new file mode 100644 index 0000000000000000000000000000000000000000..41d4f6e3cdd8d4e811de7613694c85eefccd2a60 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmphnnjjotg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc77f4895cef16aec80fe001a52ade769aa4ca217e8bef768fc9f20525de2c74 +size 458758424 diff --git a/progress/SpecForge/cache/processed_dataset/tmpi_zlx6tj b/progress/SpecForge/cache/processed_dataset/tmpi_zlx6tj new file mode 100644 index 0000000000000000000000000000000000000000..97d8d3772138b611ad06a7cdcc84932b0e4da07e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpi_zlx6tj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3cb9ac452eb842b28f1aa527f777ee6eb16e59e2b7b664f5c05eed1821d55fd9 +size 530961696 diff --git a/progress/SpecForge/cache/processed_dataset/tmpicvvi414 b/progress/SpecForge/cache/processed_dataset/tmpicvvi414 new file mode 100644 index 0000000000000000000000000000000000000000..ddc6e0fa67f74e2cbe9cc19a53b98a5d21fe4403 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpicvvi414 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81cf6fe1d42a1134c9fb6778bd023a2f1d3d8515cdb99ed32f942f1eed51c7cd +size 501623472 diff --git a/progress/SpecForge/cache/processed_dataset/tmpinvido_z b/progress/SpecForge/cache/processed_dataset/tmpinvido_z new file mode 100644 index 0000000000000000000000000000000000000000..4be9c195c69600d43788fc5d6cc4cb0df95860e6 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpinvido_z @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cc791cd4fb0f50e0ee56bd959c89403771d2abc7bd4cbdc7e1d0b66ad75146c +size 28822072 diff --git a/progress/SpecForge/cache/processed_dataset/tmpiqh2jriw b/progress/SpecForge/cache/processed_dataset/tmpiqh2jriw new file mode 100644 index 0000000000000000000000000000000000000000..5e868a5a3d16ee3d104fc4e49a988babbf46db5f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpiqh2jriw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9bd8768af7a7b827718d2d16d7c7cb61d5c968a61bad19f353dd8a5c3f2b3a0 +size 475935496 diff --git a/progress/SpecForge/cache/processed_dataset/tmpj1355egn b/progress/SpecForge/cache/processed_dataset/tmpj1355egn new file mode 100644 index 0000000000000000000000000000000000000000..184a08ba350248515e1e15d78742ce608ff68df3 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpj1355egn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3724358cc8ab218e8e3e68080c3b635ce8623e2287a8138407c1d360c9a7d05 +size 14339544 diff --git a/progress/SpecForge/cache/processed_dataset/tmpjccpfqmi b/progress/SpecForge/cache/processed_dataset/tmpjccpfqmi new file mode 100644 index 0000000000000000000000000000000000000000..6936eb6d6fe5ffbb3600843435caca3e808b9280 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpjccpfqmi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b33cc8b0968eadd5f1989cf0fcce2de1c7aaf50a5295e62e47880d82631dbd0 +size 14546144 diff --git a/progress/SpecForge/cache/processed_dataset/tmpjp0seuji b/progress/SpecForge/cache/processed_dataset/tmpjp0seuji new file mode 100644 index 0000000000000000000000000000000000000000..517561880763045e2115dc00e7302f6e41e94268 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpjp0seuji @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9786f0420afef0a6f9709665015df76a539e8c4551fec3ef61bd41acb12b8195 +size 487511368 diff --git a/progress/SpecForge/cache/processed_dataset/tmpk5b32oqt b/progress/SpecForge/cache/processed_dataset/tmpk5b32oqt new file mode 100644 index 0000000000000000000000000000000000000000..9503a0fe1f6eb8860ac0e5e5566c5eb19e3a750c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpk5b32oqt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e14d71e747a49c2a23df2952ac438301a60015b23e2409a8b3d1418020c860f +size 14258064 diff --git a/progress/SpecForge/cache/processed_dataset/tmpkx1kbis9 b/progress/SpecForge/cache/processed_dataset/tmpkx1kbis9 new file mode 100644 index 0000000000000000000000000000000000000000..b26e27ece6e7d77613d6efa5cf480522ca235eec --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpkx1kbis9 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f1397753abda5e31b52f4656a1fd88f1018b51180eeca345e035e057f097bb6 +size 14570896 diff --git a/progress/SpecForge/cache/processed_dataset/tmpky8ztc3l b/progress/SpecForge/cache/processed_dataset/tmpky8ztc3l new file mode 100644 index 0000000000000000000000000000000000000000..30d5a41983810d95ad8c9cf100f24df564800c87 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpky8ztc3l @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4032f840e31345fad47c1d73f2a8cdbfd717bbb395d26e015966aa8620f39125 +size 14312816 diff --git a/progress/SpecForge/cache/processed_dataset/tmpl94c7jxi b/progress/SpecForge/cache/processed_dataset/tmpl94c7jxi new file mode 100644 index 0000000000000000000000000000000000000000..c7b995711ebba4af84765109ae8b1b08a60df5d4 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpl94c7jxi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb68c302ae1c921eb34592b6208dc51a94e7ba534b64992d0f98b6cc9c793dfc +size 14229592 diff --git a/progress/SpecForge/cache/processed_dataset/tmplij7ouu8 b/progress/SpecForge/cache/processed_dataset/tmplij7ouu8 new file mode 100644 index 0000000000000000000000000000000000000000..efdd64711b429550fd29166c3e6469b84d3e1bc6 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmplij7ouu8 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bffd832127a0e7e1c195bfc4cc7a94ef83f140a207d6e20b9acb6ff8685c68c +size 515230272 diff --git a/progress/SpecForge/cache/processed_dataset/tmplr1d0pbd b/progress/SpecForge/cache/processed_dataset/tmplr1d0pbd new file mode 100644 index 0000000000000000000000000000000000000000..f6be9a7ba3039f9496dd3cecdd1e55219ceeb19c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmplr1d0pbd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49fa72c472f3ae87e32c34005ea114fa13028e60e7025bfa8e6c1b32760eede2 +size 472959816 diff --git a/progress/SpecForge/cache/processed_dataset/tmpluqfik5a b/progress/SpecForge/cache/processed_dataset/tmpluqfik5a new file mode 100644 index 0000000000000000000000000000000000000000..5bfc5f0afdc12f80266f80183faa8175bf358164 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpluqfik5a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c852c369f52b1ada33d800da23bb65c9f784e613584b346be5d55479359e4d35 +size 14005624 diff --git a/progress/SpecForge/cache/processed_dataset/tmplx6mijvc b/progress/SpecForge/cache/processed_dataset/tmplx6mijvc new file mode 100644 index 0000000000000000000000000000000000000000..bc15b016fe029db7fa7138887727217f80df6227 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmplx6mijvc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a2afe0d731e023566e7d688d314545ffb8667b9644b89faa5e6c85a48580328 +size 14035736 diff --git a/progress/SpecForge/cache/processed_dataset/tmplybow6c1 b/progress/SpecForge/cache/processed_dataset/tmplybow6c1 new file mode 100644 index 0000000000000000000000000000000000000000..df7c13dc522ea7adee691d2d8ba65ad11cb4928f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmplybow6c1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e84f78f6b06d9969d4e507bed05ecadfd588d14c8709cc6409f68fcbe52a05f +size 518843248 diff --git a/progress/SpecForge/cache/processed_dataset/tmpm9ca334x b/progress/SpecForge/cache/processed_dataset/tmpm9ca334x new file mode 100644 index 0000000000000000000000000000000000000000..dc42a5b6ec538e4eb17f5e557096be4cd26be024 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpm9ca334x @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fce5a7ddbec7002564f20974d29902d47464ee246b8b36d907a19b02a3a7873 +size 473072952 diff --git a/progress/SpecForge/cache/processed_dataset/tmpmu8bav05 b/progress/SpecForge/cache/processed_dataset/tmpmu8bav05 new file mode 100644 index 0000000000000000000000000000000000000000..1d620b6779fcd2a71108d473de5c272160a32796 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpmu8bav05 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ac682e9dc98243e44078bbd0254a44e7ce771a42b1c172978c7d83bb76cb838 +size 14717200 diff --git a/progress/SpecForge/cache/processed_dataset/tmpn3tpi7x_ b/progress/SpecForge/cache/processed_dataset/tmpn3tpi7x_ new file mode 100644 index 0000000000000000000000000000000000000000..c58607363f7e68267954928dfd3be43a429d6dc9 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpn3tpi7x_ @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fcd24346a1ca76e25c71579d511141026fd8268df65f3e81848a8befd37eb78 +size 14576720 diff --git a/progress/SpecForge/cache/processed_dataset/tmpndtuj2n8 b/progress/SpecForge/cache/processed_dataset/tmpndtuj2n8 new file mode 100644 index 0000000000000000000000000000000000000000..1d48a8e3998c9de529351f30b729fed117717c1b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpndtuj2n8 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06b2313b25f58e9a3ee4308372565413cfaae4b646f2621b80d7bb2714fd1e9d +size 473338424 diff --git a/progress/SpecForge/cache/processed_dataset/tmpnf1xv0v2 b/progress/SpecForge/cache/processed_dataset/tmpnf1xv0v2 new file mode 100644 index 0000000000000000000000000000000000000000..35ee30be4b2b81df37bd837deed335878938190b --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpnf1xv0v2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a86b98be57d4d71abfcd2c3ab75be82b6a708d36913f31bae51ce3be0dc047e1 +size 488831656 diff --git a/progress/SpecForge/cache/processed_dataset/tmpo340xjlj b/progress/SpecForge/cache/processed_dataset/tmpo340xjlj new file mode 100644 index 0000000000000000000000000000000000000000..8e7c95e2e20f4ec00464824b654f0bc2cd969ef7 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpo340xjlj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f91a200da3edbb0e6c3a2d769f012717f0dae48344eae8108d2c109dfa9206cb +size 14367552 diff --git a/progress/SpecForge/cache/processed_dataset/tmpo3nudsla b/progress/SpecForge/cache/processed_dataset/tmpo3nudsla new file mode 100644 index 0000000000000000000000000000000000000000..7fb04d7bb4f3f3ee976978dfbd779579dbfcbf60 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpo3nudsla @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fda3b87ef0571683fdc35591982b93525e2b09fb140583c26cef5291ea78c3c3 +size 487715680 diff --git a/progress/SpecForge/cache/processed_dataset/tmpo7jb0q89 b/progress/SpecForge/cache/processed_dataset/tmpo7jb0q89 new file mode 100644 index 0000000000000000000000000000000000000000..e949abbbaeb9623087a9bc81fd886b70145e01b9 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpo7jb0q89 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e41ad0bc36c59a77e93401b3fdf4d96607989a428b2b8e542e67d3004abbbf5 +size 14341280 diff --git a/progress/SpecForge/cache/processed_dataset/tmpo7o8udng b/progress/SpecForge/cache/processed_dataset/tmpo7o8udng new file mode 100644 index 0000000000000000000000000000000000000000..37d0f0f46c52793db5dad4a0a7865adadaa87f66 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpo7o8udng @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:02d2aaf6bc9e675fdb8e9e752165668106fafcfe2f5f3847c0904b230bf5fb38 +size 461402304 diff --git a/progress/SpecForge/cache/processed_dataset/tmpofiedrhp b/progress/SpecForge/cache/processed_dataset/tmpofiedrhp new file mode 100644 index 0000000000000000000000000000000000000000..f6bf1aa76cfaea62894169f88c9b7fb9a7524ea4 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpofiedrhp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e05cafac414a1f605eef36e7498457b2e8bd649d8b504af1a01bc35f2063530 +size 487531336 diff --git a/progress/SpecForge/cache/processed_dataset/tmpoftc3flv b/progress/SpecForge/cache/processed_dataset/tmpoftc3flv new file mode 100644 index 0000000000000000000000000000000000000000..6e0e11198beed94f5736ae4bffcd0d9106ccd3e9 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpoftc3flv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcd010828fcc2138e27f16065338b76124093ab7a165d7cc7f862139211c9965 +size 488453488 diff --git a/progress/SpecForge/cache/processed_dataset/tmpqjqf7u2l b/progress/SpecForge/cache/processed_dataset/tmpqjqf7u2l new file mode 100644 index 0000000000000000000000000000000000000000..0df253cc8ce829c137b1ddc39f57d0aaea836815 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpqjqf7u2l @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30cd5ddf9b43ec1079431b1c59c6647a44419c5a77885296a2d5c46c05b6d867 +size 14499472 diff --git a/progress/SpecForge/cache/processed_dataset/tmpqkt5jm8t b/progress/SpecForge/cache/processed_dataset/tmpqkt5jm8t new file mode 100644 index 0000000000000000000000000000000000000000..ad14a28787510c3f2ae71250cec621e534bbad22 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpqkt5jm8t @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81cdf82896389c1d49821af6d5ccdcf8af74847da98ebd58ea6cfe7d45b99e0a +size 487888488 diff --git a/progress/SpecForge/cache/processed_dataset/tmpqpwxjunu b/progress/SpecForge/cache/processed_dataset/tmpqpwxjunu new file mode 100644 index 0000000000000000000000000000000000000000..1b1c4a1ab89f1497ea4d5247b1fe79fb1eb26267 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpqpwxjunu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9858591e5a9750b7588edd5a63c237beefc9cd3dc3b94d6ff307985a31ebbeac +size 14412920 diff --git a/progress/SpecForge/cache/processed_dataset/tmpqs4xxvi3 b/progress/SpecForge/cache/processed_dataset/tmpqs4xxvi3 new file mode 100644 index 0000000000000000000000000000000000000000..17781d8166c4639b88440c45197808343562dd9d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpqs4xxvi3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:872fdb18356057cf19bd1bad97fdaec05ee15963155293f18c767d6ac7a86802 +size 14193968 diff --git a/progress/SpecForge/cache/processed_dataset/tmpruq5gh5h b/progress/SpecForge/cache/processed_dataset/tmpruq5gh5h new file mode 100644 index 0000000000000000000000000000000000000000..3709f504cba5bcaaa77a41aa39033a20d735ea9c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpruq5gh5h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e2c00be5f5333a5b3342d896f928453841eb87c64b00cea2c22543c761ce14f9 +size 14478288 diff --git a/progress/SpecForge/cache/processed_dataset/tmpsaud7inh b/progress/SpecForge/cache/processed_dataset/tmpsaud7inh new file mode 100644 index 0000000000000000000000000000000000000000..f8ab301489f61cb32e4be5d112f1884e41e35b3f --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpsaud7inh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:863ca028ae0bb623fdf1f88720fb6e4f058b7f2ffbde4ef7214414f5630d2779 +size 14363408 diff --git a/progress/SpecForge/cache/processed_dataset/tmpstdi1exz b/progress/SpecForge/cache/processed_dataset/tmpstdi1exz new file mode 100644 index 0000000000000000000000000000000000000000..93ebc0250356dac599c7d3c4eb6fbe86066e3a96 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpstdi1exz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2178c3ae41dd903b69cb8dcbbbfd83ce5fbf86db0a274cec0a532798c3910fe9 +size 14662024 diff --git a/progress/SpecForge/cache/processed_dataset/tmpsykkhwag b/progress/SpecForge/cache/processed_dataset/tmpsykkhwag new file mode 100644 index 0000000000000000000000000000000000000000..f1cdc1f646f112f22b14256144a0467d05f1b361 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpsykkhwag @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:52440467251a7f4c15b2a062f75ce4f05b9c1e67ad0907ebee16a31e53ff5785 +size 475190256 diff --git a/progress/SpecForge/cache/processed_dataset/tmptj9k8ln1 b/progress/SpecForge/cache/processed_dataset/tmptj9k8ln1 new file mode 100644 index 0000000000000000000000000000000000000000..91a07d18562760305c0107043b9ecfd0157cbd8d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmptj9k8ln1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c69780d36b75ccf0541248bd7588b860925eb000ca78a72a5308dbd98e4d4d1c +size 487511368 diff --git a/progress/SpecForge/cache/processed_dataset/tmptqvqvpdk b/progress/SpecForge/cache/processed_dataset/tmptqvqvpdk new file mode 100644 index 0000000000000000000000000000000000000000..7b1a67ad9c40789f61232ba7d3a0ee5de2ee8fb0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmptqvqvpdk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92d2050b80737ef74ece2d0ee9c62546842b4e3c4990107e8947f087c3a6a89b +size 14496864 diff --git a/progress/SpecForge/cache/processed_dataset/tmpu7s66cjj b/progress/SpecForge/cache/processed_dataset/tmpu7s66cjj new file mode 100644 index 0000000000000000000000000000000000000000..c4d667c80f57ad30b2df0bc1678cb1d38cea9480 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpu7s66cjj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed7717e339b26bc7ac4ed1da09c7011f6453460edeb0636a0ea1ac728a4e90fc +size 14351480 diff --git a/progress/SpecForge/cache/processed_dataset/tmpu_vaznd1 b/progress/SpecForge/cache/processed_dataset/tmpu_vaznd1 new file mode 100644 index 0000000000000000000000000000000000000000..e080a2a5d9a2d991039c0e82ec4dd195a7c04086 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpu_vaznd1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35b4a01de87218418767a44e44573762faf9cd767267bf6ae4198f5dfb6dfa96 +size 14429400 diff --git a/progress/SpecForge/cache/processed_dataset/tmpv8xdp85p b/progress/SpecForge/cache/processed_dataset/tmpv8xdp85p new file mode 100644 index 0000000000000000000000000000000000000000..24362adcd7113c1ebc04325d9842e732d8a0b0d5 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpv8xdp85p @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04a02511311b4deb271488ba63b4183c68dab0801a0d464304aef7132571d082 +size 488972088 diff --git a/progress/SpecForge/cache/processed_dataset/tmpwokpzxbw b/progress/SpecForge/cache/processed_dataset/tmpwokpzxbw new file mode 100644 index 0000000000000000000000000000000000000000..abbce804072ba4826e11bc068260927dd39acf7c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpwokpzxbw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da5cae1766e6b4ef121502b532aa0159708aa2177f8d9c19797cc7fd367afd38 +size 14520848 diff --git a/progress/SpecForge/cache/processed_dataset/tmpwq89ng3z b/progress/SpecForge/cache/processed_dataset/tmpwq89ng3z new file mode 100644 index 0000000000000000000000000000000000000000..5619fa65cca90775b1360cb0da857d18c5b071a8 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpwq89ng3z @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14ad6c44805732fb971151aa5abfb296219f96c8e9a090d8e840d876d18903b9 +size 14664576 diff --git a/progress/SpecForge/cache/processed_dataset/tmpwvln4iw8 b/progress/SpecForge/cache/processed_dataset/tmpwvln4iw8 new file mode 100644 index 0000000000000000000000000000000000000000..30f9cc78af4e7088ce0a47a26fa25ae0573fd79e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpwvln4iw8 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e92b685c9313c4f0063ecdff6588451ea542af0213f6ea9d04ee1e3cfb9848e +size 28655320 diff --git a/progress/SpecForge/cache/processed_dataset/tmpxbmp3uq0 b/progress/SpecForge/cache/processed_dataset/tmpxbmp3uq0 new file mode 100644 index 0000000000000000000000000000000000000000..ba1981fc799a3faca8e19499a69c6715976fc2c0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpxbmp3uq0 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81c4779703ea91b12b1d0679a2d98a4e34353b1aa412cb4ebd92714c4ac9a08d +size 502204432 diff --git a/progress/SpecForge/cache/processed_dataset/tmpxk7g3wl5 b/progress/SpecForge/cache/processed_dataset/tmpxk7g3wl5 new file mode 100644 index 0000000000000000000000000000000000000000..1758ff8a6d902b746b9a5d3cd68e2fb04427f21c --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpxk7g3wl5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea6abdc99db80dfc4dabcda998016c14b4a536aeae9c48a7385abd07faadab62 +size 457286272 diff --git a/progress/SpecForge/cache/processed_dataset/tmpxzf5tfs9 b/progress/SpecForge/cache/processed_dataset/tmpxzf5tfs9 new file mode 100644 index 0000000000000000000000000000000000000000..253730d3225a0d52074ca160e9e590592ad8dcce --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpxzf5tfs9 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cbc28cd2d84d82aebfa5f0dc8eed7e97f308b442e821810b1716bf259d96aae5 +size 461402304 diff --git a/progress/SpecForge/cache/processed_dataset/tmpy2x5wfyd b/progress/SpecForge/cache/processed_dataset/tmpy2x5wfyd new file mode 100644 index 0000000000000000000000000000000000000000..03b4f308eb645d3fe62261a7dce6efaf933e8276 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpy2x5wfyd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:317d35e41e35a48fc782bbc4427bdd896a817d3383b4aa0a339c7284ddf5abd4 +size 13988392 diff --git a/progress/SpecForge/cache/processed_dataset/tmpyhujpj1h b/progress/SpecForge/cache/processed_dataset/tmpyhujpj1h new file mode 100644 index 0000000000000000000000000000000000000000..107fd2321e9869745b58a92938ffa42b5196ece1 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpyhujpj1h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97788196d246c60dc725b4ae3d60d1702741985eef99fc73f64a2c5c513d4a2f +size 14912032 diff --git a/progress/SpecForge/cache/processed_dataset/tmpyvnh9pse b/progress/SpecForge/cache/processed_dataset/tmpyvnh9pse new file mode 100644 index 0000000000000000000000000000000000000000..1574b1d1da433a584739753256e8545bc3ce248d --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpyvnh9pse @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4c0e00828ec5274470da0cb756d2bd27d70d91c95960c540ef6a10a18277937 +size 460554904 diff --git a/progress/SpecForge/cache/processed_dataset/tmpzc3wkb46 b/progress/SpecForge/cache/processed_dataset/tmpzc3wkb46 new file mode 100644 index 0000000000000000000000000000000000000000..264325607c08de68a29cda9ca641fe6c43b6eca0 --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpzc3wkb46 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1cebf91c168d2e3467a02af30f3ead0300f96b3e2f07ff79ed51f806b8d3c766 +size 473338424 diff --git a/progress/SpecForge/cache/processed_dataset/tmpzrflqnck b/progress/SpecForge/cache/processed_dataset/tmpzrflqnck new file mode 100644 index 0000000000000000000000000000000000000000..48bec8ce02ba32a57381327cbaf374e6f8c646fa --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpzrflqnck @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9303bdfe20af46910227968c6c71fd109ef4844e86e84dc352afa76aba27bec5 +size 14265816 diff --git a/progress/SpecForge/cache/processed_dataset/tmpzyqafx5e b/progress/SpecForge/cache/processed_dataset/tmpzyqafx5e new file mode 100644 index 0000000000000000000000000000000000000000..6091bf671968f7170eafd16470f17f51e6e9288e --- /dev/null +++ b/progress/SpecForge/cache/processed_dataset/tmpzyqafx5e @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7d2c2a6ab1e82b1b10aede9b9397fc310d8ce9f4f392020429ca75e3847aa6b +size 14488104 diff --git a/progress/SpecForge/docs/_static/imgs/specbundle-logo.png b/progress/SpecForge/docs/_static/imgs/specbundle-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4f80b7247e2850e047b11b0d3747893922f35c1 --- /dev/null +++ b/progress/SpecForge/docs/_static/imgs/specbundle-logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:491edeb3e50c472046cdaae93f8158f0fe70be1d16282f6397a622f67fa80d5a +size 224984 diff --git a/progress/SpecForge/docs/spec_bundle/public/logo.ico b/progress/SpecForge/docs/spec_bundle/public/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dfee01264af823a48c4558a6c806a062be0c669 --- /dev/null +++ b/progress/SpecForge/docs/spec_bundle/public/logo.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9857743362a074a6856e89dfcc6a93018012260053dee332f3c60163a46bc4f3 +size 264254 diff --git a/progress/SpecForge/train_dflash_lora.log b/progress/SpecForge/train_dflash_lora.log new file mode 100644 index 0000000000000000000000000000000000000000..25ba6def715b8961ff9b6ad60aca548f15b0110f --- /dev/null +++ b/progress/SpecForge/train_dflash_lora.log @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c75e267403b12972a17fd644ec19accca88dd12f5c5f30142962383c4d6efef +size 52129478 diff --git a/progress/github/SpecForge/assets/acknowledgements.png b/progress/github/SpecForge/assets/acknowledgements.png new file mode 100644 index 0000000000000000000000000000000000000000..f732e05cd20323f32ab54cd690c55f997bfa68c9 --- /dev/null +++ b/progress/github/SpecForge/assets/acknowledgements.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4e5890a0b7e11dae887e67c59f58d75530912ed010f22c511fab3a93d17ef2c +size 382844 diff --git a/progress/github/SpecForge/assets/logo.ico b/progress/github/SpecForge/assets/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dfee01264af823a48c4558a6c806a062be0c669 --- /dev/null +++ b/progress/github/SpecForge/assets/logo.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9857743362a074a6856e89dfcc6a93018012260053dee332f3c60163a46bc4f3 +size 264254 diff --git a/progress/github/SpecForge/assets/logo.png b/progress/github/SpecForge/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eaca99e9e514c6fde2b194ea33e3019fa0427f23 --- /dev/null +++ b/progress/github/SpecForge/assets/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:10dd0f59cdb12935d2ba6f9aad133a53b7fe790effab4a8d000c4800053af883 +size 315793 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 new file mode 100644 index 0000000000000000000000000000000000000000..24b8aeb8fb6615a328f0dc1e9f7bfc0b6366c0f8 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/37kgdaepiywbyufckxwc6iqoqpzr3ax5zpzbkatppss47kngkz6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfd461808f462c1c50a255ec2f220e83f31d82fdcbf215026f7ca5cfa9a6567d +size 1800738 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/bqcfmo26ipizieje35jzj3p77l3tamkajdwru37qtzywjwia32d b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/bqcfmo26ipizieje35jzj3p77l3tamkajdwru37qtzywjwia32d new file mode 100644 index 0000000000000000000000000000000000000000..a385a969d377b107406ed8dbd7c135ef109d2107 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2q/f2qqzwb2om7jjsjmf3wp46kspszvla5bprbgqunavuakgepeuub6/bqcfmo26ipizieje35jzj3p77l3tamkajdwru37qtzywjwia32d @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c04563b5e43d1941124df5394edfffaf730314048ed1a6ff09e7164d900de87 +size 13041065 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rmkq2tmgi2e3jettmvqroo34bdljlach5zxzke2iesw5lvsw2f/y457u3akysyuggxtftzemzods7yz5wdvkm37z6kxq5monwe2rt3 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rmkq2tmgi2e3jettmvqroo34bdljlach5zxzke2iesw5lvsw2f/y457u3akysyuggxtftzemzods7yz5wdvkm37z6kxq5monwe2rt3 new file mode 100644 index 0000000000000000000000000000000000000000..4a2e414f93b95407b6329203e1d896d29443dcbc --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rmkq2tmgi2e3jettmvqroo34bdljlach5zxzke2iesw5lvsw2f/y457u3akysyuggxtftzemzods7yz5wdvkm37z6kxq5monwe2rt3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c73bfa6c0ac4b1431af32cf24665c397f19ed8755337fcf9578758e6d89a8cf6 +size 1709504 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rupwxc3oob37htdzmh5rbnfmm2ds7sitswph7v4g6s6pgylyqx/nuw4czyp4quhocn3rd5zh5cnzhk47qwi3p4tbzen3opshfn76nb b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rupwxc3oob37htdzmh5rbnfmm2ds7sitswph7v4g6s6pgylyqx/nuw4czyp4quhocn3rd5zh5cnzhk47qwi3p4tbzen3opshfn76nb new file mode 100644 index 0000000000000000000000000000000000000000..be1c92cfc0a8e0890e47360bead29ed27aa6d3b0 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2r/f2rupwxc3oob37htdzmh5rbnfmm2ds7sitswph7v4g6s6pgylyqx/nuw4czyp4quhocn3rd5zh5cnzhk47qwi3p4tbzen3opshfn76nb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d2dc1670fe4287709bb88fb93f44dc9d5cfc2c8dbf930e48ddb9f2395bff343 +size 1807797 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2t/f2tyfv76cdkhvqiwg2bhtaj5k2bhjbgofjye4bj4zdbzwpp75ist/tjzlo4yrtts7fjzp7w6hv35v2goffyedasp3stcmgqb2o45n5vw b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2t/f2tyfv76cdkhvqiwg2bhtaj5k2bhjbgofjye4bj4zdbzwpp75ist/tjzlo4yrtts7fjzp7w6hv35v2goffyedasp3stcmgqb2o45n5vw new file mode 100644 index 0000000000000000000000000000000000000000..5a631a45dfdede0b56508b775276b9bbe74da1b9 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/2t/f2tyfv76cdkhvqiwg2bhtaj5k2bhjbgofjye4bj4zdbzwpp75ist/tjzlo4yrtts7fjzp7w6hv35v2goffyedasp3stcmgqb2o45n5vw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a72b773119ce5f2a72ffdbc7aefb5d19c52e083049fb94c4c3403a773aded6d +size 1821979 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3b/f3bzwnfpglfx5lgj5z72xpxl6ct57dgp35fmrra6jkcgqup2f73r/wnhxolcactcqpkweti6kcm4cswi42uqna433darknma7obu7dty b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3b/f3bzwnfpglfx5lgj5z72xpxl6ct57dgp35fmrra6jkcgqup2f73r/wnhxolcactcqpkweti6kcm4cswi42uqna433darknma7obu7dty new file mode 100644 index 0000000000000000000000000000000000000000..8eac78f6ec437dc75b0d8198689eadc67151ec1a --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3b/f3bzwnfpglfx5lgj5z72xpxl6ct57dgp35fmrra6jkcgqup2f73r/wnhxolcactcqpkweti6kcm4cswi42uqna433darknma7obu7dty @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b34f772c4014c507aac49a3ca133829591cd520d0737b1822a6b01f7069f1cf0 +size 1822008 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3r/f3rynbog3ty5tokp7ne5gzlcad2dsp2tdt3xfazjqievpsue24yi/yw3coy32vnorw4tloixata33pzwfkqzvi7gqw4c5ljbvvk4f55j b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3r/f3rynbog3ty5tokp7ne5gzlcad2dsp2tdt3xfazjqievpsue24yi/yw3coy32vnorw4tloixata33pzwfkqzvi7gqw4c5ljbvvk4f55j new file mode 100644 index 0000000000000000000000000000000000000000..78087b55d7df58c39ce4fa235a17551a2f73c3b1 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3r/f3rynbog3ty5tokp7ne5gzlcad2dsp2tdt3xfazjqievpsue24yi/yw3coy32vnorw4tloixata33pzwfkqzvi7gqw4c5ljbvvk4f55j @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5b627637aab5d1b726b722e09837b7e6c55433547cd0b705d5a435aab85ef53 +size 1611499 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b new file mode 100644 index 0000000000000000000000000000000000000000..728a34e8ad696b90d19251fabed2422865b5903c --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/3y/f3yzr7zp4ivkkmq2cfhbzo72gmvy5vuxr6ersqwmbr65xgc6eyfw/2dfdlvsoh3in3txs6nf63xqnoyljj7vuygaxnvc3ncmz6mqmw2b @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0ca35d64e3ed0ddcef2f34bedde0d761694feb4c18176d45b68999f320cb682 +size 1738196 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz new file mode 100644 index 0000000000000000000000000000000000000000..0434f3825335e3e583a959243c9d902effee6878 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/55/f554hhda7asir4j5v5pu5nwdggutzg7vpyyajuilfietf26g5id7/l37izoav2xujt3tuowmyt2gjr5xmqwx54n7v3vx6seqldw6esdz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5efe8cb815d5e899ee74759989e8c98f6ec85afde37f5dd6fe9120b1dbc490f2 +size 1638866 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb new file mode 100644 index 0000000000000000000000000000000000000000..1759f5231f20c8350b6b77aa440ef9cedbad5554 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6h3whwp6iwujzqrgqed73ox5tcdstlzlk74jqncmahu73bjqbab/obpdksdkre6emml4afbbdpmm3ewase2ce35cs6bq3c6zgywx5zb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:705e35486a893c46317c014211bd8cd92c09134226fa297830d8bd9362d7ee43 +size 1709535 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/6naimkcsh74lxihunjqbffnofd6jp57iwfeo5a7v3uuhhuzy5rd b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/6naimkcsh74lxihunjqbffnofd6jp57iwfeo5a7v3uuhhuzy5rd new file mode 100644 index 0000000000000000000000000000000000000000..3ec248e235ce786f07b2c7f86ae22e0bb5050a7e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/6naimkcsh74lxihunjqbffnofd6jp57iwfeo5a7v3uuhhuzy5rd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3408628523ff8bba0f46a601295ae28fc97f7e8b148ee83f5dd2873d338ec47 +size 13041068 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh new file mode 100644 index 0000000000000000000000000000000000000000..c10cf03012e9f21c9f67333510924432f6ce1934 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/6h/f6hi3oybrefqcdarestqirguyfs5iq3aelp2h33gqpi4q24tflwo/eopddqtmsotlnwpkkwra6555phfmkcju3bynxi3abwcztkhb4xh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:239e31c26c93a6b6d9ea55a20f77bd79cac50934d870dba3600d8599a8e1e5cf +size 1800741 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/nfsjgw27web6fb5zbkynso5h33xkux3mhozbmivsv74havau77j b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/nfsjgw27web6fb5zbkynso5h33xkux3mhozbmivsv74havau77j new file mode 100644 index 0000000000000000000000000000000000000000..d7d6d5946dc4203d6a8b1901dae342398998d141 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/nfsjgw27web6fb5zbkynso5h33xkux3mhozbmivsv74havau77j @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6964935b5fb103e287b90ab0d93ba7deeeaa5f6c3bb21622b2aff8705414ffd2 +size 13041035 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s new file mode 100644 index 0000000000000000000000000000000000000000..274dcb56a1639079899e8fbe3a4ff03df6553a2f --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/7e/f7eopvljpv2chnfunkjhwrs4tvupyx323xggs7mqwml6vdmdal32/tal6nggqlrhjiaucplomodagerevlxtvomwzbm7qews6pswct2s @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9817e698d05c4e9402827adcc70c06244955de75732d90b3f025a5e7cac29ea4 +size 1800737 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/jfea23gku4yhakqmgavb5xucs2xsfmutdw2mtxtebhcm2vccxrs b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/jfea23gku4yhakqmgavb5xucs2xsfmutdw2mtxtebhcm2vccxrs new file mode 100644 index 0000000000000000000000000000000000000000..d59fe40a03816b4ec68aa18706b16a9f77084799 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/jfea23gku4yhakqmgavb5xucs2xsfmutdw2mtxtebhcm2vccxrs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49480d6ccaa730702a0c302a1ede8296af22b2931db4c9de6409c4cd5442bc65 +size 1800728 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/vwomrl6y54ugwc5ufyr6szgk3glqd2fifx4i4wsyof2ehuzytz5 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/vwomrl6y54ugwc5ufyr6szgk3glqd2fifx4i4wsyof2ehuzytz5 new file mode 100644 index 0000000000000000000000000000000000000000..c0261f3ace493d287c30621d0713d28dff1dfc21 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ae/faexmyg2usujvickklpvk5aewk3scfrklzdvlvhdfbllgexgxeop/vwomrl6y54ugwc5ufyr6szgk3glqd2fifx4i4wsyof2ehuzytz5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ad9cc8afd8ef286b0bb42e23e964cad99701e8a82df88e5a58717443d3389e7a +size 13041089 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl new file mode 100644 index 0000000000000000000000000000000000000000..01b39d4fb3170943f5104ed502fff83f18e5745d --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/kergg5tmmm7lya33c5264okwe7uwa6ts4t4apgfzq7axabcvyfl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:512263766c633ebc037b1775ee395627e9607a72e4f80798b987c1700455c156 +size 1800735 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq new file mode 100644 index 0000000000000000000000000000000000000000..921b60d97a1c5f53f97858d3666a3dd23edc1aaf --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/at/fatsph6ityf7bw5abt6a7jcef6aeeuf3gilzpnexk3gj44q34n6t/nojbsrcdolpsvr2j3623jzdruw4sjjieydobb654nkmjhvqb4sq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6b9219444372df2ac749dfb5b4e471a5b924a504c0dc10fbbc6a9893d601e4a0 +size 13041080 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cm/fcmuvpflnpx57jjci3fvuwipestyowfk5cygrs5zkn4kju27jklg/gecl4oarfzflfmmqc4olmobba72uoz7rx2yixalfjtdla6ka25v b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cm/fcmuvpflnpx57jjci3fvuwipestyowfk5cygrs5zkn4kju27jklg/gecl4oarfzflfmmqc4olmobba72uoz7rx2yixalfjtdla6ka25v new file mode 100644 index 0000000000000000000000000000000000000000..256599ec6bc4babe8e12fa1e021c06da15a0c403 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cm/fcmuvpflnpx57jjci3fvuwipestyowfk5cygrs5zkn4kju27jklg/gecl4oarfzflfmmqc4olmobba72uoz7rx2yixalfjtdla6ka25v @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3104be38112e4ab2b190171cb6382107f54767f1beb08b81654cc6b07940d76a +size 1708839 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n new file mode 100644 index 0000000000000000000000000000000000000000..1c7bdc1f37d9a18d688c2ef7acc9ecdf291386db --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cp/fcpkklfphvzsgduibr5uimciushyl5czaxt2rsvaclvapqxsu5hr/tllyeejrpqpcgivk4mzquio43ebcenbgckjdjwedghd3j5lcz3n @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9ad78211317c1e2322aae3330a21dcd902223426129234d88331c7b4f562cedb +size 1638189 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cq/fcq7y7ognlkp6mglgv4dto7rtv2ucev4kwlzqkzfsdektpwroch5/lokxdmwuz6dfo2dywr2emse3yei4vdvxzauxmxedvnd7ibmuiiy b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cq/fcq7y7ognlkp6mglgv4dto7rtv2ucev4kwlzqkzfsdektpwroch5/lokxdmwuz6dfo2dywr2emse3yei4vdvxzauxmxedvnd7ibmuiiy new file mode 100644 index 0000000000000000000000000000000000000000..3fd99e1fba0de42dc12678319bb63037d4ed958d --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/cq/fcq7y7ognlkp6mglgv4dto7rtv2ucev4kwlzqkzfsdektpwroch5/lokxdmwuz6dfo2dywr2emse3yei4vdvxzauxmxedvnd7ibmuiiy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b9571b2d4cf86576878b47446489bc111ca8eb7c829765c83ab47f405944231 +size 1821996 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/eo/feonriuqattorpyq7qydqtulxbq7viikup5gk2jfkwgn4jo4t3da/yqijcwsdh7szltsgww52htt54towwgkfezt3swuvxh6frqxf6yc b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/eo/feonriuqattorpyq7qydqtulxbq7viikup5gk2jfkwgn4jo4t3da/yqijcwsdh7szltsgww52htt54towwgkfezt3swuvxh6frqxf6yc new file mode 100644 index 0000000000000000000000000000000000000000..9068bc6edc62a21feab3c41a71015bc12ff89aa6 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/eo/feonriuqattorpyq7qydqtulxbq7viikup5gk2jfkwgn4jo4t3da/yqijcwsdh7szltsgww52htt54towwgkfezt3swuvxh6frqxf6yc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c410915a433fe595ce46b5bba3ce7de4dd6b19452667b95a95b9fc58c2e5f604 +size 1737519 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 new file mode 100644 index 0000000000000000000000000000000000000000..a2bfc408463609ab2e63fa2bf613ab98a2086594 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gg/fggvgr2c5mnbz7npdzrr2mklraigaqixskpeazhwhyrliuzglzue/ybrrs6q6rmxyj2isl2cwtp2molwa5kafqkqlmqmmnbdl7cgk6v2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c063197a1e8b2f84e9125e8569bf4c72ec0ea80582a0b6418c6846bf88caf574 +size 1807783 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz new file mode 100644 index 0000000000000000000000000000000000000000..aa5dddf6d33ab61b8f42ae12c04cc1a35629b0cd --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/gt/fgtklisxifbyg4g4ovzzmfwoxhjfzlxsg3zfgpfqoudxvj6qcqcr/vfu3spdistcrymhzsjrwblwbmlr6uytv767n767yqzh4q6htzuz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a969b93c6894c51c30f9926360aec162e3ea6275ffbedffbf8864fc878f3cd33 +size 1738709 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov new file mode 100644 index 0000000000000000000000000000000000000000..616a12ef2c9d8ea83b733037c7a62342e88b5ea3 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/i7/fi73ncbhxdqwxmunkw7njm5ecr5hlsy6isha6h52xwjryvkniobz/nh7obz423fzoaagbjz5yps4reougtbpj2o2j3tvz3mpczl2yvov @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69fee0e79ad972e000c14e7b87cb9123a86985e9d3b49dceb9db1e2caf58abab +size 1610811 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ia/fial3pyfgpr6yu6rbb4ngfj2efqoptjkzbc5xkgspdgqmqwwtvoz/oiskhzuq6nfzog7awbvlsclh7xt2pfl4badcs5paxngueg3x2to b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ia/fial3pyfgpr6yu6rbb4ngfj2efqoptjkzbc5xkgspdgqmqwwtvoz/oiskhzuq6nfzog7awbvlsclh7xt2pfl4badcs5paxngueg3x2to new file mode 100644 index 0000000000000000000000000000000000000000..ca2e9ddf79361772a08df36252f29276a9ecb2c6 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ia/fial3pyfgpr6yu6rbb4ngfj2efqoptjkzbc5xkgspdgqmqwwtvoz/oiskhzuq6nfzog7awbvlsclh7xt2pfl4badcs5paxngueg3x2to @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7224a3e690f34b971be0b06ab90967fde7a7957c08062975e0bb4d421b77d4dc +size 1738009 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ie/fiewkam5s7tpgfnsnrf3ayj3pyf4c53rle7lim2whvqknxjvi3so/3nem6zwnv256cocmodc6wrvlolrx7iseqnvigwtx33tsq2cfzx2 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ie/fiewkam5s7tpgfnsnrf3ayj3pyf4c53rle7lim2whvqknxjvi3so/3nem6zwnv256cocmodc6wrvlolrx7iseqnvigwtx33tsq2cfzx2 new file mode 100644 index 0000000000000000000000000000000000000000..cbd63ed392b885cbe8f1f2593000fdf4942920cd --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ie/fiewkam5s7tpgfnsnrf3ayj3pyf4c53rle7lim2whvqknxjvi3so/3nem6zwnv256cocmodc6wrvlolrx7iseqnvigwtx33tsq2cfzx2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db48cf66cdaebbe1384c70c5eb46ab72e37fa244836a835a77dee7286845cdf4 +size 1736436 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 new file mode 100644 index 0000000000000000000000000000000000000000..ff441d3f0a7d116022d04a81b739694cb45c24a3 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/jo/fjo5regw33f3oistu3pmkq76uccpl73bjt5dwydhdumihfgu4q7w/joxgrauyfbsog66uednnbh4jycvlbj3yfqvwhmj45nrpkupfft3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bae6882982864e37bd420dad09f89c0aab0a7782c2b63b13ceb62f551e52cf7 +size 1751060 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz new file mode 100644 index 0000000000000000000000000000000000000000..fde2d7ad01696b39daa270f8216439818551078d --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/kr/fkrpdlq7p5tvxxipujkxuwzup325k2nnuoyh55xbiijs3f5ygg4x/rtesbmq5aijq2y3vksdyxwh2pglev3hyjwx7iiyw3awzcayhvsz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8cc920b21d02130d637554878bd8fa79964aecf84daff42316d82d910307acb2 +size 1804750 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/7mutgynsdwo6mdvomsqtknzze2dms3p7jpyytzv57pmiysfzeoi b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/7mutgynsdwo6mdvomsqtknzze2dms3p7jpyytzv57pmiysfzeoi new file mode 100644 index 0000000000000000000000000000000000000000..a86848170531ccf5d935697a1a9bd43b2ccb94c6 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/7mutgynsdwo6mdvomsqtknzze2dms3p7jpyytzv57pmiysfzeoi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb293361b21d9de60eae64a13537392686c96dff4bf189e6bdfbd88c48b92390 +size 13041042 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/lvmozut4mz4puj6rgr3k5y3co2km4ljyehjcaw2o3sjs6ahbfih b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/lvmozut4mz4puj6rgr3k5y3co2km4ljyehjcaw2o3sjs6ahbfih new file mode 100644 index 0000000000000000000000000000000000000000..3dfbb294af00b6d126c113c888079c283d06f0ae --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ld/fld53pjk2u726frboiljqefkgxww4znrghszmshoq2vvjcoogeje/lvmozut4mz4puj6rgr3k5y3co2km4ljyehjcaw2o3sjs6ahbfih @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d58ecd27c6678fa27d13476aee3627694ce2d3821d2205b4edc932f00e12a0f +size 1800741 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lj/fljjn5o6yhgalxerilsjssfuctvvsbjivhyj4s77f4gl7hsgu6px/wdjvlpvmja3nlgla33sismftlk7vytuj7gygjhgzgogtdged7na b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lj/fljjn5o6yhgalxerilsjssfuctvvsbjivhyj4s77f4gl7hsgu6px/wdjvlpvmja3nlgla33sismftlk7vytuj7gygjhgzgogtdged7na new file mode 100644 index 0000000000000000000000000000000000000000..4f602db0712464801e919baa05a8d3eb1e815333 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lj/fljjn5o6yhgalxerilsjssfuctvvsbjivhyj4s77f4gl7hsgu6px/wdjvlpvmja3nlgla33sismftlk7vytuj7gygjhgzgogtdged7na @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b0d355beac4836d59960dee48930b35abf5c4e89f9b0649cd9338d319883fb41 +size 1638184 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lp/flpce5hrjkeamjxahwtiwsrl5ezmzkl4waozen7lvwaqkajp7ib3/dh77wgbhyvaoyqmhd3ik6y3uaozvree5j54bvp7pwmruwkd6hy6 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lp/flpce5hrjkeamjxahwtiwsrl5ezmzkl4waozen7lvwaqkajp7ib3/dh77wgbhyvaoyqmhd3ik6y3uaozvree5j54bvp7pwmruwkd6hy6 new file mode 100644 index 0000000000000000000000000000000000000000..d8e0076f910087932e263e0f05331fbb08a9e091 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lp/flpce5hrjkeamjxahwtiwsrl5ezmzkl4waozen7lvwaqkajp7ib3/dh77wgbhyvaoyqmhd3ik6y3uaozvree5j54bvp7pwmruwkd6hy6 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:19fffb1827c540ec41871ed0af637403b358909d4f781abfefb3234b287e3e3d +size 1738718 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h new file mode 100644 index 0000000000000000000000000000000000000000..72f8df0de80d812a4c21b9d5becdeb48d3b0af70 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/lx/flxfl3p35nd5thewh5vfvn4cwh6f5qaouv3pu6pyy6mp637wibpg/yb5g2trv2wfmty7mm7msxvfbcljkpjjyzyhk75lmvynxf35iu5h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c07a6d4e35d58ac9e3ec67d92bd4a112d2a7a538ce0eaff56cae1b72efa8a74f +size 1822002 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy new file mode 100644 index 0000000000000000000000000000000000000000..33e7540345755f5041fa59ae9c65585793d3f862 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/or/foryjaxyimimia377x77zt3xtnye37l2zqp7tnlfpbj2zqfklfxr/swo2xp4xisgzndatncahx32egacd6wbjmu7g6tq5klh2ldsiuxy @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:959dabbf97448d968c1368807bef4430043f5829653e6f4e1d52cfa58e48a5f1 +size 1821994 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc new file mode 100644 index 0000000000000000000000000000000000000000..288e49b064d04e995182438dafa2b878ada4f51e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/os/fosonlwjhx33t6cv3ktikppey2yn27jqlf7yhlgdwgz262loshnb/ofi3yyciw7hlli3gaudvsvpagg2tgbbl4xfea72coxtsfda72uc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7151bc6048b7ceb5a36605075955e031b533042be5ca407f4275e7228c1fd505 +size 1738501 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln new file mode 100644 index 0000000000000000000000000000000000000000..8da39563e4b29b1356f8c2238e6b8cb8f0718436 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/oz/foz2rozltlil6akgtwyjcmoeuz5bymwm44hao6lufyqnx2arem5p/fpga27cqfulk5ctjyid4jlgnhv7dvbsxof26bnk2f4okkclnvln @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2bcc0d7c502d16ae8a69c207c4accd3d7e3a86577175e0b55a2f1ca5096daadb +size 1807798 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw new file mode 100644 index 0000000000000000000000000000000000000000..8cfc7595c43fc50b9be6d73c4a1c9d8be7073a29 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/pj/fpjmtmc7vfyy3cyk54psrgaavrwfmqbhpf2rkhda6kffiykbngld/o54e3xzzqxvkksckb5d5r35vvxtra6reqpywnhjbnbmkdrgmgcw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:77784ddf3985eaa5484a0f47d8efb5ade7107a2483f1669d216858a1c4cc30ac +size 1743042 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso new file mode 100644 index 0000000000000000000000000000000000000000..5183df43dc88d7a3361b04a6158283fbb99f8032 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/q4/fq4cma7j4i7z74x4tkzp2idh5oxdrc7gw233yjnzkoy5wei3xtsd/p2nf5ac37mw5xw3t57sp3uvyesnpt2pqdg5ectgqyho5ddsyeso @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e9a5e805bfb2ddbdb73efe4fdd2b8249af9e9f019ba414cd0c1ddd18e58249c +size 1751153 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn new file mode 100644 index 0000000000000000000000000000000000000000..c07103198ebfa53d5287287452a88389ae3c0f5e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/qr/fqr5rx7wvhvtj7cet67kemsq7pkejaz5i2uk6bdg475fnz2prttn/4zrcdw7zket5bcwxoh337pjyzgdaaoxr6bpdgp3j3ulnbzgahdn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e66221dbf95127d08ad771f7bfbd38c986003af1f05e333f69dd16d0e4c038db +size 1737821 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs new file mode 100644 index 0000000000000000000000000000000000000000..ca129ae09972a831836d893d082cfa783c75572a --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rl/frlqj5be3225xe77brwcmw4m7azz4fx2m7g42qwdpbt2i7btg2he/lwvjiecy2dlvekwbfmdxjlvlv7cnk7znsqzuyx35nbahjfjoivs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5daa941058d0d7522ac12b0774aeabafc4d57f2d94334c5f7d684074952e4565 +size 1738004 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr new file mode 100644 index 0000000000000000000000000000000000000000..32717014aea22ef9b1b874235c16d98b03f05162 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/rw/frwmcv6lx6rkqcajnul7t475fd3dh7gpuspk5xw2w33syazgplzy/drpfkch7vee63kponcxer6xhus432k736dupvv7ea2sbj75sdmr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c5e5508ffa909eda9ee68ae48fae7a4b9bd2bfbf0e8fad7e406a414ffb21b22 +size 1638861 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep new file mode 100644 index 0000000000000000000000000000000000000000..546e9b56f91601f0d1629fbd18b36a2e8946fd92 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tk/ftkr5sguhz2adsboh5czn6a3qo7gnhaz3zrq4itxj2hqqa5ibebh/f6f7pxokg4xvvoszlqp5342vi7fbdd2ufdegqeje5hakrhtegep @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2f8bf7ddca372f5aba595c1fddf35547ca118f5428c8681124e9c0a89e64311e +size 1804644 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tp/ftpa47eenzh2y37qv3oxjuo2h2ddd4xzh7lsojdgohxyce6z5bhh/tofa3kmoquvdbbv32vkns3dcydq4rmtryzs55bjkrnotsrrckpe b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tp/ftpa47eenzh2y37qv3oxjuo2h2ddd4xzh7lsojdgohxyce6z5bhh/tofa3kmoquvdbbv32vkns3dcydq4rmtryzs55bjkrnotsrrckpe new file mode 100644 index 0000000000000000000000000000000000000000..e6f39d90cfa532a1544ae234eba52adc1d9cb7b4 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/tp/ftpa47eenzh2y37qv3oxjuo2h2ddd4xzh7lsojdgohxyce6z5bhh/tofa3kmoquvdbbv32vkns3dcydq4rmtryzs55bjkrnotsrrckpe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b8a0da98e852a3086bbd554d96c62c0e1c8b271c665de852a8b5d39462253c8 +size 1738018 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r new file mode 100644 index 0000000000000000000000000000000000000000..3bf94de420742c472549d58ef886bbe2682f2d5c --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ty/fty4coawvx5n5bz6zs3c5olvbjtxm2fcza6y7fdh2ox4nyesnime/k2tiwyu4iyw6fz73httajnnvzrdxv2cbehya3ij7z3pmhy3s44r @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56a68b629c462de2e7fb3ce604b5b5cc477ae84121f00da13fcedec3e372e723 +size 1738704 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ur/furegr7cnnouau5apv575ga6yeaeaoyxtyi75xwolnjgrklub7pk/kxxtbo6x7i4hrjcm54na72qsazuthc42izqix3a5w2tronyf7ll b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ur/furegr7cnnouau5apv575ga6yeaeaoyxtyi75xwolnjgrklub7pk/kxxtbo6x7i4hrjcm54na72qsazuthc42izqix3a5w2tronyf7ll new file mode 100644 index 0000000000000000000000000000000000000000..16b5218dadf6ef1b590812bc215ec987aa0b1d0b --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ur/furegr7cnnouau5apv575ga6yeaeaoyxtyi75xwolnjgrklub7pk/kxxtbo6x7i4hrjcm54na72qsazuthc42izqix3a5w2tronyf7ll @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55ef30bbd7fa3878a44cef1a0fea120669338b9a46608bec1db6a7173705fad7 +size 1735759 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a new file mode 100644 index 0000000000000000000000000000000000000000..d68b568a709f6c312c53a692f2b9d0c09909f33c --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/ut/futpdihybpbvzuz3gmased6rzsymhqo6be7a4efoyik7i25engr2/g5wp5n5pjj4im3bmdgtsioh2bcfmyic2f3ebncsafkfhx4yht6a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:376cfeb7af4a78866c2c19a72438fa088acc205a2ec8168a402a8a7bf3079f81 +size 1709292 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/jhc6zp252pqoyff7uiqsdkvrakwalhkt6v4q22bycsog7pdskqz b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/jhc6zp252pqoyff7uiqsdkvrakwalhkt6v4q22bycsog7pdskqz new file mode 100644 index 0000000000000000000000000000000000000000..2c9b7ea1fb5d0f6bcf7d60b2326fe62ae4ae5219 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/jhc6zp252pqoyff7uiqsdkvrakwalhkt6v4q22bycsog7pdskqz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:49c5ecbf5dd3e0ec14bfa22121aab102ac059d53f5790d6838149c6fbc725432 +size 13041072 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/l6haafig2ocrjlh5jvafvjnnusnfutfmpkejvmgawo542o3u2h3 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/l6haafig2ocrjlh5jvafvjnnusnfutfmpkejvmgawo542o3u2h3 new file mode 100644 index 0000000000000000000000000000000000000000..7888b995e57b2507f7acd07b1d7ea2a429fc9a49 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/l6haafig2ocrjlh5jvafvjnnusnfutfmpkejvmgawo542o3u2h3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f8e001506d38514acfd4d405aa5ada49a5a4cac7a889ab0c0b3bbcd3b74d1f7 +size 1800723 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/q4dkpcnp66xtouoevwchuv5u5m6ahvmi5w7uvt2hv6nsmrph6xa b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/q4dkpcnp66xtouoevwchuv5u5m6ahvmi5w7uvt2hv6nsmrph6xa new file mode 100644 index 0000000000000000000000000000000000000000..c093b353e99cdc0575dc5f4d3725923d073a56b6 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vg/fvgbmom5l7xmwtovk33vvxbakq3p2f3fhpa2mwgrarow4svxv6fh/q4dkpcnp66xtouoevwchuv5u5m6ahvmi5w7uvt2hv6nsmrph6xa @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8706a789aff7af3751c4ad847a57b4eb3c03d588edbf4acf47af9b2645e7f5c1 +size 7682295 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca new file mode 100644 index 0000000000000000000000000000000000000000..874e620bab55c5b3a440c5d91a7c8409af2db2f0 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/vn/fvnn4jqqhnfhy4ib2b4g2iqmikkhay242o2hnbls54bmjvqi6sqq/kd5j2uq2zug3ydbjduxscootkij5kk543swc75qls3quirvxhca @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50fa9d521acd0dbc0c291d2f2139d35213d52bbcdcac2ff60b96e14446b73880 +size 1821861 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 new file mode 100644 index 0000000000000000000000000000000000000000..26576705ff179b6cd429bad6b99ba4767153c339 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/fehygb7iobmgfg6l3id6k3v3362lcvds2krftld5tfvdeki34n5 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:290f8307e87058629bcbda07e56ebbdfb4b15472d2a259ac7d996a32291be37b +size 13041048 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/mjwarexf623xgk5xjmz2u6ohk432kj4cilavbtlrqki5uip47ug b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/mjwarexf623xgk5xjmz2u6ohk432kj4cilavbtlrqki5uip47ug new file mode 100644 index 0000000000000000000000000000000000000000..56fa575ccc3a49fad2382c651d0b0f818cd2fb70 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xj/fxji4ibewqothr7fmiig3d77xl4qmbzvrbq5k4riqpwcgslugwm5/mjwarexf623xgk5xjmz2u6ohk432kj4cilavbtlrqki5uip47ug @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:626c0892e5f6b7732bb74b33aa79c75737a5278242c150cd718291da21fcfd0c +size 1800748 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u new file mode 100644 index 0000000000000000000000000000000000000000..233f5362213960adfb37958d85fc8b6d2f645d22 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xv/fxvgzz3tiwhqcyfhsth5de2uadcvane6eje2yztbjqcxpoffwrri/at4ad3jksit3hlejt5sszprkoo5e2rswo6fwus5vlkzpkagp76u @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04f801ed2a9227b3ac899f652cbe2a73ba4d4656778b6a4bb55ab2f500cfffa9 +size 1751152 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xw/fxwcwpkv4ldzgd7lvvizht2avytq32qqfgf6folnvcmtky7waomn/2nq5xoncppb4wjqp36rtrpvrvpacey7qnx4kpgheswbkrf2swjg b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xw/fxwcwpkv4ldzgd7lvvizht2avytq32qqfgf6folnvcmtky7waomn/2nq5xoncppb4wjqp36rtrpvrvpacey7qnx4kpgheswbkrf2swjg new file mode 100644 index 0000000000000000000000000000000000000000..803c1a2aa449d39bfcf3804feffdafe7173ddf51 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/xw/fxwcwpkv4ldzgd7lvvizht2avytq32qqfgf6folnvcmtky7waomn/2nq5xoncppb4wjqp36rtrpvrvpacey7qnx4kpgheswbkrf2swjg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d361dbb9a27bc3cb260fdfa338beb1abc02263f06df8a798e49582a89752b24d +size 1807773 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/yb/fybhxidrrihf3vhks4wuv6jrwfcpuwx725brem7ufc7tsomyka3w/cgopmtn75c65zo7hrmnr3bfjqjus7d5i5kvnqiq5hwetbqynn62 b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/yb/fybhxidrrihf3vhks4wuv6jrwfcpuwx725brem7ufc7tsomyka3w/cgopmtn75c65zo7hrmnr3bfjqjus7d5i5kvnqiq5hwetbqynn62 new file mode 100644 index 0000000000000000000000000000000000000000..9988a52c87ee6a0bca5fff0e6f295c74e894a190 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/yb/fybhxidrrihf3vhks4wuv6jrwfcpuwx725brem7ufc7tsomyka3w/cgopmtn75c65zo7hrmnr3bfjqjus7d5i5kvnqiq5hwetbqynn62 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:119cf64dbfe8bddcbbe78b1b1d84a982692f8fa8eaaad8221d3d8930c30d6fb4 +size 1707778 diff --git a/progress/github/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe new file mode 100644 index 0000000000000000000000000000000000000000..09ca8a6050f707b55a38cf5a2ae7c67da06b72b7 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/fxgraph/zr/fzrd3hpwxcnjcgclfjfqvwsyepcmqnyzwzlzlxj553lkvzxwiujj/av3upjugke3laipgi4ehuileufnq54r4ixv4dcjm4l7ct7nj4fe @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:057747a6865136b021e647087a2164a15b0ef23c45ebc1892ce2fe29fda9e148 +size 1709486 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..2671cd447e8f9c031eb19792c5f45eece3c70b44 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:69908e13133d104c5d114d4e01cb4b2d36ac7871162d14a7ef8b1289ecc88be7 +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..700574794c869da4a7d846810dac4171bb239c17 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/3CW7DQXG7Q46TBJOLOFOIPFW4BJYSNKDHZ5SWWP5SYKUYVVTSXHQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6f04c186cbc8f5c7b670aea4cd29ace0c41469d640fd1537dab78df2f7e3937 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dda0c94205d35ad16247f7716d09430687953f44 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92c587ba7ea7317a29be4825206e60d3ca61bca8e7be2e1de93dc5a125b78051 +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d9df6ba1e6b21b1decd33a17a859967aace25ac8 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8bd9879cb44e0ff819e89a3317fd62ae0d497c8f1e97f9f818391a7553674c4f +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1c411a22ddd997c6d5ab23a614111ca2a9dae299 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/HSMLZP65PZRCILQKYV7TDF2JLKZBRNERKN742A4UUXSIRTTIBU7Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b60ef9dc3fe552f20ab5cd48c1a1b85ebf1dc4e16870380458152a9a7a7ce4e +size 174160 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9b3b04e5c19aaebc006d8f8ee704b25afaf7c6d0 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cb4e7856edaade12a654f7866321b4051622fa0ab8d098f42cc661bc4b5cfbe +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ec278f613e603814e4c04b83b3e977d25b73913c --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/RKFHBOCFEXZQKWYDHIXE3VYT3RRDR64MO67OQJC7AO7MGKKCN2HA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84f42c017b2d6ded6717aa39151f7e716dd750168ff283f8423df439b90348ed +size 403080 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f037496fb9796e7724b66653ca611a6ccfff488a --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/0/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f08563cc05f21f823f0d7729e457ad25ff8f2c63961339df354d78afac0e1dd1 +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d8c231999bbae13e3e2be935ed01fc513a37144e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a0c4ffd5a86442813d3b633c52f0e67dde3a2b0fbabbb8e25f081c70e74d558 +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..bba866fd581d38557ca9bcff7db60fed0d87d9c7 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b2d1d3db62b9a3a48379d446f7532d8a38cc4100b7485aa29a10c2a2a46951c +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..00d07782081fdb488bac65c676946cc7685c7b9e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/7FP37PIFBRP6IL6FQYKTWHVUJKZYWTR2DWDICW6YKJYPD7ZPYZ7Q/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ddaab87750dd4226d655928ea52ef1214a8b4754e3a77d0e263e80c8254ca30d +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..92130115125c937f6ad864d133ff6a74635e8f57 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:867714535f33b94be79241341ccfb8117d7d3cf15e12e18fcda7e4603420ba6e +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..7cdac2ca9ce38fba28045b13c162a8d4bd2b9b62 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:509cfd7fd459815804cd514c9ff89b927185e82b48a6401f4bb02a8665cfceef +size 143952 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..97c864a074fc913f64e845acedd0990290b550de --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4e2320a36cbfeaa3e715b2a26581b859bfa35c4da796e142bef265691bf8546 +size 327048 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d2fe27475ba3b91abbbbe4427b02641780ec61ab --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92dbf2b48d35c147f3269f7b2251eec4f0713fbaed844e46b9da891a9a6cf753 +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..14879c2ab396ca986af278fadbb1010b6c0ad8a5 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/1/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:195c9de024180aaea3a8ae93f06a3a305afc9e3ca47b98ac938a875881ba71a0 +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..bb5a3215ea9ae49619b813fbbe29329318bfe6cc --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f5acb596e3ed3297180e684bd17017a7576d1eeadbf2f1aa2670934857d51079 +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0072bbb54d647e2e04494a037e1c6bdaaf69a0ad --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:abbaecadb60e572029b83ae062e7e054d486a662226111d78132a8c9c6358c3a +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..c408a68fdf9c549400b94c0963deec45604dc5a8 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ae53043a633e61fccf97e73e25eafb7990d0c921e6550ba4629c52f3092347ff +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f96211c1f7cf3fea5cd05d6b10d4021a74aa7331 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9600b3cb86abad1717f52d2eae20a266f203d0e7862f1850b989b6e3cd7660e9 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b943bb4eb6c69fb5459c8ce05ea3a83fefc64e17 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/MQYAUWEO7W2DUOKM4T3FEUO2ECUKNWVHWDWNFBJTPUPBPBHTWMSA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db9a230821e65e8457c93beaae3c514cd83d343aa6ffe4aa19ef8b7be19a3da3 +size 174160 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..4b4ff51cd6210fd663c618d30f4f2c2e104db39a --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9e10adf4c456df3685c2663e9a93046d040cda09999fe02f52ac3c4a187221fc +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e8a9ce041a8eb3b2fac908bbaa45c0695cbcd0a5 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0f32ce7663d78ca2cf6f377bc255d80ed13d3f79881b77020c954107654ed19 +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..53b31bde8ca46d270dcca7b35dfacebda6f31ee8 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/2/YV3EQ3GBTZP33EITZOLM5U5QN33SXODFOHN356373TBUOVRY4CIA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e1081a370d761fb92df8c79d3a7dac46e3af6c43e37c6e305e505b41e804957 +size 403848 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..aa9b284c234bf0c764a81948cbb4263377bf5df1 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:772e85f6ad5dae5fbac6a6d86383ecdd8d4f5e3b9920df813a16d452cce86f6b +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..ba003af45936b5c73655e70895488b1fca34f971 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f39c9575e1f00817bbdddec15c36aa39a20bfca6ce84fd78462086213c7cf550 +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..431e49b964ca5e1e426344f9f1e4f9b2bccc74f7 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/5EMJSZKQENCMZ6EJOMWBJD7DKRWL7O5DF72P7CNFSHSLWGJ4WWGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a59fd32b75b1bd7ff56a1764e7355bacde1d67221c4849830caa067326280c89 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0e15cac2288008b7c1e9f8a488ad7ffc77d7a382 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43f6b67ba9e2f8e86c78ddd74928b12630ac5a65f8f1c2b8a97d7b618e900385 +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b7b4a9942ff03badf1442e10c3870903f8398ed7 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/J4RPZEW3TK62IGDBPY3LO7542UO7A3QZHCCRCK2DP6JVOFA3VDIQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2d712f97651d47dd1f2f7b7f9738be5c6f49b7ea3f6c60955ac902063700243 +size 174160 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..085378e26d550917891e9d98294b3e1371e452b5 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d64c4dd843b8eeec27cba44201e3afc84405f25a3668eab209698ec8ca1c27b +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..cf708a6f02f2bc5bc376c38ec14f526f38b0ce22 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dcda9e4f6f98dc3fc5ab38111c644ab8a0ae58f4a338dadd323081c6282cd286 +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0afab8a9777df704c222b035261b903d6e1ed013 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/3/YO6EOQUVQ26OAAHC5UGFARWJ35SHXHA54ELAFTWWS6DIXP4NH2CQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7d58383ffa04ef8b43aa10cc41307df165cce180b4aa2f1e13069eaf01aac0a +size 403080 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9db878720a85ee9e1bb8699607f756686a959192 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce260f1cfb7a716a019ce435926a000f44456cc90367024b156f9ab1328c8294 +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..64a0012f9fadfbca9dedbb7b67d61aa194120e8a --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea1fd41f54ef74df42e4ec363f451de1c1ca17c055a130c2b52fffec657e5c2a +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..3c7837fed172a54a13bd80dd48af6ef243949230 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/5JJ5UGHYLDOD6UQVWJ5RVD4NWYZJWX5QXEN7AUEN52DG5LN4MWBQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4bb675987f8e53a01bb0df1faeb545f2a7a98b5147cc3d1fb4ff25aa38a8ab5f +size 174672 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b7f6be1911ed5f36fcf1021b59fefb623a52c4ee --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/7SYRJODM5LFL77VOISZUCNOOTOO4AV7NJFG6NHF66IQWRUZQ3VZQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a4561e1a1975435b3adc84edf632266379bf4ac7ebc7a3cfffa68b704e3e81c3 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..544b18ebef55ec276fca76c619a102968dec74fd --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c76ba755e085e19a4b3f10135ad7340b002176f24dc52c1895e2c7eda4bfd780 +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..87959cd9093870e94f5760f66cd519ceb28d9455 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/PIO2IK7XDJPYESKH5KBTZYRYMUKXZZ4OODBEI4BWFB7E35UOWAJA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:823a85e5b38f5c1d6b2cd352cf91c1f0b4316eca62d9d821fac444da3a44cfcd +size 403720 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..c7ec0fd762ce35861e42a9d12596cad44485d6f6 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd2716f99b3800339934d9475b444b270b34914d70d231555db6f6b18e36fdce +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b4376e20912bc11fef008c258343cc0a29a12996 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/4/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2eec24018999f8bcece3babe91b31a765c5522fa452c4b49f3854c45fb43dffa +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..60fbf45f1959535aed80ae3cebec0fc2689ede91 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:01490ba535afc05ee334d448ed47cab3259b31295dc7c47e528e9c2d8838208f +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..2b55730e5fdaab0274b87e6e86ee3d33231ecfa1 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12df001221bbfdbfb9d6dd333a7f0561cf551c9926496bb035d8978594ae94b4 +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..af223b8a3c5aa0bed6719a744f3a99b91e9cd4a0 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f1d0011d73a793edad00e0991603df931f0c739fd83d2c7bd8ff43288e0f8d20 +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..4657417bc006314888b449baeccd6c51dab772d4 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/D6IDJUJXN24YEOIGY5RIQ5ZG47A4OX3RMH7WH6MFXAVLMXUJLSGA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:726dbef7970ca53a3904b933d43664eefaffef6ed47c788ef494005c34ce85d4 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..f06675dc89539d721df747c50eaab1f1a489236d --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/MCO3N4AYXUQACQZE4JGAJI6RZY4AZATO63HFLAOFLKONCQKBQPOA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f238b24a1022ddfc9ed5cdc14dafa9237f09c50347eb3e3a4f723c130325dac9 +size 143952 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0431177ed8fe1656997c0f45faa4369fdf101441 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/MO45XNOXFUCHRK7VOQNSU6QZODG5ZJXJDUA4RGVIWJTW23L4WSOA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fe6ed16faccc00fa8eff816a625f08f2b44d172dab172146b74f3bf5a8cff36 +size 327048 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..b182d32f541452dc7cf8a1ebfa550eab91e90430 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9f0526e18691cf4f8a4fc9d35ff7bdb0823db932bcdfc6ee8ee5f324fca1fb39 +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dd78d2f6463167dc75c73d301ae4559cd7e55ab8 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/5/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cb0d866dd9d6ec111e4d778c5bcde2b262e650468af26bda5a56a80baaf5f3fe +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..7b9324ee119e1e4c3602a8a6fc82b0aeb632d353 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8af8bdf9fc75186a002199f7e26bc1aba864f7e663ce8b732534fdd2df620791 +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..d9063f11b490e7b871287a325dee3987d8cccc53 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0796bf5d011ca48f60e8078c3ad0f7448c4396f346e34af7de1f3ee7e0757be1 +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..47f192eb42daa633e78ab64d6c3f045e7bdba6b2 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6bafae213c6c4c04b4b2c8e7bb12fb940c6a03e039b466875350620dd43ced56 +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..e8aa93d1402b62432c334a40ec1eae55e6d68319 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/FHV5Y7F4KT7NEEU6R2SM5Y2Z3LPI3U4EELQTCLYOEEXFQOHCRKQQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ba64552a61c25e061ffbad049f5aca9205a4ad9abb2c067b19459fdac99d1d7 +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a1e9af17c43203070c351781f41a5bb0f354cef2 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/JVTNHVFDKA4LESRACQY2XPF5NDODUIBQSVFZDCGCZ3ORIYDD3ZHA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61c0e2161c5f1faeaabc9d2d727785a3e0c2288f09f842bccd453c8219f6b346 +size 402056 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dbcaf1fb5a458569019f5b64cdcf91884a120b7b --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/P5HDG675Q72NL3HZ7XGOXYCQSZHCV45FMKETZG2QE7P34X5UIB3Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3637eeb67c7a7131210e6e3de7317c89719269074aeac31140c634ccf9d627a8 +size 174160 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0028ffe2d63f6c9775f5df9c49b7fd46942ac598 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cc6fa6c42b7acb451951acf22773704ad56e8ebb188ac0d79c4bc54e61728f4 +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..a948284eea993025adab1a38760a9cc26147a623 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de25dad900afc814c092819616712b1df58ff625de2f02eda01e35eeec54fefd +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..60672cc7d48f5e74f5be4bbf1a52e1576a5c38ce --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/6/WVN7L6AKYZ25BUMZVQA34FUKPTGUU3R2QRAJG4YY3X6H6YDKZDGQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c37055c52a45bca095a807af95ee39ecd9570b5d642da437a7b896399ad6139b +size 1752792 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..8206c6911dc372b59777eed9643287f4e3b12268 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/23MFPG6HLDX2565HGAMARD6NR52JWXZFYOVRFUBKYJAOEMI2YQEQ/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d55e59e6fad153629a5b03cfe5a2ced32c43016aa1ce40b67785f0fe7aff35bd +size 173416 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0afe78d518a2c14900e7e61c8bf736ad5f12cb37 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/55SWO7OMWD6RZIZ6F36YLXJHWVKHGX3ISMIWZLSGCCCPLNLDEP7A/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b9a692d3fc249c555705e89fc4f6e5d62c0e0c1e0116237faffcc80b55db1d62 +size 3318360 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..308f164ba01bb85475101b61163af940f5c6f861 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/7XYCMOPGDICSBBN4N46UWO2BLUA2ZH4YYLO2F5SVEXNOEL6NVJRQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ea725e37a89db43a1a5e6c4a58be8d71ea5e258151d75a2c20621faecd52467 +size 463272 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..1f68b06cb727f645be8147fbb41e45c657b8b954 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/BDG4ET25LXBRK26B25P5B3UVFBZX2LLVDGNFF5446XZR4AGJPD7Q/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:09214a998818470130b01a045e4c984ed47907942163812313f2c4b4bab3e47f +size 173520 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..9eb0973a01565bda9aa813dd26ef12adac2bc952 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/IZ66LQX6UJ4O7V3S2AUOHX26H5RAAUXGTZ5TK4DZJMUH2C62JAGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94d2239a474c76076dcff4de4b1bbb416d4267273eeccde745723c82b668f44d +size 463264 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..0d8eaf2c1da9c5096b15373cc4aac3e702e6d973 --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/PJJES3QEVXF7MPESQRKFQ4D55L4Y7YJPTGXSVMGRCNUVXD3MMXGQ/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:892fd11e6233e00f61ff01fcc97a907ea46a43177a04f3cf0e98dc3082fefd66 +size 462480 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin new file mode 100644 index 0000000000000000000000000000000000000000..493a6653780d4dd205de6d40de8b67c7da20220e --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/TKQ76XZVBACEHVMANNR2CEWNWJW6KUV7UUWRRJBEGHJX6SPHQCAA/triton_tem_fused_0.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04d02a11a4b38e94afa062eda0881f22990045151fddb2c74bf7731ed28de99b +size 173144 diff --git a/progress/github/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin b/progress/github/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin new file mode 100644 index 0000000000000000000000000000000000000000..dacbbc92266bdedffe6bcf8952b0011e5fc7b92f --- /dev/null +++ b/progress/github/SpecForge/cache/compiled_kernels/triton/7/ZXDXU5BEB2QMUZ6FM4UEXKQ6PX5MA5YQAZA57PYS57SGBOFLE2AA/triton_tem_fused_mul_1.cubin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5adbf7ecac22edb443a90cc6f8c0ab171e7862cc235d6f7a1993d3a316c3cfa3 +size 404232 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..f1111b32b66e2ddf659940ddf2b3761566de33ca --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00000_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:132c886d625765401f3e019cc5959ad247ec441c4b51e9e155bf0a46914357b9 +size 735721400 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..907ce655f1a2dd49722e752b6004b175d84340eb --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00001_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4a2b9099b787b4d3acf78e2d5fa6fb38aecb31ab69b231a15e9ed86b7da7ee0f +size 735557744 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9f0b7da6a3bd3d76f4f7a42d94a0776b7b9413e8 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00002_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f999001c24e33174fd773268591ae3681b02d02a651fb57bd8d09f9005ab6352 +size 735095872 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..6da1a2c9e03052a4fa96f57fc6bcd40d120bb211 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00003_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63ac28124314c75a11231f97948b2b0280c44b2b94b9ca06ead8b3e10969e1b5 +size 732256888 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..575592eb174f034ad074c48f8c6a233f3275aef3 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00004_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:297731c4c092a56c5b15b20afd7e1cfcdc8fe0e6389e1ebf83caf9dc036f3c55 +size 733823872 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..96cf85d36ccc757d03a9be9c213aa7bb7183fe98 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00005_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:721081d3411c964927b3cef05bef704ac00ef37d4fc166078c840bf79e935530 +size 735340496 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..3334996ace7267af0098f8034aa4e79ac365f1da --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00006_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5966bb10e2b0de0d52439f258947a7750f4a6deb5647ebb81cca47ab7391e880 +size 736955496 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..1f96e14d4d4b65fbf70674cc9b5a7520c4fd2981 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00007_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c6c4003f88c3717d190f3cb99bfe24f1e5363392d6b7df24216d0df4b01144f +size 737732272 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b552c287ca623c4690b0b4cf4d8496428f2e5514 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00008_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c00e288b4bc7f2662ac1085c1bba556b0b373f33134a75aa3e961fef7d67cbc +size 731997528 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cf64c6f0d6b3a6162fb545766e27c59c78764d22 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00009_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e86e86424896fd1cdb40d2fadb007fa1be7aa189757ba49a2a2e5963266916ba +size 734300776 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..00d5bfab07aa01e8fa24a716b12d5d143b488a80 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00010_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:639abb78f011e69cd47a321e3c6d6bae9a6428d5d29a70c8ec20030b7fec4245 +size 732017816 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..7ae90fbc654a4c5691bb40c02e3359bf4823588b --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00011_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d69c8c94eccfb1f9cd9def566dc6782281675604171ea31d3c0f76d56434ba62 +size 733279896 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..0647f948edb000d70a864286f72990317fdf9cd1 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00012_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c23b266c83cbab92268d32038a1f257d35b64f94e850a64903ee35ec4f281b46 +size 734685704 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..9c79ad4ce7966812f08e7f2e4880a84cc1f426be --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00013_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fb741a13f6f8359cd9b86302eeec12d5e10403e7ddaf642bd4e71701dd6032ec +size 732961272 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..86e298197a85ef454e04ce36c095e4dd66587c95 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00014_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:930d0c3705341a9cbc9666416baaefc1e0f99867955bcacb610553c510a1fa64 +size 732441392 diff --git a/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl new file mode 100644 index 0000000000000000000000000000000000000000..ff860383c7a31e6c379908e28c16af0d17fcbda1 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/83967db1929c2a8184d35d6891dc115b_00015_of_00016.pkl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08c4fbfaa28d67217d43a96be17c486803d6f5378b6e079559b678ed4ab480e5 +size 733167752 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow new file mode 100644 index 0000000000000000000000000000000000000000..897af2c3b069371f2129e5205ae92ddeda375cf6 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-3903aae90a46fd54.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1db1d3dedad9e7690adaba29a0dfa584d691cda9850556d9a1ef397073392d9 +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow new file mode 100644 index 0000000000000000000000000000000000000000..8cd53932a5731bd13ba675852c8987491d8deca9 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-5e594a3413471d61.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7aaeda730f17c6c7ecb3025d26f88b92975cced394fc2c7366c0df5d35668490 +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow new file mode 100644 index 0000000000000000000000000000000000000000..eb7a83cc67d41abfac390721eabba7bbe2444bb5 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-77fced7df9807f00.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d790acddc26d55d56e7c17be8f8b22d6c6c570a2faafba2589a030fa4fbd3517 +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow new file mode 100644 index 0000000000000000000000000000000000000000..3fdb7a88291f37bb02abbbbc81b4502ba763e8ab --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-8ac2d3fc56fed7bb.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf708743744631848d2791290ed5ba7c526fde8b85025afcad213f6315c7bf4b +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow new file mode 100644 index 0000000000000000000000000000000000000000..35455d51b0e9c05b815b9a2f2a8f5a999526a206 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-a78107d16074f372.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ac4a97457a59253f5f897550abc8e49b3bec59f74ba42319ea0685da21d396a8 +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow b/progress/github/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow new file mode 100644 index 0000000000000000000000000000000000000000..0b960ae32f8f2789f15e383ad3da43f266a16570 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/cache-ca05f99d08b68367.arrow @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5120a4fe4250bd6a7b44e910a4e879616ba231f99ee73e51ac5302571e5504f8 +size 6459120 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp01so9qky b/progress/github/SpecForge/cache/processed_dataset/tmp01so9qky new file mode 100644 index 0000000000000000000000000000000000000000..d79ef286ba6226980d1f7f15e67fe56c3199e4bf --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp01so9qky @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:db6615f9753c47f5b2085cfc74066f52a579018064107871e743ddf74dbd50c1 +size 14008256 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp12qwgf9o b/progress/github/SpecForge/cache/processed_dataset/tmp12qwgf9o new file mode 100644 index 0000000000000000000000000000000000000000..3ea302681f0a88ed1d9dfb80fe634affe36cc7be --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp12qwgf9o @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:535d6454c289db1a6140314706ad6715a321c9fa046fd1169273178316bd4d68 +size 14469240 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp1bg64fz1 b/progress/github/SpecForge/cache/processed_dataset/tmp1bg64fz1 new file mode 100644 index 0000000000000000000000000000000000000000..85656573bdc51f9d3ee682d29eb4206f13380036 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp1bg64fz1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:850016fc63d602c65a5a97cbdd4e6bce0955507dfe01a8fcb72c18ce8ba36b5c +size 27985920 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp1e9_w76a b/progress/github/SpecForge/cache/processed_dataset/tmp1e9_w76a new file mode 100644 index 0000000000000000000000000000000000000000..04717103f7ba340a819e1427d282f93c1701d85b --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp1e9_w76a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ff1b9c9bedd9867155f90452c530fe455d998636d7e6fdfbc8e4d7cff7abff4 +size 14309592 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp1olkr9hg b/progress/github/SpecForge/cache/processed_dataset/tmp1olkr9hg new file mode 100644 index 0000000000000000000000000000000000000000..32e01064951a44831d3a9d14fde5db509fb4666a --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp1olkr9hg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60e7b092412b38c3bbd43a8704042519e012e177878f5e27d41feb2eede2e65e +size 14610104 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp2rghitts b/progress/github/SpecForge/cache/processed_dataset/tmp2rghitts new file mode 100644 index 0000000000000000000000000000000000000000..e794c77eb97d5cb195e4152e26d201e02c2d5244 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp2rghitts @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff8234c074f61444a34be85fc081dd97b8bc02d0b9a8338ac33e09bbe6068ddd +size 14208160 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp31b6467g b/progress/github/SpecForge/cache/processed_dataset/tmp31b6467g new file mode 100644 index 0000000000000000000000000000000000000000..1e2d4670bb4d78f0ea39438936fc928d4e00c96c --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp31b6467g @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:21691227b89f0dbccbbb58054a584d4aa14cd70f895c6064fe58326d9414df02 +size 14685448 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp3zlhgr3y b/progress/github/SpecForge/cache/processed_dataset/tmp3zlhgr3y new file mode 100644 index 0000000000000000000000000000000000000000..f30e0213ea72a0076584ba098c1b1a95b2380714 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp3zlhgr3y @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d532983ff065b8a6b5f8ca8c22e5e6afb38b4490a7889b920b69b0b32f75186f +size 14305088 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp4mtyrhf4 b/progress/github/SpecForge/cache/processed_dataset/tmp4mtyrhf4 new file mode 100644 index 0000000000000000000000000000000000000000..00bb26f18ea66b3af2fc480c63188e5ad9a32925 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp4mtyrhf4 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b67abcb711547061f6e9063dc8f65815698bf2c23d77a6a4344ea827a5cc1505 +size 14390160 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp5_v0vecp b/progress/github/SpecForge/cache/processed_dataset/tmp5_v0vecp new file mode 100644 index 0000000000000000000000000000000000000000..fb4d0062678b3527bd890688efabf9dd6c94e4bb --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp5_v0vecp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c283619f14142c3078b9ee768f67b4389b1d8bfbadcc8743bbc434ccd7f79c7a +size 14299264 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp7ap84b3p b/progress/github/SpecForge/cache/processed_dataset/tmp7ap84b3p new file mode 100644 index 0000000000000000000000000000000000000000..8a6494ff40fefa08e23029d3ae4da8db905dd6a1 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp7ap84b3p @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f7fe14827200349ce37068031d15a72a1c7827b129331c137c39be888cd41f7 +size 14549528 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp839oymis b/progress/github/SpecForge/cache/processed_dataset/tmp839oymis new file mode 100644 index 0000000000000000000000000000000000000000..c9be5317d347f4988383041606dc97795e371a3e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp839oymis @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65eda2476c3315b8459176862b2cac66674fe47bff1cb39a8be29ea46c3c870b +size 14418328 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp8mzly0vz b/progress/github/SpecForge/cache/processed_dataset/tmp8mzly0vz new file mode 100644 index 0000000000000000000000000000000000000000..d78709cfd5da53c6ce9c80dfc687c9594dd2bc6e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp8mzly0vz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:026d9317135af7923defc111961718a758c0083c064c320d0b829915b1281a7c +size 14213152 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp8uie6nur b/progress/github/SpecForge/cache/processed_dataset/tmp8uie6nur new file mode 100644 index 0000000000000000000000000000000000000000..3a94da8d44d4c3d93c9b35016ef4245475264e74 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp8uie6nur @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:831744c4048a87dc92965b0dddba06eeb705660db620669043d9ccf74da41a37 +size 13645392 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp_1rdxt81 b/progress/github/SpecForge/cache/processed_dataset/tmp_1rdxt81 new file mode 100644 index 0000000000000000000000000000000000000000..4872c14aebec93de6714255530e565a70eb5ef3c --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp_1rdxt81 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:187cf4c9b1f448699c206b06befbfc8edfb36ba8bd89aef30dc210fa4bef6177 +size 14507192 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp_7409t7u b/progress/github/SpecForge/cache/processed_dataset/tmp_7409t7u new file mode 100644 index 0000000000000000000000000000000000000000..73581aabc40ef4c7d65cbce180ef2e5f11517921 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp_7409t7u @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64232b7b419a87af2a4a1066369bdb20e0ac6b7f964e9ca49ef61e3476d8dcfe +size 14234528 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp_c37vzra b/progress/github/SpecForge/cache/processed_dataset/tmp_c37vzra new file mode 100644 index 0000000000000000000000000000000000000000..857469eb0bd860d5bb700b2a7199084e2fd7c2d6 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp_c37vzra @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:38d0bcc8b6725f30240ffc98717a2eb4032a175384924ed35dcbd9efb369de08 +size 14435592 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmp_f0wuxqs b/progress/github/SpecForge/cache/processed_dataset/tmp_f0wuxqs new file mode 100644 index 0000000000000000000000000000000000000000..77417cb675c159fe2048c368141d6e8371e020a0 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmp_f0wuxqs @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7e0970132d41db6e79d32214280ddcdadf3e634d58049b6f48b47b1c376fcc7e +size 14120112 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpaswc6t6a b/progress/github/SpecForge/cache/processed_dataset/tmpaswc6t6a new file mode 100644 index 0000000000000000000000000000000000000000..9d9cd57143a382efe1599d7b32f7d00bfc1ca560 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpaswc6t6a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e48377fdcbd661adcecdf4a212c58a0bb2bd2358b4158f78bcd9b5eb209b0d48 +size 14128576 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpb5ufd_3k b/progress/github/SpecForge/cache/processed_dataset/tmpb5ufd_3k new file mode 100644 index 0000000000000000000000000000000000000000..d2519aa3cc7a07dbd63d21c5c442a7a3317300f6 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpb5ufd_3k @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:93c58e0177cb18a21a7dbbf16cc10c6e90f59cc3a491445ec64dd058aef6e0e7 +size 14375008 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpc8k1wpao b/progress/github/SpecForge/cache/processed_dataset/tmpc8k1wpao new file mode 100644 index 0000000000000000000000000000000000000000..32817148393655f0e0d65e1d87e6e80bcc2ade4f --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpc8k1wpao @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:170e85a998af0fc7cf916d3541090dce8480b695bf03b0e96da7961aa6606681 +size 14232504 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpcv0d9wzf b/progress/github/SpecForge/cache/processed_dataset/tmpcv0d9wzf new file mode 100644 index 0000000000000000000000000000000000000000..62e0781c69865e78a4c9aef5589d5814b5953b7d --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpcv0d9wzf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e548789b824fc02508aaaf05fab42f7ffc47965a90181707f640e6fc8dbf3b8a +size 14575760 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpdbim2npk b/progress/github/SpecForge/cache/processed_dataset/tmpdbim2npk new file mode 100644 index 0000000000000000000000000000000000000000..8a35eff8200c1dbeff9382553849e4377775597e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpdbim2npk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2b7d33855d7d9d61cd886d3c906b06df1ef4a23aaadd0e38c4caec8a16caa36d +size 14694400 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpdof5i3di b/progress/github/SpecForge/cache/processed_dataset/tmpdof5i3di new file mode 100644 index 0000000000000000000000000000000000000000..c64fd0a2957f5e6ab3569026a392136fba9c6c2e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpdof5i3di @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b8d465005bcbe007f75fbfc40d052755a43339e5d1e5725960cc5d0fb8f0a09 +size 14838328 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpdrvr46bq b/progress/github/SpecForge/cache/processed_dataset/tmpdrvr46bq new file mode 100644 index 0000000000000000000000000000000000000000..7d7ebb61f43847a6d2950f63eeebd17b6335ab57 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpdrvr46bq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7954aaecbf8c55b01f14b00bca050e7e3fa294af5056564ae341bb86944288f2 +size 14471528 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpe_yqe1zz b/progress/github/SpecForge/cache/processed_dataset/tmpe_yqe1zz new file mode 100644 index 0000000000000000000000000000000000000000..5df8b760ceeb0071dcb52f32bd843d145b5dddae --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpe_yqe1zz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:621aecec64a2d05c8d1a38c678757888302dc82d36604261e1cb5c4ab7919140 +size 14125832 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpei5ah9j_ b/progress/github/SpecForge/cache/processed_dataset/tmpei5ah9j_ new file mode 100644 index 0000000000000000000000000000000000000000..085ed4d37397aa6a75bc08724c9da0279033cf41 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpei5ah9j_ @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:494498607bed3a91a834928a1f80b46e3f941fb5f219a72915b3551a1b54d230 +size 14201920 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpfbj_hvmg b/progress/github/SpecForge/cache/processed_dataset/tmpfbj_hvmg new file mode 100644 index 0000000000000000000000000000000000000000..21774f85d51670bf903f550170478236cc9de2f0 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpfbj_hvmg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1200d98242813cde1971641f3003efb206d9b32e073f8455775627de1eaf1fcf +size 14697016 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpfuuhammv b/progress/github/SpecForge/cache/processed_dataset/tmpfuuhammv new file mode 100644 index 0000000000000000000000000000000000000000..27b2a68296e49ee51006bd81d87b954abe456ffe --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpfuuhammv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0dc4c385c82a5171eee984bd5036f0316b9d3174a90c5cb927d4cc8f30e302e +size 14949680 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpfwb2ckp1 b/progress/github/SpecForge/cache/processed_dataset/tmpfwb2ckp1 new file mode 100644 index 0000000000000000000000000000000000000000..71e87a58651d19ea4d9f292ce6d084444b6f9c50 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpfwb2ckp1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3ee6965e2ce70f29fd7a3fb54c5fe0cbc0dcfcfa3e2e8bd545dd59fc0d8bb3c +size 14296152 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpfz9hw9rn b/progress/github/SpecForge/cache/processed_dataset/tmpfz9hw9rn new file mode 100644 index 0000000000000000000000000000000000000000..4d89fba6ce3f538ba57b502434d50a38f99193dd --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpfz9hw9rn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:83c5a15aa88ad5d05e870dbd691ed399e232448866a5b1dc36b6e5810ea9a980 +size 28418544 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpgr9rw0_h b/progress/github/SpecForge/cache/processed_dataset/tmpgr9rw0_h new file mode 100644 index 0000000000000000000000000000000000000000..4c7ba5edac6ef33ce3d33067001ccef4316476c9 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpgr9rw0_h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a36f169e73c9e16e49514fe0a3ead45f69208927930231533a102e51a895f67 +size 14559528 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpgszlo7oq b/progress/github/SpecForge/cache/processed_dataset/tmpgszlo7oq new file mode 100644 index 0000000000000000000000000000000000000000..a1557a92c6c4f699d4200de783920a5f4ac362d7 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpgszlo7oq @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:315988bf5b6e683b3a5270a73d064b9d4d76b112a7d0b2f27b8221420af3615e +size 14329432 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmph93s_2g1 b/progress/github/SpecForge/cache/processed_dataset/tmph93s_2g1 new file mode 100644 index 0000000000000000000000000000000000000000..786d5351bf1f28648cfa032430b3a24f56751fc4 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmph93s_2g1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1174bee728f89020c9d1ebc98eb4770dc8e86e49d26bcaaa1cd6976d707ecbf0 +size 14203256 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpinvido_z b/progress/github/SpecForge/cache/processed_dataset/tmpinvido_z new file mode 100644 index 0000000000000000000000000000000000000000..4be9c195c69600d43788fc5d6cc4cb0df95860e6 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpinvido_z @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9cc791cd4fb0f50e0ee56bd959c89403771d2abc7bd4cbdc7e1d0b66ad75146c +size 28822072 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpj1355egn b/progress/github/SpecForge/cache/processed_dataset/tmpj1355egn new file mode 100644 index 0000000000000000000000000000000000000000..184a08ba350248515e1e15d78742ce608ff68df3 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpj1355egn @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b3724358cc8ab218e8e3e68080c3b635ce8623e2287a8138407c1d360c9a7d05 +size 14339544 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpjccpfqmi b/progress/github/SpecForge/cache/processed_dataset/tmpjccpfqmi new file mode 100644 index 0000000000000000000000000000000000000000..6936eb6d6fe5ffbb3600843435caca3e808b9280 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpjccpfqmi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b33cc8b0968eadd5f1989cf0fcce2de1c7aaf50a5295e62e47880d82631dbd0 +size 14546144 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpk5b32oqt b/progress/github/SpecForge/cache/processed_dataset/tmpk5b32oqt new file mode 100644 index 0000000000000000000000000000000000000000..9503a0fe1f6eb8860ac0e5e5566c5eb19e3a750c --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpk5b32oqt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e14d71e747a49c2a23df2952ac438301a60015b23e2409a8b3d1418020c860f +size 14258064 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpkx1kbis9 b/progress/github/SpecForge/cache/processed_dataset/tmpkx1kbis9 new file mode 100644 index 0000000000000000000000000000000000000000..b26e27ece6e7d77613d6efa5cf480522ca235eec --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpkx1kbis9 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8f1397753abda5e31b52f4656a1fd88f1018b51180eeca345e035e057f097bb6 +size 14570896 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpky8ztc3l b/progress/github/SpecForge/cache/processed_dataset/tmpky8ztc3l new file mode 100644 index 0000000000000000000000000000000000000000..30d5a41983810d95ad8c9cf100f24df564800c87 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpky8ztc3l @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4032f840e31345fad47c1d73f2a8cdbfd717bbb395d26e015966aa8620f39125 +size 14312816 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpl94c7jxi b/progress/github/SpecForge/cache/processed_dataset/tmpl94c7jxi new file mode 100644 index 0000000000000000000000000000000000000000..c7b995711ebba4af84765109ae8b1b08a60df5d4 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpl94c7jxi @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb68c302ae1c921eb34592b6208dc51a94e7ba534b64992d0f98b6cc9c793dfc +size 14229592 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpluqfik5a b/progress/github/SpecForge/cache/processed_dataset/tmpluqfik5a new file mode 100644 index 0000000000000000000000000000000000000000..5bfc5f0afdc12f80266f80183faa8175bf358164 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpluqfik5a @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c852c369f52b1ada33d800da23bb65c9f784e613584b346be5d55479359e4d35 +size 14005624 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmplx6mijvc b/progress/github/SpecForge/cache/processed_dataset/tmplx6mijvc new file mode 100644 index 0000000000000000000000000000000000000000..bc15b016fe029db7fa7138887727217f80df6227 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmplx6mijvc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a2afe0d731e023566e7d688d314545ffb8667b9644b89faa5e6c85a48580328 +size 14035736 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpmu8bav05 b/progress/github/SpecForge/cache/processed_dataset/tmpmu8bav05 new file mode 100644 index 0000000000000000000000000000000000000000..1d620b6779fcd2a71108d473de5c272160a32796 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpmu8bav05 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7ac682e9dc98243e44078bbd0254a44e7ce771a42b1c172978c7d83bb76cb838 +size 14717200 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpn3tpi7x_ b/progress/github/SpecForge/cache/processed_dataset/tmpn3tpi7x_ new file mode 100644 index 0000000000000000000000000000000000000000..c58607363f7e68267954928dfd3be43a429d6dc9 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpn3tpi7x_ @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fcd24346a1ca76e25c71579d511141026fd8268df65f3e81848a8befd37eb78 +size 14576720 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpo340xjlj b/progress/github/SpecForge/cache/processed_dataset/tmpo340xjlj new file mode 100644 index 0000000000000000000000000000000000000000..8e7c95e2e20f4ec00464824b654f0bc2cd969ef7 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpo340xjlj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f91a200da3edbb0e6c3a2d769f012717f0dae48344eae8108d2c109dfa9206cb +size 14367552 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpo7jb0q89 b/progress/github/SpecForge/cache/processed_dataset/tmpo7jb0q89 new file mode 100644 index 0000000000000000000000000000000000000000..e949abbbaeb9623087a9bc81fd886b70145e01b9 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpo7jb0q89 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3e41ad0bc36c59a77e93401b3fdf4d96607989a428b2b8e542e67d3004abbbf5 +size 14341280 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpqjqf7u2l b/progress/github/SpecForge/cache/processed_dataset/tmpqjqf7u2l new file mode 100644 index 0000000000000000000000000000000000000000..0df253cc8ce829c137b1ddc39f57d0aaea836815 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpqjqf7u2l @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:30cd5ddf9b43ec1079431b1c59c6647a44419c5a77885296a2d5c46c05b6d867 +size 14499472 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpqpwxjunu b/progress/github/SpecForge/cache/processed_dataset/tmpqpwxjunu new file mode 100644 index 0000000000000000000000000000000000000000..1b1c4a1ab89f1497ea4d5247b1fe79fb1eb26267 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpqpwxjunu @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9858591e5a9750b7588edd5a63c237beefc9cd3dc3b94d6ff307985a31ebbeac +size 14412920 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpqs4xxvi3 b/progress/github/SpecForge/cache/processed_dataset/tmpqs4xxvi3 new file mode 100644 index 0000000000000000000000000000000000000000..17781d8166c4639b88440c45197808343562dd9d --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpqs4xxvi3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:872fdb18356057cf19bd1bad97fdaec05ee15963155293f18c767d6ac7a86802 +size 14193968 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpruq5gh5h b/progress/github/SpecForge/cache/processed_dataset/tmpruq5gh5h new file mode 100644 index 0000000000000000000000000000000000000000..3709f504cba5bcaaa77a41aa39033a20d735ea9c --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpruq5gh5h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e2c00be5f5333a5b3342d896f928453841eb87c64b00cea2c22543c761ce14f9 +size 14478288 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpsaud7inh b/progress/github/SpecForge/cache/processed_dataset/tmpsaud7inh new file mode 100644 index 0000000000000000000000000000000000000000..f8ab301489f61cb32e4be5d112f1884e41e35b3f --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpsaud7inh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:863ca028ae0bb623fdf1f88720fb6e4f058b7f2ffbde4ef7214414f5630d2779 +size 14363408 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpstdi1exz b/progress/github/SpecForge/cache/processed_dataset/tmpstdi1exz new file mode 100644 index 0000000000000000000000000000000000000000..93ebc0250356dac599c7d3c4eb6fbe86066e3a96 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpstdi1exz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2178c3ae41dd903b69cb8dcbbbfd83ce5fbf86db0a274cec0a532798c3910fe9 +size 14662024 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmptqvqvpdk b/progress/github/SpecForge/cache/processed_dataset/tmptqvqvpdk new file mode 100644 index 0000000000000000000000000000000000000000..7b1a67ad9c40789f61232ba7d3a0ee5de2ee8fb0 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmptqvqvpdk @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92d2050b80737ef74ece2d0ee9c62546842b4e3c4990107e8947f087c3a6a89b +size 14496864 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpu7s66cjj b/progress/github/SpecForge/cache/processed_dataset/tmpu7s66cjj new file mode 100644 index 0000000000000000000000000000000000000000..c4d667c80f57ad30b2df0bc1678cb1d38cea9480 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpu7s66cjj @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed7717e339b26bc7ac4ed1da09c7011f6453460edeb0636a0ea1ac728a4e90fc +size 14351480 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpu_vaznd1 b/progress/github/SpecForge/cache/processed_dataset/tmpu_vaznd1 new file mode 100644 index 0000000000000000000000000000000000000000..e080a2a5d9a2d991039c0e82ec4dd195a7c04086 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpu_vaznd1 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35b4a01de87218418767a44e44573762faf9cd767267bf6ae4198f5dfb6dfa96 +size 14429400 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpwokpzxbw b/progress/github/SpecForge/cache/processed_dataset/tmpwokpzxbw new file mode 100644 index 0000000000000000000000000000000000000000..abbce804072ba4826e11bc068260927dd39acf7c --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpwokpzxbw @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:da5cae1766e6b4ef121502b532aa0159708aa2177f8d9c19797cc7fd367afd38 +size 14520848 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpwq89ng3z b/progress/github/SpecForge/cache/processed_dataset/tmpwq89ng3z new file mode 100644 index 0000000000000000000000000000000000000000..5619fa65cca90775b1360cb0da857d18c5b071a8 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpwq89ng3z @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14ad6c44805732fb971151aa5abfb296219f96c8e9a090d8e840d876d18903b9 +size 14664576 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpwvln4iw8 b/progress/github/SpecForge/cache/processed_dataset/tmpwvln4iw8 new file mode 100644 index 0000000000000000000000000000000000000000..30f9cc78af4e7088ce0a47a26fa25ae0573fd79e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpwvln4iw8 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e92b685c9313c4f0063ecdff6588451ea542af0213f6ea9d04ee1e3cfb9848e +size 28655320 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpy2x5wfyd b/progress/github/SpecForge/cache/processed_dataset/tmpy2x5wfyd new file mode 100644 index 0000000000000000000000000000000000000000..03b4f308eb645d3fe62261a7dce6efaf933e8276 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpy2x5wfyd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:317d35e41e35a48fc782bbc4427bdd896a817d3383b4aa0a339c7284ddf5abd4 +size 13988392 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpyhujpj1h b/progress/github/SpecForge/cache/processed_dataset/tmpyhujpj1h new file mode 100644 index 0000000000000000000000000000000000000000..107fd2321e9869745b58a92938ffa42b5196ece1 --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpyhujpj1h @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97788196d246c60dc725b4ae3d60d1702741985eef99fc73f64a2c5c513d4a2f +size 14912032 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpzrflqnck b/progress/github/SpecForge/cache/processed_dataset/tmpzrflqnck new file mode 100644 index 0000000000000000000000000000000000000000..48bec8ce02ba32a57381327cbaf374e6f8c646fa --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpzrflqnck @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9303bdfe20af46910227968c6c71fd109ef4844e86e84dc352afa76aba27bec5 +size 14265816 diff --git a/progress/github/SpecForge/cache/processed_dataset/tmpzyqafx5e b/progress/github/SpecForge/cache/processed_dataset/tmpzyqafx5e new file mode 100644 index 0000000000000000000000000000000000000000..6091bf671968f7170eafd16470f17f51e6e9288e --- /dev/null +++ b/progress/github/SpecForge/cache/processed_dataset/tmpzyqafx5e @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7d2c2a6ab1e82b1b10aede9b9397fc310d8ce9f4f392020429ca75e3847aa6b +size 14488104 diff --git a/progress/github/SpecForge/docs/_static/imgs/specbundle-logo.png b/progress/github/SpecForge/docs/_static/imgs/specbundle-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a4f80b7247e2850e047b11b0d3747893922f35c1 --- /dev/null +++ b/progress/github/SpecForge/docs/_static/imgs/specbundle-logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:491edeb3e50c472046cdaae93f8158f0fe70be1d16282f6397a622f67fa80d5a +size 224984 diff --git a/progress/github/SpecForge/docs/spec_bundle/public/logo.ico b/progress/github/SpecForge/docs/spec_bundle/public/logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..8dfee01264af823a48c4558a6c806a062be0c669 --- /dev/null +++ b/progress/github/SpecForge/docs/spec_bundle/public/logo.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9857743362a074a6856e89dfcc6a93018012260053dee332f3c60163a46bc4f3 +size 264254 diff --git a/progress/github/SpecForge/tests/test_modeling/test_target/test_sglang_backend/images/demo.jpeg b/progress/github/SpecForge/tests/test_modeling/test_target/test_sglang_backend/images/demo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..bd3b67aa7ebe6fc21429ddd155176a84185e748a --- /dev/null +++ b/progress/github/SpecForge/tests/test_modeling/test_target/test_sglang_backend/images/demo.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9eeaa87013b4e800930e8a411b58ff9e2fd5383906b1a022f4a712720af34cc2 +size 496395 diff --git a/progress/github/SpecForge/train_dflash_lora.log b/progress/github/SpecForge/train_dflash_lora.log new file mode 100644 index 0000000000000000000000000000000000000000..bb17e0fa6044b96d560411b304fa2de310099340 --- /dev/null +++ b/progress/github/SpecForge/train_dflash_lora.log @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c2c903da50980b203801767d8bdceeab5f05e277d13fd845225a431f7c16092 +size 45575814 diff --git a/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00001-of-00004.safetensors b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00001-of-00004.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..efbf2c782b44e05ec2383a06600ecd0e15cd122a --- /dev/null +++ b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00001-of-00004.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0dc64934ae0f730ddc80d99af44968d01a89e8454df07d762096ea1356446bc +size 4902257696 diff --git a/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00002-of-00004.safetensors b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00002-of-00004.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..5ec8dfa5f25e7f3e6358a3893242b96fd9a9373c --- /dev/null +++ b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00002-of-00004.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d58533b468c31caa0222540a8aefddea1d74dc6e1fee928da8556d3d85729d6e +size 4915960368 diff --git a/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00003-of-00004.safetensors b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00003-of-00004.safetensors new file mode 100644 index 0000000000000000000000000000000000000000..72f833f96e2bd17fe6153bb46f20a79d4238bdb7 --- /dev/null +++ b/qwen3-8b-dflash-merged/epoch_3_step_18576/model-00003-of-00004.safetensors @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:74927fec432e050365bf757bb30348f560a44394efac89f492680b7c910b64fd +size 4983068496 diff --git a/sglang/.github/ISSUE_TEMPLATE/1-bug-report.yml b/sglang/.github/ISSUE_TEMPLATE/1-bug-report.yml new file mode 100644 index 0000000000000000000000000000000000000000..6e3d9a83b476c78081ba27eb58ea276f494774bf --- /dev/null +++ b/sglang/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -0,0 +1,35 @@ +name: 🐞 Bug report +description: Report a bug to help us reproduce and fix it. +title: "[Bug] " +labels: ['Bug'] + +body: +- type: checkboxes + attributes: + label: Checklist + options: + - label: I searched related issues but found no solution. + - label: The bug persists in the latest version. + - label: Issues without environment info and a minimal reproducible demo are hard to resolve and may receive no feedback. + - label: If this is not a bug report but a general question, please start a discussion at https://github.com/sgl-project/sglang/discussions. Otherwise, it will be closed. + - label: Please use English. Otherwise, it will be closed. +- type: textarea + attributes: + label: Describe the bug + description: A clear, concise description of the bug. + validations: + required: true +- type: textarea + attributes: + label: Reproduction + description: Command/script run and model used. + placeholder: Paste the command here. + validations: + required: true +- type: textarea + attributes: + label: Environment + description: Run `python3 -m sglang.check_env` and paste output here. Issues without this will be closed. + placeholder: Paste environment output here. + validations: + required: true diff --git a/sglang/.github/ISSUE_TEMPLATE/2-feature-request.yml b/sglang/.github/ISSUE_TEMPLATE/2-feature-request.yml new file mode 100644 index 0000000000000000000000000000000000000000..99f1f4d5ed11496dde313b08ee5f1bf08440de72 --- /dev/null +++ b/sglang/.github/ISSUE_TEMPLATE/2-feature-request.yml @@ -0,0 +1,23 @@ +name: 🚀 Feature request +description: Suggest an idea for this project +title: "[Feature] " + +body: +- type: checkboxes + attributes: + label: Checklist + options: + - label: If this is not a feature request but a general question, please start a discussion at https://github.com/sgl-project/sglang/discussions. Otherwise, it will be closed. + - label: Please use English. Otherwise, it will be closed. +- type: textarea + attributes: + label: Motivation + description: | + Clearly and concisely describe the feature's motivation. + validations: + required: true +- type: textarea + attributes: + label: Related resources + description: | + Provide official releases or third-party implementations if available. diff --git a/sglang/.github/actions/upload-cuda-coredumps/action.yml b/sglang/.github/actions/upload-cuda-coredumps/action.yml new file mode 100644 index 0000000000000000000000000000000000000000..0e9fdde2799dc49ab9ea8d948c36dc282ee9352b --- /dev/null +++ b/sglang/.github/actions/upload-cuda-coredumps/action.yml @@ -0,0 +1,27 @@ +name: Upload CUDA Coredumps +description: Upload CUDA coredump files as artifacts and clean up the directory. + +inputs: + artifact-suffix: + description: Suffix appended to the artifact name (e.g. matrix partition id) + required: false + default: "" + retention-days: + description: Number of days to retain the artifact + required: false + default: "7" + +runs: + using: composite + steps: + - name: Upload CUDA coredumps + uses: actions/upload-artifact@v4 + with: + name: cuda-coredumps-${{ github.job }}${{ inputs.artifact-suffix && format('-{0}', inputs.artifact-suffix) }} + path: ${{ env.SGLANG_CUDA_COREDUMP_DIR || '/tmp/sglang_cuda_coredumps' }}/ + retention-days: ${{ inputs.retention-days }} + if-no-files-found: ignore + + - name: Cleanup CUDA coredumps + shell: bash + run: rm -rf "${{ env.SGLANG_CUDA_COREDUMP_DIR || '/tmp/sglang_cuda_coredumps' }}" diff --git a/sglang/.github/workflows/amd-aiter-scout.yml b/sglang/.github/workflows/amd-aiter-scout.yml new file mode 100644 index 0000000000000000000000000000000000000000..9e7b413bc57d02b89af0a75a160f10b946f8791e --- /dev/null +++ b/sglang/.github/workflows/amd-aiter-scout.yml @@ -0,0 +1,161 @@ +name: AMD AITER Scout + +on: + schedule: + - cron: '0 20 * * 1' # Monday 20:00 UTC + - cron: '0 20 * * 4' # Thursday 20:00 UTC + workflow_dispatch: + inputs: + aiter_ref: + description: 'AITER git ref (branch, tag, or SHA). Default: main (latest commit)' + required: false + type: string + default: 'main' + job_filter: + description: 'Comma-separated workflows to run: nightly-amd, nightly-amd-rocm720, pr-test-amd, pr-test-amd-rocm720. Default: all' + required: false + type: string + default: 'all' + continue_on_error: + description: 'Continue running other workflows even if one fails' + required: false + type: boolean + default: true + +concurrency: + group: amd-aiter-scout-${{ github.run_id }} + cancel-in-progress: true + +jobs: + resolve-aiter: + runs-on: ubuntu-latest + outputs: + aiter_sha: ${{ steps.resolve.outputs.sha }} + run_nightly_amd: ${{ steps.parse.outputs.run_nightly_amd }} + run_nightly_amd_rocm720: ${{ steps.parse.outputs.run_nightly_amd_rocm720 }} + run_pr_test_amd: ${{ steps.parse.outputs.run_pr_test_amd }} + run_pr_test_amd_rocm720: ${{ steps.parse.outputs.run_pr_test_amd_rocm720 }} + steps: + - name: Resolve AITER commit + id: resolve + run: | + REF="${{ inputs.aiter_ref || 'main' }}" + echo "Resolving AITER ref: ${REF}" + + SHA=$(git ls-remote https://github.com/ROCm/aiter.git "refs/heads/${REF}" | head -1 | cut -f1) + if [ -z "$SHA" ]; then + SHA=$(git ls-remote https://github.com/ROCm/aiter.git "refs/tags/${REF}" | head -1 | cut -f1) + fi + if [ -z "$SHA" ]; then + SHA=$(git ls-remote https://github.com/ROCm/aiter.git "${REF}" | head -1 | cut -f1) + fi + if [ -z "$SHA" ]; then + SHA="${REF}" + fi + + echo "sha=${SHA}" >> $GITHUB_OUTPUT + echo "### AITER Ref Resolution" >> $GITHUB_STEP_SUMMARY + echo "- **Requested ref:** \`${REF}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Resolved SHA:** \`${SHA}\`" >> $GITHUB_STEP_SUMMARY + echo "- **AITER commit:** https://github.com/ROCm/aiter/commit/${SHA}" >> $GITHUB_STEP_SUMMARY + + - name: Parse job filter + id: parse + run: | + FILTER="${{ inputs.job_filter || 'all' }}" + echo "Job filter: ${FILTER}" + + if [[ "$FILTER" == "all" ]]; then + echo "run_nightly_amd=true" >> $GITHUB_OUTPUT + echo "run_nightly_amd_rocm720=true" >> $GITHUB_OUTPUT + echo "run_pr_test_amd=true" >> $GITHUB_OUTPUT + echo "run_pr_test_amd_rocm720=true" >> $GITHUB_OUTPUT + else + # Wrap with commas for exact substring matching (avoids "nightly-amd" matching "nightly-amd-rocm720") + PADDED=",${FILTER// /}," + echo "run_nightly_amd=$(echo "$PADDED" | grep -q ',nightly-amd,' && echo true || echo false)" >> $GITHUB_OUTPUT + echo "run_nightly_amd_rocm720=$(echo "$PADDED" | grep -q ',nightly-amd-rocm720,' && echo true || echo false)" >> $GITHUB_OUTPUT + echo "run_pr_test_amd=$(echo "$PADDED" | grep -q ',pr-test-amd,' && echo true || echo false)" >> $GITHUB_OUTPUT + echo "run_pr_test_amd_rocm720=$(echo "$PADDED" | grep -q ',pr-test-amd-rocm720,' && echo true || echo false)" >> $GITHUB_OUTPUT + fi + + echo "### Job Filter" >> $GITHUB_STEP_SUMMARY + echo "- **Filter:** \`${FILTER}\`" >> $GITHUB_STEP_SUMMARY + + call-nightly-amd: + if: needs.resolve-aiter.outputs.run_nightly_amd == 'true' + needs: resolve-aiter + uses: ./.github/workflows/nightly-test-amd.yml + secrets: inherit + with: + ref: ${{ github.sha }} + aiter_ref: ${{ needs.resolve-aiter.outputs.aiter_sha }} + job_filter: 'all' + continue_on_error: ${{ inputs.continue_on_error == '' && true || inputs.continue_on_error }} + + call-nightly-amd-rocm720: + if: needs.resolve-aiter.outputs.run_nightly_amd_rocm720 == 'true' + needs: resolve-aiter + uses: ./.github/workflows/nightly-test-amd-rocm720.yml + secrets: inherit + with: + ref: ${{ github.sha }} + aiter_ref: ${{ needs.resolve-aiter.outputs.aiter_sha }} + job_filter: 'all' + continue_on_error: ${{ inputs.continue_on_error == '' && true || inputs.continue_on_error }} + + call-pr-test-amd: + if: needs.resolve-aiter.outputs.run_pr_test_amd == 'true' + needs: resolve-aiter + uses: ./.github/workflows/pr-test-amd.yml + secrets: inherit + with: + run_all_tests: true + aiter_ref: ${{ needs.resolve-aiter.outputs.aiter_sha }} + continue_on_error: ${{ inputs.continue_on_error == '' && true || inputs.continue_on_error }} + + call-pr-test-amd-rocm720: + if: needs.resolve-aiter.outputs.run_pr_test_amd_rocm720 == 'true' + needs: resolve-aiter + uses: ./.github/workflows/pr-test-amd-rocm720.yml + secrets: inherit + with: + run_all_tests: true + aiter_ref: ${{ needs.resolve-aiter.outputs.aiter_sha }} + continue_on_error: ${{ inputs.continue_on_error == '' && true || inputs.continue_on_error }} + + check-all-jobs: + if: always() + needs: + - resolve-aiter + - call-nightly-amd + - call-nightly-amd-rocm720 + - call-pr-test-amd + - call-pr-test-amd-rocm720 + runs-on: ubuntu-latest + steps: + - name: Summary + run: | + echo "## AMD AITER Scout Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **AITER SHA:** \`${{ needs.resolve-aiter.outputs.aiter_sha }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **AITER commit:** https://github.com/ROCm/aiter/commit/${{ needs.resolve-aiter.outputs.aiter_sha }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Workflow | Result |" >> $GITHUB_STEP_SUMMARY + echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY + echo "| Nightly AMD (AITER Latest) | \`${{ needs.call-nightly-amd.result }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| Nightly AMD ROCm 7.2 | \`${{ needs.call-nightly-amd-rocm720.result }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| PR Test AMD (AITER Latest) | \`${{ needs.call-pr-test-amd.result }}\` |" >> $GITHUB_STEP_SUMMARY + echo "| PR Test AMD ROCm 7.2 | \`${{ needs.call-pr-test-amd-rocm720.result }}\` |" >> $GITHUB_STEP_SUMMARY + + - name: Check if any job failed + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + echo "One or more workflows failed" + exit 1 + fi + if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more workflows were cancelled" + exit 1 + fi + echo "All workflows passed" diff --git a/sglang/.github/workflows/amd-ci-job-monitor.yml b/sglang/.github/workflows/amd-ci-job-monitor.yml new file mode 100644 index 0000000000000000000000000000000000000000..1d89deb9ae9bf7fa3dc603b0e47b3835d628aa8b --- /dev/null +++ b/sglang/.github/workflows/amd-ci-job-monitor.yml @@ -0,0 +1,149 @@ +name: AMD CI Job Monitor + +on: + schedule: + - cron: '0 0 * * *' # Daily at midnight UTC + pull_request: + paths: + - '.github/workflows/amd-ci-job-monitor.yml' + - 'scripts/ci/query_job_status.py' + workflow_dispatch: + inputs: + hours: + description: 'Time window in hours' + required: false + default: '24' + type: string + job_filter: + description: 'Job name filter (leave empty for all AMD jobs)' + required: false + type: string + +jobs: + # Single job filter mode + custom-report: + name: Custom Job Report + if: ${{ inputs.job_filter }} + runs-on: ubuntu-latest + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: pip install tabulate + + - name: Generate Custom Job Report + timeout-minutes: 30 + run: | + python scripts/ci/query_job_status.py \ + --repo ${{ github.repository }} \ + --job "${{ inputs.job_filter }}" \ + --workflow "pr-test-amd.yml" \ + --hours ${{ inputs.hours || '24' }} \ + --summary + + # Parse workflow files to get job names dynamically + parse-workflows: + name: Parse Workflow Jobs + if: ${{ !inputs.job_filter }} + runs-on: ubuntu-latest + outputs: + pr_jobs: ${{ steps.parse.outputs.pr_jobs }} + nightly_jobs: ${{ steps.parse.outputs.nightly_jobs }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Parse workflow files + id: parse + run: | + # Parse pr-test-amd.yml and extract job names (exclude utility jobs) + # Excluded: call-gate, check-changes, pr-test-amd-finish, cancel, check-all-jobs + pr_jobs=$(yq -r '.jobs | keys | .[]' .github/workflows/pr-test-amd.yml | \ + grep -v -E '^(call-gate|check-changes|pr-test-amd-finish|cancel|check-all-jobs)$' | \ + jq -R -s -c 'split("\n") | map(select(length > 0))') + echo "pr_jobs=$pr_jobs" >> $GITHUB_OUTPUT + echo "PR jobs: $pr_jobs" + + # Parse nightly-test-amd.yml and extract job names (exclude utility jobs) + # Excluded: check-all-jobs + nightly_jobs=$(yq -r '.jobs | keys | .[]' .github/workflows/nightly-test-amd.yml | \ + grep -v -E '^(check-all-jobs)$' | \ + jq -R -s -c 'split("\n") | map(select(length > 0))') + echo "nightly_jobs=$nightly_jobs" >> $GITHUB_OUTPUT + echo "Nightly jobs: $nightly_jobs" + + # PR CI reports using dynamic matrix + pr-ci-reports: + name: PR - ${{ matrix.job_name }} + needs: parse-workflows + if: ${{ !inputs.job_filter }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + job_name: ${{ fromJson(needs.parse-workflows.outputs.pr_jobs) }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: pip install tabulate + + - name: Generate Report + timeout-minutes: 15 + run: | + python scripts/ci/query_job_status.py \ + --repo ${{ github.repository }} \ + --job "${{ matrix.job_name }}" \ + --workflow "pr-test-amd.yml" \ + --hours ${{ inputs.hours || '24' }} \ + --summary + + # Nightly AMD test reports using dynamic matrix + nightly-reports: + name: Nightly - ${{ matrix.job_name }} + needs: parse-workflows + if: ${{ !inputs.job_filter }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + job_name: ${{ fromJson(needs.parse-workflows.outputs.nightly_jobs) }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: pip install tabulate + + - name: Generate Nightly Report + timeout-minutes: 15 + run: | + python scripts/ci/query_job_status.py \ + --repo ${{ github.repository }} \ + --job "${{ matrix.job_name }}" \ + --workflow "nightly-test-amd.yml" \ + --hours ${{ inputs.hours || '24' }} \ + --summary diff --git a/sglang/.github/workflows/auto-format.yml b/sglang/.github/workflows/auto-format.yml new file mode 100644 index 0000000000000000000000000000000000000000..15b208db82abf19bbddd3a6cd657abbcff13f1b8 --- /dev/null +++ b/sglang/.github/workflows/auto-format.yml @@ -0,0 +1,71 @@ +name: Auto Format Code + +on: + pull_request: + types: [labeled] + +permissions: + contents: write + pull-requests: write + +jobs: + auto-format: + if: github.event.label.name == 'format' + runs-on: ubuntu-latest + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install pre-commit hook + run: | + python -m pip install pre-commit + pre-commit install + + - name: Run pre-commit to format code + run: SKIP=no-commit-to-branch pre-commit run --all-files + continue-on-error: true + + - name: Check for changes + id: check_changes + run: | + if [[ -n $(git status -s) ]]; then + echo "has_changes=true" >> $GITHUB_OUTPUT + else + echo "has_changes=false" >> $GITHUB_OUTPUT + fi + + - name: Commit and push changes + if: steps.check_changes.outputs.has_changes == 'true' + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add . + git commit -m "🤖 Auto-format code with isort, black, ruff, and clang-format" + git push + + - name: Remove format label + if: always() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'format' + }); + } catch (error) { + console.log('Label may have already been removed'); + } diff --git a/sglang/.github/workflows/auto-tune.yml b/sglang/.github/workflows/auto-tune.yml new file mode 100644 index 0000000000000000000000000000000000000000..0afc79bb7c8c08e1071ccc46acf28cc60bbd030f --- /dev/null +++ b/sglang/.github/workflows/auto-tune.yml @@ -0,0 +1,10 @@ +name: Auto tune + +on: + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 diff --git a/sglang/.github/workflows/bot-bump-flashinfer-version.yml b/sglang/.github/workflows/bot-bump-flashinfer-version.yml new file mode 100644 index 0000000000000000000000000000000000000000..cc1cba930ce2bfcc0a41760da888196977bfd866 --- /dev/null +++ b/sglang/.github/workflows/bot-bump-flashinfer-version.yml @@ -0,0 +1,50 @@ +name: Bot Bump Flashinfer Version + +on: + workflow_dispatch: + inputs: + new_version: + description: 'New flashinfer version (e.g., 0.6.4)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + bump-flashinfer-version: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python dependencies + run: | + pip install tomli + + - name: Configure Git and branch + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4) + BRANCH_NAME="bot/bump-flashinfer-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}" + git checkout -b "$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + + - name: Run flashinfer version bump script + run: | + python scripts/release/bump_flashinfer_version.py "${{ github.event.inputs.new_version }}" + + - name: Commit and create PR + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + run: | + bash scripts/release/commit_and_pr.sh "flashinfer" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME" diff --git a/sglang/.github/workflows/bot-bump-kernel-version-to-sglang.yml b/sglang/.github/workflows/bot-bump-kernel-version-to-sglang.yml new file mode 100644 index 0000000000000000000000000000000000000000..817889846a8d5ce11bdcdd54fbe9792223d1ca3f --- /dev/null +++ b/sglang/.github/workflows/bot-bump-kernel-version-to-sglang.yml @@ -0,0 +1,100 @@ +name: Bot Bump Kernel Version to SGLang + +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + bump-kernel-version-to-sglang: + runs-on: ubuntu-latest + outputs: + branch_name: ${{ steps.set_output.outputs.branch_name }} + needs_sync: ${{ steps.check_sync.outputs.needs_sync }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python dependencies + run: | + pip install tomli + + - name: Check if sync is needed + id: check_sync + run: | + python scripts/release/check_kernel_version_to_sglang.py + + - name: Configure Git and branch + if: steps.check_sync.outputs.needs_sync == 'true' + id: set_output + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4) + KERNEL_VERSION="${{ steps.check_sync.outputs.kernel_version }}" + BRANCH_NAME="bot/bump-kernel-version-to-sglang-${KERNEL_VERSION}-${RANDOM_SUFFIX}" + git checkout -b "$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + echo "KERNEL_VERSION=$KERNEL_VERSION" >> $GITHUB_ENV + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Run kernel version bump script + if: steps.check_sync.outputs.needs_sync == 'true' + run: | + python scripts/release/bump_kernel_version_to_sglang.py + + - name: Commit and create PR + if: steps.check_sync.outputs.needs_sync == 'true' + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + run: | + bash scripts/release/commit_and_pr_kernel_to_sglang.sh "$KERNEL_VERSION" "$BRANCH_NAME" + + run-nightly-tests-nvidia: + needs: bump-kernel-version-to-sglang + if: needs.bump-kernel-version-to-sglang.outputs.needs_sync == 'true' + uses: ./.github/workflows/nightly-test-nvidia.yml + with: + ref: ${{ needs.bump-kernel-version-to-sglang.outputs.branch_name }} + secrets: inherit + + run-nightly-tests-amd: + needs: bump-kernel-version-to-sglang + if: needs.bump-kernel-version-to-sglang.outputs.needs_sync == 'true' + uses: ./.github/workflows/nightly-test-amd.yml + with: + ref: ${{ needs.bump-kernel-version-to-sglang.outputs.branch_name }} + secrets: inherit + + run-nightly-tests-npu: + needs: bump-kernel-version-to-sglang + if: needs.bump-kernel-version-to-sglang.outputs.needs_sync == 'true' + uses: ./.github/workflows/nightly-test-npu.yml + with: + ref: ${{ needs.bump-kernel-version-to-sglang.outputs.branch_name }} + secrets: inherit + + run-pr-tests-xeon: + needs: bump-kernel-version-to-sglang + if: needs.bump-kernel-version-to-sglang.outputs.needs_sync == 'true' + uses: ./.github/workflows/pr-test-xeon.yml + with: + ref: ${{ needs.bump-kernel-version-to-sglang.outputs.branch_name }} + secrets: inherit + + run-pr-tests-xpu: + needs: bump-kernel-version-to-sglang + if: needs.bump-kernel-version-to-sglang.outputs.needs_sync == 'true' + uses: ./.github/workflows/pr-test-xpu.yml + with: + ref: ${{ needs.bump-kernel-version-to-sglang.outputs.branch_name }} + secrets: inherit diff --git a/sglang/.github/workflows/bot-bump-kernel-version.yml b/sglang/.github/workflows/bot-bump-kernel-version.yml new file mode 100644 index 0000000000000000000000000000000000000000..91a808c6ab61225fcda8fd182952f482d8cdc43c --- /dev/null +++ b/sglang/.github/workflows/bot-bump-kernel-version.yml @@ -0,0 +1,50 @@ +name: Bot Bump Kernel Version + +on: + workflow_dispatch: + inputs: + new_version: + description: 'New sgl-kernel version (e.g., 0.3.12)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + bump-kernel-version: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python dependencies + run: | + pip install tomli + + - name: Configure Git and branch + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4) + BRANCH_NAME="bot/bump-kernel-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}" + git checkout -b "$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + + - name: Run kernel version bump script + run: | + python scripts/release/bump_kernel_version.py "${{ github.event.inputs.new_version }}" + + - name: Commit and create PR + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + run: | + bash scripts/release/commit_and_pr.sh "sgl-kernel" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME" diff --git a/sglang/.github/workflows/bot-bump-sglang-version.yml b/sglang/.github/workflows/bot-bump-sglang-version.yml new file mode 100644 index 0000000000000000000000000000000000000000..e0a8041e7b5b7fb2c38a2c346ef74c70144fbab9 --- /dev/null +++ b/sglang/.github/workflows/bot-bump-sglang-version.yml @@ -0,0 +1,89 @@ +name: Bot Bump SGLang Version + +on: + workflow_dispatch: + inputs: + new_version: + description: 'New SGLang version (e.g., 0.5.3 or 0.5.3rc0)' + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + bump-sglang-version: + runs-on: ubuntu-latest + outputs: + branch_name: ${{ steps.set_output.outputs.branch_name }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python dependencies + run: | + pip install tomli + + - name: Configure Git and branch + id: set_output + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + RANDOM_SUFFIX=$(echo $RANDOM | md5sum | head -c 4) + BRANCH_NAME="bot/bump-sglang-version-${{ github.event.inputs.new_version }}-${RANDOM_SUFFIX}" + git checkout -b "$BRANCH_NAME" + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT + + - name: Run SGLang version bump script + run: | + python scripts/release/bump_sglang_version.py "${{ github.event.inputs.new_version }}" + + - name: Commit and create PR + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + run: | + bash scripts/release/commit_and_pr.sh "SGLang" "${{ github.event.inputs.new_version }}" "$BRANCH_NAME" + + run-nightly-tests-nvidia: + needs: bump-sglang-version + uses: ./.github/workflows/nightly-test-nvidia.yml + with: + ref: ${{ needs.bump-sglang-version.outputs.branch_name }} + secrets: inherit + + run-nightly-tests-amd: + needs: bump-sglang-version + uses: ./.github/workflows/nightly-test-amd.yml + with: + ref: ${{ needs.bump-sglang-version.outputs.branch_name }} + secrets: inherit + + run-nightly-tests-npu: + needs: bump-sglang-version + uses: ./.github/workflows/nightly-test-npu.yml + with: + ref: ${{ needs.bump-sglang-version.outputs.branch_name }} + secrets: inherit + + run-pr-tests-xeon: + needs: bump-sglang-version + uses: ./.github/workflows/pr-test-xeon.yml + with: + ref: ${{ needs.bump-sglang-version.outputs.branch_name }} + secrets: inherit + + run-pr-tests-xpu: + needs: bump-sglang-version + uses: ./.github/workflows/pr-test-xpu.yml + with: + ref: ${{ needs.bump-sglang-version.outputs.branch_name }} + secrets: inherit diff --git a/sglang/.github/workflows/bot-cherry-pick.yml b/sglang/.github/workflows/bot-cherry-pick.yml new file mode 100644 index 0000000000000000000000000000000000000000..bfc70392e31343cc3428e3ae58f8ab60fe94d07f --- /dev/null +++ b/sglang/.github/workflows/bot-cherry-pick.yml @@ -0,0 +1,182 @@ +name: Bot Cherry Pick to Release Branch + +on: + workflow_dispatch: + inputs: + commit_sha: + description: 'Commit SHA to cherry-pick (full or short hash)' + required: true + type: string + target_branch: + description: 'Target release branch (e.g., release/v0.5.7)' + required: true + type: string + create_pr: + description: 'Create a PR instead of pushing directly' + required: false + type: boolean + default: true + +permissions: + contents: write + pull-requests: write + +concurrency: + group: cherry-pick-${{ github.event.inputs.target_branch }} + cancel-in-progress: false + +jobs: + cherry-pick: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + environment: 'prod' + steps: + - name: Validate inputs + env: + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + run: | + if [[ ! "$TARGET_BRANCH" =~ ^release/v[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then + echo "::error::Target branch must match pattern 'release/vX.Y' or 'release/vX.Y.Z' (e.g., release/v0.5.7)" + exit 1 + fi + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + + - name: Configure Git + run: | + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + + - name: Validate target branch exists + env: + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + run: | + git fetch origin + if ! git ls-remote --exit-code --heads origin "$TARGET_BRANCH" > /dev/null 2>&1; then + echo "::error::Target branch '$TARGET_BRANCH' does not exist on remote" + exit 1 + fi + + - name: Get commit info + id: commit_info + env: + COMMIT_SHA_INPUT: ${{ github.event.inputs.commit_sha }} + run: | + # Verify commit exists + if ! git cat-file -t "$COMMIT_SHA_INPUT" > /dev/null 2>&1; then + echo "::error::Commit SHA '$COMMIT_SHA_INPUT' does not exist" + exit 1 + fi + + # Get full SHA if short hash provided + FULL_SHA=$(git rev-parse "$COMMIT_SHA_INPUT") + COMMIT_TITLE=$(git log -1 --format="%s" "$FULL_SHA") + SHORT_SHA=$(git rev-parse --short "$FULL_SHA") + echo "full_sha=$FULL_SHA" >> $GITHUB_OUTPUT + echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT + # Use delimiter for multiline-safe output + { + echo "commit_title<> $GITHUB_OUTPUT + echo "Cherry-picking commit: $SHORT_SHA - $COMMIT_TITLE" + + - name: Cherry-pick commit + id: cherry_pick + env: + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + FULL_SHA: ${{ steps.commit_info.outputs.full_sha }} + SHORT_SHA: ${{ steps.commit_info.outputs.short_sha }} + CREATE_PR: ${{ github.event.inputs.create_pr }} + run: | + if [[ "$CREATE_PR" == "true" ]]; then + # Create a new branch for the PR + RANDOM_SUFFIX=$(head -c 4 /dev/urandom | xxd -p) + NEW_BRANCH="cherry-pick/${SHORT_SHA}-to-${TARGET_BRANCH#release/}-${RANDOM_SUFFIX}" + git checkout -b "$NEW_BRANCH" "origin/$TARGET_BRANCH" + echo "new_branch=$NEW_BRANCH" >> $GITHUB_OUTPUT + else + # Checkout target branch directly + git checkout "$TARGET_BRANCH" + fi + + # Attempt cherry-pick + if git cherry-pick "$FULL_SHA"; then + echo "cherry_pick_success=true" >> $GITHUB_OUTPUT + else + echo "::error::Cherry-pick failed due to conflicts. Please resolve manually." + git cherry-pick --abort || true + echo "cherry_pick_success=false" >> $GITHUB_OUTPUT + exit 1 + fi + + - name: Push changes + if: steps.cherry_pick.outputs.cherry_pick_success == 'true' + env: + CREATE_PR: ${{ github.event.inputs.create_pr }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + NEW_BRANCH: ${{ steps.cherry_pick.outputs.new_branch }} + run: | + if [[ "$CREATE_PR" == "true" ]]; then + git push origin "$NEW_BRANCH" + else + git push origin "$TARGET_BRANCH" + fi + + - name: Create Pull Request + if: steps.cherry_pick.outputs.cherry_pick_success == 'true' && github.event.inputs.create_pr == 'true' + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_PULL_REQUEST }} + TARGET_BRANCH: ${{ github.event.inputs.target_branch }} + SHORT_SHA: ${{ steps.commit_info.outputs.short_sha }} + COMMIT_TITLE: ${{ steps.commit_info.outputs.commit_title }} + FULL_SHA: ${{ steps.commit_info.outputs.full_sha }} + NEW_BRANCH: ${{ steps.cherry_pick.outputs.new_branch }} + run: | + PR_TITLE="[Cherry-pick] ${COMMIT_TITLE} to ${TARGET_BRANCH}" + + gh pr create \ + --title "$PR_TITLE" \ + --base "$TARGET_BRANCH" \ + --head "$NEW_BRANCH" \ + --label "cherry-pick" \ + --body-file - <> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Triggered by:** @${ACTOR}" >> $GITHUB_STEP_SUMMARY + echo "- **Commit:** ${FULL_SHA}" >> $GITHUB_STEP_SUMMARY + echo "- **Title:** ${COMMIT_TITLE}" >> $GITHUB_STEP_SUMMARY + echo "- **Target Branch:** ${TARGET_BRANCH}" >> $GITHUB_STEP_SUMMARY + if [[ "$CHERRY_PICK_SUCCESS" == "true" ]]; then + echo "- **Status:** ✅ Success" >> $GITHUB_STEP_SUMMARY + else + echo "- **Status:** ❌ Failed" >> $GITHUB_STEP_SUMMARY + fi + if [[ "$CREATE_PR" == "true" && "$CHERRY_PICK_SUCCESS" == "true" ]]; then + echo "- **PR Branch:** ${NEW_BRANCH}" >> $GITHUB_STEP_SUMMARY + fi diff --git a/sglang/.github/workflows/cancel-pr-workflow-on-merge.yml b/sglang/.github/workflows/cancel-pr-workflow-on-merge.yml new file mode 100644 index 0000000000000000000000000000000000000000..535884ba60029580ca148a0866689f58f5722cfd --- /dev/null +++ b/sglang/.github/workflows/cancel-pr-workflow-on-merge.yml @@ -0,0 +1,22 @@ +name: Cancel PR Workflows on Merge + +on: + pull_request_target: + types: + - closed + +permissions: + actions: write + +jobs: + cancel: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.12.1 + with: + workflow_id: all + access_token: ${{ secrets.GITHUB_TOKEN }} + ignore_sha: true + pr_number: ${{ github.event.pull_request.number }} diff --git a/sglang/.github/workflows/cancel-unfinished-pr-tests.yml b/sglang/.github/workflows/cancel-unfinished-pr-tests.yml new file mode 100644 index 0000000000000000000000000000000000000000..2c0e9f63f0bad8a430e3fa2d9a565dfed2608044 --- /dev/null +++ b/sglang/.github/workflows/cancel-unfinished-pr-tests.yml @@ -0,0 +1,141 @@ +name: Cancel Unfinished PR Runs + +on: + workflow_dispatch: + inputs: + workflows: + description: 'Space-separated list of workflow filenames to cancel' + required: true + type: string + default: 'pr-test.yml' + +permissions: + actions: write # Needed to cancel runs + contents: read # Needed to read repo info + pull-requests: read # needed for gh pr view (labels) + +jobs: + cancel-unfinished-pr-runs: + runs-on: ubuntu-latest + steps: + - name: Install GitHub CLI + run: sudo apt-get install -y gh jq + + - name: Cancel unfinished PR-associated runs (skip high-priority PRs) + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + WORKFLOWS: ${{ github.event.inputs.workflows || 'pr-test.yml' }} + shell: bash + run: | + set -euo pipefail + + # Read the space-separated string from the input into a bash array + read -r -a WORKFLOW_FILES <<< "${WORKFLOWS}" + + echo "Targeting ${#WORKFLOW_FILES[@]} workflow(s): ${WORKFLOWS}" + echo "" + + for workflow_file in "${WORKFLOW_FILES[@]}"; do + echo "=========================================" + echo "Workflow: $workflow_file" + echo "=========================================" + + # Get all unfinished runs + all_runs=$(gh run list \ + --repo "$REPO" \ + --workflow "$workflow_file" \ + --json databaseId,status,event,url,createdAt \ + --limit 1000 \ + | jq -c '.[] | select(.status=="queued" or .status=="waiting" or .status=="in_progress")') + + if [ -z "$all_runs" ]; then + echo "✅ No unfinished runs found" + echo "" + continue + fi + + # Count runs by event type + total_runs=$(echo "$all_runs" | wc -l) + pr_runs=$(echo "$all_runs" | jq -s '[.[] | select(.event=="pull_request")] | length') + other_runs=$(echo "$all_runs" | jq -s '[.[] | select(.event!="pull_request")] | length') + + echo "📊 Summary: $total_runs unfinished runs ($pr_runs PR-related, $other_runs other)" + echo "" + + # Process non-PR runs first + if [ "$other_runs" -gt 0 ]; then + echo "--- Non-PR Runs ---" + echo "$all_runs" | jq -c 'select(.event!="pull_request")' | while read -r run; do + run_url=$(echo "$run" | jq -r '.url') + run_event=$(echo "$run" | jq -r '.event') + run_status=$(echo "$run" | jq -r '.status') + echo " • $run_event ($run_status): $run_url" + done + echo "" + fi + + # Process PR runs + if [ "$pr_runs" -gt 0 ]; then + echo "--- PR Runs (checking for cancellation) ---" + echo "$all_runs" | jq -c 'select(.event=="pull_request")' | while read -r run; do + run_id=$(echo "$run" | jq -r '.databaseId') + run_url=$(echo "$run" | jq -r '.url') + run_status=$(echo "$run" | jq -r '.status') + + echo "" + echo "Run ($run_status): $run_url" + + # Fetch full run details to get head repository and branch info + run_details=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/$REPO/actions/runs/$run_id" 2>/dev/null || true) + + if [ -z "$run_details" ]; then + echo " ⚠️ Could not fetch run details, skipping" + continue + fi + + # Get head owner and branch (works for both fork and non-fork PRs) + head_owner=$(echo "$run_details" | jq -r '.head_repository.owner.login // empty') + head_branch=$(echo "$run_details" | jq -r '.head_branch // empty') + + if [ -z "$head_owner" ] || [ -z "$head_branch" ]; then + echo " ⚠️ Missing head info, skipping" + continue + fi + + echo " Branch: ${head_owner}:${head_branch}" + + # Find PR by searching with head=owner:branch + pr_number=$(gh api -H "Accept: application/vnd.github+json" \ + "repos/$REPO/pulls?state=open&head=${head_owner}:${head_branch}" \ + --jq '.[0].number // empty' 2>/dev/null || true) + + if [ -z "$pr_number" ]; then + echo " ⚠️ No open PR found, skipping" + continue + fi + + pr_url="https://github.com/$REPO/pull/$pr_number" + echo " PR: $pr_url" + + # Check for high priority label + labels=$(gh pr view "$pr_number" --repo "$REPO" --json labels \ + | jq -r '.labels[].name' 2>/dev/null || true) + + if echo "$labels" | grep -Fxq "high priority"; then + echo " 🛑 Skipping (high priority label)" + continue + fi + + echo " 🚫 Cancelling..." + gh run cancel "$run_id" --repo "$REPO" || echo " ⚠️ Cancellation failed" + done + fi + + echo "" + done + + echo "=========================================" + echo "✅ Processing complete" + echo "=========================================" diff --git a/sglang/.github/workflows/ci-coverage-overview.yml b/sglang/.github/workflows/ci-coverage-overview.yml new file mode 100644 index 0000000000000000000000000000000000000000..db9269d67e86691d3814582784c0696f99c31513 --- /dev/null +++ b/sglang/.github/workflows/ci-coverage-overview.yml @@ -0,0 +1,92 @@ +name: CI Coverage Overview + +on: + schedule: + - cron: '0 6 * * *' # Daily at 6 AM UTC + pull_request: + paths: + - '.github/workflows/ci-coverage-overview.yml' + - 'scripts/ci/utils/ci_coverage_report.py' + - 'test/registered/**' + workflow_dispatch: + inputs: + output_format: + description: 'Output format' + required: false + default: 'markdown' + type: choice + options: + - markdown + - json + +jobs: + summary: + name: Summary + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Generate Summary Report + run: | + python scripts/ci/utils/ci_coverage_report.py --section summary + + by-folder: + name: Tests by Folder + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Generate Tests by Folder Report + run: | + python scripts/ci/utils/ci_coverage_report.py --section by-folder + + by-suite: + name: Tests by Suite + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Generate Tests by Suite Report + run: | + python scripts/ci/utils/ci_coverage_report.py --section by-suite + + json-export: + name: JSON Export + runs-on: ubuntu-latest + if: inputs.output_format == 'json' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Generate JSON Report + run: | + python scripts/ci/utils/ci_coverage_report.py --output-format json > ci_coverage.json + + - name: Upload JSON artifact + uses: actions/upload-artifact@v4 + with: + name: ci-coverage-report + path: ci_coverage.json diff --git a/sglang/.github/workflows/ci-failure-monitor.yml b/sglang/.github/workflows/ci-failure-monitor.yml new file mode 100644 index 0000000000000000000000000000000000000000..07dcea7d611130007ce59b96ff784c679279a8f6 --- /dev/null +++ b/sglang/.github/workflows/ci-failure-monitor.yml @@ -0,0 +1,72 @@ +name: CI Failure Monitor + +on: + schedule: + - cron: '0 */12 * * *' # Every 12 hour + workflow_dispatch: + +concurrency: + group: ci-failure-monitor-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + actions: read + +jobs: + failure-analysis: + if: github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.14' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install requests slack_sdk + + - name: Run Failure Analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + GH_PAT_FOR_RUNNER_ADMIN: ${{ secrets.GH_PAT_FOR_RUNNER_ADMIN }} + PYTHONUNBUFFERED: 1 + PYTHONIOENCODING: utf-8 + run: | + cd scripts/ci_monitor + python ci_failures_analysis.py \ + --token $GITHUB_TOKEN \ + --limit 100 \ + --output ci_failure_analysis_$(date +%Y%m%d_%H%M%S).json + + - name: Upload Analysis Results + uses: actions/upload-artifact@v4 + with: + name: ci-failure-analysis-${{ github.run_number }} + path: | + scripts/ci_monitor/ci_failure_analysis_*.json + retention-days: 7 + + - name: Send Slack Notification + if: always() + env: + SGLANG_DIFFUSION_SLACK_TOKEN: ${{ secrets.SGLANG_DIFFUSION_SLACK_TOKEN }} + run: | + cd scripts/ci_monitor + LATEST_REPORT=$(ls -t ci_failure_analysis_*.json | head -1) + + if [ ! -f "$LATEST_REPORT" ]; then + echo "No report found, so skipping Slack notification" + exit 0 + fi + + if [ -n "$SGLANG_DIFFUSION_SLACK_TOKEN" ]; then + python3 post_ci_failures_to_slack.py --report-file "$LATEST_REPORT" + else + echo "SGLANG_DIFFUSION_SLACK_TOKEN not configured, skipping notification" + fi diff --git a/sglang/.github/workflows/ci-monitor.yml b/sglang/.github/workflows/ci-monitor.yml new file mode 100644 index 0000000000000000000000000000000000000000..28a198a32a58a90e732940c6dfa17bdc3630fbd5 --- /dev/null +++ b/sglang/.github/workflows/ci-monitor.yml @@ -0,0 +1,111 @@ +name: CI Monitor + +on: + schedule: + - cron: '0 */12 * * *' # Every 12 hours for main analysis + workflow_dispatch: + inputs: + limit: + description: 'Number of CI runs to analyze' + required: false + default: '1000' + type: string + +concurrency: + group: ci-monitor-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + actions: read + +jobs: + ci-monitor: + if: github.repository == 'sgl-project/sglang'|| github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install requests matplotlib pandas + + - name: Run CI Analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + PYTHONUNBUFFERED: 1 + PYTHONIOENCODING: utf-8 + run: | + cd scripts/ci_monitor + python ci_analyzer.py --token $GITHUB_TOKEN --limit ${{ inputs.limit || '1000' }} --output ci_analysis_$(date +%Y%m%d_%H%M%S).json + + - name: Run Nightly Test Analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + PYTHONUNBUFFERED: 1 + PYTHONIOENCODING: utf-8 + run: | + cd scripts/ci_monitor + python ci_analyzer.py --token $GITHUB_TOKEN --mode nightly --days 2 --output nightly_analysis_$(date +%Y%m%d_%H%M%S).json + + - name: Run Performance Analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + PYTHONUNBUFFERED: 1 + PYTHONIOENCODING: utf-8 + run: | + cd scripts/ci_monitor + python ci_analyzer_perf.py --token $GITHUB_TOKEN --limit ${{ inputs.limit || '1000' }} --output-dir performance_tables_$(date +%Y%m%d_%H%M%S) --upload-to-github + + - name: Upload Analysis Results + uses: actions/upload-artifact@v4 + with: + name: ci-analysis-results-${{ github.run_number }} + path: | + scripts/ci_monitor/ci_analysis_*.json + scripts/ci_monitor/nightly_analysis_*.json + scripts/ci_monitor/performance_tables_* + retention-days: 30 + + ci-monitor-balance: + needs: ci-monitor + if: github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install requests + + - name: Run Test Balance Analysis + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + PYTHONUNBUFFERED: 1 + PYTHONIOENCODING: utf-8 + run: | + cd scripts/ci_monitor + python ci_analyzer_balance.py --token $GITHUB_TOKEN --limit ${{ inputs.limit || '1000' }} --output test_balance_report_$(date +%Y%m%d_%H%M%S).json + + - name: Upload Balance Analysis Results + uses: actions/upload-artifact@v4 + with: + name: test-balance-results-${{ github.run_number }} + path: | + scripts/ci_monitor/test_balance_report_*.json + scripts/ci_monitor/test_balance_report_*.csv + retention-days: 30 diff --git a/sglang/.github/workflows/close-inactive-issues.yml b/sglang/.github/workflows/close-inactive-issues.yml new file mode 100644 index 0000000000000000000000000000000000000000..048e6c443c8140e537f0d87136b2f0b15dd4edc6 --- /dev/null +++ b/sglang/.github/workflows/close-inactive-issues.yml @@ -0,0 +1,96 @@ +name: Close Inactive Issues + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +permissions: + issues: write + contents: read + +jobs: + close-inactive-issues: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + steps: + - name: Check and close inactive issues + uses: actions/github-script@v6 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const sixtyDaysAgo = new Date(Date.now() - 60 * 24 * 60 * 60 * 1000); + + const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/'); + console.log(`Owner: ${owner}, Repo: ${repo}`); + + async function fetchIssues(page = 1) { + console.log(`Fetching issues for ${owner}/${repo}, page ${page}`); + return await github.rest.issues.listForRepo({ + owner, + repo, + state: 'open', + sort: 'updated', + direction: 'asc', + per_page: 100, + page: page + }); + } + + async function processIssues() { + console.log('Starting to process issues'); + console.log(`Repository: ${owner}/${repo}`); + + let page = 1; + let hasMoreIssues = true; + while (hasMoreIssues) { + try { + const issues = await fetchIssues(page); + console.log(`Fetched ${issues.data.length} issues on page ${page}`); + + if (issues.data.length === 0) { + hasMoreIssues = false; + break; + } + + for (const issue of issues.data) { + // Skip if the issue has 'good first issue' label + if (issue.labels.some(label => label.name === 'good first issue')) { + console.log(`Skipping issue #${issue.number} as it's marked as 'good first issue'`); + continue; + } + if (new Date(issue.updated_at) < sixtyDaysAgo) { + try { + await github.rest.issues.update({ + owner, + repo, + issue_number: issue.number, + state: 'closed', + labels: [...issue.labels.map(l => l.name), 'inactive'] + }); + await github.rest.issues.createComment({ + owner, + repo, + issue_number: issue.number, + body: 'This issue has been automatically closed due to inactivity. Please feel free to reopen it if needed.' + }); + console.log(`Closed issue #${issue.number} due to inactivity.`); + } catch (error) { + console.error(`Failed to close issue #${issue.number}: ${error.message}`); + } + } else { + console.log(`Issue #${issue.number} is still active. Stopping processing.`); + hasMoreIssues = false; + break; + } + } + page += 1; + } catch (error) { + console.error(`Error fetching issues on page ${page}: ${error.message}`); + hasMoreIssues = false; + } + } + console.log('Finished processing issues'); + } + + await processIssues(); diff --git a/sglang/.github/workflows/diffusion-ci-gt-gen.yml b/sglang/.github/workflows/diffusion-ci-gt-gen.yml new file mode 100644 index 0000000000000000000000000000000000000000..ef039180b0c3ad4ba23bfa63bdfcb4e2ae49bf4e --- /dev/null +++ b/sglang/.github/workflows/diffusion-ci-gt-gen.yml @@ -0,0 +1,129 @@ +name: Diffusion CI Ground Truth Generation + +on: + workflow_dispatch: + inputs: + ref: + description: 'Git ref to checkout' + required: false + default: '' + type: string + case_ids: + description: 'Specific case IDs to run (space-separated, optional)' + required: false + default: '' + type: string + +concurrency: + group: diffusion-ci-gt-gen-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: write + actions: read + +jobs: + multimodal-diffusion-gen-1gpu: + if: github.repository == 'sgl-project/sglang' + runs-on: 1-gpu-runner + strategy: + matrix: + part: [0, 1] + timeout-minutes: 60 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: bash scripts/ci/ci_install_dependency.sh diffusion + + - name: Generate outputs + run: | + cd python + python -m sglang.multimodal_gen.test.scripts.gen_diffusion_ci_outputs \ + --suite 1-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + --out-dir ./diffusion-ci-outputs \ + --continue-on-error \ + ${{ inputs.case_ids != '' && format('--case-ids {0}', inputs.case_ids) || '' }} + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: diffusion-gen-1gpu-part${{ matrix.part }} + path: python/diffusion-ci-outputs + retention-days: 7 + + multimodal-diffusion-gen-2gpu: + if: github.repository == 'sgl-project/sglang' + runs-on: 2-gpu-runner + strategy: + matrix: + part: [0, 1] + timeout-minutes: 60 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: bash scripts/ci/ci_install_dependency.sh diffusion + + - name: Generate outputs + run: | + cd python + python -m sglang.multimodal_gen.test.scripts.gen_diffusion_ci_outputs \ + --suite 2-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + --out-dir ./diffusion-ci-outputs \ + --continue-on-error \ + ${{ inputs.case_ids != '' && format('--case-ids {0}', inputs.case_ids) || '' }} + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: diffusion-gen-2gpu-part${{ matrix.part }} + path: python/diffusion-ci-outputs + retention-days: 7 + + diffusion-ci-push: + needs: [multimodal-diffusion-gen-1gpu, multimodal-diffusion-gen-2gpu] + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + steps: + - name: Checkout sgl-test-files + uses: actions/checkout@v4 + with: + repository: sgl-project/sgl-test-files + path: sgl-test-files + ref: main + token: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + pattern: diffusion-gen-* + path: combined + merge-multiple: true + + - name: Copy image and video frame files + run: | + mkdir -p sgl-test-files/diffusion-ci/consistency_gt + find combined \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.webp" \) -type f -exec cp -f {} sgl-test-files/diffusion-ci/consistency_gt/ \; + + - name: Git commit and push + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + run: | + cd sgl-test-files + git config user.email "github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" + git remote set-url origin "https://x-access-token:${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }}@github.com/sgl-project/sgl-test-files.git" + git add diffusion-ci/consistency_gt/ + git diff --staged --quiet || git commit -m "diffusion-ci: update consistency_gt images [automated]" + git push origin main diff --git a/sglang/.github/workflows/execute-notebook.yml b/sglang/.github/workflows/execute-notebook.yml new file mode 100644 index 0000000000000000000000000000000000000000..b24fe8c81b7f6c8ee120834203b2b67829c25060 --- /dev/null +++ b/sglang/.github/workflows/execute-notebook.yml @@ -0,0 +1,74 @@ +name: Execute Notebooks + +on: + pull_request: + branches: [ main ] + types: [opened, synchronize, reopened, labeled] + paths: + - "python/sglang/**" + - "docs/**" + - "!python/sglang/**/*.md" + - "!docs/**/*.md" + workflow_dispatch: + + +concurrency: + group: execute-notebook-${{ github.ref }} + cancel-in-progress: true + +env: + SGLANG_IS_IN_CI: true + +jobs: + call-gate: + # Align with PR Test: fail fast if PR doesn't have run-ci label. + # This makes /tag-and-rerun-ci work by rerunning this failed workflow. + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + + run-all-notebooks: + needs: [call-gate] + runs-on: 1-gpu-runner + if: github.event_name != 'pull_request' || needs.call-gate.result == 'success' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + pip install -r docs/requirements.txt + apt-get update && apt-get install -y pandoc parallel retry + ln -sf "$(which python3)" /usr/bin/python + + - name: Setup Jupyter Kernel + run: | + python -m ipykernel install --user --name python3 --display-name "Python 3" + + - name: Execute notebooks + timeout-minutes: 40 + run: | + cd docs + make clean + make compile + + + notebook-finish: + needs: [ + call-gate, + run-all-notebooks + ] + runs-on: ubuntu-latest + if: always() && needs.run-all-notebooks.result != 'skipped' + steps: + - name: Check all dependent job statuses + run: | + results=(${{ join(needs.*.result, ' ') }}) + for result in "${results[@]}"; do + if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then + echo "Job failed with result: $result" + exit 1 + fi + done + echo "All jobs completed successfully" + exit 0 diff --git a/sglang/.github/workflows/labeler.yml b/sglang/.github/workflows/labeler.yml new file mode 100644 index 0000000000000000000000000000000000000000..5509bd41170cdcda62fdb75defb42684c585835c --- /dev/null +++ b/sglang/.github/workflows/labeler.yml @@ -0,0 +1,20 @@ +name: Auto Label PRs + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Auto-label by file changes + uses: actions/labeler@v5 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler.yml + sync-labels: false diff --git a/sglang/.github/workflows/lint.yml b/sglang/.github/workflows/lint.yml new file mode 100644 index 0000000000000000000000000000000000000000..80569a22016928a51037d397dce12c4a5bf1ab8d --- /dev/null +++ b/sglang/.github/workflows/lint.yml @@ -0,0 +1,34 @@ +name: Lint + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.12" + + - name: Install pre-commit hook + run: | + python -m pip install pre-commit + pre-commit install + + - name: Run pre-commit checks + run: SKIP=no-commit-to-branch pre-commit run --all-files --show-diff-on-failure + + - name: Run sgl-kernel clang-format checks + uses: DoozyX/clang-format-lint-action@v0.20 + with: + source: sgl-kernel + extensions: h,c,cpp,hpp,cu,cuh,cc + clangFormatVersion: 20 + style: file diff --git a/sglang/.github/workflows/list-active-pr-runs.yml.yml b/sglang/.github/workflows/list-active-pr-runs.yml.yml new file mode 100644 index 0000000000000000000000000000000000000000..10deab8374cff8fd9f3552b621eb77a35f7db965 --- /dev/null +++ b/sglang/.github/workflows/list-active-pr-runs.yml.yml @@ -0,0 +1,317 @@ +name: List Active Runs + +on: + workflow_dispatch: + inputs: + workflows: + description: 'Space-separated list of workflow filenames to check' + required: false + type: string + default: 'pr-test.yml' + +permissions: + actions: read + contents: read + pull-requests: read + +jobs: + list-active-runs: + runs-on: ubuntu-latest + steps: + - name: Install GitHub CLI + run: sudo apt-get install -y gh jq + + - name: List active runs grouped by PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + WORKFLOWS: ${{ github.event.inputs.workflows || 'pr-test.yml' }} + shell: bash + run: | + set -euo pipefail + + echo "=========================================" + echo "🔍 Active Workflow Runs Report" + echo "=========================================" + echo "" + + # Get all workflows or specific ones + read -r -a workflow_files <<< "${WORKFLOWS}" + echo "📋 Checking specified workflows: ${WORKFLOWS}" + + echo "" + + # Create a temporary file to store PR data + pr_data_file=$(mktemp) + + # Process each workflow + for workflow_file in ${workflow_files[@]}; do + echo "Scanning workflow: $workflow_file" + + # Get all active runs (queued, waiting, in_progress) + active_runs=$(gh run list \ + --repo "$REPO" \ + --workflow "$workflow_file" \ + --json databaseId,status,event,headBranch,createdAt,updatedAt,headSha,number,attempt \ + --limit 500 \ + | jq -c '.[] | select(.status=="queued" or .status=="waiting" or .status=="in_progress")') + + if [ -z "$active_runs" ]; then + continue + fi + + # Process each run + echo "$active_runs" | while read -r run; do + run_id=$(echo "$run" | jq -r '.databaseId') + run_status=$(echo "$run" | jq -r '.status') + run_event=$(echo "$run" | jq -r '.event') + created_at=$(echo "$run" | jq -r '.createdAt') + head_sha=$(echo "$run" | jq -r '.headSha') + run_number=$(echo "$run" | jq -r '.number') + run_attempt=$(echo "$run" | jq -r '.attempt // 1') + + # Get detailed run information including jobs + run_details=$(gh api "repos/$REPO/actions/runs/$run_id" 2>/dev/null || true) + + if [ -z "$run_details" ]; then + continue + fi + + head_owner=$(echo "$run_details" | jq -r '.head_repository.owner.login // empty') + head_branch=$(echo "$run_details" | jq -r '.head_branch // empty') + + if [ -z "$head_owner" ] || [ -z "$head_branch" ]; then + continue + fi + + # Find PR number (may be empty for non-PR runs) + pr_number=$(gh api "repos/$REPO/pulls?state=open&head=${head_owner}:${head_branch}" \ + --jq '.[0].number // empty' 2>/dev/null || true) + + if [ -z "$pr_number" ]; then + pr_number="NO_PR" + fi + + # Get jobs for this run (with pagination to avoid missing jobs) + jobs=$(gh api "repos/$REPO/actions/runs/$run_id/jobs" --paginate --jq '.jobs[]' | jq -s '.') + + running_jobs=$(echo "$jobs" | jq '[.[] | select(.status=="in_progress")] | length') + queued_jobs=$(echo "$jobs" | jq '[.[] | select(.status=="queued" or .status=="waiting")] | length') + + # Get runner info for running jobs + runners=$(echo "$jobs" | jq -r '.[] | select(.status=="in_progress") | .runner_name // "N/A"' | paste -sd "," -) + + # Calculate queue time + current_time=$(date -u +%s) + created_time=$(date -u -d "$created_at" +%s 2>/dev/null || echo "$current_time") + queue_time=$((current_time - created_time)) + queue_minutes=$((queue_time / 60)) + + # Store data in temporary file (unified format with event and branch) + echo "$pr_number|$workflow_file|$run_id|$run_status|$running_jobs|$queued_jobs|$runners|$queue_minutes|$created_at|$head_sha|$run_attempt|$run_event|$head_branch" >> "$pr_data_file" + done + done + + echo "" + echo "=========================================" + echo "📊 Active Runs Summary" + echo "=========================================" + echo "" + + if [ ! -s "$pr_data_file" ]; then + echo "✅ No active runs found" + rm -f "$pr_data_file" + exit 0 + fi + + # Get unique PR numbers (exclude NO_PR entries) + pr_numbers=$(cut -d'|' -f1 < "$pr_data_file" | grep -v '^NO_PR$' | sort -u || true) + + # Separate high priority and normal PRs + high_priority_prs=() + normal_prs=() + + for pr_num in $pr_numbers; do + labels=$(gh pr view "$pr_num" --repo "$REPO" --json labels \ + | jq -r '.labels[].name' 2>/dev/null || true) + + if echo "$labels" | grep -Fxq "high priority"; then + high_priority_prs+=($pr_num) + else + normal_prs+=($pr_num) + fi + done + + # Combine: high priority first, then normal + sorted_pr_numbers=("${high_priority_prs[@]}" "${normal_prs[@]}") + + pr_count=0 + total_running=0 + total_queued=0 + + for pr_num in "${sorted_pr_numbers[@]}"; do + pr_count=$((pr_count + 1)) + + # Get PR details + pr_info=$(gh pr view "$pr_num" --repo "$REPO" --json title,author,labels,url 2>/dev/null || true) + + if [ -z "$pr_info" ]; then + continue + fi + + pr_title=$(echo "$pr_info" | jq -r '.title') + pr_author=$(echo "$pr_info" | jq -r '.author.login') + pr_url=$(echo "$pr_info" | jq -r '.url') + pr_labels=$(echo "$pr_info" | jq -r '.labels[].name' | paste -sd ", " -) + + if [ -z "$pr_labels" ]; then + pr_labels="(no labels)" + fi + + # Add priority indicator + priority_indicator="" + if echo "$pr_labels" | grep -q "high priority"; then + priority_indicator="🔴 [HIGH PRIORITY] " + fi + + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "🔗 ${priority_indicator}PR #$pr_num: $pr_title" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "👤 Author: $pr_author" + echo "🏷️ Labels: $pr_labels" + echo "🔗 URL: $pr_url" + echo "" + + # Get all runs for this PR + pr_runs=$(grep "^$pr_num|" "$pr_data_file") + + pr_running_total=0 + pr_queued_total=0 + + echo "$pr_runs" | while read -r line; do + workflow=$(echo "$line" | cut -d'|' -f2) + run_id=$(echo "$line" | cut -d'|' -f3) + status=$(echo "$line" | cut -d'|' -f4) + running=$(echo "$line" | cut -d'|' -f5) + queued=$(echo "$line" | cut -d'|' -f6) + runners=$(echo "$line" | cut -d'|' -f7) + queue_min=$(echo "$line" | cut -d'|' -f8) + created=$(echo "$line" | cut -d'|' -f9) + attempt=$(echo "$line" | cut -d'|' -f11) + + pr_running_total=$((pr_running_total + running)) + pr_queued_total=$((pr_queued_total + queued)) + + run_url="https://github.com/$REPO/actions/runs/$run_id" + + # Calculate retry count for this specific run + retry_count=$((attempt - 1)) + + # Show retry indicator + retry_indicator="" + if [ "$retry_count" -gt 0 ]; then + retry_indicator=" 🔄 Retry #$retry_count" + fi + + echo " 📦 Workflow: $workflow (Run #$run_id)$retry_indicator" + echo " Status: $status" + echo " 🟢 Running jobs: $running" + echo " 🟡 Queued jobs: $queued" + + if [ "$running" -gt 0 ] && [ "$runners" != "" ]; then + echo " 🖥️ Runners: $runners" + fi + + if [ "$queue_min" -gt 0 ]; then + echo " ⏱️ Queue time: ${queue_min} minutes" + fi + + echo " 🔗 Run URL: $run_url" + echo "" + done + + # Summary for this PR + pr_running_total=$(grep "^$pr_num|" "$pr_data_file" | cut -d'|' -f5 | awk '{sum+=$1} END {print sum+0}') + pr_queued_total=$(grep "^$pr_num|" "$pr_data_file" | cut -d'|' -f6 | awk '{sum+=$1} END {print sum+0}') + + total_running=$((total_running + pr_running_total)) + total_queued=$((total_queued + pr_queued_total)) + + echo " 📊 PR Total: $pr_running_total running, $pr_queued_total queued" + echo "" + done + + # --- Non-PR Runs Section --- + non_pr_runs=$(grep '^NO_PR|' "$pr_data_file" 2>/dev/null || true) + non_pr_running=0 + non_pr_queued=0 + + if [ -n "$non_pr_runs" ]; then + echo "=========================================" + echo "📦 Non-PR Runs (manual / scheduled / other)" + echo "=========================================" + echo "" + + echo "$non_pr_runs" | while read -r line; do + workflow=$(echo "$line" | cut -d'|' -f2) + run_id=$(echo "$line" | cut -d'|' -f3) + status=$(echo "$line" | cut -d'|' -f4) + running=$(echo "$line" | cut -d'|' -f5) + queued=$(echo "$line" | cut -d'|' -f6) + runners=$(echo "$line" | cut -d'|' -f7) + queue_min=$(echo "$line" | cut -d'|' -f8) + created=$(echo "$line" | cut -d'|' -f9) + attempt=$(echo "$line" | cut -d'|' -f11) + event=$(echo "$line" | cut -d'|' -f12) + branch=$(echo "$line" | cut -d'|' -f13) + + run_url="https://github.com/$REPO/actions/runs/$run_id" + + retry_count=$((attempt - 1)) + retry_indicator="" + if [ "$retry_count" -gt 0 ]; then + retry_indicator=" 🔄 Retry #$retry_count" + fi + + echo " 📦 Workflow: $workflow (Run #$run_id)$retry_indicator" + echo " Event: $event" + echo " Branch: $branch" + echo " Status: $status" + echo " 🟢 Running jobs: $running" + echo " 🟡 Queued jobs: $queued" + + if [ "$running" -gt 0 ] && [ "$runners" != "" ]; then + echo " 🖥️ Runners: $runners" + fi + + if [ "$queue_min" -gt 0 ]; then + echo " ⏱️ Queue time: ${queue_min} minutes" + fi + + echo " 🔗 Run URL: $run_url" + echo "" + done + + non_pr_running=$(echo "$non_pr_runs" | cut -d'|' -f5 | awk '{sum+=$1} END {print sum+0}') + non_pr_queued=$(echo "$non_pr_runs" | cut -d'|' -f6 | awk '{sum+=$1} END {print sum+0}') + non_pr_count=$(echo "$non_pr_runs" | wc -l | tr -d ' ') + + total_running=$((total_running + non_pr_running)) + total_queued=$((total_queued + non_pr_queued)) + + echo " 📊 Non-PR Total: $non_pr_running running, $non_pr_queued queued" + echo "" + fi + + # Overall summary + echo "=========================================" + echo "📈 Overall Summary" + echo "=========================================" + echo "Total PRs with active runs: $pr_count" + echo "Total non-PR active runs: ${non_pr_count:-0}" + echo "Total running jobs: $total_running" + echo "Total queued jobs: $total_queued" + echo "=========================================" + + # Cleanup + rm -f "$pr_data_file" diff --git a/sglang/.github/workflows/nightly-release-gateway.yml b/sglang/.github/workflows/nightly-release-gateway.yml new file mode 100644 index 0000000000000000000000000000000000000000..19c952103c404d3e7873e1ec6422e6ad9bcea783 --- /dev/null +++ b/sglang/.github/workflows/nightly-release-gateway.yml @@ -0,0 +1,196 @@ +# Nightly release workflow for SGLang Model Gateway + +name: Nightly Release SGLang Model Gateway to PyPI + +on: + schedule: + # Run at 2 AM UTC every day + - cron: '0 2 * * *' + workflow_dispatch: # Allow manual trigger + +jobs: + build: + name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }}) + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu, macos, windows] + target: [x86_64, aarch64] + manylinux: [auto] + include: + - os: ubuntu + platform: linux + - os: windows + ls: dir + target: x86_64 + python-architecture: x64 + interpreter: 3.9 3.10 3.11 3.12 3.13 + - os: macos + target: aarch64 + interpreter: 3.9 3.10 3.11 3.12 3.13 + - os: ubuntu + platform: linux + target: aarch64 + # musllinux + - os: ubuntu + platform: linux + target: x86_64 + manylinux: musllinux_1_1 + - os: ubuntu + platform: linux + target: aarch64 + manylinux: musllinux_1_1 + exclude: + - os: windows + target: aarch64 + + steps: + - uses: actions/checkout@v4 + with: + path: sglang-repo + + - name: Move sgl-model-gateway folder to root and delete sglang-repo + run: | + mv sglang-repo/sgl-model-gateway/* . + rm -rf sglang-repo + ls -alt + shell: bash + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + architecture: ${{ matrix.python-architecture || 'x64' }} + + - name: Modify version for nightly release + run: | + # Get current version from pyproject.toml + CURRENT_VERSION=$(python -c "import tomllib; print(tomllib.load(open('bindings/python/pyproject.toml', 'rb'))['project']['version'])" 2>/dev/null || python -c "import tomli; print(tomli.load(open('bindings/python/pyproject.toml', 'rb'))['project']['version'])") + # Create nightly version with date: e.g., 0.2.1.dev20250128 + NIGHTLY_VERSION="${CURRENT_VERSION}.dev$(date +%Y%m%d)" + echo "Nightly version: $NIGHTLY_VERSION" + + # Update pyproject.toml with nightly version (temporary, not committed) + sed -i.bak "s/version = \"${CURRENT_VERSION}\"/version = \"${NIGHTLY_VERSION}\"/" bindings/python/pyproject.toml + + # Verify the change + cat bindings/python/pyproject.toml | grep "^version" + shell: bash + + - name: Install twine and tomli + run: pip install -U twine tomli + + - name: Install protoc (macOS) + if: matrix.os == 'macos' + run: brew install protobuf + + - name: Install protoc (Windows) + if: matrix.os == 'windows' + run: choco install protoc -y + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + working-directory: bindings/python + target: ${{ matrix.target }} + manylinux: ${{ matrix.manylinux || 'auto' }} + args: --release --out dist --features vendored-openssl --interpreter ${{ matrix.interpreter || '3.9 3.10 3.11 3.12 3.13 3.14' }} + rust-toolchain: stable + docker-options: -e CI -e CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc -e CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ + before-script-linux: | + # Install build dependencies (perl/make for vendored OpenSSL, protoc for gRPC) + if command -v yum &> /dev/null; then + yum update -y && yum install -y wget unzip gcc gcc-c++ perl-core make + # Install cross-compilation toolchain for aarch64 if needed + if [ "${{ matrix.target }}" = "aarch64" ]; then + yum install -y gcc-aarch64-linux-gnu gcc-c++-aarch64-linux-gnu || true + fi + elif command -v apt-get &> /dev/null; then + apt-get update && apt-get install -y wget unzip gcc g++ perl make + # Install cross-compilation toolchain for aarch64 if needed + if [ "${{ matrix.target }}" = "aarch64" ]; then + apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu || true + fi + fi + (cd /tmp && \ + wget https://github.com/protocolbuffers/protobuf/releases/download/v32.0/protoc-32.0-linux-x86_64.zip && \ + unzip protoc-32.0-linux-x86_64.zip -d /usr/local && \ + rm protoc-32.0-linux-x86_64.zip) + protoc --version + + - name: List built packages + run: ${{ matrix.ls || 'ls -lh' }} bindings/python/dist/ + + - name: Check packages + run: twine check --strict bindings/python/dist/* + + - uses: actions/upload-artifact@v4 + with: + name: packages-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux || 'auto' }} + path: bindings/python/dist/ + + build-sdist: + name: Build SDist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: sglang-repo + + - name: Move sgl-model-gateway folder to root and delete sglang-repo + run: | + mv sglang-repo/sgl-model-gateway/* . + rm -rf sglang-repo + ls -alt + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Modify version for nightly release + run: | + # Get current version from pyproject.toml + CURRENT_VERSION=$(python -c "import tomllib; print(tomllib.load(open('bindings/python/pyproject.toml', 'rb'))['project']['version'])" 2>/dev/null || python -c "import tomli; print(tomli.load(open('bindings/python/pyproject.toml', 'rb'))['project']['version'])") + # Create nightly version with date: e.g., 0.2.1.dev20250128 + NIGHTLY_VERSION="${CURRENT_VERSION}.dev$(date +%Y%m%d)" + echo "Nightly version: $NIGHTLY_VERSION" + + # Update pyproject.toml with nightly version (temporary, not committed) + sed -i "s/version = \"${CURRENT_VERSION}\"/version = \"${NIGHTLY_VERSION}\"/" bindings/python/pyproject.toml + + # Verify the change + cat bindings/python/pyproject.toml | grep "^version" + + - name: Build SDist + uses: PyO3/maturin-action@v1 + with: + working-directory: bindings/python + command: sdist + args: --out dist + rust-toolchain: stable + + - uses: actions/upload-artifact@v4 + with: + name: sdist + path: bindings/python/dist/*.tar.gz + + upload: + name: Upload to TestPyPI + if: github.repository == 'sgl-project/sglang' # Ensure this job only runs for the sgl-project/sglang repository + needs: [build, build-sdist] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Upload to TestPyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.TEST_PYPI_TOKEN_ROUTER }} + run: | + pip install twine + twine upload --repository testpypi dist/* --verbose diff --git a/sglang/.github/workflows/nightly-test-amd-rocm720.yml b/sglang/.github/workflows/nightly-test-amd-rocm720.yml new file mode 100644 index 0000000000000000000000000000000000000000..d94c0f86ccd7a70812f0ab227f60147f750c913b --- /dev/null +++ b/sglang/.github/workflows/nightly-test-amd-rocm720.yml @@ -0,0 +1,1366 @@ +name: Nightly Test (AMD ROCm 7.2) + +on: + schedule: + - cron: '0 2 * * *' + push: + branches: + - main + paths: + - "python/sglang/version.py" + workflow_dispatch: + inputs: + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + job_select: + description: 'Select a job to run from dropdown (choose "all" to run all jobs)' + required: false + type: choice + default: 'all' + options: + - 'all' + - nightly-test-1-gpu-unit-rocm720 + - nightly-accuracy-2-gpu-rocm720 + - nightly-accuracy-2-gpu-vlm-rocm720 + - nightly-perf-2-gpu-text-rocm720 + - nightly-perf-2-gpu-vlm-rocm720 + - nightly-accuracy-8-gpu-rocm720 + - nightly-8-gpu-grok1-int4-rocm720 + - nightly-8-gpu-grok2-rocm720 + - nightly-8-gpu-deepseek-v31-rocm720 + - nightly-8-gpu-deepseek-v32-rocm720 + - nightly-8-gpu-deepseek-v32-mtp-rocm720 + - nightly-8-gpu-deepseek-v3-kv-fp8-rocm720 + - nightly-8-gpu-kimi-k25-rocm720 + - nightly-8-gpu-qwen3-235b-rocm720 + - nightly-8-gpu-qwen35-rocm720 + - nightly-8-gpu-glm5-rocm720 + - nightly-8-gpu-minimax-m25-rocm720 + - nightly-1-gpu-zimage-turbo-rocm720 + - nightly-test-1-gpu-mi35x-rocm720 + - nightly-accuracy-8-gpu-mi35x-rocm720 + - nightly-8-gpu-mi35x-grok1-int4-rocm720 + - nightly-8-gpu-mi35x-grok2-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion-rocm720 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-rocm720 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp-rocm720 + - nightly-perf-8-gpu-mi35x-deepseek-v32-basic-rocm720 + - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720 + - nightly-8-gpu-mi35x-kimi-k25-rocm720 + - nightly-8-gpu-mi35x-qwen3-235b-mxfp4-rocm720 + - nightly-8-gpu-mi35x-qwen35-rocm720 + - nightly-8-gpu-mi35x-glm5-rocm720 + - nightly-8-gpu-mi35x-minimax-m25-rocm720 + job_filter: + description: 'Or type comma-separated job names (overrides dropdown if non-empty)' + required: false + type: string + default: '' + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: string + default: 'all' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + +env: + AITER_COMMIT_OVERRIDE: ${{ inputs.aiter_ref }} + +concurrency: + # When called via workflow_call with ref set, use a unique group per caller run to avoid + # collisions with direct schedule/push triggers. We use inputs.ref (not github.event_name) + # to detect this, because github.event_name inherits from the caller in workflow_call. + group: nightly-test-amd-rocm720-${{ inputs.ref && format('caller-{0}', github.run_id) || github.ref }} + cancel-in-progress: ${{ !inputs.ref && github.event_name != 'workflow_call' }} + +jobs: + # ============================================== MI30x ROCm 7.2 Unit Tests ============================================== + # 1-GPU Unit Tests - LoRA, debug utils, scheduler, etc. (MI30x ROCm 7.2) + nightly-test-1-gpu-unit-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-test-1-gpu-unit-rocm720,')) + runs-on: linux-mi325-1gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Nightly Unit Test ROCm 7.2 (1-GPU) + timeout-minutes: 90 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-1-gpu --nightly --timeout-per-file 900 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x ROCm 7.2 Accuracy Tests ============================================== + # 2-GPU Accuracy Tests - GSM8K eval (MI30x ROCm 7.2) + nightly-accuracy-2-gpu-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-2-gpu-rocm720,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Nightly Test ROCm 7.2 (2-GPU) + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU VLM Accuracy Tests - Vision-Language Models MMMU evaluation (ROCm 7.2) + nightly-accuracy-2-gpu-vlm-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-2-gpu-vlm-rocm720,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Nightly Accuracy Test ROCm 7.2 (2-GPU VLM MMMU) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-2-gpu-vlm --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU Text Models Performance Tests (ROCm 7.2) + nightly-perf-2-gpu-text-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-2-gpu-text-rocm720,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Performance Test ROCm 7.2 (2-GPU Text Models) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-perf-text-2-gpu --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU VLM Performance Tests (ROCm 7.2) + nightly-perf-2-gpu-vlm-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-2-gpu-vlm-rocm720,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Performance Test ROCm 7.2 (2-GPU VLM Models) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-perf-vlm-2-gpu --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Accuracy Tests - GPT-OSS, Grok1-FP8 (ROCm 7.2) + nightly-accuracy-8-gpu-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU GPT-OSS) + timeout-minutes: 180 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-gpt-oss --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Accuracy Test ROCm 7.2 (8-GPU Grok1-FP8) + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok1-fp8 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x ROCm 7.2 Combined Accuracy + Performance Tests ============================================== + # 8-GPU Grok1-INT4 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-grok1-int4-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-grok1-int4-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU Grok1-INT4) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test ROCm 7.2 (8-GPU Grok1-INT4) + timeout-minutes: 60 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Grok2 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-grok2-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-grok2-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU Grok2) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test ROCm 7.2 (8-GPU Grok2) + timeout-minutes: 60 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.1 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-deepseek-v31-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v31-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU DeepSeek-V3.1) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v31 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test ROCm 7.2 (8-GPU DeepSeek-V3.1) + timeout-minutes: 300 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_ROCM700A=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v31 --nightly --timeout-per-file 18000 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.2 (Basic Accuracy + Perf) ROCm 7.2 + nightly-8-gpu-deepseek-v32-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v32-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v32 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test ROCm 7.2 (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 150 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v32-basic --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.2 MTP (MTP Accuracy + Perf) ROCm 7.2 + nightly-8-gpu-deepseek-v32-mtp-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v32-mtp-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v32-mtp --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test ROCm 7.2 (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 180 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v32-mtp --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3 KV FP8 (Basic + MTP with --kv-cache-dtype fp8_e4m3) ROCm 7.2 + nightly-8-gpu-deepseek-v3-kv-fp8-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v3-kv-fp8-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: DeepSeek-V3 KV FP8 Test ROCm 7.2 (8-GPU Basic + MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-deepseek-v3-kv-fp8 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Kimi-K2.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-kimi-k25-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-kimi-k25-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU Kimi-K2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-kimi-k25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Qwen3-235B (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-qwen3-235b-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-qwen3-235b-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test + Performance Test ROCm 7.2 (8-GPU Qwen3) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-8-gpu-qwen3-235b --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Qwen 3.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-qwen35-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-qwen35-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-aiter-build --skip-test-time-deps + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git mistral-common "lm-eval[api]" --upgrade + + - name: Accuracy Test ROCm 7.2 (8-GPU Qwen 3.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-qwen35 --nightly --timeout-per-file 3600 --continue-on-error || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU GLM-5 (Accuracy) ROCm 7.2 + nightly-8-gpu-glm5-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-glm5-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # GLM-5 requires latest transformers for glm_moe_dsa architecture + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git + + - name: Accuracy Test ROCm 7.2 (8-GPU GLM-5 NSA) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-glm5 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU MiniMax-M2.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-minimax-m25-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m25-rocm720,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + + - name: Accuracy Test ROCm 7.2 (8-GPU MiniMax-M2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x ROCm 7.2 Diffusion Tests ============================================== + # 1-GPU Z-Image-Turbo (Diffusion T2I) ROCm 7.2 + nightly-1-gpu-zimage-turbo-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-1-gpu-zimage-turbo-rocm720,')) + runs-on: linux-mi325-1gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Z-Image-Turbo Diffusion Test ROCm 7.2 (1-GPU) + timeout-minutes: 45 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + -e SGLANG_DIFFUSION_ARTIFACT_DIR="/sglang-checkout/diffusion-artifacts" \ + pytest test/registered/amd/test_zimage_turbo.py -v -s ${{ inputs.continue_on_error && '|| true' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Upload generated images + if: always() + uses: actions/upload-artifact@v4 + with: + name: zimage-turbo-outputs-rocm720 + path: diffusion-artifacts/ + if-no-files-found: ignore + retention-days: 30 + + # ============================================== MI35x ROCm 7.2 Tests ============================================== + # MI35x 1-GPU ROCm 7.2 tests + nightly-test-1-gpu-mi35x-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-test-1-gpu-mi35x-rocm720,')) + runs-on: linux-mi35x-gpu-1 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Nightly Test MI35x ROCm 7.2 (1-GPU) + timeout-minutes: 90 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-1-gpu-mi35x --nightly --timeout-per-file 900 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Accuracy Tests - GPT-OSS (ROCm 7.2) + nightly-accuracy-8-gpu-mi35x-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU GPT-OSS) + timeout-minutes: 180 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Grok1-INT4 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-grok1-int4-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-grok1-int4-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU Grok1-INT4) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x ROCm 7.2 (8-GPU Grok1-INT4) + timeout-minutes: 60 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Grok2 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-grok2-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-grok2-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU Grok2) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x ROCm 7.2 (8-GPU Grok2) + timeout-minutes: 60 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-deepseek-r1-mxfp4-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4) + timeout-minutes: 300 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 KV FP8 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4 KV FP8) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4 KV FP8) + timeout-minutes: 300 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_kv_fp8_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x ROCm 7.2 (8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion) + timeout-minutes: 300 + continue-on-error: true + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_ar_fusion_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Accuracy Test (ROCm 7.2) + nightly-accuracy-8-gpu-mi35x-deepseek-v32-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x-deepseek-v32-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU DeepSeek-V3.2) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-v32 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 TP+MTP Accuracy Test (ROCm 7.2) + nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU DeepSeek-V3.2 TP+MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-deepseek-v32-mtp --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Performance Test (Basic) ROCm 7.2 + nightly-perf-8-gpu-mi35x-deepseek-v32-basic-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-basic-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Performance Test MI35x ROCm 7.2 (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 150 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-deepseek-v32-basic --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Kimi-K2.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-mi35x-kimi-k25-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-kimi-k25-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU Kimi-K2.5) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-kimi-k25 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Qwen3-235B-MXFP4 (Accuracy + Performance) ROCm 7.2 + nightly-8-gpu-mi35x-qwen3-235b-mxfp4-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-qwen3-235b-mxfp4-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test + Performance Test MI35x ROCm 7.2 (8-GPU Qwen3-235B-MXFP4) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-8-gpu-mi35x-qwen3-235b-mxfp4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Qwen 3.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-mi35x-qwen35-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-qwen35-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-aiter-build --skip-test-time-deps + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git mistral-common "lm-eval[api]" --upgrade + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU Qwen 3.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-qwen35 --nightly --timeout-per-file 3600 --continue-on-error || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + nightly-8-gpu-mi35x-glm5-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-glm5-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + # GLM-5 requires latest transformers for glm_moe_dsa architecture + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU GLM-5 NSA) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-glm5 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU MiniMax-M2.5 (Accuracy) ROCm 7.2 + nightly-8-gpu-mi35x-minimax-m25-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-minimax-m25-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x ROCm 7.2 (8-GPU MiniMax-M2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP) ROCm 7.2 + nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker (ROCm 7.2) + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh --skip-test-time-deps + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Performance Test MI35x ROCm 7.2 (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-deepseek-v32-mtp --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + check-all-jobs: + if: always() && (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') + needs: + # MI30x ROCm 7.2 Unit Tests + - nightly-test-1-gpu-unit-rocm720 + # MI30x ROCm 7.2 Accuracy Tests + - nightly-accuracy-2-gpu-rocm720 + - nightly-accuracy-2-gpu-vlm-rocm720 + # MI30x ROCm 7.2 Performance Tests + - nightly-perf-2-gpu-text-rocm720 + - nightly-perf-2-gpu-vlm-rocm720 + - nightly-accuracy-8-gpu-rocm720 + # MI30x ROCm 7.2 Combined Accuracy + Performance Tests + - nightly-8-gpu-grok1-int4-rocm720 + - nightly-8-gpu-grok2-rocm720 + - nightly-8-gpu-deepseek-v31-rocm720 + - nightly-8-gpu-deepseek-v32-rocm720 + - nightly-8-gpu-deepseek-v32-mtp-rocm720 + - nightly-8-gpu-deepseek-v3-kv-fp8-rocm720 + - nightly-8-gpu-kimi-k25-rocm720 + - nightly-8-gpu-qwen3-235b-rocm720 + - nightly-8-gpu-qwen35-rocm720 + - nightly-8-gpu-glm5-rocm720 + - nightly-8-gpu-minimax-m25-rocm720 + # MI30x ROCm 7.2 Diffusion Tests + - nightly-1-gpu-zimage-turbo-rocm720 + # MI35x ROCm 7.2 jobs + - nightly-test-1-gpu-mi35x-rocm720 + - nightly-accuracy-8-gpu-mi35x-rocm720 + - nightly-8-gpu-mi35x-grok1-int4-rocm720 + - nightly-8-gpu-mi35x-grok2-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8-rocm720 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion-rocm720 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-rocm720 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp-rocm720 + - nightly-perf-8-gpu-mi35x-deepseek-v32-basic-rocm720 + - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp-rocm720 + - nightly-8-gpu-mi35x-kimi-k25-rocm720 + - nightly-8-gpu-mi35x-qwen3-235b-mxfp4-rocm720 + - nightly-8-gpu-mi35x-qwen35-rocm720 + - nightly-8-gpu-mi35x-glm5-rocm720 + - nightly-8-gpu-mi35x-minimax-m25-rocm720 + runs-on: ubuntu-latest + steps: + - name: Check if any job failed + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + echo "One or more ROCm 7.2 nightly test jobs failed" + exit 1 + fi + if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more ROCm 7.2 nightly test jobs were cancelled" + exit 1 + fi + echo "All ROCm 7.2 nightly test jobs passed" diff --git a/sglang/.github/workflows/nightly-test-amd.yml b/sglang/.github/workflows/nightly-test-amd.yml new file mode 100644 index 0000000000000000000000000000000000000000..5aa969b73c984acf007436ee373a712e82c8c865 --- /dev/null +++ b/sglang/.github/workflows/nightly-test-amd.yml @@ -0,0 +1,1373 @@ +name: Nightly Test (AMD) + +on: + schedule: + - cron: '0 0 * * *' + push: + branches: + - main + paths: + - "python/sglang/version.py" + workflow_dispatch: + inputs: + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + job_select: + description: 'Select a job to run from dropdown (choose "all" to run all jobs)' + required: false + type: choice + default: 'all' + options: + - 'all' + - nightly-test-1-gpu-unit + - nightly-accuracy-2-gpu + - nightly-accuracy-2-gpu-vlm + - nightly-perf-2-gpu-text + - nightly-perf-2-gpu-vlm + - nightly-accuracy-8-gpu + - nightly-8-gpu-grok1-int4 + - nightly-8-gpu-grok2 + - nightly-8-gpu-deepseek-v31 + - nightly-8-gpu-deepseek-v32 + - nightly-8-gpu-deepseek-v32-mtp + - nightly-8-gpu-deepseek-v3-kv-fp8 + - nightly-8-gpu-kimi-k25 + - nightly-8-gpu-qwen3-235b + - nightly-8-gpu-qwen35 + - nightly-8-gpu-glm5 + - nightly-8-gpu-minimax-m25 + - nightly-1-gpu-zimage-turbo + - nightly-test-1-gpu-mi35x + - nightly-accuracy-8-gpu-mi35x + - nightly-8-gpu-mi35x-grok1-int4 + - nightly-8-gpu-mi35x-grok2 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion + - nightly-accuracy-8-gpu-mi35x-deepseek-v32 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp + - nightly-perf-8-gpu-mi35x-deepseek-v32-basic + - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp + - nightly-8-gpu-mi35x-kimi-k25 + - nightly-8-gpu-mi35x-qwen3-235b-mxfp4 + - nightly-8-gpu-mi35x-qwen35 + - nightly-8-gpu-mi35x-glm5 + - nightly-8-gpu-mi35x-minimax-m25 + job_filter: + description: 'Or type comma-separated job names (overrides dropdown if non-empty)' + required: false + type: string + default: '' + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: string + default: 'all' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + +env: + AITER_COMMIT_OVERRIDE: ${{ inputs.aiter_ref }} + +concurrency: + # When called via workflow_call with ref set, use a unique group per caller run to avoid + # collisions with direct schedule/push triggers. We use inputs.ref (not github.event_name) + # to detect this, because github.event_name inherits from the caller in workflow_call. + group: nightly-test-amd-${{ inputs.ref && format('caller-{0}', github.run_id) || github.ref }} + cancel-in-progress: ${{ !inputs.ref && github.event_name != 'workflow_call' }} + +jobs: + # ============================================== MI30x Unit Tests ============================================== + # 1-GPU Unit Tests - LoRA, debug utils, scheduler, etc. (MI30x only) + nightly-test-1-gpu-unit: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-test-1-gpu-unit,')) + runs-on: linux-mi325-1gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Nightly Unit Test (1-GPU) + timeout-minutes: 90 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-1-gpu --nightly --timeout-per-file 900 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x Accuracy Tests ============================================== + # 2-GPU Accuracy Tests - GSM8K eval (MI30x only) + nightly-accuracy-2-gpu: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-2-gpu,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Nightly Test (2-GPU) + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU VLM Accuracy Tests - Vision-Language Models MMMU evaluation + nightly-accuracy-2-gpu-vlm: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-2-gpu-vlm,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Nightly Accuracy Test (2-GPU VLM MMMU) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-2-gpu-vlm --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU Text Models Performance Tests + nightly-perf-2-gpu-text: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-2-gpu-text,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Performance Test (2-GPU Text Models) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-perf-text-2-gpu --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 2-GPU VLM Performance Tests + nightly-perf-2-gpu-vlm: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-2-gpu-vlm,')) + runs-on: linux-mi325-2gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Performance Test (2-GPU VLM Models) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-perf-vlm-2-gpu --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Accuracy Tests - GPT-OSS, Grok1-FP8 (accuracy only) + nightly-accuracy-8-gpu: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU GPT-OSS) + timeout-minutes: 180 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-gpt-oss --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Accuracy Test (8-GPU Grok1-FP8) + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok1-fp8 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x Combined Accuracy + Performance Tests ============================================== + # 8-GPU Grok1-INT4 (Accuracy + Performance combined) + nightly-8-gpu-grok1-int4: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-grok1-int4,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU Grok1-INT4) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test (8-GPU Grok1-INT4) + timeout-minutes: 60 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Grok2 (Accuracy + Performance combined) + nightly-8-gpu-grok2: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-grok2,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU Grok2) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test (8-GPU Grok2) + timeout-minutes: 60 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.1 (Accuracy + Performance combined) + nightly-8-gpu-deepseek-v31: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v31,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU DeepSeek-V3.1) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v31 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test (8-GPU DeepSeek-V3.1) + timeout-minutes: 300 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_ROCM700A=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v31 --nightly --timeout-per-file 18000 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.2 (Basic Accuracy + Perf) + nightly-8-gpu-deepseek-v32: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v32,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v32 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 150 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v32-basic --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3.2 MTP (MTP Accuracy + Perf) + nightly-8-gpu-deepseek-v32-mtp: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v32-mtp,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-deepseek-v32-mtp --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 180 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-deepseek-v32-mtp --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU DeepSeek-V3 KV FP8 (Basic + MTP with --kv-cache-dtype fp8_e4m3) + nightly-8-gpu-deepseek-v3-kv-fp8: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-deepseek-v3-kv-fp8,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: DeepSeek-V3 KV FP8 Test (8-GPU Basic + MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-deepseek-v3-kv-fp8 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Kimi-K2.5 (Accuracy) + nightly-8-gpu-kimi-k25: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-kimi-k25,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU Kimi-K2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-kimi-k25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + nightly-8-gpu-qwen3-235b: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-qwen3-235b,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test + Performance Test (8-GPU Qwen3) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-8-gpu-qwen3-235b --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU Qwen 3.5 (Accuracy) + nightly-8-gpu-qwen35: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-qwen35,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git mistral-common "lm-eval[api]" --upgrade + + - name: Accuracy Test (8-GPU Qwen 3.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-qwen35 --nightly --timeout-per-file 3600 || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + nightly-8-gpu-glm5: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-glm5,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # GLM-5 requires latest transformers for glm_moe_dsa architecture + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git + + - name: Accuracy Test (8-GPU GLM-5 NSA) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-glm5 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # 8-GPU MiniMax-M2.5 (Accuracy) + nightly-8-gpu-minimax-m25: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-minimax-m25,')) + runs-on: linux-mi325-8gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Accuracy Test (8-GPU MiniMax-M2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # ============================================== MI30x Diffusion Tests ============================================== + # 1-GPU Z-Image-Turbo (Diffusion T2I) + nightly-1-gpu-zimage-turbo: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-1-gpu-zimage-turbo,')) + runs-on: linux-mi325-1gpu-sglang + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Z-Image-Turbo Diffusion Test (1-GPU) + timeout-minutes: 45 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + -e SGLANG_DIFFUSION_ARTIFACT_DIR="/sglang-checkout/diffusion-artifacts" \ + pytest test/registered/amd/test_zimage_turbo.py -v -s ${{ inputs.continue_on_error && '|| true' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Upload generated images + if: always() + uses: actions/upload-artifact@v4 + with: + name: zimage-turbo-outputs + path: diffusion-artifacts/ + if-no-files-found: ignore + retention-days: 30 + + # ============================================== MI35x Tests ============================================== + # MI35x 1-GPU tests - platform-agnostic tests that may work on CDNA4 (gfx950) + nightly-test-1-gpu-mi35x: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-test-1-gpu-mi35x,')) + runs-on: linux-mi35x-gpu-1 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Nightly Test MI35x (1-GPU) + timeout-minutes: 90 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-1-gpu-mi35x --nightly --timeout-per-file 900 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Accuracy Tests - GPT-OSS (accuracy only) + nightly-accuracy-8-gpu-mi35x: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU GPT-OSS) + timeout-minutes: 180 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Grok1-INT4 (Accuracy + Performance combined) + nightly-8-gpu-mi35x-grok1-int4: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-grok1-int4,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU Grok1-INT4) + timeout-minutes: 90 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-grok1-int4 --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x (8-GPU Grok1-INT4) + timeout-minutes: 60 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-grok1-int4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Grok2 (Accuracy + Performance combined) + nightly-8-gpu-mi35x-grok2: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-grok2,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU Grok2) + timeout-minutes: 60 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x (8-GPU Grok2) + timeout-minutes: 60 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e RCCL_MSCCL_ENABLE=0 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-grok2 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 (Accuracy + Performance combined) + nightly-8-gpu-mi35x-deepseek-r1-mxfp4: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU DeepSeek-R1-MXFP4) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x (8-GPU DeepSeek-R1-MXFP4) + timeout-minutes: 300 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 KV FP8 (Accuracy + Performance combined) + nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU DeepSeek-R1-MXFP4 KV FP8) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x (8-GPU DeepSeek-R1-MXFP4 KV FP8) + timeout-minutes: 300 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_kv_fp8_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion (Accuracy + Performance combined) + nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + - name: Performance Test MI35x (8-GPU DeepSeek-R1-MXFP4 AllReduce Fusion) + timeout-minutes: 300 + continue-on-error: true # Perf test failure doesn't fail the job if accuracy passed + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 registered/amd/perf/mi35x/test_deepseek_r1_mxfp4_ar_fusion_perf_mi35x.py || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Accuracy Test + nightly-accuracy-8-gpu-mi35x-deepseek-v32: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x-deepseek-v32,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU DeepSeek-V3.2) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-deepseek-v32 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 TP+MTP Accuracy Test + nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU DeepSeek-V3.2 TP+MTP) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-deepseek-v32-mtp --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Performance Test (Basic) + nightly-perf-8-gpu-mi35x-deepseek-v32-basic: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-basic,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Performance Test MI35x (8-GPU DeepSeek-V3.2 Basic) + timeout-minutes: 150 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-deepseek-v32-basic --nightly --timeout-per-file 5400 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Kimi-K2.5 (Accuracy) + nightly-8-gpu-mi35x-kimi-k25: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-kimi-k25,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU Kimi-K2.5) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-kimi-k25 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Qwen3-235B-MXFP4 (Accuracy + Performance) + nightly-8-gpu-mi35x-qwen3-235b-mxfp4: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-qwen3-235b-mxfp4,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test + Performance Test MI35x (8-GPU Qwen3-235B-MXFP4) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-8-gpu-mi35x-qwen3-235b-mxfp4 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU Qwen 3.5 (Accuracy) + nightly-8-gpu-mi35x-qwen35: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-qwen35,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git mistral-common "lm-eval[api]" --upgrade + + - name: Accuracy Test MI35x (8-GPU Qwen 3.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-accuracy-8-gpu-mi35x-qwen35 --nightly --timeout-per-file 3600 || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + nightly-8-gpu-mi35x-glm5: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-glm5,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + # GLM-5 requires latest transformers for glm_moe_dsa architecture + bash scripts/ci/amd/amd_ci_exec.sh pip install git+https://github.com/huggingface/transformers.git + + - name: Accuracy Test MI35x (8-GPU GLM-5 NSA) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-glm5 --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU MiniMax-M2.5 (Accuracy) + nightly-8-gpu-mi35x-minimax-m25: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-8-gpu-mi35x-minimax-m25,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Accuracy Test MI35x (8-GPU MiniMax-M2.5) + timeout-minutes: 120 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e SGLANG_USE_AITER=1 \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-amd-8-gpu-mi35x-minimax-m25 --nightly --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + # MI35x 8-GPU DeepSeek-V3.2 Performance Test (MTP) + nightly-perf-8-gpu-mi35x-deepseek-v32-mtp: + if: (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') && (!(inputs.job_filter || inputs.job_select) || (inputs.job_filter || inputs.job_select) == 'all' || contains(format(',{0},', inputs.job_filter || inputs.job_select), ',nightly-perf-8-gpu-mi35x-deepseek-v32-mtp,')) + runs-on: linux-mi35x-gpu-8 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Setup docker + run: | + touch github_summary.md + bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + # Install tabulate for run_suite.py (missing in MI35x container) + bash scripts/ci/amd/amd_ci_exec.sh pip install tabulate + + - name: Performance Test MI35x (8-GPU DeepSeek-V3.2 MTP) + timeout-minutes: 180 + run: | + > github_summary.md # Clear summary file + bash scripts/ci/amd/amd_ci_exec.sh -w /sglang-checkout/test \ + -e GITHUB_STEP_SUMMARY="/sglang-checkout/github_summary.md" \ + python3 run_suite.py --hw amd --suite nightly-perf-8-gpu-mi35x-deepseek-v32-mtp --nightly --timeout-per-file 7200 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} || TEST_EXIT_CODE=$? + echo "$(> $GITHUB_STEP_SUMMARY || true + exit ${TEST_EXIT_CODE:-0} + + check-all-jobs: + if: always() && (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') + needs: + # MI30x Unit Tests + - nightly-test-1-gpu-unit + # MI30x Accuracy Tests + - nightly-accuracy-2-gpu + - nightly-accuracy-2-gpu-vlm + - nightly-accuracy-8-gpu + # MI30x Performance Tests - excluded from check (perf failures don't block CI) + # - nightly-perf-2-gpu-text + # - nightly-perf-2-gpu-vlm + # MI30x Combined Accuracy + Performance Tests + - nightly-8-gpu-grok1-int4 + - nightly-8-gpu-grok2 + - nightly-8-gpu-deepseek-v31 + - nightly-8-gpu-deepseek-v32 + - nightly-8-gpu-deepseek-v32-mtp + - nightly-8-gpu-deepseek-v3-kv-fp8 + - nightly-8-gpu-kimi-k25 + - nightly-8-gpu-qwen3-235b + - nightly-8-gpu-qwen35 + - nightly-8-gpu-glm5 + - nightly-8-gpu-minimax-m25 + # MI30x Diffusion Tests + - nightly-1-gpu-zimage-turbo + # MI35x jobs + - nightly-test-1-gpu-mi35x + - nightly-accuracy-8-gpu-mi35x + - nightly-8-gpu-mi35x-grok1-int4 + - nightly-8-gpu-mi35x-grok2 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-kv-fp8 + - nightly-8-gpu-mi35x-deepseek-r1-mxfp4-ar-fusion + - nightly-accuracy-8-gpu-mi35x-deepseek-v32 + - nightly-accuracy-8-gpu-mi35x-deepseek-v32-mtp + - nightly-8-gpu-mi35x-kimi-k25 + - nightly-8-gpu-mi35x-qwen3-235b-mxfp4 + - nightly-8-gpu-mi35x-qwen35 + - nightly-8-gpu-mi35x-glm5 + - nightly-8-gpu-mi35x-minimax-m25 + # MI35x perf jobs excluded from check - perf failures don't block CI + # - nightly-perf-8-gpu-mi35x-deepseek-v32-basic + # - nightly-perf-8-gpu-mi35x-deepseek-v32-mtp + runs-on: ubuntu-latest + steps: + - name: Check if any job failed + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + echo "One or more nightly test jobs failed" + exit 1 + fi + if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more nightly test jobs were cancelled" + exit 1 + fi + echo "All nightly test jobs passed" diff --git a/sglang/.github/workflows/nightly-test-intel.yml b/sglang/.github/workflows/nightly-test-intel.yml new file mode 100644 index 0000000000000000000000000000000000000000..7f4242370c791a28a144b67c20c4b55896f21664 --- /dev/null +++ b/sglang/.github/workflows/nightly-test-intel.yml @@ -0,0 +1,33 @@ +name: Nightly Test (Intel) + +on: + schedule: + - cron: '0 0 * * *' + push: + branches: + - main + paths: + - "python/sglang/version.py" + workflow_dispatch: + workflow_call: + inputs: + ref: + description: "Branch, tag or SHA to checkout" + required: false + type: string + default: "" + +concurrency: + group: nightly-test-intel-${{ inputs.ref || github.ref }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +jobs: + # Placeholder for Intel GPU tests + # Add Intel-specific nightly test workflows here when available + + placeholder: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + steps: + - name: Placeholder + run: echo "Intel nightly tests will be added here" diff --git a/sglang/.github/workflows/nightly-test-npu.yml b/sglang/.github/workflows/nightly-test-npu.yml new file mode 100644 index 0000000000000000000000000000000000000000..bfbbe80410af03d484258986821737c64f56cd02 --- /dev/null +++ b/sglang/.github/workflows/nightly-test-npu.yml @@ -0,0 +1,320 @@ +name: Nightly Test (NPU) + +on: + schedule: + - cron: '0 17 * * *' # Execute at 1:00 a.m. Beijing Time every day + pull_request: + branches: + - main + paths: + - ".github/workflows/nightly-test-npu.yml" + workflow_dispatch: + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: string + default: 'all' + +concurrency: + group: nightly-test-npu-${{ inputs.ref || github.ref }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +jobs: + nightly-1-npu-a3: + if: ${{ (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') }} + runs-on: linux-aarch64-a3-2 + strategy: + fail-fast: false + matrix: + part: [0, 1] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.extra-index-url "https://pypi.tuna.tsinghua.edu.cn/simple" + pip config set global.trusted-host "${CACHING_URL} pypi.tuna.tsinghua.edu.cn" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Print Log Information + run: | + bash scripts/ci/npu/npu_log_print.sh + + - name: Run test + timeout-minutes: 240 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + pip install sentence_transformers accelerate + cd test + python3 run_suite.py --hw npu --suite nightly-1-npu-a3 --nightly --continue-on-error --timeout-per-file 3600 --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 + + nightly-2-npu-a3: + if: ${{ (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') }} + runs-on: linux-aarch64-a3-2 + strategy: + fail-fast: false + matrix: + part: [0] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.extra-index-url "https://pypi.tuna.tsinghua.edu.cn/simple" + pip config set global.trusted-host "${CACHING_URL} pypi.tuna.tsinghua.edu.cn" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Print Log Information + run: | + bash scripts/ci/npu/npu_log_print.sh + - name: Run test + timeout-minutes: 240 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + pip install sentence_transformers accelerate + cd test + python3 run_suite.py --hw npu --suite nightly-2-npu-a3 --nightly --continue-on-error --timeout-per-file 3600 --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 + + nightly-4-npu-a3: + if: ${{ (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') }} + runs-on: linux-aarch64-a3-4 + strategy: + fail-fast: false + matrix: + part: [0] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Print Log Information + run: | + bash scripts/ci/npu/npu_log_print.sh + + - name: Run test + timeout-minutes: 240 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + hf download lmms-lab/MMMU --repo-type dataset + pip install sentence_transformers + pip install protobuf==6.31.1 zss pre-commit wandb>=0.16.0 tenacity==8.3.0 loguru openpyxl latex2sympy2 zstandard transformers-stream-generator tqdm-multiprocess pycocoevalcap + pip install yt-dlp sentencepiece==0.1.99 nltk av ftfy sqlitedict==2.1.0 sacrebleu>=1.5.0 pytablewriter peft==0.2.0 black==24.1.0 isort==5.13.2 peft>=0.2.0 accelerate>=0.29.1 + pip install jsonlines httpx==0.25.0 evaluate>=0.4.0 datasets==2.16.1 numexpr xgrammar==0.1.25 numpy==1.26.4 dotenv + git clone --branch v0.3.3 --depth 1 https://github.com/EvolvingLMMs-Lab/lmms-eval.git + cd ./lmms-eval + nohup pip install . > lmmslog.txt 2>&1 & + sleep 120 + export PYTHONPATH=$PYTHONPATH:$(pwd) + cd ../ + cd test + python3 run_suite.py --hw npu --suite nightly-4-npu-a3 --nightly --continue-on-error --timeout-per-file 3600 --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 + + nightly-8-npu-a3: + if: ${{ (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') }} + runs-on: linux-aarch64-a3-8 + strategy: + fail-fast: false + matrix: + part: [0] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.extra-index-url "https://pypi.tuna.tsinghua.edu.cn/simple" + pip config set global.trusted-host "${CACHING_URL} pypi.tuna.tsinghua.edu.cn" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://gh-proxy.test.osinfra.cn/https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Print Log Information + run: | + bash scripts/ci/npu/npu_log_print.sh + + - name: Run test + timeout-minutes: 240 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + hf download lmms-lab/MMMU --repo-type dataset + pip install sentence_transformers + pip install protobuf==6.31.1 zss pre-commit wandb>=0.16.0 tenacity==8.3.0 loguru openpyxl latex2sympy2 zstandard transformers-stream-generator tqdm-multiprocess pycocoevalcap + pip install yt-dlp sentencepiece==0.1.99 nltk av ftfy sqlitedict==2.1.0 sacrebleu>=1.5.0 pytablewriter peft==0.2.0 black==24.1.0 isort==5.13.2 peft>=0.2.0 accelerate>=0.29.1 + pip install jsonlines httpx==0.25.0 evaluate>=0.4.0 datasets==2.16.1 numexpr xgrammar==0.1.25 numpy==1.26.4 dotenv + git clone --branch v0.3.3 --depth 1 https://github.com/EvolvingLMMs-Lab/lmms-eval.git + cd ./lmms-eval + nohup pip install . > lmmslog.txt 2>&1 & + sleep 120 + export PYTHONPATH=$PYTHONPATH:$(pwd) + cd ../ + cd test + python3 run_suite.py --hw npu --suite nightly-8-npu-a3 --nightly --continue-on-error --timeout-per-file 3600 --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 + + nightly-16-npu-a3: + if: ${{ (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') }} + runs-on: linux-aarch64-a3-16 + strategy: + fail-fast: false + matrix: + part: [0] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.extra-index-url "https://pypi.tuna.tsinghua.edu.cn/simple" + pip config set global.trusted-host "${CACHING_URL} pypi.tuna.tsinghua.edu.cn" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://gh-proxy.test.osinfra.cn/https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Print Log Information + run: | + bash scripts/ci/npu/npu_log_print.sh + + - name: Run test + timeout-minutes: 240 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + hf download lmms-lab/MMMU --repo-type dataset + pip install sentence_transformers + pip install protobuf==6.31.1 zss pre-commit wandb>=0.16.0 tenacity==8.3.0 loguru openpyxl latex2sympy2 zstandard transformers-stream-generator tqdm-multiprocess pycocoevalcap + pip install yt-dlp sentencepiece==0.1.99 nltk av ftfy sqlitedict==2.1.0 sacrebleu>=1.5.0 pytablewriter peft==0.2.0 black==24.1.0 isort==5.13.2 peft>=0.2.0 accelerate>=0.29.1 + pip install jsonlines httpx==0.25.0 evaluate>=0.4.0 datasets==2.16.1 numexpr xgrammar==0.1.25 numpy==1.26.4 dotenv + git clone --branch v0.3.3 --depth 1 https://github.com/EvolvingLMMs-Lab/lmms-eval.git + cd ./lmms-eval + nohup pip install . > lmmslog.txt 2>&1 & + sleep 120 + export PYTHONPATH=$PYTHONPATH:$(pwd) + cd ../ + cd test + python3 run_suite.py --hw npu --suite nightly-16-npu-a3 --nightly --continue-on-error --timeout-per-file 3600 --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 + + check-all-jobs: + if: github.repository == 'sgl-project/sglang' && always() + needs: + - nightly-1-npu-a3 + - nightly-2-npu-a3 + - nightly-4-npu-a3 + - nightly-8-npu-a3 + - nightly-16-npu-a3 + runs-on: ubuntu-latest + container: + image: docker.m.daocloud.io/ubuntu:22.04 + steps: + - name: Check if any job failed + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + echo "One or more nightly test jobs failed" + exit 1 + fi + if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more nightly test jobs were cancelled" + exit 1 + fi + echo "All nightly test jobs passed" diff --git a/sglang/.github/workflows/nightly-test-nvidia.yml b/sglang/.github/workflows/nightly-test-nvidia.yml new file mode 100644 index 0000000000000000000000000000000000000000..e95078cb7cc277862956751fb2068fa520a9a25e --- /dev/null +++ b/sglang/.github/workflows/nightly-test-nvidia.yml @@ -0,0 +1,637 @@ +name: Nightly Test (Nvidia) + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + inputs: + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: choice + default: 'all' + options: + - 'all' + - 'nightly-test-general-1-gpu-runner' + - 'nightly-test-general-4-gpu-h100' + - 'nightly-test-general-8-gpu-h200' + - 'nightly-test-general-8-gpu-h20' + - 'nightly-test-general-8-gpu-b200' + - 'nightly-test-text-accuracy-2-gpu-runner' + - 'nightly-test-text-perf-2-gpu-runner' + - 'nightly-test-vlm-accuracy-2-gpu-runner' + - 'nightly-test-vlm-perf-2-gpu-runner' + - 'nightly-test-multimodal-server-1-gpu' + - 'nightly-test-multimodal-server-2-gpu' + - 'nightly-test-perf-4-gpu-b200' + - 'nightly-test-perf-8-gpu-b200' + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: string + default: 'all' + +concurrency: + group: nightly-test-nvidia-${{ inputs.ref || github.ref }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +env: + SGLANG_IS_IN_CI: true + SGLANG_CUDA_COREDUMP: "1" + HF_HUB_DOWNLOAD_TIMEOUT: 300 + HF_HUB_ETAG_TIMEOUT: 300 + +jobs: + # General tests - 1 GPU + nightly-test-general-1-gpu-runner: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-general-1-gpu-runner') + runs-on: 1-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 60 + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-1-gpu --nightly --continue-on-error + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # General tests - 4 GPU H100 + nightly-test-general-4-gpu-h100: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-general-4-gpu-h100') + runs-on: 4-gpu-h100 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-4-gpu --nightly --continue-on-error + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # General tests - 8 GPU H200 + nightly-test-general-8-gpu-h200: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-general-8-gpu-h200') + runs-on: 8-gpu-h200 + strategy: + fail-fast: false + matrix: + partition: [0, 1, 2, 3] + env: + RUNNER_LABELS: 8-gpu-h200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run common 8-GPU model tests + if: always() + timeout-minutes: 300 + env: + TRACE_BASE_URL: https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/traces/${{ github.run_id }} + PERFETTO_RELAY_URL: ${{ vars.PERFETTO_RELAY_URL }} + GPU_CONFIG: "8-gpu-h200" + IS_H200: "1" + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-8-gpu-common --nightly --timeout-per-file=18000 --continue-on-error --auto-partition-id=${{ matrix.partition }} --auto-partition-size=4 + + - name: Publish traces to storage repo + if: always() + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + run: | + TRACE_ARGS="" + for dir in test/performance_profiles_*/; do + [ -d "$dir" ] && TRACE_ARGS="$TRACE_ARGS --traces-dir $dir" + done + if [ -n "$TRACE_ARGS" ]; then + python3 scripts/ci/utils/publish_traces.py $TRACE_ARGS + find test/performance_profiles_*/ -name '*.json.gz' -delete + else + echo "No trace directories found, skipping publish" + fi + + - name: Run test + timeout-minutes: 30 + env: + GPU_CONFIG: "8-gpu-h200" + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-8-gpu-h200 --nightly --continue-on-error + + - name: Collect performance metrics + if: always() + run: | + python3 scripts/ci/save_metrics.py \ + --gpu-config 8-gpu-h200 \ + --partition ${{ matrix.partition }} \ + --run-id ${{ github.run_id }} \ + --output test/metrics-8gpu-h200-partition-${{ matrix.partition }}.json \ + --search-dir test/performance_profiles_8_gpu \ + --search-dir test + + - name: Upload partition metrics + if: always() + uses: actions/upload-artifact@v4 + with: + name: metrics-8gpu-h200-partition-${{ matrix.partition }} + path: test/metrics-8gpu-h200-partition-${{ matrix.partition }}.json + retention-days: 5 + if-no-files-found: ignore + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.partition }} + + # General tests - 8 GPU H20 + nightly-test-general-8-gpu-h20: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-general-8-gpu-h20') + runs-on: 8-gpu-h20 + env: + SGLANG_CI_RDMA_ALL_DEVICES: "mlx5_1,mlx5_2,mlx5_3,mlx5_4" + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + env: + GPU_CONFIG: "8-gpu-h20" + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-8-gpu-h20 --nightly --continue-on-error + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # General tests - 8 GPU B200 + nightly-test-general-8-gpu-b200: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-general-8-gpu-b200') + runs-on: 8-gpu-b200 + strategy: + fail-fast: false + matrix: + partition: [0, 1, 2, 3] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run common 8-GPU model tests + if: always() + timeout-minutes: 300 + env: + TRACE_BASE_URL: https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/traces/${{ github.run_id }} + PERFETTO_RELAY_URL: ${{ vars.PERFETTO_RELAY_URL }} + GPU_CONFIG: "8-gpu-b200" + run: | + cd test + IS_BLACKWELL=1 python3 run_suite.py --hw cuda --suite nightly-8-gpu-common --nightly --timeout-per-file=12000 --continue-on-error --auto-partition-id=${{ matrix.partition }} --auto-partition-size=4 + + - name: Publish traces to storage repo + if: always() + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + run: | + TRACE_ARGS="" + for dir in test/performance_profiles_*/; do + [ -d "$dir" ] && TRACE_ARGS="$TRACE_ARGS --traces-dir $dir" + done + if [ -n "$TRACE_ARGS" ]; then + python3 scripts/ci/utils/publish_traces.py $TRACE_ARGS + find test/performance_profiles_*/ -name '*.json.gz' -delete + else + echo "No trace directories found, skipping publish" + fi + + - name: Collect performance metrics + if: always() + run: | + python3 scripts/ci/save_metrics.py \ + --gpu-config 8-gpu-b200 \ + --partition ${{ matrix.partition }} \ + --run-id ${{ github.run_id }} \ + --output test/metrics-8gpu-b200-partition-${{ matrix.partition }}.json \ + --search-dir test/performance_profiles_8_gpu \ + --search-dir test + + - name: Upload partition metrics + if: always() + uses: actions/upload-artifact@v4 + with: + name: metrics-8gpu-b200-partition-${{ matrix.partition }} + path: test/metrics-8gpu-b200-partition-${{ matrix.partition }}.json + retention-days: 5 + if-no-files-found: ignore + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.partition }} + + # Text model accuracy tests + nightly-test-text-accuracy-2-gpu-runner: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-text-accuracy-2-gpu-runner') + runs-on: 2-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run eval test for text models + timeout-minutes: 120 + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-eval-text-2-gpu --nightly --continue-on-error --timeout-per-file 4500 + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # Text model performance tests + nightly-test-text-perf-2-gpu-runner: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-text-perf-2-gpu-runner') + runs-on: 2-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run performance test for text models + timeout-minutes: 180 + env: + TRACE_BASE_URL: https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/traces/${{ github.run_id }} + PERFETTO_RELAY_URL: ${{ vars.PERFETTO_RELAY_URL }} + GPU_CONFIG: "2-gpu-runner" + run: | + cd test + rm -rf performance_profiles_text_models/ + python3 run_suite.py --hw cuda --suite nightly-perf-text-2-gpu --nightly --continue-on-error --timeout-per-file 3600 + + - name: Publish traces to storage repo + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + run: | + python3 scripts/ci/utils/publish_traces.py --traces-dir test/performance_profiles_text_models + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # VLM accuracy tests + nightly-test-vlm-accuracy-2-gpu-runner: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-vlm-accuracy-2-gpu-runner') + runs-on: 2-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run eval test for VLM models (fixed MMMU-100) + timeout-minutes: 240 + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-eval-vlm-2-gpu --nightly --continue-on-error --timeout-per-file 9000 + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # VLM performance tests + nightly-test-vlm-perf-2-gpu-runner: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-vlm-perf-2-gpu-runner') + runs-on: 2-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run perf test for VLM models (MMMU) + timeout-minutes: 240 + env: + TRACE_BASE_URL: https://raw.githubusercontent.com/sglang-bot/sglang-ci-data/main/traces/${{ github.run_id }} + PERFETTO_RELAY_URL: ${{ vars.PERFETTO_RELAY_URL }} + GPU_CONFIG: "2-gpu-runner" + run: | + cd test + rm -rf performance_profiles_vlms/ + python3 run_suite.py --hw cuda --suite nightly-perf-vlm-2-gpu --nightly --continue-on-error --timeout-per-file 3600 + + - name: Publish traces to storage repo + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_NIGHTLY_CI_DATA }} + GITHUB_RUN_ID: ${{ github.run_id }} + GITHUB_RUN_NUMBER: ${{ github.run_number }} + run: | + python3 scripts/ci/utils/publish_traces.py --traces-dir test/performance_profiles_vlms + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # diffusion performance tests + nightly-test-multimodal-server-1-gpu: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-multimodal-server-1-gpu') + runs-on: 1-gpu-runner + strategy: + fail-fast: false + max-parallel: 5 + matrix: + part: [0, 1] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh diffusion + pip install slack_sdk + + - name: Run diffusion server tests + env: + SGLANG_DIFFUSION_SLACK_TOKEN: ${{ secrets.SGLANG_DIFFUSION_SLACK_TOKEN }} + GITHUB_RUN_ID: ${{ github.run_id }} + GPU_CONFIG: "1-gpu-runner" + + timeout-minutes: 60 + run: | + cd python + python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 1-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 + + - name: Collect diffusion performance metrics + if: always() + run: | + python3 scripts/ci/save_diffusion_metrics.py \ + --gpu-config 1-gpu-runner \ + --run-id ${{ github.run_id }} \ + --output python/diffusion-metrics-1gpu-partition-${{ matrix.part }}.json \ + --results-json python/diffusion-results.json + + - name: Upload diffusion metrics + if: always() + uses: actions/upload-artifact@v4 + with: + name: diffusion-metrics-1gpu-partition-${{ matrix.part }} + path: python/diffusion-metrics-1gpu-partition-${{ matrix.part }}.json + retention-days: 90 + if-no-files-found: ignore + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + nightly-test-multimodal-server-2-gpu: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-multimodal-server-2-gpu') + runs-on: 2-gpu-runner + strategy: + fail-fast: false + max-parallel: 5 + matrix: + part: [0, 1] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh diffusion + pip install slack_sdk + + - name: Run diffusion server tests + env: + SGLANG_DIFFUSION_SLACK_TOKEN: ${{ secrets.SGLANG_DIFFUSION_SLACK_TOKEN }} + GITHUB_RUN_ID: ${{ github.run_id }} + GPU_CONFIG: "2-gpu-runner" + + timeout-minutes: 60 + run: | + cd python + python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 2-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 + + - name: Collect diffusion performance metrics + if: always() + run: | + python3 scripts/ci/save_diffusion_metrics.py \ + --gpu-config 2-gpu-runner \ + --run-id ${{ github.run_id }} \ + --output python/diffusion-metrics-2gpu-partition-${{ matrix.part }}.json \ + --results-json python/diffusion-results.json + + - name: Upload diffusion metrics + if: always() + uses: actions/upload-artifact@v4 + with: + name: diffusion-metrics-2gpu-partition-${{ matrix.part }} + path: python/diffusion-metrics-2gpu-partition-${{ matrix.part }}.json + retention-days: 90 + if-no-files-found: ignore + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + # B200 Performance tests - 4 GPU + nightly-test-perf-4-gpu-b200: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-perf-4-gpu-b200') + runs-on: 4-gpu-b200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 300 + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-4-gpu-b200 --nightly --continue-on-error --timeout-per-file 12000 + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # Specialized B200 tests - 8 GPU, for specific backends and configs + nightly-test-specialized-8-gpu-b200: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'nightly-test-perf-8-gpu-b200') + runs-on: 8-gpu-b200 + env: + RUNNER_LABELS: 8-gpu-b200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + run: | + IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 120 + env: + GPU_CONFIG: "8-gpu-b200" + run: | + cd test + python3 run_suite.py --hw cuda --suite nightly-8-gpu-b200 --nightly --continue-on-error --timeout-per-file 2400 + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + # Consolidate performance metrics from all jobs + consolidate-metrics: + if: github.repository == 'sgl-project/sglang' && always() + needs: + - nightly-test-general-8-gpu-h200 + - nightly-test-general-8-gpu-b200 + - nightly-test-multimodal-server-1-gpu + - nightly-test-multimodal-server-2-gpu + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Download all partition metrics + uses: actions/download-artifact@v4 + with: + pattern: "*metrics-*" + path: metrics/ + merge-multiple: true + + - name: List downloaded metrics + run: | + echo "Downloaded metrics files:" + find metrics/ -name "*.json" -type f 2>/dev/null || echo "No metrics files found" + + - name: Merge metrics + run: | + python3 scripts/ci/merge_metrics.py \ + --input-dir metrics/ \ + --output consolidated-metrics-${{ github.run_id }}.json \ + --run-id ${{ github.run_id }} \ + --commit-sha ${{ github.sha }} \ + --branch ${{ github.ref_name }} + + - name: Upload consolidated metrics + uses: actions/upload-artifact@v4 + with: + name: consolidated-metrics-${{ github.run_id }} + path: consolidated-metrics-${{ github.run_id }}.json + retention-days: 90 + if-no-files-found: warn + + # Final check job + check-all-jobs: + if: github.repository == 'sgl-project/sglang' && always() + needs: + - nightly-test-general-1-gpu-runner + - nightly-test-general-4-gpu-h100 + - nightly-test-general-8-gpu-h200 + - nightly-test-general-8-gpu-h20 + - nightly-test-general-8-gpu-b200 + - nightly-test-text-accuracy-2-gpu-runner + - nightly-test-text-perf-2-gpu-runner + - nightly-test-vlm-accuracy-2-gpu-runner + - nightly-test-vlm-perf-2-gpu-runner + - nightly-test-multimodal-server-1-gpu + - nightly-test-multimodal-server-2-gpu + - nightly-test-perf-4-gpu-b200 + - nightly-test-specialized-8-gpu-b200 + - consolidate-metrics + runs-on: ubuntu-latest + steps: + - name: Check if any job failed + run: | + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + echo "One or more nightly test jobs failed" + exit 1 + fi + if [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + echo "One or more nightly test jobs were cancelled" + exit 1 + fi + echo "All nightly test jobs passed" diff --git a/sglang/.github/workflows/open-pr-copy-to-oss.yml b/sglang/.github/workflows/open-pr-copy-to-oss.yml new file mode 100644 index 0000000000000000000000000000000000000000..a29c6bc2aa2a965018d9b8367a75aecce32481b3 --- /dev/null +++ b/sglang/.github/workflows/open-pr-copy-to-oss.yml @@ -0,0 +1,31 @@ +name: Open A PR to Copy Diff To OSS + +on: + workflow_dispatch: + inputs: + commit_sha: + description: 'The commit SHA to copy. Defaults to LAST to copy the latest commit.' + required: false + default: 'LAST' + +permissions: + contents: write + +jobs: + copy: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install GitHub CLI (if not present) + run: | + bash scripts/code_sync/install_github_cli.sh + + - name: Copy to OSS code + env: + GH_TOKEN: ${{ secrets.GH_PAT_FOR_OPEN_PR_TO_OSS }} + run: | + python3 scripts/code_sync/copy_to_oss.py --commit ${{ github.event.inputs.commit_sha }} diff --git a/sglang/.github/workflows/patch-docker-dev.yml b/sglang/.github/workflows/patch-docker-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..30b560783ff5fe59d2ee126d6aebf20ab60809ee --- /dev/null +++ b/sglang/.github/workflows/patch-docker-dev.yml @@ -0,0 +1,115 @@ +name: Patch Docker Image + +on: + workflow_dispatch: + inputs: + pr_numbers: + description: "Comma-separated PR numbers to apply (e.g. 18962,19010)" + required: false + default: "" + image_tag: + description: "Base image tag to patch (e.g. dev-x86, dev-x86-cu13)" + required: true + +concurrency: + group: patch-docker-${{ inputs.image_tag }} + cancel-in-progress: true + +jobs: + patch: + if: github.repository == 'sgl-project/sglang' + runs-on: x64-docker-build-node + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Pull base image and extract commit + run: | + IMAGE="lmsysorg/sglang:${{ inputs.image_tag }}" + docker pull "${IMAGE}" + if BASE_SHA=$(docker run --rm "${IMAGE}" git -C /sgl-workspace/sglang rev-parse HEAD 2>/dev/null); then + echo "Image built from commit: ${BASE_SHA}" + else + BASE_SHA="" + echo "::warning::Image has no .git directory — cannot extract base commit" + fi + echo "BASE_SHA=${BASE_SHA}" >> "$GITHUB_ENV" + + - name: Generate patches + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + git fetch origin main + mkdir -p /tmp/patch-ctx + + if [ -n "${{ inputs.pr_numbers }}" ]; then + IFS=',' read -ra PRS <<< "${{ inputs.pr_numbers }}" + for pr in "${PRS[@]}"; do + pr=$(echo "${pr}" | xargs) + echo "Fetching PR #${pr}" + git fetch origin "pull/${pr}/head:pr-${pr}" + MERGE_BASE=$(git merge-base origin/main "pr-${pr}") + echo " PR #${pr}: merge-base=${MERGE_BASE}" + git diff "${MERGE_BASE}..pr-${pr}" > "/tmp/patch-ctx/${pr}.patch" + echo " PR #${pr}: $(wc -l < /tmp/patch-ctx/${pr}.patch) lines" + done + elif [ -n "${BASE_SHA}" ]; then + echo "Generating diff: image ${BASE_SHA} → latest main" + git fetch origin "${BASE_SHA}" + git diff "${BASE_SHA}..origin/main" > /tmp/patch-ctx/main.patch + echo " main: $(wc -l < /tmp/patch-ctx/main.patch) lines" + else + echo "::error::No PR numbers specified and image has no .git — cannot generate diff against main" + exit 1 + fi + + TOTAL=$(cat /tmp/patch-ctx/*.patch | wc -l) + if [ "${TOTAL}" -eq 0 ]; then + echo "::warning::All patches are empty — image is already up to date" + echo "SKIP_BUILD=true" >> "$GITHUB_ENV" + fi + + - name: Build patched image + if: env.SKIP_BUILD != 'true' + run: | + IMAGE="lmsysorg/sglang:${{ inputs.image_tag }}" + + cat <<'DOCKERFILE' > /tmp/patch-ctx/Dockerfile + ARG BASE_IMAGE + FROM ${BASE_IMAGE} + COPY *.patch /tmp/patches/ + RUN cd /sgl-workspace/sglang \ + && for p in /tmp/patches/*.patch; do \ + if [ ! -s "${p}" ]; then \ + echo "Skipping ${p} (empty)"; \ + else \ + echo "Applying ${p}..." \ + && patch -p1 --fuzz=2 --no-backup-if-mismatch -f < "${p}" \ + || { echo "ERROR: Failed to apply ${p}"; exit 1; }; \ + fi; \ + done \ + && rm -rf /tmp/patches + DOCKERFILE + + docker build \ + --no-cache \ + --build-arg BASE_IMAGE="${IMAGE}" \ + -t "${IMAGE}" \ + /tmp/patch-ctx/ + + - name: Push patched image + if: env.SKIP_BUILD != 'true' + run: | + IMAGE="lmsysorg/sglang:${{ inputs.image_tag }}" + docker push "${IMAGE}" + + echo "### Patched \`${IMAGE}\`" >> "$GITHUB_STEP_SUMMARY" + echo "- **Base commit:** \`${BASE_SHA:-unknown (no .git)}\`" >> "$GITHUB_STEP_SUMMARY" + echo "- **Source:** ${{ inputs.pr_numbers && format('PRs: {0}', inputs.pr_numbers) || 'latest main' }}" >> "$GITHUB_STEP_SUMMARY" diff --git a/sglang/.github/workflows/pr-benchmark-rust.yml b/sglang/.github/workflows/pr-benchmark-rust.yml new file mode 100644 index 0000000000000000000000000000000000000000..49dd73895a9a8bf497fe42f25e7f9a7f6132c650 --- /dev/null +++ b/sglang/.github/workflows/pr-benchmark-rust.yml @@ -0,0 +1,198 @@ +name: PR Benchmark (SMG Components) + +on: + push: + branches: [ main ] + paths: + - "sgl-model-gateway/**" + pull_request: + branches: [ main ] + paths: + - "sgl-model-gateway/**" + workflow_dispatch: + +concurrency: + group: pr-benchmark-rust-${{ github.ref }} + cancel-in-progress: true + +env: + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "true" + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + benchmark-compile-check: + name: Benchmark Compilation Check + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_gateway_dependencies.sh + + - name: Configure sccache + uses: mozilla-actions/sccache-action@v0.0.9 + with: + version: "v0.12.0" + disable_annotations: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: sgl-model-gateway + shared-key: "rust-cache" + save-if: true + cache-all-crates: true + cache-on-failure: true + + - name: Check benchmarks compile + run: | + source "$HOME/.cargo/env" + cd sgl-model-gateway/ + cargo check --benches + + - name: Show sccache stats + if: always() + run: sccache --show-stats + + benchmark: + name: Benchmark - ${{ matrix.name }} + if: | + github.repository == 'sgl-project/sglang' && + (github.event_name == 'push' || + github.event_name == 'workflow_dispatch' || + (contains(github.event.pull_request.labels.*.name, 'router-benchmark') && + contains(github.event.pull_request.labels.*.name, 'run-ci'))) + strategy: + fail-fast: false + matrix: + include: + - name: Request Processing + bench_name: request_processing + bench_args: "benchmark_summary --exact" + runner: ubuntu-latest + sccache_version: "v0.12.0" + artifact_name: request-processing-results + artifact_path: criterion/benchmark_summary/ + - name: Manual Policy + bench_name: manual_policy_benchmark + bench_args: "" + runner: ubuntu-latest + sccache_version: "v0.12.0" + artifact_name: manual-policy-results + artifact_path: criterion/manual_policy*/ + runs-on: ${{ matrix.runner }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 100 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_gateway_dependencies.sh + + - name: Configure sccache + uses: mozilla-actions/sccache-action@v0.0.9 + with: + version: ${{ matrix.sccache_version }} + disable_annotations: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: sgl-model-gateway + shared-key: "rust-cache" + cache-all-crates: true + cache-on-failure: true + save-if: true + + - name: Run benchmark + timeout-minutes: 30 + run: | + source "$HOME/.cargo/env" + cd sgl-model-gateway/ + if command -v sccache &> /dev/null; then + echo "Testing sccache availability..." + export RUSTC_WRAPPER=sccache + export SCCACHE_GHA_ENABLED="true" + if sccache --start-server 2>/dev/null && sccache --show-stats 2>/dev/null; then + echo "sccache is working, using it for compilation" + else + echo "sccache failed to start, falling back to regular cargo" + unset RUSTC_WRAPPER + unset SCCACHE_GHA_ENABLED + fi + else + echo "sccache not available, using regular cargo" + fi + cargo bench --bench ${{ matrix.bench_name }} -- ${{ matrix.bench_args }} 2>&1 | tee benchmark_output.txt + + - name: Upload benchmark results + if: always() + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact_name }}-${{ github.sha }} + path: | + sgl-model-gateway/target/${{ matrix.artifact_path }} + sgl-model-gateway/benchmark_output.txt + retention-days: 30 + + - name: Show sccache stats + if: always() + run: sccache --show-stats + + benchmark-summary: + name: Benchmark Summary + needs: [benchmark] + if: always() && (github.repository == 'sgl-project/sglang' || github.event_name == 'pull_request') + runs-on: ubuntu-latest + steps: + - name: Download all benchmark results + uses: actions/download-artifact@v4 + with: + pattern: '*-results-${{ github.sha }}' + path: benchmark-results + + - name: Generate summary + run: | + generate_section() { + local title="$1" dir_name="$2" lines="${3:-100}" + local dir="benchmark-results/${dir_name}-${{ github.sha }}" + echo "### $title" >> summary.md + if [ -d "$dir" ]; then + echo "✅ **Completed**" >> summary.md + if [ -f "$dir/benchmark_output.txt" ]; then + echo -e "\n
\nView Results\n\n\`\`\`" >> summary.md + tail -"$lines" "$dir/benchmark_output.txt" >> summary.md + echo -e "\`\`\`\n
" >> summary.md + fi + else + echo "❌ Failed or skipped" >> summary.md + fi + echo "" >> summary.md + } + + echo "## 🚀 Benchmark Results Summary" > summary.md + echo "" >> summary.md + + generate_section "Request Processing" "request-processing-results" 60 + generate_section "Manual Policy (Sticky Sessions)" "manual-policy-results" 100 + + echo -e "---\n_Generated at $(date -u '+%Y-%m-%d %H:%M:%S UTC')_" >> summary.md + + cat summary.md + cat summary.md >> $GITHUB_STEP_SUMMARY + + - name: Upload summary + uses: actions/upload-artifact@v4 + with: + name: benchmark-summary-${{ github.sha }} + path: summary.md + retention-days: 30 diff --git a/sglang/.github/workflows/pr-gate.yml b/sglang/.github/workflows/pr-gate.yml new file mode 100644 index 0000000000000000000000000000000000000000..9e65c856647a9354e4b56255b31b11d09240fc20 --- /dev/null +++ b/sglang/.github/workflows/pr-gate.yml @@ -0,0 +1,254 @@ +on: + workflow_call: + inputs: + require-run-ci: + description: "Whether the PR must have the run-ci label" + type: boolean + default: true + cool-down-minutes: + description: "Cooldown period in minutes for low-permission users; 0 disables rate limiting" + type: number + default: 120 + +jobs: + pr-gate: + # 1. for commits on main: no gating needed + # 2. for workflow_dispatch: this can only be triggered by users with write access + runs-on: ubuntu-latest + steps: + - name: Fetch latest PR info + if: github.event_name == 'pull_request' + id: pr + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + core.setOutput("labels", JSON.stringify(pr.data.labels.map(l => l.name))); + core.setOutput("draft", pr.data.draft); + core.setOutput("user", pr.data.user.login); + + - name: Log PR info + if: github.event_name == 'pull_request' + run: | + echo "===== PR Info =====" + echo "PR Event: ${{ github.event_name }}" + echo "PR Labels: ${{ steps.pr.outputs.labels }}" + echo "PR Draft: ${{ steps.pr.outputs.draft }}" + echo "PR User: ${{ steps.pr.outputs.user }}" + echo "Require run-ci: ${{ inputs.require-run-ci }}" + echo "Cool down minutes: ${{ inputs.cool-down-minutes }}" + echo "===================" + + - name: Block draft PR + if: github.event_name == 'pull_request' && fromJson(steps.pr.outputs.draft) + run: | + echo "PR is draft. Blocking CI." + exit 1 + + - name: Require run-ci label (optional) + if: github.event_name == 'pull_request' && inputs.require-run-ci == true + run: | + labels='${{ steps.pr.outputs.labels }}' + if [[ "${{ contains(fromJson(steps.pr.outputs.labels), 'run-ci') }}" == "false" ]]; then + echo "Missing required label 'run-ci'. See https://docs.sglang.io/developer_guide/contribution_guide.html#how-to-trigger-ci-tests for more details." + exit 1 + fi + + - name: Enforce rate limit for low-permission actors (optional) + if: github.event_name == 'pull_request' && inputs.cool-down-minutes > 0 + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const DEFAULT_MINUTES = Number("${{ inputs.cool-down-minutes }}"); + const owner = context.repo.owner; + const repo = context.repo.repo; + const eventName = context.eventName; + const curRun = await github.rest.actions.getWorkflowRun({ + owner, repo, run_id: context.runId + }); + let triggeringActor = curRun.data.triggering_actor?.login || context.actor; + if (triggeringActor === "github-actions[bot]") { + triggeringActor = `${{ steps.pr.outputs.user }}`; + core.info( + `triggering_actor is github-actions[bot]; substituting PR author '${triggeringActor}'.` + ); + } + + async function hasHighPermission(username) { + try { + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ owner, repo, username }); + const perm = data.permission || 'none'; + return perm === 'write' || perm === 'maintain' || perm === 'admin'; + } catch (e) { + if (e.status === 404 || e.status === 403) return false; + throw e; + } + } + + if (await hasHighPermission(triggeringActor)) { + core.info(`Triggering user '${triggeringActor}' has high permission. No rate limit applied.`); + return; + } + + let effectiveCooldownMinutes = DEFAULT_MINUTES; + let perUserCooldownMinutes = null; + + try { + const contentResp = await github.rest.repos.getContent({ + owner, + repo, + path: ".github/CI_PERMISSIONS.json", + ref: "main", + }); + + if (!Array.isArray(contentResp.data) && contentResp.data && "content" in contentResp.data) { + const raw = Buffer.from( + contentResp.data.content, + contentResp.data.encoding || "base64" + ).toString(); + const ciPermissions = JSON.parse(raw); + + const userPerm = ciPermissions[triggeringActor]; + if (userPerm && typeof userPerm.cooldown_interval_minutes === "number") { + perUserCooldownMinutes = userPerm.cooldown_interval_minutes; + core.info( + `Per-user cooldown for '${triggeringActor}' from CI_PERMISSIONS.json: ${perUserCooldownMinutes} minutes.` + ); + } else { + core.info(`No per-user cooldown found for '${triggeringActor}' in CI_PERMISSIONS.json.`); + } + } else { + core.info("CI_PERMISSIONS.json content response is not a file; skipping per-user cooldown."); + } + } catch (e) { + core.info(`CI_PERMISSIONS.json not found or unreadable: ${e.message}. Using default rate limit only.`); + } + + if (perUserCooldownMinutes !== null) { + effectiveCooldownMinutes = Math.min(effectiveCooldownMinutes, perUserCooldownMinutes); + } + + if (effectiveCooldownMinutes <= 0) { + core.info( + `Effective cooldown for '${triggeringActor}' is 0 minutes; no rate limit enforced for this user.` + ); + return; + } + + const cutoff = new Date(Date.now() - effectiveCooldownMinutes * 60 * 1000); + core.info( + `Checking for workflow runs since ${cutoff.toISOString()} (last ${effectiveCooldownMinutes} minutes) for event '${eventName}'.` + ); + + const { data } = await github.rest.actions.listWorkflowRuns({ + owner, + repo, + workflow_id: 'pr-test.yml', + event: eventName, + per_page: 100, + }); + + const runs = data.workflow_runs || []; + + // Rate Limiting Logic: + // We only count workflow runs that actually consumed CI resources (i.e., passed the gate). + // A run "passes the gate" if any jobs beyond the gate jobs (check-changes, pr-gate, call-gate) + // actually executed (not skipped/cancelled). This prevents scenarios where: + // - User has PR A with missing 'run-ci' label (fails at gate) + // - User opens PR B with 'run-ci' label + // - PR B should be able to run even though PR A triggered a run recently + + // Helper function to check if a run passed the gate (i.e., actually consumed CI resources) + async function didRunPassGate(run) { + try { + // Note: Fetching up to 100 jobs (API maximum). If a workflow has >100 jobs, + // we may miss some, but this is unlikely in practice. + const { data: jobsData } = await github.rest.actions.listJobsForWorkflowRun({ + owner, repo, run_id: run.id, per_page: 100 + }); + const jobs = jobsData.jobs || []; + + // If no jobs exist yet, the run hasn't started consuming resources + if (jobs.length === 0) { + core.info(`Run ${run.id} has no jobs yet; not counting against rate limit.`); + return false; + } + + // Gate jobs that don't consume significant CI resources + const gateJobs = ['check-changes', 'pr-gate', 'call-gate', 'pr-test-finish']; + const jobsBeyondGate = jobs.filter(j => !gateJobs.some(g => j.name === g || j.name.startsWith(g + ' '))); + + // A job "ran" if it reached a terminal conclusion state that indicates actual execution + const ranStates = ['success', 'failure', 'timed_out', 'action_required']; + const hasJobsThatRan = jobsBeyondGate.some(j => j.conclusion && ranStates.includes(j.conclusion)); + return hasJobsThatRan; + } catch (e) { + core.warning(`Could not check jobs for run ${run.id}: ${e.message}`); + + // If it's a rate limit error, count it conservatively to prevent abuse + if (e.status === 429) { + core.warning(`Hit rate limit checking run ${run.id}; counting it to be safe.`); + return true; + } + + // For cancelled/skipped runs, they likely didn't consume resources + if (run.conclusion === 'cancelled' || run.conclusion === 'skipped') { + return false; + } + + // Default to counting it to prevent abuse + return true; + } + } + + // Limit the number of runs we'll check in detail to avoid API rate limits + const MAX_RUNS_TO_CHECK = 5; + let runsChecked = 0; + let runsSkippedAtGate = 0; + let recentFound = null; + + for (const run of runs) { + if (String(run.id) === String(context.runId)) continue; + if (new Date(run.created_at) < cutoff) continue; + const isUserRun = (run.actor?.login === triggeringActor) || (run.triggering_actor?.login === triggeringActor); + if (!isUserRun) continue; + + runsChecked++; + core.info(`Checking run ${run.id} (created: ${run.created_at}, conclusion: ${run.conclusion})`); + + // Safety limit: if we've checked too many runs, assume the next one passed to be conservative + if (runsChecked > MAX_RUNS_TO_CHECK) { + core.warning(`Checked ${MAX_RUNS_TO_CHECK} runs; assuming this one passed gate to avoid API limits.`); + recentFound = run; + break; + } + + // Only count runs that actually passed the gate and consumed CI resources + if (await didRunPassGate(run)) { + recentFound = run; + core.info(`Found recent run ${run.id} that passed gate.`); + break; + } else { + runsSkippedAtGate++; + core.info(`Run ${run.id} failed at gate; not counting against rate limit.`); + } + } + + core.info(`Rate limit check summary: checked ${runsChecked} runs, ${runsSkippedAtGate} failed at gate.`); + + if (recentFound) { + core.setFailed( + `User '${triggeringActor}' already triggered '${context.workflow}' via '${eventName}' at ${recentFound.created_at}. ` + + `Please wait ${effectiveCooldownMinutes} minutes before triggering again.` + ); + } else { + core.info( + `No recent runs detected for '${triggeringActor}' within the last ${effectiveCooldownMinutes} minutes; proceeding.` + ); + } diff --git a/sglang/.github/workflows/pr-test-amd-rocm720.yml b/sglang/.github/workflows/pr-test-amd-rocm720.yml new file mode 100644 index 0000000000000000000000000000000000000000..4489ac74a82c34356ed1b34031affed1eb228ada --- /dev/null +++ b/sglang/.github/workflows/pr-test-amd-rocm720.yml @@ -0,0 +1,1026 @@ +name: PR Test ROCm 7.2 (AMD) +# Dynamic run-name for /rerun-stage commands to enable URL lookup +# Format: "[stage-name] sha" for fork PRs, "[stage-name]" for non-fork, default for normal runs +run-name: ${{ (inputs.target_stage || inputs.target_stage_select) && (inputs.pr_head_sha && format('[{0}] {1}', inputs.target_stage || inputs.target_stage_select, inputs.pr_head_sha) || format('[{0}]', inputs.target_stage || inputs.target_stage_select)) || '' }} + +on: + # run rocm 720 pr tests once a day at 2am UTC to avoid overwhelming the CI system + schedule: + - cron: '0 2 * * *' + # push: + # branches: [ main ] + # paths: + # - "python/**" + # - "scripts/ci/**" + # - "test/**" + # - "sgl-kernel/**" + # - ".github/workflows/pr-test-amd-rocm720.yml" + # - "docker/rocm.Dockerfile" + # pull_request: + # branches: [ main ] + # paths: + # - "python/**" + # - "scripts/ci/**" + # - "test/**" + # - "sgl-kernel/**" + # - ".github/workflows/pr-test-amd-rocm720.yml" + # - "docker/rocm.Dockerfile" + workflow_dispatch: + inputs: + target_stage_select: + description: "Select a stage to run from dropdown (leave empty for auto-detect)" + required: false + type: choice + default: '' + options: + - '' + - sgl-kernel-unit-test-amd + - sgl-kernel-unit-test-2-gpu-amd + - stage-a-test-1-amd + - jit-kernel-unit-test-amd + - stage-b-test-small-1-gpu-amd + - stage-b-test-small-1-gpu-amd-nondeterministic + - stage-b-test-small-1-gpu-amd-mi35x + - stage-b-test-large-1-gpu-amd + - stage-b-test-large-2-gpu-amd + - multimodal-gen-test-1-gpu-amd + - multimodal-gen-test-2-gpu-amd + - stage-c-test-large-8-gpu-amd + - stage-c-test-large-8-gpu-amd-mi35x + - stage-b-test-large-8-gpu-disaggregation-amd + target_stage: + description: "Or type comma-separated stage names (overrides dropdown if non-empty)" + required: false + type: string + default: "" + pr_head_sha: + description: "PR head SHA to checkout (for /rerun-stage on fork PRs)" + required: false + type: string + default: "" + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: true + +env: + AITER_COMMIT_OVERRIDE: ${{ inputs.aiter_ref }} + +concurrency: + # When called via workflow_call with run_all_tests=true, use a unique group per run to + # avoid collisions with direct schedule/workflow_dispatch triggers. We use run_all_tests + # (not github.event_name) to detect this, because github.event_name inherits from the caller. + group: pr-test-amd-rocm720-${{ inputs.run_all_tests && format('full-{0}', github.run_id) || inputs.pr_head_sha || inputs.ref || github.ref }} + cancel-in-progress: ${{ !inputs.run_all_tests && github.event_name != 'workflow_call' }} + +jobs: + call-gate: + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + check-changes: + needs: [call-gate] + runs-on: ubuntu-latest + outputs: + main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} + sgl_kernel: ${{ steps.filter.outputs.sgl_kernel || steps.run-mode.outputs.run_all_tests }} + jit_kernel: ${{ steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} + multimodal_gen: ${{ steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + if: steps.run-mode.outputs.run_all_tests != 'true' + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject_rocm.toml" + - "python/pyproject_other.toml" + - "scripts/ci/amd/*" + - "scripts/ci/utils/*" + - "test/**" + - ".github/workflows/pr-test-amd-rocm720.yml" + sgl_kernel: + - "sgl-kernel/**" + - ".github/workflows/pr-test-amd-rocm720.yml" + jit_kernel: + - "python/sglang/jit_kernel/**" + - ".github/workflows/pr-test-amd-rocm720.yml" + multimodal_gen: + - "python/sglang/multimodal_gen/**" + - "python/sglang/cli/**" + - "python/sglang/jit_kernel/diffusion/**" + - "python/pyproject_rocm.toml" + - "python/pyproject_other.toml" + + # =============================================== sgl-kernel ==================================================== + sgl-kernel-unit-test-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',sgl-kernel-unit-test-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.sgl_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 14 + run: | + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_align.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_topk_softmax.py + docker exec -w /sglang-checkout/sgl-kernel/tests/speculative ci_sglang python3 -m pytest test_eagle_utils.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_apply_token_bitmask_inplace.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_activation.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_topk.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_kvcacheio.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_topk_sigmoid.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_torch_defaults_reset.py + + sgl-kernel-unit-test-2-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',sgl-kernel-unit-test-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.sgl_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-2gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 20 + run: | + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_amd_deterministic_custom_allreduce.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_amd_nccl_allreduce_determinism.py + + # =============================================== primary ==================================================== + + stage-a-test-1-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-a-test-1-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 10 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-a-test-1-amd ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + jit-kernel-unit-test-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',jit-kernel-unit-test-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.jit_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run JIT kernel unit tests + timeout-minutes: 10 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout" python3 -m pytest -q python/sglang/jit_kernel/tests/test_store_cache.py + + stage-b-test-small-1-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 14 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-small-1-gpu-amd-nondeterministic: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd-nondeterministic,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd-nondeterministic --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-small-1-gpu-amd-mi35x: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd-mi35x,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd-mi35x ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-large-1-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-1-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-large-2-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-2gpu-sglang] + part: [0, 1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-2-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + multimodal-gen-test-1-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',multimodal-gen-test-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + max-parallel: 1 # Run one at a time to avoid eviction from resource exhaustion during AITER kernel JIT + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1] # 2 partitions: 11 tests ÷ 2 = ~5-6 tests each + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh diffusion + docker exec ci_sglang pip install amdsmi + + - name: Setup kernel caches + run: | + # Use the persistent /sgl-data directory (mounted from /home/runner/sgl-data) + # This directory persists across container restarts on the self-hosted runner + docker exec ci_sglang mkdir -p /sgl-data/aiter-kernels /sgl-data/miopen-cache /sgl-data/hf-cache/hub + + # Clear pre-built AITER kernels from Docker image to avoid segfaults + # The image may have stale/incompatible kernels at /sgl-workspace/aiter/aiter/jit/ + echo "Clearing pre-built AITER kernels from Docker image..." + docker exec ci_sglang rm -rf /sgl-workspace/aiter/aiter/jit/*.so 2>/dev/null || true + docker exec ci_sglang rm -rf /sgl-data/aiter-kernels/*.so 2>/dev/null || true + echo "AITER kernels cleared - will be rebuilt on first use" + + # Create persistent cache marker if /sgl-data is a real mount (not ephemeral) + # This tells the test cleanup code to NOT delete downloaded models + if docker exec ci_sglang test -d /sgl-data && docker exec ci_sglang mountpoint -q /sgl-data 2>/dev/null; then + docker exec ci_sglang touch /sgl-data/hf-cache/.persistent_cache + echo "Created .persistent_cache marker - HF cache will persist" + else + echo "WARNING: /sgl-data is not a mount point - models will be cleaned up after each test" + fi + + # Check MIOpen cache (VAE convolution kernels) + miopen_files=$(docker exec ci_sglang find /sgl-data/miopen-cache -name "*.udb" 2>/dev/null | wc -l || echo "0") + echo "Found ${miopen_files} MIOpen cache files" + + - name: Diagnose HF cache and system resources + run: | + echo "=== System Memory Status ===" + free -h + echo "" + echo "=== Disk Space ===" + df -h /home/runner/sgl-data 2>/dev/null || df -h + echo "" + echo "=== HF Cache Directory Structure ===" + docker exec ci_sglang ls -la /sgl-data/hf-cache/ 2>/dev/null || echo "HF cache dir not found" + docker exec ci_sglang ls -la /sgl-data/hf-cache/hub/ 2>/dev/null || echo "HF hub cache not found" + echo "" + echo "=== Checking for cached diffusion models (1-GPU tests) ===" + # Models used in 1-GPU tests: Wan2.1-T2V-1.3B, HunyuanVideo, Qwen-Image, FLUX.1, FLUX.2 + for model in "Wan-AI--Wan2.1-T2V-1.3B-Diffusers" "tencent--HunyuanVideo" "Qwen--Qwen-Image" "black-forest-labs--FLUX.1-dev" "black-forest-labs--FLUX.2-dev"; do + cache_path="/sgl-data/hf-cache/hub/models--${model}" + if docker exec ci_sglang test -d "$cache_path"; then + size=$(docker exec ci_sglang du -sh "$cache_path" 2>/dev/null | cut -f1) + echo "✓ CACHED: $model ($size)" + else + echo "✗ NOT CACHED: $model" + fi + done + echo "" + echo "=== GPU Memory Status ===" + docker exec ci_sglang rocm-smi --showmeminfo vram 2>/dev/null || echo "rocm-smi not available" + + - name: Run diffusion server tests (1-GPU) + timeout-minutes: 60 + run: | + # AMD CI: All 1-GPU tests except FLUX.2 (FLUX.1 covers same code path) + # Tests: T2V, T2I, I2V, LoRA + # + # HF download env vars: + # - HF_HUB_ENABLE_HF_TRANSFER=1: Use faster hf_transfer for downloads (if available) + # - HF_HUB_DISABLE_SYMLINKS_WARNING=1: Suppress symlink warnings + docker exec \ + -e SGLANG_E2E_TOLERANCE=0.3 \ + -e SGLANG_STAGE_TIME_TOLERANCE=0.2 \ + -e SGLANG_NON_DENOISE_STAGE_TIME_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_STEP_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_AGG_TOLERANCE=0.3 \ + -e SGLANG_TEST_NUM_INFERENCE_STEPS=5 \ + -e AITER_JIT_DIR=/sgl-data/aiter-kernels \ + -e MIOPEN_USER_DB_PATH=/sgl-data/miopen-cache \ + -e HF_HUB_ENABLE_HF_TRANSFER=1 \ + -e HF_HUB_DISABLE_SYMLINKS_WARNING=1 \ + -w /sglang-checkout/python \ + ci_sglang python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 1-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + -k "not flux_2" + + # Post-test diagnostics + echo "=== Post-test System Memory Status ===" + free -h + + multimodal-gen-test-2-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',multimodal-gen-test-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + max-parallel: 1 # Run one at a time to avoid eviction from resource exhaustion during AITER kernel JIT + matrix: + runner: [linux-mi325-2gpu-sglang] + part: [0, 1] # 2 partitions: 9 tests ÷ 2 = ~4-5 tests each + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh diffusion + docker exec ci_sglang pip install amdsmi + + - name: Setup kernel caches + run: | + # Use the persistent /sgl-data directory (mounted from /home/runner/sgl-data) + docker exec ci_sglang mkdir -p /sgl-data/aiter-kernels /sgl-data/miopen-cache /sgl-data/hf-cache/hub + + # Clear pre-built AITER kernels from Docker image to avoid segfaults + # The image may have stale/incompatible kernels at /sgl-workspace/aiter/aiter/jit/ + echo "Clearing pre-built AITER kernels from Docker image..." + docker exec ci_sglang rm -rf /sgl-workspace/aiter/aiter/jit/*.so 2>/dev/null || true + docker exec ci_sglang rm -rf /sgl-data/aiter-kernels/*.so 2>/dev/null || true + echo "AITER kernels cleared - will be rebuilt on first use" + + # Create persistent cache marker if /sgl-data is a real mount (not ephemeral) + # This tells the test cleanup code to NOT delete downloaded models + if docker exec ci_sglang test -d /sgl-data && docker exec ci_sglang mountpoint -q /sgl-data 2>/dev/null; then + docker exec ci_sglang touch /sgl-data/hf-cache/.persistent_cache + echo "Created .persistent_cache marker - HF cache will persist" + else + echo "WARNING: /sgl-data is not a mount point - models will be cleaned up after each test" + fi + + # Check MIOpen cache (VAE convolution kernels) + miopen_files=$(docker exec ci_sglang find /sgl-data/miopen-cache -name "*.udb" 2>/dev/null | wc -l || echo "0") + echo "Found ${miopen_files} MIOpen cache files" + + - name: Diagnose HF cache and system resources + run: | + echo "=== System Memory Status ===" + free -h + echo "" + echo "=== Disk Space ===" + df -h /home/runner/sgl-data 2>/dev/null || df -h + echo "" + echo "=== HF Cache Directory Structure ===" + docker exec ci_sglang ls -la /sgl-data/hf-cache/ 2>/dev/null || echo "HF cache dir not found" + docker exec ci_sglang ls -la /sgl-data/hf-cache/hub/ 2>/dev/null || echo "HF hub cache not found" + echo "" + echo "=== Checking for cached diffusion models (2-GPU tests) ===" + # Models used in 2-GPU tests: Wan2.2-T2V-A14B, Wan2.1-T2V-14B, Qwen-Image, FLUX.1 + for model in "Wan-AI--Wan2.2-T2V-A14B-Diffusers" "Wan-AI--Wan2.1-T2V-14B-Diffusers" "Qwen--Qwen-Image" "black-forest-labs--FLUX.1-dev"; do + cache_path="/sgl-data/hf-cache/hub/models--${model}" + if docker exec ci_sglang test -d "$cache_path"; then + size=$(docker exec ci_sglang du -sh "$cache_path" 2>/dev/null | cut -f1) + echo "✓ CACHED: $model ($size)" + else + echo "✗ NOT CACHED: $model" + fi + done + echo "" + echo "=== GPU Memory Status ===" + docker exec ci_sglang rocm-smi --showmeminfo vram 2>/dev/null || echo "rocm-smi not available" + + - name: Run diffusion server tests (2-GPU) + timeout-minutes: 80 + run: | + # AMD CI: All 2-GPU tests including LoRA + # Tests: T2V, T2I, I2V, LoRA + # + # HF download env vars: + # - HF_HUB_ENABLE_HF_TRANSFER=1: Use faster hf_transfer for downloads (if available) + # - HF_HUB_DISABLE_SYMLINKS_WARNING=1: Suppress symlink warnings + docker exec \ + -e SGLANG_E2E_TOLERANCE=0.3 \ + -e SGLANG_STAGE_TIME_TOLERANCE=0.2 \ + -e SGLANG_NON_DENOISE_STAGE_TIME_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_STEP_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_AGG_TOLERANCE=0.3 \ + -e SGLANG_TEST_NUM_INFERENCE_STEPS=5 \ + -e AITER_JIT_DIR=/sgl-data/aiter-kernels \ + -e MIOPEN_USER_DB_PATH=/sgl-data/miopen-cache \ + -e HF_HUB_ENABLE_HF_TRANSFER=1 \ + -e HF_HUB_DISABLE_SYMLINKS_WARNING=1 \ + -w /sglang-checkout/python \ + ci_sglang python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 2-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 + + # Post-test diagnostics + echo "=== Post-test System Memory Status ===" + free -h + + + stage-c-test-large-8-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-c-test-large-8-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + env: + RUNNER_LABELS: linux-mi325-8gpu-sglang + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-8gpu-sglang] + part: [0, 1, 2] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Test RCCL multi-GPU communication + timeout-minutes: 5 + run: | + echo "Testing RCCL multi-GPU communication with debug info..." + docker exec ci_sglang bash -c "cd /sglang-checkout && NCCL_DEBUG=INFO RCCL_DEBUG=INFO torchrun --nproc_per_node=8 scripts/ci/amd/test_rccl_multi_gpu.py" + + - name: Run test + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-c-test-large-8-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 3 --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-c-test-large-8-gpu-amd-mi35x: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-c-test-large-8-gpu-amd-mi35x,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-8] + part: [0] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + - name: Run test + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-c-test-large-8-gpu-amd-mi35x --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + # =============================================== Disaggregation ==================================================== + stage-b-test-large-8-gpu-35x-disaggregation-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-8-gpu-disaggregation-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-8.fabric] + + runs-on: ${{matrix.runner}} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Check Host RDMA Environment + id: rdma_detect + run: | + set +e + echo "=== Checking Host RDMA Environment ===" + + echo "" + echo "=== 1. Ionic driver library check ===" + ls -l /usr/lib/x86_64-linux-gnu/libibverbs/libionic* 2>/dev/null || echo "libionic not found in standard path" + + echo "" + echo "=== 2. Infiniband devices ===" + ls -la /dev/infiniband/ 2>/dev/null || echo "/dev/infiniband not found" + ls -la /sys/class/infiniband/ 2>/dev/null || echo "/sys/class/infiniband not found" + + echo "" + echo "=== 3. ibv_devinfo ===" + which ibv_devinfo 2>/dev/null && ibv_devinfo 2>&1 || echo "ibv_devinfo not available" + + echo "" + echo "=== 4. Kernel modules ===" + lsmod 2>/dev/null | grep -E "ib_|rdma|ionic" || echo "No RDMA kernel modules loaded" + + echo "" + echo "=== 5. Detect RDMA Devices for test environment ===" + if [ -d "/sys/class/infiniband" ]; then + RDMA_DEVS=$(ls /sys/class/infiniband | paste -sd "," -) + echo "Detected RDMA Devices: $RDMA_DEVS" + echo "SGLANG_TEST_RDMA_DEVICE=$RDMA_DEVS" >> $GITHUB_ENV + else + echo "No RDMA devices found in /sys/class/infiniband" + echo "SGLANG_TEST_RDMA_DEVICE=" >> $GITHUB_ENV + fi + + echo "" + echo "=== Host RDMA Check Complete ===" + + - name: Start Special Container + run: bash scripts/ci/amd/amd_ci_start_container_disagg.sh --rocm-version rocm720 + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Verify RDMA in Container + run: | + docker exec -u root ci_sglang bash -c ' + echo "=== Container RDMA Verification ===" + echo "Device nodes:" + ls -la /dev/infiniband/ + echo "" + echo "Provider libraries:" + ls /usr/lib/x86_64-linux-gnu/libibverbs/ | grep -E "ionic|mlx" || echo "No Ionic/Mellanox providers" + echo "" + echo "HCA devices:" + HCA_COUNT=$(ibv_devinfo -list 2>&1 | grep -oE "^[0-9]+ HCAs? found" | grep -oE "^[0-9]+" || echo "0") + ibv_devinfo -list + if [ "$HCA_COUNT" -gt 0 ]; then + echo "" + echo "=== SUCCESS: RDMA setup complete. Found $HCA_COUNT HCA(s) ===" + else + echo "" + echo "=== WARNING: No HCAs detected. RDMA tests may fail ===" + fi + ' + + - name: Run Aiter Op Test (RMSNorm) + timeout-minutes: 10 + run: | + echo "Running pre-check: test_rmsnorm2d.py" + docker exec \ + -e MAX_JOBS=192 \ + ci_sglang \ + python /sgl-workspace/aiter/op_tests/test_rmsnorm2d.py + + - name: Run test_disaggregation + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh \ + -e SGLANG_TEST_RDMA_DEVICE="${{ env.SGLANG_TEST_RDMA_DEVICE }}" \ + -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-8-gpu-35x-disaggregation-amd --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + pr-test-amd-finish: + needs: + [ + call-gate, + check-changes, + + sgl-kernel-unit-test-amd, + sgl-kernel-unit-test-2-gpu-amd, + multimodal-gen-test-1-gpu-amd, + multimodal-gen-test-2-gpu-amd, + + stage-a-test-1-amd, + jit-kernel-unit-test-amd, + stage-b-test-small-1-gpu-amd, + stage-b-test-small-1-gpu-amd-nondeterministic, + stage-b-test-small-1-gpu-amd-mi35x, + stage-b-test-large-1-gpu-amd, + stage-b-test-large-2-gpu-amd, + stage-b-test-large-8-gpu-35x-disaggregation-amd, + stage-c-test-large-8-gpu-amd, + stage-c-test-large-8-gpu-amd-mi35x, + ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check all dependent job statuses + run: | + # Convert the 'needs' context to a JSON string + json_needs='${{ toJson(needs) }}' + + # Get a list of all job names from the JSON keys + job_names=$(echo "$json_needs" | jq -r 'keys_unsorted[]') + + for job in $job_names; do + # For each job, extract its result + result=$(echo "$json_needs" | jq -r --arg j "$job" '.[$j].result') + + # Print the job name and its result + echo "$job: $result" + + # Check for failure or cancellation and exit if found + if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then + echo "The above jobs failed." + exit 1 + fi + done + + # If the loop completes, all jobs were successful + echo "All jobs completed successfully" + exit 0 diff --git a/sglang/.github/workflows/pr-test-amd.yml b/sglang/.github/workflows/pr-test-amd.yml new file mode 100644 index 0000000000000000000000000000000000000000..1aa7b419b45bebbe7621239568db17ed68993652 --- /dev/null +++ b/sglang/.github/workflows/pr-test-amd.yml @@ -0,0 +1,1030 @@ +name: PR Test (AMD) +# Dynamic run-name for /rerun-stage commands to enable URL lookup +# Format: "[stage-name] sha" for fork PRs, "[stage-name]" for non-fork, default for normal runs +run-name: ${{ (inputs.target_stage || inputs.target_stage_select) && (inputs.pr_head_sha && format('[{0}] {1}', inputs.target_stage || inputs.target_stage_select, inputs.pr_head_sha) || format('[{0}]', inputs.target_stage || inputs.target_stage_select)) || '' }} + +on: + push: + branches: [ main ] + paths: + - "python/**" + - "scripts/ci/**" + - "test/**" + - "sgl-kernel/**" + - ".github/workflows/pr-test-amd.yml" + - "docker/rocm.Dockerfile" + pull_request: + branches: [ main ] + paths: + - "python/**" + - "scripts/ci/**" + - "test/**" + - "sgl-kernel/**" + - ".github/workflows/pr-test-amd.yml" + - "docker/rocm.Dockerfile" + workflow_dispatch: + inputs: + target_stage_select: + description: "Select a stage to run from dropdown (leave empty for auto-detect)" + required: false + type: choice + default: '' + options: + - '' + - sgl-kernel-unit-test-amd + - sgl-kernel-unit-test-2-gpu-amd + - stage-a-test-1-amd + - jit-kernel-unit-test-amd + - stage-b-test-small-1-gpu-amd + - stage-b-test-small-1-gpu-amd-nondeterministic + - stage-b-test-small-1-gpu-amd-mi35x + - stage-b-test-large-1-gpu-amd + - stage-b-test-large-2-gpu-amd + - multimodal-gen-test-1-gpu-amd + - multimodal-gen-test-2-gpu-amd + - stage-c-test-large-8-gpu-amd + - stage-c-test-large-8-gpu-amd-mi35x + - stage-b-test-large-8-gpu-disaggregation-amd + target_stage: + description: "Or type comma-separated stage names (overrides dropdown if non-empty)" + required: false + type: string + default: "" + pr_head_sha: + description: "PR head SHA to checkout (for /rerun-stage on fork PRs)" + required: false + type: string + default: "" + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: false + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + aiter_ref: + description: 'Override AITER commit (optional, leave empty to use Dockerfile default)' + required: false + type: string + default: '' + continue_on_error: + description: 'Continue on error (do not fail the workflow on test failures)' + required: false + type: boolean + default: false + +env: + AITER_COMMIT_OVERRIDE: ${{ inputs.aiter_ref }} + +concurrency: + # When called via workflow_call with run_all_tests=true, use a unique group per run to + # avoid collisions with direct push/PR triggers. We use run_all_tests (not github.event_name) + # to detect this, because github.event_name inherits from the caller in workflow_call. + group: pr-test-amd-${{ inputs.run_all_tests && format('full-{0}', github.run_id) || inputs.pr_head_sha || inputs.ref || github.ref }} + cancel-in-progress: ${{ !inputs.run_all_tests && github.event_name != 'workflow_call' }} + +jobs: + call-gate: + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + check-changes: + needs: [call-gate] + runs-on: ubuntu-latest + outputs: + main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} + sgl_kernel: ${{ steps.filter.outputs.sgl_kernel || steps.run-mode.outputs.run_all_tests }} + jit_kernel: ${{ steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} + multimodal_gen: ${{ steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + if: steps.run-mode.outputs.run_all_tests != 'true' + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject_rocm.toml" + - "python/pyproject_other.toml" + - "scripts/ci/amd/*" + - "scripts/ci/utils/*" + - "test/**" + - ".github/workflows/pr-test-amd.yml" + sgl_kernel: + - "sgl-kernel/**" + - ".github/workflows/pr-test-amd.yml" + jit_kernel: + - "python/sglang/jit_kernel/**" + - ".github/workflows/pr-test-amd.yml" + multimodal_gen: + - "python/sglang/multimodal_gen/**" + - "python/sglang/cli/**" + - "python/sglang/jit_kernel/diffusion/**" + - "python/pyproject_rocm.toml" + - "python/pyproject_other.toml" + + # =============================================== sgl-kernel ==================================================== + sgl-kernel-unit-test-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',sgl-kernel-unit-test-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.sgl_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 14 + run: | + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_align.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_topk_softmax.py + docker exec -w /sglang-checkout/sgl-kernel/tests/speculative ci_sglang python3 -m pytest test_eagle_utils.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_apply_token_bitmask_inplace.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_activation.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_topk.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_kvcacheio.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_moe_topk_sigmoid.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_torch_defaults_reset.py + + sgl-kernel-unit-test-2-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',sgl-kernel-unit-test-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.sgl_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-2gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 20 + run: | + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_amd_deterministic_custom_allreduce.py + docker exec -w /sglang-checkout/sgl-kernel/tests ci_sglang python3 -m pytest test_amd_nccl_allreduce_determinism.py + + # =============================================== primary ==================================================== + + stage-a-test-1-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-a-test-1-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 10 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-a-test-1-amd ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + jit-kernel-unit-test-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',jit-kernel-unit-test-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.jit_kernel == 'true' + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run JIT kernel unit tests + timeout-minutes: 10 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout" python3 -m pytest -q python/sglang/jit_kernel/tests/test_store_cache.py + + stage-b-test-small-1-gpu-amd: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 14 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-small-1-gpu-amd-nondeterministic: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd-nondeterministic,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd-nondeterministic --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-small-1-gpu-amd-mi35x: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-small-1-gpu-amd-mi35x,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-small-1-gpu-amd-mi35x ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-large-1-gpu-amd: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-1-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-b-test-large-2-gpu-amd: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-2gpu-sglang] + part: [0, 1] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-2-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + multimodal-gen-test-1-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',multimodal-gen-test-1-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.multimodal_gen == 'true' + ) + ) + strategy: + fail-fast: false + max-parallel: 1 # Run one at a time to avoid eviction from resource exhaustion during AITER kernel JIT + matrix: + runner: [linux-mi325-1gpu-sglang] + part: [0, 1] # 2 partitions: 11 tests ÷ 2 = ~5-6 tests each + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh diffusion + + - name: Setup kernel caches + run: | + # Use the persistent /sgl-data directory (mounted from /home/runner/sgl-data) + # This directory persists across container restarts on the self-hosted runner + docker exec ci_sglang mkdir -p /sgl-data/aiter-kernels /sgl-data/miopen-cache /sgl-data/hf-cache/hub + + # Clear pre-built AITER kernels from Docker image to avoid segfaults + # The image may have stale/incompatible kernels at /sgl-workspace/aiter/aiter/jit/ + echo "Clearing pre-built AITER kernels from Docker image..." + docker exec ci_sglang rm -rf /sgl-workspace/aiter/aiter/jit/*.so 2>/dev/null || true + docker exec ci_sglang rm -rf /sgl-data/aiter-kernels/*.so 2>/dev/null || true + echo "AITER kernels cleared - will be rebuilt on first use" + + # Create persistent cache marker if /sgl-data is a real mount (not ephemeral) + # This tells the test cleanup code to NOT delete downloaded models + if docker exec ci_sglang test -d /sgl-data && docker exec ci_sglang mountpoint -q /sgl-data 2>/dev/null; then + docker exec ci_sglang touch /sgl-data/hf-cache/.persistent_cache + echo "Created .persistent_cache marker - HF cache will persist" + else + echo "WARNING: /sgl-data is not a mount point - models will be cleaned up after each test" + fi + + # Check MIOpen cache (VAE convolution kernels) + miopen_files=$(docker exec ci_sglang find /sgl-data/miopen-cache -name "*.udb" 2>/dev/null | wc -l || echo "0") + echo "Found ${miopen_files} MIOpen cache files" + + - name: Diagnose HF cache and system resources + run: | + echo "=== System Memory Status ===" + free -h + echo "" + echo "=== Disk Space ===" + df -h /home/runner/sgl-data 2>/dev/null || df -h + echo "" + echo "=== HF Cache Directory Structure ===" + docker exec ci_sglang ls -la /sgl-data/hf-cache/ 2>/dev/null || echo "HF cache dir not found" + docker exec ci_sglang ls -la /sgl-data/hf-cache/hub/ 2>/dev/null || echo "HF hub cache not found" + echo "" + echo "=== Checking for cached diffusion models (1-GPU tests) ===" + # Models used in 1-GPU tests: Wan2.1-T2V-1.3B, HunyuanVideo, Qwen-Image, FLUX.1, FLUX.2 + for model in "Wan-AI--Wan2.1-T2V-1.3B-Diffusers" "tencent--HunyuanVideo" "Qwen--Qwen-Image" "black-forest-labs--FLUX.1-dev" "black-forest-labs--FLUX.2-dev"; do + cache_path="/sgl-data/hf-cache/hub/models--${model}" + if docker exec ci_sglang test -d "$cache_path"; then + size=$(docker exec ci_sglang du -sh "$cache_path" 2>/dev/null | cut -f1) + echo "✓ CACHED: $model ($size)" + else + echo "✗ NOT CACHED: $model" + fi + done + echo "" + echo "=== GPU Memory Status ===" + docker exec ci_sglang rocm-smi --showmeminfo vram 2>/dev/null || echo "rocm-smi not available" + + - name: Run diffusion server tests (1-GPU) + timeout-minutes: 70 + run: | + # AMD CI: All 1-GPU tests except FLUX.2 (FLUX.1 covers same code path) + # Tests: T2V, T2I, I2V, LoRA + # + # HF download env vars: + # - HF_HUB_ENABLE_HF_TRANSFER=1: Use faster hf_transfer for downloads (if available) + # - HF_HUB_DISABLE_SYMLINKS_WARNING=1: Suppress symlink warnings + docker exec \ + -e SGLANG_E2E_TOLERANCE=0.3 \ + -e SGLANG_STAGE_TIME_TOLERANCE=0.2 \ + -e SGLANG_NON_DENOISE_STAGE_TIME_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_STEP_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_AGG_TOLERANCE=0.3 \ + -e SGLANG_TEST_NUM_INFERENCE_STEPS=5 \ + -e AITER_JIT_DIR=/sgl-data/aiter-kernels \ + -e MIOPEN_USER_DB_PATH=/sgl-data/miopen-cache \ + -e HF_HUB_ENABLE_HF_TRANSFER=1 \ + -e HF_HUB_DISABLE_SYMLINKS_WARNING=1 \ + -w /sglang-checkout/python \ + ci_sglang python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 1-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + -k "not flux_2" + + # Post-test diagnostics + echo "=== Post-test System Memory Status ===" + free -h + + multimodal-gen-test-2-gpu-amd: + needs: [check-changes] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',multimodal-gen-test-2-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + needs.check-changes.outputs.multimodal_gen == 'true' + ) + ) + strategy: + fail-fast: false + max-parallel: 1 # Run one at a time to avoid eviction from resource exhaustion during AITER kernel JIT + matrix: + runner: [linux-mi325-2gpu-sglang] + part: [0, 1] # 2 partitions: 9 tests ÷ 2 = ~4-5 tests each + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: | + bash scripts/ci/amd/amd_ci_install_dependency.sh diffusion + + - name: Setup kernel caches + run: | + # Use the persistent /sgl-data directory (mounted from /home/runner/sgl-data) + docker exec ci_sglang mkdir -p /sgl-data/aiter-kernels /sgl-data/miopen-cache /sgl-data/hf-cache/hub + + # Clear pre-built AITER kernels from Docker image to avoid segfaults + # The image may have stale/incompatible kernels at /sgl-workspace/aiter/aiter/jit/ + echo "Clearing pre-built AITER kernels from Docker image..." + docker exec ci_sglang rm -rf /sgl-workspace/aiter/aiter/jit/*.so 2>/dev/null || true + docker exec ci_sglang rm -rf /sgl-data/aiter-kernels/*.so 2>/dev/null || true + echo "AITER kernels cleared - will be rebuilt on first use" + + # Create persistent cache marker if /sgl-data is a real mount (not ephemeral) + # This tells the test cleanup code to NOT delete downloaded models + if docker exec ci_sglang test -d /sgl-data && docker exec ci_sglang mountpoint -q /sgl-data 2>/dev/null; then + docker exec ci_sglang touch /sgl-data/hf-cache/.persistent_cache + echo "Created .persistent_cache marker - HF cache will persist" + else + echo "WARNING: /sgl-data is not a mount point - models will be cleaned up after each test" + fi + + # Check MIOpen cache (VAE convolution kernels) + miopen_files=$(docker exec ci_sglang find /sgl-data/miopen-cache -name "*.udb" 2>/dev/null | wc -l || echo "0") + echo "Found ${miopen_files} MIOpen cache files" + + - name: Diagnose HF cache and system resources + run: | + echo "=== System Memory Status ===" + free -h + echo "" + echo "=== Disk Space ===" + df -h /home/runner/sgl-data 2>/dev/null || df -h + echo "" + echo "=== HF Cache Directory Structure ===" + docker exec ci_sglang ls -la /sgl-data/hf-cache/ 2>/dev/null || echo "HF cache dir not found" + docker exec ci_sglang ls -la /sgl-data/hf-cache/hub/ 2>/dev/null || echo "HF hub cache not found" + echo "" + echo "=== Checking for cached diffusion models (2-GPU tests) ===" + # Models used in 2-GPU tests: Wan2.2-T2V-A14B, Wan2.1-T2V-14B, Qwen-Image, FLUX.1 + for model in "Wan-AI--Wan2.2-T2V-A14B-Diffusers" "Wan-AI--Wan2.1-T2V-14B-Diffusers" "Qwen--Qwen-Image" "black-forest-labs--FLUX.1-dev"; do + cache_path="/sgl-data/hf-cache/hub/models--${model}" + if docker exec ci_sglang test -d "$cache_path"; then + size=$(docker exec ci_sglang du -sh "$cache_path" 2>/dev/null | cut -f1) + echo "✓ CACHED: $model ($size)" + else + echo "✗ NOT CACHED: $model" + fi + done + echo "" + echo "=== GPU Memory Status ===" + docker exec ci_sglang rocm-smi --showmeminfo vram 2>/dev/null || echo "rocm-smi not available" + + - name: Run diffusion server tests (2-GPU) + timeout-minutes: 80 + run: | + # AMD CI: All 2-GPU tests including LoRA + # Tests: T2V, T2I, I2V, LoRA + # + # HF download env vars: + # - HF_HUB_ENABLE_HF_TRANSFER=1: Use faster hf_transfer for downloads (if available) + # - HF_HUB_DISABLE_SYMLINKS_WARNING=1: Suppress symlink warnings + docker exec \ + -e SGLANG_E2E_TOLERANCE=0.3 \ + -e SGLANG_STAGE_TIME_TOLERANCE=0.2 \ + -e SGLANG_NON_DENOISE_STAGE_TIME_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_STEP_TOLERANCE=0.6 \ + -e SGLANG_DENOISE_AGG_TOLERANCE=0.3 \ + -e SGLANG_TEST_NUM_INFERENCE_STEPS=5 \ + -e AITER_JIT_DIR=/sgl-data/aiter-kernels \ + -e MIOPEN_USER_DB_PATH=/sgl-data/miopen-cache \ + -e HF_HUB_ENABLE_HF_TRANSFER=1 \ + -e HF_HUB_DISABLE_SYMLINKS_WARNING=1 \ + -w /sglang-checkout/python \ + ci_sglang python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 2-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 + + # Post-test diagnostics + echo "=== Post-test System Memory Status ===" + free -h + + + stage-c-test-large-8-gpu-amd: + needs: [check-changes, call-gate, stage-b-test-small-1-gpu-amd, stage-b-test-large-2-gpu-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-c-test-large-8-gpu-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + env: + RUNNER_LABELS: linux-mi325-8gpu-sglang + strategy: + fail-fast: false + matrix: + runner: [linux-mi325-8gpu-sglang] + part: [0, 1, 2] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Test RCCL multi-GPU communication + timeout-minutes: 5 + run: | + echo "Testing RCCL multi-GPU communication with debug info..." + docker exec ci_sglang bash -c "cd /sglang-checkout && NCCL_DEBUG=INFO RCCL_DEBUG=INFO torchrun --nproc_per_node=8 scripts/ci/amd/test_rccl_multi_gpu.py" + + - name: Run test + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-c-test-large-8-gpu-amd --auto-partition-id ${{ matrix.part }} --auto-partition-size 3 --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + stage-c-test-large-8-gpu-amd-mi35x: + needs: [check-changes, call-gate, stage-b-test-small-1-gpu-amd, stage-b-test-large-2-gpu-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-c-test-large-8-gpu-amd-mi35x,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-8] + part: [0] + runs-on: ${{matrix.runner}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Start CI container + run: bash scripts/ci/amd/amd_ci_start_container.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Run test + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-c-test-large-8-gpu-amd-mi35x --auto-partition-id ${{ matrix.part }} --auto-partition-size 1 --timeout-per-file 3600 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + # =============================================== Disaggregation ==================================================== + stage-b-test-large-8-gpu-35x-disaggregation-amd: + needs: [check-changes, stage-a-test-1-amd] + if: | + always() && + ( + (contains(format(',{0},', inputs.target_stage || inputs.target_stage_select), ',stage-b-test-large-8-gpu-disaggregation-amd,')) || + ( + !(inputs.target_stage || inputs.target_stage_select) && + (!failure() && !cancelled()) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + strategy: + fail-fast: false + matrix: + runner: [linux-mi35x-gpu-8.fabric] + + runs-on: ${{matrix.runner}} + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Ensure VRAM is clear + run: bash scripts/ensure_vram_clear.sh rocm + + - name: Check Host RDMA Environment + id: rdma_detect + run: | + set +e + echo "=== Checking Host RDMA Environment ===" + + echo "" + echo "=== 1. Ionic driver library check ===" + ls -l /usr/lib/x86_64-linux-gnu/libibverbs/libionic* 2>/dev/null || echo "libionic not found in standard path" + + echo "" + echo "=== 2. Infiniband devices ===" + ls -la /dev/infiniband/ 2>/dev/null || echo "/dev/infiniband not found" + ls -la /sys/class/infiniband/ 2>/dev/null || echo "/sys/class/infiniband not found" + + echo "" + echo "=== 3. ibv_devinfo ===" + which ibv_devinfo 2>/dev/null && ibv_devinfo 2>&1 || echo "ibv_devinfo not available" + + echo "" + echo "=== 4. Kernel modules ===" + lsmod 2>/dev/null | grep -E "ib_|rdma|ionic" || echo "No RDMA kernel modules loaded" + + echo "" + echo "=== 5. Detect RDMA Devices for test environment ===" + if [ -d "/sys/class/infiniband" ]; then + RDMA_DEVS=$(ls /sys/class/infiniband | paste -sd "," -) + echo "Detected RDMA Devices: $RDMA_DEVS" + echo "SGLANG_TEST_RDMA_DEVICE=$RDMA_DEVS" >> $GITHUB_ENV + else + echo "No RDMA devices found in /sys/class/infiniband" + echo "SGLANG_TEST_RDMA_DEVICE=" >> $GITHUB_ENV + fi + + echo "" + echo "=== Host RDMA Check Complete ===" + + - name: Start Special Container + run: bash scripts/ci/amd/amd_ci_start_container_disagg.sh + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + + - name: Install dependencies + run: bash scripts/ci/amd/amd_ci_install_dependency.sh + + - name: Verify RDMA in Container + run: | + docker exec -u root ci_sglang bash -c ' + echo "=== Container RDMA Verification ===" + echo "Device nodes:" + ls -la /dev/infiniband/ + echo "" + echo "Provider libraries:" + ls /usr/lib/x86_64-linux-gnu/libibverbs/ | grep -E "ionic|mlx" || echo "No Ionic/Mellanox providers" + echo "" + echo "HCA devices:" + HCA_COUNT=$(ibv_devinfo -list 2>&1 | grep -oE "^[0-9]+ HCAs? found" | grep -oE "^[0-9]+" || echo "0") + ibv_devinfo -list + if [ "$HCA_COUNT" -gt 0 ]; then + echo "" + echo "=== SUCCESS: RDMA setup complete. Found $HCA_COUNT HCA(s) ===" + else + echo "" + echo "=== WARNING: No HCAs detected. RDMA tests may fail ===" + fi + ' + + - name: Run Aiter Op Test (RMSNorm) + timeout-minutes: 10 + run: | + echo "Running pre-check: test_rmsnorm2d.py" + docker exec \ + -e MAX_JOBS=192 \ + ci_sglang \ + python /sgl-workspace/aiter/op_tests/test_rmsnorm2d.py + + - name: Run test_disaggregation + timeout-minutes: 60 + run: | + bash scripts/ci/amd/amd_ci_exec.sh \ + -e SGLANG_TEST_RDMA_DEVICE="${{ env.SGLANG_TEST_RDMA_DEVICE }}" \ + -w "/sglang-checkout/test" python3 run_suite.py --hw amd --suite stage-b-test-large-8-gpu-35x-disaggregation-amd --timeout-per-file 1800 ${{ inputs.continue_on_error && '--continue-on-error' || '' }} + + pr-test-amd-finish: + needs: + [ + call-gate, + check-changes, + + sgl-kernel-unit-test-amd, + sgl-kernel-unit-test-2-gpu-amd, + multimodal-gen-test-1-gpu-amd, + multimodal-gen-test-2-gpu-amd, + + stage-a-test-1-amd, + jit-kernel-unit-test-amd, + stage-b-test-small-1-gpu-amd, + stage-b-test-small-1-gpu-amd-nondeterministic, + stage-b-test-small-1-gpu-amd-mi35x, + stage-b-test-large-1-gpu-amd, + stage-b-test-large-2-gpu-amd, + stage-b-test-large-8-gpu-35x-disaggregation-amd, + stage-c-test-large-8-gpu-amd, + stage-c-test-large-8-gpu-amd-mi35x, + ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check all dependent job statuses + run: | + # Convert the 'needs' context to a JSON string + json_needs='${{ toJson(needs) }}' + + # Get a list of all job names from the JSON keys + job_names=$(echo "$json_needs" | jq -r 'keys_unsorted[]') + + for job in $job_names; do + # For each job, extract its result + result=$(echo "$json_needs" | jq -r --arg j "$job" '.[$j].result') + + # Print the job name and its result + echo "$job: $result" + + # Check for failure or cancellation and exit if found + if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then + echo "The above jobs failed." + exit 1 + fi + done + + # If the loop completes, all jobs were successful + echo "All jobs completed successfully" + exit 0 diff --git a/sglang/.github/workflows/pr-test-npu.yml b/sglang/.github/workflows/pr-test-npu.yml new file mode 100644 index 0000000000000000000000000000000000000000..7694ee943eb36d602b9c7d00e0e493e01e9f8580 --- /dev/null +++ b/sglang/.github/workflows/pr-test-npu.yml @@ -0,0 +1,340 @@ +name: PR Test (NPU) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + +concurrency: + group: pr-test-npu-${{ inputs.ref || github.ref }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +jobs: + # ==================== Check Changes ==================== # + check-changes: + runs-on: ubuntu-latest + outputs: + changes_exist: ${{ steps.filter.outputs.main_package == 'true' || steps.filter.outputs.multimodal_gen == 'true' || steps.run-mode.outputs.run_all_tests == 'true'}} + main_package: ${{ steps.filter.outputs.main_package == 'true' || steps.run-mode.outputs.run_all_tests == 'true' }} + multimodal_gen: ${{ steps.filter.outputs.multimodal_gen == 'true' || steps.run-mode.outputs.run_all_tests == 'true' }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + if: steps.run-mode.outputs.run_all_tests != 'true' + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject_npu.toml" + - "scripts/ci/npu/npu_ci_install_dependency.sh" + - "test/srt/ascend/**" + - ".github/workflows/pr-test-npu.yml" + multimodal_gen: + - "python/sglang/multimodal_gen/**" + - "python/pyproject_npu.toml" + - "scripts/ci/npu/npu_ci_install_dependency.sh" + - ".github/workflows/pr-test-npu.yml" + + # ==================== PR Gate ==================== # + pr-gate: + needs: check-changes + if: needs.check-changes.outputs.changes_exist == 'true' + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + + per-commit-1-npu-a2: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: linux-aarch64-a2-1 + strategy: + fail-fast: false + matrix: + part: [ 0, 1 ] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-910b-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh 910b + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + cd test/srt + python3 run_suite.py --suite per-commit-1-npu-a2 --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 + + per-commit-2-npu-a2: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: linux-aarch64-a2-2 + strategy: + fail-fast: true + matrix: + part: [0, 1] + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-910b-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh 910b + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + cd test/srt + python3 run_suite.py --suite per-commit-2-npu-a2 --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 + + per-commit-4-npu-a3: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: linux-aarch64-a3-4 + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + cd test/srt + python3 run_suite.py --suite per-commit-4-npu-a3 --timeout-per-file 3600 + + per-commit-16-npu-a3: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: linux-aarch64-a3-16 + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.5.0-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://gh-proxy.test.osinfra.cn/https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + cd test/srt + python3 run_suite.py --suite per-commit-16-npu-a3 --timeout-per-file 3600 + + multimodal-gen-test-1-npu-a3: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.multimodal_gen == 'true' + runs-on: linux-aarch64-a3-2 + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.3.rc2-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://gh-proxy.test.osinfra.cn/https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + export PATH="/usr/local/Ascend/8.3.RC1/compiler/bishengir/bin:${PATH}" + cd python + python3 sglang/multimodal_gen/test/run_suite.py --suite 1-npu + + multimodal-gen-test-2-npu-a3: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.multimodal_gen == 'true' + runs-on: linux-aarch64-a3-16 + container: + image: swr.cn-southwest-2.myhuaweicloud.com/base_image/ascend-ci/cann:8.3.rc2-a3-ubuntu22.04-py3.11 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + env: + TORCH_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/whl/cpu" + PYPI_CACHE_URL: "http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple" + GITHUB_PROXY_URL: "https://gh-proxy.test.osinfra.cn/" + run: | + # speed up by using infra cache services + CACHING_URL="cache-service.nginx-pypi-cache.svc.cluster.local" + sed -Ei "s@(ports|archive).ubuntu.com@${CACHING_URL}:8081@g" /etc/apt/sources.list + pip config set global.index-url http://${CACHING_URL}/pypi/simple + pip config set global.trusted-host "${CACHING_URL}" + + bash scripts/ci/npu/npu_ci_install_dependency.sh a3 + # copy required file from our daily cache + cp ~/.cache/modelscope/hub/datasets/otavia/ShareGPT_Vicuna_unfiltered/ShareGPT_V3_unfiltered_cleaned_split.json /tmp + # copy download through proxy + curl -o /tmp/test.jsonl -L https://gh-proxy.test.osinfra.cn/https://raw.githubusercontent.com/openai/grade-school-math/master/grade_school_math/data/test.jsonl + + - name: Run test + timeout-minutes: 60 + env: + SGLANG_USE_MODELSCOPE: true + SGLANG_IS_IN_CI: true + HF_ENDPOINT: https://hf-mirror.com + TORCH_EXTENSIONS_DIR: /tmp/torch_extensions + PYTORCH_NPU_ALLOC_CONF: "expandable_segments:True" + STREAMS_PER_DEVICE: 32 + run: | + export PATH="/usr/local/Ascend/8.3.RC1/compiler/bishengir/bin:${PATH}" + cd python + python3 sglang/multimodal_gen/test/run_suite.py --suite 2-npu diff --git a/sglang/.github/workflows/pr-test-rust.yml b/sglang/.github/workflows/pr-test-rust.yml new file mode 100644 index 0000000000000000000000000000000000000000..a1e96316e5a83691aee3fa5ddb144481a212bf6f --- /dev/null +++ b/sglang/.github/workflows/pr-test-rust.yml @@ -0,0 +1,358 @@ +name: PR Test (SMG) + +on: + push: + branches: [ main ] + paths: + - "sgl-model-gateway/**" + pull_request: + branches: [ main ] + types: [opened, synchronize, reopened, labeled] + paths: + - "sgl-model-gateway/**" + workflow_dispatch: + +concurrency: + group: gateway-tests-${{ github.ref }} + cancel-in-progress: true + +env: + RUSTC_WRAPPER: sccache + SCCACHE_GHA_ENABLED: "true" + +jobs: + build-wheel: + if: | + github.event_name != 'pull_request' || + (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run-ci')) || + (github.event.action == 'labeled' && github.event.label.name == 'run-ci') + runs-on: 4-gpu-a10 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install rust dependencies + run: | + bash scripts/ci/cuda/ci_install_gateway_dependencies.sh + + - name: Configure sccache + uses: mozilla-actions/sccache-action@v0.0.9 + with: + version: "v0.12.0" + disable_annotations: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: sgl-model-gateway + shared-key: "rust-cache" + cache-all-crates: true + cache-on-failure: true + save-if: true + + - name: Build python binding + run: | + source "$HOME/.cargo/env" + export RUSTC_WRAPPER=sccache + cd sgl-model-gateway/bindings/python + python3 -m pip install --upgrade pip maturin + maturin build --profile ci --features vendored-openssl --out dist + + - name: List built wheel + run: ls -lh sgl-model-gateway/bindings/python/dist/ + + - name: Upload wheel artifact + uses: actions/upload-artifact@v4 + with: + name: smg-wheel + path: sgl-model-gateway/bindings/python/dist/*.whl + retention-days: 1 + + - name: Test wheel install + run: | + pip install sgl-model-gateway/bindings/python/dist/*.whl + python3 -c "import sglang_router; print('Python package: OK')" + python3 -c "from sglang_router.sglang_router_rs import Router; print('Rust extension: OK')" + python3 -m sglang_router.launch_router --help > /dev/null && echo "Entry point: OK" + + python-unit-tests: + needs: build-wheel + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: sglang-repo + + - name: Move sgl-model-gateway folder to root + run: | + mv sglang-repo/sgl-model-gateway/* . + rm -rf sglang-repo + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Download wheel artifact + uses: actions/download-artifact@v4 + with: + name: smg-wheel + path: dist/ + + - name: Install wheel + run: pip install dist/*.whl + + - name: Run Python unit tests + run: | + cd bindings/python + python3 -m pip install pytest pytest-cov pytest-xdist + pytest -q tests --cov=sglang_router --cov-config=.coveragerc --cov-report=term-missing --cov-fail-under=80 + + unit-tests: + if: | + github.event_name != 'pull_request' || + (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run-ci')) || + (github.event.action == 'labeled' && github.event.label.name == 'run-ci') + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_gateway_dependencies.sh + + - name: Configure sccache + uses: mozilla-actions/sccache-action@v0.0.9 + with: + version: "v0.12.0" + disable_annotations: true + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: sgl-model-gateway + shared-key: "rust-cache" + cache-all-crates: true + cache-on-failure: true + save-if: true + + - name: Run lint + run: | + source "$HOME/.cargo/env" + cd sgl-model-gateway/ + rustup component add clippy + cargo clippy --all-targets --all-features -- -D warnings + + - name: Run fmt + run: | + source "$HOME/.cargo/env" + cd sgl-model-gateway/ + rustup component add --toolchain nightly-x86_64-unknown-linux-gnu rustfmt + rustup toolchain install nightly --profile minimal + cargo +nightly fmt -- --check + + - name: Generate vision golden fixtures + run: | + pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu + + pip install transformers pillow numpy scipy + pip install transformers pillow numpy + cd sgl-model-gateway/ + python scripts/generate_vision_golden.py + + - name: Run Rust tests + timeout-minutes: 20 + run: | + source "$HOME/.cargo/env" + cd sgl-model-gateway/ + cargo test + + - name: Show sccache stats + if: always() + run: sccache --show-stats + + gateway-e2e: + name: ${{ matrix.name }} + needs: build-wheel + if: | + github.event_name != 'pull_request' || + (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run-ci')) || + (github.event.action == 'labeled' && github.event.label.name == 'run-ci') + strategy: + fail-fast: false + matrix: + include: + - name: benchmarks + timeout: 32 + test_dirs: "e2e_test/benchmarks" + extra_deps: "genai-bench==0.0.3" + env_vars: "" + reruns: "" + upload_benchmarks: true + parallel_opts: "" # No parallel for benchmarks (performance measurement) + - name: responses + timeout: 45 + test_dirs: "e2e_test/responses" + extra_deps: "" + env_vars: "SHOW_WORKER_LOGS=0 SHOW_ROUTER_LOGS=1" + reruns: "--reruns 2 --reruns-delay 5" + setup_oracle: true + setup_brave: true + parallel_opts: "" # Cloud backend tests not compatible with parallel execution + - name: e2e + timeout: 45 + test_dirs: "e2e_test/router e2e_test/embeddings" + extra_deps: "pytest-parallel py" # py is required for pytest-parallel with newer pytest + env_vars: "SHOW_WORKER_LOGS=0 SHOW_ROUTER_LOGS=1" + reruns: "--reruns 2 --reruns-delay 5" + parallel_opts: "--workers 1 --tests-per-worker 4" # Thread-based parallelism + - name: chat-completions + timeout: 45 + test_dirs: "e2e_test/chat_completions" + extra_deps: "" + env_vars: "SHOW_WORKER_LOGS=0 SHOW_ROUTER_LOGS=1" + reruns: "--reruns 2 --reruns-delay 5" + parallel_opts: "" + runs-on: 4-gpu-a10 + timeout-minutes: ${{ matrix.timeout }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install SGLang dependencies + run: | + sudo --preserve-env=PATH bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Setup Oracle Instant Client + if: matrix.setup_oracle + run: | + sudo apt-get install -y unzip + INSTANT_CLIENT_DIR="/home/ubuntu/instant-client" + INSTANT_CLIENT_ZIP="instantclient-basic-linux.x64-23.9.0.25.07.zip" + + if [ ! -d "$INSTANT_CLIENT_DIR/instantclient_23_9" ]; then + echo "Downloading Oracle Instant Client..." + mkdir -p "$INSTANT_CLIENT_DIR" + cd "$INSTANT_CLIENT_DIR" + wget https://download.oracle.com/otn_software/linux/instantclient/2390000/$INSTANT_CLIENT_ZIP + unzip $INSTANT_CLIENT_ZIP + rm $INSTANT_CLIENT_ZIP + else + echo "Oracle Instant Client already exists, skipping download" + fi + + echo "LD_LIBRARY_PATH=/home/ubuntu/instant-client/instantclient_23_9:\$LD_LIBRARY_PATH" >> $GITHUB_ENV + + - name: Start Oracle Database + if: matrix.setup_oracle + run: | + docker run -d -p 1521:1521 -e ORACLE_PASSWORD=oracle --name oracle-db gvenzl/oracle-xe:21-slim + echo "Starting Oracle DB..." + + # Export Oracle connection environment variables + echo "ATP_USER=system" >> $GITHUB_ENV + echo "ATP_PASSWORD=oracle" >> $GITHUB_ENV + echo "ATP_DSN=localhost:1521/XEPDB1" >> $GITHUB_ENV + + - name: Start Brave MCP Server + if: matrix.setup_brave + run: | + docker run -d --rm \ + -p 8001:8080 \ + -e BRAVE_API_KEY \ + --name brave-search-server \ + shoofio/brave-search-mcp-sse:1.0.10 + echo "Starting Brave MCP Server..." + sleep 2 + curl -f --max-time 1 http://localhost:8001/sse > /dev/null 2>&1 && echo "Brave MCP Server is healthy!" || echo "Brave MCP Server responded" + + - name: Download wheel artifact + uses: actions/download-artifact@v4 + with: + name: smg-wheel + path: wheel/ + + - name: Install wheel + run: | + pip uninstall -y sglang-router || true + pip install wheel/*.whl + + - name: Install e2e test dependencies + run: | + python3 -m pip install pytest pytest-rerunfailures httpx openai grpcio grpcio-health-checking numpy + if [ -n "${{ matrix.extra_deps }}" ]; then + python3 -m pip --no-cache-dir install --upgrade ${{ matrix.extra_deps }} + fi + + - name: Run E2E tests + run: | + bash scripts/killall_sglang.sh all + cd sgl-model-gateway + ${{ matrix.env_vars }} ROUTER_LOCAL_MODEL_PATH="/home/ubuntu/models" pytest ${{ matrix.reruns }} ${{ matrix.parallel_opts }} ${{ matrix.test_dirs }} -s -vv -o log_cli=true --log-cli-level=INFO + + - name: Upload benchmark results + if: matrix.upload_benchmarks && success() + uses: actions/upload-artifact@v4 + with: + name: genai-bench-results-all-policies + path: sgl-model-gateway/benchmark_**/ + + - name: Cleanup Brave MCP Server + if: always() && matrix.setup_brave + run: | + docker stop brave-search-server || true + docker rm brave-search-server || true + + - name: Cleanup Oracle Database + if: always() && matrix.setup_oracle + run: | + docker stop oracle-db || true + docker rm oracle-db || true + + docker-build-test: + if: | + github.event_name != 'pull_request' || + (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run-ci')) || + (github.event.action == 'labeled' && github.event.label.name == 'run-ci') + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image (no push) + uses: docker/build-push-action@v5 + with: + context: . + file: docker/gateway.Dockerfile + push: false + tags: sgl-model-gateway:test + cache-from: type=gha + cache-to: type=gha,mode=max + + finish: + needs: [build-wheel, python-unit-tests, unit-tests, gateway-e2e, docker-build-test] + runs-on: ubuntu-latest + steps: + - name: Finish + run: echo "This is an empty step to ensure that all jobs are completed." + + summarize-benchmarks: + needs: gateway-e2e + runs-on: ubuntu-latest + if: success() + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download benchmark results + uses: actions/download-artifact@v4 + with: + name: genai-bench-results-all-policies + + - name: Create benchmark summary + run: python3 sgl-model-gateway/e2e_test/benchmarks/summarize.py . diff --git a/sglang/.github/workflows/pr-test-xeon.yml b/sglang/.github/workflows/pr-test-xeon.yml new file mode 100644 index 0000000000000000000000000000000000000000..021a1308593c55515a08272b7d63c63d68908934 --- /dev/null +++ b/sglang/.github/workflows/pr-test-xeon.yml @@ -0,0 +1,131 @@ +name: PR Test (Xeon) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + +concurrency: + group: pr-test-xeon-${{ inputs.ref || github.ref }} + cancel-in-progress: false + +jobs: + # ==================== Check Changes ==================== # + check-changes: + runs-on: ubuntu-latest + outputs: + main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests}} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + if: steps.run-mode.outputs.run_all_tests != 'true' + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject_cpu.toml" + - "test/**" + - "sgl-kernel/**" + - ".github/workflows/pr-test-xeon.yml" + - "docker/xeon.Dockerfile" + + # ==================== PR Gate ==================== # + pr-gate: + needs: check-changes + if: needs.check-changes.outputs.main_package == 'true' + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + + build-test: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: xeon-gnr + env: + HF_HOME: /home/sdp/.cache/huggingface + strategy: + matrix: + build_type: ['all'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Build and Push + run: | + version=$(cat python/sglang/version.py | cut -d'"' -f2) + tag=v${version}-xeon + PR_REPO=${{ github.event.pull_request.head.repo.clone_url }} + PR_HEAD_REF=${{ github.head_ref }} + + docker build \ + ${PR_REPO:+--build-arg SGLANG_REPO=$PR_REPO} \ + ${PR_HEAD_REF:+--build-arg VER_SGLANG=$PR_HEAD_REF} \ + . -f docker/xeon.Dockerfile -t sglang_xeon --no-cache + + - name: Run container + run: | + docker run -dt \ + -v ${{ github.workspace }}:/sglang-checkout/ --ipc=host \ + -v ${HF_HOME}:/root/.cache/huggingface \ + --name ci_sglang_xeon \ + sglang_xeon + + - name: Check AMX support + id: check_amx + timeout-minutes: 5 + run: | + docker exec -w /sglang-checkout/ ci_sglang_xeon \ + bash -c "source /opt/.venv/bin/activate && python3 -c 'import torch; import sgl_kernel; assert torch._C._cpu._is_amx_tile_supported(); assert hasattr(torch.ops.sgl_kernel, \"convert_weight_packed\"); '" + + - name: Run unit tests + timeout-minutes: 36 + run: | + docker exec -w /sglang-checkout/ ci_sglang_xeon \ + bash -c "source /opt/.venv/bin/activate && cd ./test/srt && python3 run_suite.py --suite per-commit-cpu --timeout-per-file 1500" + + - name: Change permission + timeout-minutes: 2 + run: | + docker exec -u root ci_sglang_xeon bash -c " + rm -rf /tmp/ci-home && + chown -R $(id -u):$(id -g) /sglang-checkout/ 2>/dev/null || true + " + + - name: Cleanup container + if: always() + run: | + docker rm -f ci_sglang_xeon || true diff --git a/sglang/.github/workflows/pr-test-xpu.yml b/sglang/.github/workflows/pr-test-xpu.yml new file mode 100644 index 0000000000000000000000000000000000000000..38b89762a75aa6ea616c30018711854ea7c128bb --- /dev/null +++ b/sglang/.github/workflows/pr-test-xpu.yml @@ -0,0 +1,145 @@ +name: PR Test (XPU) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + workflow_dispatch: + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + +concurrency: + group: pr-test-xpu-${{ inputs.ref || github.ref }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +jobs: + # ==================== Check Changes ==================== # + check-changes: + runs-on: ubuntu-latest + outputs: + main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || github.ref }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + if: steps.run-mode.outputs.run_all_tests != 'true' + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject_xpu.toml" + - "test/**" + - "sgl-kernel/**" + - ".github/workflows/pr-test-xpu.yml" + - "docker/xpu.Dockerfile" + + # ==================== PR Gate ==================== # + pr-gate: + needs: check-changes + if: needs.check-changes.outputs.main_package == 'true' + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + + build-and-test: + needs: [check-changes, pr-gate] + if: needs.check-changes.outputs.main_package == 'true' + runs-on: intel-bmg + env: + HF_HOME: /home/sdp/.cache/huggingface + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.ref || github.ref }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + run: | + PR_REPO=${{ github.event.pull_request.head.repo.clone_url }} + PR_HEAD_REF=${{ github.head_ref }} + docker build \ + ${PR_REPO:+--build-arg SG_LANG_REPO=$PR_REPO} \ + ${PR_HEAD_REF:+--build-arg SG_LANG_BRANCH=$PR_HEAD_REF} \ + --no-cache --progress=plain -f docker/xpu.Dockerfile -t xpu_sglang_main:bmg . + + - name: Run container + id: start_container + run: | + container_id=$(docker run -dt \ + --group-add 992 \ + --group-add $(getent group video | cut -d: -f3) \ + -v ${HF_HOME}:/root/.cache/huggingface \ + --device /dev/dri \ + -e HF_TOKEN="$(cat ~/huggingface_token.txt)" \ + xpu_sglang_main:bmg) + echo "Started container: $container_id" + echo "container_id=$container_id" >> "$GITHUB_OUTPUT" + + - name: Install Dependency + timeout-minutes: 20 + run: | + cid="${{ steps.start_container.outputs.container_id }}" + docker exec "$cid" /home/sdp/miniforge3/envs/py3.10/bin/python3 -m pip install --upgrade pip + docker exec "$cid" /home/sdp/miniforge3/envs/py3.10/bin/python3 -m pip install pytest expecttest ray huggingface_hub + docker exec "$cid" /home/sdp/miniforge3/envs/py3.10/bin/python3 -m pip uninstall -y flashinfer-python + docker exec "$cid" /bin/bash -c '/home/sdp/miniforge3/envs/py3.10/bin/hf auth login --token ${HF_TOKEN} ' + docker exec -u root "$cid" /bin/bash -c "ln -sf /home/sdp/miniforge3/envs/py3.10/bin/python3 /usr/bin/python3" + + - name: Run E2E Bfloat16 tests + timeout-minutes: 20 + run: | + cid="${{ steps.start_container.outputs.container_id }}" + docker exec -w /home/sdp/sglang/ "$cid" \ + bash -c "LD_LIBRARY_PATH=/home/sdp/miniforge3/envs/py3.10/lib:$LD_LIBRARY_PATH && cd ./test/srt && python3 run_suite.py --suite per-commit-xpu" + + - name: Cleanup container + if: always() + run: | + cid="${{ steps.start_container.outputs.container_id }}" + docker rm -f "$cid" || true + + finish: + if: always() + needs: [build-and-test, pr-gate] + runs-on: ubuntu-latest + steps: + - name: Check job status + run: | + result="${{ needs.build-and-test.result }}" + if [ "$result" != "success" ] && [ "$result" != "skipped" ]; then + echo "Job failed with result: $result" + exit 1 + fi + echo "All jobs completed successfully (result: $result)" + exit 0 diff --git a/sglang/.github/workflows/pr-test.yml b/sglang/.github/workflows/pr-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..abc7a0970e47bea7585dd47a0a5332fe6e08dbec --- /dev/null +++ b/sglang/.github/workflows/pr-test.yml @@ -0,0 +1,1738 @@ +name: PR Test +# Dynamic run-name for /rerun-stage commands to enable URL lookup +# Format: "[stage-name] sha" for fork PRs, "[stage-name]" for non-fork, default for normal runs +run-name: ${{ inputs.target_stage && (inputs.pr_head_sha && format('[{0}] {1}', inputs.target_stage, inputs.pr_head_sha) || format('[{0}]', inputs.target_stage)) || '' }} + +on: + schedule: + - cron: '0 */6 * * *' # Run every 6 hours + pull_request: + branches: [main] + workflow_dispatch: + inputs: + version: + description: "FlashInfer version" + required: true + type: choice + default: "release" + options: + - "release" + - "nightly" + target_stage: + description: "Specific stage to run (optional, for quick testing)" + required: false + type: string + default: "" + force_continue_on_error: + description: "Force continue-on-error (test scheduled CI behavior)" + required: false + type: boolean + default: false + pr_head_sha: + description: "PR head SHA to checkout (for /rerun-stage on fork PRs)" + required: false + type: string + default: "" + test_parallel_dispatch: + description: "Test parallel dispatch behavior (simulates scheduled run)" + required: false + type: boolean + default: false + workflow_call: + inputs: + ref: + description: 'Git ref (branch, tag, or SHA) to test. If not provided, uses the default branch.' + required: false + type: string + default: '' + run_all_tests: + description: "Run all tests (for releasing or testing purpose)" + required: false + type: boolean + default: false + +concurrency: + # Concurrency group structure: pr-test-{event}-{branch}-{pr_sha}-{stage} + # - event_name prevents scheduled runs from colliding with fork PRs whose branch is named 'main' + # (without it, both resolve the branch segment to 'main' and block each other) + # - github.head_ref (pull_request) or github.ref_name (workflow_dispatch) normalizes to branch name + # - pr_head_sha isolates /rerun-stage from main branch runs + # - target_stage allows parallel stage dispatches to run independently + group: pr-test-${{ github.event_name }}-${{ github.head_ref || github.ref_name || 'default' }}-${{ inputs.pr_head_sha || 'current' }}-${{ inputs.target_stage || inputs.ref || 'all' }} + cancel-in-progress: ${{ github.event_name != 'workflow_call' }} + +env: + SGLANG_IS_IN_CI: true + SGLANG_CUDA_COREDUMP: "1" + SGLANG_JIT_DEEPGEMM_FAST_WARMUP: true + +permissions: + actions: write + contents: read + pull-requests: read + +jobs: + # =============================================== check changes ==================================================== + check-changes: + runs-on: ubuntu-latest + outputs: + # Use API-based detection for target_stage mode (filter-api), otherwise use dorny/paths-filter (filter) + main_package: ${{ steps.filter-api.outputs.main_package || steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} + # sgl_kernel is forced to false when target_stage is set, since sgl-kernel-build-wheels won't run + # This prevents CUSTOM_BUILD_SGL_KERNEL=true when the wheel artifacts aren't available + # Note: If PR has kernel changes AND target_stage is set, the validate-target-stage step will fail + sgl_kernel: ${{ !inputs.target_stage && (steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel) }} + # Raw sgl_kernel value before target_stage override (used for validation) + sgl_kernel_raw: ${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel }} + jit_kernel: ${{ steps.filter-api.outputs.jit_kernel || steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} + multimodal_gen: ${{ steps.filter-api.outputs.multimodal_gen || steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} + max_parallel: ${{ steps.set-parallel.outputs.max_parallel }} + b200_runner: ${{ steps.set-runner.outputs.b200_runner }} + enable_retry: ${{ steps.set-retry.outputs.enable_retry }} + continue_on_error: ${{ steps.set-continue-on-error.outputs.continue_on_error }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Determine run mode + id: run-mode + run: | + # Run all tests for scheduled runs and workflow_call (when ref input is provided) + # Note: github.event_name is inherited from caller, so we detect workflow_call by checking inputs.ref + if [[ "${{ github.event_name }}" == "schedule" || "${{ inputs.run_all_tests }}" == "true" ]]; then + echo "run_all_tests=true" >> $GITHUB_OUTPUT + echo "Run mode: ALL TESTS (schedule=${{ github.event_name == 'schedule' }}, run_all_tests=${{ inputs.run_all_tests }})" + else + echo "run_all_tests=false" >> $GITHUB_OUTPUT + echo "Run mode: FILTERED (triggered by ${{ github.event_name }})" + fi + + - name: Detect file changes + id: filter + uses: dorny/paths-filter@v3 + # Only use paths-filter for pull_request events (where it works correctly) + # For workflow_dispatch with target_stage, we use GitHub API in the next step + if: steps.run-mode.outputs.run_all_tests != 'true' && !inputs.target_stage + with: + filters: | + main_package: + - "python/sglang/!(multimodal_gen)/**" + - "python/pyproject.toml" + - "scripts/ci/cuda/*" + - "scripts/ci/utils/*" + - "test/**" + - ".github/workflows/pr-test.yml" + sgl_kernel: + - "sgl-kernel/**" + jit_kernel: + - "python/sglang/jit_kernel/**" + - "python/pyproject.toml" + - ".github/workflows/pr-test.yml" + multimodal_gen: + - "python/sglang/multimodal_gen/**" + - "python/sglang/jit_kernel/**" + - "python/sglang/cli/**" + - "python/pyproject.toml" + - ".github/workflows/pr-test.yml" + + # For /rerun-stage (workflow_dispatch with target_stage), dorny/paths-filter doesn't work + # correctly because it falls back to "last commit" detection which breaks for merge commits. + # Instead, we use the GitHub API to compare the PR commit against main. + - name: Detect file changes via API (for target_stage) + id: filter-api + if: inputs.target_stage && inputs.pr_head_sha + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Detecting file changes via GitHub API for target_stage mode..." + echo "PR head SHA: ${{ inputs.pr_head_sha }}" + + # Get the list of changed files by comparing PR commit against main + # This correctly handles merge commits by looking at the actual PR diff + CHANGED_FILES=$(gh api "repos/${{ github.repository }}/compare/main...${{ inputs.pr_head_sha }}" \ + --jq '[.files[].filename] | .[]' 2>/dev/null || echo "") + + if [ -z "$CHANGED_FILES" ]; then + echo "Warning: Could not fetch changed files from API, assuming no changes" + echo "sgl_kernel=false" >> $GITHUB_OUTPUT + echo "main_package=false" >> $GITHUB_OUTPUT + echo "jit_kernel=false" >> $GITHUB_OUTPUT + echo "multimodal_gen=false" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "Changed files:" + echo "$CHANGED_FILES" | head -20 + echo "..." + + # Check for sgl-kernel changes + if echo "$CHANGED_FILES" | grep -q "^sgl-kernel/"; then + echo "sgl_kernel=true" >> $GITHUB_OUTPUT + echo "Detected sgl-kernel changes" + else + echo "sgl_kernel=false" >> $GITHUB_OUTPUT + fi + + # Check for main_package changes (excluding multimodal_gen) + # Note: Need to filter out multimodal_gen before checking, not pipe grep -q output + MAIN_PKG_FILES=$(echo "$CHANGED_FILES" | grep -E "^(python/sglang/|python/pyproject\.toml|scripts/ci/cuda/|scripts/ci/utils/|test/|\.github/workflows/pr-test\.yml)" | grep -v "^python/sglang/multimodal_gen/" || true) + if [ -n "$MAIN_PKG_FILES" ]; then + echo "main_package=true" >> $GITHUB_OUTPUT + echo "Detected main_package changes" + else + echo "main_package=false" >> $GITHUB_OUTPUT + fi + + # Check for jit_kernel changes + if echo "$CHANGED_FILES" | grep -qE "^(python/sglang/jit_kernel/|python/pyproject\.toml|\.github/workflows/pr-test\.yml)"; then + echo "jit_kernel=true" >> $GITHUB_OUTPUT + echo "Detected jit_kernel changes" + else + echo "jit_kernel=false" >> $GITHUB_OUTPUT + fi + + # Check for multimodal_gen changes + if echo "$CHANGED_FILES" | grep -qE "^(python/sglang/multimodal_gen/|python/sglang/cli/|python/pyproject\.toml|\.github/workflows/pr-test\.yml)"; then + echo "multimodal_gen=true" >> $GITHUB_OUTPUT + echo "Detected multimodal_gen changes" + else + echo "multimodal_gen=false" >> $GITHUB_OUTPUT + fi + + - name: Set max-parallel based on run type + id: set-parallel + env: + GH_TOKEN: ${{ github.token }} + run: | + # Scheduled runs and high-priority PRs get full parallelism + if [[ "${{ github.event_name }}" == "schedule" ]]; then + echo "max_parallel=14" >> $GITHUB_OUTPUT + echo "Scheduled run detected, setting max_parallel to 14" + elif [[ "${{ github.event_name }}" == "pull_request" && "${{ contains(github.event.pull_request.labels.*.name, 'high priority') }}" == "true" ]]; then + echo "max_parallel=14" >> $GITHUB_OUTPUT + echo "High priority PR detected, setting max_parallel to 14" + elif [[ -n "${{ inputs.target_stage }}" ]]; then + # /rerun-stage (workflow_dispatch): query PR labels via GitHub API + # Try SHA lookup first (fork PRs), fallback to branch name (non-fork PRs) + LABELS="" + PR_HEAD_SHA="${{ inputs.pr_head_sha }}" + if [[ -n "$PR_HEAD_SHA" ]]; then + LABELS=$(gh api "repos/${{ github.repository }}/commits/${PR_HEAD_SHA}/pulls" \ + --jq '.[0].labels[].name' 2>/dev/null || true) + fi + if [[ -z "$LABELS" ]]; then + LABELS=$(gh pr list --head "${{ github.ref_name }}" --repo "${{ github.repository }}" \ + --json labels --jq '.[0].labels[].name' 2>/dev/null || true) + fi + echo "PR labels: ${LABELS:-"(none)"}" + if echo "$LABELS" | grep -Fxq "high priority"; then + echo "max_parallel=14" >> $GITHUB_OUTPUT + echo "High priority PR detected via API (/rerun-stage), setting max_parallel to 14" + else + echo "max_parallel=3" >> $GITHUB_OUTPUT + echo "Using default max_parallel of 3 (/rerun-stage, no high priority label)" + fi + else + echo "max_parallel=3" >> $GITHUB_OUTPUT + echo "Using default max_parallel of 3" + fi + + - name: Set B200 runner tag + id: set-runner + run: | + # Use kernel-build runner only when sgl_kernel changes are detected AND we're not in target_stage mode + # (target_stage skips wheel builds, so we can't use custom kernels) + # Use API-based detection (filter-api) for target_stage mode, otherwise use dorny/paths-filter (filter) + sgl_kernel="${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel || steps.run-mode.outputs.run_all_tests }}" + target_stage="${{ inputs.target_stage }}" + if [[ "$sgl_kernel" == "true" && -z "$target_stage" ]]; then + echo "b200_runner=4-gpu-b200-kernel" >> $GITHUB_OUTPUT + else + echo "b200_runner=4-gpu-b200" >> $GITHUB_OUTPUT + fi + + - name: Enable retry for CI + id: set-retry + run: | + echo "enable_retry=true" >> $GITHUB_OUTPUT + echo "Retry logic enabled for CI" + + - name: Set continue-on-error for full test runs + id: set-continue-on-error + run: | + if [[ "${{ steps.run-mode.outputs.run_all_tests }}" == "true" || "${{ inputs.force_continue_on_error }}" == "true" ]]; then + echo "continue_on_error=true" >> $GITHUB_OUTPUT + echo "Full test run or force flag detected, enabling continue-on-error to run all tests" + else + echo "continue_on_error=false" >> $GITHUB_OUTPUT + echo "Filtered run, continue-on-error disabled" + fi + + - name: Validate target_stage with kernel changes + # Use API-based detection (filter-api) for target_stage mode, otherwise use dorny/paths-filter (filter) + if: inputs.target_stage && (steps.filter-api.outputs.sgl_kernel == 'true' || steps.filter.outputs.sgl_kernel == 'true') + run: | + echo "::error::Cannot use /rerun-stage when PR has sgl-kernel changes." + echo "::error::The sgl-kernel-build-wheels job is skipped in target_stage mode, but this PR modifies sgl-kernel/ files." + echo "::error::Please use /tag-and-rerun-ci to run the full workflow including kernel builds." + echo "" + echo "ERROR: Cannot use /rerun-stage when PR has sgl-kernel changes." + echo "" + echo "This PR modifies files in sgl-kernel/, which requires building custom kernel wheels." + echo "The /rerun-stage command skips the wheel build job, so the test would run against" + echo "the wrong (PyPI) version of sgl-kernel instead of your changes." + echo "" + echo "To properly test your kernel changes, use one of these commands instead:" + echo " /tag-and-rerun-ci - Re-run the full workflow including kernel builds" + echo " /rerun-ci - Re-run the full workflow" + echo "" + exit 1 + + - name: Show filter results in summary (table) + run: | + { + echo "## Change Detection" + echo "" + echo "| Component | Changed |" + echo "|-------------------|---------|" + echo "| main_package | ${{ steps.filter-api.outputs.main_package || steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }} |" + echo "| sgl_kernel (raw) | ${{ steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel }} |" + echo "| sgl_kernel (used) | ${{ !inputs.target_stage && (steps.filter-api.outputs.sgl_kernel || steps.filter.outputs.sgl_kernel) }} |" + echo "| jit_kernel | ${{ steps.filter-api.outputs.jit_kernel || steps.filter.outputs.jit_kernel || steps.run-mode.outputs.run_all_tests }} |" + echo "| multimodal_gen | ${{ steps.filter-api.outputs.multimodal_gen || steps.filter.outputs.multimodal_gen || steps.run-mode.outputs.run_all_tests }} |" + echo "| target_stage | ${{ inputs.target_stage || '(none)' }} |" + echo "| detection_method | ${{ inputs.target_stage && 'GitHub API' || 'dorny/paths-filter' }} |" + echo "| max_parallel | ${{ steps.set-parallel.outputs.max_parallel }} |" + echo "| b200_runner | ${{ steps.set-runner.outputs.b200_runner }} |" + echo "| enable_retry | ${{ steps.set-retry.outputs.enable_retry }} |" + echo "| continue_on_error | ${{ steps.set-continue-on-error.outputs.continue_on_error }} |" + } >> $GITHUB_STEP_SUMMARY + + # =============================================== Wait Jobs for Sequential PR Execution ==================================================== + # These jobs poll GitHub API to wait for previous stages to complete. + # For PR runs: wait jobs run and enforce sequential execution via polling. + # For scheduled runs: wait jobs are skipped, enabling parallel execution for easier retry. + + wait-for-stage-a: + needs: [check-changes, call-gate] + # Only run for PRs (not scheduled) and when not targeting a specific stage + # Skip if call-gate failed (stage-a jobs will be skipped, nothing to wait for) + # !cancelled() ensures this job respects workflow cancellation from concurrency group + if: | + always() && + !cancelled() && + github.event_name == 'pull_request' && + !inputs.target_stage && + inputs.test_parallel_dispatch != true && + (needs.check-changes.outputs.main_package == 'true' || needs.check-changes.outputs.sgl_kernel == 'true') && + (needs.call-gate.result == 'success' || needs.call-gate.result == 'skipped') + runs-on: ubuntu-latest + outputs: + stage_a_result: ${{ steps.wait.outputs.result }} + steps: + - name: Wait for stage-a-test-1 to complete + id: wait + uses: actions/github-script@v7 + with: + script: | + const maxWaitMinutes = 240; + const pollIntervalSeconds = 120; // 2 minutes to reduce GH API calls + const maxAttempts = (maxWaitMinutes * 60) / pollIntervalSeconds; + + for (let attempt = 0; attempt < maxAttempts; attempt++) { + const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, { + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId, + per_page: 100, + }); + + const stageAJob = jobs.find(job => job.name === 'stage-a-test-1'); + + if (stageAJob) { + console.log(`stage-a-test-1 status: ${stageAJob.status}, conclusion: ${stageAJob.conclusion}`); + + if (stageAJob.status === 'completed') { + if (stageAJob.conclusion === 'success' || stageAJob.conclusion === 'skipped') { + core.setOutput('result', stageAJob.conclusion === 'success' ? 'success' : 'skipped'); + return; + } else { + core.setOutput('result', 'failure'); + core.setFailed(`stage-a-test-1 ${stageAJob.conclusion}`); + return; + } + } + } else { + console.log('stage-a-test-1 job not found yet'); + } + + console.log(`Waiting ${pollIntervalSeconds}s... (attempt ${attempt + 1}/${maxAttempts})`); + await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000)); + } + + core.setFailed('Timeout waiting for stage-a-test-1'); + core.setOutput('result', 'timeout'); + + wait-for-stage-b: + needs: [check-changes, call-gate, wait-for-stage-a] + # Only run for PRs (not scheduled) and when not targeting a specific stage + # Skip if call-gate failed (stage-b jobs will be skipped, nothing to wait for) + if: | + always() && + !cancelled() && + github.event_name == 'pull_request' && + !inputs.target_stage && + inputs.test_parallel_dispatch != true && + (needs.check-changes.outputs.main_package == 'true' || needs.check-changes.outputs.sgl_kernel == 'true') && + (needs.wait-for-stage-a.result == 'success' || needs.wait-for-stage-a.result == 'skipped') && + (needs.call-gate.result == 'success' || needs.call-gate.result == 'skipped') + runs-on: ubuntu-latest + outputs: + stage_b_result: ${{ steps.wait.outputs.result }} + steps: + - name: Wait for stage-b jobs to complete + id: wait + uses: actions/github-script@v7 + with: + script: | + const maxWaitMinutes = 480; + const pollIntervalSeconds = 120; // 2 minutes to reduce GH API calls + const maxAttempts = (maxWaitMinutes * 60) / pollIntervalSeconds; + + // Stage-b jobs to wait for + const stageBJobs = [ + { prefix: 'stage-b-test-small-1-gpu', expectedCount: 8 }, // partitions 0-7 + { prefix: 'stage-b-test-large-1-gpu', expectedCount: 14 }, // partitions 0-13 + { prefix: 'stage-b-test-large-2-gpu', expectedCount: 4 }, // partitions 0-3 + { prefix: 'stage-b-test-4-gpu-b200', expectedCount: 1 }, + ]; + const totalExpectedJobs = stageBJobs.reduce((sum, j) => sum + j.expectedCount, 0); // 27 total + + // Helper to match job names exactly (prefix alone or prefix + " (N)" for matrix jobs) + const matchesPrefix = (jobName, prefix) => { + return jobName === prefix || jobName.startsWith(prefix + ' ('); + }; + + for (let attempt = 0; attempt < maxAttempts; attempt++) { + const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, { + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.runId, + per_page: 100, + }); + + let allCompleted = true; + let anyFailed = false; + let failedJobs = []; + let completedCount = 0; + let totalCount = 0; + + for (const { prefix, expectedCount } of stageBJobs) { + const matchingJobs = jobs.filter(job => matchesPrefix(job.name, prefix)); + + // Check existing jobs for failures first (fail fast) + for (const job of matchingJobs) { + totalCount++; + console.log(`${job.name}: status=${job.status}, conclusion=${job.conclusion}`); + + if (job.status !== 'completed') { + allCompleted = false; + } else { + completedCount++; + if (job.conclusion !== 'success' && job.conclusion !== 'skipped') { + anyFailed = true; + failedJobs.push(job.name); + } + } + } + + if (matchingJobs.length < expectedCount) { + console.log(`${prefix}: found ${matchingJobs.length}/${expectedCount} jobs (waiting for more)`); + allCompleted = false; + } + } + + console.log(`Progress: ${completedCount}/${totalCount} jobs completed (expected ${totalExpectedJobs})`); + + // Fail fast if any jobs failed (don't wait for all jobs to be created) + if (anyFailed) { + core.setOutput('result', 'failure'); + core.setFailed(`Stage-b jobs failed: ${failedJobs.join(', ')}`); + return; + } + + if (allCompleted && totalCount >= totalExpectedJobs) { + core.setOutput('result', 'success'); + return; + } + + console.log(`Waiting ${pollIntervalSeconds}s... (attempt ${attempt + 1}/${maxAttempts})`); + await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000)); + } + + core.setFailed('Timeout waiting for stage-b jobs'); + core.setOutput('result', 'timeout'); + + # =============================================== PR Gate ==================================================== + call-gate: + needs: check-changes + # Skip for scheduled runs (they run all tests) and when target_stage is specified + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + ( + needs.check-changes.outputs.main_package == 'true' || + needs.check-changes.outputs.sgl_kernel == 'true' || + needs.check-changes.outputs.jit_kernel == 'true' || + needs.check-changes.outputs.multimodal_gen == 'true' + ) + uses: ./.github/workflows/pr-gate.yml + secrets: inherit + + # =============================================== sgl-kernel ==================================================== + + sgl-kernel-build-wheels: + needs: [check-changes, call-gate] + # Skip for scheduled runs (they run stages independently) and when target_stage is set + if: github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && !inputs.target_stage && needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: x64-kernel-build-node + timeout-minutes: 240 + strategy: + matrix: + include: + - python-version: "3.10" + cuda-version: "12.9" + # Add back when CUDA 13.0 is supported on CI + # - python-version: "3.10" + # cuda-version: "13.0" + name: Build Wheel + steps: + - name: Cleanup + run: | + sudo rm -rf $GITHUB_WORKSPACE/* || true + + - uses: actions/checkout@v4 + with: + submodules: "recursive" + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build wheel for Python ${{ matrix.python-version }} and CUDA ${{ matrix.cuda-version }} + run: | + cd sgl-kernel + ./build.sh "${{ matrix.python-version }}" "${{ matrix.cuda-version }}" + env: + USE_CCACHE: 1 + + - name: Verify wheel artifacts + run: | + ls -alh sgl-kernel/dist + ls -alh sgl-kernel/dist/*.whl + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-cuda${{ matrix.cuda-version }} + path: sgl-kernel/dist/* + if-no-files-found: error + + sgl-kernel-build-wheels-arm: + needs: [check-changes, call-gate] + # Skip for scheduled runs (they run stages independently) and when target_stage is set + if: github.event_name != 'schedule' && inputs.test_parallel_dispatch != true && !inputs.target_stage && needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: arm-kernel-build-node + timeout-minutes: 240 + strategy: + matrix: + include: + - python-version: "3.10" + cuda-version: "12.9" + name: Build Wheel Arm + steps: + - name: Cleanup + run: | + if [ -d "$GITHUB_WORKSPACE" ]; then + sudo rm -rf "$GITHUB_WORKSPACE"/* || true + else + echo "$GITHUB_WORKSPACE does not exist, nothing to clean" + fi + + - uses: actions/checkout@v4 + with: + submodules: "recursive" + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build wheel for Python ${{ matrix.python-version }} and CUDA ${{ matrix.cuda-version }} + run: | + cd sgl-kernel + ./build.sh "${{ matrix.python-version }}" "${{ matrix.cuda-version }}" + env: + USE_CCACHE: 1 + + - name: Verify wheel artifacts + run: | + ls -alh sgl-kernel/dist + ls -alh sgl-kernel/dist/*.whl + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}-aarch64 + path: sgl-kernel/dist/* + if-no-files-found: error + + sgl-kernel-unit-test: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + # Skip for scheduled runs and when target_stage is set + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-runner + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Cleanup + run: | + ls -alh sgl-kernel/dist || true + rm -rf sgl-kernel/dist/* || true + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh diffusion + + - name: Run test + timeout-minutes: 30 + run: | + cd sgl-kernel + pytest tests/ + + sgl-kernel-mla-test: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + # Skip for scheduled runs and when target_stage is set + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-runner + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Cleanup + run: | + ls -alh sgl-kernel/dist || true + rm -rf sgl-kernel/dist/* || true + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd test/registered/mla + python3 test_mla_deepseek_v3.py + + sgl-kernel-benchmark-test: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + # Skip for scheduled runs and when target_stage is set + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + CI: true + RUNNER_LABELS: 1-gpu-runner + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Cleanup + run: | + ls -alh sgl-kernel/dist || true + rm -rf sgl-kernel/dist/* || true + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run benchmark tests + timeout-minutes: 45 + run: | + cd sgl-kernel/benchmark + echo "Running sgl-kernel benchmark tests in CI mode..." + + echo "CI environment variable: $CI" + echo "GITHUB_ACTIONS environment variable: $GITHUB_ACTIONS" + + for bench_file in bench_*.py; do + echo "Testing $bench_file..." + timeout 60 python3 "$bench_file" || echo "Warning: $bench_file timed out or failed, continuing..." + echo "Completed $bench_file" + echo "---" + done + + echo "All benchmark tests completed!" + + sgl-kernel-b200-test: + needs: [check-changes, sgl-kernel-build-wheels] + # Skip for scheduled runs and when target_stage is set + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + needs.check-changes.outputs.sgl_kernel == 'true' + runs-on: ${{ needs.check-changes.outputs.b200_runner }} + timeout-minutes: 240 + env: + RUNNER_LABELS: ${{ needs.check-changes.outputs.b200_runner }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Cleanup + run: | + ls -alh sgl-kernel/dist || true + rm -rf sgl-kernel/dist/* || true + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh diffusion + + - name: Run sgl-kernel unit tests on B200 + timeout-minutes: 30 + run: | + cd sgl-kernel + pytest tests/ + + # Adding a single CUDA13 smoke test to verify that the kernel builds and runs + # TODO: Add back this test when it can pass on CI + # cuda13-kernel-smoke-test: + # needs: [check-changes, sgl-kernel-build-wheels] + # if: needs.check-changes.outputs.sgl_kernel == 'true' + # runs-on: x64-cu13-kernel-tests + # steps: + # - uses: actions/checkout@v4 + + # - name: Cleanup + # run: | + # ls -alh sgl-kernel/dist || true + # rm -rf sgl-kernel/dist/* || true + + # - name: Download CUDA 13.0 artifacts + # uses: actions/download-artifact@v4 + # with: + # path: sgl-kernel/dist/ + # merge-multiple: true + # pattern: wheel-python3.10-cuda13.0 + + # - name: Install dependencies + # run: | + # CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + # - name: Run kernel unit tests + # timeout-minutes: 30 + # run: | + # cd sgl-kernel + # pytest tests/ + + # =============================================== jit-kernel ==================================================== + + jit-kernel-unit-test: + needs: [check-changes, call-gate] + # Skip for scheduled runs and when target_stage is set + if: | + github.event_name != 'schedule' && + inputs.test_parallel_dispatch != true && + !inputs.target_stage && + needs.check-changes.outputs.jit_kernel == 'true' + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-runner + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Install dependencies + timeout-minutes: 20 + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd python/sglang/jit_kernel + pytest tests/ + + # =============================================== primary ==================================================== + + stage-a-test-1: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'stage-a-test-1') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-runner + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 10 + run: | + cd test/ + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-a-test-1 $CONTINUE_ON_ERROR_FLAG + # temporarily put backend-independent cpu tests here + python3 run_suite.py --hw cpu --suite default $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + stage-a-cpu-only: + needs: [check-changes, call-gate] + if: | + always() && + ( + (inputs.target_stage == 'stage-a-cpu-only') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + (needs.check-changes.outputs.main_package == 'true') + ) + ) + runs-on: ubuntu-latest + timeout-minutes: 240 + steps: + - name: Free disk space + run: | + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc + df -h + + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + timeout-minutes: 20 + run: | + pip install -e "python/[dev]" + + - name: Run test + timeout-minutes: 10 + run: | + cd test/ + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cpu --suite stage-a-cpu-only $CONTINUE_ON_ERROR_FLAG + + # Runs on 5090 (32GB, SM120) + stage-b-test-small-1-gpu: + needs: [check-changes, call-gate, wait-for-stage-a, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'stage-b-test-small-1-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 1-gpu-5090 + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-5090 + IS_BLACKWELL: "1" + strategy: + fail-fast: false + max-parallel: 8 + matrix: + partition: [0, 1, 2, 3, 4, 5, 6, 7] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + source /etc/profile.d/sglang-ci.sh + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + git clone https://github.com/merrymercy/human-eval.git + cd human-eval + pip install -e . --no-build-isolation + + - name: Run test + timeout-minutes: 30 + run: | + source /etc/profile.d/sglang-ci.sh + cd test/ + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-b-test-small-1-gpu --auto-partition-id ${{ matrix.partition }} --auto-partition-size 8 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.partition }} + + # Runs on H100 (80GB, SM90) - tests that don't pass on 5090 (FA3, FP8, high VRAM, etc.) + stage-b-test-large-1-gpu: + needs: [check-changes, call-gate, wait-for-stage-a, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'stage-b-test-large-1-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 1-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 1-gpu-runner + strategy: + fail-fast: false + max-parallel: ${{ fromJson(needs.check-changes.outputs.max_parallel) }} + matrix: + partition: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd test/ + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-b-test-large-1-gpu --auto-partition-id ${{ matrix.partition }} --auto-partition-size 14 --timeout-per-file 1800 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.partition }} + + stage-b-test-large-2-gpu: + needs: [check-changes, call-gate, wait-for-stage-a, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'stage-b-test-large-2-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 2-gpu-runner + timeout-minutes: 240 + env: + RUNNER_LABELS: 2-gpu-runner + strategy: + fail-fast: false + matrix: + partition: [0, 1, 2, 3] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + git clone https://github.com/merrymercy/human-eval.git + cd human-eval + pip install -e . --no-build-isolation + + - name: Run test + timeout-minutes: 30 + run: | + cd test/ + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-b-test-large-2-gpu --auto-partition-id ${{ matrix.partition }} --auto-partition-size 4 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.partition }} + + stage-b-test-4-gpu-b200: + needs: [check-changes, call-gate, wait-for-stage-a, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'stage-b-test-4-gpu-b200') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: ${{ needs.check-changes.outputs.b200_runner }} + timeout-minutes: 240 + env: + RUNNER_LABELS: ${{ needs.check-changes.outputs.b200_runner }} + strategy: + fail-fast: false + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v6 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + IS_BLACKWELL=1 python3 run_suite.py --hw cuda --suite stage-b-test-4-gpu-b200 $CONTINUE_ON_ERROR_FLAG + + - name: Run FA4 jit_kernel tests (SM100+) + timeout-minutes: 10 + run: | + IS_BLACKWELL=1 python3 -m pytest -q python/sglang/jit_kernel/tests/test_flash_attention_4.py + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + multimodal-gen-test-1-gpu: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'multimodal-gen-test-1-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + needs.check-changes.outputs.multimodal_gen == 'true' + ) + ) + runs-on: 1-gpu-runner + timeout-minutes: 240 + strategy: + fail-fast: false + matrix: + part: [0, 1] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh diffusion + - name: Run diffusion server tests + timeout-minutes: 240 + env: + RUNAI_STREAMER_MEMORY_LIMIT: 0 + run: | + cd python + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 1-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + multimodal-gen-test-2-gpu: + needs: [check-changes, call-gate, sgl-kernel-build-wheels] + if: | + always() && + ( + (inputs.target_stage == 'multimodal-gen-test-2-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + needs.check-changes.outputs.multimodal_gen == 'true' + ) + ) + runs-on: 2-gpu-runner + timeout-minutes: 240 + strategy: + fail-fast: false + matrix: + part: [0, 1] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh diffusion + + - name: Run diffusion server tests + timeout-minutes: 240 + env: + RUNAI_STREAMER_MEMORY_LIMIT: 0 + run: | + cd python + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 sglang/multimodal_gen/test/run_suite.py \ + --suite 2-gpu \ + --partition-id ${{ matrix.part }} \ + --total-partitions 2 \ + $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + stage-c-test-4-gpu-h100: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-4-gpu-h100') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 4-gpu-h100 + timeout-minutes: 240 + env: + RUNNER_LABELS: 4-gpu-h100 + strategy: + fail-fast: false + matrix: + part: [0, 1, 2] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 20 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-c-test-4-gpu-h100 --auto-partition-id ${{ matrix.part }} --auto-partition-size 3 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + stage-c-test-8-gpu-h200: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-8-gpu-h200') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 8-gpu-h200 + timeout-minutes: 240 + env: + RUNNER_LABELS: 8-gpu-h200 + strategy: + fail-fast: false + matrix: + part: [0, 1, 2, 3] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Warmup DeepGEMM JIT Compilation + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_deep_gemm.py \ + deepseek-ai/DeepSeek-V3-0324:8 \ + deepseek-ai/DeepSeek-V3.2-Exp:8 + + - name: Warmup Server CUDA Graphs + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_server.py \ + deepseek-ai/DeepSeek-V3-0324:8 \ + inclusionAI/Ring-2.5-1T:8 + + - name: Run test + timeout-minutes: 30 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-c-test-8-gpu-h200 --auto-partition-id ${{ matrix.part }} --auto-partition-size 4 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + stage-c-test-8-gpu-h20: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-8-gpu-h20') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 8-gpu-h20 + timeout-minutes: 240 + env: + SGLANG_CI_RDMA_ALL_DEVICES: "mlx5_1,mlx5_2,mlx5_3,mlx5_4" + RUNNER_LABELS: 8-gpu-h20 + strategy: + fail-fast: false + matrix: + part: [0, 1] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_deepep.sh + + - name: Run test + timeout-minutes: 20 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-c-test-8-gpu-h20 --auto-partition-id ${{ matrix.part }} --auto-partition-size 2 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + stage-c-test-deepep-4-gpu: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-deepep-4-gpu') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 4-gpu-h100 + timeout-minutes: 240 + env: + RUNNER_LABELS: 4-gpu-h100 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_deepep.sh + + - name: Warmup DeepGEMM JIT Compilation + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_deep_gemm.py \ + lmsys/sglang-ci-dsv3-test:4 + + - name: Warmup Server CUDA Graphs + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_server.py \ + lmsys/sglang-ci-dsv3-test:4 + + - name: Run test + timeout-minutes: 20 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-c-test-deepep-4-gpu $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + stage-c-test-deepep-8-gpu-h200: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-deepep-8-gpu-h200') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: 8-gpu-h200 + timeout-minutes: 240 + env: + RUNNER_LABELS: 8-gpu-h200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_deepep.sh + + - name: Warmup DeepGEMM JIT Compilation + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_deep_gemm.py \ + deepseek-ai/DeepSeek-V3-0324:8 \ + deepseek-ai/DeepSeek-V3.2-Exp:8 + + - name: Warmup Server CUDA Graphs + timeout-minutes: 25 + run: | + python3 scripts/ci/cuda/warmup_server.py \ + deepseek-ai/DeepSeek-V3-0324:8 + + - name: Run test + timeout-minutes: 45 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + python3 run_suite.py --hw cuda --suite stage-c-test-deepep-8-gpu-h200 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + + stage-c-test-4-gpu-b200: + needs: [check-changes, call-gate, wait-for-stage-b] + if: | + always() && + ( + (inputs.target_stage == 'stage-c-test-4-gpu-b200') || + ( + !inputs.target_stage && + ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + ) + ) + runs-on: ${{ needs.check-changes.outputs.b200_runner }} + timeout-minutes: 240 + env: + RUNNER_LABELS: ${{ needs.check-changes.outputs.b200_runner }} + strategy: + fail-fast: false + matrix: + part: [0, 1, 2] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + + - name: Download artifacts + if: needs.check-changes.outputs.sgl_kernel == 'true' + uses: actions/download-artifact@v6 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-python3.10-cuda12.9 + + - name: Install dependencies + timeout-minutes: 20 + run: | + CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} IS_BLACKWELL=1 bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run test + timeout-minutes: 30 + run: | + cd test + CONTINUE_ON_ERROR_FLAG="" + if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + CONTINUE_ON_ERROR_FLAG="--continue-on-error" + fi + IS_BLACKWELL=1 python3 run_suite.py --hw cuda --suite stage-c-test-4-gpu-b200 --auto-partition-id ${{ matrix.part }} --auto-partition-size 3 --timeout-per-file 1800 $CONTINUE_ON_ERROR_FLAG + + - uses: ./.github/actions/upload-cuda-coredumps + if: always() + with: + artifact-suffix: ${{ matrix.part }} + + # NOTE: GB200 stage temporarily disabled — no company-owned GB200 runner available yet. + # Re-enable when a 4-gpu-gb200 runner is provisioned. + # stage-c-test-4-gpu-gb200: + # needs: [check-changes, call-gate, wait-for-stage-b, sgl-kernel-build-wheels-arm] + # if: | + # always() && + # ( + # (inputs.target_stage == 'stage-c-test-4-gpu-gb200') || + # ( + # !inputs.target_stage && + # ((github.event_name == 'schedule' || inputs.test_parallel_dispatch == true) || (!failure() && !cancelled())) && + # ((needs.check-changes.outputs.main_package == 'true') || (needs.check-changes.outputs.sgl_kernel == 'true')) + # ) + # ) + # runs-on: 4-gpu-gb200 + # timeout-minutes: 240 + # env: + # RUNNER_LABELS: 4-gpu-gb200 + # strategy: + # fail-fast: false + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + # with: + # ref: ${{ inputs.pr_head_sha || inputs.ref || github.sha }} + # + # - name: Download artifacts + # if: needs.check-changes.outputs.sgl_kernel == 'true' + # uses: actions/download-artifact@v4 + # with: + # path: sgl-kernel/dist/ + # merge-multiple: true + # pattern: wheel-python3.10-cuda12.9-aarch64 + # + # - name: Install dependencies + # timeout-minutes: 20 + # run: | + # CUSTOM_BUILD_SGL_KERNEL=${{needs.check-changes.outputs.sgl_kernel}} IS_BLACKWELL=1 GRACE_BLACKWELL=1 bash scripts/ci/cuda/ci_install_deepep.sh + # + # - name: Run test + # timeout-minutes: 45 + # run: | + # cd test + # CONTINUE_ON_ERROR_FLAG="" + # if [[ "${{ needs.check-changes.outputs.continue_on_error }}" == "true" ]]; then + # CONTINUE_ON_ERROR_FLAG="--continue-on-error" + # fi + # python3 run_suite.py --hw cuda --suite stage-c-test-4-gpu-gb200 --timeout-per-file 3600 $CONTINUE_ON_ERROR_FLAG + # + # - uses: ./.github/actions/upload-cuda-coredumps + # if: always() + + pr-test-finish: + needs: + [ + call-gate, + check-changes, + + sgl-kernel-build-wheels, + sgl-kernel-unit-test, + sgl-kernel-mla-test, + sgl-kernel-benchmark-test, + sgl-kernel-b200-test, + + wait-for-stage-a, + wait-for-stage-b, + + jit-kernel-unit-test, + + multimodal-gen-test-1-gpu, + multimodal-gen-test-2-gpu, + + stage-a-test-1, + stage-a-cpu-only, + stage-b-test-small-1-gpu, + stage-b-test-large-1-gpu, + stage-b-test-large-2-gpu, + stage-b-test-4-gpu-b200, + stage-c-test-4-gpu-h100, + stage-c-test-8-gpu-h20, + stage-c-test-8-gpu-h200, + stage-c-test-deepep-4-gpu, + stage-c-test-deepep-8-gpu-h200, + stage-c-test-4-gpu-b200, + # stage-c-test-4-gpu-gb200, # Temporarily disabled — no GB200 runner + ] + if: always() + runs-on: ubuntu-latest + steps: + - name: Check all dependent job statuses + run: | + # Convert the 'needs' context to a JSON string + json_needs='${{ toJson(needs) }}' + + # Get a list of all job names from the JSON keys + job_names=$(echo "$json_needs" | jq -r 'keys_unsorted[]') + + for job in $job_names; do + # For each job, extract its result + result=$(echo "$json_needs" | jq -r --arg j "$job" '.[$j].result') + + # Print the job name and its result + echo "$job: $result" + + # Check for failure or cancellation and exit if found + if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then + echo "The above jobs failed." + exit 1 + fi + done + # If the loop completes, all jobs were successful + echo "All jobs completed successfully" + exit 0 diff --git a/sglang/.github/workflows/release-docker-amd-nightly.yml b/sglang/.github/workflows/release-docker-amd-nightly.yml new file mode 100644 index 0000000000000000000000000000000000000000..b07d473e9bb0bbfb9ec93759fc4340b07984f318 --- /dev/null +++ b/sglang/.github/workflows/release-docker-amd-nightly.yml @@ -0,0 +1,170 @@ +name: Release Docker Images Nightly (AMD) +on: + workflow_dispatch: + schedule: + - cron: '0 12 * * *' + +concurrency: + # A PR number if a pull request and otherwise the commit hash. This cancels + # queued and in-progress runs for the same PR (presubmit) or commit + # (postsubmit). The workflow name is prepended to avoid conflicts between + # different workflows. + group: ${{ github.workflow }}-${{ github.event.number || github.sha }} + cancel-in-progress: true + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: amd-docker-scale + environment: 'prod' + strategy: + fail-fast: false + matrix: + gpu_arch: ['gfx942', 'gfx950'] + build_type: ['all'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git describe to find tags + + - name: "Set Date" + run: | + echo "DATE=$(date +%Y%m%d)" >> $GITHUB_ENV + + - name: Get version from latest tag + id: version + run: | + # Get the latest version tag sorted by version number (e.g., v0.5.7 -> 0.5.7) + VERSION=$(git tag -l 'v[0-9]*' --sort=-v:refname | head -1 | sed 's/^v//') + + if [ -z "$VERSION" ]; then + echo "::error::Could not determine version from git tags" + exit 1 + fi + + # Get short commit hash of current HEAD + COMMIT_HASH=$(git rev-parse --short HEAD) + + # Compose pretend version for setuptools_scm: e.g., 0.5.8.dev20260129+g1a2b3c4 + PRETEND_VERSION="${VERSION}.dev${{ env.DATE }}+g${COMMIT_HASH}" + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "pretend_version=${PRETEND_VERSION}" >> $GITHUB_OUTPUT + echo "Detected version: ${VERSION}" + echo "Pretend version for pip: ${PRETEND_VERSION}" + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_AMD_USERNAME }} + password: ${{ secrets.DOCKERHUB_AMD_TOKEN }} + + - name: Build and Push + run: | + version=${{ steps.version.outputs.version }} + pretend_version=${{ steps.version.outputs.pretend_version }} + echo "Version: ${version}" + echo "Pretend version: ${pretend_version}" + + if [ "${{ matrix.gpu_arch }}" = "gfx942" ]; then + rocm_tag="rocm700-mi30x" + elif [ "${{ matrix.gpu_arch }}" = "gfx950" ]; then + rocm_tag="rocm700-mi35x" + else + echo "Unsupported gfx arch" + exit 1 + fi + + tag=v${version}-${rocm_tag} + + docker build . -f docker/rocm.Dockerfile --build-arg SGL_BRANCH=${{ github.ref_name }} --build-arg BUILD_TYPE=${{ matrix.build_type }} --build-arg GPU_ARCH=${{ matrix.gpu_arch }} --build-arg ENABLE_MORI=1 --build-arg NIC_BACKEND=ainic --build-arg SETUPTOOLS_SCM_PRETEND_VERSION=${pretend_version} -t rocm/sgl-dev:${tag}-${{ env.DATE }} --no-cache + docker push rocm/sgl-dev:${tag}-${{ env.DATE }} + + # Temporarily disable docker cache seeding until performant storage is in place + cache: + if: false + # if: always() && github.repository == 'sgl-project/sglang' + runs-on: linux-mi300-gpu-1 + environment: 'prod' + needs: publish + strategy: + fail-fast: false + matrix: + gpu_arch: ['gfx942'] + build_type: ['all'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git describe to find tags + + - name: "Set Date" + run: | + echo "DATE=$(date +%Y%m%d)" >> $GITHUB_ENV + + - name: Get version from latest tag + id: version + run: | + # Get the latest version tag sorted by version number (e.g., v0.5.7 -> 0.5.7) + VERSION=$(git tag -l 'v[0-9]*' --sort=-v:refname | head -1 | sed 's/^v//') + + if [ -z "$VERSION" ]; then + echo "::error::Could not determine version from git tags" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "Detected version: ${VERSION}" + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_AMD_USERNAME }} + password: ${{ secrets.DOCKERHUB_AMD_TOKEN }} + + - name: Pull and Save Docker Image to Cache + run: | + set -euxo pipefail + + version=${{ steps.version.outputs.version }} + echo "Version: ${version}" + + if [ "${{ matrix.gpu_arch }}" = "gfx942" ]; then + rocm_tag="rocm700-mi30x" + else + echo "Unsupported gfx arch" + exit 1 + fi + + tag=v${version}-${rocm_tag} + + if [ "${{ matrix.build_type }}" = "all" ]; then + tag_suffix="" + else + echo "Unsupported build type" + exit 1 + fi + + image="rocm/sgl-dev:${tag}-${{ env.DATE }}${tag_suffix}" + + # Determine target cache file name based on ROCm variant + if [[ "${rocm_tag}" == rocm700* ]]; then + final_path="/home/runner/sgl-data/docker/image-700.tar" + else + echo "Unexpected ROCm tag: ${rocm_tag}" + exit 1 + fi + + tmp_path="${final_path}.tmp" + + echo "Pulling image: ${image}" + docker pull "${image}" + + echo "Saving to temp file: ${tmp_path}" + docker save "${image}" -o "${tmp_path}" + + echo "Moving to final path: ${final_path}" + mv -f "${tmp_path}" "${final_path}" + + echo "Cache populated successfully at ${final_path}" diff --git a/sglang/.github/workflows/release-docker-amd-rocm720-nightly.yml b/sglang/.github/workflows/release-docker-amd-rocm720-nightly.yml new file mode 100644 index 0000000000000000000000000000000000000000..376817f8fa9fa49b23cabbedd1b26387d127f8d8 --- /dev/null +++ b/sglang/.github/workflows/release-docker-amd-rocm720-nightly.yml @@ -0,0 +1,82 @@ +name: Release Docker Images ROCm 7.2.0 Nightly Preview (AMD) +on: + workflow_dispatch: + schedule: + - cron: '0 12 * * *' + +concurrency: + # A PR number if a pull request and otherwise the commit hash. This cancels + # queued and in-progress runs for the same PR (presubmit) or commit + # (postsubmit). The workflow name is prepended to avoid conflicts between + # different workflows. + group: ${{ github.workflow }}-${{ github.event.number || github.sha }} + cancel-in-progress: True + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: amd-docker-scale + environment: 'prod' + strategy: + fail-fast: false + matrix: + gpu_arch: ['gfx942-rocm720', 'gfx950-rocm720'] + build_type: ['all'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git describe to find tags + + - name: "Set Date" + run: | + echo "DATE=$(date +%Y%m%d)" >> $GITHUB_ENV + + - name: Get version from latest tag + id: version + run: | + # Get the latest version tag sorted by version number (e.g., v0.5.7 -> 0.5.7) + VERSION=$(git tag -l 'v[0-9]*' --sort=-v:refname | head -1 | sed 's/^v//') + + if [ -z "$VERSION" ]; then + echo "::error::Could not determine version from git tags" + exit 1 + fi + + # Get short commit hash of current HEAD + COMMIT_HASH=$(git rev-parse --short HEAD) + + # Compose pretend version for setuptools_scm: e.g., 0.5.8.post1.dev20260211+g1a2b3c4 + PRETEND_VERSION="${VERSION}.dev${{ env.DATE }}+g${COMMIT_HASH}" + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "pretend_version=${PRETEND_VERSION}" >> $GITHUB_OUTPUT + echo "Detected version: ${VERSION}" + echo "Pretend version for pip: ${PRETEND_VERSION}" + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_AMD_USERNAME }} + password: ${{ secrets.DOCKERHUB_AMD_TOKEN }} + + - name: Build and Push + run: | + version=${{ steps.version.outputs.version }} + pretend_version=${{ steps.version.outputs.pretend_version }} + echo "Version: ${version}" + echo "Pretend version: ${pretend_version}" + + if [ "${{ matrix.gpu_arch }}" = "gfx942-rocm720" ]; then + rocm_tag="rocm720-mi30x" + elif [ "${{ matrix.gpu_arch }}" = "gfx950-rocm720" ]; then + rocm_tag="rocm720-mi35x" + else + echo "Unsupported gfx arch" + exit 1 + fi + + tag=v${version}-${rocm_tag} + + docker build . -f docker/rocm.Dockerfile --build-arg SGL_BRANCH=${{ github.ref_name }} --build-arg BUILD_TYPE=${{ matrix.build_type }} --build-arg GPU_ARCH=${{ matrix.gpu_arch }} --build-arg ENABLE_MORI=1 --build-arg NIC_BACKEND=ainic --build-arg SETUPTOOLS_SCM_PRETEND_VERSION=${pretend_version} -t rocm/sgl-dev:${tag}-${{ env.DATE }} --no-cache + docker push rocm/sgl-dev:${tag}-${{ env.DATE }} diff --git a/sglang/.github/workflows/release-docker-amd.yml b/sglang/.github/workflows/release-docker-amd.yml new file mode 100644 index 0000000000000000000000000000000000000000..28c0edc15e5aff561d433dd81a15aa1028c71454 --- /dev/null +++ b/sglang/.github/workflows/release-docker-amd.yml @@ -0,0 +1,88 @@ +name: Release Docker Images (AMD) +on: + push: + tags: + - 'v[0-9]+.*' + workflow_dispatch: + inputs: + version: + description: 'Version to build (without v prefix, e.g., 0.5.7)' + required: true + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: amd-docker-scale + environment: 'prod' + strategy: + matrix: + rocm_version: ['rocm700', 'rocm720'] + gpu_arch: ['gfx942', 'gfx950'] + build_type: ['all'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build and Push + run: | + version=${{ steps.version.outputs.version }} + echo "Version: ${version}" + + gpu_arch_suffix="" + if [ "${{ matrix.rocm_version }}" = "rocm700" ]; then + if [ "${{ matrix.gpu_arch }}" = "gfx942" ]; then + rocm_tag="rocm700-mi30x" + elif [ "${{ matrix.gpu_arch }}" = "gfx950" ]; then + rocm_tag="rocm700-mi35x" + else + echo "Unsupported gfx arch" + exit 1 + fi + elif [ "${{ matrix.rocm_version }}" = "rocm720" ]; then + gpu_arch_suffix="-${{ matrix.rocm_version }}" + if [ "${{ matrix.gpu_arch }}" = "gfx942" ]; then + rocm_tag="rocm720-mi30x" + elif [ "${{ matrix.gpu_arch }}" = "gfx950" ]; then + rocm_tag="rocm720-mi35x" + else + echo "Unsupported gfx arch" + exit 1 + fi + else + echo "Unsupported rocm version" + exit 1 + fi + + tag=v${version}-${rocm_tag} + + # rocm.Dockerfile expects SGL_BRANCH with 'v' prefix for git tag checkout + docker build . -f docker/rocm.Dockerfile --build-arg BUILD_TYPE=${{ matrix.build_type }} --build-arg GPU_ARCH=${{ matrix.gpu_arch }}${gpu_arch_suffix} --build-arg SGL_BRANCH=v${version} --build-arg ENABLE_MORI=1 --build-arg NIC_BACKEND=ainic -t lmsysorg/sglang:${tag} --no-cache + docker push lmsysorg/sglang:${tag} diff --git a/sglang/.github/workflows/release-docker-cu13-framework.yml b/sglang/.github/workflows/release-docker-cu13-framework.yml new file mode 100644 index 0000000000000000000000000000000000000000..a0800b7fe45576a75b34855dbe1abfec8564653f --- /dev/null +++ b/sglang/.github/workflows/release-docker-cu13-framework.yml @@ -0,0 +1,156 @@ +name: Release CUDA 13 Framework Docker Images (Temporary) + +# Temporary workflow to build only versioned cu13 framework images +# Can be deleted after use + +on: + workflow_dispatch: + inputs: + version: + description: "Version to build (without v prefix, e.g., 0.5.8)" + required: true +jobs: + publish-x86: + if: github.repository == 'sgl-project/sglang' + runs-on: x64-docker-build-node + steps: + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Free disk space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + docker-images: false + android: true + dotnet: true + haskell: true + large-packages: true + swap-storage: false + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Validate version + id: version + run: | + VERSION="${{ github.event.inputs.version }}" + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build and Push AMD64 Framework (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-amd64 + + docker buildx build \ + --target framework \ + --platform linux/amd64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=all \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg GRACE_BLACKWELL=0 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + publish-arm64: + if: github.repository == 'sgl-project/sglang' + runs-on: arm-docker-build-node + steps: + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Validate version + id: version + run: | + VERSION="${{ github.event.inputs.version }}" + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build and Push ARM64 Framework (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-arm64 + + docker buildx build \ + --target framework \ + --platform linux/arm64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=all \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg GRACE_BLACKWELL=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + create-manifest: + runs-on: ubuntu-22.04 + needs: [publish-x86, publish-arm64] + if: github.repository == 'sgl-project/sglang' + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Create multi-arch manifest + run: | + version=${{ github.event.inputs.version }} + + # Create versioned CUDA 13 framework manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:v${version}-cu130 \ + lmsysorg/sglang:v${version}-cu130-amd64 \ + lmsysorg/sglang:v${version}-cu130-arm64 + + # Create latest CUDA 13 framework manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:latest-cu130 \ + lmsysorg/sglang:v${version}-cu130-amd64 \ + lmsysorg/sglang:v${version}-cu130-arm64 diff --git a/sglang/.github/workflows/release-docker-dev.yml b/sglang/.github/workflows/release-docker-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..18dbed5734c9bee63f670d652ca3d68ac729119d --- /dev/null +++ b/sglang/.github/workflows/release-docker-dev.yml @@ -0,0 +1,197 @@ +name: Build and Push Development Docker Images + +on: + workflow_dispatch: + inputs: + pr_number: + description: "PR number to build from (leave empty to use current branch)" + required: false + default: "" + tag: + description: "Custom tag suffix (overrides pr_number in tag). E.g. 'my-test' → dev-x86-my-test, dev-cu13-my-test, etc." + required: false + default: "" + schedule: + - cron: "0 0 * * *" + +concurrency: + group: release-docker-dev-${{ inputs.tag || inputs.pr_number || 'nightly' }} + cancel-in-progress: true + +jobs: + build-dev: + if: ${{ github.repository == 'sgl-project/sglang' }} + runs-on: ${{ matrix.runner }} + strategy: + matrix: + include: + - runner: x64-docker-build-node + platform: linux/amd64 + build_type: all + grace_blackwell: 0 + arch_tag: x86 + version: 12.9.1 + - runner: arm-docker-build-node + platform: linux/arm64 + build_type: all + grace_blackwell: 1 + arch_tag: arm64 + version: 12.9.1 + - runner: x64-docker-build-node + platform: linux/amd64 + build_type: all + grace_blackwell: 0 + arch_tag: x86-cu13 + version: 13.0.1 + - runner: arm-docker-build-node + platform: linux/arm64 + build_type: all + grace_blackwell: 1 + arch_tag: arm64-cu13 + version: 13.0.1 + steps: + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || github.ref }} + + - name: Free disk space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: true + docker-images: true + android: true + dotnet: true + haskell: true + large-packages: true + swap-storage: true + + - name: Prune Docker to reclaim disk space + run: | + docker buildx prune --filter "until=72h" -f + docker system prune -af --filter "until=72h" + docker volume prune -af + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and Push Dev Image + run: | + # Tag suffix: custom tag > pr number > none + SUFFIX="" + if [ -n "${{ inputs.tag }}" ]; then + SUFFIX="-${{ inputs.tag }}" + elif [ -n "${{ inputs.pr_number }}" ]; then + SUFFIX="-pr-${{ inputs.pr_number }}" + fi + + TAG="dev-${{ matrix.arch_tag }}${SUFFIX}" + + # Nightly (schedule) installs latest release; manual dispatch builds from checked-out source + if [ "${{ github.event_name }}" = "schedule" ]; then + SOURCE_ARG="--build-arg USE_LATEST_SGLANG=1" + else + SOURCE_ARG="--build-arg BRANCH_TYPE=local" + fi + + echo "Building lmsysorg/sglang:${TAG}" + + docker buildx build \ + --platform ${{ matrix.platform }} \ + --push \ + --target framework \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=${{ matrix.version }} \ + --build-arg BUILD_TYPE=${{ matrix.build_type }} \ + --build-arg CMAKE_BUILD_PARALLEL_LEVEL=$(nproc) \ + --build-arg GRACE_BLACKWELL=${{ matrix.grace_blackwell }} \ + ${SOURCE_ARG} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + -t lmsysorg/sglang:${TAG} \ + --no-cache \ + . + + create-manifests: + runs-on: ubuntu-22.04 + needs: [build-dev] + if: ${{ github.repository == 'sgl-project/sglang' }} + strategy: + matrix: + variant: + - base: dev + x86: x86 + arm64: arm64 + - base: dev-cu13 + x86: x86-cu13 + arm64: arm64-cu13 + steps: + - uses: docker/setup-buildx-action@v3 + + - uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Create multi-arch manifest + run: | + SUFFIX="" + if [ -n "${{ inputs.tag }}" ]; then + SUFFIX="-${{ inputs.tag }}" + elif [ -n "${{ inputs.pr_number }}" ]; then + SUFFIX="-pr-${{ inputs.pr_number }}" + fi + + TAG="${{ matrix.variant.base }}${SUFFIX}" + X86_TAG="dev-${{ matrix.variant.x86 }}${SUFFIX}" + ARM64_TAG="dev-${{ matrix.variant.arm64 }}${SUFFIX}" + + # For nightly (no suffix), also stamp a dated tag + EXTRA_TAG="" + if [ -z "${SUFFIX}" ]; then + SHORT_SHA="${{ github.sha }}" + EXTRA_TAG="-t lmsysorg/sglang:nightly-${TAG}-$(date +%Y%m%d)-${SHORT_SHA:0:8}" + fi + + docker buildx imagetools create \ + -t lmsysorg/sglang:${TAG} \ + ${EXTRA_TAG} \ + lmsysorg/sglang:${X86_TAG} \ + lmsysorg/sglang:${ARM64_TAG} + + echo "✓ Published lmsysorg/sglang:${TAG}" + + - name: Cleanup Old Nightly Builds + if: ${{ !inputs.tag && !inputs.pr_number }} + run: | + TOKEN=$(curl -s -H "Content-Type: application/json" \ + -X POST -d '{"username": "${{ secrets.DOCKERHUB_USERNAME }}", "password": "${{ secrets.DOCKERHUB_TOKEN }}"}' \ + https://hub.docker.com/v2/users/login/ | jq -r .token) + + TAGS_RESPONSE=$(curl -s -H "Authorization: JWT $TOKEN" \ + "https://hub.docker.com/v2/repositories/lmsysorg/sglang/tags/?page_size=100") + + TAGS=$(echo "$TAGS_RESPONSE" | jq -r \ + '.results[] | select(.name | test("^nightly-${{ matrix.variant.base }}-[0-9]")) | "\(.last_updated)|\(.name)"' \ + | sort -r | cut -d'|' -f2) + + TAG_COUNT=$(echo "$TAGS" | wc -l) + if [ "$TAG_COUNT" -gt 14 ]; then + echo "Found $TAG_COUNT nightly builds, keeping only the 14 most recent" + TAGS_TO_DELETE=$(echo "$TAGS" | tail -n +15) + for tag in $TAGS_TO_DELETE; do + echo "Deleting tag: $tag" + curl -X DELETE -H "Authorization: JWT $TOKEN" \ + "https://hub.docker.com/v2/repositories/lmsysorg/sglang/tags/$tag/" + done + else + echo "Only $TAG_COUNT nightly builds found, no cleanup needed" + fi diff --git a/sglang/.github/workflows/release-docker-gateway.yml b/sglang/.github/workflows/release-docker-gateway.yml new file mode 100644 index 0000000000000000000000000000000000000000..3b5e5a68f17be542ba2ae6e0ab5bd987b88e5fc8 --- /dev/null +++ b/sglang/.github/workflows/release-docker-gateway.yml @@ -0,0 +1,39 @@ +name: Release SGLang Model Gateway Docker Image +on: + push: + branches: + - main + paths: + - sgl-model-gateway/bindings/python/pyproject.toml + workflow_dispatch: + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-24.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and Push + run: | + version=$(cat sgl-model-gateway/bindings/python/src/sglang_router/version.py | cut -d'"' -f2) + tag=v${version} + + docker buildx build . -f docker/gateway.Dockerfile \ + --platform linux/amd64,linux/arm64 \ + -t lmsysorg/sgl-model-gateway:${tag} \ + -t lmsysorg/sgl-model-gateway:latest \ + --push diff --git a/sglang/.github/workflows/release-docker-npu-nightly.yml b/sglang/.github/workflows/release-docker-npu-nightly.yml new file mode 100644 index 0000000000000000000000000000000000000000..fe49016a651b3d1c39fc099d170d0ed7ecf10b6a --- /dev/null +++ b/sglang/.github/workflows/release-docker-npu-nightly.yml @@ -0,0 +1,85 @@ +name: Release Docker Images Nightly (NPU) +on: + pull_request: + branches: + - 'main' + paths: + - '.github/workflows/release-docker-npu-nightly.yml' + - 'docker/npu.Dockerfile' + workflow_dispatch: + schedule: + - cron: "0 0 * * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-22.04-arm + strategy: + matrix: + cann_version: ["8.5.0"] + device_type: ["910b", "a3"] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Free up disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: true + docker-images: false + + - name: Setup Docker buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + lmsysorg/sglang + # push with schedule event + # push with workflow_dispatch event + tags: | + type=ref,event=pr + type=ref,event=branch + type=schedule,pattern=main + flavor: | + latest=false + suffix=-cann${{ matrix.cann_version }}-${{ matrix.device_type }},onlatest=true + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into docker hub + uses: docker/login-action@v3 + if: ${{ github.repository == 'sgl-project/sglang' && github.event_name != 'pull_request' }} + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + # Enable Docker multi-architecture build environment + # Emulate non-native architectures + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + # Required for building and pushing multi-arch Docker images + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v6 + with: + context: docker + file: docker/npu.Dockerfile + platforms: linux/arm64,linux/amd64 + labels: ${{ steps.meta.outputs.labels }} + tags: ${{ steps.meta.outputs.tags }} + push: ${{ github.repository == 'sgl-project/sglang' && github.event_name != 'pull_request' }} + provenance: false + build-args: | + SGLANG_KERNEL_NPU_TAG=2026.02.01.post2 + CANN_VERSION=${{ matrix.cann_version }} + DEVICE_TYPE=${{ matrix.device_type }} diff --git a/sglang/.github/workflows/release-docker-npu.yml b/sglang/.github/workflows/release-docker-npu.yml new file mode 100644 index 0000000000000000000000000000000000000000..77a7bfe2c269e14f1a8cc497b7e4121dd24923be --- /dev/null +++ b/sglang/.github/workflows/release-docker-npu.yml @@ -0,0 +1,93 @@ +name: Release Docker Images (NPU) +on: + push: + tags: + - 'v[0-9]+.*' + workflow_dispatch: + inputs: + version: + description: 'Version to build (without v prefix, e.g., 0.5.7)' + required: true + +jobs: + build: + runs-on: ubuntu-22.04-arm + strategy: + matrix: + cann_version: ["8.5.0"] + device_type: ["910b", "a3"] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Free up disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: true + docker-images: false + + # push with tag + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + lmsysorg/sglang + tags: | + type=ref,event=pr + flavor: | + latest=false + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Login to Docker Hub + uses: docker/login-action@v2 + if: ${{ github.repository == 'sgl-project/sglang' && github.event_name != 'pull_request' }} + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + echo "version=v${VERSION}" >> $GITHUB_OUTPUT + echo "TAG=lmsysorg/sglang:v${VERSION}-cann${{ matrix.cann_version }}-${{ matrix.device_type }}" >> $GITHUB_OUTPUT + # Enable Docker multi-architecture build environment + # Emulate non-native architectures + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + # Required for building and pushing multi-arch Docker images + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image + id: build-and-push + uses: docker/build-push-action@v6 + with: + context: docker + file: docker/npu.Dockerfile + platforms: linux/arm64,linux/amd64 + labels: ${{ steps.meta.outputs.labels }} + tags: ${{ steps.meta.outputs.tags || steps.version.outputs.TAG }} + push: ${{ github.repository == 'sgl-project/sglang' && github.event_name != 'pull_request' }} + provenance: false + build-args: | + SGLANG_KERNEL_NPU_TAG=2026.02.01.post2 + CANN_VERSION=${{ matrix.cann_version }} + DEVICE_TYPE=${{ matrix.device_type }} + SGLANG_TAG=${{ steps.version.outputs.version }} diff --git a/sglang/.github/workflows/release-docker-xeon.yml b/sglang/.github/workflows/release-docker-xeon.yml new file mode 100644 index 0000000000000000000000000000000000000000..cde5ad15ed3b52f72a09f1acfe94384982ed1843 --- /dev/null +++ b/sglang/.github/workflows/release-docker-xeon.yml @@ -0,0 +1,62 @@ +name: Release Docker Xeon Images +on: + push: + tags: + - 'v[0-9]+.*' + workflow_dispatch: + inputs: + version: + description: 'Version to build (without v prefix, e.g., 0.5.7)' + required: true + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-24.04 + environment: 'prod' + strategy: + matrix: + build_type: ['all'] + steps: + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build and Push + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-xeon + + docker build . -f docker/xeon.Dockerfile \ + --build-arg VER_SGLANG=v${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache + docker push lmsysorg/sglang:${tag} diff --git a/sglang/.github/workflows/release-docker.yml b/sglang/.github/workflows/release-docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..ecca43722d77ba6f4149e7914fe5c20a5a00f50b --- /dev/null +++ b/sglang/.github/workflows/release-docker.yml @@ -0,0 +1,372 @@ +name: Release Docker Images +# +# This workflow builds and publishes both framework and runtime Docker images: +# +# Framework images (full development environment): +# - lmsysorg/sglang:v{version}, lmsysorg/sglang:latest +# - lmsysorg/sglang:v{version}-cu129-{amd64,arm64} +# +# Runtime images (production-optimized, ~50% smaller): +# - lmsysorg/sglang:v{version}-runtime, lmsysorg/sglang:latest-runtime +# - lmsysorg/sglang:v{version}-cu129-{amd64,arm64}-runtime +# +on: + push: + tags: + - "v[0-9]+.*" + workflow_dispatch: + inputs: + version: + description: "Version to build (without v prefix, e.g., 0.5.7)" + required: true + +jobs: + publish-x86: + if: github.repository == 'sgl-project/sglang' + environment: "prod" + strategy: + matrix: + variant: + - cuda_version: "12.9.1" + build_type: "all" + grace_blackwell: 0 + runs-on: x64-docker-build-node + steps: + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Free disk space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + docker-images: false + android: true + dotnet: true + haskell: true + large-packages: true + swap-storage: false + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build AMD64 Framework + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu129-amd64 + + docker buildx build \ + --target framework \ + --platform linux/amd64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=${{ matrix.variant.cuda_version }} \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg GRACE_BLACKWELL=${{ matrix.variant.grace_blackwell }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push AMD64 Runtime + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu129-amd64-runtime + + docker buildx build \ + --target runtime \ + --platform linux/amd64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=${{ matrix.variant.cuda_version }} \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg GRACE_BLACKWELL=${{ matrix.variant.grace_blackwell }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push AMD64 Framework (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-amd64 + + docker buildx build \ + --target framework \ + --platform linux/amd64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg GRACE_BLACKWELL=0 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push AMD64 Runtime (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-amd64-runtime + + docker buildx build \ + --target runtime \ + --platform linux/amd64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg GRACE_BLACKWELL=0 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + publish-arm64: + if: github.repository == 'sgl-project/sglang' + environment: "prod" + strategy: + matrix: + variant: + - cuda_version: "12.9.1" + build_type: "all" + grace_blackwell: 1 + runs-on: arm-docker-build-node + steps: + - name: Delete huge unnecessary tools folder + run: rm -rf /opt/hostedtoolcache + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Build ARM64 Framework + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu129-arm64 + + docker buildx build \ + --target framework \ + --platform linux/arm64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=${{ matrix.variant.cuda_version }} \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg GRACE_BLACKWELL=${{ matrix.variant.grace_blackwell }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push ARM64 Runtime + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu129-arm64-runtime + + docker buildx build \ + --target runtime \ + --platform linux/arm64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=${{ matrix.variant.cuda_version }} \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg GRACE_BLACKWELL=${{ matrix.variant.grace_blackwell }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push ARM64 Framework (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-arm64 + + docker buildx build \ + --target framework \ + --platform linux/arm64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg INSTALL_FLASHINFER_JIT_CACHE=1 \ + --build-arg GRACE_BLACKWELL=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + - name: Build and Push ARM64 Runtime (CUDA 13) + run: | + version=${{ steps.version.outputs.version }} + tag=v${version}-cu130-arm64-runtime + + docker buildx build \ + --target runtime \ + --platform linux/arm64 \ + --push \ + -f docker/Dockerfile \ + --build-arg CUDA_VERSION=13.0.1 \ + --build-arg BUILD_TYPE=${{ matrix.variant.build_type }} \ + --build-arg GRACE_BLACKWELL=1 \ + --build-arg SGL_VERSION=${version} \ + -t lmsysorg/sglang:${tag} \ + --no-cache \ + . + + create-manifests: + runs-on: ubuntu-22.04 + needs: [publish-x86, publish-arm64] + if: github.repository == 'sgl-project/sglang' + environment: "prod" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Get version from tag + id: version + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + # Extract version from tag (e.g., v0.5.7 -> 0.5.7) + VERSION="${GITHUB_REF_NAME#v}" + fi + + # Validate version format + if [ -z "$VERSION" ]; then + echo "::error::Version is empty" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z)" + exit 1 + fi + + echo "version=${VERSION}" >> $GITHUB_OUTPUT + + - name: Create multi-arch manifests + run: | + version=${{ steps.version.outputs.version }} + + # Create versioned framework manifest (default) + docker buildx imagetools create \ + -t lmsysorg/sglang:v${version} \ + lmsysorg/sglang:v${version}-cu129-amd64 \ + lmsysorg/sglang:v${version}-cu129-arm64 + + # Create latest framework manifest (default) + docker buildx imagetools create \ + -t lmsysorg/sglang:latest \ + lmsysorg/sglang:v${version}-cu129-amd64 \ + lmsysorg/sglang:v${version}-cu129-arm64 + + # Create versioned runtime manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:v${version}-runtime \ + lmsysorg/sglang:v${version}-cu129-amd64-runtime \ + lmsysorg/sglang:v${version}-cu129-arm64-runtime + + # Create latest runtime manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:latest-runtime \ + lmsysorg/sglang:v${version}-cu129-amd64-runtime \ + lmsysorg/sglang:v${version}-cu129-arm64-runtime + + # Create versioned CUDA 13 framework manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:v${version}-cu130 \ + lmsysorg/sglang:v${version}-cu130-amd64 \ + lmsysorg/sglang:v${version}-cu130-arm64 + + # Create latest CUDA 13 framework manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:latest-cu130 \ + lmsysorg/sglang:v${version}-cu130-amd64 \ + lmsysorg/sglang:v${version}-cu130-arm64 + + # Create versioned CUDA 13 runtime manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:v${version}-cu130-runtime \ + lmsysorg/sglang:v${version}-cu130-amd64-runtime \ + lmsysorg/sglang:v${version}-cu130-arm64-runtime + + # Create latest CUDA 13 runtime manifest + docker buildx imagetools create \ + -t lmsysorg/sglang:latest-cu130-runtime \ + lmsysorg/sglang:v${version}-cu130-amd64-runtime \ + lmsysorg/sglang:v${version}-cu130-arm64-runtime diff --git a/sglang/.github/workflows/release-docs.yml b/sglang/.github/workflows/release-docs.yml new file mode 100644 index 0000000000000000000000000000000000000000..18fa650f4f8b720d0589c35898e97464fb2ab417 --- /dev/null +++ b/sglang/.github/workflows/release-docs.yml @@ -0,0 +1,89 @@ +name: Release Documentation + +on: + release: + types: [published] + push: + branches: + - main + paths: + - "docs/**" + - "python/sglang/version.py" + - "python/sglang/**" + workflow_dispatch: + +concurrency: + group: release-docs-${{ github.ref }} + cancel-in-progress: true + +env: + SGLANG_IS_IN_CI: true + +jobs: + execute-and-deploy: + runs-on: 1-gpu-runner + if: github.repository == 'sgl-project/sglang' + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Fetch full git history for release index + if: github.event_name == 'release' + run: | + git fetch --prune --unshallow || git fetch --prune --depth=0 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + pip install -r docs/requirements.txt + apt-get update && apt-get install -y pandoc parallel retry + ln -sf "$(which python3)" /usr/bin/python + + - name: Setup Jupyter Kernel + run: | + python -m ipykernel install --user --name python3 --display-name "Python 3" + + - name: Execute notebooks + timeout-minutes: 40 + run: | + cd docs + make clean + make compile + + - name: Push HTML to sgl-project.github.io + timeout-minutes: 30 + env: + GITHUB_TOKEN: ${{ secrets.GH_PAT_FOR_DOCUMENTATION }} + run: | + cd docs + make html + make markdown + python3 wrap_run_llm.py + + if [[ "${{ github.event_name }}" == "release" ]]; then + python3 release_lookup/generate_index.py --output release_lookup/release_index.json + + # Copy release lookup tool for official docs on published releases. + mkdir -p _build/html/release_lookup + cp release_lookup/index.html _build/html/release_lookup/ + cp release_lookup/release_index.json _build/html/release_lookup/ + fi + + cd _build/html + + git clone https://$GITHUB_TOKEN@github.com/sgl-project/sgl-project.github.io.git ../sgl-project.github.io --depth 1 + if [[ "${{ github.event_name }}" == "release" ]]; then + find ../sgl-project.github.io/ -mindepth 1 -not -path "../sgl-project.github.io/.git*" -not -name CNAME -not -name ".jekyll" -not -name ".nojekyll" -delete + else + find ../sgl-project.github.io/ -mindepth 1 -not -path "../sgl-project.github.io/.git*" -not -path "../sgl-project.github.io/release_lookup*" -not -name CNAME -not -name ".jekyll" -not -name ".nojekyll" -delete + fi + cp -r * ../sgl-project.github.io + cp ../../README.md ../sgl-project.github.io/README.md + cd ../sgl-project.github.io + git config user.name "sglang-bot" + git config user.email "sglangbot@gmail.com" + git add . + git commit -m "Update $(date +'%Y-%m-%d %H:%M:%S')" + git push https://$GITHUB_TOKEN@github.com/sgl-project/sgl-project.github.io.git main + cd .. + rm -rf sgl-project.github.io diff --git a/sglang/.github/workflows/release-pypi-gateway.yml b/sglang/.github/workflows/release-pypi-gateway.yml new file mode 100644 index 0000000000000000000000000000000000000000..7faac68c674c7f3ed946c0421a259f2dbf78623f --- /dev/null +++ b/sglang/.github/workflows/release-pypi-gateway.yml @@ -0,0 +1,167 @@ +name: Release SGLang Model Gateway to PyPI + +on: + push: + branches: + - main + paths: + - sgl-model-gateway/bindings/python/pyproject.toml + workflow_dispatch: + +jobs: + build: + name: build on ${{ matrix.platform || matrix.os }} (${{ matrix.target }} - ${{ matrix.manylinux || 'auto' }}) + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu, macos, windows] + target: [x86_64, aarch64] + manylinux: [auto] + include: + - os: ubuntu + platform: linux + - os: windows + ls: dir + target: x86_64 + python-architecture: x64 + interpreter: 3.9 3.10 3.11 3.12 3.13 + - os: macos + target: aarch64 + interpreter: 3.9 3.10 3.11 3.12 3.13 + - os: ubuntu + platform: linux + target: aarch64 + # musllinux + - os: ubuntu + platform: linux + target: x86_64 + manylinux: musllinux_1_1 + - os: ubuntu + platform: linux + target: aarch64 + manylinux: musllinux_1_1 + exclude: + - os: windows + target: aarch64 + + steps: + - uses: actions/checkout@v4 + with: + path: sglang-repo + + - name: Move sgl-model-gateway folder to root and delete sglang-repo + run: | + mv sglang-repo/sgl-model-gateway/* . + rm -rf sglang-repo + ls -alt + shell: bash + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + architecture: ${{ matrix.python-architecture || 'x64' }} + + - name: Install twine + run: pip install -U twine + + - name: Install protoc (macOS) + if: matrix.os == 'macos' + run: brew install protobuf + + - name: Install protoc (Windows) + if: matrix.os == 'windows' + run: choco install protoc -y + + - name: Build wheels + uses: PyO3/maturin-action@v1 + with: + working-directory: bindings/python + target: ${{ matrix.target }} + manylinux: ${{ matrix.manylinux || 'auto' }} + args: --release --out dist --features vendored-openssl --interpreter ${{ matrix.interpreter || '3.9 3.10 3.11 3.12 3.13 3.14' }} + rust-toolchain: stable + docker-options: -e CI -e CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc -e CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ + before-script-linux: | + # Install build dependencies (perl/make for vendored OpenSSL, protoc for gRPC) + if command -v yum &> /dev/null; then + yum update -y && yum install -y wget unzip gcc gcc-c++ perl-core make + # Install cross-compilation toolchain for aarch64 if needed + if [ "${{ matrix.target }}" = "aarch64" ]; then + yum install -y gcc-aarch64-linux-gnu gcc-c++-aarch64-linux-gnu || true + fi + elif command -v apt-get &> /dev/null; then + apt-get update && apt-get install -y wget unzip gcc g++ perl make + # Install cross-compilation toolchain for aarch64 if needed + if [ "${{ matrix.target }}" = "aarch64" ]; then + apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu || true + fi + fi + (cd /tmp && \ + wget https://github.com/protocolbuffers/protobuf/releases/download/v32.0/protoc-32.0-linux-x86_64.zip && \ + unzip protoc-32.0-linux-x86_64.zip -d /usr/local && \ + rm protoc-32.0-linux-x86_64.zip) + protoc --version + + - name: List built packages + run: ${{ matrix.ls || 'ls -lh' }} bindings/python/dist/ + + - name: Check packages + run: twine check --strict bindings/python/dist/* + + - uses: actions/upload-artifact@v4 + with: + name: packages-${{ matrix.os }}-${{ matrix.target }}-${{ matrix.manylinux || 'auto' }} + path: bindings/python/dist/ + + build-sdist: + name: Build SDist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: sglang-repo + + - name: Move sgl-model-gateway folder to root and delete sglang-repo + run: | + mv sglang-repo/sgl-model-gateway/* . + rm -rf sglang-repo + ls -alt + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Build SDist + uses: PyO3/maturin-action@v1 + with: + working-directory: bindings/python + command: sdist + args: --out dist + rust-toolchain: stable + + - uses: actions/upload-artifact@v4 + with: + name: sdist + path: bindings/python/dist/*.tar.gz + + upload: + name: Upload to PyPI + if: github.repository == 'sgl-project/sglang' # Ensure this job only runs for the sgl-project/sglang repository + needs: [build, build-sdist] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Upload to PyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN_ROUTER }} + run: | + pip install twine + twine upload dist/* --verbose diff --git a/sglang/.github/workflows/release-pypi-nightly.yml b/sglang/.github/workflows/release-pypi-nightly.yml new file mode 100644 index 0000000000000000000000000000000000000000..edc058bed1afd5f065b3e94f2e15bfee55e5fdab --- /dev/null +++ b/sglang/.github/workflows/release-pypi-nightly.yml @@ -0,0 +1,165 @@ +name: Release PyPI Nightly Wheels + +on: + # Run daily at 2 AM UTC + schedule: + - cron: '0 2 * * *' + # Triggered by nightly Docker workflow to use same commit + repository_dispatch: + types: [nightly-release] + # Manual trigger for testing + workflow_dispatch: + inputs: + commit_sha: + description: 'Specific commit SHA to build (leave empty for latest)' + required: false + type: string + cuda_version: + description: 'CUDA version (e.g., 129 or 130)' + required: false + default: '129' + type: string + +concurrency: + group: release-pypi-nightly-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-nightly-wheel: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + outputs: + nightly_version: ${{ steps.build.outputs.nightly_version }} + commit_hash: ${{ steps.build.outputs.commit_hash }} + build_date: ${{ steps.build.outputs.build_date }} + steps: + - uses: actions/checkout@v4 + with: + # Use commit from: 1) Docker workflow, 2) manual input, 3) latest main + ref: ${{ github.event.client_payload.commit_sha || inputs.commit_sha || github.sha }} + fetch-depth: 0 # Need full history for setuptools-scm + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install build dependencies + run: | + pip install build wheel setuptools setuptools-scm + + - name: Build wheel + id: build + run: | + cd python + cp ../README.md ../LICENSE . + + # Parse git describe output to get latest tag + # Use same command as pyproject.toml to ensure version consistency + DESC=$(git tag --list --sort=-version:refname 'v*.*.*' | head -1 | xargs git describe --tags --long 2>/dev/null || echo 'v0.0.0-0-g0000000') + TAG=$(echo "$DESC" | cut -d- -f1) + HASH="g$(git rev-parse --short HEAD)" + BUILD_DATE=$(date -u +%Y%m%d) + + # Increment patch version for nightlies (e.g., v0.5.8 -> 0.5.9) + VERSION=${TAG#v} # Remove 'v' prefix + MAJOR=$(echo "$VERSION" | cut -d. -f1) + MINOR=$(echo "$VERSION" | cut -d. -f2) + PATCH=$(echo "$VERSION" | cut -d. -f3) + NEXT_PATCH=$((PATCH + 1)) + NEXT_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}" + + # Use date-based dev number for correct chronological sorting + # e.g., 0.5.9.dev20260215+g4cf4f0859 > 0.5.9.dev20260214+g45a4697d4 + FORCE_VERSION="${NEXT_VERSION}.dev${BUILD_DATE}+${HASH}" + echo "Forcing nightly version to: $FORCE_VERSION" + export SETUPTOOLS_SCM_PRETEND_VERSION="$FORCE_VERSION" + + # Build wheel + python3 -m build --wheel + + # Extract version from built wheel filename + WHEEL_FILE=$(ls dist/*.whl) + NIGHTLY_VERSION=$(echo "$WHEEL_FILE" | sed 's/.*sglang-\(.*\)-py3.*/\1/') + + # Get commit info + COMMIT_HASH=$(git rev-parse --short HEAD) + BUILD_DATE=$(date -u +%Y-%m-%d) + + echo "Built wheel: $WHEEL_FILE" + echo "Nightly version: ${NIGHTLY_VERSION}" + echo "Commit: ${COMMIT_HASH}" + echo "Build date: ${BUILD_DATE}" + + echo "nightly_version=${NIGHTLY_VERSION}" >> $GITHUB_OUTPUT + echo "commit_hash=${COMMIT_HASH}" >> $GITHUB_OUTPUT + echo "build_date=${BUILD_DATE}" >> $GITHUB_OUTPUT + + - name: Upload wheel artifact + uses: actions/upload-artifact@v4 + with: + name: nightly-wheel + path: python/dist/*.whl + retention-days: 7 + + release-nightly: + needs: build-nightly-wheel + runs-on: ubuntu-latest + environment: 'prod' + steps: + - uses: actions/checkout@v4 + + - name: Download wheel artifact + uses: actions/download-artifact@v4 + with: + name: nightly-wheel + path: dist/ + + - name: List downloaded wheels + run: | + echo "Downloaded wheel:" + ls -lh dist/ + + - name: Create GitHub Release for nightly wheel + uses: softprops/action-gh-release@v2 + with: + tag_name: nightly-${{ needs.build-nightly-wheel.outputs.build_date }}-${{ needs.build-nightly-wheel.outputs.commit_hash }} + name: Nightly Build ${{ needs.build-nightly-wheel.outputs.build_date }} (${{ needs.build-nightly-wheel.outputs.commit_hash }}) + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + prerelease: true + body: | + Nightly build from commit ${{ github.sha }} + Build date: ${{ needs.build-nightly-wheel.outputs.build_date }} + Version: ${{ needs.build-nightly-wheel.outputs.nightly_version }} + files: | + dist/*.whl + + - name: Clone wheel index repository + run: | + git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Update wheel index + run: | + python3 scripts/update_nightly_whl_index.py \ + --commit-hash ${{ needs.build-nightly-wheel.outputs.commit_hash }} \ + --nightly-version ${{ needs.build-nightly-wheel.outputs.nightly_version }} \ + --cuda-version ${{ inputs.cuda_version || '129' }} \ + --build-date ${{ needs.build-nightly-wheel.outputs.build_date }} + + - name: Push wheel index + run: | + cd sgl-whl + git add -A + git diff --staged --quiet || git commit -m "Update nightly wheel index for commit ${{ needs.build-nightly-wheel.outputs.commit_hash }}" + git push diff --git a/sglang/.github/workflows/release-pypi-pr.yml b/sglang/.github/workflows/release-pypi-pr.yml new file mode 100644 index 0000000000000000000000000000000000000000..d14be109f6ed30b8b62810d3abe98ab337728940 --- /dev/null +++ b/sglang/.github/workflows/release-pypi-pr.yml @@ -0,0 +1,183 @@ +name: Release PyPI PR Wheels + +on: + workflow_dispatch: + inputs: + pr_number: + description: 'PR number to build wheel for (works with both internal and fork PRs)' + required: true + type: string + +concurrency: + group: build-pr-wheel-${{ github.event.inputs.pr_number }} + cancel-in-progress: true + +jobs: + build-pr-wheel: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + outputs: + wheel_version: ${{ steps.gen_version.outputs.wheel_version }} + commit_hash: ${{ steps.gen_version.outputs.commit_hash }} + build_date: ${{ steps.gen_version.outputs.build_date }} + steps: + - uses: actions/checkout@v4 + with: + ref: refs/pull/${{ inputs.pr_number }}/head + fetch-depth: 0 # Need full history for version generation + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Generate PR wheel version + id: gen_version + run: | + # Get base version from the latest v*.*.* git tag directly + # Note: We cannot use setuptools_scm here because the [tool.setuptools_scm] + # config (with custom git_describe_command) lives in python/pyproject.toml, + # not at the repo root. Without that config, setuptools_scm falls back to + # default git describe which finds gateway-* tags instead of v*.*.* release tags. + LATEST_TAG=$(git tag --list --sort=-version:refname 'v*.*.*' | head -1) + BASE_VERSION=${LATEST_TAG#v} + echo "Latest release tag: ${LATEST_TAG}" + + # Get commit info + COMMIT_HASH=$(git rev-parse --short HEAD) + COMMIT_COUNT=$(git rev-list --count HEAD) + + # Get current date in YYYY-MM-DD format + BUILD_DATE=$(date -u +%Y-%m-%d) + + # Always use pr-{number} format for suffix + SUFFIX="pr-${{ inputs.pr_number }}" + + # Generate PR wheel version following PEP 440 + # Format: {base_version}.dev{commit_count}+pr-{number}.g{commit_hash} + WHEEL_VERSION="${BASE_VERSION}.dev${COMMIT_COUNT}+${SUFFIX}.g${COMMIT_HASH}" + + echo "Base version: ${BASE_VERSION}" + echo "PR wheel version: ${WHEEL_VERSION}" + echo "Commit: ${COMMIT_HASH}" + echo "Build date: ${BUILD_DATE}" + + echo "wheel_version=${WHEEL_VERSION}" >> $GITHUB_OUTPUT + echo "commit_hash=${COMMIT_HASH}" >> $GITHUB_OUTPUT + echo "base_version=${BASE_VERSION}" >> $GITHUB_OUTPUT + echo "build_date=${BUILD_DATE}" >> $GITHUB_OUTPUT + + - name: Update pyproject.toml with PR wheel version + run: | + cd python + WHEEL_VERSION="${{ steps.gen_version.outputs.wheel_version }}" + + # Update pyproject.toml to use static version instead of dynamic + # Remove 'version' from dynamic list and add static version + sed -i 's/dynamic = \["version"\]/dynamic = []/' pyproject.toml + sed -i "/^name = \"sglang\"/a version = \"${WHEEL_VERSION}\"" pyproject.toml + + # Verify update + echo "Updated version in pyproject.toml:" + grep "^version" pyproject.toml + grep "^dynamic" pyproject.toml + + - name: Install build dependencies + run: | + cd python + pip install build wheel setuptools + + - name: Build wheel + run: | + cd python + cp ../README.md ../LICENSE . + python3 -m build --wheel + + # List built wheels + echo "Built wheel:" + ls -lh dist/ + + - name: Upload wheel artifact + uses: actions/upload-artifact@v4 + with: + name: pr-wheel-${{ inputs.pr_number }} + path: python/dist/*.whl + retention-days: 30 + + release-pr-wheel: + needs: build-pr-wheel + runs-on: ubuntu-latest + environment: 'prod' + steps: + - uses: actions/checkout@v4 + + - name: Download wheel artifact + uses: actions/download-artifact@v4 + with: + name: pr-wheel-${{ inputs.pr_number }} + path: dist/ + + - name: List downloaded wheels + run: | + echo "Downloaded wheel:" + ls -lh dist/ + + - name: Create GitHub Release for PR wheel + uses: softprops/action-gh-release@v2 + with: + tag_name: pr-${{ inputs.pr_number }}-${{ needs.build-pr-wheel.outputs.build_date }}-${{ needs.build-pr-wheel.outputs.commit_hash }} + name: "PR #${{ inputs.pr_number }} Build (${{ needs.build-pr-wheel.outputs.commit_hash }})" + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + prerelease: true + body: | + PR wheel build from PR #${{ inputs.pr_number }} + Commit: ${{ github.sha }} + Build date: ${{ needs.build-pr-wheel.outputs.build_date }} + Version: ${{ needs.build-pr-wheel.outputs.wheel_version }} + + **Installation via index (pip):** + ```bash + pip install sglang==${{ needs.build-pr-wheel.outputs.wheel_version }} --index-url https://sgl-project.github.io/whl/pr/ + ``` + + **Installation via index (uv):** + ```bash + uv pip install sglang==${{ needs.build-pr-wheel.outputs.wheel_version }} --index-url https://sgl-project.github.io/whl/pr/ --extra-index-url https://pypi.org/simple --index-strategy unsafe-best-match + ``` + + **Direct installation:** + ```bash + pip install https://github.com/sgl-project/whl/releases/download/pr-${{ inputs.pr_number }}-${{ needs.build-pr-wheel.outputs.build_date }}-${{ needs.build-pr-wheel.outputs.commit_hash }}/sglang-${{ needs.build-pr-wheel.outputs.wheel_version }}-py3-none-any.whl + ``` + files: | + dist/*.whl + + - name: Clone wheel index repository + run: | + git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Update wheel index + run: | + python3 scripts/update_pr_whl_index.py \ + --pr-number ${{ inputs.pr_number }} \ + --commit-hash ${{ needs.build-pr-wheel.outputs.commit_hash }} \ + --wheel-version ${{ needs.build-pr-wheel.outputs.wheel_version }} \ + --build-date ${{ needs.build-pr-wheel.outputs.build_date }} + + - name: Push wheel index + run: | + cd sgl-whl + git add -A + git diff --staged --quiet || git commit -m "Update PR wheel index for PR #${{ inputs.pr_number }} (commit ${{ needs.build-pr-wheel.outputs.commit_hash }})" + git push diff --git a/sglang/.github/workflows/release-pypi.yml b/sglang/.github/workflows/release-pypi.yml new file mode 100644 index 0000000000000000000000000000000000000000..e6190c03254e5683c73facd19b1c0886ad18f3e4 --- /dev/null +++ b/sglang/.github/workflows/release-pypi.yml @@ -0,0 +1,31 @@ +name: Release PyPI +on: + push: + tags: + - 'v[0-9]+.*' + workflow_dispatch: + +jobs: + publish: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + environment: "prod" + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for setuptools-scm to determine version from tags + + - name: Upload to pypi + run: | + cd python + cp ../README.md ../LICENSE . + pip install build wheel setuptools setuptools-scm + python3 -m build + pip install twine + python3 -m twine upload dist/* -u __token__ -p ${{ secrets.PYPI_TOKEN }} diff --git a/sglang/.github/workflows/release-tag.yml b/sglang/.github/workflows/release-tag.yml new file mode 100644 index 0000000000000000000000000000000000000000..89b8bcac145d595837b5112004033e311bb154f9 --- /dev/null +++ b/sglang/.github/workflows/release-tag.yml @@ -0,0 +1,68 @@ +name: Release Tag +# Creates a git tag to trigger release workflows (PyPI, Docker) +# Use this after testing on a release branch is complete +on: + workflow_dispatch: + inputs: + version: + description: 'Version to tag (without v prefix, e.g., 0.5.7)' + required: true + type: string + ref: + description: 'Branch or commit to tag (e.g., release/v0.5.7, main, or commit SHA)' + required: false + default: 'main' + type: string + +permissions: + contents: write + +jobs: + create-tag: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-latest + environment: 'prod' + steps: + - name: Validate version format + run: | + VERSION="${{ github.event.inputs.version }}" + if [ -z "$VERSION" ]; then + echo "::error::Version is required" + exit 1 + fi + if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then + echo "::error::Invalid version format: $VERSION (expected: X.Y.Z or X.Y.Z.postN)" + exit 1 + fi + echo "Version validated: v$VERSION" + + - name: Checkout repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.ref }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Check if tag already exists + run: | + TAG="v${{ github.event.inputs.version }}" + if git rev-parse "$TAG" >/dev/null 2>&1; then + echo "::error::Tag $TAG already exists" + exit 1 + fi + echo "Tag $TAG does not exist, proceeding..." + + - name: Create and push tag + run: | + TAG="v${{ github.event.inputs.version }}" + REF="${{ github.event.inputs.ref }}" + + git config user.name "sglang-bot" + git config user.email "sglang-bot@users.noreply.github.com" + + echo "Creating tag $TAG on ref $REF (commit: $(git rev-parse HEAD))" + git tag -a "$TAG" -m "Release $TAG" + git push origin "$TAG" + + echo "::notice::Successfully created and pushed tag $TAG" + echo "This will trigger the release workflows (PyPI, Docker)" diff --git a/sglang/.github/workflows/release-whl-kernel.yml b/sglang/.github/workflows/release-whl-kernel.yml new file mode 100644 index 0000000000000000000000000000000000000000..9e6cb37177a67f294857aa2fbe7a6d63d2eb6d2a --- /dev/null +++ b/sglang/.github/workflows/release-whl-kernel.yml @@ -0,0 +1,387 @@ +name: Release SGLang Kernels + +on: + push: + branches: + - main + paths: + - sgl-kernel/python/sgl_kernel/version.py + workflow_dispatch: + inputs: + target: + type: choice + description: 'Build target' + required: false + default: 'all' + options: + - 'all' + - 'cu129' + - 'cu130' + - 'rocm700' + - 'musa43' + tag_name: + type: string + required: false + pr_number: + description: "PR number to build from (e.g. 12345)" + type: string + required: false + +concurrency: + group: release-sglang-kernels-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-cu129-matrix: + if: | + github.repository == 'sgl-project/sglang' && + (github.event.inputs.target == 'all' || github.event.inputs.target == 'cu129') + strategy: + matrix: + python-version: ["3.10"] + cuda-version: ["12.9"] + arch: [x86_64, aarch64] + include: + - arch: x86_64 + runner: x64-kernel-build-node + - arch: aarch64 + runner: arm-kernel-build-node + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build wheels + run: | + cd sgl-kernel + chmod +x ./build.sh + ./build.sh "${{ matrix.python-version }}" "${{ matrix.cuda-version }}" ${{ matrix.arch == 'aarch64' && 'aarch64' || '' }} + env: + BUILD_JOBS: 64 + NVCC_THREADS: 8 + + - name: Upload to PyPI + working-directory: sgl-kernel + run: | + pip install twine + python3 -m twine upload --skip-existing dist/* -u __token__ -p ${{ secrets.PYPI_TOKEN }} + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}${{ matrix.arch == 'aarch64' && '-aarch64' || '' }} + path: sgl-kernel/dist/* + + release-cu129: + needs: build-cu129-matrix + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-* + + - name: Set tag name + id: set_tag_name + run: | + if [ -z "${{ inputs.tag_name }}" ]; then + TAG_NAME="v$(cat sgl-kernel/python/sgl_kernel/version.py | cut -d'"' -f2)" + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + else + echo "tag_name=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT + fi + + - name: Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.set_tag_name.outputs.tag_name }} + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + files: | + sgl-kernel/dist/* + + - name: Clone wheel index + run: git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Update wheel index + run: python3 scripts/update_kernel_whl_index.py --cuda 129 + + - name: Push wheel index + run: | + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + git add -A + git commit -m "update whl index" + git push + + # for now we do not release CUDA 13.0 wheels to pypi + build-cu130-matrix: + if: | + github.repository == 'sgl-project/sglang' && + (github.event.inputs.target == 'all' || github.event.inputs.target == 'cu130') + strategy: + matrix: + python-version: ["3.10"] + cuda-version: ["13.0"] + arch: [x86_64, aarch64] + include: + - arch: x86_64 + runner: x64-kernel-build-node + - arch: aarch64 + runner: arm-kernel-build-node + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build wheels + run: | + cd sgl-kernel + chmod +x ./build.sh + ./build.sh "${{ matrix.python-version }}" "${{ matrix.cuda-version }}" ${{ matrix.arch == 'aarch64' && 'aarch64' || '' }} + env: + BUILD_JOBS: 64 + NVCC_THREADS: 8 + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-cuda${{ matrix.cuda-version }}${{ matrix.arch == 'aarch64' && '-aarch64' || '' }} + path: sgl-kernel/dist/* + + release-cu130: + needs: build-cu130-matrix + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-* + + - name: Set tag name + id: set_tag_name + run: | + if [ -z "${{ inputs.tag_name }}" ]; then + TAG_NAME="v$(cat sgl-kernel/python/sgl_kernel/version.py | cut -d'"' -f2)" + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + else + echo "tag_name=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT + fi + + - name: Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.set_tag_name.outputs.tag_name }} + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + files: | + sgl-kernel/dist/* + + - name: Clone wheel index + run: git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Update wheel index + run: python3 scripts/update_kernel_whl_index.py --cuda 130 + + - name: Push wheel index + run: | + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + git add -A + git commit -m "update whl index" + git push + + build-rocm700: + if: | + github.repository == 'sgl-project/sglang' && + (github.event.inputs.target == 'all' || github.event.inputs.target == 'rocm700') + runs-on: amd-docker-scale + strategy: + matrix: + python-version: ["3.10"] + rocm-version: ["700"] + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Build wheels + run: | + cp 3rdparty/amd/sgl-kernel/* sgl-kernel/ + cd sgl-kernel + chmod +x ./build_rocm.sh + ./build_rocm.sh "${{ matrix.rocm-version }}" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-rocm${{ matrix.rocm-version }} + path: sgl-kernel/dist/* + + release-rocm700: + needs: build-rocm700 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.pr_number && format('refs/pull/{0}/head', inputs.pr_number) || '' }} + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-* + + - name: Set tag name + id: set_tag_name + run: | + if [ -z "${{ inputs.tag_name }}" ]; then + TAG_NAME="v$(cat sgl-kernel/python/sgl_kernel/version.py | cut -d'"' -f2)" + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + else + echo "tag_name=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT + fi + + - name: Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.set_tag_name.outputs.tag_name }} + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + files: | + sgl-kernel/dist/* + + - name: Clone wheel index + run: git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Update wheel index + run: python3 scripts/update_kernel_whl_index.py --rocm 700 + + - name: Push wheel index + run: | + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + git add -A + git commit -m "update whl index" + git push + + build-musa43: + if: | + github.repository == 'sgl-project/sglang' && + (github.event.inputs.target == 'all' || github.event.inputs.target == 'musa43') + runs-on: kernel-build-node-musa + strategy: + matrix: + python-version: ["3.10"] + musa-version: ["43"] + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + + - name: Build wheels + run: | + cd sgl-kernel + mv pyproject_musa.toml pyproject.toml + python setup_musa.py sdist bdist_wheel + + - name: Rename MUSA wheels + run: | + bash scripts/ci/musa/rename_wheels_musa.sh ${{ matrix.musa-version }} sgl-kernel/dist + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: wheel-python${{ matrix.python-version }}-musa${{ matrix.musa-version }} + path: sgl-kernel/dist/* + + release-musa43: + needs: build-musa43 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: sgl-kernel/dist/ + merge-multiple: true + pattern: wheel-* + + - name: Set tag name + id: set_tag_name + run: | + if [ -z "${{ inputs.tag_name }}" ]; then + TAG_NAME="v$(cat sgl-kernel/python/sgl_kernel/version.py | cut -d'"' -f2)" + echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT + else + echo "tag_name=${{ inputs.tag_name }}" >> $GITHUB_OUTPUT + fi + + - name: Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.set_tag_name.outputs.tag_name }} + repository: sgl-project/whl + token: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + files: | + sgl-kernel/dist/* + + - name: Clone wheel index + run: git clone https://oauth2:${WHL_TOKEN}@github.com/sgl-project/whl.git sgl-whl + env: + WHL_TOKEN: ${{ secrets.GH_PAT_FOR_WHL_RELEASE }} + + - name: Update wheel index + run: python3 scripts/update_kernel_whl_index.py --musa 43 + + - name: Push wheel index + run: | + cd sgl-whl + git config --local user.name "sglang-bot" + git config --local user.email "sglangbot@gmail.com" + git add -A + git commit -m "update whl index" + git push diff --git a/sglang/.github/workflows/retag-docker.yml b/sglang/.github/workflows/retag-docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..633a275ed033a07eebc43de7f2e12d69cb939e20 --- /dev/null +++ b/sglang/.github/workflows/retag-docker.yml @@ -0,0 +1,30 @@ +name: Retag Docker Image + +on: + workflow_dispatch: + inputs: + source_tag: + description: "Existing image tag (e.g., v0.4.7-cu129-amd64)" + required: true + target_tag: + description: "New tag to apply (e.g., latest)" + required: true + +jobs: + retag: + if: github.repository == 'sgl-project/sglang' + runs-on: ubuntu-22.04 + environment: "prod" + steps: + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Retag image + run: | + echo "Retagging lmsysorg/sglang:${{ inputs.source_tag }} -> lmsysorg/sglang:${{ inputs.target_tag }}" + docker buildx imagetools create \ + -t lmsysorg/sglang:${{ inputs.target_tag }} \ + lmsysorg/sglang:${{ inputs.source_tag }} diff --git a/sglang/.github/workflows/runner-utilization.yml b/sglang/.github/workflows/runner-utilization.yml new file mode 100644 index 0000000000000000000000000000000000000000..7c37e41de569d2257a8332af502daa8c0d0b5044 --- /dev/null +++ b/sglang/.github/workflows/runner-utilization.yml @@ -0,0 +1,43 @@ +name: Runner Utilization Report + +on: + schedule: + - cron: '0 8 * * *' # Daily at 8 AM UTC + pull_request: + paths: + - '.github/workflows/runner-utilization.yml' + - 'scripts/ci/utils/runner_utilization_report.py' + workflow_dispatch: + inputs: + hours: + description: 'Time window in hours' + required: false + default: '24' + type: string + filter: + description: 'Filter runner labels (e.g., 5090, h200)' + required: false + type: string + +jobs: + report: + name: Generate Report + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Generate Utilization Report + timeout-minutes: 30 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + python scripts/ci/utils/runner_utilization_report.py \ + --repo ${{ github.repository }} \ + --hours ${{ inputs.hours || '24' }} \ + ${{ inputs.filter && format('--filter {0}', inputs.filter) || '' }} diff --git a/sglang/.github/workflows/slash-command-handler.yml b/sglang/.github/workflows/slash-command-handler.yml new file mode 100644 index 0000000000000000000000000000000000000000..9411e0798e7286f4071cbc93427bf5c18d98b762 --- /dev/null +++ b/sglang/.github/workflows/slash-command-handler.yml @@ -0,0 +1,79 @@ +name: Slash Command Handler + +on: + issue_comment: + types: [created, edited] + +permissions: + contents: read + pull-requests: write # Required to add labels and reactions + actions: write # Required to rerun workflows + issues: write # Required for comment reactions in some contexts + +jobs: + slash_command: + # Only run if it is a PR and the comment contains a recognized command + # Use contains() since startsWith() can't handle leading whitespace/newlines + if: > + github.event.issue.pull_request && + (contains(github.event.comment.body, '/tag-run-ci-label') || + contains(github.event.comment.body, '/rerun-failed-ci') || + contains(github.event.comment.body, '/tag-and-rerun-ci') || + contains(github.event.comment.body, '/rerun-stage') || + contains(github.event.comment.body, '/rerun-ut')) + runs-on: ubuntu-latest + + steps: + # SECURITY: This workflow runs on issue_comment trigger with elevated permissions + # (pull-requests: write, actions: write). For non-fork PRs, we can safely checkout + # the PR branch to allow testing changes to this handler. For fork PRs, we MUST + # stay on main to prevent untrusted code execution with these elevated permissions. + - name: Get PR details + id: pr + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_DATA=$(gh pr view ${{ github.event.issue.number }} --repo ${{ github.repository }} --json headRefName,headRepositoryOwner) || { + echo "::error::Failed to fetch PR data" + exit 1 + } + # Use 'empty' filter to handle null/missing values (e.g., deleted forks) + HEAD_OWNER=$(echo "$PR_DATA" | jq -r '.headRepositoryOwner.login // empty') + REPO_OWNER="${{ github.repository_owner }}" + # Treat missing/null owner as fork for security (fail-safe) + if [[ -z "$HEAD_OWNER" || "$HEAD_OWNER" != "$REPO_OWNER" ]]; then + IS_FORK="true" + else + IS_FORK="false" + fi + echo "is_fork=$IS_FORK" >> $GITHUB_OUTPUT + echo "ref=$(echo "$PR_DATA" | jq -r '.headRefName')" >> $GITHUB_OUTPUT + echo "PR owner: $HEAD_OWNER, Repo owner: $REPO_OWNER, Is fork: $IS_FORK" + + - name: Checkout code + uses: actions/checkout@v4 + with: + # For non-fork PRs, checkout PR branch to allow testing handler changes + # For fork PRs, stay on main for security (don't run untrusted code with elevated permissions) + ref: ${{ steps.pr.outputs.is_fork == 'false' && steps.pr.outputs.ref || '' }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install dependencies + run: | + pip install PyGithub + + - name: Handle Slash Command + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO_FULL_NAME: ${{ github.repository }} + PR_NUMBER: ${{ github.event.issue.number }} + COMMENT_ID: ${{ github.event.comment.id }} + COMMENT_BODY: ${{ github.event.comment.body }} + USER_LOGIN: ${{ github.event.comment.user.login }} + run: | + python scripts/ci/utils/slash_command_handler.py diff --git a/sglang/.github/workflows/stress-test.yml b/sglang/.github/workflows/stress-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..241c097e8f8d517b160e6b717d9b0f73a5c2b0a8 --- /dev/null +++ b/sglang/.github/workflows/stress-test.yml @@ -0,0 +1,44 @@ +name: Stress Test + +on: + workflow_dispatch: + inputs: + num_prompts: + description: 'Number of prompts per model' + required: true + default: '50000' + type: string + duration_minutes: + description: 'Timeout per model in minutes' + required: true + default: '45' + type: string + +jobs: + stress-test: + if: github.repository == 'sgl-project/sglang' + runs-on: 8-gpu-h200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run stress tests + timeout-minutes: 210 + env: + NUM_PROMPTS: ${{ inputs.num_prompts }} + DURATION_MINUTES: ${{ inputs.duration_minutes }} + run: | + cd test + python3 run_suite.py --hw cuda --suite stress + + - name: Upload results + if: always() + uses: actions/upload-artifact@v4 + with: + name: stress-test-results + path: | + stress_test_*.jsonl diff --git a/sglang/.github/workflows/weekly-test-nvidia.yml b/sglang/.github/workflows/weekly-test-nvidia.yml new file mode 100644 index 0000000000000000000000000000000000000000..01769cf024dab3825e0ee16e2fd9cd69e265793d --- /dev/null +++ b/sglang/.github/workflows/weekly-test-nvidia.yml @@ -0,0 +1,49 @@ +name: Weekly Test (Nvidia) + +on: + schedule: + - cron: '0 0 * * 0' # Run every Sunday at midnight UTC + workflow_dispatch: + inputs: + job_filter: + description: 'Select which job to run (leave empty or "all" to run all jobs)' + required: false + type: choice + default: 'all' + options: + - 'all' + - 'weekly-test-8-gpu-h200' + +concurrency: + group: weekly-test-nvidia-${{ github.ref }} + cancel-in-progress: true + +env: + SGLANG_IS_IN_CI: true + HF_HUB_DOWNLOAD_TIMEOUT: 300 + HF_HUB_ETAG_TIMEOUT: 300 + +jobs: + # Weekly tests - 8 GPU H200 + weekly-test-8-gpu-h200: + if: github.repository == 'sgl-project/sglang' && (inputs.job_filter == '' || inputs.job_filter == 'all' || inputs.job_filter == 'weekly-test-8-gpu-h200') + runs-on: 8-gpu-h200 + timeout-minutes: 120 + env: + RUNNER_LABELS: 8-gpu-h200 + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + bash scripts/ci/cuda/ci_install_dependency.sh + + - name: Run weekly 8-GPU H200 tests + timeout-minutes: 120 + env: + GPU_CONFIG: "8-gpu-h200" + IS_H200: "1" + run: | + cd test + python3 run_suite.py --hw cuda --suite weekly-8-gpu-h200 --nightly --continue-on-error --timeout-per-file 7200 diff --git a/sglang/docs/advanced_features/attention_backend.md b/sglang/docs/advanced_features/attention_backend.md new file mode 100644 index 0000000000000000000000000000000000000000..af163fc8b236ae1bfdd3e72c64b6f2920e5624c5 --- /dev/null +++ b/sglang/docs/advanced_features/attention_backend.md @@ -0,0 +1,346 @@ +# Attention Backend + +SGLang supports a large variety of attention backends. Each of them has different pros and cons. +You can test them according to your needs. + +```{important} +Selecting an optimal attention backend is crucial for maximizing your performance. Different backends excel in various scenarios, so choose based on your model, hardware, and use case. Not all backends are supported on all platforms and model architectures. + +If you don't specify `--attention-backend`, SGLang makes a best effort to automatically select the most performant backend based on your hardware and model architecture. +``` + +## Support Matrix + +The support matrix is split into two parts: MHA (standard attention) and MLA (multi-head latent attention). For an explanation of the key differences between MHA and MLA, please see the [SGLang documentation on DeepSeek MLA](../basic_usage/deepseek_v3.md#multi-head-latent-attention-mla-throughput-optimizations) and the original [DeepSeek MLA paper](https://arxiv.org/pdf/2405.04434). + +### MHA Backends + +| **Backend** | **Page Size > 1 (native)** | **FP8 KV Cache** | **FP4 KV Cache** | **Spec topk=1** | **Spec topk>1** | **Sliding Window** | **MultiModal** | +|---------------------------------|-----------------------------|------------------|-----------------|-----------------|-----------------|--------------------|----------------| +| **FlashInfer** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | +| **FA3 (FlashAttention 3)** | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | +| **FA4 (FlashAttention 4)** | 128 | ❌ | ✅ | ❌ | ❌ | ❌ | ✅ | +| **Triton** | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | +| **Torch Native (SDPA)** | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | +| **FlexAttention (PyTorch)** | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | +| **TRTLLM MHA** | 16, 32 or 64 | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | +| **Dual Chunk FlashAttention** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| **AITER (ROCm)** | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | +| **Wave (ROCm)** | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| **Ascend (NPU)** | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | +| **Intel XPU** | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | +| **Intel AMX (CPU)** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | + +### MLA Backends + +| **Backend** | **Native Page Sizes** | **FP8 KV Cache** | **FP4 KV Cache** | **Chunked Prefix Cache** | **Spec topk=1** | **Spec topk>1** | +|----------------------------|---------------------------|------------------|------------------|--------------------------|-----------------|-----------------| +| **FlashInfer MLA** | 1 | ❌ | ✅ | ✅ | ✅ | ❌ | +| **FlashMLA** | 64 | ✅ | ✅ | ✅ | ✅ | ❌ | +| **Cutlass MLA** | 128 | ✅ | ✅ | ✅ | ✅ | ❌ | +| **TRTLLM MLA (Blackwell)** | 32 or 64 | ✅ | ✅ | ✅ | ✅ | ❌ | +| **FA3 (FlashAttention 3)** | n/a | ❌ | ❌ | ✅ | ✅ | ⚠️ (page_size=1 only) | +| **Triton** | n/a | ❌ | ❌ | ❌ | ✅ | ⚠️ (page_size=1 only) | +| **FA4** | 1 | ❌ | ✅ | ❌ | ❌ | ❌ | +| **Ascend MLA (NPU)** | 128 | ❌ | ❌ | ❌ | ❌ | ❌ | + +```{note} +Multimodal attention is selected by `--mm-attention-backend`. The "MultiModal" column indicates whether a corresponding multimodal implementation exists for that backend family. +``` + +```{note} +- FlashAttention 4 supports both prefill and decode on SM90 (Hopper) and SM100 (Blackwell). On SM90, `page_size` must be 128. +- NSA is specifically designed for [DeepSeek V3.2 DSA](https://lmsys.org/blog/2025-09-29-deepseek-V32/). +``` + +```{warning} +**FA4 on Hopper (SM90):** FA4 decode speed decreases as sequence length grows due to lack of SplitKV support. At batch=1 compared to FA3 on H100: ~-10% at 2K tokens, ~-18% at 4K, ~-31% at 8K, ~-49% at 16K. Larger batch sizes reduce the gap (e.g., batch=8: ~-2% at 2K, ~-8% at 4K). Blackwell (SM100) is not affected. +``` + +```{note} +For the KV4 FA4 scenario, FA4 requires using a different --decode-attention-backend to run. Except for trtllm_mha being incompatible with FA4, all other decode backends behave as shown in the table. +``` + +```{tip} +Speculative decoding topk: `topk` is the number of draft tokens sampled per step from the draft model. `topk = 1` follows classic EAGLE; `topk > 1` explores multiple branches and requires backend support in both draft and verification paths. +``` + +```{tip} +Page size controls how many tokens are grouped into a KV cache block. For the prefix cache to take effect, the number of tokens must fill at least one complete page. For example, if your prompt is only 32 tokens and `page_size = 64`, it won't fill a complete page and cannot be matched in the prefix cache (pages cannot be padded). With 65 tokens and `page_size = 64`, only the first page of 64 tokens will be cached and matched; the remaining 1 token is discarded. Use `page_size = 1` for maximum prefix reuse (token-level matching). +``` + +Many backends that do not natively operate on pages can emulate `page_size > 1` at the wrapper layer by expanding page tables to per-token indices. The "Page Size > 1 (native)" column indicates true in-kernel paging. Some backends require fixed native page sizes and cannot be reduced/emulated differently: TRTLLM MHA (16/32/64), TRTLLM MLA (32/64), FlashMLA (64), Cutlass MLA (128), Ascend (128). + +MLA page-size constraints: +- FlashInfer MLA: page_size = 1. +- FlashMLA: page_size = 64. +- Cutlass MLA: page_size = 128. +- TRTLLM MLA: page_size ∈ {32, 64}. + +### GDN Attention Backends + +GDN (Gated Delta Network) is a linear attention mechanism with O(n) complexity, used in hybrid models that alternate GDN linear attention layers with standard full attention layers. GDN is **not** selected via `--attention-backend`; it is automatically activated when the model architecture requires it (e.g., Qwen 3.5, Qwen 3 Next, Jet Nemotron, Jet VLM). + +The GDN linear attention layers have their own kernel backends, selected via `--linear-attn-backend` (default: `triton`). You can override the kernel per phase with `--linear-attn-decode-backend` and `--linear-attn-prefill-backend`. + +| **Backend** | **Decode** | **Prefill / Extend** | **Spec Decoding (Target Verify)** | +|--------------------------|------------|----------------------|-----------------------------------| +| **Triton (CUDA)** | ✅ | ✅ | ✅ | +| **Triton (AMD/ROCm)** | ✅ | ✅ | ✅ | +| **Triton (NPU)** | ✅ | ✅ | ❌ | +| **Triton (CPU)** | ✅ | ✅ | ❌ | +| **CuTe DSL (CUDA only)**| ✅ | ❌ | ❌ | + +```{important} +GDN models are hybrid: the full-attention layers still require a standard `--attention-backend`. Platform constraints for the full-attention backend on hybrid GDN models: +- **Blackwell (e.g., B200)**: `triton`, `trtllm_mha`, or `fa4` only. +- **NPU (Ascend)**: `ascend` only. +- **AMD (ROCm)**: `triton` recommended. +- **Other CUDA (Hopper, Ampere, etc.)**: auto-selection works; no special constraints. +``` + +### Hybrid attention (different backends for prefill vs decode) (Experimental) + +```{warning} +Hybrid attention is an experimental feature. +``` + +You can mix-and-match attention backends for prefill and decode. This is useful when one backend excels at prefill and another excels at decode. For the implementation details, please see `python/sglang/srt/layers/attention/hybrid_attn_backend.py`. + +```bash +# Example: Prefill with FA4, Decode with TRTLLM MLA (Blackwell) +python3 -m sglang.launch_server \ + --model-path nvidia/DeepSeek-R1-FP4 \ + --tp 8 \ + --attention-backend trtllm_mla \ + --moe-runner-backend flashinfer_trtllm \ + --quantization modelopt_fp4 \ + --prefill-attention-backend fa4 +``` + +#### Speculative decoding with hybrid attention + +Hybrid attention also works with speculative decoding. The backend used for draft decoding and target verification depends on `--speculative-attention-mode`: + +- `--speculative-attention-mode decode` (recommended): draft/verify use the decode backend. +- `--speculative-attention-mode prefill` (default): draft/verify use the prefill backend. + +Constraints when combining hybrid attention with speculative decoding: + +- If any attention backend is `trtllm_mha`, speculative decoding supports only `--speculative-eagle-topk 1`. +- For paged MHA backends with `--page-size > 1` and `--speculative-eagle-topk > 1`, only `flashinfer` is supported. +- CUDA Graph: the decode backend is always captured; the prefill backend is captured only when `--speculative-attention-mode prefill`. + + +```{tip} +If you set only one of `--prefill-attention-backend` or `--decode-attention-backend`, the unspecified phase inherits `--attention-backend`. +If both are specified and differ, SGLang automatically enables a hybrid wrapper to dispatch to the chosen backend per phase. +``` + +## Attention Backend Selection Guide (CUDA) + +If the `--attention-backend` argument is not specified, SGLang automatically selects the best backend based on the hardware (CUDA) and model architecture. + +### Automatic Selection Logic + +**1. MHA Models (e.g., Llama, Qwen)** +- **Hopper (e.g., H100, H200)**: Defaults to `fa3` if using CUDA 12.3+ and the model configuration is supported. +- **Blackwell (e.g., B200)**: Defaults to `trtllm_mha`, unless using speculative decoding with `topk > 1`. +- **Other Architectures (Ampere, Ada, etc.)**: Defaults to `flashinfer` if available; otherwise falls back to `triton`. + +**2. MLA Models (e.g., DeepSeek V3)** +- **Hopper**: Defaults to `fa3` (requires CUDA 12.3+). +- **Blackwell**: Defaults to `trtllm_mla`. +- **Other Architectures**: Defaults to `triton`. + + +## User Guide + +### Launch Command for Different Attention Backends + +- FlashInfer (Default for Non-Hopper Machines, e.g., A100, A40) +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend flashinfer +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-V3 \ + --attention-backend flashinfer \ + --trust-remote-code +``` + +- FlashAttention 3 (Default for Hopper Machines, e.g., H100, H200, H20) +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend fa3 +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-V3 \ + --trust-remote-code \ + --attention-backend fa3 +``` + +- Triton +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend triton +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-V3 \ + --attention-backend triton \ + --trust-remote-code +``` + +- FlashMLA +```bash +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --attention-backend flashmla \ + --trust-remote-code +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --attention-backend flashmla \ + --kv-cache-dtype fp8_e4m3 \ + --trust-remote-code +``` + +- TRTLLM MLA (Optimized for Blackwell Architecture, e.g., B200) +```bash +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --attention-backend trtllm_mla \ + --trust-remote-code +``` + +- TRTLLM MLA with FP8 KV Cache (Higher concurrency, lower memory footprint) +```bash +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --attention-backend trtllm_mla \ + --kv-cache-dtype fp8_e4m3 \ + --trust-remote-code +``` + +- TRTLLM MHA (Optimized for Blackwell Architecture, e.g., B200) +```bash +python3 -m sglang.launch_server \ + --tp 4 \ + --model Qwen/Qwen3.5-35B-A3B-FP8 \ + --attention-backend trtllm_mha \ + --trust-remote-code +``` + +- TRTLLM MHA (XQA backend) (Optimized for SM90 and SM120, e.g., H20, H200, 5090) +Note that TRTLLM XQA backend only works well for pagesize 64. +```bash +python3 -m sglang.launch_server \ + --tp 4 \ + --model Qwen/Qwen3.5-35B-A3B-FP8 \ + --decode-attention-backend trtllm_mha \ + --trust-remote-code +``` + +- FlashAttention 4 (MHA & MLA) +```bash +# FA4 for both prefill and decode on SM90/SM100 +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-30B-A3B-Instruct-2507-FP8 \ + --attention-backend fa4 \ + --page-size 128 \ + --trust-remote-code + +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --prefill-attention-backend fa4 \ + --trust-remote-code +``` + +- Cutlass MLA +```bash +python3 -m sglang.launch_server \ + --tp 8 \ + --model deepseek-ai/DeepSeek-R1 \ + --attention-backend cutlass_mla \ + --trust-remote-code +``` + +- Ascend +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend ascend +``` + +- Intel XPU +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend intel_xpu +``` + +- Wave +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend wave +``` + +- FlexAttention +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend flex_attention +``` + +- Dual Chunk FlashAttention +```bash +python3 -m sglang.launch_server \ + --model Qwen/Qwen2.5-14B-Instruct-1M \ + --attention-backend dual_chunk_flash_attn +``` + +- Torch Native +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --attention-backend torch_native +``` + +## Steps to add a new attention backend +To add a new attention backend, you can learn from the existing backends +(`python/sglang/srt/layers/attention/triton_backend.py`, `python/sglang/srt/layers/attention/flashattention_backend.py`) +and follow the steps below. + +```{note} +Linear attention kernel backends (GDN, KDA) follow a different pattern. They implement `LinearAttnKernelBase` in `python/sglang/srt/layers/attention/linear/kernels/` and are dispatched by `GDNKernelDispatcher` / `KDAKernelDispatcher` rather than registered via `@register_attention_backend`. +``` + +1. Run without cuda graph. Support the two forward functions + - forward_extend + - Will be used for prefill, prefill with KV cache, and target verification + - It will be called once per layer + - forward_decode + - Will be used for normal decode, and draft decode + - It will be called once per layer + - init_forward_metadata + - Initialize the class and common metadata shared by all layers + - Call the plan function for optimizations like split_kv + - It will be called once per forward +2. Run with cuda graph. It has two phases (capture and replay) and you need to implement three functions + - init_cuda_graph_state + - It will be called once during life time + - Create all common shared buffers + - init_forward_metadata_capture_cuda_graph + - It will be called before capturing a cuda graph + - It is similar to init_forward_metadata but write the medatada to some pre-defined buffers + - init_forward_metadata_replay_cuda_graph + - It will be called before replaying a cuda graph + - This function is in the critical path and needs to be fast diff --git a/sglang/docs/advanced_features/cuda_graph_for_multi_modal_encoder.md b/sglang/docs/advanced_features/cuda_graph_for_multi_modal_encoder.md new file mode 100644 index 0000000000000000000000000000000000000000..184995ff178aee5d17acdf4bf818bd6380782a79 --- /dev/null +++ b/sglang/docs/advanced_features/cuda_graph_for_multi_modal_encoder.md @@ -0,0 +1,73 @@ +# Cuda Graph for Multi-Modal Encoder in SGLang + +## Motivation + +In multimodal reasoning services, the visual encoder (ViT / Vision Transformer) typically has a few characteristic traits: + +Many layers, fragmented operators: Each layer includes LN, QKV projections, attention, MLP, residual connections, etc., resulting in extremely frequent kernel launches. + +Server-side “small batch / low latency” is common: The batch size is very small (sometimes it looks like 1 after “flattening” the batch), so kernel launch overhead accounts for a large portion of end-to-end latency. + +Input token count (number of patches) varies frequently: Different image/video resolutions and different batch composition lead to different sequence lengths +S — and this is precisely the biggest obstacle for CUDA Graph (unstable shapes). + +The value of CUDA Graph: It captures a long sequence of GPU kernels with fixed shapes and fixed memory addresses into a graph; later, for the same shapes, it can replay the graph directly, dramatically reducing launch overhead and making GPU scheduling more compact. + +This led us to seek a CUDA Graph enabled feature for ViT in order to improve ViT performance. + +## Design and Restrictions + +The new CUDA Graph enabled ViT logic is built on ViTCudaGraphRunner. This runner captures the "blocks + merger + deepstack merger (optional)" part of a vision transformer into a CUDA graph and replays it for identical shapes. See the following design consideration and restrictions for more details. + +### Dynamic inputs to fit static constraints of CUDA Graph + +Variable sequence length S is very common in ViT. While CUDA Graph requires fixed shapes. The solution is to build a graph cache by S(e.g., graph_key = S). The first time create a new S, and then capture a graph; afterwards, replay it. + +If there are many distinct S values, we need to increase VRAM usage which is graph-private memory pools for many graphs. + +### Stable addresses + +Everything "parameter-like" becomes a static buffer: + +- block_input / block_ws / block_output +- cu_full_len / cu_window_len and their kk variants +- sin_cos_ws + +In this way to solve the underlying requirement: during replay, not allowed to swap tensors, can only modify tensor contents. + +### Attention backend arguments +Attention backend arguments are fixed inside the graph: + +TritonAttn expects [cu_seqlens, cu_seqlens_kk, max_len] +FA3 expects [cu_seqlens, max_len] + +max_len is frozen as an int constant. +cu_seqlens is cached into a dict during create_graph(), and its contents are not updated during subsequent replays. + +For the same graph_key = S, you not only require the input shape to match, but also require the segmentation pattern in cu_seqlens (and window seqlens) to be identical. Otherwise, attention will segment the sequence incorrectly. + +### Rotary buffer management +The feature reallocates a larger sin_cos_ws when seq_len increases. +The max_content_len is used to make sure the maximum size of the allocated rotary buffer. + + +## Command Example +You can enable CUDA Graph for ViT by setting env variable `SGLANG_VIT_ENABLE_CUDA_GRAPH=1`, for example: +``` +SGLANG_VIT_ENABLE_CUDA_GRAPH=1 \ +python3 -m sglang.launch_server \ + --model Qwen/Qwen3-VL-8B-Instruct +``` +Or you can run CUDA Graph for ViT together with Piecewise CUDA Graph feature by both setting env variable `SGLANG_VIT_ENABLE_CUDA_GRAPH=1` and setting `--enable-piecewise-cuda-graph`, for example: +``` +SGLANG_VIT_ENABLE_CUDA_GRAPH=1 \ +python3 -m sglang.launch_server \ + --model Qwen/Qwen3-VL-8B-Instruct \ + --piecewise-cuda-graph-max-tokens 4096 \ + --enable-piecewise-cuda-graph \ + --piecewise-cuda-graph-compiler eager +``` + +## Known supported models +- Qwen2.5-VL (https://github.com/sgl-project/sglang/pull/14422) +- Qwen3-VL (https://github.com/sgl-project/sglang/pull/15320) diff --git a/sglang/docs/advanced_features/deterministic_inference.md b/sglang/docs/advanced_features/deterministic_inference.md new file mode 100644 index 0000000000000000000000000000000000000000..b5b6b521656b0607fde21802935281aeb4a5be89 --- /dev/null +++ b/sglang/docs/advanced_features/deterministic_inference.md @@ -0,0 +1,154 @@ +# Deterministic Inference + +## Why Deterministic Inference Matters + +Deterministic inference ensures consistent LLM outputs across runs, which is critical for: +- **Reinforcement Learning**: Ensures consistent logprobs across runs, reducing stochastic noise and making RL training more stable, reproducible, and debuggable. +- **Testing & Debugging**: Enables reproducible validation +- **Production**: Improves reliability and user experience + +Even with `temperature=0`, standard LLM inference can produce different outputs due to dynamic batching and varying reduction orders in GPU kernels. + +## The Root Cause of Non-Determinism + +The main source is **varying batch sizes**. Different batch sizes cause GPU kernels to split reduction operations differently, leading to different addition orders. Due to floating-point non-associativity (`(a + b) + c ≠ a + (b + c)`), this produces different results even for identical inputs. + + +## SGLang's Solution + +Building on [Thinking Machines Lab's batch-invariant operators](https://github.com/thinking-machines-lab/batch_invariant_ops), SGLang achieves fully deterministic inference while maintaining compatibility with chunked prefill, CUDA graphs, radix cache, and non-greedy sampling. The development roadmap for deterministic inference features can be found in this [issue](https://github.com/sgl-project/sglang/issues/10278). + +### Supported Backends + +Deterministic inference is only supported with the following three attention backends: **FlashInfer**, **FlashAttention 3 (FA3)**, and **Triton**. + +The following table shows feature compatibility for deterministic inference across different attention backends: + +| Attention Backend | CUDA Graph | Chunked Prefill | Radix Cache | Non-greedy Sampling (Temp > 0) | +|-------------------|------------|-----------------|-------------|---------------------| +| **FlashInfer** | ✅ Yes | ✅ Yes | ❌ No | ✅ Yes | +| **FlashAttention 3 (FA3)** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | +| **Triton** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | + +## Usage + +### Basic Usage + +Enable deterministic inference by adding the `--enable-deterministic-inference` flag: + +```bash +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-8B \ + --attention-backend fa3 \ + --enable-deterministic-inference +``` + +### Server Arguments + +| Argument | Type/Default | Description | +|----------|--------------|-------------| +| `--enable-deterministic-inference` | flag; default: disabled | Enable deterministic inference with batch-invariant operations | +| `--attention-backend` | string; default: fa3 | Choose attention backend (flashinfer, fa3, or triton) | + +### Example Configurations + +#### Qwen3-8B +```bash +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-8B \ + --attention-backend flashinfer \ + --enable-deterministic-inference +``` + +#### Llama Models +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --attention-backend fa3 \ + --enable-deterministic-inference +``` + +#### Qwen3-30B-A3B (MoE Model) +```bash +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-30B-A3B \ + --attention-backend fa3 \ + --enable-deterministic-inference +``` + +### Deterministic Inference with Non-Greedy Sampling (Temperature > 0) + +SGLang supports deterministic inference even with non-greedy sampling by using sampling seeds. This is particularly useful for reinforcement learning scenarios like GRPO (Group Relative Policy Optimization) where you need multiple diverse but reproducible responses. + +#### Default Behavior + +By default, SGLang uses a sampling seed of `42` for reproducible sampling: + +```python +import requests + +response = requests.post( + "http://localhost:30000/generate", + json={ + "text": "Tell me a joke", + "sampling_params": { + "temperature": 0.8, # Non-greedy sampling + "max_new_tokens": 128, + }, + }, +) +print(response.json()) +# This will always produce the same response across runs +``` + +#### Generating Multiple Reproducible Responses + +To sample different responses from the same prompt while maintaining reproducibility (e.g., for GRPO training), provide different sampling seeds in your requests: + +```python +import requests + +# Prepare a list of sampling seeds for different responses +sampling_seeds = [42, 43, 44, 45, 46] + +responses = [] +for seed in sampling_seeds: + response = requests.post( + "http://localhost:30000/generate", + json={ + "text": "Tell me a joke", + "sampling_params": { + "temperature": 0.8, + "max_new_tokens": 128, + "sampling_seed": seed, # Specify sampling seed + }, + }, + ) + responses.append(response.json()) + +# Each seed will produce a different but reproducible response +# Using the same seed will always produce the same response +``` + +This approach ensures that: +- Different seeds produce diverse responses +- The same seed always produces the same response across different runs +- Results are reproducible for debugging and evaluation + + +## Verification + +Run deterministic tests to verify consistent outputs: + +```bash +# Single test: same prompt, varying batch sizes +python3 -m sglang.test.test_deterministic --test-mode single --n-trials 50 + +# Prefix test: prompts with different prefix lengths +python3 -m sglang.test.test_deterministic --test-mode prefix --n-trials 50 + +# Radix Cache Consistency mode: test radix cache determinism (cached vs uncached prefill) +python3 -m sglang.test.test_deterministic --test-mode radix_cache +``` + +Expected result: All tests should show `Unique samples: 1` (perfectly deterministic). diff --git a/sglang/docs/advanced_features/dp_dpa_smg_guide.md b/sglang/docs/advanced_features/dp_dpa_smg_guide.md new file mode 100644 index 0000000000000000000000000000000000000000..9ec5df64856ea0e4d8641822b3dd5e8f2c650619 --- /dev/null +++ b/sglang/docs/advanced_features/dp_dpa_smg_guide.md @@ -0,0 +1,373 @@ +# DP, DPA and SGLang DP Router + +This guide explains the difference between Data Parallelism (DP) and Data Parallelism Attention (DPA), how to enable each mode correctly, and how to use the SGLang Model Gateway (SMG) for production-grade DP deployments. + +## Data Parallelism (DP) + +**Data Parallelism (DP)** is the most common parallelism strategy that replicates the entire model across multiple GPU sets and processes different batches of requests in parallel. Each GPU set handles independent requests. With dedicated routing strategies, as we will introduce later, with those proper routing algorithms in SGLang Model Gateway, the throughput of your serving system could be multiplied nearly linearly. + +### Key characteristics + +- Each replica has a full copy of the model +- Requests are distributed/scattered across replicas +- No inter-replica communication during one request's inference (for simple DP) + +## Data Parallelism Attention (DPA) + +**Data Parallelism Attention (DPA)**, also known as DP Attention, is an advanced parallelism strategy. While DPA provides the most significant benefits for **Multi-Head Latent Attention (MLA)** models (such as DeepSeek, MiniMax, Kimi-K2), it also supports **standard attention models** like Qwen. + +### The Problem with Tensor Parallelism for MLA Models + +The most common parallelism strategy for inference is **Tensor Parallelism (TP)**. However, TP might not be the most efficient strategy for certain models. For example, DeepSeek models use MLA and only have **one KV head**. If we use tensor parallelism on 8 GPUs, it will lead to: + +- **Duplicated KV cache** across all GPUs +- **Unwanted memory usage** that limits batch size +- **Reduced throughput** due to memory constraints + +### How DPA Works + +DPA addresses these limitations by applying **data parallelism specifically to the attention component**. + + + + + + +
+DPA + EP Architecture + + +**Each DP replica:** + +- Processes different batches independently (can be in different forward modes: prefill, decode, or idle) +- Maintains its own KV cache (no duplication) +- Enables significantly larger batch sizes due to memory savings + +**Communication patterns in DPA + EP:** +- +- **All2All (Dispatch)**: Routes tokens to expert sub-groups based on gating decisions +- **All2All (Combine)**: Gathers computed results from experts back to original token positions + +
+ +### Key benefits of DPA + +1. **Significantly reduced KV cache memory**: Each DP replica only stores KV cache for its own batches +2. **Larger batch sizes**: Memory savings enable larger batch sizes +3. **Improved decoding throughput**: Significant throughput gains for MLA-based models +4. **Independent forward modes**: Each DP replica can be in different forward modes (prefill, decode, or idle) and handles its assigned batches independently during attention computation + +### DPA with Expert Parallelism for MoE + +For MoE models like DeepSeek, DPA is **often** paired with Expert Parallelism (EP) for best throughput at scale. However, **DPA does not require EP**: you can enable DPA without EP if your deployment does not need expert sharding. + +- Distribute 256+ expert weights across GPUs (cannot fit on a single GPU) +- Enable efficient all-to-all token routing via DeepEP +- Scale to large clusters (up to 5x throughput improvement over vanilla TP) + +### Recommended setup for DeepSeek + +```bash +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3 \ + --tp 8 \ + --dp-size 8 \ + --ep 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --moe-runner-backend deep_gemm +``` + +> **Note**: `--dp-size` must be explicitly set when using `--enable-dp-attention`. If `dp_size` is 1 (default), DPA will be disabled. + +For detailed EP configuration (DeepEP, Two-Batch Overlap, EPLB), see [Expert Parallelism](expert_parallelism.md). + +### Target Models + +DPA supports the following model architectures: + +- **MLA (Multi-Head Latent Attention) models** - where DPA provides the most significant benefits: + - DeepSeek family (DeepSeek-V2, DeepSeek-V3, DeepSeek-R1) + - MiniMax models + - Kimi-K2 + - Other models using MLA architecture + +- **Standard attention models** - also supported: + - Qwen models (see [PR #6121](https://github.com/sgl-project/sglang/pull/6121)) + +For models like Llama, with standard GQA, standard DP, or TP is typically recommended. + +To enable DPA, add `--enable-dp-attention` to your server launch command. + +### Activation Logic + +DPA is enabled explicitly via server arguments (CLI or config). You must set both `--dp-size` and `--enable-dp-attention`: + +```bash +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3 \ + --tp 8 \ + --dp-size 8 \ + --enable-dp-attention +``` + +**Important**: `--dp-size` must be greater than 1 for DPA to work. When `dp_size == 1` (default), `--enable-dp-attention` is automatically disabled. The constraint `tp_size % dp_size == 0` must also be satisfied. + +### Standard DP for MLA models + +Note that MLA models, of course, also support DP. Suppose you want to enable standard DP for MLA models. First, launch each MLA model's replica independently. You may launch these replicas one by one with DPA enabled. After launching each MLA model's replica, launch an SMG and connect all the replicas to the SMG. A detailed explanation of SMG is as follows. + +## Modern Data Parallelism SGLang Model Gateway (SMG) + +### Native DP Mode + +Native DP (built-in Data Parallelism) in SGLang creates multiple worker processes within a single SGLang instance, under the control of `DataParallelController` with the launching parameter of `dp-size`. + + +```bash +# Native DP mode +python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --dp-size 4 +``` + +**Limitations:** + +- Built-in in-process load balancing only (e.g., `round_robin`, `total_requests`, `total_tokens`) +- No cache-aware routing +- Limited observability and metrics +- No fault tolerance or circuit breakers +- Not suitable for production workloads + +⚠️ Native DP is **highly not recommended for use right now**. It is only used in some ancient/outdated RL frameworks. You can use SGLang Model Gateway (SMG) to power up your data parallelism in any use case. + +### SMG-Based DP (Recommended) + +Starting from September 2024, SGLang Model Gateway, i.e., SMG, formerly named as SGLang DP Router, was built especially as a production-ready DP routing system with Rust. It starts from DP routing, but later we further expanded its scope to coordinate RL, PD Disaggregation, and other scenarios. This doc only discusses SMG's usage in DP routing. For other usage, please refer to [SGLang Model Gateway Documentation](sgl_model_gateway.md). + +> To achieve the best production-level routing performance and reduce the overhead to an extreme extent, we use Rust to build SMG, but not Python, since Python is never FAST enough. + +**We strongly recommend using the SGLang Model Gateway (SMG) for production-grade Data Parallelism.** SMG provides significant advantages over native DP mode. + +```bash +# SMG-based DP mode (Recommended) +python -m sglang_router.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --dp-size 4 +``` + +⚠️ Note that **SMG and Naive DP share the same launching parameter, `--dp-size`**. But the entrypoint of Naive DP is `python -m sglang.launch_server`, and SMG's entrypoint is `python -m sglang_router.launch_server`. + +**Advantages of SMG-Based DP:** + +| Feature | Native DP | SMG-Based DP | +|---------|-----------|--------------| +| **Load Balancing** | Built-in in-process methods | Advanced policies (cache-aware, power-of-two, etc.) | +| **Cache Awareness** | ❌ No | ✅ Yes - significantly higher cache hit rate | +| **Throughput** | Baseline | Significant improvement | +| **Multi-Node Support** | Limited | ✅ Full support | +| **Worker Health Monitoring** | Basic | ✅ Circuit breakers, health checks | +| **Reliability** | Basic | ✅ Retries, rate limiting, queuing | +| **Observability** | Basic metrics | ✅ 40+ Prometheus metrics, OpenTelemetry | +| **Hot Worker Add/Remove** | ❌ No | ✅ Yes | + +### SMG's Performance + +The cache-aware routing policy in SMG significantly improves performance for workloads with shared prefixes: + +| Metric | Without Cache-Aware | With Cache-Aware SMG | +|--------|---------------------|----------------------| +| Throughput (token/s) | 82,665 | 158,596 (+92%) | +| Cache Hit Rate | 20% | 75% (+275%) | + +*Benchmark from [SGLang v0.4 blog](https://lmsys.org/blog/2024-12-04-sglang-v0-4/), workload with multiple long prefix groups, 8x A100 80GB GPUs, dp-size=8* + +### When to Use Each + +**Use Native DP when:** + +- ~Never use Native/Naive DP~ +- Learning material of DP routing + +**Use SMG-Based DP when:** + +- In any case, when you think DP is needed +- Production deployments +- Multi-node distributed setups +- Workloads with shared prefixes (high cache reuse potential) +- You need high availability and reliability features +- You require detailed observability and metrics +- You want to have highly efficient RL rollout systems + +Note that for RL rollout systems, **there are four crucial reasons that SMG-Based DP is far better than naive DP routing**. Details can be found at [Load Balancing Router in RL](./sglang_for_rl.md#load-balancing-router). + +### Quick Start For SMG + +**Installation** + +```bash +pip install sglang-router +# or +pip install "sglang[all]" +``` + +**Option A: Co-launch Workers and SMG (Simplest)** + +This is the easiest way to get started - SMG and workers are launched together: + +```bash +python -m sglang_router.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --dp-size 4 \ + --host 0.0.0.0 \ + --port 30000 +``` + +**Option B: Separate Launch (Multi-Node)** + +For distributed deployments across multiple machines: + +1. Launch workers on each node + +```bash +# Node 1 +python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --port 8000 + +# Node 2 +python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --port 8000 +``` + +2. Launch SMG pointing to workers + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://node1:8000 http://node2:8000 \ + --policy cache_aware \ + --host 0.0.0.0 \ + --port 30000 +``` + +**Option C: Dynamic Worker Registration** + +For elastic deployments where workers can be added/removed dynamically: + +```bash +# Launch SMG first +python -m sglang_router.launch_router \ + --policy cache_aware \ + --host 0.0.0.0 \ + --port 30000 + +# Register workers dynamically +curl -X POST http://localhost:30000/workers \ + -H "Content-Type: application/json" \ + -d '{"url": "http://worker1:8000"}' + +curl -X POST http://localhost:30000/workers \ + -H "Content-Type: application/json" \ + -d '{"url": "http://worker2:8000"}' +``` + +### Load Balancing Policies + +SMG supports multiple load balancing policies: + +| Policy | Description | Best For | +|--------|-------------|----------| +| `cache_aware` | Combines cache locality with load balancing | **Recommended for most workloads** | +| `round_robin` | Cycles through workers in order | Simple, predictable distribution | +| `random` | Random worker selection | Baseline, testing | +| `power_of_two` | Samples two workers, picks lighter one | Low latency requirements | + +**Cache-Aware Policy (Default, Recommended)** + +The cache-aware policy provides the best performance for most workloads: + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8000 \ + --policy cache_aware \ + --cache-threshold 0.5 \ + --balance-abs-threshold 32 \ + --balance-rel-threshold 1.5 \ + --eviction-interval-secs 120 \ + --max-tree-size 67108864 +``` + +**How it works:** + +1. Maintains an approximate radix tree for each worker based on request history +2. Routes requests to workers with the highest prefix match (cache hit) +3. Falls back to shortest-queue routing when load is imbalanced +4. Automatically evicts old entries to prevent memory overflow + +### Best Practices + +1. **Start with `cache_aware` policy** - It provides the best balance between cache locality and load distribution for most workloads +2. **Use SMG for production** - Prefer `sglang_router.launch_server` over `sglang.launch_server` for better reliability and observability +3. **Enable health checks** - Configure `--router-health-check-interval-secs` to detect and remove unhealthy workers automatically + +**Recommended command with best practices applied:** + +```bash +python -m sglang_router.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --dp-size 4 \ + --router-policy cache_aware \ + --router-health-check-interval-secs 30 \ + --router-prometheus-port 10001 \ + --host 0.0.0.0 \ + --port 30000 +``` + +For advanced configuration (circuit breakers, retries, Prometheus metrics, K8s integration), see [SGLang Model Gateway Documentation](sgl_model_gateway.md). + +### Verifying Traffic Distribution + +After launching SMG, verify that traffic is being distributed correctly: + +**1. Check worker status:** + +```bash +curl http://localhost:30000/workers +``` + +**2. Check load distribution:** + +```bash +curl http://localhost:30000/get_loads +``` + +**3. Monitor metrics (if Prometheus enabled):** + +```bash +# Key metrics to check +smg_router_requests_total{model="..."} +smg_worker_requests_active{worker="..."} +sglang_cache_hit_rate{source="..."} +``` + +For detailed metrics and monitoring setup, see [SGLang Model Gateway Documentation](sgl_model_gateway.md). + +## Reference + +| Strategy | Use Case | Key Benefit | +|----------|----------|-------------| +| **Native DP** (`--dp-size`) | Never | Easy to understand, not rust based | +| **SMG-Based DP** | **Production (recommended)** | Cache-aware routing, high availability | +| **DPA** (`--dp-size N --enable-dp-attention`) | DeepSeek/MLA models | Eliminates KV cache duplication, improved throughput | +| **DPA + EP** | DeepSeek MoE models | Significant throughput improvement vs vanilla TP | + +**Recommended production setup for DeepSeek:** +1. Enable **DPA** for attention layers (`--dp-size 8 --enable-dp-attention`) +2. Enable **EP** for MoE layers (`--ep 8 --moe-a2a-backend deepep`) +3. Use **SMG** with **cache_aware** policy + +**Related documentation:** +- [Expert Parallelism](expert_parallelism.md) - DeepEP, Two-Batch Overlap, EPLB +- [SGLang Model Gateway Documentation](sgl_model_gateway.md) - SMG configuration & troubleshooting +- [Large-Scale EP Blog](https://lmsys.org/blog/2025-05-05-large-scale-ep/) - 96 GPU deployment guide diff --git a/sglang/docs/advanced_features/dp_for_multi_modal_encoder.md b/sglang/docs/advanced_features/dp_for_multi_modal_encoder.md new file mode 100644 index 0000000000000000000000000000000000000000..a100e068843981381fc268c0612620e604641f03 --- /dev/null +++ b/sglang/docs/advanced_features/dp_for_multi_modal_encoder.md @@ -0,0 +1,30 @@ +# DP for Multi-Modal Encoder in SGLang + +A typical VLM architecture involves two main components: an multi-modal encoder and a text decoder. + +Most VLMs utilize a Vision Transformer (ViT) as their multi-modal encoder, it is responsible for processing visual data, extracting features (objects, colors, textures, etc.), and transforming them into a format that can be understood by the model. + +The text decoder is based on LLM. It processes textual data and generates output based on the encoded visual features. + +However, since the size of ViT is very small compared to language decoders, +there is relatively little gain from TP. On the other hand, TP incurs significant communication +overhead because of all-reduce being performed after every layer. + +Placing the ViT in data parallel while keeping the LLM in tensor parallel consistently lowers TTFT and boosts end-to-end throughput. In this hybrid layout, the vision front-end becomes parallel and lightweight, while scarce interconnect bandwidth and collective ops are reserved for the LLM. + +Data parallelism replicates the entire model across multiple GPU sets and processes different batches of requests in parallel. + +## Command Example +You can enable batch-level DP by setting `mm-enable-dp-encoder`, for example: +``` +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen2.5-VL-7B-Instruct \ + --tp 2 \ + --mm-enable-dp-encoder +``` + +## Known supported models +- Qwen2.5-VL () +- Qwen3-VL () +- InternVL () +- GLM-4.5V & GLM-4.6V () diff --git a/sglang/docs/advanced_features/epd_disaggregation.md b/sglang/docs/advanced_features/epd_disaggregation.md new file mode 100644 index 0000000000000000000000000000000000000000..c543c29bc5452f1f0ce87ec49f5e6e6247923044 --- /dev/null +++ b/sglang/docs/advanced_features/epd_disaggregation.md @@ -0,0 +1,119 @@ +# EPD Disaggregation + +## Why and What is EPD Disaggregation? + +In modern Vision-Language Model (VLM) inference, request execution naturally decomposes into three distinct stages: Encoder, Prefill, and Decode. +The Encoder stage performs vision preprocessing and ViT-based image encoding, which is highly compute-intensive but only required during request initialization. The Prefill stage processes the full multimodal input sequence to initialize the language model’s Key-Value (KV) cache, while the Decode stage is dominated by memory bandwidth and KV cache access for autoregressive token generation. + +Existing deployments typically colocate these stages within a unified execution engine, or at best apply Prefill–Decode (PD) disaggregation. However, such designs still tightly couple vision encoding with language prefill, leading to inefficient resource utilization, limited scalability for image-heavy workloads, and suboptimal scheduling under load. + +To address these challenges, we introduce Encoder–Prefill–Decode (EPD) Disaggregation in SGLang. EPD further separates vision encoding from language processing, enabling independent horizontal scaling of encoder servers, improved load balancing for multimodal requests, and seamless integration with existing PD disaggregation to form a fully decoupled three-tier inference architecture. + +### Usage + +You can launch a language-only model using `--language-only`, or an encoder-only model using `--encoder-only`. +When launching a language-only model, you must additionally specify the encoder service endpoints via `--encoder-urls`. + +We support multiple encoder transfer backends, including zmq_to_scheduler, zmq_to_tokenizer, and mooncake (the default is zmq_to_scheduler). The backend can be selected using `--encoder-transfer-backend`. + +#### Qwen VL + +- EP Disaggregation + +```bash +# encoder 0 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --encoder-only \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30000 +# encoder 1 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --encoder-only \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30001 +# language-only server +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --language-only \ + --encoder-urls http://127.0.0.1:30000 http://127.0.0.1:30001 \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30002 +``` + +- EPD Disaggregation + +```bash +# encoder 0 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --encoder-only \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30000 +# encoder 1 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --encoder-only \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30001 +# prefill 0 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --disaggregation-mode prefill \ + --language-only \ + --encoder-urls http://127.0.0.1:30000 http://127.0.0.1:30001 \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30002 +# decode 0 +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --disaggregation-mode decode \ + --port 30003 +# router +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --prefill http://$PREFILL_HOST:30002 \ + --decode http://$DECODE_HOST:30003 \ + --port 8000 + +``` + +#### gRPC Encoder (EPD) + +You can run the encoder as a gRPC server while keeping prefill/decode as HTTP. +When using gRPC encoders, set `SGLANG_ENCODER_MM_RECEIVER_MODE=grpc` for the +prefill process so it uses the gRPC receiver. + +```bash +# gRPC encoder +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --encoder-only \ + --grpc-mode \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30000 + +# prefill (HTTP) - tell it to use gRPC receiver +SGLANG_ENCODER_MM_RECEIVER_MODE=grpc \ +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --disaggregation-mode prefill \ + --language-only \ + --encoder-urls grpc://127.0.0.1:30000 \ + --encoder-transfer-backend zmq_to_scheduler \ + --port 30002 + +# decode (HTTP) +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --disaggregation-mode decode \ + --port 30003 + +# router +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --prefill http://$PREFILL_HOST:30002 \ + --decode http://$DECODE_HOST:30003 \ + --port 8000 +``` diff --git a/sglang/docs/advanced_features/expert_parallelism.md b/sglang/docs/advanced_features/expert_parallelism.md new file mode 100644 index 0000000000000000000000000000000000000000..9abe69b5ac04b18b3ade718a75e694cffb338f4c --- /dev/null +++ b/sglang/docs/advanced_features/expert_parallelism.md @@ -0,0 +1,198 @@ +# Expert Parallelism + +Expert Parallelism (EP) in SGLang distributes expert weights across multiple devices in Mixture-of-Experts (MoE) models, addressing memory bottlenecks and enabling efficient scaling for high-performance inference. It is particularly vital for serving large-scale MoE models where tokens are dynamically routed to specialized experts across GPUs. By leveraging optimized all-to-all communication and grouped matrix multiplications (GEMMs), EP reduces latency, boosts throughput, and minimizes idle GPU time. SGLang's EP offers strong extensibility through its modular framework, allowing seamless integration of custom kernels, backends, and optimizations without refactoring core logic, supporting diverse hardware and quantization schemes. + +## Supported Backends and Selection Guidance + +SGLang's EP integrates diverse, highly efficient backends for different use cases, allowing fine-grained control over performance trade-offs. Users specify backends via command-line flags: +- `--moe-a2a-backend`: Selects the backend for all-to-all communication. +- `--moe-runner-backend`: Selects the backend for MoE computation. + +### Backends for All-to-All Communication + +| Backend | Description | Use Cases | +|--------------|-----------------------------------------------------------------------------|------------------------------------| +| **`none` (default)** | Disables all-to-all for EP. Uses All-Reduce or All-Gather for token dispatch. | Hybrid EP and TP setups. | +| `deepep` | DeepEP, a communication library for efficient token shuffling in MoE models. | Large-scale EP deployments. | +| `mooncake` | An extension of DeepEP for elastic inference, leveraging RDMA for high-performance data transfers. | Elastic EP serving. | +| `mori` | MORI-EP, AMD's native all-to-all communication implementation optimized for ROCm. | AMD GPU deployments. | +| `flashinfer` | Flashinfer implementation of all-to-all. | Large-scale EP deployments. | +| `ascend_fuseep` | Ascend NPU native fused all-to-all communication. | Ascend NPU deployments. | + +DeepEP and Mooncake backends support two modes for token dispatch: `normal` mode (optimized for prefill workloads with high throughput) and `low_latency` mode (optimized for decode workloads with low latency and CUDA Graph compatibility). MORI backend only supports `normal` mode now. Users are recommended to set `--deepep-mode auto` to enable automatic dispatch mode switching during runtime. Setting `--deepep-mode normal` or `--deepep-mode low_latency` is useful for debugging or development purposes. + +Currently, DeepEP, Mooncake, `ascend_fuseep` and MORI only support cases where `ep_size = tp_size`. For hybrid EP and TP (i.e., `ep_size < tp_size`), only the `none` backend (All-Reduce or All-Gather-based dispatching) is supported. + +### Backends for MoE Computation + +| Backend | Description | Use Cases | +|--------------------------|-----------------------------------------------------------------------------|------------------------------------| +| **`auto` (default)** | Automatically selects the optimal backend based on model architecture, hardware (e.g., NVIDIA architecture like Ampere, Hopper, Blackwell), quantization scheme (e.g., FP8, FP4), and runtime conditions. | General-purpose deployments; ensures compatibility and performance without user intervention. | +| `triton` | Triton-based implementation for grouped GEMMs. To achieve higher performance, it's highly recommended to create [tuned configurations](https://github.com/sgl-project/sglang/blob/main/benchmark/kernels/fused_moe_triton/README.md). | Custom kernel development or scenarios requiring high extensibility with Torch compilation support. | +| `deep_gemm` | DeepGEMM backend optimized for MoE matrix multiplications, supporting contiguous layouts for prefill and masked layouts for decode; often JIT-compiled for performance. | Large-scale EP deployments with FP8 block-wise quantization. | +| `cutlass` | CUTLASS-based backend for efficient GEMMs. | NVIDIA architectures with CUTLASS support. | +| `flashinfer_trtllm` | FlashInfer integrated with TensorRT-LLM for accelerated MoE computations, supporting FP4 communication operators and high-performance GEMMs. | Blackwell with TRT-LLM. | +| `flashinfer_cutlass` | FlashInfer combined with CUTLASS for high-performance grouped GEMMs in MoE layers, handling FP4/FP8 quantization efficiently. | Blackwell with FP4/FP8 models. | +| `flashinfer_mxfp4` | FlashInfer variant optimized for MXFP4 (mixed FP4) quantization in MoE runners, focusing on memory-efficient low-precision inference. | Low-precision models with MXFP4. | +| `flashinfer_cutedsl` | FlashInfer with a custom DSL for flexible and efficient MoE kernel generation, integrated with ModelOpt FP4 quantization. | Low-precision models with NVFP4. | + +### Examples + +Launch with DeepEP and DeepGEMM for DeepSeek-V3: + +```bash +python -m sglang.launch_server --model-path deepseek-ai/DeepSeek-V3 --moe-a2a-backend deepep --moe-runner-backend deep_gemm --tp 8 --ep 8 +``` + +## Extensible EP Framework + +SGLang's EP framework provides modular abstractions for easy integration of custom kernels, backends, and optimizations. It decouples the MoE forward pass into stages (dispatch → pre-permute → core runner → post-permute → combine), enabling seamless extensions without refactoring core logic. + +### Framework Overview + +The framework centers on `FusedMoE` as the unified entry point for a single, extensible structure. Key components include: +- **Dispatcher**: Manages dispatch/combine for backends like DeepEP (implements `BaseDispatcher` subclasses). +- **MoeRunner**: Orchestrates grouped-GEMM execution via `MoeRunnerCore` implementations (e.g., `TritonRunnerCore`). +- **PermuteMethodPool**: Auto-registers layout conversions (e.g., pre/post-permute via `register_pre_permute` and `register_post_permute` for dynamic modes, or `register_fused_func` for static, torch.compile-compatible fused operations). +- **TopK Router**: Backend-agnostic expert selection. + +This design supports multiple backends via `--moe-a2a-backend` and `--moe-runner-backend`, with quantization integrated through a standardized `apply()` method. The computation flow ensures modularity: + +``` +[input_hidden_states] + | + v + TopK.forward -> select_experts / triton_kernels.routing / bypass + | + v + [TopKOutput] + | + v + FusedMoE.forward -> Dispatcher.dispatch -> DeepEP / bypass + | | + | v + | [DispatchOutput] + | | + | v + | quant_method.apply -> MoeRunner.forward + | | | + | | v + | | pre-permute + grouped_gemm + post-permute + | | | + | |-------------- + | v + | [CombineInput] + | | + | v + | Dispatcher.combine -> DeepEP / bypass + | | + |--------------------- + v +[final_hidden_states] +``` + +For details, see the [MoE Refactor Roadmap](https://github.com/sgl-project/sglang/issues/8715). + +### Implementing New Backends + +To add a new backend: +1. For a new all-to-all dispatcher, implement a `BaseDispatcher` subclass with `dispatch` and `combine` methods. +2. For a new MoE runner backend, define a `MoeRunnerCore` subclass for core operations (e.g., grouped GEMMs). +3. Define new input/output formats for the dispatcher or model runner (e.g., `RunnerInput`, `RunnerOutput`). +4. Register permute/unpermute methods to ensure compatibility: + - **Fused Mode** (static, torch.compile-compatible): Use `register_fused_func` for end-to-end operations. + - **Permute Mode** (dynamic): Register `register_pre_permute` and `register_post_permute` for flexible layouts. + +See the [MoE Refactor Implementation PR](https://github.com/sgl-project/sglang/pull/9269) for full changes, including type hints and config expansions. + +### Examples + +For an example implementation, see [moe_runner/triton.py](https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/layers/moe/moe_runner/triton.py), which demonstrates Triton-based grouped GEMMs with registered fused and permutation functions. + +## Computation and Communication Overlap + +SGLang's EP employs advanced overlap techniques to hide communication latency behind computation, maximizing GPU utilization in MoE layers. + +### Two-Batch Overlap (TBO) + +TBO splits requests into micro-batches, interleaving attention computation with dispatch/combine operations. Yield points in the execution graph allow pausing for overlaps, increasing overall throughput without peak memory spikes: + +```python +operations = [ + self._forward_attn, + YieldOperation(), # Overlap with dispatch of prior micro-batch + self._forward_dispatch, + self._forward_mlp, + YieldOperation(), # Overlap with combine + self._forward_combine, +] +``` + +Users need to specify `--enable-two-batch-overlap` to unlock up to 2x throughput. For details, see the [Large-Scale EP Blog](https://lmsys.org/blog/2025-05-05-large-scale-ep/#two-batch-overlap). + +### Single-Batch Overlap (SBO) + +SGLang introduces a dispatcher-hook system for Single-Batch Overlap (SBO), enabling the overlap of operations within a single batch—such as shared experts computation with communication—while decentralizing logic to enhance modularity. These hooks execute before and after the `dispatch` and `combine` operations without modifying core MoE modules. This design simplifies interfaces, reduces coupling, and improves extensibility. For implementation details and an example of overlapping shared experts with DeepEP's combine operation, refer to [PR #13327](https://github.com/sgl-project/sglang/pull/13327). Users can set `--enable-single-batch-overlap` to enable this feature. + + +## Workload Balancer + +SGLang integrates the [Expert Parallelism Load Balancer (EPLB)](https://github.com/deepseek-ai/EPLB) from DeepSeek to address routing imbalances in MoE models. By analyzing expert activation statistics, EPLB computes an optimal expert arrangement, strategically placing or replicating experts to minimize GPU utilization variance, reduce idle cycles, and enhance scalability. + +To enable EPLB, use the flags `--enable-eplb`. For optimal performance, increase batch sizes to stabilize activation statistics and configure periodic rebalancing (e.g., every 1000 requests) to adapt to evolving workloads. Simulations demonstrate significant improvements in load balancedness (ratio of mean to max computation time), correlating strongly with throughput gains. + +For more details, refer to the [EPLB Section in the Large-Scale EP Blog](https://lmsys.org/blog/2025-05-05-large-scale-ep/#expert-parallelism-load-balancer) and the [EPLB Repository](https://github.com/deepseek-ai/eplb). + + +## EP with Spectulative Decoding + + +When utilizing speculative decoding with MTP on MoE architectures, use the `--speculative-moe-runner-backend` and `--speculative-moe-a2a-backend` arguments to customize the MoE layer behavior for the draft model. While they default to the target model’s settings, users can differentiate them for varying precisions between target and draft models. + +For model like `nvidia/DeepSeek-R1-0528-NVFP4-v2`, the target model uses NVFP4 precision while the draft model uses BF16. To apply `flashinfer_trtllm` kernel for target MoE layer while falling back to triton fused MoE kernel for draft MoE layer, users can set the arguments as follows: +``` +... +--moe-runner-backend flashinfer_trtllm \ +--speculative-moe-runner-backend triton \ +... +``` + + +## Ascend NPU Guidance + + +### Guidance on SGLang configuration in Ascend NPU +- `--moe-a2a-backend` only supports `deepep` and `ascend_fuseep` backends, + - `deepep`: The mechanism is consistent with the above description. + - `ascend_fuseep`: Offer a large fused operator which integrates all operations between dispatch and combine to boost MoE computation. Only used for decode stage in PD Disaggregation Mode. +- `--moe-runner-backend` parameter does not need to be configured. +- `--deepep-mode`: + - In PD mixed mode, please set `--deepep-mode auto`. + - In PD Disaggregation Mode, prefill instance sets `--deepep-mode normal`, and decode instance sets `--deepep-mode low_latency`. + + +### DeepEP Ascend Introduction + +DeepEP Ascend is the adapted version of the DeepEP communication library for Huawei Ascend NPUs, specifically designed for Mixture-of-Experts (MoE) model Expert Parallelism (EP). +It supports the Ant-moving Function (Split the sequence length into rounds for streaming batch transmission) to optimize the buffer size occupied during collective communication in prefill stage, especially for long sequences. + +Ant-moving Function can be enabled for both the dispatch and combine phases via the following environment variables: +- `DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS`: Enable ant-moving function in dispatch stage. Indicates the number of tokens transmitted per round on each rank, default 8192. +- `DEEPEP_NORMAL_LONG_SEQ_ROUND`: Enable ant-moving function in dispatch stage. Indicates the number of rounds transmitted on each rank, default 1. +- `DEEPEP_NORMAL_COMBINE_ENABLE_LONG_SEQ`: Enable ant-moving function in combine stage, default 0 (means disabled). + +`DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS * DEEPEP_NORMAL_LONG_SEQ_ROUND` means input sequence length. When the input sequence length exceeds 8192, it is recommended to enable the ant-moving function in both dispatch and combine phase. + +The environment variable `HCCL_BUFFSIZE` is used to configure the buffer size (MB) actually allocated. Its calculation formula is as follows: +```angular2html +# Enable Ant-moving Function +HCCL_BUFFSIZE >= 2 * (102MB + 4MB + DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS * (hidden_size + hidden_size + hidden_size) * topk) + PADDING_BUFFSIZE + +# Disable Ant-moving Function +HCCL_BUFFSIZE >= 2 * (102MB + 4MB + TOTAL_SEQ_LEN * (hidden_size + hidden_size) * topk) + PADDING_BUFFSIZE +``` +Wherein the parameters are described as follows: +- `hidden_size`: hidden size in model config. +- `topk`: The number of selected routing experts. +- `TOTAL_SEQ_LEN`: input sequence length. +- `PADDING_BUFFSIZE`: A value of 20 or greater is recommended. diff --git a/sglang/docs/advanced_features/forward_hooks.md b/sglang/docs/advanced_features/forward_hooks.md new file mode 100644 index 0000000000000000000000000000000000000000..4dc170b332455ea9319139d467b730f9e716922a --- /dev/null +++ b/sglang/docs/advanced_features/forward_hooks.md @@ -0,0 +1,297 @@ +## Model Hooks + +SGLang supports attaching PyTorch forward hooks to specific submodules in the loaded model, configured entirely via `server_args` JSON. + +This is useful for: + +* Logging intermediate activations +* Debugging model internals +* Exporting hidden states to external tooling + +Hooks are attached once during `ModelRunner.initialize` and run on every forward pass. + +--- + +### Configuration overview + +Hooks are configured via a `ServerArgs` field: + +```python +class ServerArgs: + ... + # For forward hooks + forward_hooks: Optional[List[dict[str, Any]]] = None +```` + +In JSON form, a minimal configuration looks like: + +```jsonc +{ + "forward_hooks": [ + { + "name": "outer_linear_hooks", + "target_modules": ["outer.0", "outer.1"], + "hook_factory": "my_project.hooks:dummy_hook_factory", + "config": { + "tag": "outer-layer" + } + } + ] +} +``` + +#### Top-level fields + +* `forward_hooks` (optional list of objects) + Each element is a hook spec describing: + + * Which modules to target + * Which Python factory to call + * What configuration to pass into that factory + +--- + +### Hook spec schema + +Each entry in `forward_hooks` is a JSON object with the following shape: + +```jsonc +{ + "name": "optional-descriptive-name", + "target_modules": ["pattern1", "pattern2", "..."], + "hook_factory": "module.submodule:factory_name", + "config": { + "...": "arbitrary JSON" + } +} +``` + +#### `name` (optional) + +* Human-readable name for logging. +* Used only in log messages such as: + + ```text + Registered forward hook 'outer_linear_hooks' on outer.0 + ``` + +#### `target_modules` (required) + +* List of **module name patterns** used to match entries in `model.named_modules()`. +* Patterns are matched using `fnmatch.fnmatch`, so: + + * `"outer.0"` matches exactly `"outer.0"`. + * `"outer.*"` matches `"outer.0"`, `"outer.1"`, `"outer.inner"`, etc. + * `"outer.inner.*"` matches children under `outer.inner`. + +> If no modules match the given patterns, hook registration does **not** fail. +> Instead, SGLang logs a warning and continues: +> +> ```text +> No modules matched hook spec 'name' patterns=['...'] +> ``` + +#### `hook_factory` (required) + +* String path to the Python factory function that creates the hook. +* Supported formats: + + * `"package.module:factory_name"` + * `"package.module.submodule.factory_name"` + +The path is resolved via: + +```python +def resolve_callable(path: Optional[str]) -> Optional[Callable]: + if path is None: + return None + + if ":" in path: + module_name, fn_name = path.split(":", 1) + else: + parts = path.split(".") + if len(parts) < 2: + raise ValueError( + f"Invalid hook callable path '{path}'. " + "Expected 'module.submodule:factory' or 'module.submodule.factory'." + ) + *mod_parts, fn_name = parts + module_name = ".".join(mod_parts) + + module = importlib.import_module(module_name) + try: + return getattr(module, fn_name) + except AttributeError as e: + raise AttributeError( + f"Module '{module_name}' has no attribute '{fn_name}' " + f"(from hook path '{path}')" + ) from e +``` + +**Failure modes**: + +* If the path is malformed (not enough dots and no `:`), a `ValueError` is raised at startup. +* If the module imports but the attribute is missing, an `AttributeError` is raised with a clear error message. +* If the hook factory returns `None`, a warning is logged and no hook is registered for that spec (initialization continues). + +The first two cause initialization to fail fast with a descriptive error; the last one is non-fatal. + +#### `config` (optional) + +* Arbitrary JSON object. +* Passed directly to the hook factory as a Python `dict`. +* This lets you parameterize hook behavior from config (e.g. tags, log levels, sampling rates, etc.). + +--- + +### Hook lifecycle and behavior + +Hooks are registered in `ModelRunner.initialize()`: + +```python +if server_args.forward_hooks: + register_forward_hooks(self.model, server_args.forward_hooks) +``` + +The actual registration logic is implemented by `register_forward_hooks`: + +```python +def register_forward_hooks(model: nn.Module, hook_specs: List[dict[str, Any]]) -> None: + """ + hook_specs is a list of dicts from server_args.forward_hooks. + Attaches forward hooks to the matching modules. + """ + name_to_module = dict(model.named_modules()) + + for spec in hook_specs: + spec_name = spec.get("name", "") + target_patterns = spec.get("target_modules", []) + if not target_patterns: + logger.warning( + f"Hook spec '{spec_name}' has no 'target_modules', skipping" + ) + continue + + hook_factory_path = spec.get("hook_factory") + if not hook_factory_path: + logger.warning( + f"Hook spec '{spec_name}' has no 'hook_factory', skipping" + ) + continue + + config = spec.get("config") or {} + hook_factory = resolve_callable(hook_factory_path) + + hook = hook_factory(config) if hook_factory else None + if hook is None: + logger.warning( + f"Hook factory '{hook_factory_path}' for spec '{spec_name}' " + "returned None, not registering any hook" + ) + continue + + # Resolve patterns like "model.layers.*.mlp" + matched = [] + for name, module in name_to_module.items(): + if any(fnmatch.fnmatch(name, pattern) for pattern in target_patterns): + matched.append((name, module)) + + if not matched: + logger.warning( + f"No modules matched hook spec '{spec_name}' " + f"patterns={target_patterns}" + ) + continue + + for module_name, module in matched: + if hook: + _ = module.register_forward_hook(hook) + logger.info( + f"Registered forward hook '{spec_name}' " + f"on {module_name}" + ) +``` + +Key points: + +* Hooks are **forward hooks only** (via `module.register_forward_hook`). +* They are attached once at initialization. +* Hook handles are currently not stored on `ModelRunner` (they cannot be removed later via this API). +* Failure to match any modules is non-fatal; a warning is logged instead. +* If a hook factory returns `None`, a warning is logged and that spec is skipped. + +--- + +### Writing a hook factory + +A hook factory is a regular Python function: + +* Takes a `config: dict` (from JSON) +* Returns a forward hook function with signature `(module, inputs, output)` + +Example: + +```python +HOOK_CALLS = [] + +def dummy_hook_factory(config): + """Factory that returns a forward hook capturing a tag from config.""" + tag = config.get("tag", "default") + + def hook(module, inputs, output): + HOOK_CALLS.append( + { + "module_type": type(module).__name__, + "tag": tag, + "shape": tuple(output.shape), + } + ) + return output # must return output if you don’t want to modify the tensor + + return hook +``` + +In JSON: + +```jsonc +{ + "forward_hooks": [ + { + "name": "capture_outer", + "target_modules": ["outer.0", "outer.1"], + "hook_factory": "my_project.hooks:dummy_hook_factory", + "config": { + "tag": "outer" + } + } + ] +} +``` + +This will: + +* Resolve `my_project.hooks:dummy_hook_factory` to a Python callable. +* Call it with `config = {"tag": "outer"}`. +* Use the returned hook for all modules matching `outer.0` and `outer.1`. +* Append metadata about each call to `HOOK_CALLS`. + +--- + +### Summary + +* Define `forward_hooks` as a list of specs in `ServerArgs` to turn on the feature. + +* Each spec: + + * selects modules via `target_modules` (glob patterns over `model.named_modules()`), + * points to a hook factory via `hook_factory`, + * passes arbitrary `config` into that factory. + +* Hook factories are resolved via `resolve_callable`, which supports `module:factory` and `module.submodule.factory`. + +* Hooks are standard PyTorch forward hooks, attached once at startup and invoked on every forward pass. + +* Misconfiguration is either: + + * **fatal and explicit** (bad path / missing attribute), or + * **non-fatal with clear warnings** (no targets matched, or factory returned `None`). diff --git a/sglang/docs/advanced_features/hicache.rst b/sglang/docs/advanced_features/hicache.rst new file mode 100644 index 0000000000000000000000000000000000000000..e7d83211dc9aa58f53c93ce1bbe83d358fff59f0 --- /dev/null +++ b/sglang/docs/advanced_features/hicache.rst @@ -0,0 +1,9 @@ +Hierarchical KV Caching (HiCache) +================================= + +.. toctree:: + :maxdepth: 1 + + hicache_best_practices.md + hicache_design.md + hicache_storage_runtime_attach_detach.md diff --git a/sglang/docs/advanced_features/hicache_best_practices.md b/sglang/docs/advanced_features/hicache_best_practices.md new file mode 100644 index 0000000000000000000000000000000000000000..104c2b0e2d54f80613ef84affc30a4c420633fa3 --- /dev/null +++ b/sglang/docs/advanced_features/hicache_best_practices.md @@ -0,0 +1,217 @@ +# SGLang HiCache Best Practices + +## Why HiCache Matters + +SGLang HiCache extends the traditional RadixAttention with a three-tier hierarchical KV caching system that dramatically improves performance for long-context and multi-turn conversation scenarios. By intelligently managing KV caches across GPU memory, host memory, and external storage backends, HiCache addresses the fundamental capacity bottleneck that limits cache hit rates in conventional systems. + +## Configuration Guidelines + +## Core HiCache Parameters + +```bash +# Essential HiCache flags +--page-size 64 # Page size for cache management +--enable-hierarchical-cache # Enable HiCache +--hicache-ratio 2 # Host memory ratio (2x GPU memory) +--hicache-size 100 # Host memory size in GBs, will override the above ratio +--hicache-io-backend kernel # The I/O backend of moving data between CPU and GPU +--hicache-write-policy write_through # Cache write policy from GPU to CPU +--hicache-storage-backend # Optional storage backend (e.g., hf3fs, mooncake, etc.) +``` + +Notes: + +- Besides configuring `--hicache-storage-backend` at startup, SGLang also supports **runtime attach/detach** of the HiCache storage backend (no restart required) via HTTP admin endpoints. See [Runtime Attach/Detach HiCache Storage Backend](hicache_storage_runtime_attach_detach.md). + +## Key Configurations with Storage Backends Enabled + +### Memory Layout Optimization + +```bash +# Page-first: Optimized for I/O efficiency with zero-copy (recommended with kernel backend) +--hicache-mem-layout page_first +# Page-first-direct: Optimized for direct I/O operations (Compatible with fa3 and same zero-copy performance as page_first) +--hicache-mem-layout page_first_direct +# Layer-first +--hicache-mem-layout layer_first +``` +**Layout Compatibility:** +- `page_first`: Only compatible with `kernel` I/O backend, automatically switches to `layer_first` with `direct` backend +- `page_first_direct`: Specifically designed for `direct` I/O backend with optimized memory organization + +### Heterogeneous TP Support (GQA/MHA models) + +HiCache storage supports cross-cluster KV reuse when different deployments use different TP sizes (for example, `tp=4` and `tp=8`) and share the same storage backend namespace. + +Use `tp_lcm_size` in `--hicache-storage-backend-extra-config`: + +```bash +# Example: heterogeneous TP = {4, 8}, so lcm = 8 +--hicache-storage-backend-extra-config '{"tp_lcm_size": 8}' +``` + +Guidelines: + +- Set `tp_lcm_size` to the least common multiple (LCM) of all TP sizes that will share the same HiCache storage. +- For MHA models with Mooncake and `page_head` layout, HiCache will split head shards based on `tp_lcm_size` to make keys reusable across heterogeneous TP deployments. +- If all clusters use the same TP size, this option is not needed. + +### Prefetch Policies + +```bash +# Best-effort: Terminate prefetch when needed +--hicache-storage-prefetch-policy best_effort +# Wait-complete: Ensure complete prefetch, higher cache reuse +--hicache-storage-prefetch-policy wait_complete +# Timeout: Balance between completion and best-effort +--hicache-storage-prefetch-policy timeout +``` + +### Integration with PD Disaggregation + +HiCache works seamlessly with PD Disaggregation. You can choose between two configurations: + +1. **Prefill-only HiCache**: Enable HiCache only on Prefill nodes, allowing KV cache sharing among Prefill instances +2. **Full HiCache with async offloading**: Enable HiCache on Prefill nodes and async KV cache offloading on Decode nodes, allowing Prefill nodes to reuse KV caches from Decode nodes in multi-turn dialogue scenarios + +```bash +# Prefill node with HiCache enabled for cross-prefill sharing (ideal for SystemPrompt scenarios) +python3 -m sglang.launch_server \ + --model-path /xxx/DeepSeek-R1/ \ + --tp 8 \ + --host 0.0.0.0 \ + --port 10000 \ + --enable-metrics \ + --enable-cache-report \ + --mem-fraction-static 0.85 \ + --page-size 64 \ + --enable-hierarchical-cache \ + --hicache-ratio 2 \ + --hicache-size 0 \ + --hicache-mem-layout page_first_direct \ + --hicache-io-backend direct \ + --hicache-write-policy write_through \ + --hicache-storage-backend hf3fs \ + --hicache-storage-prefetch-policy wait_complete \ + --disaggregation-ib-device mlx5_0 \ + --disaggregation-mode prefill \ + --disaggregation-transfer-backend mooncake + +# Decode node with async offloading enabled for KV cache reuse by Prefill (ideal for multi-turn conversations) +python3 -m sglang.launch_server \ + --model-path /xxx/DeepSeek-R1/ \ + --tp 8 \ + --host 0.0.0.0 \ + --port 10000 \ + --enable-metrics \ + --enable-cache-report \ + --page-size 64 \ + --hicache-ratio 2 \ + --hicache-size 0 \ + --hicache-mem-layout page_first_direct \ + --hicache-io-backend direct \ + --hicache-write-policy write_through \ + --hicache-storage-backend hf3fs \ + --hicache-storage-prefetch-policy wait_complete \ + --disaggregation-decode-enable-offload-kvcache \ # Enable async KV cache offloading in decode node + --disaggregation-ib-device mlx5_0 \ + --disaggregation-mode decode \ + --disaggregation-transfer-backend mooncake +``` + + +### Deployment with HF3FS + +Here is an example of deploying DeepSeek-R1 with HiCache-HF3FS. For more details, see the [HF3FS Documentation](../../python/sglang/srt/mem_cache/storage/hf3fs/docs/README.md). + +```bash +python3 -m sglang.launch_server \ + --model-path /xxx/DeepSeek-R1/ \ + --log-level info \ + --tp 8 \ + --host 0.0.0.0 \ + --port 10000 \ + --enable-metrics \ + --enable-cache-report \ + --page-size 64 \ + --mem-fraction-static 0.85 \ + --enable-hierarchical-cache \ + --hicache-ratio 2 \ + --hicache-size 0 \ + --hicache-mem-layout page_first_direct \ + --hicache-io-backend direct \ + --hicache-write-policy write_through \ + --hicache-storage-backend hf3fs \ + --hicache-storage-prefetch-policy wait_complete \ +``` + +### Deployment with Mooncake + +Here is an example of deploying Qwen3-235B-A22B-Instruct-2507 with Mooncake. For more details, see the [Mooncake Documentation](../../python/sglang/srt/mem_cache/storage/mooncake_store/README.md). + +```bash +# Set Mooncake environment variables +export MOONCAKE_TE_META_DATA_SERVER="http://127.0.0.1:8080/metadata" +export MOONCAKE_GLOBAL_SEGMENT_SIZE=816043786240 +export MOONCAKE_PROTOCOL="rdma" +export MOONCAKE_DEVICE="$DEVICE_LIST" +export MOONCAKE_MASTER=127.0.0.1:50051 + +# Launch SGLang server with Mooncake backend +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --tp 8 \ + --page-size 64 \ + --enable-hierarchical-cache \ + --hicache-ratio 2 \ + --hicache-mem-layout page_first_direct \ + --hicache-io-backend direct \ + --hicache-storage-backend mooncake \ + --hicache-write-policy write_through \ + --hicache-storage-prefetch-policy timeout +``` + + +## Custom Storage Backend Integration + +To integrate a new storage backend: + +1. **Implement three core methods:** + - `get(key)`: Retrieve value by key + - `exists(key)`: Check key existence + - `set(key, value)`: Store key-value pair + +2. **Register your backend:** Add your storage backend to the HiCache [BackendFactory](../../python/sglang/srt/mem_cache/storage/backend_factory.py#L188) + +The HiCache controller handles all scheduling and synchronization automatically. + +### Dynamic Backend Loading + +Alternatively, you can use dynamic loading to avoid hard-coding your backend in the repository: + +```bash +python3 -m sglang.launch_server \ + --model-path your-model \ + --enable-hierarchical-cache \ + --hicache-storage-backend dynamic \ + --hicache-storage-backend-extra-config '{"backend_name":"custom_backend_name", "module_path": "your_module_path", "class_name": "YourHiCacheClassName"}' +``` + +**Configuration Parameters:** +- `--hicache-storage-backend`: Set to `dynamic` +- `--hicache-storage-backend-extra-config`: JSON configuration with: + - `backend_name`: Custom backend identifier + - `module_path`: Python module path to your implementation + - `class_name`: Your HiCache implementation class name + - `interface_v1`: 0 (disable) or 1 (enable) to control usage of batch_get_v1 and batch_set_v1 methods + + +## Community and Support + +- **GitHub Issues**: Report bugs and feature requests +- **Slack Channel**: Join community discussions in #sgl-kv-cache-store +- **Documentation**: Refer to storage backend-specific guides + +--- + +*This document will be continuously updated based on community feedback and new features. Contributions and suggestions are welcome!* diff --git a/sglang/docs/advanced_features/hicache_design.md b/sglang/docs/advanced_features/hicache_design.md new file mode 100644 index 0000000000000000000000000000000000000000..8996dc6c79f8c2b3d5d3408fb95a02f1aa422880 --- /dev/null +++ b/sglang/docs/advanced_features/hicache_design.md @@ -0,0 +1,157 @@ +# HiCache System Design and Optimization + +This document provides a comprehensive overview of SGLang HiCache, covering its system architecture, workflow and key components. It also details configuration parameters, optimization techniques, and integration with various L3 storage backends, serving as a complete reference for users and developers to understand and tune HiCache for efficient LLM inference. + +## Why and What is HiCache? + +In large language model inference, the prefill phase is often time-consuming: input sequences need to be first converted into Key-Value cache (KV cache) for subsequent decoding. When multiple requests share the same prefix, the KV cache for that prefix is identical. By caching and reusing these shared KV caches, redundant computation can be avoided. To address this, SGLang introduced RadixAttention, which leverages idle GPU memory to cache and reuse prefix KV caches, and **HiCache**, which extends this idea to host memory and distributed storage. + +Inspired by the classic three-level cache design of modern CPUs, HiCache organizes GPU memory as L1, host memory as L2, and distributed storage as L3. This hierarchy enables HiCache to fully exploit the "idle" storage space of GPUs and CPUs, while integrating distributed cache systems such as Mooncake, 3FS, NIXL, and AIBrix KVCache for global KV cache storage and scheduling. As a result, HiCache significantly expands KV cache capacity while maintaining strong read performance—especially in workloads such as multi-QA and long-context inference, where KV cache reuse is frequent. For detailed benchmark results, see [this blog](https://lmsys.org/blog/2025-09-10-sglang-hicache/). + + +## System Design + +### Overall Architecture + +In many modern CPU architectures, the small but fast L1 and L2 caches are private to each core, enabling rapid access to the hottest data, while the larger L3 cache is shared across all cores to significantly reduce redundancy within the cache. Similarly, in HiCache, the L1 and L2 KV caches are private to each inference instance, whereas the L3 KV cache is shared among all inference instances within the cluster. + +### HiRadixTree: Metadata Organization in HiCache + +For KV cache data organization, HiCache builds upon the RadixTree structure introduced in RadixAttention and proposes HiRadixTree. In RadixAttention, each node of the RadixTree corresponds to the KV cache of a consecutive span of tokens in GPU memory. A path from the root to a leaf node represents the prefix of a request, and shared prefixes across multiple requests can reuse the same nodes, thereby avoiding redundant storage. + +HiRadixTree extends this idea: each node corresponds to the KV cache of a span of consecutive tokens and records where that KV cache is stored—whether in local GPU memory, CPU memory, L3 storage, or multiple of these tiers. If stored locally, HiRadixTree maintains precise metadata, including the exact storage address. However, to reduce overhead, HiRadixTree does not store or continuously synchronize metadata for L3 KV cache. Instead, when accessing L3 data, it queries the backend in real time to retrieve the necessary metadata, such as whether the data exists and on which server and location it resides. + +### Overall Workflow + +The workflow of HiCache mainly involves three key operations: **local match**, **prefetch** and **write-back**. When the system receives a new request, it first searches the local L1 and L2 caches for matching KV caches. For parts not found locally, it attempts to prefetch from L3. After prefetching, all required KV caches are loaded into the GPU for computation. Once the prefill computation is complete, the system considers storing the newly generated data into L2 or L3. + +![HiCache Workflow](https://lmsys.org/images/blog/hicache/hicache_overview.png) + +### Local Match + +Local matching is the first step in HiCache's workflow, where incoming request tokens are matched against the HiRadixTree to locate cached KV data in local memory tiers (L1 GPU memory and L2 host memory). + +The matching algorithm traverses the HiRadixTree from the root node, following child nodes that match the token sequence prefix. At each node, the incoming token sequence is compared with the node’s stored token sequence. When `page_size > 1`, matching is performed at the page granularity to optimize memory access patterns. If a match terminates within a node’s stored sequence, the node is automatically split to create an exact boundary, improving the efficiency of future matches. + +The algorithm returns a continuous prefix of the request, with the first part residing in L1 and the latter part in L2. + +Since the process only requires traversing the local HiRadixTree and does not involve any actual data copying, local matching is extremely fast. + +### Prefetch from L3 + +Data prefetching is one of HiCache’s core optimization techniques, designed to proactively load KV caches from L3 storage into local L2 memory, thereby reducing access latency during subsequent operations. + +**Prefetch Trigger Conditions**: +After local matching, for the parts not found in L1 or L2, the system queries L3 to retrieve metadata for the next continuous matching KV caches. If the length of hit cache in L3 exceeds a threshold (default: 256 tokens, configurable), a prefetch operation is triggered. + +**Prefetch Strategies**: HiCache provides three different prefetch termination strategies to address different scenario needs: +- **best_effort**: Terminates immediately when GPU can execute prefill computation, with no waiting time, suitable for scenarios extremely sensitive to latency. +- **wait_complete**: Must wait for all prefetch operations to complete, suitable for scenarios requiring high cache hit rates. +- **timeout**: Terminates after specified time or when complete, balancing latency and cache hit rate needs. + +After prefetching stops, the data already fetched is used together with the local data for the prefill computation. + +For **timeout** strategy, HiCache introduces two configuration parameters to support fine-grained control over prefetch timeout conditions: + +* `prefetch_timeout_base`: the base timeout, representing overhead unrelated to the number of tokens (e.g., scheduling and synchronization). +* `prefetch_timeout_per_ki_token`: the incremental timeout per thousand tokens. + +The timeout is computed as: + +``` +timeout = prefetch_timeout_base + prefetch_timeout_per_ki_token * num_token_to_fetch / 1024 +``` + +### Data Write-back + +The write-back mechanism is responsible for moving frequently accessed KV caches from L1 to L2 and L3, enabling larger and longer-term storage as well as cache sharing across instances. + +**Configurable Write-back Policies**: HiCache supports three write-back strategies: + +* **write_through**: Every access is immediately written back to the next level. When bandwidth is sufficient, this strategy provides the strongest caching benefit. +* **write_through_selective**: Data is written back only after the access frequency exceeds a threshold. This strategy backs up only hot data, reducing I/O overhead. +* **write_back**: Data is written back to the next level only when it is evicted from the upper level. This strategy alleviates storage pressure and is suitable for scenarios where storage capacity is limited but memory utilization must be maximized. + +**Cross-instance Sharing**: When data is written back from L2 to L3, only data not already present in L3 is transferred. KV caches stored in L3 can then be shared across all SGLang instances in the cluster (depending on the L3 backend implementation), significantly improving cache hit rates within the same memory budget. + +### Multi-Rank Synchronization + +During multi-GPU parallel computation, such as tensor parallelism (TP), HiCache must ensure consistent states across different ranks. Therefore, critical computation steps require the use of `all_reduce` for state synchronization. + +For example, during prefetching, `all_reduce(op=min)` is used to ensure that all ranks obtain the same number of L3 hits, preventing inconsistent judgments about whether the prefetch threshold has been reached. Similarly, after prefetching completes or terminates, `all_reduce(op=min)` is again required to guarantee consensus among ranks on the prefix length of the successfully retrieved KV cache. + +### Data Transfer Optimization + +**Zero-Copy Data Transfers**: Both prefetching and write-back involve substantial data movement. Minimizing the number of data copies can significantly improve system performance. HiCache supports passing memory addresses and sizes directly when transferring data from L2 memory to an L3 backend. + +**“Batch-Oriented” Data Organization**: The granularity of data reads and writes has a major impact on performance. To address this, HiCache L3 stores and transfers KV cache data at the granularity of **pages** and supports different data layouts beyond the existing `layer first` scheme, including `page first` and `page first direct`. Under the `page first` and `page first direct` layouts, all KV cache data belonging to the same page is placed in contiguous memory, allowing it to be passed as a single object to L3 using zero-copy transfers. + +![HiCache L2 MEM layout](https://lmsys.org/images/blog/hicache/hicache_layout.png) + +However, because GPU KV computation is naturally performed layer by layer, the GPU inherently operates in a `layer first` layout. When transferring `page first` data from L2 to the GPU, data must be transferred at the granularity of one token per layer. The `page first direct` layout mitigates this issue by grouping together all tokens of a given layer within a page, allowing transfers from L2 to GPU to be aggregated at the page-layer level. + +**CPU-to-GPU Transfer Optimizations**: In HiCache, moving data from CPU memory to GPU is as performance-critical as prefetching data from L3 to L2. HiCache employs several optimizations for this process: + +* **Compute-Transfer Overlap**: During the prefill phase, when transferring data from CPU to GPU, HiCache overlaps layers by concurrently loading the KV cache of layer N+1 while computing layer N. This effectively hides data transfer latency. +* **GPU-assisted I/O Kernels**: On top of `cudaMemcpyAsync`, HiCache implements a set of GPU-assisted I/O kernels specifically optimized for KV cache transfers between CPU and GPU. Compared to the baseline approach, these kernels achieve up to 3x higher transfer speed. + +**Write-back Optimization for MLA**: For MHA (Multi-Head Attention) models under multi-TP, each rank holds `1/tp_size` of a token’s KV data. In contrast, for MLA (Multi-Layer Attention) models, all ranks hold the complete and identical KV data for each token. HiCache includes a dedicated optimization for MLA: only one rank initiates the write-back operation, ensuring that data is not redundantly stored across ranks. + +### Integration with PD-Disaggregation Deployment Mode + +SGLang supports a PD (Prefill-Decode) disaggregation deployment mode through the Mooncake TransferEngine (for details, see [this doc](https://docs.sglang.io/advanced_features/pd_disaggregation.html)). In the PD-disaggregation deployment mode, HiCache can be enabled on both the prefill nodes and decode nodes to optimize prefill performance. If enabled on decode nodes, the decode output will also be written back to L3. + +### Unified Interfaces and Rich L3 Storage Backends + +HiCache encapsulates all read, write, and query operations on L3 backends within the `class HiCacheStorage(ABC)`, exposing a set of simple and consistent interfaces. This design supports a wide range of L3 storage backends and allows users to select the one that best fits their specific use cases. + +- **Mooncake**: Mooncake is a high-performance caching system for LLM inference that leverages RDMA and multi-NIC resources to enable zero-copy, ultra-fast data transfers. Try Mooncake [here](https://github.com/sgl-project/sglang/tree/main/python/sglang/srt/mem_cache/storage/mooncake_store). + +- **DeepSeek 3FS (HF3FS)**: HF3FS is a Kubernetes-native distributed storage solution with operator-based deployment. Try HF3FS [here](https://github.com/sgl-project/sglang/tree/main/python/sglang/srt/mem_cache/storage/hf3fs). + +- **NIXL**: NIXL provides a unified API for accessing various storage plugins, including but not limited to DeepSeek's 3FS, GPU Direct Storage (GDS) and Amazon S3-compatible object storage. Try NIXL [here](https://github.com/sgl-project/sglang/tree/main/python/sglang/srt/mem_cache/storage/nixl). + +- **AIBrix KVCache**: AIBrix KVCache is a production-ready KVCache Offloading Framework, which enables efficient memory tiering and low-overhead cross-engine reuse. Try AIBrix KVCache [here](https://github.com/sgl-project/sglang/tree/main/python/sglang/srt/mem_cache/storage/aibrix_kvcache). + +- **HiCacheFile**: A simple file-based storage backend for demonstration purposes. + +Specifically, **LMCache**, an efficient KV cache layer for enterprise-scale LLM inference, provides an alternative solution to HiCache. Try LMCache [here](https://github.com/sgl-project/sglang/tree/main/python/sglang/srt/mem_cache/storage/lmcache). + +## Related Parameters + +- **`--enable-hierarchical-cache`**: Enable hierarchical cache functionality. This is required to use HiCache. + +- **`--hicache-ratio HICACHE_RATIO`**: The ratio of the size of host KV cache memory pool to the size of device pool. For example, a value of 2 means the host memory pool is twice as large as the device memory pool. The value of this parameter must be greater than 1, as the current implementation requires the host memory allocated for the KV cache to be larger than the device memory allocated for the KV cache. + +- **`--hicache-size HICACHE_SIZE`**: The size of host KV cache memory pool in gigabytes. This parameter overrides `hicache-ratio` if set. For example, `--hicache-size 30` allocates 30GB (1GB = 1e9 bytes) for the host memory pool **for each rank**. If there are 8 ranks, then the total memory size is 240GB. Just like `hicache-ratio`, the value of this parameter must be larger than the size of device memory allocated for KV cache. + +**Note**: `--hicache-ratio` and `--hicache-size` are two critical parameters. In general, a larger HiCache size leads to a higher cache hit rate, which improves prefill performance. However, the relationship between cache size and hit rate is not linear. Once most reusable KV data—especially hot tokens—are already cached, further increasing the size may yield only marginal performance gains. Users can set these parameters based on their workload characteristics and performance requirements. + +- **`--page-size PAGE_SIZE`**: The number of tokens per page. This parameter determines the granularity of KV cache storage and retrieval. Larger page sizes reduce metadata overhead and improve I/O efficiency for storage backends, but may lower the cache hit rate when only part of a page matches the stored KV cache. For workloads with long common prefixes, larger pages can improve performance, while workloads with more diverse prefixes may benefit from smaller pages. See [Data Transfer Optimization](#data-transfer-optimization) for how page granularity affects I/O performance. + +- **`--hicache-storage-prefetch-policy {best_effort,wait_complete,timeout}`**: Controls when prefetching from storage should stop. See [Prefetch from L3](#prefetch-from-l3) for details. + - `best_effort`: Prefetch as much as possible without blocking + - `wait_complete`: Wait for prefetch to complete before proceeding + - `timeout`: Terminates after specified time or when complete (Recommended for production environments, as setting an appropriate timeout helps the system meet required SLOs) + +- **`--hicache-write-policy {write_back,write_through,write_through_selective}`**: Controls how data is written from faster to slower memory tiers. See [Data Write-back](#data-write-back) for details. + - `write_through`: Immediately writes data to all tiers (strongest caching benefits) + - `write_through_selective`: Uses hit-count tracking to back up only frequently accessed data + - `write_back`: Writes data back to slower tiers only when eviction is needed (reduces I/O load) + +- **`--hicache-io-backend {direct,kernel}`**: Choose the I/O backend for KV cache transfer between CPU and GPU. See [Data Transfer Optimization](#data-transfer-optimization) for details. + - `direct`: Standard CUDA memory copy operations + - `kernel`: GPU-assisted I/O kernels (recommended for better performance) + +- **`--hicache-mem-layout {layer_first,page_first,page_first_direct}`**: Memory layout for the host memory pool. See [Data Transfer Optimization](#data-transfer-optimization) for details. + - `layer_first`: Compatible with GPU computation kernels (default for GPU memory) + - `page_first`: Optimized for I/O efficiency + - `page_first_direct`: Groups all tokens of a given layer within a page, allowing transfers from L2 to GPU to be aggregated at the page-layer level + +- **`--hicache-storage-backend {file,mooncake,hf3fs,nixl,aibrix,dynamic}`**: Choose the storage backend for the L3 tier. Built-in backends: file, mooncake, hf3fs, nixl, aibrix. For dynamic backend, use --hicache-storage-backend-extra-config to specify: `backend_name` (custom name), `module_path` (Python module path), `class_name` (backend class name). See [Unified Interfaces and Rich L3 Storage Backends](#unified-interfaces-and-rich-l3-storage-backends) for available backends. + +- **`--enable-lmcache`**: Using LMCache as an alternative hierarchical cache solution. + +- **`--hicache-storage-backend-extra-config HICACHE_STORAGE_BACKEND_EXTRA_CONFIG`**: the extra config can be either + - a JSON string containing extra configuration for the storage backend, e.g., `--hicache-storage-backend-extra-config '{"prefetch_threshold":512, "prefetch_timeout_base": 0.5, "prefetch_timeout_per_ki_token": 0.25}' `, or + - a TOML or JSON or YAML file specifying the extra configuration for the storage backend (to differentiate from the JSON string input, prepend a `@` in front of the file name), e.g., `--hicache-storage-backend-extra-config "@config.toml"` where `config.toml` is the config file containing the complex configurations. This can be useful when the configuration consists of many or complex key-value pairs (for instance, it is preferred to use a config file for NIXL backend as its configurations can be complex). diff --git a/sglang/docs/advanced_features/hicache_storage_runtime_attach_detach.md b/sglang/docs/advanced_features/hicache_storage_runtime_attach_detach.md new file mode 100644 index 0000000000000000000000000000000000000000..f40e36cd083ffe5b38b1bcb68882aa8747e305ce --- /dev/null +++ b/sglang/docs/advanced_features/hicache_storage_runtime_attach_detach.md @@ -0,0 +1,132 @@ +# Runtime Attach/Detach HiCache Storage Backend (No Restart) + +This document explains how to **dynamically attach/detach the HiCache L3 storage backend at runtime** (e.g., `mooncake` / `hf3fs` / `nixl` / `file` / `aibrix` / `eic`) while **SGLang is already running and serving traffic**, without restarting the process. + +For safety and consistency, the current implementation **strictly requires** these operations to happen only when the service is **idle**: + +- **No running requests** +- **No waiting/queued requests** + +If the idle condition is not met, the API will fail fast (HTTP 400) and **will not modify** the current service state. + +--- + +## 1. Background and implementation overview + +### 1.1 Architecture / control path + +The control path is: + +1. **HTTP Server** (`python/sglang/srt/entrypoints/http_server.py`) + - Exposes `PUT /hicache/storage-backend`, `DELETE /hicache/storage-backend`, `GET /hicache/storage-backend` +2. **TokenizerManager** (`python/sglang/srt/managers/tokenizer_communicator_mixin.py`) + - Sends the request to the Scheduler via `_Communicator` +3. **Scheduler** (`python/sglang/srt/managers/scheduler.py`) + - Performs a **strict idle check** + - Calls `tree_cache.attach_storage_backend(...)` / `detach_storage_backend(...)` +4. **HiRadixCache** (`python/sglang/srt/mem_cache/hiradix_cache.py`) + - Parses `hicache_storage_backend_extra_config_json` (supports both backend config and prefetch knobs) + - Calls `cache_controller.attach_storage_backend(...)` / `detach_storage_backend(...)` +5. **HiCacheController** (`python/sglang/srt/managers/cache_controller.py`) + - Creates/destroys the storage backend instance (via `StorageBackendFactory`) + - Starts/stops backend background threads at runtime (prefetch/backup) + +--- + +## 2. Idle-state requirement (strict) + +The Scheduler uses a stricter `_is_idle_for_hicache_storage_op()`: + +- `_is_no_request()` is true (covers running/overlap/pp/disagg and other active states) +- `waiting_queue` is empty +- `grammar_queue` is empty (if the grammar backend is enabled) + +If the condition is not met, attach/detach returns an error like: + +- `Reject attach: scheduler is not idle. #queue-req=... #running-req=...` + +> Tip: before switching, drain upstream traffic and wait for the server to become idle, then call attach/detach. + +### 2.1 DP (data parallel) semantics + +When `dp_size > 1`, the tokenizer dispatches the request to **all DP scheduler instances** and aggregates their responses: + +- The final `success` is **true only if all DP ranks return success** +- The final `message` concatenates messages from all DP ranks + +This is intended to prevent “silent partial success”, but it also means you may see: + +- Overall **failure** even though **some ranks already succeeded** + +Currently there is **no automatic partial rollback** across DP ranks (see TODO in code). Operationally: + +- Prefer to keep backend config identical across ranks +- If attach fails, immediately call detach (best-effort/idempotent), fix config, then retry attach + +--- + +## 3. How to use (HTTP Admin API) + +The examples below assume your SGLang HTTP server is at `http://127.0.0.1:30000`. + +### 3.1 Query current storage backend status + +```bash +curl -s http://127.0.0.1:30000/hicache/storage-backend +``` + +Example response: + +```json +{ + "hicache_storage_backend": "mooncake", + "hicache_storage_backend_extra_config": "{\"master_server_address\":\"127.0.0.1:50051\", ...}" +} +``` + +### 3.2 Attach (enable) a storage backend +```bash +curl -s -X PUT http://127.0.0.1:30000/hicache/storage-backend \ + -H 'Content-Type: application/json' \ + -d '{ + "hicache_storage_backend": "mooncake" + }' +``` + +```bash +curl -s -X PUT http://127.0.0.1:30000/hicache/storage-backend \ + -H 'Content-Type: application/json' \ + -d '{ + "hicache_storage_backend": "mooncake", + "hicache_storage_backend_extra_config_json": "{\"master_server_address\":\"127.0.0.1:50051\",\"protocol\":\"tcp\",\"global_segment_size\":\"4gb\",\"prefetch_threshold\":256}", + "hicache_storage_prefetch_policy": "timeout" + }' +``` + +Notes: + +- `hicache_storage_backend_extra_config_json` can include both: + - **Backend configuration** (e.g., Mooncake master/metadata/protocol, etc.) + - **Prefetch configuration** (`prefetch_threshold`, `prefetch_timeout_base`, `prefetch_timeout_per_ki_token`, `hicache_storage_pass_prefix_keys`) + +### 3.3 Detach (disable) the storage backend + +```bash +curl -s -X DELETE http://127.0.0.1:30000/hicache/storage-backend +``` + +Notes: + +- Detach only makes SGLang **stop using** the L3 storage backend and stops prefetch/backup threads +- It **does not automatically delete** data stored in Mooncake/HF3FS (or other remote backends) + +--- + +## 4. Behavior and caveats + +- **No restart required**: attach/detach switches in-process at runtime +- **Must be idle**: otherwise the request is rejected to avoid consistency issues +- **Host KV layout constraints still apply**: for example, Mooncake still requires layouts like `page_first/page_first_direct/page_head`; if the server's HiCache host-memory layout does not satisfy the backend requirements, attach will fail with an error +- **Observability**: + - After attach, `server_args.hicache_storage_backend*` is updated on both the tokenizer and scheduler sides + - If metrics are enabled, attach will create a storage metrics collector in `HiRadixCache` on demand diff --git a/sglang/docs/advanced_features/hyperparameter_tuning.md b/sglang/docs/advanced_features/hyperparameter_tuning.md new file mode 100644 index 0000000000000000000000000000000000000000..2cdae90b6261da9917b4fdd25fe16a7a89ca49ea --- /dev/null +++ b/sglang/docs/advanced_features/hyperparameter_tuning.md @@ -0,0 +1,77 @@ +# Hyperparameter Tuning + +## Achieving high throughput for offline batch inference + +Achieving a large batch size is the most important thing for attaining high throughput in offline batch inference. +When the server is running at full load in a steady state, look for the following in the log: + +```Decode batch. #running-req: 233, #token: 370959, token usage: 0.82, cuda graph: True, gen throughput (token/s): 4594.01, #queue-req: 317``` + +### Adjust the request submission speed to control `#queue-req` + +`#queue-req` indicates the number of requests in the queue. +If you frequently see `#queue-req: 0`, it suggests that your client code is submitting requests too slowly. +A healthy range for `#queue-req` is `100 - 2000`. +However, avoid making `#queue-req` too large, as this will increase the scheduling overhead on the server. + +### Achieve a high `token usage` + +`token usage` indicates the KV cache memory utilization of the server. `token usage > 0.9` means good utilization. + +If you frequently see `token usage < 0.9` and `#queue-req > 0`, it means the server is too conservative about taking in new requests. You can decrease `--schedule-conservativeness` to a value like 0.3. +The case of a server being too conservative can happen when users send many requests with a large `max_new_tokens` but the requests stop very early due to EOS or stop strings. + +On the other hand, if you see `token usage` very high and you frequently see warnings like +`KV cache pool is full. Retract requests. #retracted_reqs: 1, #new_token_ratio: 0.9998 -> 1.0000`, you can increase `--schedule-conservativeness` to a value like 1.3. +If you see `KV cache pool is full. Retract requests.` occasionally but not frequently (~1 time per minute), it is okay. + +### Tune `--mem-fraction-static` to increase KV cache pool capacity +SGLang allocates memory as follows: + +Total memory usage = model weights + KV cache pool + CUDA graph buffers + activations + +The `--mem-fraction-static` parameter determines how much memory is allocated to the first two components: + +mem_fraction_static = (model weights + KV cache pool) / GPU memory capacity + +To support higher concurrency, you should maximize the KV cache pool capacity by setting `--mem-fraction-static` as high as possible while still reserving enough memory for activations and CUDA graph buffers. + +SGLang uses simple heuristics to set the default value of `--mem-fraction-static`, but you can optimize it for your use cases. +As a rule of thumb, reserving 5–8 GB of memory for activations is typically sufficient. You can check this by inspecting the logs just before the server is ready. +Look for log entries like this: + +``` +[2025-08-11 17:17:03] max_total_num_tokens=665690, chunked_prefill_size=8192, max_prefill_tokens=16384, max_running_requests=4096, context_len=65536, available_gpu_mem=13.50 GB +``` + +Check the `available_gpu_mem` value. +- If it is between 5–8 GB, the setting is good. +- If it is too high (e.g., 10 - 20 GB), increase `--mem-fraction-static` to allocate more memory to the KV cache. +- If it is too low, you risk out-of-memory (OOM) errors later, so decrease `--mem-fraction-static`. + +Another straightforward approach is to increase `--mem-fraction-static` in increments of 0.01 until you encounter OOM errors for your workloads. + +### Avoid out-of-memory errors by tuning `--chunked-prefill-size`, `--mem-fraction-static`, and `--max-running-requests` + +If you encounter out-of-memory (OOM) errors, you can adjust the following parameters: + +- If OOM occurs during prefill, try reducing `--chunked-prefill-size` to `4096` or `2048`. This saves memory but slows down the prefill speed for long prompts. +- If OOM occurs during decoding, try lowering `--max-running-requests`. +- You can also reduce `--mem-fraction-static` to a smaller value, such as 0.8 or 0.7. This decreases the memory usage of the KV cache memory pool and helps prevent OOM errors during both prefill and decoding. However, it limits maximum concurrency and reduces peak throughput. + +### Tune `--cuda-graph-max-bs` +By default, CUDA graph is enabled only for small batch sizes (e.g., less than 160 or 256). +However, for some models, especially at large tensor parallelism sizes, CUDA graph can be useful for batch sizes up to 512 or 768. +Therefore, it may be beneficial to increase `--cuda-graph-max-bs` to a larger value. +Note that CUDA graph consumes more memory, so you may need to reduce `--mem-fraction-static` at the same time. + +### Tune `--dp-size` and `--tp-size` + +Data parallelism is better for throughput. When there is enough GPU memory, always favor data parallelism for throughput. Refer to [SGLang Model Gateway (former Router)](../advanced_features/sgl_model_gateway.md) for a better data parallelism rather than using `dp_size` parameter. + +### Try other options + +- `torch.compile` accelerates small models on small batch sizes. You can enable it with `--enable-torch-compile`. +- Try other quantization (e.g. FP8 quantization with `--quantization fp8`) +- Try other parallelism strategies (e.g. [expert parallelism](https://lmsys.org/blog/2025-05-05-large-scale-ep/)) or DP attention for deepseek models (with `--enable-dp-attention --dp-size 8`). +- If the workload has many shared prefixes, try `--schedule-policy lpm`. Here, `lpm` stands for longest prefix match. It reorders requests to encourage more cache hits but introduces more scheduling overhead. diff --git a/sglang/docs/advanced_features/lora.ipynb b/sglang/docs/advanced_features/lora.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..8e6e6d0a02aff74bc7c4bfd4b21525b9169cc542 --- /dev/null +++ b/sglang/docs/advanced_features/lora.ipynb @@ -0,0 +1,714 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# LoRA Serving" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SGLang enables the use of [LoRA adapters](https://arxiv.org/abs/2106.09685) with a base model. By incorporating techniques from [S-LoRA](https://arxiv.org/pdf/2311.03285) and [Punica](https://arxiv.org/pdf/2310.18547), SGLang can efficiently support multiple LoRA adapters for different sequences within a single batch of inputs." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Arguments for LoRA Serving" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following server arguments are relevant for multi-LoRA serving:\n", + "\n", + "* `enable_lora`: Enable LoRA support for the model. This argument is automatically set to True if `--lora-paths` is provided for backward compatibility.\n", + "\n", + "* `enable_lora_overlap_loading`: Enable asynchronous LoRA weight loading in order to overlap H2D transfers with GPU compute. This should be enabled if you find that your LoRA workloads are bottlenecked by adapter weight loading, for example when frequently loading large LoRA adapters.\n", + "\n", + "* `lora_paths`: The list of LoRA adapters to load. Each adapter must be specified in one of the following formats: | = | JSON with schema {\"lora_name\":str,\"lora_path\":str,\"pinned\":bool}.\n", + "\n", + "* `max_loras_per_batch`: Maximum number of adaptors used by each batch. This argument can affect the amount of GPU memory reserved for multi-LoRA serving, so it should be set to a smaller value when memory is scarce. Defaults to be 8.\n", + "\n", + "* `max_loaded_loras`: If specified, it limits the maximum number of LoRA adapters loaded in CPU memory at a time. The value must be greater than or equal to `max-loras-per-batch`.\n", + "\n", + "* `lora_eviction_policy`: LoRA adapter eviction policy when GPU memory pool is full. `lru`: Least Recently Used (default, better cache efficiency). `fifo`: First-In-First-Out.\n", + "\n", + "* `lora_backend`: The backend of running GEMM kernels for Lora modules. Currently we support Triton LoRA backend (`triton`) and Chunked SGMV backend (`csgmv`). In the future, faster backend built upon Cutlass or Cuda kernels will be added.\n", + "\n", + "* `max_lora_rank`: The maximum LoRA rank that should be supported. If not specified, it will be automatically inferred from the adapters provided in `--lora-paths`. This argument is needed when you expect to dynamically load adapters of larger LoRA rank after server startup.\n", + "\n", + "* `lora_target_modules`: The union set of all target modules where LoRA should be applied (e.g., `q_proj`, `k_proj`, `gate_proj`). If not specified, it will be automatically inferred from the adapters provided in `--lora-paths`. This argument is needed when you expect to dynamically load adapters of different target modules after server startup. You can also set it to `all` to enable LoRA for all supported modules. However, enabling LoRA on additional modules introduces a minor performance overhead. If your application is performance-sensitive, we recommend only specifying the modules for which you plan to load adapters.\n", + "\n", + "* `--max-lora-chunk-size`: Maximum chunk size for the ChunkedSGMV LoRA backend. Only used when --lora-backend is 'csgmv'. Choosing a larger value might improve performance. Please tune this value based on your hardware and workload as needed. Defaults to 16.\n", + "\n", + "* `tp_size`: LoRA serving along with Tensor Parallelism is supported by SGLang. `tp_size` controls the number of GPUs for tensor parallelism. More details on the tensor sharding strategy can be found in [S-Lora](https://arxiv.org/pdf/2311.03285) paper.\n", + "\n", + "From client side, the user needs to provide a list of strings as input batch, and a list of adaptor names that each input sequence corresponds to." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage\n", + "\n", + "### Serving Single Adaptor" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** SGLang supports LoRA adapters through two APIs:\n", + "\n", + "1. **OpenAI-Compatible API** (`/v1/chat/completions`, `/v1/completions`): Use the `model:adapter-name` syntax. See [OpenAI API with LoRA](../basic_usage/openai_api_completions.ipynb#Using-LoRA-Adapters) for examples.\n", + "\n", + "2. **Native API** (`/generate`): Pass `lora_path` in the request body (shown below)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import requests\n", + "\n", + "from sglang.test.doc_patch import launch_server_cmd\n", + "from sglang.utils import wait_for_server, terminate_process" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "server_process, port = launch_server_cmd(\n", + " # Here we set max-loras-per-batch to 2: one slot for adaptor and another one for base model\n", + " \"\"\"\n", + "python3 -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --lora-paths lora0=algoprog/fact-generation-llama-3.1-8b-instruct-lora \\\n", + " --max-loras-per-batch 2 \\\n", + " --log-level warning \\\n", + "\"\"\"\n", + ")\n", + "\n", + "wait_for_server(f\"http://localhost:{port}\", process=server_process)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = f\"http://127.0.0.1:{port}\"\n", + "json_data = {\n", + " \"text\": [\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": {\"max_new_tokens\": 32, \"temperature\": 0},\n", + " # The first input uses lora0, and the second input uses the base model\n", + " \"lora_path\": [\"lora0\", None],\n", + "}\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "print(f\"Output 0: {response.json()[0]['text']}\")\n", + "print(f\"Output 1: {response.json()[1]['text']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Serving Multiple Adaptors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "server_process, port = launch_server_cmd(\"\"\"\n", + "python3 -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --lora-paths lora0=algoprog/fact-generation-llama-3.1-8b-instruct-lora \\\n", + " lora1=Nutanix/Meta-Llama-3.1-8B-Instruct_SFT_lora_4_alpha_16_humaneval_raw_json \\\n", + " --max-loras-per-batch 2 \\\n", + " --log-level warning \\\n", + "\"\"\")\n", + "\n", + "wait_for_server(f\"http://localhost:{port}\", process=server_process)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = f\"http://127.0.0.1:{port}\"\n", + "json_data = {\n", + " \"text\": [\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": {\"max_new_tokens\": 32, \"temperature\": 0},\n", + " # The first input uses lora0, and the second input uses lora1\n", + " \"lora_path\": [\"lora0\", \"lora1\"],\n", + "}\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "print(f\"Output 0: {response.json()[0]['text']}\")\n", + "print(f\"Output 1: {response.json()[1]['text']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamic LoRA loading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of specifying all adapters during server startup via `--lora-paths`. You can also load & unload LoRA adapters dynamically via the `/load_lora_adapter` and `/unload_lora_adapter` API.\n", + "\n", + "When using dynamic LoRA loading, it's recommended to explicitly specify both `--max-lora-rank` and `--lora-target-modules` at startup. For backward compatibility, SGLang will infer these values from `--lora-paths` if they are not explicitly provided. However, in that case, you would have to ensure that all dynamically loaded adapters share the same shape (rank and target modules) as those in the initial `--lora-paths` or are strictly \"smaller\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "lora0 = \"Nutanix/Meta-Llama-3.1-8B-Instruct_SFT_lora_4_alpha_16_humaneval_raw_json\" # rank - 4, target modules - q_proj, k_proj, v_proj, o_proj, gate_proj\n", + "lora1 = \"algoprog/fact-generation-llama-3.1-8b-instruct-lora\" # rank - 64, target modules - q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj\n", + "lora0_new = \"philschmid/code-llama-3-1-8b-text-to-sql-lora\" # rank - 256, target modules - q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj\n", + "\n", + "\n", + "# The `--target-lora-modules` param below is technically not needed, as the server will infer it from lora0 which already has all the target modules specified.\n", + "# We are adding it here just to demonstrate usage.\n", + "server_process, port = launch_server_cmd(\"\"\"\n", + " python3 -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --cuda-graph-max-bs 2 \\\n", + " --max-loras-per-batch 2 \\\n", + " --max-lora-rank 256\n", + " --lora-target-modules all\n", + " --log-level warning\n", + " \"\"\")\n", + "\n", + "url = f\"http://127.0.0.1:{port}\"\n", + "wait_for_server(url, process=server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load adapter lora0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " url + \"/load_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora0\",\n", + " \"lora_path\": lora0,\n", + " },\n", + ")\n", + "\n", + "if response.status_code == 200:\n", + " print(\"LoRA adapter loaded successfully.\", response.json())\n", + "else:\n", + " print(\"Failed to load LoRA adapter.\", response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load adapter lora1:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " url + \"/load_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora1\",\n", + " \"lora_path\": lora1,\n", + " },\n", + ")\n", + "\n", + "if response.status_code == 200:\n", + " print(\"LoRA adapter loaded successfully.\", response.json())\n", + "else:\n", + " print(\"Failed to load LoRA adapter.\", response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check inference output:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = f\"http://127.0.0.1:{port}\"\n", + "json_data = {\n", + " \"text\": [\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": {\"max_new_tokens\": 32, \"temperature\": 0},\n", + " # The first input uses lora0, and the second input uses lora1\n", + " \"lora_path\": [\"lora0\", \"lora1\"],\n", + "}\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "print(f\"Output from lora0: \\n{response.json()[0]['text']}\\n\")\n", + "print(f\"Output from lora1 (updated): \\n{response.json()[1]['text']}\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Unload lora0 and replace it with a different adapter:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " url + \"/unload_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora0\",\n", + " },\n", + ")\n", + "\n", + "response = requests.post(\n", + " url + \"/load_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora0\",\n", + " \"lora_path\": lora0_new,\n", + " },\n", + ")\n", + "\n", + "if response.status_code == 200:\n", + " print(\"LoRA adapter loaded successfully.\", response.json())\n", + "else:\n", + " print(\"Failed to load LoRA adapter.\", response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check output again:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = f\"http://127.0.0.1:{port}\"\n", + "json_data = {\n", + " \"text\": [\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": {\"max_new_tokens\": 32, \"temperature\": 0},\n", + " # The first input uses lora0, and the second input uses lora1\n", + " \"lora_path\": [\"lora0\", \"lora1\"],\n", + "}\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "print(f\"Output from lora0: \\n{response.json()[0]['text']}\\n\")\n", + "print(f\"Output from lora1 (updated): \\n{response.json()[1]['text']}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### OpenAI-compatible API usage\n", + "\n", + "You can use LoRA adapters via the OpenAI-compatible APIs by specifying the adapter in the `model` field using the `base-model:adapter-name` syntax (for example, `qwen/qwen2.5-0.5b-instruct:adapter_a`). For more details and examples, see the “Using LoRA Adapters” section in the OpenAI API documentation: [openai_api_completions.ipynb](../basic_usage/openai_api_completions.ipynb).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### LoRA GPU Pinning" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another advanced option is to specify adapters as `pinned` during loading. When an adapter is pinned, it is permanently assigned to one of the available GPU pool slots (as configured by `--max-loras-per-batch`) and will not be evicted from GPU memory during runtime. Instead, it remains resident until it is explicitly unloaded.\n", + "\n", + "This can improve performance in scenarios where the same adapter is frequently used across requests, by avoiding repeated memory transfers and reinitialization overhead. However, since GPU pool slots are limited, pinning adapters reduces the flexibility of the system to dynamically load other adapters on demand. If too many adapters are pinned, it may lead to degraded performance, or in the most extreme case (`Number of pinned adapters == max-loras-per-batch`), halt all unpinned requests. Therefore, currently SGLang limits maximal number of pinned adapters to `max-loras-per-batch - 1` to prevent unexpected starvations. \n", + "\n", + "In the example below, we start a server with `lora1` loaded as pinned, `lora2` and `lora3` loaded as regular (unpinned) adapters. Please note that, we intentionally specify `lora2` and `lora3` in two different formats to demonstrate that both are supported." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "server_process, port = launch_server_cmd(\"\"\"\n", + " python3 -m sglang.launch_server --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --cuda-graph-max-bs 8 \\\n", + " --max-loras-per-batch 3 \\\n", + " --max-lora-rank 256 \\\n", + " --lora-target-modules all \\\n", + " --lora-paths \\\n", + " {\"lora_name\":\"lora0\",\"lora_path\":\"Nutanix/Meta-Llama-3.1-8B-Instruct_SFT_lora_4_alpha_16_humaneval_raw_json\",\"pinned\":true} \\\n", + " {\"lora_name\":\"lora1\",\"lora_path\":\"algoprog/fact-generation-llama-3.1-8b-instruct-lora\"} \\\n", + " lora2=philschmid/code-llama-3-1-8b-text-to-sql-lora\n", + " --log-level warning\n", + " \"\"\")\n", + "\n", + "\n", + "url = f\"http://127.0.0.1:{port}\"\n", + "wait_for_server(url, process=server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also specify adapter as pinned during dynamic adapter loading. In the example below, we reload `lora2` as pinned adapter:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " url + \"/unload_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora1\",\n", + " },\n", + ")\n", + "\n", + "response = requests.post(\n", + " url + \"/load_lora_adapter\",\n", + " json={\n", + " \"lora_name\": \"lora1\",\n", + " \"lora_path\": \"algoprog/fact-generation-llama-3.1-8b-instruct-lora\",\n", + " \"pinned\": True, # Pin the adapter to GPU\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Verify that the results are expected:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "url = f\"http://127.0.0.1:{port}\"\n", + "json_data = {\n", + " \"text\": [\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": {\"max_new_tokens\": 32, \"temperature\": 0},\n", + " # The first input uses lora0, and the second input uses lora1\n", + " \"lora_path\": [\"lora0\", \"lora1\", \"lora2\"],\n", + "}\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "print(f\"Output from lora0 (pinned): \\n{response.json()[0]['text']}\\n\")\n", + "print(f\"Output from lora1 (pinned): \\n{response.json()[1]['text']}\\n\")\n", + "print(f\"Output from lora2 (not pinned): \\n{response.json()[2]['text']}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Choosing LoRA Backend\n", + "\n", + "SGLang supports two LoRA backends that you can choose from using the `--lora-backend` argument:\n", + "\n", + "- `triton`: Basic Triton-based backend.\n", + "- `csgmv`: Default chunked SGMV backend optimized for high concurrency scenarios.\n", + "\n", + "The `csgmv` backend was recently introduced to improve performance especially at high-concurrency scenarios. Our benchmark shows that it achieves 20% to 80% latency improvements over the basic triton backend." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "server_process, port = launch_server_cmd(\"\"\"\n", + " python3 -m sglang.launch_server \\\n", + " --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --lora-backend csgmv \\\n", + " --max-loras-per-batch 16 \\\n", + " --lora-paths lora1=path/to/lora1 lora2=path/to/lora2\n", + " \"\"\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## LoRA Overlap Loading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By using the `--enable-lora-overlap-loading` server argument, the SGLang engine is able to overlap the loading of LoRA weights with prefill and decode compute, essentially hiding the data movement for LoRA weights behind GPU computation. Our benchmarks show that under adversarial conditions, enabling this feature can result in a ~35% reduction in median TTFT - (see the [LoRA overlap loading PR](https://github.com/sgl-project/sglang/pull/15512) for detailed benchmarks)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "lora0 = \"Nutanix/Meta-Llama-3.1-8B-Instruct_SFT_lora_4_alpha_16_humaneval_raw_json\"\n", + "lora1 = \"algoprog/fact-generation-llama-3.1-8b-instruct-lora\"\n", + "lora2 = \"philschmid/code-llama-3-1-8b-text-to-sql-lora\"\n", + "\n", + "\n", + "server_process, port = launch_server_cmd(\"\"\"\n", + " python3 -m sglang.launch_server \\\n", + " --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \\\n", + " --enable-lora \\\n", + " --enable-lora-overlap-loading \\\n", + " --lora-paths lora0=Nutanix/Meta-Llama-3.1-8B-Instruct_SFT_lora_4_alpha_16_humaneval_raw_json \\\n", + " lora1=algoprog/fact-generation-llama-3.1-8b-instruct-lora \\\n", + " lora2=philschmid/code-llama-3-1-8b-text-to-sql-lora \\\n", + " --max-lora-rank 256 \\\n", + " --max-loras-per-batch 2 \\\n", + " --max-loaded-loras 4\n", + " \"\"\")\n", + "\n", + "url = f\"http://127.0.0.1:{port}\"\n", + "wait_for_server(url, process=server_process)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "json_data = {\n", + " \"text\": [\n", + " \"Write a very long fairy-tale.\",\n", + " \"List 3 countries and their capitals.\",\n", + " \"List 3 countries and their capitals.\",\n", + " ],\n", + " \"sampling_params\": [\n", + " {\"max_new_tokens\": 1024, \"temperature\": 0},\n", + " {\"max_new_tokens\": 64, \"temperature\": 0},\n", + " {\"max_new_tokens\": 64, \"temperature\": 0},\n", + " ],\n", + " \"lora_path\": [\"lora0\", \"lora1\", \"lora2\"],\n", + "}\n", + "\n", + "# lora0 and lora1 will be loaded into the memory pool first, and because max_loras_per_batch = 2, lora2's request will remain in the queue.\n", + "# lora1's request will likely finish first, and once it does, lora2 will be loaded. With --enable-lora-overlap-loading, this loading will\n", + "# occur asynchronously and thus decoding for lora0's request won't be blocked.\n", + "response = requests.post(\n", + " url + \"/generate\",\n", + " json=json_data,\n", + ")\n", + "\n", + "for i in range(3):\n", + " print(f\"Output from lora{i}: \\n{response.json()[i]['text']}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Limitations of LoRA Overlap Loading" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, LoRA overlap loading is not free and comes with two important caveats:\n", + "\n", + "1. **Pinned CPU memory requirement**:\n", + " Asynchronous H2D memory copies require LoRA weights to be pinned in CPU memory, which is a finite system resource. To mitigate excessive pinned-memory usage, SGLang currently restricts `max_loaded_loras` to be at most 2× `max_loras_per_batch` when LoRA overlap loading is enabled.\n", + "\n", + "2. **Reduced multi-adapter prefill batching**:\n", + " With overlap loading, adapters become available on the GPU at different times because each adapter is loaded asynchronously. This can reduce the scheduler’s ability to form multi-adapter prefill batches, since only requests whose adapters are currently loaded can be grouped together. As a result, requests for different adapters will be scheduled in separate (or smaller) prefill batches, which can increase TTFT when adapter load time is small compared to prefill compute time. This is why LoRA overlap loading is disabled by default: it should only be enabled when users have determined that LoRA weight loading is a bottleneck (EG high adapter churn, heavy adapter weights, or PCIe-bottlenecked workloads).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Example When Overlap Loading Results in Higher Latency" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For instance, suppose we have four LoRA adapters: `lora0`, `lora1`, `lora2`, and `lora3`. Loading any adapter takes 2ms, while the prefill step for requests for that adapter takes 20ms.\n", + "\n", + "1. **Baseline**:\n", + " The engine loads all four adapters synchronously, then runs one combined prefill batch, giving us a total time of ≈ `2 * 4 + 20 = 28ms`\n", + "\n", + "2. **With LoRA overlap loading enabled**:\n", + " The engine begins loading `lora0` and, once it is ready, schedules a prefill batch containing only `lora0` while `lora1` loads in the background. Then it schedules `lora1`’s prefill while `lora2` loads, and so on. In the worst case where prefill cannot be batched across adapters, total time is ≈ `2 + 4 * 20 = 82ms`\n", + "\n", + "In this scenario, overlap loading reduces adapter-load overhead, but the loss of multi-adapter prefill batching dominates and leads to higher TTFT." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Future Works\n", + "\n", + "The development roadmap for LoRA-related features can be found in this [issue](https://github.com/sgl-project/sglang/issues/2929). Other features, including Embedding Layer, Unified Paging, Cutlass backend are still under development." + ] + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/sglang/docs/advanced_features/observability.md b/sglang/docs/advanced_features/observability.md new file mode 100644 index 0000000000000000000000000000000000000000..9c5d2e1753408170909f019e15e01a16149b2431 --- /dev/null +++ b/sglang/docs/advanced_features/observability.md @@ -0,0 +1,35 @@ +# Observability + +## Production Metrics +SGLang exposes the following metrics via Prometheus. You can enable them by adding `--enable-metrics` when launching the server. +You can query them by: +``` +curl http://localhost:30000/metrics +``` + +See [Production Metrics](../references/production_metrics.md) and [Production Request Tracing](../references/production_request_trace.md) for more details. + +## Logging + +By default, SGLang does not log any request contents. You can log them by using `--log-requests`. +You can control the verbosity by using `--log-request-level`. +See [Logging](server_arguments.md#logging) for more details. + +## Request Dump and Replay + +You can dump all requests and replay them later for benchmarking or other purposes. + +To start dumping, use the following command to send a request to a server: +``` +python3 -m sglang.srt.managers.configure_logging --url http://localhost:30000 --dump-requests-folder /tmp/sglang_request_dump --dump-requests-threshold 100 +``` +The server will dump the requests into a pickle file for every 100 requests. + +To replay the request dump, use `scripts/playground/replay_request_dump.py`. + +## Crash Dump and Replay +Sometimes the server might crash, and you may want to debug the cause of the crash. +SGLang supports crash dumping, which will dump all requests from the 5 minutes before the crash, allowing you to replay the requests and debug the reason later. + +To enable crash dumping, use `--crash-dump-folder /tmp/crash_dump`. +To replay the crash dump, use `scripts/playground/replay_request_dump.py`. diff --git a/sglang/docs/advanced_features/pd_disaggregation.md b/sglang/docs/advanced_features/pd_disaggregation.md new file mode 100644 index 0000000000000000000000000000000000000000..17b81b86368eddc71c690535929a0eca1f86be67 --- /dev/null +++ b/sglang/docs/advanced_features/pd_disaggregation.md @@ -0,0 +1,352 @@ +# PD Disaggregation + +## Why and What is PD Disaggregation? + +Large Language Model (LLM) inference comprises two distinct phases: **Prefill** and **Decode**. The Prefill phase is computation-intensive, processing the entire input sequence, while the Decode phase is memory-intensive, managing the Key-Value (KV) cache for token generation. Traditionally, these phases are handled within a unified engine, where combined scheduling of prefill and decode batches introduces inefficiencies. To address these challenges, we introduce **Prefill and Decoding (PD) Disaggregation** in SGLang. + +### Issues with Unified Scheduling + +The conventional unified engine, which processes prefill and decode batches together, results in two significant problems: + +1. **Prefill Interruption**: Incoming prefill batches frequently interrupt ongoing decode batches, causing substantial delays in token generation. +2. **DP Attention Imbalance**: In data-parallel (DP) attention, one DP worker may process a prefill batch while another handles a decode batch simultaneously, leading to increased decode latency. + +PD Disaggregation resolves these by separating the two stages, enabling tailored optimizations for each. + +For the design details, please refer to [link](https://docs.google.com/document/d/1rQXJwKd5b9b1aOzLh98mnyMhBMhlxXA5ATZTHoQrwvc/edit?tab=t.0). + +Currently, we support Mooncake and NIXL as the transfer engine. + +## Profiling in PD Disaggregation Mode + +When you need to profile prefill or decode workers in PD disaggregation mode, please refer to the [Profile In PD Disaggregation Mode](https://docs.sglang.io/developer_guide/benchmark_and_profiling.html#profile-in-pd-disaggregation-mode) section in the Benchmark and Profiling guide. Due to torch profiler limitations, prefill and decode workers must be profiled separately using dedicated command-line options. + +## Router Integration + +For deploying PD disaggregation at scale with load balancing and fault tolerance, SGLang provides a router. The router can distribute requests between prefill and decode instances using various routing policies. For detailed information on setting up routing with PD disaggregation, including configuration options and deployment patterns, see the [SGLang Model Gateway (former Router)](../advanced_features/sgl_model_gateway.md#prefill-decode-disaggregation). + + +## Mooncake +### Requirements + +```bash +uv pip install mooncake-transfer-engine +``` + +### Usage + +### Llama Single Node + +```bash +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode prefill \ + --port 30000 \ + --disaggregation-ib-device mlx5_roce0 +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode decode \ + --port 30001 \ + --base-gpu-id 1 \ + --disaggregation-ib-device mlx5_roce0 +python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000 +``` + +### DeepSeek Multi-Node + +```bash +# prefill 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-ib-device ${device_name} \ + --disaggregation-mode prefill \ + --host ${local_ip} \ + --port 30000 \ + --trust-remote-code \ + --dist-init-addr ${prefill_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 0 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 +# prefill 1 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-ib-device ${device_name} \ + --disaggregation-mode prefill \ + --host ${local_ip} \ + --port 30000 \ + --trust-remote-code \ + --dist-init-addr ${prefill_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 1 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 +# decode 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-ib-device ${device_name} \ + --disaggregation-mode decode \ + --host ${local_ip} \ + --port 30001 \ + --trust-remote-code \ + --dist-init-addr ${decode_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 0 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 \ + --max-running-requests 128 +# decode 1 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-ib-device ${device_name} \ + --disaggregation-mode decode \ + --host ${local_ip} \ + --port 30001 \ + --trust-remote-code \ + --dist-init-addr ${decode_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 1 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 \ + --max-running-requests 128 +``` +### Advanced Configuration + +PD Disaggregation with Mooncake supports the following environment variables for fine-grained control over system behavior. + +#### NVLink Transport Configuration +To enable NVLink transport for KV cache transfers with the mooncake backend (recommended for NVL72 deployments), set the following environment variables. Note that auxiliary data transfer will still use TCP as a temporary workaround. + +```bash +export SGLANG_MOONCAKE_CUSTOM_MEM_POOL=NVLINK +export MC_FORCE_MNNVL=True +``` + +The `SGLANG_MOONCAKE_CUSTOM_MEM_POOL` environment variable enables the custom memory pool. Supported values are `NVLINK` (or `True`), `BAREX`, and `INTRA_NODE_NVLINK`. + +#### Prefill Server Configuration +| Variable | Description | Default | +|:--------:|:-----------:|:--------: +| **`SGLANG_DISAGGREGATION_THREAD_POOL_SIZE`** | Controls the total number of worker threads for KVCache transfer operations per TP rank | A dynamic value calculated by `int(0.75 * os.cpu_count()) // 8)`, which is limited to be larger than 4 and less than 12 to ensure efficiency and prevent thread race conditions | +| **`SGLANG_DISAGGREGATION_QUEUE_SIZE`** | Sets the number of parallel transfer queues. KVCache transfer requests from multiple decode instances will be sharded into these queues so that they can share the threads and the transfer bandwidth at the same time. If it is set to `1`, then we transfer requests one by one according to fcfs strategy | `4` | +| **`SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT`** | Timeout (seconds) for receiving destination KV indices during request initialization | `300` | +| **`SGLANG_DISAGGREGATION_BOOTSTRAP_ENTRY_CLEANUP_INTERVAL`** | Interval (seconds) between cleanups of bootstrap entries | `120` | + +If a greater mean TTFT is acceptable, you can `export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600` (10 minutes) to relax the timeout condition. +Please be aware that this setting will cause prefill instances to take a longer time to clean up the affected memory resources when a running decode node loses connection. + +#### Decode Server Configuration +| Variable | Description | Default | +|:--------:|:-----------:|:--------: +| **`SGLANG_DISAGGREGATION_HEARTBEAT_INTERVAL`** | Interval (seconds) between health checks to prefill bootstrap servers | `5.0` | +| **`SGLANG_DISAGGREGATION_HEARTBEAT_MAX_FAILURE`** | Consecutive heartbeat failures before marking prefill server offline | `2` | +| **`SGLANG_DISAGGREGATION_WAITING_TIMEOUT`** | Timeout (seconds) for receiving KV Cache after request initialization | `300` | + +If a greater mean TTFT is acceptable, you can `export SGLANG_DISAGGREGATION_WAITING_TIMEOUT=600` (10 minutes) to relax the timeout condition. + + +## NIXL +### Requirements + +Install via pip. + +```bash +pip install nixl +``` + +Or build from source - may be required if you already have UCX installed. + +```bash +git clone https://github.com/ai-dynamo/nixl.git +cd nixl +pip install . --config-settings=setup-args="-Ducx_path=/path/to/ucx" +``` + + +### Usage + +### Llama Single Node + +```bash +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode prefill \ + --port 30000 \ + --disaggregation-transfer-backend nixl +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode decode \ + --port 30001 \ + --base-gpu-id 1 \ + --disaggregation-transfer-backend nixl +python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000 +``` + +### DeepSeek Multi-Node + +```bash +# prefill 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend nixl \ + --disaggregation-mode prefill \ + --host ${local_ip} \ + --port 30000 \ + --trust-remote-code \ + --dist-init-addr ${prefill_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 0 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 +# prefill 1 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend nixl \ + --disaggregation-mode prefill \ + --host ${local_ip} \ + --port 30000 \ + --trust-remote-code \ + --dist-init-addr ${prefill_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 1 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 +# decode 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend nixl \ + --disaggregation-mode decode \ + --host ${local_ip} \ + --port 30001 \ + --trust-remote-code \ + --dist-init-addr ${decode_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 0 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 \ + --max-running-requests 128 +# decode 1 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend nixl \ + --disaggregation-mode decode \ + --host ${local_ip} \ + --port 30001 \ + --trust-remote-code \ + --dist-init-addr ${decode_master_ip}:5000 \ + --nnodes 2 \ + --node-rank 1 \ + --tp-size 16 \ + --dp-size 8 \ + --enable-dp-attention \ + --moe-a2a-backend deepep \ + --mem-fraction-static 0.8 \ + --max-running-requests 128 +``` + +### Advanced Configuration + +#### NIXL Backend Selection + +By default, NIXL uses the **UCX** backend for KV cache transfers. You can select a different NIXL plugin backend depending on your infrastructure using the environment variable `SGLANG_DISAGGREGATION_NIXL_BACKEND`. + +Example: `export SGLANG_DISAGGREGATION_NIXL_BACKEND=LIBFABRIC` + +**Available backends:** UCX (default), LIBFABRIC, or any installed NIXL plugin. + +Example usage: +```bash +export SGLANG_DISAGGREGATION_NIXL_BACKEND=LIBFABRIC +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode prefill \ + --disaggregation-transfer-backend nixl \ + --port 30000 +``` + +## ASCEND + +### Usage + +Use ascend backend with [memfabric_hybrid](https://gitcode.com/Ascend/memfabric_hybrid) and ASCEND_MF_STORE_URL being set + +```bash +pip install memfabric-hybrid==1.0.0 +export ASCEND_MF_STORE_URL="tcp://xxx.xx.xxx.xxx:xxxx" +``` +Use mooncake backend, more details can be found in mooncake section. +```bash +export ENABLE_ASCEND_TRANSFER_WITH_MOONCAKE=true +``` +ASCEND_NPU_PHY_ID need to be set in container env +```bash +export ASCEND_NPU_PHY_ID=xxx +``` + + +### Llama Single Node + +```bash +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode prefill \ + --port 30000 \ + --disaggregation-transfer-backend ascend +python -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode decode \ + --port 30001 \ + --base-gpu-id 1 \ + --disaggregation-transfer-backend ascend +python -m sglang_router.launch_router --pd-disaggregation --prefill http://127.0.0.1:30000 --decode http://127.0.0.1:30001 --host 0.0.0.0 --port 8000 +``` + +### DeepSeek Multi-Node + +```bash +# prefill 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend ascend \ + --disaggregation-mode prefill \ + --host ${local_ip} \ + --port 30000 \ + --trust-remote-code \ + --dist-init-addr ${prefill_master_ip}:5000 \ + --nnodes 1 \ + --node-rank 0 \ + --tp-size 16 +# decode 0 +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --disaggregation-transfer-backend ascend \ + --disaggregation-mode decode \ + --host ${local_ip} \ + --port 30001 \ + --trust-remote-code \ + --dist-init-addr ${decode_master_ip}:5000 \ + --nnodes 1 \ + --node-rank 0 \ + --tp-size 16 +``` diff --git a/sglang/docs/advanced_features/piecewise_cuda_graph.md b/sglang/docs/advanced_features/piecewise_cuda_graph.md new file mode 100644 index 0000000000000000000000000000000000000000..e0bb47af94eb2a669229344ecda141e65e892530 --- /dev/null +++ b/sglang/docs/advanced_features/piecewise_cuda_graph.md @@ -0,0 +1,189 @@ +# Piecewise CUDA Graph + +## Motivation + +Standard CUDA graphs capture the entire model forward pass as a single graph. This works well for decode (fixed batch size), but not for extend/prefill where the number of tokens varies across iterations. + +Piecewise CUDA Graph (PCG) solves this by splitting the model's computation graph into pieces (roughly one per layer) at "split points" (e.g., MoE dispatch ops). Each piece is captured as a separate CUDA graph for a set of pre-defined token lengths. At runtime, the input is padded to the nearest captured size, and each piece is replayed. This eliminates kernel launch overhead for prefill/extend while still supporting dynamic shapes. + +Recently we **enabled PCG by default**, which means that the old `--enable-piecewise-cuda-graph` flag is deprecated. Use `--disable-piecewise-cuda-graph` to turn it off. + +## Usage + +PCG is enabled by default for supported configurations. No extra flags needed: + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct +``` + +### Disable PCG + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disable-piecewise-cuda-graph +``` + +### Custom capture sizes + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --piecewise-cuda-graph-max-tokens 2048 +``` + +### Server Args + +| Argument | Default | Description | +|---|---|---| +| `--disable-piecewise-cuda-graph` | `False` | Disable PCG for extend/prefill. | +| `--enforce-piecewise-cuda-graph` | `False` | Force-enable PCG, skipping all auto-disable conditions. For testing only. | +| `--piecewise-cuda-graph-max-tokens` | `None` (auto) | Maximum token count to capture. Defaults to `chunked_prefill_size` (non-MLA) or `2048` (MLA). | +| `--piecewise-cuda-graph-tokens` | `None` (auto) | Explicit list of token lengths to capture. Auto-generated if not set. | +| `--piecewise-cuda-graph-compiler` | `"eager"` | Compiler backend for the captured subgraphs. Choices: `eager`, `inductor`. | +| ~~`--enable-piecewise-cuda-graph`~~ | — | **Deprecated.** PCG is now enabled by default. Use `--enforce-piecewise-cuda-graph` to skip auto-disable conditions. | + +## Bug Report + +PCG is enabled by default but is still in an experimental stage. Since PCG relies on `torch.compile` to trace the model's forward pass, most bugs are introduced by torch compile tracing failures (e.g., untraceable ops, dynamic control flow, or graph breaks). If you encounter any issues related to PCG, please disable it by adding `--disable-piecewise-cuda-graph` to your launch command and report the bug at [GitHub Issues](https://github.com/sgl-project/sglang/issues/new/choose). We greatly appreciate your help in improving this feature. + +### For Users + +If you see an error message like the following during server startup, it is a PCG bug: + +``` +Piecewise CUDA Graph is enabled by default as an experimental feature. +To work around this error, add --disable-piecewise-cuda-graph to your launch command. +Please report this issue at https://github.com/sgl-project/sglang/issues/new/choose +``` + +To work around it, add `--disable-piecewise-cuda-graph` to your launch command. When filing a bug report, please include: +1. The full error traceback +2. Model name and quantization method +3. Launch command with all arguments +4. GPU type and driver version + +### For Developers + +Since PCG relies on `torch.compile` to trace the model's forward pass, newly developed CUDA kernels (both JIT kernels and sgl-kernels) are typically not compatible with `torch.compile` out of the box. The tracing will fail on untraceable operations such as JIT compilation, file I/O, or dynamic module loading inside the kernel. + +To make a kernel compatible with PCG, you need to register it as a custom op using `register_custom_op` from `sglang.srt.utils.custom_op`. This wraps the kernel as an opaque node in the compiled graph so that `torch.compile` will not trace inside it. + +**Example usage (JIT kernel):** + +```python +from sglang.srt.utils.custom_op import register_custom_op + +# Inplace operator (no return value) +@register_custom_op(mutates_args=["output_q", "output_s"]) +def per_token_group_quant_8bit( + input: torch.Tensor, + output_q: torch.Tensor, + output_s: torch.Tensor, +) -> None: + # kernel implementation ... +``` + +**Example usage (operator with output):** + +```python +# out_shape indicates which argument has the same shape as the output +@register_custom_op(mutates_args=["x"], out_shape=0) +def add(x: torch.Tensor, y: torch.Tensor) -> torch.Tensor: + return x.add_(y) +``` + +For wrapping external library functions (e.g., FlashInfer kernels), use `register_custom_op_from_extern` instead. See `python/sglang/srt/utils/custom_op.py` for full API documentation. + +## How it works +### Torch compile backend + +PCG uses `torch.compile` with a custom backend (`SGLangBackend`) to split and compile the model's forward pass. The flow is: + +``` +model.forward wrapper +→ torch.compile(..., backend=SGLangBackend) +→ FX graph +→ split_graph() at registered split ops +→ split_gm (top-level graph that chains the pieces) +→ replace capturable submodules with CUDAPiecewiseBackend +→ runtime dispatch: eager split ops + per-piece capture/replay +``` + +- **Install**: `install_torch_compiled()` replaces `model.forward` with a wrapper function. When `is_in_piecewise_cuda_graph()` returns True, the wrapper dispatches to the compiled callable; otherwise it falls back to the original forward. The first invocation through this path triggers Dynamo tracing and graph compilation — CUDA graph replay only happens after the capture phase completes. + +- **Split**: When `torch.compile` traces the model, `SGLangBackend` receives the FX graph and calls `split_graph()`. Ops listed in `CompilationConfig.split_ops` are treated as split points, so the graph is cut at each one. These split-op submodules are left to run eagerly at runtime, while the surrounding submodules are compiled and wrapped by `CUDAPiecewiseBackend`. The result is a top-level "stitching graph" (`split_gm`) with children such as `submod_0`, `submod_1`, … interleaving capturable subgraphs and eager split-op submodules. + +- **Replace**: `PiecewiseCompileInterpreter` iterates over each capturable submodule in `split_gm`, compiles it for general (dynamic) shapes, and replaces it in-place with a `CUDAPiecewiseBackend` instance. Split-op submodules (e.g., attention, all-reduce) are left as-is and run eagerly at runtime. + +- **Dispatch**: At runtime, calling `split_gm` executes the stitching graph, which calls each submodule in order. Split-op submodules run eagerly. Each `CUDAPiecewiseBackend` submodule goes through three phases: + - **Compile warmup** — runs the general-shape compiled path. + - **Capture** — for each capture size, runs one warmup pass then records a CUDA graph. + - **Steady-state replay** — replays the captured CUDA graph for each forward pass. + +### Piecewise cuda graph runner + +`PiecewiseCudaGraphRunner` orchestrates the full lifecycle through three phases: + +- **Compile** — Warms up JIT kernels with a dummy forward pass, then wraps the model with `torch.compile`, triggering Dynamo tracing to split the FX graph and create `CUDAPiecewiseBackend` instances for each subgraph piece. + +- **Capture** — Iterates over capture sizes in reverse order (largest first). For each size, runs the forward pass twice (one warmup, one CUDA graph capture). + +- **Replay** — At runtime, finds the smallest captured size >= actual token count via binary search, copies inputs into static buffers with zero-padding, replays the captured CUDA graphs, and slices outputs back to the actual token count. + +### Memory optimization + +The memory cost of PCG comes from two parts: **torch memory allocator** and **non-torch memory**. + +The torch memory allocator overhead is trivial thanks to several optimizations: a global shared memory pool is reused across all CUDA graph runners and capture sizes, capture is done in reverse order (large to small) so smaller graphs reuse memory allocated by larger ones, and output tensors of the last subgraph are stored as weak references to maximize memory reuse. + +The main memory overhead comes from non-torch memory — the CUDA graph objects themselves require GPU memory to store the recorded kernel launch parameters and internal state. This overhead scales with the number of captured sizes, which is why `piecewise_cuda_graph_max_tokens` is capped conservatively by default. + +### Shape configuration +Piecewise CUDA graph pre-captures graphs for a set of token counts. At runtime, the actual token count is rounded up to the nearest captured size (via binary search), and the corresponding graph is replayed. If the token count exceeds the largest captured size, the runtime falls back to the normal (non-graph) forward path. + +The default capture schedule is auto-generated with increasing granularity: + +| Token range | Step size | +|-------------|-----------| +| 4 – 32 | 4 | +| 48 – 256 | 16 | +| 288 – 512 | 32 | +| 576 – 1024 | 64 | +| 1280 – 4096 | 256 | +| 4096+ | 512 | + +For the auto-generated schedule, sizes are capped at `--piecewise-cuda-graph-max-tokens`. The default cap is `chunked_prefill_size` for non-MLA models and `2048` for MLA backend models. If `--max-total-tokens` is set, the cap is further limited to not exceed it. Additionally, Llama-2 models are auto-capped at 4096 tokens as a temporary workaround. + +## Compatibility + +PCG is auto-disabled in the following scenarios. We are actively working on expanding compatibility — support for many of these will be coming soon. + +- Disabled model architectures (e.g., `DeepseekV32ForCausalLM`) +- Speculative decoding +- DP attention +- Pipeline parallelism (`pp_size > 1`) +- Non-CUDA hardware (AMD ROCm, Ascend NPU) +- MoE A2A backend +- LoRA +- Multimodal / VLM models +- DLLM (diffusion LLM) +- Deterministic inference +- PD disaggregation +- Expert distribution recorder / EPLB + +Use `--enforce-piecewise-cuda-graph` to skip all auto-disable checks (for testing/debugging only). + +## Code Reference + +| File | Description | +|---|---| +| `python/sglang/srt/model_executor/piecewise_cuda_graph_runner.py` | Main runner: init, capture, replay | +| `python/sglang/srt/compilation/compile.py` | `install_torch_compiled` trampoline | +| `python/sglang/srt/compilation/backend.py` | `SGLangBackend`, graph splitting, piecewise compilation | +| `python/sglang/srt/compilation/cuda_piecewise_backend.py` | Per-subgraph CUDA graph capture/replay | +| `python/sglang/srt/compilation/piecewise_context_manager.py` | Global context flags and `ForwardContext` | +| `python/sglang/srt/compilation/compilation_config.py` | Capture sizes, split ops, compiler config | +| `python/sglang/srt/utils/custom_op.py` | `register_custom_op` for torch.compile compatibility | +| `python/sglang/srt/server_args.py` | Server arguments and auto-disable logic | diff --git a/sglang/docs/advanced_features/pipeline_parallelism.md b/sglang/docs/advanced_features/pipeline_parallelism.md new file mode 100644 index 0000000000000000000000000000000000000000..9a565f602ed6a1d195d85fb790cd9665535f9daf --- /dev/null +++ b/sglang/docs/advanced_features/pipeline_parallelism.md @@ -0,0 +1,116 @@ +# Pipeline Parallelism for Long Context + +## Why Pipeline Parallelism? + +As Large Language Models (LLMs) scale toward trillion-parameter architectures and "infinite" context windows, the underlying serving infrastructure must evolve toward more granular, cross-node parallelization strategies. While KV cache techniques effectively mitigate redundant computation, they cannot circumvent the prohibitive Time to First Token (TTFT) inherent in ultra-long sequences with extremely large initial Input Token Length (ITL). Although Tensor Parallelism (TP) remains the conventional approach for intra-node scaling, it frequently encounters communication bottlenecks during multi-node deployments. On the other hand, pipeline parallelism only requires cross-node communication at the boundaries of each pipeline stage, which can achieve better computation-communication overlap compared to a large TP. Therefore, it is also a promising parallelization strategy for improving throughput. + +Detailed analysis can be found in this [blog](https://lmsys.org/blog/2026-01-15-chunked-pipeline/). + +## Implementation Refactoring based on Async Communication +With Dynamic Chunked Prefill, pipeline parallelism has the potential to reduce the TTFT of long-context inputs. For each request, its input tokens can be partitioned into multiple chunks, each no longer than the chunked prefill size. Different chunks of the same request can be processed simultaneously by different nodes, thus parallelizing the processing and reducing TTFT. SGLang has supported Pipeline Parallelism (#5724) for some time and made it compatible with the PD Disaggregation feature (#8846), but the implementation was not perfect and had significant room for performance improvements. + +To eliminate this performance hazard, SGLang implements a Micro-batching Event Loop with non-blocking asynchronous peer-to-peer (P2P) communication to overlap GPU computation with CPU metadata processing and PP communication. This ensures that while one micro-batch is being computed on the GPU, the next one is already being prepared and moved into position effectively, ensuring the pipeline remains as saturated as possible. This approach was first proposed in #7979 and has been redesigned and included in #11852. + +The key mechanisms of the implementation include: + +* **Decoupled Sync/Async Logic in the Event Loop:** The scheduler uses `async_send` in `_pp_send_pyobj_to_next_stage`. Instead of waiting for a transfer to complete, it returns a `P2PWork` handle. The actual synchronization (`P2PWork.work.wait()`) is deferred until `_pp_commit_comm_work` is called, allowing the CPU to perform other work—like scheduling the next batch or processing metadata—while data is in flight. +* **Multi-Stream Execution:** In addition to the main `default_stream`, which serves as the synchronization stream, SGLang utilizes dedicated `forward_stream` and `copy_stream` to execute forward pass GPU computation and Data-to-Host (D2H) memory transfers separately for better overlapping. While `_pp_launch_batch` is executing the current micro-batch on the GPU for the current stage, the CPU processes the previous micro-batch's results using `_pp_process_batch_result`. + +## Guidance about Dynamic Chunking + +### Why Dynamic Chunking +Chunked prefill with a fixed size can cause bubbles in the pipeline, especially when the pp size is large. The main reason behind this phenomenon is that the model has a non-uniform running time, even though each chunk size is identical (brought by the Transformer structure). The larger the prefix sequence length, the longer the running time of the chunk. And these bubbles will be propagated to the next stage, and will significantly degrade the scale efficiency of larger pp ranks. + +To address this issue, SGLang introduces a dynamic chunking mechanism to predict the optimal size for the next chunk such that it satisfies this condition: + +Runtime(L + Next Chunk Size) - Runtime(L) = Runtime(Initial Chunk Size) + +where ***L*** denotes the Prefix Sequence Length. By profiling a series of requests with different ITLs, we model the cumulative runtime as a quadratic function of sequence length. Using this model, we solve the optimal next chunk size for any given prefix length ***L***. Since the computation complexity of the Attention mechanism scales with ***L***, the next chunk size will be progressively reduced as ***L*** grows to maintain an aligned chunk execution time across pipeline stages. + +Based on this method, the scheduler can predict and dynamically reduce the chunk size during runtime to minimize the bubbles caused by the stage misalignment. To be noticed, the scheduler does not use the raw predicted value. To facilitate efficient KVCache memory management and ensure affinity with hardware execution efficiency, the value is aligned downward to the nearest multiple of max(`--page-size`, 64). + + +### Chunked Prefill Size and Smoothing Factor + +When `--enable-dynamic-chunking` is enabled, each chunk size of a sequence is determined dynamically based on the quadratic model that predicts the next chunk size based on the estimated runtime of the initial chunk length. In this case, we use `--chunked-prefill-size` to set up the initial chunk size. When switching to the dynamic chunking mode, the initial chunk size (`--chunked-prefill-size`) should be set to a larger value comparable to the original chunked prefill size, so that there won't be too many chunks. + +**`SGLANG_DYNAMIC_CHUNKING_SMOOTH_FACTOR`** is an environmental variable that controls the smoothing factor for the dynamic chunking algorithm, defaulting to 0.75. It determines how much the chunk size can change during the prefill phase. A larger value means a more aggressive chunk size change, which may lead to better performance but also to greater chunk size changes (the chunk size at the end may become very small, which could lead to performance degradation) and more total chunks. When it is set to 1, the chunk size will be adjusted strictly based on the aforementioned quadratic model that predicts the next chunk size. A smaller value means a more conservative chunk size change, which may lead to smaller chunk size changes and fewer total chunks. When it is set to 0, the chunk size will not be adjusted dynamically, so it is identical to the traditional way with a fixed chunked prefill size. + +Due to the variation in hardware, models, and target workloads, a static configuration is seldom optimal across all scenarios. Consequently, achieving peak performance necessitates a degree of hyperparameter tuning when switching to the dynamic chunking mode. + +**Tuning Guidance for Dynamic Chunked Prefill** + +* **Step 1 \- Iterate to find the optimal fixed chunked prefill size for the targeted PP size**: Different PP sizes for targeted ITL may have different optimal chunked prefill sizes. Therefore, users should iterate to obtain the baseline according to the available resources for scaling. +* **Step 2 \- Initial Chunk Size Selection for Dynamic Chunking**: Set the initial size to 2× or 3× the optimal fixed chunked prefill size. This reduces the total number of chunks and prevents "tail chunks" from underutilizing hardware. To maintain efficiency for extremely large Input Token Lengths (ITL), the dynamic predictor automatically ensures subsequent chunks are at least 1/4 of this initial size. In addition, it is recommended to use a larger initial chunk size (e.g., 4× the optimal fixed chunked prefill size) for such cases as well. +* **Step 3 \- Smooth Factor Adjustment**: This factor controls how strictly the chunk size adjusts the prediction given by the quadratic performance fitting model. + * 1.0: Follows the model strictly. + * **0.6 – 0.85 (Recommended)**: Typical range for the best balance between dynamic scaling and hardware stability. Through experiments, we find that a range between 0.6 and 0.85 typically yields the best performance for dynamic chunking. + * 0: Disables dynamic adjustment, reverting to traditional fixed-size chunking. +* **Another small optimization tip:** Put the larger partition in the higher PP rank when the layers are not evenly divisible across ranks. It can increase the GPU utilization when a larger PP rank is waiting for the previous stage’s result, hence reducing the bubbles on higher PP ranks. If we take DeepSeek-V3.1 as an example, `SGLANG_PP_LAYER_PARTITION=15,15,15,16` usually performs better than `16,15,15,15`. + +## Best Practice for Long Context + +### Tuning the Chunked Prefill Size +Optimizing the chunked prefill size is crucial for balancing pipeline efficiency and resource utilization. The ideal size depends on factors including model architecture, hardware configuration, and typical input lengths. We recommend starting with a small chunk size, such as 4K, and gradually increasing it until you find the optimal size for your specific use case (Different targeted ITL and PP Sizes may have different optimal chunked prefill sizes. Therefore, users should iterate to obtain the baseline according to the available resources for scaling). Alternatively, you can analyze the hardware capacity and determine the optimal chunk size based on the roofline model. + +### Enable Dynamic Chunking and Adjust Smoothing Factor for Ultra-long ITL +SGLang also offers a dynamic chunking solution that could further improve performance. This feature is currently an experimental feature that requires a certain amount of tuning experimentation and may not be suitable for all workloads. In addition, fine-tuning the smoothing factor can help optimize performance for specific workloads and model characteristics. + +### Case Study on NVIDIA H20 + +When evaluating pipeline parallelism with fixed chunked prefill sizes from 2K to 16K, experiment results show that a 4K chunk size delivered optimal prefill TTFT performance for the DeepSeek-V3.1, and a 6K chunk size delivered optimal prefill TTFT performance for the Qwen3-235B-A22B-FP8. + +When enabling dynamic chunking, we first scale the optimal fixed chunked prefill size by a factor of 3 as the initial chunk size. Through experimentation, we found that a multiplier of 2-3 provides an appropriate balance—avoiding excessive initial pipeline bubbles while ensuring that subsequent chunks don't become too small as context length increases. With the default dynamic chunking smoothing factor of 0.75, we performed parameter tuning and determined that a value of 0.65 works optimally with the 12K initial chunk size for the DeepSeek-V3.1, while a value of 0.8 works optimally with the 18K initial chunk size for the Qwen3-235B-A22B-FP8. + +#### DeepSeek-V3.1 with 128K Input Token Length +```bash +# prefill node 0 (fixed chunked prefill size) +python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3.1 --trust-remote-code \ + --nnodes 4 --node-rank 0 --tp 8 --pp-size 4 \ + --port 30000 --dist-init-addr \ + --disable-radix-cache --mem-fraction-static 0.8 \ + --attention-backend fa3 --host 0.0.0.0 --watchdog-timeout 3600 \ + --max-running-requests 128 --chunked-prefill-size 4096 +``` + +```bash +# prefill node 0 (with dynamic chunking) +export SGLANG_DYNAMIC_CHUNKING_SMOOTH_FACTOR=0.65 +python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3.1 --trust-remote-code \ + --nnodes 4 --node-rank 0 --tp 8 --pp-size 4 \ + --port 30000 --dist-init-addr \ + --disable-radix-cache --mem-fraction-static 0.8 \ + --attention-backend fa3 --host 0.0.0.0 --watchdog-timeout 3600 \ + --max-running-requests 128 --chunked-prefill-size 12288 --enable-dynamic-chunking +``` + +#### Qwen3-235B-A22B-FP8 with 128K Input Token Length +```bash +# prefill node 0 (fixed chunked prefill size) +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-235B-A22B-FP8 --trust-remote-code \ + --nnodes 4 --node-rank 0 --tp 4 --pp-size 8 \ + --port 30000 --dist-init-addr \ + --disable-radix-cache --mem-fraction-static 0.8 \ + --attention-backend fa3 --host 0.0.0.0 --watchdog-timeout 3600 \ + --max-running-requests 128 --chunked-prefill-size 6144 +``` + +```bash +# prefill node 0 (with dynamic chunking) +export SGLANG_DYNAMIC_CHUNKING_SMOOTH_FACTOR=0.8 +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3-235B-A22B-FP8 --trust-remote-code \ + --nnodes 4 --node-rank 0 --tp 4 --pp-size 8 \ + --port 30000 --dist-init-addr \ + --disable-radix-cache --mem-fraction-static 0.8 \ + --attention-backend fa3 --host 0.0.0.0 --watchdog-timeout 3600 \ + --max-running-requests 128 --chunked-prefill-size 18432 --enable-dynamic-chunking +``` + +Note: `--disable-radix-cache` is enabled only for reproducible benchmarking purposes. It is not recommended to use it in production. + +## Best Practice for Pipeline Parallelism with PD Disaggregation +To be added. Stay tuned for the latest updates on Pipeline Parallelism with PD Disaggregation. diff --git a/sglang/docs/advanced_features/quantization.md b/sglang/docs/advanced_features/quantization.md new file mode 100644 index 0000000000000000000000000000000000000000..ce14bbaf2bbc2367786dbb7ab4283490c49f7761 --- /dev/null +++ b/sglang/docs/advanced_features/quantization.md @@ -0,0 +1,496 @@ +# Quantization + +SGLang supports various quantization methods, including offline quantization and online dynamic quantization. + +Offline quantization loads pre-quantized model weights directly during inference. This is required for quantization methods +such as GPTQ and AWQ, which collect and pre-compute various statistics from the original weights using the calibration dataset. + +Online quantization dynamically computes scaling parameters—such as the maximum/minimum values of model weights—during runtime. +Like NVIDIA FP8 training's [delayed scaling](https://docs.nvidia.com/deeplearning/transformer-engine/user-guide/examples/fp8_primer.html#Mixed-precision-training-with-FP8) mechanism, online quantization calculates the appropriate scaling factors +on-the-fly to convert high-precision weights into a lower-precision format. + +**Note: For better performance, usability and convenience, offline quantization is recommended over online quantization.** + +If you use a pre-quantized model, do not add `--quantization` to enable online quantization at the same time. +For popular pre-quantized models, please visit [Unsloth](https://huggingface.co/unsloth), [NVIDIA ModelOpt](https://huggingface.co/collections/nvidia/inference-optimized-checkpoints-with-model-optimizer) +or [NeuralMagic](https://huggingface.co/collections/neuralmagic) collections on HF for some +popular quality validated quantized models. Quantized models must be validated via benchmarks post-quantization +to guard against abnormal quantization loss regressions. + +## Platform Compatibility + +The following table summarizes quantization method support across NVIDIA and AMD GPUs. + +| Method | NVIDIA GPUs | AMD GPUs (MI300X/MI325X/MI350X) | Notes | +|--------|:-----------:|:-------------------------------:|-------| +| `fp8` | Yes | Yes | Aiter or Triton backend on AMD | +| `mxfp4` | Yes | Yes | Requires CDNA3/CDNA4 with MXFP support; uses Aiter | +| `blockwise_int8` | Yes | Yes | Triton-based, works on both platforms | +| `w8a8_int8` | Yes | Yes | | +| `w8a8_fp8` | Yes | Yes | Aiter or Triton FP8 on AMD | +| `awq` | Yes | Yes | Uses Triton dequantize on AMD (vs. optimized CUDA kernels on NVIDIA) | +| `gptq` | Yes | Yes | Uses Triton or vLLM kernels on AMD | +| `compressed-tensors` | Yes | Yes | Aiter paths for FP8/MoE on AMD | +| `quark` | Yes | Yes | AMD Quark quantization; Aiter GEMM paths on AMD | +| `auto-round` | Yes | Yes | Platform-agnostic (Intel auto-round) | +| `quark_int4fp8_moe` | No | Yes | AMD-only; online INT4-to-FP8 MoE quantization (CDNA3/CDNA4) | +| `awq_marlin` | Yes | No | Marlin kernels are CUDA-only | +| `gptq_marlin` | Yes | No | Marlin kernels are CUDA-only | +| `gguf` | Yes | No | CUDA-only kernels in sgl-kernel | +| `modelopt` / `modelopt_fp8` | Yes | No | NVIDIA ModelOpt, requires NVIDIA hardware | +| `modelopt_fp4` | Yes (Blackwell) | No | NVIDIA Blackwell only | +| `petit_nvfp4` | Yes (Blackwell) | No | NVIDIA NvFP4, Blackwell only | +| `bitsandbytes` | Yes | Experimental | Depends on bitsandbytes ROCm support | +| `torchao` (`int4wo`, etc.) | Yes | Partial | `int4wo` not supported on AMD; other methods may work | + +On AMD, several of these methods use [Aiter](https://github.com/ROCm/aiter) for acceleration -- set `SGLANG_USE_AITER=1` where noted. See [AMD GPU setup](../platforms/amd_gpu.md) for installation and configuration details. + +## Offline Quantization + +To load already quantized models, simply load the model weights and config. **Again, if the model has been quantized offline, +there's no need to add `--quantization` argument when starting the engine. The quantization method will be parsed from the +downloaded Hugging Face config. For example, DeepSeek V3/R1 models are already in FP8, so do not add redundant parameters.** + +```bash +python3 -m sglang.launch_server \ + --model-path hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4 \ + --port 30000 --host 0.0.0.0 +``` + +Take note, if your model is **per-channel quantized (INT8 or FP8) with per-token dynamic quantization activation**, you can opt to include `--quantization w8a8_int8` or `--quantization w8a8_fp8` to invoke the corresponding CUTLASS int8_kernel or fp8_kernel in sgl-kernel. This action will ignore the Hugging Face config's quantization settings. For instance, with `neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8-dynamic`, if you execute with `--quantization w8a8_fp8`, the system will use the `W8A8Fp8Config` from SGLang to invoke the sgl-kernel, rather than the `CompressedTensorsConfig` for vLLM kernels. + +```bash +python3 -m sglang.launch_server \ + --model-path neuralmagic/Meta-Llama-3.1-8B-Instruct-FP8-dynamic \ + --quantization w8a8_fp8 \ + --port 30000 --host 0.0.0.0 +``` + +### Examples of Offline Model Quantization + +#### Using [Unsloth](https://docs.unsloth.ai/basics/inference-and-deployment/sglang-guide) + +We strongly suggest the use of Unsloth to quantize and load the model. Please refer to [SGLang Deployment & Inference Guide with Unsloth](https://docs.unsloth.ai/basics/inference-and-deployment/sglang-guide). + +#### Using [auto-round](https://github.com/intel/auto-round) + +```bash +# Install +pip install auto-round +``` + +- LLM quantization + +```py +# for LLM +from auto_round import AutoRound +model_id = "meta-llama/Llama-3.2-1B-Instruct" +quant_path = "Llama-3.2-1B-Instruct-autoround-4bit" +# Scheme examples: "W2A16", "W3A16", "W4A16", "W8A16", "NVFP4", "MXFP4" (no real kernels), "GGUF:Q4_K_M", etc. +scheme = "W4A16" +format = "auto_round" +autoround = AutoRound(model_id, scheme=scheme) +autoround.quantize_and_save(quant_path, format=format) # quantize and save + +``` + +- VLM quantization +```py +# for VLMs +from auto_round import AutoRoundMLLM +model_name = "Qwen/Qwen2-VL-2B-Instruct" +quant_path = "Qwen2-VL-2B-Instruct-autoround-4bit" +scheme = "W4A16" +format = "auto_round" +autoround = AutoRoundMLLM(model_name, scheme) +autoround.quantize_and_save(quant_path, format=format) # quantize and save + +``` + +- Command Line Usage (Gaudi/CPU/Intel GPU/CUDA) + +```bash +auto-round \ + --model meta-llama/Llama-3.2-1B-Instruct \ + --bits 4 \ + --group_size 128 \ + --format "auto_round" \ + --output_dir ./tmp_autoround +``` + +- known issues + +Several limitations currently affect offline quantized model loading in sglang, These issues might be resolved in future updates of sglang. If you experience any problems, consider using Hugging Face Transformers as an alternative. + +1. Mixed-bit Quantization Limitations + + Mixed-bit quantization is not fully supported. Due to vLLM's layer fusion (e.g., QKV fusion), applying different bit-widths to components within the same fused layer can lead to compatibility issues. + + +2. Limited Support for Quantized MoE Models + + Quantized MoE models may encounter inference issues due to kernel limitations (e.g., lack of support for mlp.gate layer quantization). please try to skip quantizing these layers to avoid such errors. + + +3. Limited Support for Quantized VLMs +
+ VLM failure cases + + Qwen2.5-VL-7B + + auto_round:auto_gptq format: Accuracy is close to zero. + + GPTQ format: Fails with: + ``` + The output size is not aligned with the quantized weight shape + ``` + auto_round:auto_awq and AWQ format: These work as expected. +
+ +#### Using [GPTQModel](https://github.com/ModelCloud/GPTQModel) + +```bash +# install +pip install gptqmodel --no-build-isolation -v +``` + +```py +from datasets import load_dataset +from gptqmodel import GPTQModel, QuantizeConfig + +model_id = "meta-llama/Llama-3.2-1B-Instruct" +quant_path = "Llama-3.2-1B-Instruct-gptqmodel-4bit" + +calibration_dataset = load_dataset( + "allenai/c4", data_files="en/c4-train.00001-of-01024.json.gz", + split="train" + ).select(range(1024))["text"] + +quant_config = QuantizeConfig(bits=4, group_size=128) # quantization config +model = GPTQModel.load(model_id, quant_config) # load model + +model.quantize(calibration_dataset, batch_size=2) # quantize +model.save(quant_path) # save model +``` + +#### Using [LLM Compressor](https://github.com/vllm-project/llm-compressor/) + +```bash +# install +pip install llmcompressor +``` + +Here, we take quantize `meta-llama/Meta-Llama-3-8B-Instruct` to `FP8` as an example to elaborate on how to do offline quantization. + +```python +from transformers import AutoTokenizer +from llmcompressor.transformers import SparseAutoModelForCausalLM +from llmcompressor.transformers import oneshot +from llmcompressor.modifiers.quantization import QuantizationModifier + +# Step 1: Load the original model. +MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct" + +model = SparseAutoModelForCausalLM.from_pretrained( + MODEL_ID, device_map="auto", torch_dtype="auto") +tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) + +# Step 2: Perform offline quantization. +# Step 2.1: Configure the simple PTQ quantization. +recipe = QuantizationModifier( + targets="Linear", scheme="FP8_DYNAMIC", ignore=["lm_head"]) + +# Step 2.2: Apply the quantization algorithm. +oneshot(model=model, recipe=recipe) + +# Step 3: Save the model. +SAVE_DIR = MODEL_ID.split("/")[1] + "-FP8-Dynamic" +model.save_pretrained(SAVE_DIR) +tokenizer.save_pretrained(SAVE_DIR) +``` + +Then, you can directly use the quantized model with `SGLang`, by using the following command: + +```bash +python3 -m sglang.launch_server \ + --model-path $PWD/Meta-Llama-3-8B-Instruct-FP8-Dynamic \ + --port 30000 --host 0.0.0.0 +``` + +#### Using [NVIDIA ModelOpt](https://github.com/NVIDIA/Model-Optimizer) + +NVIDIA Model Optimizer (ModelOpt) provides advanced quantization techniques optimized for NVIDIA hardware. + +**Offline vs. Online Quantization:** + +SGLang supports two modes for ModelOpt. + +* **Offline Quantization (pre-quantized):** + * **Usage:** Download a pre-quantized model from Hugging Face or run `hf_ptq.py` once to create a new quantized checkpoint. Then load this quantized checkpoint. + * **Pros:** Fast server startup, quantization can be validated before deployment, efficient resource usage. + * **Cons:** Requires an extra preparation step. + +* **Online Quantization (quant and serve):** + * **Usage:** Load a standard BF16/FP16 model and add a flag. The engine applies quantization *on startup*. + * **Pros:** Convenient (no new checkpoint needed). + * **Cons:** **High startup time**, increases VRAM usage during initialization (risk of OOM). + +The following sections guide you through using the Offline path: loading pre-quantized models or creating your own checkpoints. + +##### Using Pre-Quantized Checkpoints + +If a model is already quantized (e.g., from Hugging Face), you can load it directly. + +* **FP8 Models:** + Use `--quantization modelopt_fp8`. + ```bash + python3 -m sglang.launch_server \ + --model-path nvidia/Llama-3.1-8B-Instruct-FP8 \ + --quantization modelopt_fp8 \ + --port 30000 + ``` + +* **FP4 Models:** + Use `--quantization modelopt_fp4`. + ```bash + python3 -m sglang.launch_server \ + --model-path nvidia/Llama-3.3-70B-Instruct-NVFP4 \ + --quantization modelopt_fp4 \ + --port 30000 + ``` + +##### Creating Your Own Quantized Checkpoints + +If a pre-quantized checkpoint is not available for your model, you can create one using NVIDIA Model Optimizer's `hf_ptq.py` script. + +**Why quantize?** +- Reduce VRAM usage +- Higher throughput and lower latency +- More flexible deployment (on smaller GPUs) + +**What can be quantized?** +- The entire model +- MLP layers only +- KV cache + +**Key options in `hf_ptq.py`:** + +`--qformat`: Quantization formats `fp8`, `nvfp4`, `nvfp4_mlp_only` + +`--kv_cache_qformat`: KV cache quantization format (default: `fp8`) + +**Note:** The default `kv_cache_qformat` may not be optimal for all use cases. Consider setting this explicitly. + +**Hardware requirements:** Hopper and higher are recommended. Insufficient GPU memory may cause weight offloading, resulting in extremely long quantization time. + +For detailed usage and supported model architectures, see [NVIDIA Model Optimizer LLM PTQ](https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/llm_ptq). + +SGLang includes a streamlined workflow for quantizing models with ModelOpt and automatically exporting them for deployment. + + +##### Installation + +First, install ModelOpt: + +```bash +pip install nvidia-modelopt +``` + +##### Quantization and Export Workflow + +SGLang provides an example script that demonstrates the complete ModelOpt quantization and export workflow: + +```bash +# Quantize and export a model using ModelOpt FP8 quantization +python examples/usage/modelopt_quantize_and_export.py quantize \ + --model-path TinyLlama/TinyLlama-1.1B-Chat-v1.0 \ + --export-dir ./quantized_tinyllama_fp8 \ + --quantization-method modelopt_fp8 + +# For FP4 quantization +python examples/usage/modelopt_quantize_and_export.py quantize \ + --model-path TinyLlama/TinyLlama-1.1B-Chat-v1.0 \ + --export-dir ./quantized_tinyllama_fp4 \ + --quantization-method modelopt_fp4 +``` + +##### Available Quantization Methods + +- `modelopt_fp8`: FP8 quantization with optimal performance on NVIDIA Hopper and Blackwell GPUs +- `modelopt_fp4`: FP4 quantization with optimal performance on Nvidia Blackwell GPUs + +##### Python API Usage + +You can also use ModelOpt quantization programmatically: + +```python +import sglang as sgl +from sglang.srt.configs.device_config import DeviceConfig +from sglang.srt.configs.load_config import LoadConfig +from sglang.srt.configs.model_config import ModelConfig +from sglang.srt.model_loader.loader import get_model_loader + +# Configure model with ModelOpt quantization and export +model_config = ModelConfig( + model_path="TinyLlama/TinyLlama-1.1B-Chat-v1.0", + quantization="modelopt_fp8", # or "modelopt_fp4" + trust_remote_code=True, +) + +load_config = LoadConfig( + modelopt_export_path="./exported_model", + modelopt_checkpoint_save_path="./checkpoint.pth", # optional, fake quantized checkpoint +) +device_config = DeviceConfig(device="cuda") + +# Load and quantize the model (export happens automatically) +model_loader = get_model_loader(load_config, model_config) +quantized_model = model_loader.load_model( + model_config=model_config, + device_config=device_config, +) +``` + +##### Deploying Quantized Models + +After quantization and export, you can deploy the model with SGLang: + +```bash +# Deploy the exported quantized model +python -m sglang.launch_server \ + --model-path ./quantized_tinyllama_fp8 \ + --quantization modelopt \ + --port 30000 --host 0.0.0.0 +``` + +Or using the Python API: + +```python +import sglang as sgl + +def main(): + # Deploy exported ModelOpt quantized model + llm = sgl.Engine( + model_path="./quantized_tinyllama_fp8", + quantization="modelopt", + ) + + # Run inference + prompts = [ + "Hello, how are you?", + "What is the capital of France?", + ] + sampling_params = { + "temperature": 0.8, + "top_p": 0.95, + "max_new_tokens": 100, + } + + outputs = llm.generate(prompts, sampling_params) + + for i, output in enumerate(outputs): + print(f"Prompt: {prompts[i]}") + print(f"Output: {output['text']}") + +if __name__ == "__main__": + main() + +``` + +##### Advanced Features + +**Checkpoint Management**: Save and restore fake quantized checkpoints for reuse: + +```bash +# Save the fake quantized checkpoint during quantization +python examples/usage/modelopt_quantize_and_export.py quantize \ + --model-path meta-llama/Llama-3.2-1B-Instruct \ + --export-dir ./quantized_model \ + --quantization-method modelopt_fp8 \ + --checkpoint-save-path ./my_checkpoint.pth + +# The checkpoint can be reused for future quantization runs and skip calibration +``` + +**Export-only Workflow**: If you have a pre-existing fake quantized ModelOpt checkpoint, you can export it directly: + +```python +from sglang.srt.configs.device_config import DeviceConfig +from sglang.srt.configs.load_config import LoadConfig +from sglang.srt.configs.model_config import ModelConfig +from sglang.srt.model_loader.loader import get_model_loader + +model_config = ModelConfig( + model_path="meta-llama/Llama-3.2-1B-Instruct", + quantization="modelopt_fp8", + trust_remote_code=True, +) + +load_config = LoadConfig( + modelopt_checkpoint_restore_path="./my_checkpoint.pth", + modelopt_export_path="./exported_model", +) + +# Load and export the model +model_loader = get_model_loader(load_config, model_config) +model_loader.load_model(model_config=model_config, device_config=DeviceConfig()) +``` + +##### Benefits of ModelOpt + +- **Hardware Optimization**: Specifically optimized for NVIDIA GPU architectures +- **Advanced Quantization**: Supports cutting-edge FP8 and FP4 quantization techniques +- **Seamless Integration**: Automatic export to HuggingFace format for easy deployment +- **Calibration-based**: Uses calibration datasets for optimal quantization quality +- **Production Ready**: Enterprise-grade quantization with NVIDIA support + +## Online Quantization + +To enable online quantization, you can simply specify `--quantization` in the command line. For example, you can launch the server with the following command to enable `FP8` quantization for model `meta-llama/Meta-Llama-3.1-8B-Instruct`: + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --quantization fp8 \ + --port 30000 --host 0.0.0.0 +``` + +Our team is working on supporting more online quantization methods. SGLang will soon support methods including but not limited to `["awq", "gptq", "marlin", "gptq_marlin", "awq_marlin", "bitsandbytes", "gguf"]`. + +### torchao online quantization method + +SGLang also supports quantization methods based on [torchao](https://github.com/pytorch/ao). You can simply specify `--torchao-config` in the command line to support this feature. For example, if you want to enable `int4wo-128` for model `meta-llama/Meta-Llama-3.1-8B-Instruct`, you can launch the server with the following command: + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --torchao-config int4wo-128 \ + --port 30000 --host 0.0.0.0 +``` + +SGLang supports the following quantization methods based on torchao `["int8dq", "int8wo", "fp8wo", "fp8dq-per_tensor", "fp8dq-per_row", "int4wo-32", "int4wo-64", "int4wo-128", "int4wo-256"]`. + +Note: According to [this issue](https://github.com/sgl-project/sglang/issues/2219#issuecomment-2561890230), `"int8dq"` method currently has some bugs when using together with cuda graph capture. So we suggest to disable cuda graph capture when using `"int8dq"` method. Namely, please use the following command: + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --torchao-config int8dq \ + --disable-cuda-graph \ + --port 30000 --host 0.0.0.0 +``` + +### `quark_int4fp8_moe` online quantization method + +SGLang running on AMD GPUs (CDNA3 or CDNA4 architecture) supports the quantization method `--quantization quark_int4fp8_moe`, that will replace [MoE layers](https://github.com/sgl-project/sglang/blob/v0.4.8/python/sglang/srt/layers/moe/fused_moe_triton/layer.py#L271) originally in high precision (bfloat16, float16 or float32) to use weights dynamically quantized to int4, that are upcasted to float8 during inference to run compute in float8 precision with activations dynamically quantized on the fly to float8. + +Other layers (e.g. projections in the attention layers) have their weights quantized online to float8 directly. + +## Reference + +- [GPTQModel](https://github.com/ModelCloud/GPTQModel) +- [LLM Compressor](https://github.com/vllm-project/llm-compressor/) +- [NVIDIA Model Optimizer (ModelOpt)](https://github.com/NVIDIA/Model-Optimizer) +- [Torchao: PyTorch Architecture Optimization](https://github.com/pytorch/ao) +- [vLLM Quantization](https://docs.vllm.ai/en/latest/quantization/) +- [auto-round](https://github.com/intel/auto-round) diff --git a/sglang/docs/advanced_features/quantized_kv_cache.md b/sglang/docs/advanced_features/quantized_kv_cache.md new file mode 100644 index 0000000000000000000000000000000000000000..d2c858492951017675b0db109bbcad26876ae647 --- /dev/null +++ b/sglang/docs/advanced_features/quantized_kv_cache.md @@ -0,0 +1,162 @@ +# Quantized KV Cache + +Quantized KV cache reduces the memory footprint of key-value cache storage by using lower-precision data types (FP8 or FP4) instead of the default model precision in BF16. During autoregressive generation, LLMs cache previously computed key-value pairs to avoid redundant calculations. The KV cache typically consumes a significant portion of GPU memory, especially for long sequences. + +Quantized KV cache is a memory optimization technique that primarily benefits throughput by allowing more tokens to be cached, but may introduce minimal accuracy degradation depending on the quantization format used. + +```{warning} +**Performance Warning**: When quantized KV cache must be dequantized before use in attention operations, performance can be extremely slow if dequantization is not fused with the attention kernel. Always verify that your chosen attention backend supports quantized KV cache. Backends without fused support may experience significant throughput degradation, potentially negating the memory benefits. + +**Backend Support**: Not all attention backends support quantized KV cache. Refer to [Attention Backend](attention_backend.md) for which backends support it. +``` + +## Supported Formats + +SGLang supports the following quantized KV cache formats: + +### FP8 Format + +[OCP (Open Compute Project)](https://www.opencompute.org) specifies two common 8-bit floating point formats: + +- **E5M2** (5 exponent bits, 2 mantissa bits): Larger dynamic range (±57344.0), lower precision +- **E4M3** (4 exponent bits, 3 mantissa bits): Higher precision, smaller dynamic range (±240.0) + +### FP4 Format + +```{warning} +FP4 quantization is currently experimental. +``` + +[OCP (Open Compute Project)](https://www.opencompute.org) specifies MXFP4 (Microscaling FP4), a 4-bit floating-point format: + +- **E2M1** (1 sign bit, 2 exponent bits, 1 mantissa bit): Uses block-based microscaling where tensors are divided into blocks of consecutive elements, with each block sharing a single 8-bit exponential scaling factor. While OCP specifies blocks of 32 elements, SGLang's current implementation uses blocks of 16 elements for KV cache quantization. + +## Usage + +### Enabling Quantized KV Cache + +To enable quantized KV cache, use the `--kv-cache-dtype` argument when launching the server: + +```bash +# Enable FP8 E5M2 KV cache +python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-R1-0528 \ + --kv-cache-dtype fp8_e5m2 \ + +# Enable FP8 E4M3 KV cache +python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-R1-0528 \ + --kv-cache-dtype fp8_e4m3 \ + +# Enable FP4 E2M1 KV cache +python3 -m sglang.launch_server \ + --model-path nvidia/DeepSeek-R1-0528-NVFP4 \ + --kv-cache-dtype fp4_e2m1 \ +``` + +### Scaling Factors + +FP8 quantization requires scaling factors to properly quantize and dequantize the KV cache. + +```{note} +Currently, only per-tensor (scalar) scaling factors are supported. +``` + +Scaling factors can be: + +- **Loaded from checkpoints**: Pre-quantized models (e.g., ModelOpt) may include `k_scale` and `v_scale` parameters that are automatically loaded +- **Provided via JSON**: Supply scaling factors via `--quantization-param-path`. + +The JSON file should follow this format: + +```json +{ + "kv_cache": { + "dtype": "float8_e4m3fn", + "scaling_factor": { + "0": { + "0": 1.0, + "1": 1.0 + } + } + } +} +``` + +Where the outer keys in `scaling_factor` are tensor parallel ranks and inner keys are layer indices. + +```{warning} +If scaling factors are not provided and not found in the checkpoint, it will default to 1.0, which may cause accuracy issues. +``` + +```{tip} +**FP4 (MXFP4)**: Unlike FP8, FP4 quantization handles scaling factors automatically on-the-fly during quantization and dequantization. No pre-quantized models or external scaling factor files are required—the block-based scaling factors are computed dynamically as needed. +``` + +## Performance Considerations + +### Memory Savings + +Quantized KV cache provides significant memory savings: +- **BF16 → FP4**: Supports approximately 3.56× more tokens than BF16 (accounting for scaling factor overhead) + +```{note} +FP4 and FP8 quantization require additional memory for block-based scaling factors, which reduces the effective memory savings compared to the raw bit-width reduction. FP4 with block size 16 supports approximately 1.78× more tokens than FP8, and approximately 3.56× more tokens than BF16. The relative token capacity between FP8 and BF16 can be derived from these ratios. +``` + +This enables longer context lengths or more concurrent requests within the same memory budget. + +### Accuracy Impact + +#### FP8 Accuracy + +FP8 E4M3 quantization typically introduces minimal accuracy degradation. The impact depends on model architecture, sequence length, and quantization format (generally, E4M3 has better accuracy than E5M2). + +#### FP4 Accuracy + +FP4 (MXFP4) quantization provides significant memory savings with varying accuracy impact depending on model size and dataset complexity. Preliminary accuracy test results from [PR #10078](https://github.com/sgl-project/sglang/pull/10078) (MLA) and [PR #12612](https://github.com/sgl-project/sglang/pull/12612) (MHA) show: + +**Large Models (e.g., Qwen3-235B-A22B, DeepSeek-R1-0528)** + +On large-scale models, FP4 maintains accuracy close to FP8/BF16, especially on simpler datasets: + +| Model | Dataset | KV16 | KV8 (FP8 E4M3) | KV4 (FP4 E2M1) | +|-------|---------|------|----------------|----------------| +| Qwen3-235B-A22B | gsm8k | 0.9168 | 0.9181 | 0.9186 | +| Qwen3-235B-A22B | aime25 | 0.7733 | 0.7333 | 0.6000 | +| Qwen3-235B-A22B | gpqa_diamond | 0.7010 | 0.6899 | 0.6778 | +| DeepSeek-R1-0528 | gsm8k | 0.9157 | 0.9154 | 0.9124 | +| DeepSeek-R1-0528 | aime25 | 0.5067 | 0.4934 | 0.4000 | +| DeepSeek-R1-0528 | gpqa_diamond | 0.7707 | 0.7697 | 0.7273 | + +**Smaller Models (e.g., GPT-OSS-120B)** + +On smaller models, FP4 shows more pronounced accuracy drops, particularly on challenging datasets: + +| Model | Dataset | KV16 | KV8 (FP8 E4M3) | KV4 (FP4 E2M1) | +|-------|---------|------|----------------|----------------| +| GPT-OSS-120B | gsm8k | 0.9161 | 0.9163 | 0.9152 | +| GPT-OSS-120B | aime25 | 0.7533 | 0.7667 | 0.3533 | +| GPT-OSS-120B | gpqa_diamond | 0.5081 | 0.5434 | 0.3202 | + +**Key Observations:** + +- **Simple datasets (e.g., gsm8k)**: FP4 maintains accuracy close to FP8/BF16 across model sizes +- **Model size matters**: Large models (200B+ parameters) generally tolerate FP4 quantization better than smaller models +- **Context length**: Accuracy degradation may be more pronounced in long-context scenarios, as the accumulation of the quantization error may become significant. + +```{tip} +Evaluate FP4 accuracy on your specific model and workload. Large models on simpler tasks typically show minimal degradation, while smaller models or complex reasoning tasks may require FP8 or BF16 for acceptable accuracy. +``` + +## Best Practices + +- **Use pre-quantized models**: Prefer models quantized offline with scaling factors included in the checkpoint. +- **Choose the right format**: Use `fp8_e4m3` for better accuracy (recommended), `fp8_e5m2` for larger dynamic range, or `fp4_e2m1` for maximum memory savings (experimental) +- **Check backend compatibility**: Verify that your chosen attention backend supports quantized KV cache + +```{seealso} +- [Quantization](quantization.md) +- [Attention Backend](attention_backend.md) +- [Server Arguments](server_arguments.md) +``` diff --git a/sglang/docs/advanced_features/rfork.md b/sglang/docs/advanced_features/rfork.md new file mode 100644 index 0000000000000000000000000000000000000000..5e01aa111216152e832799a9bc5632f2b977c80a --- /dev/null +++ b/sglang/docs/advanced_features/rfork.md @@ -0,0 +1,49 @@ +# R-Fork + +R-Fork (Tensor Remote Fork) is a novel weight loading methodology that leverages efficient inter-node GPU-to-GPU data transfer path to load tensors from a running SGLang instance to a new instance with zero-copy. It can significantly optimize the SGLang instance boot-up time by reducing model weights loading from several minutes to mere seconds. + +To learn more details about R-Fork, please check ** R-Fork blog ** + +## Usage + +| Argument | Usage | +|--------------|--------------------------------------------| +| load-format | set to `remote_instance` to enable R-Fork. | +| remote-instance-weight-loader-backend | `nccl` or `transfer_engine`, default value is `nccl` | +| remote-instance-weight-loader-seed-instance-ip | IP address of the seed instance who will provide the model weight | +| remote-instance-weight-loader-seed-instance-service-port | the port that the seed instance's HTTP server is listening on | +| remote-instance-weight-loader-send-weights-group-ports | the list of available ports on the seed instance that will be used to build NCCL communication groups between seed and client instance. This argument is only needed by `nccl` backend. | +| remote-instance-weight-loader-start-seed-via-transfer-engine | set to start seed service that supports TransferEngine as backend. It is needed for seed instances when using `transfer_engine` as backend. | + +### NCCL as backend + +seed instance: +```shell +python -m sglang.launch_server [args] +``` + +client instance: +```shell +python -m sglang.launch_server [args] \ + --load-format remote_instance \ + --remote-instance-weight-loader-seed-instance-ip [seed_instance_ip] \ + --remote-instance-weight-loader-seed-instance-service-port [seed_instance_service_port] \ + --remote-instance-weight-loader-send-weights-group-ports [send_weights_nccl_group_ports_list] \ + --remote-instance-weight-loader-backend nccl +``` + +### TransferEngine as backend + +seed instance: +```shell +python -m sglang.launch_server [args] \ + --remote-instance-weight-loader-start-seed-via-transfer-engine +``` + +```shell +python -m sglang.launch_server [args] \ + --load-format remote_instance \ + --remote-instance-weight-loader-seed-instance-ip [seed_instance_ip] \ + --remote-instance-weight-loader-seed-instance-service-port [seed_instance_service_port] \ + --remote-instance-weight-loader-backend transfer_engine +``` diff --git a/sglang/docs/advanced_features/separate_reasoning.ipynb b/sglang/docs/advanced_features/separate_reasoning.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..6277dd8bd4bc775626787151545be41660487321 --- /dev/null +++ b/sglang/docs/advanced_features/separate_reasoning.ipynb @@ -0,0 +1,377 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reasoning Parser\n", + "\n", + "SGLang supports parsing reasoning content out from \"normal\" content for reasoning models such as [DeepSeek R1](https://huggingface.co/deepseek-ai/DeepSeek-R1).\n", + "\n", + "## Supported Models & Parsers\n", + "\n", + "| Model | Reasoning tags | Parser | Notes |\n", + "|---------|-----------------------------|------------------|-------|\n", + "| [DeepSeek‑R1 series](https://huggingface.co/collections/deepseek-ai/deepseek-r1-678e1e131c0169c0bc89728d) | `` … `` | `deepseek-r1` | Supports all variants (R1, R1-0528, R1-Distill) |\n", + "| [DeepSeek‑V3 series](https://huggingface.co/deepseek-ai/DeepSeek-V3.1) | `` … `` | `deepseek-v3` | Including [DeepSeek‑V3.2](https://huggingface.co/deepseek-ai/DeepSeek-V3.2-Exp). Supports `thinking` parameter |\n", + "| [Standard Qwen3 models](https://huggingface.co/collections/Qwen/qwen3-67dd247413f0e2e4f653967f) | `` … `` | `qwen3` | Supports `enable_thinking` parameter |\n", + "| [Qwen3-Thinking models](https://huggingface.co/Qwen/Qwen3-235B-A22B-Thinking-2507) | `` … `` | `qwen3` or `qwen3-thinking` | Always generates thinking content |\n", + "| [Kimi K2 Thinking](https://huggingface.co/moonshotai/Kimi-K2-Thinking) | `◁think▷` … `◁/think▷` | `kimi_k2` | Uses special thinking delimiters. Also requires `--tool-call-parser kimi_k2` for tool use. |\n", + "| [GPT OSS](https://huggingface.co/openai/gpt-oss-120b) | `<\\|channel\\|>analysis<\\|message\\|>` … `<\\|end\\|>` | `gpt-oss` | N/A |\n", + "### Model-Specific Behaviors\n", + "\n", + "**DeepSeek-R1 Family:**\n", + "- DeepSeek-R1: No `` start tag, jumps directly to thinking content\n", + "- DeepSeek-R1-0528: Generates both `` start and `` end tags\n", + "- Both are handled by the same `deepseek-r1` parser\n", + "\n", + "**DeepSeek-V3 Family:**\n", + "- DeepSeek-V3.1/V3.2: Hybrid model supporting both thinking and non-thinking modes, use the `deepseek-v3` parser and `thinking` parameter (NOTE: not `enable_thinking`)\n", + "\n", + "**Qwen3 Family:**\n", + "- Standard Qwen3 (e.g., Qwen3-2507): Use `qwen3` parser, supports `enable_thinking` in chat templates\n", + "- Qwen3-Thinking (e.g., Qwen3-235B-A22B-Thinking-2507): Use `qwen3` or `qwen3-thinking` parser, always thinks\n", + "\n", + "**Kimi K2:**\n", + "- Kimi K2 Thinking: Uses special `◁think▷` and `◁/think▷` tags. For agentic tool use, also specify `--tool-call-parser kimi_k2`.\n", + "\n", + "**GPT OSS:**\n", + "- GPT OSS: Uses special `<|channel|>analysis<|message|>` and `<|end|>` tags" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage\n", + "\n", + "### Launching the Server" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify the `--reasoning-parser` option." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from openai import OpenAI\n", + "from sglang.test.doc_patch import launch_server_cmd\n", + "from sglang.utils import wait_for_server, print_highlight, terminate_process\n", + "\n", + "server_process, port = launch_server_cmd(\n", + " \"python3 -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n", + ")\n", + "\n", + "wait_for_server(f\"http://localhost:{port}\", process=server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that `--reasoning-parser` defines the parser used to interpret responses." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### OpenAI Compatible API\n", + "\n", + "Using the OpenAI compatible API, the contract follows the [DeepSeek API design](https://api-docs.deepseek.com/guides/reasoning_model) established with the release of DeepSeek-R1:\n", + "\n", + "- `reasoning_content`: The content of the CoT.\n", + "- `content`: The content of the final answer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Initialize OpenAI-like client\n", + "client = OpenAI(api_key=\"None\", base_url=f\"http://0.0.0.0:{port}/v1\")\n", + "model_name = client.models.list().data[0].id\n", + "\n", + "messages = [\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is 1+3?\",\n", + " }\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Non-Streaming Request" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_non_stream = client.chat.completions.create(\n", + " model=model_name,\n", + " messages=messages,\n", + " temperature=0.6,\n", + " top_p=0.95,\n", + " stream=False, # Non-streaming\n", + " extra_body={\"separate_reasoning\": True},\n", + ")\n", + "print_highlight(\"==== Reasoning ====\")\n", + "print_highlight(response_non_stream.choices[0].message.reasoning_content)\n", + "\n", + "print_highlight(\"==== Text ====\")\n", + "print_highlight(response_non_stream.choices[0].message.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Streaming Request" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_stream = client.chat.completions.create(\n", + " model=model_name,\n", + " messages=messages,\n", + " temperature=0.6,\n", + " top_p=0.95,\n", + " stream=True, # Non-streaming\n", + " extra_body={\"separate_reasoning\": True},\n", + ")\n", + "\n", + "reasoning_content = \"\"\n", + "content = \"\"\n", + "for chunk in response_stream:\n", + " if chunk.choices[0].delta.content:\n", + " content += chunk.choices[0].delta.content\n", + " if chunk.choices[0].delta.reasoning_content:\n", + " reasoning_content += chunk.choices[0].delta.reasoning_content\n", + "\n", + "print_highlight(\"==== Reasoning ====\")\n", + "print_highlight(reasoning_content)\n", + "\n", + "print_highlight(\"==== Text ====\")\n", + "print_highlight(content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optionally, you can buffer the reasoning content to the last reasoning chunk (or the first chunk after the reasoning content)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_stream = client.chat.completions.create(\n", + " model=model_name,\n", + " messages=messages,\n", + " temperature=0.6,\n", + " top_p=0.95,\n", + " stream=True, # Non-streaming\n", + " extra_body={\"separate_reasoning\": True, \"stream_reasoning\": False},\n", + ")\n", + "\n", + "reasoning_content = \"\"\n", + "content = \"\"\n", + "for chunk in response_stream:\n", + " if chunk.choices[0].delta.content:\n", + " content += chunk.choices[0].delta.content\n", + " if chunk.choices[0].delta.reasoning_content:\n", + " reasoning_content += chunk.choices[0].delta.reasoning_content\n", + "\n", + "print_highlight(\"==== Reasoning ====\")\n", + "print_highlight(reasoning_content)\n", + "\n", + "print_highlight(\"==== Text ====\")\n", + "print_highlight(content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The reasoning separation is enable by default when specify . \n", + "**To disable it, set the `separate_reasoning` option to `False` in request.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_non_stream = client.chat.completions.create(\n", + " model=model_name,\n", + " messages=messages,\n", + " temperature=0.6,\n", + " top_p=0.95,\n", + " stream=False, # Non-streaming\n", + " extra_body={\"separate_reasoning\": False},\n", + ")\n", + "\n", + "print_highlight(\"==== Original Output ====\")\n", + "print_highlight(response_non_stream.choices[0].message.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### SGLang Native API " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from transformers import AutoTokenizer\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\")\n", + "input = tokenizer.apply_chat_template(\n", + " messages, tokenize=False, add_generation_prompt=True, return_dict=False\n", + ")\n", + "\n", + "gen_url = f\"http://localhost:{port}/generate\"\n", + "gen_data = {\n", + " \"text\": input,\n", + " \"sampling_params\": {\n", + " \"skip_special_tokens\": False,\n", + " \"max_new_tokens\": 1024,\n", + " \"temperature\": 0.6,\n", + " \"top_p\": 0.95,\n", + " },\n", + "}\n", + "gen_response = requests.post(gen_url, json=gen_data).json()[\"text\"]\n", + "\n", + "print_highlight(\"==== Original Output ====\")\n", + "print_highlight(gen_response)\n", + "\n", + "parse_url = f\"http://localhost:{port}/separate_reasoning\"\n", + "separate_reasoning_data = {\n", + " \"text\": gen_response,\n", + " \"reasoning_parser\": \"deepseek-r1\",\n", + "}\n", + "separate_reasoning_response_json = requests.post(\n", + " parse_url, json=separate_reasoning_data\n", + ").json()\n", + "print_highlight(\"==== Reasoning ====\")\n", + "print_highlight(separate_reasoning_response_json[\"reasoning_text\"])\n", + "print_highlight(\"==== Text ====\")\n", + "print_highlight(separate_reasoning_response_json[\"text\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "terminate_process(server_process)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Offline Engine API" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sglang as sgl\n", + "from sglang.srt.parser.reasoning_parser import ReasoningParser\n", + "from sglang.utils import print_highlight\n", + "\n", + "llm = sgl.Engine(model_path=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\")\n", + "tokenizer = AutoTokenizer.from_pretrained(\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\")\n", + "input = tokenizer.apply_chat_template(\n", + " messages, tokenize=False, add_generation_prompt=True, return_dict=False\n", + ")\n", + "sampling_params = {\n", + " \"max_new_tokens\": 1024,\n", + " \"skip_special_tokens\": False,\n", + " \"temperature\": 0.6,\n", + " \"top_p\": 0.95,\n", + "}\n", + "result = llm.generate(prompt=input, sampling_params=sampling_params)\n", + "\n", + "generated_text = result[\"text\"] # Assume there is only one prompt\n", + "\n", + "print_highlight(\"==== Original Output ====\")\n", + "print_highlight(generated_text)\n", + "\n", + "parser = ReasoningParser(\"deepseek-r1\")\n", + "reasoning_text, text = parser.parse_non_stream(generated_text)\n", + "print_highlight(\"==== Reasoning ====\")\n", + "print_highlight(reasoning_text)\n", + "print_highlight(\"==== Text ====\")\n", + "print_highlight(text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm.shutdown()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Supporting New Reasoning Model Schemas\n", + "\n", + "For future reasoning models, you can implement the reasoning parser as a subclass of `BaseReasoningFormatDetector` in `python/sglang/srt/reasoning_parser.py` and specify the reasoning parser for new reasoning model schemas accordingly." + ] + } + ], + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/sglang/docs/advanced_features/server_arguments.md b/sglang/docs/advanced_features/server_arguments.md new file mode 100644 index 0000000000000000000000000000000000000000..b8d89c208e071208e14a934d1b7099abc876ee31 --- /dev/null +++ b/sglang/docs/advanced_features/server_arguments.md @@ -0,0 +1,569 @@ +# Server Arguments + +This page provides a list of server arguments used in the command line to configure the behavior +and performance of the language model server during deployment. These arguments enable users to +customize key aspects of the server, including model selection, parallelism policies, +memory management, and optimization techniques. +You can find all arguments by `python3 -m sglang.launch_server --help` + +## Common launch commands + +- To use a configuration file, create a YAML file with your server arguments and specify it with `--config`. CLI arguments will override config file values. + + ```bash + # Create config.yaml + cat > config.yaml << EOF + model-path: meta-llama/Meta-Llama-3-8B-Instruct + host: 0.0.0.0 + port: 30000 + tensor-parallel-size: 2 + enable-metrics: true + log-requests: true + EOF + + # Launch server with config file + python -m sglang.launch_server --config config.yaml + ``` + +- To enable multi-GPU tensor parallelism, add `--tp 2`. If it reports the error "peer access is not supported between these two devices", add `--enable-p2p-check` to the server launch command. + + ```bash + python -m sglang.launch_server --model-path meta-llama/Meta-Llama-3-8B-Instruct --tp 2 + ``` + +- To enable multi-GPU data parallelism, add `--dp 2`. Data parallelism is better for throughput if there is enough memory. It can also be used together with tensor parallelism. The following command uses 4 GPUs in total. We recommend [SGLang Model Gateway (former Router)](../advanced_features/sgl_model_gateway.md) for data parallelism. + + ```bash + python -m sglang_router.launch_server --model-path meta-llama/Meta-Llama-3-8B-Instruct --dp 2 --tp 2 + ``` + +- If you see out-of-memory errors during serving, try to reduce the memory usage of the KV cache pool by setting a smaller value of `--mem-fraction-static`. The default value is `0.9`. + + ```bash + python -m sglang.launch_server --model-path meta-llama/Meta-Llama-3-8B-Instruct --mem-fraction-static 0.7 + ``` + +- See [hyperparameter tuning](hyperparameter_tuning.md) on tuning hyperparameters for better performance. +- For docker and Kubernetes runs, you need to set up shared memory which is used for communication between processes. See `--shm-size` for docker and `/dev/shm` size update for Kubernetes manifests. +- If you see out-of-memory errors during prefill for long prompts, try to set a smaller chunked prefill size. + + ```bash + python -m sglang.launch_server --model-path meta-llama/Meta-Llama-3-8B-Instruct --chunked-prefill-size 4096 + ``` +- To enable fp8 weight quantization, add `--quantization fp8` on a fp16 checkpoint or directly load a fp8 checkpoint without specifying any arguments. +- To enable fp8 kv cache quantization, add `--kv-cache-dtype fp8_e4m3` or `--kv-cache-dtype fp8_e5m2`. +- To enable deterministic inference and batch invariant operations, add `--enable-deterministic-inference`. More details can be found in [deterministic inference document](../advanced_features/deterministic_inference.md). +- If the model does not have a chat template in the Hugging Face tokenizer, you can specify a [custom chat template](../references/custom_chat_template.md). If the tokenizer has multiple named templates (e.g., 'default', 'tool_use'), you can select one using `--hf-chat-template-name tool_use`. +- To run tensor parallelism on multiple nodes, add `--nnodes 2`. If you have two nodes with two GPUs on each node and want to run TP=4, let `sgl-dev-0` be the hostname of the first node and `50000` be an available port, you can use the following commands. If you meet deadlock, please try to add `--disable-cuda-graph` +- (Note: This feature is out of maintenance and might cause error) To enable `torch.compile` acceleration, add `--enable-torch-compile`. It accelerates small models on small batch sizes. By default, the cache path is located at `/tmp/torchinductor_root`, you can customize it using environment variable `TORCHINDUCTOR_CACHE_DIR`. For more details, please refer to [PyTorch official documentation](https://pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html) and [Enabling cache for torch.compile](https://docs.sglang.io/references/torch_compile_cache.html). + ```bash + # Node 0 + python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3-8B-Instruct \ + --tp 4 \ + --dist-init-addr sgl-dev-0:50000 \ + --nnodes 2 \ + --node-rank 0 + + # Node 1 + python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3-8B-Instruct \ + --tp 4 \ + --dist-init-addr sgl-dev-0:50000 \ + --nnodes 2 \ + --node-rank 1 + ``` + +Please consult the documentation below and [server_args.py](https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/server_args.py) to learn more about the arguments you may provide when launching a server. + +## Model and tokenizer +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--model-path`
`--model` | The path of the model weights. This can be a local folder or a Hugging Face repo ID. | `None` | Type: str | +| `--tokenizer-path` | The path of the tokenizer. | `None` | Type: str | +| `--tokenizer-mode` | Tokenizer mode. 'auto' will use the fast tokenizer if available, and 'slow' will always use the slow tokenizer. | `auto` | `auto`, `slow` | +| `--tokenizer-worker-num` | The worker num of the tokenizer manager. | `1` | Type: int | +| `--skip-tokenizer-init` | If set, skip init tokenizer and pass input_ids in generate request. | `False` | bool flag (set to enable) | +| `--load-format` | The format of the model weights to load. "auto" will try to load the weights in the safetensors format and fall back to the pytorch bin format if safetensors format is not available. "pt" will load the weights in the pytorch bin format. "safetensors" will load the weights in the safetensors format. "npcache" will load the weights in pytorch format and store a numpy cache to speed up the loading. "dummy" will initialize the weights with random values, which is mainly for profiling."gguf" will load the weights in the gguf format. "bitsandbytes" will load the weights using bitsandbytes quantization."layered" loads weights layer by layer so that one can quantize a layer before loading another to make the peak memory envelope smaller. "flash_rl" will load the weights in flash_rl format. "fastsafetensors" and "private" are also supported. | `auto` | `auto`, `pt`, `safetensors`, `npcache`, `dummy`, `sharded_state`, `gguf`, `bitsandbytes`, `layered`, `flash_rl`, `remote`, `remote_instance`, `fastsafetensors`, `private` | +| `--model-loader-extra-config` | Extra config for model loader. This will be passed to the model loader corresponding to the chosen load_format. | `{}` | Type: str | +| `--trust-remote-code` | Whether or not to allow for custom models defined on the Hub in their own modeling files. | `False` | bool flag (set to enable) | +| `--context-length` | The model's maximum context length. Defaults to None (will use the value from the model's config.json instead). | `None` | Type: int | +| `--is-embedding` | Whether to use a CausalLM as an embedding model. | `False` | bool flag (set to enable) | +| `--enable-multimodal` | Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen | `None` | bool flag (set to enable) | +| `--revision` | The specific model version to use. It can be a branch name, a tag name, or a commit id. If unspecified, will use the default version. | `None` | Type: str | +| `--model-impl` | Which implementation of the model to use. * "auto" will try to use the SGLang implementation if it exists and fall back to the Transformers implementation if no SGLang implementation is available. * "sglang" will use the SGLang model implementation. * "transformers" will use the Transformers model implementation. | `auto` | Type: str | + +## HTTP server +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--host` | The host of the HTTP server. | `127.0.0.1` | Type: str | +| `--port` | The port of the HTTP server. | `30000` | Type: int | +| `--fastapi-root-path` | App is behind a path based routing proxy. | `""` | Type: str | +| `--grpc-mode` | If set, use gRPC server instead of HTTP server. | `False` | bool flag (set to enable) | +| `--skip-server-warmup` | If set, skip warmup. | `False` | bool flag (set to enable) | +| `--warmups` | Specify custom warmup functions (csv) to run before server starts eg. --warmups=warmup_name1,warmup_name2 will run the functions `warmup_name1` and `warmup_name2` specified in warmup.py before the server starts listening for requests | `None` | Type: str | +| `--nccl-port` | The port for NCCL distributed environment setup. Defaults to a random port. | `None` | Type: int | +| `--checkpoint-engine-wait-weights-before-ready` | If set, the server will wait for initial weights to be loaded via checkpoint-engine or other update methods before serving inference requests. | `False` | bool flag (set to enable) | + +## Quantization and data type +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--dtype` | Data type for model weights and activations. * "auto" will use FP16 precision for FP32 and FP16 models, and BF16 precision for BF16 models. * "half" for FP16. Recommended for AWQ quantization. * "float16" is the same as "half". * "bfloat16" for a balance between precision and range. * "float" is shorthand for FP32 precision. * "float32" for FP32 precision. | `auto` | `auto`, `half`, `float16`, `bfloat16`, `float`, `float32` | +| `--quantization` | The quantization method. | `None` | `awq`, `fp8`, `gptq`, `marlin`, `gptq_marlin`, `awq_marlin`, `bitsandbytes`, `gguf`, `modelopt`, `modelopt_fp8`, `modelopt_fp4`, `petit_nvfp4`, `w8a8_int8`, `w8a8_fp8`, `moe_wna16`, `qoq`, `w4afp8`, `mxfp4`, `mxfp8`, `auto-round`, `compressed-tensors`, `modelslim`, `quark_int4fp8_moe` | +| `--quantization-param-path` | Path to the JSON file containing the KV cache scaling factors. This should generally be supplied, when KV cache dtype is FP8. Otherwise, KV cache scaling factors default to 1.0, which may cause accuracy issues. | `None` | Type: Optional[str] | +| `--kv-cache-dtype` | Data type for kv cache storage. "auto" will use model data type. "bf16" or "bfloat16" for BF16 KV cache. "fp8_e5m2" and "fp8_e4m3" are supported for CUDA 11.8+. "fp4_e2m1" (only mxfp4) is supported for CUDA 12.8+ and PyTorch 2.8.0+ | `auto` | `auto`, `fp8_e5m2`, `fp8_e4m3`, `bf16`, `bfloat16`, `fp4_e2m1` | +| `--enable-fp32-lm-head` | If set, the LM head outputs (logits) are in FP32. | `False` | bool flag (set to enable) | +| `--modelopt-quant` | The ModelOpt quantization configuration. Supported values: 'fp8', 'int4_awq', 'w4a8_awq', 'nvfp4', 'nvfp4_awq'. This requires the NVIDIA Model Optimizer library to be installed: pip install nvidia-modelopt | `None` | Type: str | +| `--modelopt-checkpoint-restore-path` | Path to restore a previously saved ModelOpt quantized checkpoint. If provided, the quantization process will be skipped and the model will be loaded from this checkpoint. | `None` | Type: str | +| `--modelopt-checkpoint-save-path` | Path to save the ModelOpt quantized checkpoint after quantization. This allows reusing the quantized model in future runs. | `None` | Type: str | +| `--modelopt-export-path` | Path to export the quantized model in HuggingFace format after ModelOpt quantization. The exported model can then be used directly with SGLang for inference. If not provided, the model will not be exported. | `None` | Type: str | +| `--quantize-and-serve` | Quantize the model with ModelOpt and immediately serve it without exporting. This is useful for development and prototyping. For production, it's recommended to use separate quantization and deployment steps. | `False` | bool flag (set to enable) | +| `--rl-quant-profile` | Path to the FlashRL quantization profile. Required when using --load-format flash_rl. | `None` | Type: str | + +## Memory and scheduling +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--mem-fraction-static` | The fraction of the memory used for static allocation (model weights and KV cache memory pool). Use a smaller value if you see out-of-memory errors. | `None` | Type: float | +| `--max-running-requests` | The maximum number of running requests. | `None` | Type: int | +| `--max-queued-requests` | The maximum number of queued requests. This option is ignored when using disaggregation-mode. | `None` | Type: int | +| `--max-total-tokens` | The maximum number of tokens in the memory pool. If not specified, it will be automatically calculated based on the memory usage fraction. This option is typically used for development and debugging purposes. | `None` | Type: int | +| `--chunked-prefill-size` | The maximum number of tokens in a chunk for the chunked prefill. Setting this to -1 means disabling chunked prefill. | `None` | Type: int | +| `--prefill-max-requests` | The maximum number of requests in a prefill batch. If not specified, there is no limit. | `None` | Type: int | +| `--enable-dynamic-chunking` | Enable dynamic chunk size adjustment for pipeline parallelism. When enabled, chunk sizes are dynamically calculated based on fitted function to maintain consistent execution time across chunks. | `False` | bool flag (set to enable) | +| `--max-prefill-tokens` | The maximum number of tokens in a prefill batch. The real bound will be the maximum of this value and the model's maximum context length. | `16384` | Type: int | +| `--schedule-policy` | The scheduling policy of the requests. | `fcfs` | `lpm`, `random`, `fcfs`, `dfs-weight`, `lof`, `priority`, `routing-key` | +| `--enable-priority-scheduling` | Enable priority scheduling. Requests with higher priority integer values will be scheduled first by default. | `False` | bool flag (set to enable) | +| `--abort-on-priority-when-disabled` | If set, abort requests that specify a priority when priority scheduling is disabled. | `False` | bool flag (set to enable) | +| `--schedule-low-priority-values-first` | If specified with --enable-priority-scheduling, the scheduler will schedule requests with lower priority integer values first. | `False` | bool flag (set to enable) | +| `--priority-scheduling-preemption-threshold` | Minimum difference in priorities for an incoming request to have to preempt running request(s). | `10` | Type: int | +| `--schedule-conservativeness` | How conservative the schedule policy is. A larger value means more conservative scheduling. Use a larger value if you see requests being retracted frequently. | `1.0` | Type: float | +| `--page-size` | The number of tokens in a page. | `1` | Type: int | +| `--swa-full-tokens-ratio` | The ratio of SWA layer KV tokens / full layer KV tokens, regardless of the number of swa:full layers. It should be between 0 and 1. E.g. 0.5 means if each swa layer has 50 tokens, then each full layer has 100 tokens. | `0.8` | Type: float | +| `--disable-hybrid-swa-memory` | Disable the hybrid SWA memory. | `False` | bool flag (set to enable) | +| `--radix-eviction-policy` | The eviction policy of radix trees. 'lru' stands for Least Recently Used, 'lfu' stands for Least Frequently Used. | `lru` | `lru`, `lfu` | +| `--enable-prefill-delayer` | Enable prefill delayer for DP attention to reduce idle time. | `False` | bool flag (set to enable) | +| `--prefill-delayer-max-delay-passes` | Maximum forward passes to delay prefill. | `30` | Type: int | +| `--prefill-delayer-token-usage-low-watermark` | Token usage low watermark for prefill delayer. | `None` | Type: float | +| `--prefill-delayer-forward-passes-buckets` | Custom buckets for prefill delayer forward passes histogram. 0 and max_delay_passes-1 will be auto-added. | `None` | List[float] | +| `--prefill-delayer-wait-seconds-buckets` | Custom buckets for prefill delayer wait seconds histogram. 0 will be auto-added. | `None` | List[float] | + +## Runtime options +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--device` | The device to use ('cuda', 'xpu', 'hpu', 'npu', 'cpu'). Defaults to auto-detection if not specified. | `None` | Type: str | +| `--tensor-parallel-size`
`--tp-size` | The tensor parallelism size. | `1` | Type: int | +| `--pipeline-parallel-size`
`--pp-size` | The pipeline parallelism size. | `1` | Type: int | +| `--attention-context-parallel-size`
`--attn-cp-size`| The attention context parallelism size. | `1` | Type: int| +| `--moe-data-parallel-size`
`--moe-dp-size`| The moe data parallelism size. | `1` | Type: int| +| `--pp-max-micro-batch-size` | The maximum micro batch size in pipeline parallelism. | `None` | Type: int | +| `--pp-async-batch-depth` | The async batch depth of pipeline parallelism. | `0` | Type: int | +| `--stream-interval` | The interval (or buffer size) for streaming in terms of the token length. A smaller value makes streaming smoother, while a larger value makes the throughput higher | `1` | Type: int | +| `--stream-output` | Whether to output as a sequence of disjoint segments. | `False` | bool flag (set to enable) | +| `--random-seed` | The random seed. | `None` | Type: int | +| `--constrained-json-whitespace-pattern` | (outlines and llguidance backends only) Regex pattern for syntactic whitespaces allowed in JSON constrained output. For example, to allow the model to generate consecutive whitespaces, set the pattern to [\n\t ]* | `None` | Type: str | +| `--constrained-json-disable-any-whitespace` | (xgrammar and llguidance backends only) Enforce compact representation in JSON constrained output. | `False` | bool flag (set to enable) | +| `--watchdog-timeout` | Set watchdog timeout in seconds. If a forward batch takes longer than this, the server will crash to prevent hanging. | `300` | Type: float | +| `--soft-watchdog-timeout` | Set soft watchdog timeout in seconds. If a forward batch takes longer than this, the server will dump information for debugging. | `None` | Type: float | +| `--dist-timeout` | Set timeout for torch.distributed initialization. | `None` | Type: int | +| `--download-dir` | Model download directory for huggingface. | `None` | Type: str | +| `--model-checksum` | Model file integrity verification. If provided without value, uses model-path as HF repo ID. Otherwise, provide checksums JSON file path or HuggingFace repo ID. | `None` | Type: str | +| `--base-gpu-id` | The base GPU ID to start allocating GPUs from. Useful when running multiple instances on the same machine. | `0` | Type: int | +| `--gpu-id-step` | The delta between consecutive GPU IDs that are used. For example, setting it to 2 will use GPU 0,2,4,... | `1` | Type: int | +| `--sleep-on-idle` | Reduce CPU usage when sglang is idle. | `False` | bool flag (set to enable) | +| `--custom-sigquit-handler` | Register a custom sigquit handler so you can do additional cleanup after the server is shutdown. This is only available for Engine, not for CLI. | `None` | Type: str | + +## Logging +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--log-level` | The logging level of all loggers. | `info` | Type: str | +| `--log-level-http` | The logging level of HTTP server. If not set, reuse --log-level by default. | `None` | Type: str | +| `--log-requests` | Log metadata, inputs, outputs of all requests. The verbosity is decided by --log-requests-level | `False` | bool flag (set to enable) | +| `--log-requests-level` | 0: Log metadata (no sampling parameters). 1: Log metadata and sampling parameters. 2: Log metadata, sampling parameters and partial input/output. 3: Log every input/output. | `2` | `0`, `1`, `2`, `3` | +| `--log-requests-format` | Format for request logging: 'text' (human-readable) or 'json' (structured) | `text` | `text`, `json` | +| `--log-requests-target` | Target(s) for request logging: 'stdout' and/or directory path(s) for file output. Can specify multiple targets, e.g., '--log-requests-target stdout /my/path'. | `None` | List[str] | +| `--uvicorn-access-log-exclude-prefixes` | Exclude uvicorn access logs whose request path starts with any of these prefixes. Defaults to empty (disabled). | `[]` | List[str] | +| `--crash-dump-folder` | Folder path to dump requests from the last 5 min before a crash (if any). If not specified, crash dumping is disabled. | `None` | Type: str | +| `--show-time-cost` | Show time cost of custom marks. | `False` | bool flag (set to enable) | +| `--enable-metrics` | Enable log prometheus metrics. | `False` | bool flag (set to enable) | +| `--enable-metrics-for-all-schedulers` | Enable --enable-metrics-for-all-schedulers when you want schedulers on all TP ranks (not just TP 0) to record request metrics separately. This is especially useful when dp_attention is enabled, as otherwise all metrics appear to come from TP 0. | `False` | bool flag (set to enable) | +| `--tokenizer-metrics-custom-labels-header` | Specify the HTTP header for passing custom labels for tokenizer metrics. | `x-custom-labels` | Type: str | +| `--tokenizer-metrics-allowed-custom-labels` | The custom labels allowed for tokenizer metrics. The labels are specified via a dict in '--tokenizer-metrics-custom-labels-header' field in HTTP requests, e.g., {'label1': 'value1', 'label2': 'value2'} is allowed if '--tokenizer-metrics-allowed-custom-labels label1 label2' is set. | `None` | List[str] | +| `--bucket-time-to-first-token` | The buckets of time to first token, specified as a list of floats. | `None` | List[float] | +| `--bucket-inter-token-latency` | The buckets of inter-token latency, specified as a list of floats. | `None` | List[float] | +| `--bucket-e2e-request-latency` | The buckets of end-to-end request latency, specified as a list of floats. | `None` | List[float] | +| `--collect-tokens-histogram` | Collect prompt/generation tokens histogram. | `False` | bool flag (set to enable) | +| `--prompt-tokens-buckets` | The buckets rule of prompt tokens. Supports 3 rule types: 'default' uses predefined buckets; 'tse ' generates two sides exponential distributed buckets (e.g., 'tse 1000 2 8' generates buckets [984.0, 992.0, 996.0, 998.0, 1000.0, 1002.0, 1004.0, 1008.0, 1016.0]).); 'custom ...' uses custom bucket values (e.g., 'custom 10 50 100 500'). | `None` | List[str] | +| `--generation-tokens-buckets` | The buckets rule for generation tokens histogram. Supports 3 rule types: 'default' uses predefined buckets; 'tse ' generates two sides exponential distributed buckets (e.g., 'tse 1000 2 8' generates buckets [984.0, 992.0, 996.0, 998.0, 1000.0, 1002.0, 1004.0, 1008.0, 1016.0]).); 'custom ...' uses custom bucket values (e.g., 'custom 10 50 100 500'). | `None` | List[str] | +| `--gc-warning-threshold-secs` | The threshold for long GC warning. If a GC takes longer than this, a warning will be logged. Set to 0 to disable. | `0.0` | Type: float | +| `--decode-log-interval` | The log interval of decode batch. | `40` | Type: int | +| `--enable-request-time-stats-logging` | Enable per request time stats logging | `False` | bool flag (set to enable) | +| `--kv-events-config` | Config in json format for NVIDIA dynamo KV event publishing. Publishing will be enabled if this flag is used. | `None` | Type: str | +| `--enable-trace` | Enable opentelemetry trace | `False` | bool flag (set to enable) | +| `--otlp-traces-endpoint` | Config opentelemetry collector endpoint if --enable-trace is set. format: : | `localhost:4317` | Type: str | + +## RequestMetricsExporter configuration +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--export-metrics-to-file` | Export performance metrics for each request to local file (e.g. for forwarding to external systems). | `False` | bool flag (set to enable) | +| `--export-metrics-to-file-dir` | Directory path for writing performance metrics files (required when --export-metrics-to-file is enabled). | `None` | Type: str | + +## API related +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--api-key` | Set API key of the server. It is also used in the OpenAI API compatible server. | `None` | Type: str | +| `--admin-api-key` | Set **admin API key** for administrative/control endpoints (e.g., weights update, cache flush, `/get_server_info`). Endpoints marked as admin-only require `Authorization: Bearer ` when this is set. | `None` | Type: str | +| `--served-model-name` | Override the model name returned by the v1/models endpoint in OpenAI API server. | `None` | Type: str | +| `--weight-version` | Version identifier for the model weights. Defaults to 'default' if not specified. | `default` | Type: str | +| `--chat-template` | The builtin chat template name or the path of the chat template file. This is only used for OpenAI-compatible API server. | `None` | Type: str | +| `--hf-chat-template-name` | When the HuggingFace tokenizer has multiple chat templates (e.g., 'default', 'tool_use', 'rag'), specify which named template to use. If not set, the first available template is used. | `None` | Type: str | +| `--completion-template` | The builtin completion template name or the path of the completion template file. This is only used for OpenAI-compatible API server. only for code completion currently. | `None` | Type: str | +| `--file-storage-path` | The path of the file storage in backend. | `sglang_storage` | Type: str | +| `--enable-cache-report` | Return number of cached tokens in usage.prompt_tokens_details for each openai request. | `False` | bool flag (set to enable) | +| `--reasoning-parser` | Specify the parser for reasoning models. Supported parsers: [deepseek-r1, deepseek-v3, glm45, gpt-oss, kimi, qwen3, qwen3-thinking, step3]. | `None` | `deepseek-r1`, `deepseek-v3`, `glm45`, `gpt-oss`, `kimi`, `qwen3`, `qwen3-thinking`, `step3` | +| `--tool-call-parser` | Specify the parser for handling tool-call interactions. Supported parsers: [deepseekv3, deepseekv31, glm, glm45, glm47, gpt-oss, kimi_k2, llama3, mistral, pythonic, qwen, qwen25, qwen3_coder, step3]. | `None` | `deepseekv3`, `deepseekv31`, `glm`, `glm45`, `glm47`, `gpt-oss`, `kimi_k2`, `llama3`, `mistral`, `pythonic`, `qwen`, `qwen25`, `qwen3_coder`, `step3`, `gigachat3` | +| `--tool-server` | Either 'demo' or a comma-separated list of tool server urls to use for the model. If not specified, no tool server will be used. | `None` | Type: str | +| `--sampling-defaults` | Where to get default sampling parameters. 'openai' uses SGLang/OpenAI defaults (temperature=1.0, top_p=1.0, etc.). 'model' uses the model's generation_config.json to get the recommended sampling parameters if available. Default is 'model'. | `model` | `openai`, `model` | + +## Data parallelism +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--data-parallel-size`
`--dp-size` | The data parallelism size. | `1` | Type: int | +| `--load-balance-method` | The load balancing strategy for data parallelism. The `total_tokens` algorithm can only be used when DP attention is applied. This algorithm performs load balancing based on the real-time token load of the DP workers. | `auto` | `auto`, `round_robin`, `follow_bootstrap_room`, `total_requests`, `total_tokens` | + +## Multi-node distributed serving +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--dist-init-addr`
`--nccl-init-addr` | The host address for initializing distributed backend (e.g., `192.168.0.2:25000`). | `None` | Type: str | +| `--nnodes` | The number of nodes. | `1` | Type: int | +| `--node-rank` | The node rank. | `0` | Type: int | + +## Model override args +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--json-model-override-args` | A dictionary in JSON string format used to override default model configurations. | `{}` | Type: str | +| `--preferred-sampling-params` | json-formatted sampling settings that will be returned in /get_model_info | `None` | Type: str | + +## LoRA +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-lora` | Enable LoRA support for the model. This argument is automatically set to `True` if `--lora-paths` is provided for backward compatibility. | `False` | Bool flag (set to enable) | +| `--enable-lora-overlap-loading` | Enable asynchronous LoRA weight loading in order to overlap H2D transfers with GPU compute. This should be enabled if you find that your LoRA workloads are bottlenecked by adapter weight loading, for example when frequently loading large LoRA adapters. | `False` | Bool flag (set to enable) +| `--max-lora-rank` | The maximum LoRA rank that should be supported. If not specified, it will be automatically inferred from the adapters provided in `--lora-paths`. This argument is needed when you expect to dynamically load adapters of larger LoRA rank after server startup. | `None` | Type: int | +| `--lora-target-modules` | The union set of all target modules where LoRA should be applied (e.g., `q_proj`, `k_proj`, `gate_proj`). If not specified, it will be automatically inferred from the adapters provided in `--lora-paths`. You can also set it to `all` to enable LoRA for all supported modules; note this may introduce minor performance overhead. | `None` | `q_proj`, `k_proj`, `v_proj`, `o_proj`, `gate_proj`, `up_proj`, `down_proj`, `qkv_proj`, `gate_up_proj`, `all` | +| `--lora-paths` | The list of LoRA adapters to load. Each adapter must be specified in one of the following formats: `` \| `=` \| JSON with schema `{"lora_name": str, "lora_path": str, "pinned": bool}`. | `None` | Type: List[str] / JSON objects | +| `--max-loras-per-batch` | Maximum number of adapters for a running batch, including base-only requests. | `8` | Type: int | +| `--max-loaded-loras` | If specified, limits the maximum number of LoRA adapters loaded in CPU memory at a time. Must be ≥ `--max-loras-per-batch`. | `None` | Type: int | +| `--lora-eviction-policy` | LoRA adapter eviction policy when the GPU memory pool is full. | `lru` | `lru`, `fifo` | +| `--lora-backend` | Choose the kernel backend for multi-LoRA serving. | `csgmv` | `triton`, `csgmv`, `ascend`, `torch_native` | +| `--max-lora-chunk-size` | Maximum chunk size for the ChunkedSGMV LoRA backend. Only used when `--lora-backend` is `csgmv`. Larger values may improve performance. | `16` | `16`, `32`, `64`, `128` | + +## Kernel Backends (Attention, Sampling, Grammar, GEMM) +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--attention-backend` | Choose the kernels for attention layers. | `None` | `triton`, `torch_native`, `flex_attention`, `nsa`, `cutlass_mla`, `fa3`, `fa4`, `flashinfer`, `flashmla`, `trtllm_mla`, `trtllm_mha`, `dual_chunk_flash_attn`, `aiter`, `wave`, `intel_amx`, `ascend` | +| `--prefill-attention-backend` | Choose the kernels for prefill attention layers (have priority over --attention-backend). | `None` | `triton`, `torch_native`, `flex_attention`, `nsa`, `cutlass_mla`, `fa3`, `fa4`, `flashinfer`, `flashmla`, `trtllm_mla`, `trtllm_mha`, `dual_chunk_flash_attn`, `aiter`, `wave`, `intel_amx`, `ascend` | +| `--decode-attention-backend` | Choose the kernels for decode attention layers (have priority over --attention-backend). | `None` | `triton`, `torch_native`, `flex_attention`, `nsa`, `cutlass_mla`, `fa3`, `fa4`, `flashinfer`, `flashmla`, `trtllm_mla`, `trtllm_mha`, `dual_chunk_flash_attn`, `aiter`, `wave`, `intel_amx`, `ascend` | +| `--sampling-backend` | Choose the kernels for sampling layers. | `None` | `flashinfer`, `pytorch`, `ascend` | +| `--grammar-backend` | Choose the backend for grammar-guided decoding. | `None` | `xgrammar`, `outlines`, `llguidance`, `none` | +| `--mm-attention-backend` | Set multimodal attention backend. | `None` | `sdpa`, `fa3`, `fa4`, `triton_attn`, `ascend_attn`, `aiter_attn` | +| `--nsa-prefill-backend` | Choose the NSA backend for the prefill stage (overrides `--attention-backend` when running DeepSeek NSA-style attention). | `flashmla_sparse` | `flashmla_sparse`, `flashmla_kv`, `flashmla_auto`, `fa3`, `tilelang`, `aiter`, `trtllm` | +| `--nsa-decode-backend` | Choose the NSA backend for the decode stage when running DeepSeek NSA-style attention. Overrides `--attention-backend` for decoding. | `fa3` | `flashmla_sparse`, `flashmla_kv`, `fa3`, `tilelang`, `aiter`, `trtllm` | +| `--fp8-gemm-backend` | Choose the runner backend for Blockwise FP8 GEMM operations. Options: 'auto' (default, auto-selects based on hardware), 'deep_gemm' (JIT-compiled; enabled by default on NVIDIA Hopper (SM90) and Blackwell (SM100) when DeepGEMM is installed), 'flashinfer_trtllm' (FlashInfer TRTLLM backend; SM100/SM103 only), 'flashinfer_cutlass' (FlashInfer CUTLASS backend, SM120 only), 'flashinfer_deepgemm' (Hopper SM90 only, uses swapAB optimization for small M dimensions in decoding), 'cutlass' (optimal for Hopper/Blackwell GPUs and high-throughput), 'triton' (fallback, widely compatible), 'aiter' (ROCm only). **NOTE**: This replaces the deprecated environment variables SGLANG_ENABLE_FLASHINFER_FP8_GEMM and SGLANG_SUPPORT_CUTLASS_BLOCK_FP8. | `auto` | `auto`, `deep_gemm`, `flashinfer_trtllm`, `flashinfer_cutlass`, `flashinfer_deepgemm`, `cutlass`, `triton`, `aiter` | +| `--fp4-gemm-backend` | Choose the runner backend for NVFP4 GEMM operations. Options: 'flashinfer_cutlass' (default), 'auto' (auto-selects between flashinfer_cudnn/flashinfer_cutlass based on CUDA/cuDNN version), 'flashinfer_cudnn' (FlashInfer cuDNN backend, optimal on CUDA 13+ with cuDNN 9.15+), 'flashinfer_trtllm' (FlashInfer TensorRT-LLM backend, requires different weight preparation with shuffling). All backends are from FlashInfer; when FlashInfer is unavailable, sgl-kernel CUTLASS is used as an automatic fallback. **NOTE**: This replaces the deprecated environment variable SGLANG_FLASHINFER_FP4_GEMM_BACKEND. | `flashinfer_cutlass` | `auto`, `flashinfer_cudnn`, `flashinfer_cutlass`, `flashinfer_trtllm` | +| `--disable-flashinfer-autotune` | Flashinfer autotune is enabled by default. Set this flag to disable the autotune. | `False` | bool flag (set to enable) | + +## Speculative decoding +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--speculative-algorithm` | Speculative algorithm. | `None` | `EAGLE`, `EAGLE3`, `NEXTN`, `STANDALONE`, `NGRAM` | +| `--speculative-draft-model-path`
`--speculative-draft-model` | The path of the draft model weights. This can be a local folder or a Hugging Face repo ID. | `None` | Type: str | +| `--speculative-draft-model-revision` | The specific draft model version to use. It can be a branch name, a tag name, or a commit id. If unspecified, will use the default version. | `None` | Type: str | +| `--speculative-draft-load-format` | The format of the draft model weights to load. If not specified, will use the same format as --load-format. Use 'dummy' to initialize draft model weights with random values for profiling. | `None` | Same as --load-format options | +| `--speculative-num-steps` | The number of steps sampled from draft model in Speculative Decoding. | `None` | Type: int | +| `--speculative-eagle-topk` | The number of tokens sampled from the draft model in eagle2 each step. | `None` | Type: int | +| `--speculative-num-draft-tokens` | The number of tokens sampled from the draft model in Speculative Decoding. | `None` | Type: int | +| `--speculative-accept-threshold-single` | Accept a draft token if its probability in the target model is greater than this threshold. | `1.0` | Type: float | +| `--speculative-accept-threshold-acc` | The accept probability of a draft token is raised from its target probability p to min(1, p / threshold_acc). | `1.0` | Type: float | +| `--speculative-token-map` | The path of the draft model's small vocab table. | `None` | Type: str | +| `--speculative-attention-mode` | Attention backend for speculative decoding operations (both target verify and draft extend). Can be one of 'prefill' (default) or 'decode'. | `prefill` | `prefill`, `decode` | +| `--speculative-draft-attention-backend` | Attention backend for speculative decoding drafting. | `None` | Same as attention backend options | +| `--speculative-moe-runner-backend` | MOE backend for EAGLE speculative decoding, see --moe-runner-backend for options. Same as moe runner backend if unset. | `None` | Same as --moe-runner-backend options | +| `--speculative-moe-a2a-backend` | MOE A2A backend for EAGLE speculative decoding, see --moe-a2a-backend for options. Same as moe a2a backend if unset. | `None` | Same as --moe-a2a-backend options | +| `--speculative-draft-model-quantization` | The quantization method for speculative model. | `None` | Same as --quantization options | + +## Ngram speculative decoding +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--speculative-ngram-min-match-window-size` | The minimum window size for pattern matching in ngram speculative decoding. | `1` | Type: int | +| `--speculative-ngram-max-match-window-size` | The maximum window size for pattern matching in ngram speculative decoding. | `12` | Type: int | +| `--speculative-ngram-min-bfs-breadth` | The minimum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `1` | Type: int | +| `--speculative-ngram-max-bfs-breadth` | The maximum breadth for BFS (Breadth-First Search) in ngram speculative decoding. | `10` | Type: int | +| `--speculative-ngram-match-type` | The match type for cache tree. | `BFS` | `BFS`, `PROB` | +| `--speculative-ngram-branch-length` | The branch length for ngram speculative decoding. | `18` | Type: int | +| `--speculative-ngram-capacity` | The cache capacity for ngram speculative decoding. | `10000000` | Type: int | + +## Multi-layer Eagle speculative decoding +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-multi-layer-eagle` | Enable multi-layer Eagle speculative decoding. | `False` | bool flag (set to enable) | + +## MoE +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--expert-parallel-size`
`--ep-size`
`--ep` | The expert parallelism size. | `1` | Type: int | +| `--moe-a2a-backend` | Select the backend for all-to-all communication for expert parallelism. | `none` | `none`, `deepep`, `mooncake`, `mori`, `ascend_fuseep`| +| `--moe-runner-backend` | Choose the runner backend for MoE. | `auto` | `auto`, `deep_gemm`, `triton`, `triton_kernel`, `flashinfer_trtllm`, `flashinfer_cutlass`, `flashinfer_mxfp4`, `flashinfer_cutedsl`, `cutlass` | +| `--flashinfer-mxfp4-moe-precision` | Choose the computation precision of flashinfer mxfp4 moe | `default` | `default`, `bf16` | +| `--enable-flashinfer-allreduce-fusion` | Enable FlashInfer allreduce fusion with Residual RMSNorm. | `False` | bool flag (set to enable) | +| `--enable-aiter-allreduce-fusion` | Enable aiter allreduce fusion with Residual RMSNorm. | `False` | bool flag (set to enable) | +| `--deepep-mode` | Select the mode when enable DeepEP MoE, could be `normal`, `low_latency` or `auto`. Default is `auto`, which means `low_latency` for decode batch and `normal` for prefill batch. | `auto` | `normal`, `low_latency`, `auto` | +| `--ep-num-redundant-experts` | Allocate this number of redundant experts in expert parallel. | `0` | Type: int | +| `--ep-dispatch-algorithm` | The algorithm to choose ranks for redundant experts in expert parallel. | `None` | Type: str | +| `--init-expert-location` | Initial location of EP experts. | `trivial` | Type: str | +| `--enable-eplb` | Enable EPLB algorithm | `False` | bool flag (set to enable) | +| `--eplb-algorithm` | Chosen EPLB algorithm | `auto` | Type: str | +| `--eplb-rebalance-num-iterations` | Number of iterations to automatically trigger a EPLB re-balance. | `1000` | Type: int | +| `--eplb-rebalance-layers-per-chunk` | Number of layers to rebalance per forward pass. | `None` | Type: int | +| `--eplb-min-rebalancing-utilization-threshold` | Minimum threshold for GPU average utilization to trigger EPLB rebalancing. Must be in the range [0.0, 1.0]. | `1.0` | Type: float | +| `--expert-distribution-recorder-mode` | Mode of expert distribution recorder. | `None` | Type: str | +| `--expert-distribution-recorder-buffer-size` | Circular buffer size of expert distribution recorder. Set to -1 to denote infinite buffer. | `None` | Type: int | +| `--enable-expert-distribution-metrics` | Enable logging metrics for expert balancedness | `False` | bool flag (set to enable) | +| `--deepep-config` | Tuned DeepEP config suitable for your own cluster. It can be either a string with JSON content or a file path. | `None` | Type: str | +| `--moe-dense-tp-size` | TP size for MoE dense MLP layers. This flag is useful when, with large TP size, there are errors caused by weights in MLP layers having dimension smaller than the min dimension GEMM supports. | `None` | Type: int | +| `--elastic-ep-backend` | Specify the collective communication backend for elastic EP. Currently supports 'mooncake'. | `none` | `none`, `mooncake` | +| `--enable-elastic-expert-backup` | Enable elastic EP backend to backup expert weights in DRAM feature. Currently supports 'mooncake'.| `False` | bool flag (set to enable) | +| `--mooncake-ib-device` | The InfiniBand devices for Mooncake Backend transfer, accepts multiple comma-separated devices (e.g., --mooncake-ib-device mlx5_0,mlx5_1). Default is None, which triggers automatic device detection when Mooncake Backend is enabled. | `None` | Type: str | + +## Mamba Cache +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--max-mamba-cache-size` | The maximum size of the mamba cache. | `None` | Type: int | +| `--mamba-ssm-dtype` | The data type of the SSM states in mamba cache. | `float32` | `float32`, `bfloat16`, `float16` | +| `--mamba-full-memory-ratio` | The ratio of mamba state memory to full kv cache memory. | `0.9` | Type: float | +| `--mamba-scheduler-strategy` | The strategy to use for mamba scheduler. `auto` currently defaults to `no_buffer`. 1. `no_buffer` does not support overlap scheduler due to not allocating extra mamba state buffers. Branching point caching support is feasible but not implemented. 2. `extra_buffer` supports overlap schedule by allocating extra mamba state buffers to track mamba state for caching (mamba state usage per running req becomes `2x` for non-spec; `1+(1/(2+speculative_num_draft_tokens))x` for spec dec (e.g. 1.16x if speculative_num_draft_tokens==4)). 2a. `extra_buffer` is strictly better for non-KV-cache-bound cases; for KV-cache-bound cases, the tradeoff depends on whether enabling overlap outweighs reduced max running requests. 2b. mamba caching at radix cache branching point is strictly better than non-branch but requires kernel support (currently only FLA backend), currently only extra_buffer supports branching. | `auto` | `auto`, `no_buffer`, `extra_buffer` | +| `--mamba-track-interval` | The interval (in tokens) to track the mamba state during decode. Only used when `--mamba-scheduler-strategy` is `extra_buffer`. Must be divisible by page_size if set, and must be >= speculative_num_draft_tokens when using speculative decoding. | `256` | Type: int | + +## Hierarchical cache +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-hierarchical-cache` | Enable hierarchical cache | `False` | bool flag (set to enable) | +| `--hicache-ratio` | The ratio of the size of host KV cache memory pool to the size of device pool. | `2.0` | Type: float | +| `--hicache-size` | The size of host KV cache memory pool in gigabytes, which will override the hicache_ratio if set. | `0` | Type: int | +| `--hicache-write-policy` | The write policy of hierarchical cache. | `write_through` | `write_back`, `write_through`, `write_through_selective` | +| `--hicache-io-backend` | The IO backend for KV cache transfer between CPU and GPU | `kernel` | `direct`, `kernel`, `kernel_ascend` | +| `--hicache-mem-layout` | The layout of host memory pool for hierarchical cache. | `layer_first` | `layer_first`, `page_first`, `page_first_direct`, `page_first_kv_split`, `page_head` | +| `--hicache-storage-backend` | The storage backend for hierarchical KV cache. Built-in backends: file, mooncake, hf3fs, nixl, aibrix. For dynamic backend, use --hicache-storage-backend-extra-config to specify: backend_name (custom name), module_path (Python module path), class_name (backend class name). | `None` | `file`, `mooncake`, `hf3fs`, `nixl`, `aibrix`, `dynamic`, `eic` | +| `--hicache-storage-prefetch-policy` | Control when prefetching from the storage backend should stop. | `best_effort` | `best_effort`, `wait_complete`, `timeout` | +| `--hicache-storage-backend-extra-config` | A dictionary in JSON string format, or a string starting with a `@` followed by a config file in JSON/YAML/TOML format, containing extra configuration for the storage backend. | `None` | Type: str | + +## Hierarchical sparse attention +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--hierarchical-sparse-attention-extra-config` | A dictionary in JSON string format for hierarchical sparse attention configuration. Required fields: `algorithm` (str), `backend` (str). All other fields are algorithm-specific and passed to the algorithm constructor. | `None` | Type: str | + +## LMCache +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-lmcache` | Using LMCache as an alternative hierarchical cache solution | `False` | bool flag (set to enable) | + +## Ktransformers +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--kt-weight-path` | [ktransformers parameter] The path of the quantized expert weights for amx kernel. A local folder. | `None` | Type: str | +| `--kt-method` | [ktransformers parameter] Quantization formats for CPU execution. | `AMXINT4` | Type: str | +| `--kt-cpuinfer` | [ktransformers parameter] The number of CPUInfer threads. | `None` | Type: int | +| `--kt-threadpool-count` | [ktransformers parameter] One-to-one with the number of NUMA nodes (one thread pool per NUMA). | `2` | Type: int | +| `--kt-num-gpu-experts` | [ktransformers parameter] The number of GPU experts. | `None` | Type: int | +| `--kt-max-deferred-experts-per-token` | [ktransformers parameter] Maximum number of experts deferred to CPU per token. All MoE layers except the final one use this value; the final layer always uses 0. | `None` | Type: int | + +## Diffusion LLM + +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--dllm-algorithm` | The diffusion LLM algorithm, such as LowConfidence. | `None` | Type: str | +| `--dllm-algorithm-config` | The diffusion LLM algorithm configurations. Must be a YAML file. | `None` | Type: str | + +## Double Sparsity +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-double-sparsity` | Enable double sparsity attention | `False` | bool flag (set to enable) | +| `--ds-channel-config-path` | The path of the double sparsity channel config | `None` | Type: str | +| `--ds-heavy-channel-num` | The number of heavy channels in double sparsity attention | `32` | Type: int | +| `--ds-heavy-token-num` | The number of heavy tokens in double sparsity attention | `256` | Type: int | +| `--ds-heavy-channel-type` | The type of heavy channels in double sparsity attention | `qk` | Type: str | +| `--ds-sparse-decode-threshold` | The minimum decode sequence length required before the double-sparsity backend switches from the dense fallback to the sparse decode kernel. | `4096` | Type: int | + +## Offloading +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--cpu-offload-gb` | How many GBs of RAM to reserve for CPU offloading. | `0` | Type: int | +| `--offload-group-size` | Number of layers per group in offloading. | `-1` | Type: int | +| `--offload-num-in-group` | Number of layers to be offloaded within a group. | `1` | Type: int | +| `--offload-prefetch-step` | Steps to prefetch in offloading. | `1` | Type: int | +| `--offload-mode` | Mode of offloading. | `cpu` | Type: str | + +## Args for multi-item scoring +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--multi-item-scoring-delimiter` | Delimiter token ID for multi-item scoring. Used to combine Query and Items into a single sequence: QueryItem1Item2... This enables efficient batch processing of multiple items against a single query. | `None` | Type: int | + +## Optimization/debug options +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--disable-radix-cache` | Disable RadixAttention for prefix caching. | `False` | bool flag (set to enable) | +| `--cuda-graph-max-bs` | Set the maximum batch size for cuda graph. It will extend the cuda graph capture batch size to this value. | `None` | Type: int | +| `--cuda-graph-bs` | Set the list of batch sizes for cuda graph. | `None` | List[int] | +| `--disable-cuda-graph` | Disable cuda graph. | `False` | bool flag (set to enable) | +| `--disable-cuda-graph-padding` | Disable cuda graph when padding is needed. Still uses cuda graph when padding is not needed. | `False` | bool flag (set to enable) | +| `--enable-profile-cuda-graph` | Enable profiling of cuda graph capture. | `False` | bool flag (set to enable) | +| `--enable-cudagraph-gc` | Enable garbage collection during CUDA graph capture. If disabled (default), GC is frozen during capture to speed up the process. | `False` | bool flag (set to enable) | +| `--enable-layerwise-nvtx-marker` | Enable layerwise NVTX profiling annotations for the model. This adds NVTX markers to every layer for detailed per-layer performance analysis with Nsight Systems. | `False` | bool flag (set to enable) | +| `--enable-nccl-nvls` | Enable NCCL NVLS for prefill heavy requests when available. | `False` | bool flag (set to enable) | +| `--enable-symm-mem` | Enable NCCL symmetric memory for fast collectives. | `False` | bool flag (set to enable) | +| `--disable-flashinfer-cutlass-moe-fp4-allgather` | Disables quantize before all-gather for flashinfer cutlass moe. | `False` | bool flag (set to enable) | +| `--enable-tokenizer-batch-encode` | Enable batch tokenization for improved performance when processing multiple text inputs. Do not use with image inputs, pre-tokenized input_ids, or input_embeds. | `False` | bool flag (set to enable) | +| `--disable-tokenizer-batch-decode` | Disable batch decoding when decoding multiple completions. | `False` | bool flag (set to enable) | +| `--disable-outlines-disk-cache` | Disable disk cache of outlines to avoid possible crashes related to file system or high concurrency. | `False` | bool flag (set to enable) | +| `--disable-custom-all-reduce` | Disable the custom all-reduce kernel and fall back to NCCL. | `False` | bool flag (set to enable) | +| `--enable-mscclpp` | Enable using mscclpp for small messages for all-reduce kernel and fall back to NCCL. | `False` | bool flag (set to enable) | +| `--enable-torch-symm-mem` | Enable using torch symm mem for all-reduce kernel and fall back to NCCL. Only supports CUDA device SM90 and above. SM90 supports world size 4, 6, 8. SM10 supports world size 6, 8. | `False` | bool flag (set to enable) | +| `--disable-overlap-schedule` | Disable the overlap scheduler, which overlaps the CPU scheduler with GPU model worker. | `False` | bool flag (set to enable) | +| `--enable-mixed-chunk` | Enabling mixing prefill and decode in a batch when using chunked prefill. | `False` | bool flag (set to enable) | +| `--enable-dp-attention` | Enabling data parallelism for attention and tensor parallelism for FFN. The dp size should be equal to the tp size. Currently DeepSeek-V2 and Qwen 2/3 MoE models are supported. | `False` | bool flag (set to enable) | +| `--enable-dp-lm-head` | Enable vocabulary parallel across the attention TP group to avoid all-gather across DP groups, optimizing performance under DP attention. | `False` | bool flag (set to enable) | +| `--enable-two-batch-overlap` | Enabling two micro batches to overlap. | `False` | bool flag (set to enable) | +| `--enable-single-batch-overlap` | Let computation and communication overlap within one micro batch. | `False` | bool flag (set to enable) | +| `--tbo-token-distribution-threshold` | The threshold of token distribution between two batches in micro-batch-overlap, determines whether to two-batch-overlap or two-chunk-overlap. Set to 0 denote disable two-chunk-overlap. | `0.48` | Type: float | +| `--enable-torch-compile` | Optimize the model with torch.compile. Experimental feature. | `False` | bool flag (set to enable) | +| `--enable-torch-compile-debug-mode` | Enable debug mode for torch compile. | `False` | bool flag (set to enable) | +| `--disable-piecewise-cuda-graph` | Disable piecewise cuda graph for extend/prefill. PCG is enabled by default. | `False` | bool flag (set to disable) | +| `--enforce-piecewise-cuda-graph` | Enforce piecewise cuda graph, skipping all auto-disable conditions. For testing only. | `False` | bool flag (set to enable) | +| `--piecewise-cuda-graph-tokens` | Set the list of tokens when using piecewise cuda graph. | `None` | Type: JSON list | +| `--piecewise-cuda-graph-compiler` | Set the compiler for piecewise cuda graph. Choices are: eager, inductor. | `eager` | `eager`, `inductor` | +| `--torch-compile-max-bs` | Set the maximum batch size when using torch compile. | `32` | Type: int | +| `--piecewise-cuda-graph-max-tokens` | Set the maximum tokens when using piecewise cuda graph. | `4096` | Type: int | +| `--torchao-config` | Optimize the model with torchao. Experimental feature. Current choices are: int8dq, int8wo, int4wo-, fp8wo, fp8dq-per_tensor, fp8dq-per_row | `` | Type: str | +| `--enable-nan-detection` | Enable the NaN detection for debugging purposes. | `False` | bool flag (set to enable) | +| `--enable-p2p-check` | Enable P2P check for GPU access, otherwise the p2p access is allowed by default. | `False` | bool flag (set to enable) | +| `--triton-attention-reduce-in-fp32` | Cast the intermediate attention results to fp32 to avoid possible crashes related to fp16. This only affects Triton attention kernels. | `False` | bool flag (set to enable) | +| `--triton-attention-num-kv-splits` | The number of KV splits in flash decoding Triton kernel. Larger value is better in longer context scenarios. The default value is 8. | `8` | Type: int | +| `--triton-attention-split-tile-size` | The size of split KV tile in flash decoding Triton kernel. Used for deterministic inference. | `None` | Type: int | +| `--num-continuous-decode-steps` | Run multiple continuous decoding steps to reduce scheduling overhead. This can potentially increase throughput but may also increase time-to-first-token latency. The default value is 1, meaning only run one decoding step at a time. | `1` | Type: int | +| `--delete-ckpt-after-loading` | Delete the model checkpoint after loading the model. | `False` | bool flag (set to enable) | +| `--enable-memory-saver` | Allow saving memory using release_memory_occupation and resume_memory_occupation | `False` | bool flag (set to enable) | +| `--enable-weights-cpu-backup` | Save model weights to CPU memory during release_weights_occupation and resume_weights_occupation | `False` | bool flag (set to enable) | +| `--enable-draft-weights-cpu-backup` | Save draft model weights to CPU memory during release_weights_occupation and resume_weights_occupation | `False` | bool flag (set to enable) | +| `--allow-auto-truncate` | Allow automatically truncating requests that exceed the maximum input length instead of returning an error. | `False` | bool flag (set to enable) | +| `--enable-custom-logit-processor` | Enable users to pass custom logit processors to the server (disabled by default for security) | `False` | bool flag (set to enable) | +| `--flashinfer-mla-disable-ragged` | Not using ragged prefill wrapper when running flashinfer mla | `False` | bool flag (set to enable) | +| `--disable-shared-experts-fusion` | Disable shared experts fusion optimization for deepseek v3/r1. | `False` | bool flag (set to enable) | +| `--disable-chunked-prefix-cache` | Disable chunked prefix cache feature for deepseek, which should save overhead for short sequences. | `False` | bool flag (set to enable) | +| `--disable-fast-image-processor` | Adopt base image processor instead of fast image processor. | `False` | bool flag (set to enable) | +| `--keep-mm-feature-on-device` | Keep multimodal feature tensors on device after processing to save D2H copy. | `False` | bool flag (set to enable) | +| `--enable-return-hidden-states` | Enable returning hidden states with responses. | `False` | bool flag (set to enable) | +| `--enable-return-routed-experts` | Enable returning routed experts of each layer with responses. | `False` | bool flag (set to enable) | +| `--scheduler-recv-interval` | The interval to poll requests in scheduler. Can be set to >1 to reduce the overhead of this. | `1` | Type: int | +| `--numa-node` | Sets the numa node for the subprocesses. i-th element corresponds to i-th subprocess. | `None` | List[int] | +| `--enable-deterministic-inference` | Enable deterministic inference mode with batch invariant ops. | `False` | bool flag (set to enable) | +| `--rl-on-policy-target` | The training system that SGLang needs to match for true on-policy. | `None` | `fsdp` | +| `--enable-attn-tp-input-scattered` | Allow input of attention to be scattered when only using tensor parallelism, to reduce the computational load of operations such as qkv latent. | `False` | bool flag (set to enable) | +| `--enable-nsa-prefill-context-parallel` | Enable context parallelism used in the long sequence prefill phase of DeepSeek v3.2. | `False` | bool flag (set to enable) | +| `--nsa-prefill-cp-mode` | Token splitting mode for the prefill phase of DeepSeek v3.2 under context parallelism. Optional values: `round-robin-split`(default),`in-seq-split`. `round-robin-split` distributes tokens across ranks based on `token_idx % cp_size`. It supports multi-batch prefill, fused MoE, and FP8 KV cache. | `in-seq-split` | `in-seq-split`, `round-robin-split` | +| `--enable-fused-qk-norm-rope` | Enable fused qk normalization and rope rotary embedding. | `False` | bool flag (set to enable) | +| `--enable-precise-embedding-interpolation` | Enable corner alignment for resize of embeddings grid to ensure more accurate(but slower) evaluation of interpolated embedding values. | `False` | bool flag (set to enable) | + +## Dynamic batch tokenizer +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-dynamic-batch-tokenizer` | Enable async dynamic batch tokenizer for improved performance when multiple requests arrive concurrently. | `False` | bool flag (set to enable) | +| `--dynamic-batch-tokenizer-batch-size` | [Only used if --enable-dynamic-batch-tokenizer is set] Maximum batch size for dynamic batch tokenizer. | `32` | Type: int | +| `--dynamic-batch-tokenizer-batch-timeout` | [Only used if --enable-dynamic-batch-tokenizer is set] Timeout in seconds for batching tokenization requests. | `0.002` | Type: float | + +## Debug tensor dumps +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--debug-tensor-dump-output-folder` | The output folder for dumping tensors. | `None` | Type: str | +| `--debug-tensor-dump-layers` | The layer ids to dump. Dump all layers if not specified. | `None` | Type: JSON list | +| `--debug-tensor-dump-input-file` | The input filename for dumping tensors | `None` | Type: str | +| `--debug-tensor-dump-inject` | Inject the outputs from jax as the input of every layer. | `False` | Type: str | + +## PD disaggregation +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--disaggregation-mode` | Only used for PD disaggregation. "prefill" for prefill-only server, and "decode" for decode-only server. If not specified, it is not PD disaggregated | `null` | `null`, `prefill`, `decode` | +| `--disaggregation-transfer-backend` | The backend for disaggregation transfer. Default is mooncake. | `mooncake` | `mooncake`, `nixl`, `ascend`, `fake` | +| `--disaggregation-bootstrap-port` | Bootstrap server port on the prefill server. Default is 8998. | `8998` | Type: int | +| `--disaggregation-ib-device` | The InfiniBand devices for disaggregation transfer, accepts single device (e.g., --disaggregation-ib-device mlx5_0) or multiple comma-separated devices (e.g., --disaggregation-ib-device mlx5_0,mlx5_1). Default is None, which triggers automatic device detection when mooncake backend is enabled. | `None` | Type: str | +| `--disaggregation-decode-enable-offload-kvcache` | Enable async KV cache offloading on decode server (PD mode). | `False` | bool flag (set to enable) | +| `--num-reserved-decode-tokens` | Number of decode tokens that will have memory reserved when adding new request to the running batch. | `512` | Type: int | +| `--disaggregation-decode-polling-interval` | The interval to poll requests in decode server. Can be set to >1 to reduce the overhead of this. | `1` | Type: int | + +## Encode prefill disaggregation +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--encoder-only` | For MLLM with an encoder, launch an encoder-only server | `False` | bool flag (set to enable) | +| `--language-only` | For VLM, load weights for the language model only. | `False` | bool flag (set to enable) | +| `--encoder-transfer-backend` | The backend for encoder disaggregation transfer. Default is zmq_to_scheduler. | `zmq_to_scheduler` | `zmq_to_scheduler`, `zmq_to_tokenizer`, `mooncake` | +| `--encoder-urls` | List of encoder server urls. | `[]` | Type: JSON list | + +## Custom weight loader +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--custom-weight-loader` | The custom dataloader which used to update the model. Should be set with a valid import path, such as my_package.weight_load_func | `None` | List[str] | +| `--weight-loader-disable-mmap` | Disable mmap while loading weight using safetensors. | `False` | bool flag (set to enable) | +| `--remote-instance-weight-loader-seed-instance-ip` | The ip of the seed instance for loading weights from remote instance. | `None` | Type: str | +| `--remote-instance-weight-loader-seed-instance-service-port` | The service port of the seed instance for loading weights from remote instance. | `None` | Type: int | +| `--remote-instance-weight-loader-send-weights-group-ports` | The communication group ports for loading weights from remote instance. | `None` | Type: JSON list | +| `--remote-instance-weight-loader-backend` | The backend for loading weights from remote instance. Can be 'transfer_engine' or 'nccl'. Default is 'nccl'. | `nccl` | `transfer_engine`, `nccl` | +| `--remote-instance-weight-loader-start-seed-via-transfer-engine` | Start seed server via transfer engine backend for remote instance weight loader. | `False` | bool flag (set to enable) | + +## For PD-Multiplexing +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-pdmux` | Enable PD-Multiplexing, PD running on greenctx stream. | `False` | bool flag (set to enable) | +| `--pdmux-config-path` | The path of the PD-Multiplexing config file. | `None` | Type: str | +| `--sm-group-num` | Number of sm partition groups. | `8` | Type: int | + +## Configuration file support +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--config` | Read CLI options from a config file. Must be a YAML file with configuration options. | `None` | Type: str | + +## For Multi-Modal +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--mm-max-concurrent-calls` | The max concurrent calls for async mm data processing. | `32` | Type: int | +| `--mm-per-request-timeout` | The timeout for each multi-modal request in seconds. | `10.0` | Type: int | +| `--enable-broadcast-mm-inputs-process` | Enable broadcast mm-inputs process in scheduler. | `False` | bool flag (set to enable) | +| `--mm-process-config` | Multimodal preprocessing config, a json config contains keys: `image`, `video`, `audio`. | `{}` | Type: JSON / Dict | +| `--mm-enable-dp-encoder` | Enabling data parallelism for mm encoder. The dp size will be set to the tp size automatically. | `False` | bool flag (set to enable) | +| `--limit-mm-data-per-request` | Limit the number of multimodal inputs per request. e.g. '{"image": 1, "video": 1, "audio": 1}' | `None` | Type: JSON / Dict | + +## For checkpoint decryption +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--decrypted-config-file` | The path of the decrypted config file. | `None` | Type: str | +| `--decrypted-draft-config-file` | The path of the decrypted draft config file. | `None` | Type: str | +| `--enable-prefix-mm-cache` | Enable prefix multimodal cache. Currently only supports mm-only. | `False` | bool flag (set to enable) | + +## Forward hooks +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--forward-hooks` | JSON-formatted list of forward hook specifications. Each element must include `target_modules` (list of glob patterns matched against `model.named_modules()` names) and `hook_factory` (Python import path to a factory, e.g. `my_package.hooks:make_hook`). An optional `name` field is used for logging, and an optional `config` object is passed as a `dict` to the factory. | `None` | Type: JSON list | + +## Deprecated arguments +| Argument | Description | Defaults | Options | +| --- | --- | --- | --- | +| `--enable-ep-moe` | NOTE: --enable-ep-moe is deprecated. Please set `--ep-size` to the same value as `--tp-size` instead. | `None` | N/A | +| `--enable-deepep-moe` | NOTE: --enable-deepep-moe is deprecated. Please set `--moe-a2a-backend` to 'deepep' instead. | `None` | N/A | +| `--prefill-round-robin-balance` | Note: Note: --prefill-round-robin-balance is deprecated now. | `None` | N/A | +| `--enable-flashinfer-cutlass-moe` | NOTE: --enable-flashinfer-cutlass-moe is deprecated. Please set `--moe-runner-backend` to 'flashinfer_cutlass' instead. | `None` | N/A | +| `--enable-flashinfer-cutedsl-moe` | NOTE: --enable-flashinfer-cutedsl-moe is deprecated. Please set `--moe-runner-backend` to 'flashinfer_cutedsl' instead. | `None` | N/A | +| `--enable-flashinfer-trtllm-moe` | NOTE: --enable-flashinfer-trtllm-moe is deprecated. Please set `--moe-runner-backend` to 'flashinfer_trtllm' instead. | `None` | N/A | +| `--enable-triton-kernel-moe` | NOTE: --enable-triton-kernel-moe is deprecated. Please set `--moe-runner-backend` to 'triton_kernel' instead. | `None` | N/A | +| `--enable-flashinfer-mxfp4-moe` | NOTE: --enable-flashinfer-mxfp4-moe is deprecated. Please set `--moe-runner-backend` to 'flashinfer_mxfp4' instead. | `None` | N/A | +| `--crash-on-nan` | Crash the server on nan logprobs. | `False` | Type: str | +| `--hybrid-kvcache-ratio` | Mix ratio in [0,1] between uniform and hybrid kv buffers (0.0 = pure uniform: swa_size / full_size = 1)(1.0 = pure hybrid: swa_size / full_size = local_attention_size / context_length) | `None` | Optional[float] | +| `--load-watch-interval` | The interval of load watching in seconds. | `0.1` | Type: float | +| `--nsa-prefill` | Choose the NSA backend for the prefill stage (overrides `--attention-backend` when running DeepSeek NSA-style attention). | `flashmla_sparse` | `flashmla_sparse`, `flashmla_decode`, `fa3`, `tilelang`, `aiter` | +| `--nsa-decode` | Choose the NSA backend for the decode stage when running DeepSeek NSA-style attention. Overrides `--attention-backend` for decoding. | `flashmla_kv` | `flashmla_prefill`, `flashmla_kv`, `fa3`, `tilelang`, `aiter` | diff --git a/sglang/docs/advanced_features/sgl_model_gateway.md b/sglang/docs/advanced_features/sgl_model_gateway.md new file mode 100644 index 0000000000000000000000000000000000000000..753743b0b0bb2c257cacd7d857c3de5d389894b1 --- /dev/null +++ b/sglang/docs/advanced_features/sgl_model_gateway.md @@ -0,0 +1,1725 @@ +# SGLang Model Gateway + +SGLang Model Gateway is a high-performance model-routing gateway for large-scale LLM deployments. It centralizes worker lifecycle management, balances traffic across heterogeneous protocols (HTTP, gRPC, OpenAI-compatible), and provides enterprise-ready control over history storage, MCP tooling, and privacy-sensitive workflows. The gateway is deeply optimized for the SGLang serving runtime, but can route to any OpenAI-compatible backend. + +--- + +## Table of Contents + +1. [Overview](#overview) +2. [Architecture](#architecture) + - [Control Plane](#control-plane) + - [Data Plane](#data-plane) + - [Storage and Privacy](#storage-and-privacy) +3. [Installation](#installation) +4. [Quick Start](#quick-start) +5. [Deployment Modes](#deployment-modes) + - [Co-launch Router and Workers](#co-launch-router-and-workers) + - [Separate Launch (HTTP)](#separate-launch-http) + - [gRPC Launch](#grpc-launch) + - [Prefill-Decode Disaggregation](#prefill-decode-disaggregation) + - [OpenAI Backend Proxy](#openai-backend-proxy) + - [Multi-Model Inference Gateway](#multi-model-inference-gateway) +6. [API Reference](#api-reference) + - [Inference Endpoints](#inference-endpoints) + - [Tokenization Endpoints](#tokenization-endpoints) + - [Parser Endpoints](#parser-endpoints) + - [Classification API](#classification-api) + - [Conversation and Response APIs](#conversation-and-response-apis) + - [Worker Management APIs](#worker-management-apis) + - [Admin and Health Endpoints](#admin-and-health-endpoints) +7. [Load Balancing Policies](#load-balancing-policies) +8. [Reliability and Flow Control](#reliability-and-flow-control) + - [Retries](#retries) + - [Circuit Breaker](#circuit-breaker) + - [Rate Limiting and Queuing](#rate-limiting-and-queuing) + - [Health Checks](#health-checks) +9. [Reasoning Parser Integration](#reasoning-parser-integration) +10. [Tool Call Parsing](#tool-call-parsing) +11. [Tokenizer Management](#tokenizer-management) +12. [MCP Integration](#mcp-integration) +13. [Service Discovery (Kubernetes)](#service-discovery-kubernetes) +14. [History and Data Connectors](#history-and-data-connectors) +15. [WASM Middleware](#wasm-middleware) +16. [Language Bindings](#language-bindings) +17. [Security and Authentication](#security-and-authentication) + - [TLS (HTTPS) for Gateway Server](#tls-https-for-gateway-server) + - [mTLS for Worker Communication](#mtls-for-worker-communication) +18. [Observability](#observability) + - [Prometheus Metrics](#prometheus-metrics) + - [OpenTelemetry Tracing](#opentelemetry-tracing) + - [Logging](#logging) +19. [Production Recommendations](#production-recommendations) + - [Security Best Practices](#security-best-practices) + - [High Availability](#high-availability) + - [Performance](#performance) + - [Kubernetes Deployment](#kubernetes-deployment) + - [Monitoring with PromQL](#monitoring-with-promql) +20. [Configuration Reference](#configuration-reference) +21. [Troubleshooting](#troubleshooting) + +--- + +## Overview + +- **Unified control plane** for registering, monitoring, and orchestrating regular, prefill, and decode workers across heterogeneous model fleets. +- **Multi-protocol data plane** that routes traffic across HTTP, PD (prefill/decode), gRPC, and OpenAI-compatible backends with shared reliability primitives. +- **Industry-first gRPC pipeline** with native Rust tokenization, reasoning parsers, and tool-call execution for high-throughput, OpenAI-compatible serving; supports both single-stage and PD topologies. +- **Inference Gateway Mode (`--enable-igw`)** dynamically instantiates multiple router stacks (HTTP regular/PD, gRPC) and applies per-model policies for multi-tenant deployments. +- **Conversation & responses connectors** centralize chat history inside the router so the same context can be reused across models and MCP loops without leaking data to upstream vendors (memory, none, Oracle ATP, PostgreSQL). +- **Enterprise privacy**: agentic multi-turn `/v1/responses`, native MCP client (STDIO/HTTP/SSE/Streamable), and history storage all operate within the router boundary. +- **Reliability core**: retries with jitter, worker-scoped circuit breakers, token-bucket rate limiting with queuing, background health checks, and cache-aware load monitoring. +- **Comprehensive observability**: 40+ Prometheus metrics, OpenTelemetry distributed tracing, structured logging, and request ID propagation. + +--- + +## Architecture + +### Control Plane + +- **Worker Manager** discovers capabilities (`/get_server_info`, `/get_model_info`), tracks load, and registers/removes workers in the shared registry. +- **Job Queue** serializes add/remove requests and exposes status (`/workers/{worker_id}`) so clients can track onboarding progress. +- **Load Monitor** feeds cache-aware and power-of-two policies with live worker load statistics. +- **Health Checker** continuously probes workers and updates readiness, circuit breaker state, and router metrics. +- **Tokenizer Registry** manages dynamically registered tokenizers with async loading from HuggingFace or local paths. + +### Data Plane + +- **HTTP routers** (regular & PD) implement `/generate`, `/v1/chat/completions`, `/v1/completions`, `/v1/responses`, `/v1/embeddings`, `/v1/rerank`, `/v1/classify`, `/v1/tokenize`, `/v1/detokenize`, and associated admin endpoints. +- **gRPC router** streams tokenized requests directly to SRT gRPC workers, running fully in Rust—tokenizer, reasoning parser, and tool parser all reside in-process. Supports both single-stage and PD routing, including embeddings and classification. +- **OpenAI router** proxies OpenAI-compatible endpoints to external vendors (OpenAI, xAI, etc.) while keeping chat history and multi-turn orchestration local. + +### Storage and Privacy + +- Conversation and response history is stored at the router tier (memory, none, Oracle ATP, or PostgreSQL). The same history can power multiple models or MCP loops without sending data to upstream vendors. +- `/v1/responses` agentic flows, MCP sessions, and conversation APIs share the same storage layer, enabling compliance for regulated workloads. + +--- + +## Installation + +### Docker + +Pre-built Docker images are available on Docker Hub with multi-architecture support (x86_64 and ARM64): + +```bash +docker pull lmsysorg/sgl-model-gateway:latest +``` + +### Prerequisites + +- **Rust and Cargo** + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + source "$HOME/.cargo/env" + rustc --version + cargo --version + ``` +- **Python** with `pip` and virtualenv tooling available. + +### Rust Binary + +```bash +cd sgl-model-gateway +cargo build --release +``` + +### Python Package + +```bash +pip install maturin + +# Fast development mode +cd sgl-model-gateway/bindings/python +maturin develop + +# Production build +maturin build --release --out dist --features vendored-openssl +pip install --force-reinstall dist/*.whl +``` + +--- + +## Quick Start + +### Regular HTTP Routing + +```bash +# Rust binary +./target/release/sgl-model-gateway \ + --worker-urls http://worker1:8000 http://worker2:8000 \ + --policy cache_aware + +# Python launcher +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8000 \ + --policy cache_aware +``` + +### gRPC Routing + +```bash +python -m sglang_router.launch_router \ + --worker-urls grpc://127.0.0.1:20000 \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --reasoning-parser deepseek-r1 \ + --tool-call-parser json \ + --host 0.0.0.0 --port 8080 +``` + +--- + +## Deployment Modes + +### Co-launch Router and Workers + +Launch the router and a fleet of SGLang workers in one process: + +```bash +python -m sglang_router.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --dp-size 4 \ + --host 0.0.0.0 \ + --port 30000 +``` + +Comprehensive example with router arguments (prefixed with `--router-`): + +```bash +python -m sglang_router.launch_server \ + --host 0.0.0.0 \ + --port 8080 \ + --model meta-llama/Llama-3.1-8B-Instruct \ + --tp-size 1 \ + --dp-size 8 \ + --grpc-mode \ + --log-level debug \ + --router-prometheus-port 10001 \ + --router-tool-call-parser llama \ + --router-model-path meta-llama/Llama-3.1-8B-Instruct \ + --router-policy round_robin \ + --router-log-level debug +``` + +### Separate Launch (HTTP) + +Run workers independently and point the router at their HTTP endpoints: + +```bash +# Worker nodes +python -m sglang.launch_server --model meta-llama/Meta-Llama-3.1-8B-Instruct --port 8000 +python -m sglang.launch_server --model meta-llama/Meta-Llama-3.1-8B-Instruct --port 8001 + +# Router node +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8001 \ + --policy cache_aware \ + --host 0.0.0.0 --port 30000 +``` + +### gRPC Launch + +Use SRT gRPC workers to unlock the highest throughput and access native reasoning/tool pipelines: + +```bash +# Workers expose gRPC endpoints +python -m sglang.launch_server \ + --model meta-llama/Llama-3.1-8B-Instruct \ + --grpc-mode \ + --port 20000 + +# Router +python -m sglang_router.launch_router \ + --worker-urls grpc://127.0.0.1:20000 \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --reasoning-parser deepseek-r1 \ + --tool-call-parser json \ + --host 0.0.0.0 --port 8080 +``` + +The gRPC router supports both regular HTTP-equivalent serving and PD (prefill/decode) serving. Provide `--tokenizer-path` or `--model-path` (HuggingFace ID or local directory) whenever connection mode resolves to gRPC. + +### Prefill-Decode Disaggregation + +Split prefill and decode workers for PD-aware caching and balancing: + +```bash +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --prefill http://prefill1:30001 9001 \ + --decode http://decode1:30011 \ + --prefill-policy cache_aware \ + --decode-policy power_of_two +``` + +Prefill entries accept an optional bootstrap port. PD mode merges prefill metadata with decode outputs and streams results back to the client. + +### OpenAI Backend Proxy + +Proxy OpenAI-compatible endpoints while keeping history and MCP sessions local: + +```bash +python -m sglang_router.launch_router \ + --backend openai \ + --worker-urls https://api.openai.com \ + --history-backend memory +``` + +OpenAI backend mode expects exactly one `--worker-urls` entry per router instance. + +### Multi-Model Inference Gateway + +Enable IGW mode to route multiple models through a single router: + +```bash +./target/release/sgl-model-gateway \ + --enable-igw \ + --policy cache_aware \ + --max-concurrent-requests 512 + +# Register workers dynamically +curl -X POST http://localhost:30000/workers \ + -H "Content-Type: application/json" \ + -d '{ + "url": "http://worker-a:8000", + "model_id": "mistral", + "priority": 10, + "labels": {"tier": "gold"} + }' +``` + +--- + +## API Reference + +### Inference Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/generate` | SGLang generate API | +| `POST` | `/v1/chat/completions` | OpenAI-compatible chat completions (streaming/tool calls) | +| `POST` | `/v1/completions` | OpenAI-compatible text completions | +| `POST` | `/v1/embeddings` | Embedding generation (HTTP and gRPC) | +| `POST` | `/v1/rerank`, `/rerank` | Reranking requests | +| `POST` | `/v1/classify` | Text classification | + +### Tokenization Endpoints + +The gateway provides HTTP endpoints for text tokenization with batch support, designed to mirror the SGLang Python tokenization API. + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/v1/tokenize` | Tokenize text to token IDs (single or batch) | +| `POST` | `/v1/detokenize` | Convert token IDs back to text (single or batch) | +| `POST` | `/v1/tokenizers` | Register a new tokenizer (async, returns job status) | +| `GET` | `/v1/tokenizers` | List all registered tokenizers | +| `GET` | `/v1/tokenizers/{id}` | Get tokenizer info by UUID | +| `GET` | `/v1/tokenizers/{id}/status` | Check async tokenizer loading status | +| `DELETE` | `/v1/tokenizers/{id}` | Remove a tokenizer from the registry | + +#### Tokenize Request + +```json +{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "prompt": "Hello, world!" +} +``` + +#### Batch Tokenize Request + +```json +{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "prompt": ["Hello", "World", "How are you?"] +} +``` + +#### Tokenize Response + +```json +{ + "tokens": [15339, 11, 1917, 0], + "count": 4, + "char_count": 13 +} +``` + +#### Detokenize Request + +```json +{ + "model": "meta-llama/Llama-3.1-8B-Instruct", + "tokens": [15339, 11, 1917, 0], + "skip_special_tokens": true +} +``` + +#### Detokenize Response + +```json +{ + "text": "Hello, world!" +} +``` + +#### Add Tokenizer (Async) + +```bash +curl -X POST http://localhost:30000/v1/tokenizers \ + -H "Content-Type: application/json" \ + -d '{"name": "llama3", "source": "meta-llama/Llama-3.1-8B-Instruct"}' +``` + +Response: +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "status": "pending", + "message": "Tokenizer registration queued" +} +``` + +Check status: +```bash +curl http://localhost:30000/v1/tokenizers/550e8400-e29b-41d4-a716-446655440000/status +``` + +### Parser Endpoints + +The gateway provides admin endpoints for parsing reasoning content and function calls from LLM outputs. + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/parse/reasoning` | Separate reasoning (``) from normal text | +| `POST` | `/parse/function_call` | Parse function/tool calls from text | + +#### Separate Reasoning Request + +```json +{ + "text": "Let me analyze this step by step...The answer is 42.", + "parser": "deepseek-r1" +} +``` + +#### Response + +```json +{ + "normal_text": "The answer is 42.", + "reasoning_text": "Let me analyze this step by step..." +} +``` + +#### Function Call Parsing + +```json +{ + "text": "{\"name\": \"get_weather\", \"arguments\": {\"city\": \"NYC\"}}", + "parser": "json" +} +``` + +### Classification API + +The `/v1/classify` endpoint provides text classification using sequence classification models (e.g., `Qwen2ForSequenceClassification`, `BertForSequenceClassification`). + +#### Request + +```bash +curl http://localhost:30000/v1/classify \ + -H "Content-Type: application/json" \ + -d '{ + "model": "jason9693/Qwen2.5-1.5B-apeach", + "input": "I love this product!" + }' +``` + +#### Response + +```json +{ + "id": "classify-a1b2c3d4-5678-90ab-cdef-1234567890ab", + "object": "list", + "created": 1767034308, + "model": "jason9693/Qwen2.5-1.5B-apeach", + "data": [ + { + "index": 0, + "label": "positive", + "probs": [0.12, 0.88], + "num_classes": 2 + } + ], + "usage": { + "prompt_tokens": 6, + "completion_tokens": 0, + "total_tokens": 6 + } +} +``` + +#### Response Fields + +| Field | Description | +|-------|-------------| +| `label` | Predicted class label (from model's `id2label` config, or `LABEL_N` fallback) | +| `probs` | Probability distribution over all classes (softmax of logits) | +| `num_classes` | Number of classification classes | + +#### Notes + +- Classification reuses the embedding backend—the scheduler returns logits which are converted to probabilities via softmax +- Labels come from the model's HuggingFace config (`id2label` field); models without this mapping use generic labels (`LABEL_0`, `LABEL_1`, etc.) +- Both HTTP and gRPC routers support classification + +### Conversation and Response APIs + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/v1/responses` | Create background responses (agentic loops) | +| `GET` | `/v1/responses/{id}` | Retrieve stored response | +| `POST` | `/v1/responses/{id}/cancel` | Cancel background response | +| `DELETE` | `/v1/responses/{id}` | Delete response | +| `GET` | `/v1/responses/{id}/input_items` | List response input items | +| `POST` | `/v1/conversations` | Create conversation | +| `GET` | `/v1/conversations/{id}` | Get conversation | +| `POST` | `/v1/conversations/{id}` | Update conversation | +| `DELETE` | `/v1/conversations/{id}` | Delete conversation | +| `GET` | `/v1/conversations/{id}/items` | List conversation items | +| `POST` | `/v1/conversations/{id}/items` | Add items to conversation | +| `GET` | `/v1/conversations/{id}/items/{item_id}` | Get conversation item | +| `DELETE` | `/v1/conversations/{id}/items/{item_id}` | Delete conversation item | + +### Worker Management APIs + +| Method | Path | Description | +|--------|------|-------------| +| `POST` | `/workers` | Queue worker registration (returns 202 Accepted) | +| `GET` | `/workers` | List workers with health, load, and policy metadata | +| `GET` | `/workers/{worker_id}` | Inspect specific worker or job queue entry | +| `PUT` | `/workers/{worker_id}` | Queue worker update | +| `DELETE` | `/workers/{worker_id}` | Queue worker removal | + +#### Add Worker + +```bash +curl -X POST http://localhost:30000/workers \ + -H "Content-Type: application/json" \ + -d '{"url":"grpc://0.0.0.0:31000","worker_type":"regular"}' +``` + +#### List Workers + +```bash +curl http://localhost:30000/workers +``` + +Response: +```json +{ + "workers": [ + { + "id": "2f3a0c3e-3a7b-4c3f-8c70-1b7d4c3a6e1f", + "url": "http://0.0.0.0:31378", + "model_id": "mistral", + "priority": 50, + "cost": 1.0, + "worker_type": "regular", + "is_healthy": true, + "load": 0, + "connection_mode": "Http" + } + ], + "total": 1, + "stats": { + "prefill_count": 0, + "decode_count": 0, + "regular_count": 1 + } +} +``` + +### Admin and Health Endpoints + +| Method | Path | Description | +|--------|------|-------------| +| `GET` | `/liveness` | Health check (always returns OK) | +| `GET` | `/readiness` | Readiness check (checks healthy worker availability) | +| `GET` | `/health` | Alias for liveness | +| `GET` | `/health_generate` | Health generate test | +| `GET` | `/engine_metrics` | Engine-level metrics from workers | +| `GET` | `/v1/models` | List available models | +| `GET` | `/get_model_info` | Get model information | +| `GET` | `/get_server_info` | Get server information | +| `POST` | `/flush_cache` | Clear all caches | +| `GET` | `/get_loads` | Get all worker loads | +| `POST` | `/wasm` | Upload WASM module | +| `GET` | `/wasm` | List WASM modules | +| `DELETE` | `/wasm/{module_uuid}` | Remove WASM module | + +--- + +## Load Balancing Policies + +| Policy | Description | Usage | +|--------|-------------|-------| +| `random` | Uniform random selection | `--policy random` | +| `round_robin` | Cycles through workers in order | `--policy round_robin` | +| `power_of_two` | Samples two workers and picks the lighter one | `--policy power_of_two` | +| `cache_aware` | Combines cache locality with load balancing (default) | `--policy cache_aware` | +| `bucket` | Divides workers into load buckets with dynamic boundaries | `--policy bucket` | + +### Cache-Aware Policy Tuning + +```bash +--cache-threshold 0.5 \ +--balance-abs-threshold 32 \ +--balance-rel-threshold 1.5 \ +--eviction-interval-secs 120 \ +--max-tree-size 67108864 +``` + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `--cache-threshold` | 0.3 | Minimum prefix match ratio for cache hit | +| `--balance-abs-threshold` | 64 | Absolute load difference before rebalancing | +| `--balance-rel-threshold` | 1.5 | Relative load ratio before rebalancing | +| `--eviction-interval-secs` | 120 | Cache eviction cadence in seconds | +| `--max-tree-size` | 67108864 | Maximum nodes in cache tree | + +--- + +## Reliability and Flow Control + +### Retries + +Configure exponential backoff retries: + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8001 \ + --retry-max-retries 5 \ + --retry-initial-backoff-ms 50 \ + --retry-max-backoff-ms 30000 \ + --retry-backoff-multiplier 1.5 \ + --retry-jitter-factor 0.2 +``` + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `--retry-max-retries` | 5 | Maximum retry attempts | +| `--retry-initial-backoff-ms` | 50 | Initial backoff duration (ms) | +| `--retry-max-backoff-ms` | 5000 | Maximum backoff duration (ms) | +| `--retry-backoff-multiplier` | 2.0 | Exponential backoff multiplier | +| `--retry-jitter-factor` | 0.1 | Random jitter factor (0.0-1.0) | +| `--disable-retries` | false | Disable retries entirely | + +**Retryable Status Codes:** 408, 429, 500, 502, 503, 504 + +### Circuit Breaker + +Per-worker circuit breakers prevent cascading failures: + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8001 \ + --cb-failure-threshold 5 \ + --cb-success-threshold 2 \ + --cb-timeout-duration-secs 30 \ + --cb-window-duration-secs 60 +``` + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `--cb-failure-threshold` | 5 | Consecutive failures to open circuit | +| `--cb-success-threshold` | 2 | Successes to close from half-open | +| `--cb-timeout-duration-secs` | 30 | Time before half-open attempt | +| `--cb-window-duration-secs` | 60 | Failure counting window | +| `--disable-circuit-breaker` | false | Disable circuit breaker | + +**Circuit Breaker States:** +- **Closed**: Normal operation, requests allowed +- **Open**: Failing, requests rejected immediately +- **Half-Open**: Testing recovery, limited requests allowed + +### Rate Limiting and Queuing + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 http://worker2:8001 \ + --max-concurrent-requests 256 \ + --rate-limit-tokens-per-second 512 \ + --queue-size 128 \ + --queue-timeout-secs 30 +``` + +Requests beyond the concurrency limit wait in a FIFO queue. Returns: +- `429 Too Many Requests` when queue is full +- `408 Request Timeout` when queue timeout expires + +### Health Checks + +```bash +--health-check-interval-secs 30 \ +--health-check-timeout-secs 10 \ +--health-success-threshold 2 \ +--health-failure-threshold 3 \ +--health-check-endpoint /health +``` + +--- + +## Reasoning Parser Integration + +The gateway includes built-in reasoning parsers for models that use Chain-of-Thought (CoT) reasoning with explicit thinking blocks. + +### Supported Parsers + +| Parser ID | Model Family | Think Tokens | +|-----------|--------------|--------------| +| `deepseek-r1` | DeepSeek-R1 | `...` (initial reasoning) | +| `qwen3` | Qwen-3 | `...` | +| `qwen3-thinking` | Qwen-3 Thinking | `...` (initial reasoning) | +| `kimi` | Kimi K2 | Unicode think tokens | +| `glm45` | GLM-4.5/4.6/4.7 | `...` | +| `step3` | Step-3 | `...` | +| `minimax` | MiniMax | `...` | + +### Usage + +```bash +python -m sglang_router.launch_router \ + --worker-urls grpc://127.0.0.1:20000 \ + --model-path deepseek-ai/DeepSeek-R1 \ + --reasoning-parser deepseek-r1 +``` + +The gRPC router automatically: +1. Detects reasoning blocks in streaming output +2. Separates reasoning content from normal text +3. Applies incremental streaming parsing with buffer management +4. Handles partial token detection for correct streaming behavior + +--- + +## Tool Call Parsing + +The gateway supports parsing function/tool calls from LLM outputs in multiple formats. + +### Supported Formats + +| Parser | Format | Description | +|--------|--------|-------------| +| `json` | JSON | Standard JSON tool calls | +| `python` | Pythonic | Python function call syntax | +| `xml` | XML | XML-formatted tool calls | + +### Usage + +```bash +python -m sglang_router.launch_router \ + --worker-urls grpc://127.0.0.1:20000 \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --tool-call-parser json +``` + +--- + +## Tokenizer Management + +### Tokenizer Sources + +The gateway supports multiple tokenizer backends: +- **HuggingFace**: Load from HuggingFace Hub by model ID +- **Local**: Load from local `tokenizer.json` or directory +- **Tiktoken**: Auto-detect OpenAI GPT models (gpt-4, davinci, etc.) + +### Configuration + +```bash +# HuggingFace model +--model-path meta-llama/Llama-3.1-8B-Instruct + +# Local tokenizer +--tokenizer-path /path/to/tokenizer.json + +# With chat template override +--chat-template /path/to/template.jinja +``` + +### Tokenizer Caching + +Two-level caching for optimal performance: + +| Cache | Type | Description | +|-------|------|-------------| +| L0 | Exact match | Whole-string caching for repeated prompts | +| L1 | Prefix match | Prefix boundary matching for incremental prompts | + +```bash +--enable-l0-cache \ +--l0-max-entries 10000 \ +--enable-l1-cache \ +--l1-max-memory 52428800 # 50MB +``` + +--- + +## MCP Integration + +The gateway provides native Model Context Protocol (MCP) client integration for tool execution. + +### Supported Transports + +| Transport | Description | +|-----------|-------------| +| STDIO | Local process execution | +| SSE | Server-Sent Events (HTTP) | +| Streamable | Bidirectional streaming | + +### Configuration + +```bash +python -m sglang_router.launch_router \ + --mcp-config-path /path/to/mcp-config.yaml \ + --worker-urls http://worker1:8000 +``` + +### MCP Configuration File + +```yaml +servers: + - name: "filesystem" + command: "npx" + args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] + protocol: "stdio" + required: false + + - name: "github" + url: "https://api.github.com/mcp" + token: "ghp_xxxxx" + protocol: "sse" + required: false + + - name: "custom-tools" + url: "https://tools.example.com/mcp" + protocol: "streamable" + required: true + +pool: + max_connections: 100 + idle_timeout: 300 + +proxy: + http: "http://proxy.internal:8080" + https: "https://proxy.internal:8443" + no_proxy: "localhost,127.0.0.1,*.internal" + +inventory: + enable_refresh: true + tool_ttl: 300 + refresh_interval: 300 +``` + +--- + +## Service Discovery (Kubernetes) + +Enable automatic worker discovery via Kubernetes pod selectors: + +```bash +python -m sglang_router.launch_router \ + --service-discovery \ + --selector app=sglang-worker role=inference \ + --service-discovery-namespace production \ + --service-discovery-port 8000 +``` + +### PD Mode Discovery + +```bash +--pd-disaggregation \ +--prefill-selector app=sglang component=prefill \ +--decode-selector app=sglang component=decode \ +--service-discovery +``` + +Prefill pods can expose bootstrap ports via the `sglang.ai/bootstrap-port` annotation. RBAC must allow `get`, `list`, and `watch` on pods. + +--- + +## History and Data Connectors + +| Backend | Description | Usage | +|---------|-------------|-------| +| `memory` | In-memory storage (default) | `--history-backend memory` | +| `none` | No persistence | `--history-backend none` | +| `oracle` | Oracle Autonomous Database | `--history-backend oracle` | +| `postgres` | PostgreSQL Database | `--history-backend postgres` | +| `redis` | Redis | `--history-backend redis` | + +### Oracle Configuration + +```bash +# Connection descriptor +export ATP_DSN="(description=(address=(protocol=tcps)(port=1522)(host=adb.region.oraclecloud.com))(connect_data=(service_name=service_name)))" + +# Or TNS alias (requires wallet) +export ATP_TNS_ALIAS="sglroutertestatp_high" +export ATP_WALLET_PATH="/path/to/wallet" + +# Credentials +export ATP_USER="admin" +export ATP_PASSWORD="secret" +export ATP_POOL_MIN=4 +export ATP_POOL_MAX=32 + +python -m sglang_router.launch_router \ + --backend openai \ + --worker-urls https://api.openai.com \ + --history-backend oracle +``` + +### PostgreSQL Configuration + +```bash +export POSTGRES_DB_URL="postgres://user:password@host:5432/dbname" + +python -m sglang_router.launch_router \ + --backend openai \ + --worker-urls https://api.openai.com \ + --history-backend postgres +``` + +### Redis Configuration + +```bash +export REDIS_URL="redis://localhost:6379" +export REDIS_POOL_MAX=16 +export REDIS_RETENTION_DAYS=30 + +python -m sglang_router.launch_router \ + --backend openai \ + --worker-urls https://api.openai.com \ + --history-backend redis \ + --redis-retention-days 30 +``` + +Use `--redis-retention-days -1` for persistent storage (default is 30 days). + +--- + +## WASM Middleware + +The gateway supports WebAssembly (WASM) middleware modules for custom request/response processing. This enables organization-specific logic for authentication, rate limiting, billing, logging, and more—without modifying or recompiling the gateway. + +### Overview + +WASM middleware runs in a sandboxed environment with memory isolation, no network/filesystem access, and configurable resource limits. + +| Attach Point | When Executed | Use Cases | +|--------------|---------------|-----------| +| `OnRequest` | Before forwarding to workers | Auth, rate limiting, request modification | +| `OnResponse` | After receiving worker response | Logging, response modification, error handling | + +| Action | Description | +|--------|-------------| +| `Continue` | Proceed without modification | +| `Reject(status)` | Reject request with HTTP status code | +| `Modify(...)` | Modify headers, body, or status | + +### Examples + +Complete working examples are available in `examples/wasm/`: + +| Example | Description | +|---------|-------------| +| `auth/` | API key authentication for protected routes | +| `rate_limit/` | Per-client rate limiting (requests/minute) | +| `logging/` | Request tracking headers and response modification | + +The interface definition is located at `src/wasm/interface`. + +### Building Modules + +```bash +# Prerequisites +rustup target add wasm32-wasip2 +cargo install wasm-tools + +# Build +cargo build --target wasm32-wasip2 --release + +# Convert to component format +wasm-tools component new \ + target/wasm32-wasip2/release/my_middleware.wasm \ + -o my_middleware.component.wasm +``` + +### Deploying Modules + +```bash +# Enable WASM support +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 \ + --enable-wasm + +# Upload module +curl -X POST http://localhost:30000/wasm \ + -H "Content-Type: application/json" \ + -d '{ + "modules": [{ + "name": "auth-middleware", + "file_path": "/absolute/path/to/auth.component.wasm", + "module_type": "Middleware", + "attach_points": [{"Middleware": "OnRequest"}] + }] + }' + +# List modules +curl http://localhost:30000/wasm + +# Remove module +curl -X DELETE http://localhost:30000/wasm/{module_uuid} +``` + +### Runtime Configuration + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `max_memory_pages` | 1024 (64MB) | Maximum WASM memory | +| `max_execution_time_ms` | 1000 | Execution timeout | +| `max_stack_size` | 1MB | Stack size limit | +| `module_cache_size` | 10 | Cached modules per worker | + +**Note:** Rate limiting state is per-worker thread and not shared across gateway replicas. For production, consider implementing rate limiting at a shared layer (e.g., Redis) + +--- + +## Language Bindings + +SGLang Model Gateway provides official language bindings for Python and Go, enabling integration with different technology stacks and organizational requirements. + +### Python Bindings + +The Python bindings provide a PyO3-based wrapper around the Rust gateway library. This is a straightforward binding that calls the gateway server startup from Python. + +#### Installation + +```bash +# From PyPI +pip install sglang-router + +# Development build +cd sgl-model-gateway/bindings/python +pip install maturin && maturin develop --features vendored-openssl +``` + +#### Usage + +The Python bindings are used throughout this documentation. See the [Quick Start](#quick-start) and [Deployment Modes](#deployment-modes) sections for detailed examples. + +Key components: +- `RouterArgs` dataclass with 50+ configuration options +- `Router.from_args()` for programmatic startup +- CLI commands: `smg launch`, `smg server`, `python -m sglang_router.launch_router` + +### Go Bindings + +The Go bindings provide a high-performance gRPC client library for organizations with Go-based infrastructure. This is ideal for: + +- Integration with internal Go services and tooling +- High-performance client applications +- Building custom OpenAI-compatible proxy servers + +#### Architecture + +``` +┌─────────────────────────────────────────┐ +│ High-Level Go API │ +│ (client.go - OpenAI-style interface) │ +├─────────────────────────────────────────┤ +│ gRPC Layer │ +├─────────────────────────────────────────┤ +│ Rust FFI Layer │ +│ (Tokenization, Parsing, Conversion) │ +└─────────────────────────────────────────┘ +``` + +**Key Features:** +- Native Rust tokenization via FFI (thread-safe, lock-free) +- Full streaming support with context cancellation +- Configurable channel buffer sizes for high concurrency +- Built-in tool call parsing and chat template application + +#### Installation + +```bash +# Build the FFI library first +cd sgl-model-gateway/bindings/golang +make build && make lib + +# Then use in your Go project +go get github.com/sgl-project/sgl-go-sdk +``` + +**Requirements:** Go 1.24+, Rust toolchain + +#### Examples + +Complete working examples are available in `bindings/golang/examples/`: + +| Example | Description | +|---------|-------------| +| `simple/` | Non-streaming chat completion | +| `streaming/` | Streaming chat completion with SSE | +| `oai_server/` | Full OpenAI-compatible HTTP server | + +```bash +# Run examples +cd sgl-model-gateway/bindings/golang/examples/simple && ./run.sh +cd sgl-model-gateway/bindings/golang/examples/streaming && ./run.sh +cd sgl-model-gateway/bindings/golang/examples/oai_server && ./run.sh +``` + +#### Testing + +```bash +cd sgl-model-gateway/bindings/golang + +# Unit tests +go test -v ./... + +# Integration tests (requires running SGLang server) +export SGL_GRPC_ENDPOINT=grpc://localhost:20000 +export SGL_TOKENIZER_PATH=/path/to/tokenizer +go test -tags=integration -v ./... +``` + +### Comparison + +| Feature | Python | Go | +|---------|--------|-----| +| **Primary Use** | Gateway server launcher | gRPC client library | +| **CLI Support** | Full CLI (smg, sglang-router) | Library only | +| **K8s Discovery** | Native support | N/A (client library) | +| **PD Mode** | Built-in | N/A (client library) | + +**When to Use Python:** Launching and managing the gateway server, service discovery, PD disaggregation. + +**When to Use Go:** Building custom client applications, integration with Go microservices, OpenAI-compatible proxy servers + +--- + +## Security and Authentication + +### Router API Key + +```bash +python -m sglang_router.launch_router \ + --api-key "your-router-api-key" \ + --worker-urls http://worker1:8000 +``` + +Clients must supply `Authorization: Bearer ` for protected endpoints. + +### Worker API Keys + +```bash +# Add worker with explicit key +curl -H "Authorization: Bearer router-key" \ + -X POST http://localhost:8080/workers \ + -H "Content-Type: application/json" \ + -d '{"url":"http://worker:8000","api_key":"worker-key"}' +``` + +### Security Configurations + +1. **No Authentication** (default): Use only in trusted environments +2. **Router-only Authentication**: Clients authenticate to router +3. **Worker-only Authentication**: Router open, workers require keys +4. **Full Authentication**: Both router and workers protected + +### TLS (HTTPS) for Gateway Server + +Enable TLS to serve the gateway over HTTPS: + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 \ + --tls-cert-path /path/to/server.crt \ + --tls-key-path /path/to/server.key +``` + +| Parameter | Description | +|-----------|-------------| +| `--tls-cert-path` | Path to server certificate (PEM format) | +| `--tls-key-path` | Path to server private key (PEM format) | + +Both parameters must be provided together. The gateway uses rustls with the ring crypto provider for TLS termination. If TLS is not configured, the gateway falls back to plain HTTP. + +### mTLS for Worker Communication + +Enable mutual TLS (mTLS) for secure communication with workers in HTTP mode: + +```bash +python -m sglang_router.launch_router \ + --worker-urls https://worker1:8443 https://worker2:8443 \ + --client-cert-path /path/to/client.crt \ + --client-key-path /path/to/client.key \ + --ca-cert-path /path/to/ca.crt +``` + +| Parameter | Description | +|-----------|-------------| +| `--client-cert-path` | Path to client certificate for mTLS (PEM format) | +| `--client-key-path` | Path to client private key for mTLS (PEM format) | +| `--ca-cert-path` | Path to CA certificate for verifying worker TLS (PEM format, repeatable) | + +**Key Points:** +- Client certificate and key must be provided together +- Multiple CA certificates can be added with multiple `--ca-cert-path` flags +- Uses rustls backend when TLS is configured +- Single HTTP client is created for all workers (assumes single security domain) +- TCP keepalive (30 seconds) is enabled for long-lived connections + +### Full TLS Configuration Example + +Gateway HTTPS + Worker mTLS + API Key authentication: + +```bash +python -m sglang_router.launch_router \ + --worker-urls https://worker1:8443 https://worker2:8443 \ + --tls-cert-path /etc/certs/server.crt \ + --tls-key-path /etc/certs/server.key \ + --client-cert-path /etc/certs/client.crt \ + --client-key-path /etc/certs/client.key \ + --ca-cert-path /etc/certs/ca.crt \ + --api-key "secure-api-key" \ + --policy cache_aware +``` + +--- + +## Observability + +### Prometheus Metrics + +Enable with `--prometheus-host`/`--prometheus-port` (defaults to `0.0.0.0:29000`). + +#### Metric Categories (40+ metrics) + +| Layer | Prefix | Metrics | +|-------|--------|---------| +| HTTP | `smg_http_*` | `requests_total`, `request_duration_seconds`, `responses_total`, `connections_active`, `rate_limit_total` | +| Router | `smg_router_*` | `requests_total`, `request_duration_seconds`, `request_errors_total`, `stage_duration_seconds`, `upstream_responses_total` | +| Inference | `smg_router_*` | `ttft_seconds`, `tpot_seconds`, `tokens_total`, `generation_duration_seconds` | +| Worker | `smg_worker_*` | `pool_size`, `connections_active`, `requests_active`, `health_checks_total`, `selection_total`, `errors_total` | +| Circuit Breaker | `smg_worker_cb_*` | `state`, `transitions_total`, `outcomes_total`, `consecutive_failures`, `consecutive_successes` | +| Retry | `smg_worker_*` | `retries_total`, `retries_exhausted_total`, `retry_backoff_seconds` | +| Discovery | `smg_discovery_*` | `registrations_total`, `deregistrations_total`, `sync_duration_seconds`, `workers_discovered` | +| MCP | `smg_mcp_*` | `tool_calls_total`, `tool_duration_seconds`, `servers_active`, `tool_iterations_total` | +| Database | `smg_db_*` | `operations_total`, `operation_duration_seconds`, `connections_active`, `items_stored` | + +#### Key Inference Metrics (gRPC mode) + +| Metric | Type | Description | +|--------|------|-------------| +| `smg_router_ttft_seconds` | Histogram | Time to first token | +| `smg_router_tpot_seconds` | Histogram | Time per output token | +| `smg_router_tokens_total` | Counter | Total tokens (input/output) | +| `smg_router_generation_duration_seconds` | Histogram | End-to-end generation time | + +#### Duration Buckets + +1ms, 5ms, 10ms, 25ms, 50ms, 100ms, 250ms, 500ms, 1s, 2.5s, 5s, 10s, 15s, 30s, 45s, 60s, 90s, 120s, 180s, 240s + +### OpenTelemetry Tracing + +Enable distributed tracing with OTLP export: + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 \ + --enable-trace \ + --otlp-traces-endpoint localhost:4317 +``` + +#### Features + +- OTLP/gRPC exporter (default port 4317) +- W3C Trace Context propagation for HTTP and gRPC +- Batch span processing (500ms delay, 64 span batch size) +- Custom filtering to reduce noise +- Trace context injection into upstream worker requests +- Service name: `sgl-router` + +### Logging + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 \ + --log-level debug \ + --log-dir ./router_logs +``` + +Structured tracing with optional file sink. Log levels: `debug`, `info`, `warn`, `error`. + +### Request ID Propagation + +```bash +--request-id-headers x-request-id x-trace-id x-correlation-id +``` + +Responses include `x-request-id` header for correlation. + +--- + +## Production Recommendations + +This section provides guidance for deploying SGLang Model Gateway in production environments. + +### Security Best Practices + +**Always enable TLS in production:** + +```bash +python -m sglang_router.launch_router \ + --worker-urls https://worker1:8443 https://worker2:8443 \ + --tls-cert-path /etc/certs/server.crt \ + --tls-key-path /etc/certs/server.key \ + --client-cert-path /etc/certs/client.crt \ + --client-key-path /etc/certs/client.key \ + --ca-cert-path /etc/certs/ca.crt \ + --api-key "${ROUTER_API_KEY}" +``` + +**Security Checklist:** +- Enable TLS for gateway HTTPS termination +- Enable mTLS for worker communication when workers are on untrusted networks +- Set `--api-key` to protect router endpoints +- Use Kubernetes Secrets or a secrets manager for credentials +- Rotate certificates and API keys periodically +- Restrict network access with firewalls or network policies + +### High Availability + +**Scaling Strategy:** + +The gateway supports running multiple replicas behind a load balancer for high availability. However, there are important considerations: + +| Component | Shared Across Replicas | Impact | +|-----------|----------------------|--------| +| Worker Registry | No (independent) | Each replica discovers workers independently | +| Radix Cache Tree | No (independent) | Cache hits may decrease by 10-20% | +| Circuit Breaker State | No (independent) | Each replica tracks failures independently | +| Rate Limiting | No (independent) | Limits apply per-replica, not globally | + +**Recommendations:** + +1. **Prefer horizontal scaling over vertical scaling**: Deploy multiple smaller gateway replicas rather than one large instance with excessive CPU and memory. This provides: + - Better fault tolerance (single replica failure doesn't take down the gateway) + - More predictable resource usage + - Easier capacity planning + +2. **Use Kubernetes Service Discovery**: Let the gateway automatically discover and manage workers: + ```bash + python -m sglang_router.launch_router \ + --service-discovery \ + --selector app=sglang-worker \ + --service-discovery-namespace production + ``` + +3. **Accept cache efficiency trade-off**: With multiple replicas, the cache-aware routing policy's radix tree is not synchronized across replicas. This means: + - Each replica builds its own cache tree + - Requests from the same user may hit different replicas + - Expected cache hit rate reduction: **10-20%** + - This is often acceptable given the HA benefits + +4. **Configure session affinity (optional)**: If cache efficiency is critical, configure your load balancer for session affinity based on a consistent hash of the request (e.g., user ID or API key). + +**Example HA Architecture:** +``` + ┌─────────────────┐ + │ Load Balancer │ + │ (L4/L7) │ + └────────┬────────┘ + ┌──────────────┼──────────────┐ + │ │ │ + ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ + │ Gateway │ │ Gateway │ │ Gateway │ + │ Replica 1 │ │ Replica 2 │ │ Replica 3 │ + └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ + │ │ │ + └──────────────┼──────────────┘ + │ + ┌──────────────┼──────────────┐ + │ │ │ + ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ + │ Worker │ │ Worker │ │ Worker │ + │ Pod 1 │ │ Pod 2 │ │ Pod N │ + └───────────┘ └───────────┘ └───────────┘ +``` + +### Performance + +**Use gRPC mode for high throughput:** + +gRPC mode provides the highest performance for SGLang workers: + +```bash +# Start workers in gRPC mode +python -m sglang.launch_server \ + --model meta-llama/Llama-3.1-8B-Instruct \ + --grpc-mode \ + --port 20000 + +# Configure gateway for gRPC +python -m sglang_router.launch_router \ + --worker-urls grpc://worker1:20000 grpc://worker2:20000 \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --policy cache_aware +``` + +**Performance Benefits of gRPC:** +- Native Rust tokenization (no Python overhead) +- Streaming with lower latency +- Built-in reasoning parser execution +- Tool call parsing in the gateway +- Reduced serialization overhead + +**Tuning Recommendations:** + +| Parameter | Recommendation | Reason | +|-----------|---------------|--------| +| `--policy` | `cache_aware` | Best for repeated prompts, ~30% latency reduction | +| `--max-concurrent-requests` | 2-4x worker count | Prevent overload while maximizing throughput | +| `--queue-size` | 2x max-concurrent | Buffer for burst traffic | +| `--request-timeout-secs` | Based on max generation length | Prevent stuck requests | + +### Kubernetes Deployment + +**Pod Labeling for Service Discovery:** + +For the gateway to discover workers automatically, label your worker pods consistently: + +```yaml +# Worker Deployment (Regular Mode) +apiVersion: apps/v1 +kind: Deployment +metadata: + name: sglang-worker + namespace: production +spec: + replicas: 4 + selector: + matchLabels: + app: sglang-worker + component: inference + template: + metadata: + labels: + app: sglang-worker + component: inference + model: llama-3-8b + spec: + containers: + - name: worker + image: lmsysorg/sglang:latest + ports: + - containerPort: 8000 + name: http + - containerPort: 20000 + name: grpc +``` + +**Gateway configuration for discovery:** +```bash +python -m sglang_router.launch_router \ + --service-discovery \ + --selector app=sglang-worker component=inference \ + --service-discovery-namespace production \ + --service-discovery-port 8000 +``` + +**PD (Prefill/Decode) Mode Labeling:** + +```yaml +# Prefill Worker +metadata: + labels: + app: sglang-worker + component: prefill + annotations: + sglang.ai/bootstrap-port: "9001" + +# Decode Worker +metadata: + labels: + app: sglang-worker + component: decode +``` + +**Gateway configuration for PD discovery:** +```bash +python -m sglang_router.launch_router \ + --service-discovery \ + --pd-disaggregation \ + --prefill-selector app=sglang-worker component=prefill \ + --decode-selector app=sglang-worker component=decode \ + --service-discovery-namespace production +``` + +**RBAC Requirements:** + +The gateway needs permissions to watch pods: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: sglang-gateway + namespace: production +rules: +- apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: sglang-gateway + namespace: production +subjects: +- kind: ServiceAccount + name: sglang-gateway + namespace: production +roleRef: + kind: Role + name: sglang-gateway + apiGroup: rbac.authorization.k8s.io +``` + +### Monitoring with PromQL + +Configure Prometheus to scrape the gateway metrics endpoint (default: `:29000/metrics`). + +**Essential Dashboards:** + +**1. Request Rate and Latency:** +```promql +# Request rate by endpoint +sum(rate(smg_http_requests_total[5m])) by (path, method) + +# P50 latency +histogram_quantile(0.50, sum(rate(smg_http_request_duration_seconds_bucket[5m])) by (le)) + +# P99 latency +histogram_quantile(0.99, sum(rate(smg_http_request_duration_seconds_bucket[5m])) by (le)) + +# Error rate +sum(rate(smg_http_responses_total{status=~"5.."}[5m])) / sum(rate(smg_http_responses_total[5m])) +``` + +**2. Worker Health:** +```promql +# Healthy workers +sum(smg_worker_pool_size) + +# Active connections per worker +smg_worker_connections_active + +# Worker health check failures +sum(rate(smg_worker_health_checks_total{result="failure"}[5m])) by (worker_id) +``` + +**3. Circuit Breaker Status:** +```promql +# Circuit breaker states (0=closed, 1=open, 2=half-open) +smg_worker_cb_state + +# Circuit breaker transitions +sum(rate(smg_worker_cb_transitions_total[5m])) by (worker_id, from_state, to_state) + +# Workers with open circuits +count(smg_worker_cb_state == 1) +``` + +**4. Inference Performance (gRPC mode):** +```promql +# Time to first token (P50) +histogram_quantile(0.50, sum(rate(smg_router_ttft_seconds_bucket[5m])) by (le, model)) + +# Time per output token (P99) +histogram_quantile(0.99, sum(rate(smg_router_tpot_seconds_bucket[5m])) by (le, model)) + +# Token throughput +sum(rate(smg_router_tokens_total[5m])) by (model, direction) + +# Generation duration P95 +histogram_quantile(0.95, sum(rate(smg_router_generation_duration_seconds_bucket[5m])) by (le)) +``` + +**5. Rate Limiting and Queuing:** +```promql +# Rate limit rejections +sum(rate(smg_http_rate_limit_total{decision="rejected"}[5m])) + +# Queue depth (if using concurrency limiting) +smg_worker_requests_active + +# Retry attempts +sum(rate(smg_worker_retries_total[5m])) by (worker_id) + +# Exhausted retries (failures after all retries) +sum(rate(smg_worker_retries_exhausted_total[5m])) +``` + +**6. MCP Tool Execution:** +```promql +# Tool call rate +sum(rate(smg_mcp_tool_calls_total[5m])) by (server, tool) + +# Tool latency P95 +histogram_quantile(0.95, sum(rate(smg_mcp_tool_duration_seconds_bucket[5m])) by (le, tool)) + +# Active MCP server connections +smg_mcp_servers_active +``` + +**Alerting Rules Example:** + +```yaml +groups: +- name: sglang-gateway + rules: + - alert: HighErrorRate + expr: | + sum(rate(smg_http_responses_total{status=~"5.."}[5m])) + / sum(rate(smg_http_responses_total[5m])) > 0.05 + for: 5m + labels: + severity: critical + annotations: + summary: "High error rate on SGLang Gateway" + + - alert: CircuitBreakerOpen + expr: count(smg_worker_cb_state == 1) > 0 + for: 2m + labels: + severity: warning + annotations: + summary: "Worker circuit breaker is open" + + - alert: HighLatency + expr: | + histogram_quantile(0.99, sum(rate(smg_http_request_duration_seconds_bucket[5m])) by (le)) > 30 + for: 5m + labels: + severity: warning + annotations: + summary: "P99 latency exceeds 30 seconds" + + - alert: NoHealthyWorkers + expr: sum(smg_worker_pool_size) == 0 + for: 1m + labels: + severity: critical + annotations: + summary: "No healthy workers available" +``` + +--- + +## Configuration Reference + +### Core Settings + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `--host` | str | 127.0.0.1 | Router host | +| `--port` | int | 30000 | Router port | +| `--worker-urls` | list | [] | Worker URLs (HTTP or gRPC) | +| `--policy` | str | cache_aware | Routing policy | +| `--max-concurrent-requests` | int | -1 | Concurrency limit (-1 disables) | +| `--request-timeout-secs` | int | 600 | Request timeout | +| `--max-payload-size` | int | 256MB | Maximum request payload | + +### Prefill/Decode + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `--pd-disaggregation` | flag | false | Enable PD mode | +| `--prefill` | list | [] | Prefill URLs + optional bootstrap ports | +| `--decode` | list | [] | Decode URLs | +| `--prefill-policy` | str | None | Override policy for prefill nodes | +| `--decode-policy` | str | None | Override policy for decode nodes | +| `--worker-startup-timeout-secs` | int | 600 | Worker init timeout | + +### Kubernetes Discovery + +| Parameter | Type | Description | +|-----------|------|-------------| +| `--service-discovery` | flag | Enable discovery | +| `--selector` | list | Label selectors (key=value) | +| `--prefill-selector` / `--decode-selector` | list | PD mode selectors | +| `--service-discovery-namespace` | str | Namespace to watch | +| `--service-discovery-port` | int | Worker port (default 80) | +| `--bootstrap-port-annotation` | str | Annotation for bootstrap ports | + +### TLS Configuration + +| Parameter | Type | Description | +|-----------|------|-------------| +| `--tls-cert-path` | str | Server certificate for gateway HTTPS (PEM) | +| `--tls-key-path` | str | Server private key for gateway HTTPS (PEM) | +| `--client-cert-path` | str | Client certificate for worker mTLS (PEM) | +| `--client-key-path` | str | Client private key for worker mTLS (PEM) | +| `--ca-cert-path` | str | CA certificate for verifying workers (PEM, repeatable) | + +--- + +## Troubleshooting + +### Workers Never Ready + +Increase `--worker-startup-timeout-secs` or ensure health probes respond before router startup. + +### Load Imbalance / Hot Workers + +Inspect `smg_router_requests_total` by worker and tune cache-aware thresholds (`--balance-*`, `--cache-threshold`). + +### Circuit Breaker Flapping + +Increase `--cb-failure-threshold` or extend the timeout/window durations. Consider temporarily disabling retries. + +### Queue Overflow (429) + +Increase `--queue-size` or reduce client concurrency. Ensure `--max-concurrent-requests` matches downstream capacity. + +### Memory Growth + +Reduce `--max-tree-size` or lower `--eviction-interval-secs` for more aggressive cache pruning. + +### Debugging + +```bash +python -m sglang_router.launch_router \ + --worker-urls http://worker1:8000 \ + --log-level debug \ + --log-dir ./router_logs +``` + +### gRPC Connection Issues + +Ensure workers are started with `--grpc-mode` and verify `--model-path` or `--tokenizer-path` is provided to the router. + +### Tokenizer Loading Failures + +Check HuggingFace Hub credentials (`HF_TOKEN` environment variable) for private models. Verify local paths are accessible. + +--- + +SGLang Model Gateway continues to evolve alongside the SGLang runtime. Keep CLI flags, integrations, and documentation aligned when adopting new features or contributing improvements. diff --git a/sglang/docs/advanced_features/sglang_for_rl.md b/sglang/docs/advanced_features/sglang_for_rl.md new file mode 100644 index 0000000000000000000000000000000000000000..12eb415403398fa059161cf1f88182edf63d9b42 --- /dev/null +++ b/sglang/docs/advanced_features/sglang_for_rl.md @@ -0,0 +1,271 @@ +# SGLang for RL Systems + +This document is a practical guide for infrastructure teams integrating SGLang into RL and post-training systems. It focuses on the operational pain points in the loop (rollout, evaluation, training, weight sync) and maps them to concrete SGLang APIs, flags, and integration patterns. The focus is on maximizing rollout efficiency, accuracy and stability while keeping rollout-serving behavior aligned in production environments. + +## Why SGLang for RL Lifecycle? + +Let's embrace a guiding principle from early DeepMind's RL engineering: + +**Be a library, not a framework.** + +This philosophy empowers innovation by providing SGLang as flexible tools, not rigid structures. Here are five reasons to use SGLang for your RL lifecycle: + +* **Fine-Grained Engine Sleep and Wake Up**: facilitate maximum-powered rollout and training +* **Open-To-Use Refit Functionality**: diverse methods for co-location or disaggregation +* **Easy To Postpone Generation**: enable partial rollout and dedicated rollout control +* **Deterministic Inference**: achieve deterministic inference to enable zero training-inference mismatch +* **Load Balancing Router**: cache-aware load-balancing for high-throughput rollout + +The following sections cover these aspects in detail. + +## Fine-Grained Engine Sleep and Wake Up + +Rollout and training are both memory-intensive, and co-locating them on the same GPUs often leads to memory pressure and slow handoffs. SGLang provides a memory-aware sleep/wake mechanism that releases KV cache and weights while keeping the server process alive, then resumes them for rollout without a full restart. This avoids repeated disk I/O and CUDA graph recapture during each RL step. + +Under the hood, the RL team uses CUDA-graph-aware weight offload via [torch_memory_saver](https://github.com/fzyzcjy/torch_memory_saver) to preserve virtual memory addresses for graph replay. For details, see: [Efficient RL Training - Optimizing Memory Usage in verl](https://hebiao064.github.io/rl-memory-management). + +### Server flag + +Enable memory saver support when launching the server: + +``` +--enable-memory-saver +``` + +### Release Memory + +**Endpoint:** `POST /release_memory_occupation` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `tags` | Which memory regions to release. If omitted, all are released. | `None` | Type: list[str], values: `kv_cache`, `weights` | + +**Behavior notes:** + +- This call asserts there are no ongoing requests. Ensure the engine is idle before calling it. +- If `kv_cache` is released, SGLang flushes cache; subsequent requests will rebuild KV cache as needed. + +### Resume Memory + +**Endpoint:** `POST /resume_memory_occupation` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `tags` | Which memory regions to resume. If omitted, all are resumed. | `None` | Type: list[str], values: `kv_cache`, `weights` | + + +## Open-To-Use Refit Functionality + +After training completes each step, rollout engines must be refit with new weights. SGLang supports three refit strategies so you can match your infrastructure style (co-located vs disaggregated) and scaling needs. Each strategy maps to a concrete API with clear request schemas. For a deeper dive into SGLang's weight update utilities, see [RL System Deep Thinking: Weight Update Mechanisms](https://github.com/zhaochenyang20/Awesome-ML-SYS-Tutorial/blob/main/rlhf/sys-design/readme-1-EN.md). + +**How to choose:** + +- **From disk** is simplest and best for elastic rollout scaling and checkpointing. +- **From tensor** is best for co-located training/rollout when you can pass in-memory tensors. +- **From distributed** is best for disaggregated training/rollout with dedicated communication groups (NCCL/IB). + +### Update Weights from Disk + +**When to use:** + +- Save checkpoint to disk and update weights from disk +- Dynamic scaling (new rollout instances can load from the same checkpoint) + +**Why it works well:** + +This path trades some I/O overhead for simplicity and flexibility. It integrates naturally with checkpointing and makes it trivial to add new rollout engines: point them at the same checkpoint and call the API. It is also the safest option for high availability because the checkpoint itself is the source of truth. + +**Endpoint:** `POST /update_weights_from_disk` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `model_path` | The model path with the new weights. | Required | Type: str | +| `load_format` | The format to load the weights. | `None` | Type: str | +| `abort_all_requests` | Abort all running requests before update. | `False` | Type: bool | +| `weight_version` | Optional weight version label tracked by the server. | `None` | Type: str | +| `is_async` | Perform weight load asynchronously. | `False` | Type: bool | +| `torch_empty_cache` | Empty torch cache. | `False` | Type: bool | +| `keep_pause` | Keep scheduler paused after update. | `False` | Type: bool | +| `recapture_cuda_graph` | Recapture CUDA graphs after update. | `False` | Type: bool | +| `token_step` | Trainer step id for rollout bookkeeping. | `0` | Type: int | +| `flush_cache` | Flush KV cache after update. | `True` | Type: bool | + +**Response body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `success` | Whether the update succeeded. | - | Type: bool | +| `message` | Status / error message. | - | Type: str | +| `num_paused_requests` | Number of paused requests during update. | `0` | Type: int | + +**Python Engine API:** `engine.update_weights_from_disk(model_path, load_format=None)` + +**Diffusion engine (SGLang-Diffusion):** The diffusion engine exposes the same `POST /update_weights_from_disk` endpoint with the following behavior: + +- **All-or-nothing with rollback:** if any module fails to load, all previously updated modules are rolled back to the original weights by reloading from the original model path. No partial updates are left behind. If rollback itself fails, the exception propagates so the caller knows the model is in an inconsistent state. +- **Offload-aware:** when layerwise offload (`--dit-layerwise-offload`) is enabled, the diffusion offload manager replaces GPU parameters with small `torch.empty((1,))` placeholders while real weights live in consolidated pinned CPU buffers. A naive `param.data.copy_()` would fail with a shape mismatch. Instead, the updater dynamically detects active offload managers and writes new weights directly into their CPU buffers, bypassing the placeholders entirely. For any layer that happens to be prefetched on GPU at update time, the live GPU tensor is also updated so the change takes effect immediately. This requires no extra GPU memory and does not disturb the offload state. +- **DTensor-aware:** parameters distributed via `torch.distributed.tensor` (tensor parallelism) are updated through `distribute_tensor` so that each shard is correctly placed on the right device mesh. + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `model_path` | The model path with the new weights. | Required | Type: str | +| `flush_cache` | Flush TeaCache state after update. | `True` | Type: bool | +| `target_modules` | List of module names to update (e.g. `["transformer"]`). If omitted, all `nn.Module` components are updated. | `None` | Type: list[str] | + +**Response body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `success` | Whether the update succeeded. | - | Type: bool | +| `message` | Status / error message. | - | Type: str | + +> **Note:** The diffusion engine (SGLang-Diffusion) does not currently support hot refit (updating weights while inference is in progress). The diffusion scheduler processes one request at a time and completes the entire inference before handling the next request, so weight updates and inference never run concurrently. + +### Update Weights from Tensor + +**When to use:** + +- Co-located training and rollout, where training can provide tensors directly +- Fast in-memory updates + +**Important constraints:** + +This strategy requires the training process and rollout engine to share access to the tensors. Co-located setups must keep the model on GPU; moving tensors to CPU will break the update path. For high-performance MoE or specialized attention kernels, co-location may limit some optimizations compared to disaggregated rollouts. + +**Endpoint:** `POST /update_weights_from_tensor` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `serialized_named_tensors` | Per-TP serialized tensor payloads. | Required | Type: list[str|bytes] | +| `load_format` | Optional load format selector. | `None` | `None`, `direct`, `flattened_bucket`, or a custom loader path string | +| `flush_cache` | Flush KV cache after update. | `True` | Type: bool | +| `abort_all_requests` | Abort all running requests before update. | `False` | Type: bool | +| `weight_version` | Optional version label tracked by the server. | `None` | Type: str | + +**Note:** The serialized tensor payloads must be created with `MultiprocessingSerializer.serialize(...)` and should be base64-safe strings. + +**Python Engine API:** `engine.update_weights_from_tensor(named_tensors, load_format=None, flush_cache=True)` + +### Update Weights from Distributed Group + +**When to use:** + +- Disaggregated training and rollout +- NCCL or IB-backed weight broadcast from training workers to rollout workers + +**How it works:** + +Training workers gather weights (typically on TP rank 0), broadcast them to the rollout group, and each rollout TP shard loads the parameters it needs. This avoids disk I/O and keeps training and rollout decoupled, at the cost of managing a dedicated communication group. + +**Initialize weight update group** + +**Endpoint:** `POST /init_weights_update_group` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `master_address` | Group master address. | Required | Type: str | +| `master_port` | Group master port. | Required | Type: int | +| `rank_offset` | Offset for local rank mapping. | Required | Type: int | +| `world_size` | Total world size. | Required | Type: int | +| `group_name` | Group name. | `weight_update_group` | Type: str | +| `backend` | Communication backend. | `nccl` | Type: str | + +**Update weight** + +**Endpoint:** `POST /update_weights_from_distributed` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `names` | Parameter names to update. | Required | Type: list[str] | +| `dtypes` | Dtype strings for each parameter. | Required | Type: list[str] | +| `shapes` | Tensor shapes. | Required | Type: list[list[int]] | +| `group_name` | Group name. | `weight_update_group` | Type: str | +| `flush_cache` | Flush KV cache after update. | `True` | Type: bool | +| `abort_all_requests` | Abort all running requests before update. | `False` | Type: bool | +| `weight_version` | Optional version label. | `None` | Type: str | +| `load_format` | Optional format selector. | `None` | `None` or `flattened_bucket` | + +**Destroy weights update group** + +**Endpoint:** `POST /destroy_weights_update_group` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `group_name` | Group name. | `weight_update_group` | Type: str | + +**Python Engine APIs:** + +- `engine.init_weights_update_group(...)` +- `engine.update_weights_from_distributed(names, dtypes, shapes, ...)` +- `engine.destroy_weights_update_group(group_name)` + +## Easy To Postpone Generation + +Multi-turn RL rollouts often suffer from long-tail requests that block the entire batch. A small number of slow interactions can stall all GPUs, and the long-tail behavior makes profiling and monitoring difficult. + +SGLang exposes explicit pause/resume APIs so you can pause slow requests and continue them later. This pattern matches systems like [APRIL](https://arxiv.org/abs/2509.18521), terminate once enough responses are collected, and recycle incomplete responses in the next step. The result is higher GPU utilization without discarding partial work. + +`pause_generation` --- update weights --- `continue_generation` is the correct execution flow when updating weights from training. An update can only happen when SGLang is not actively processing inference tasks. + +### Pause Generation + +**Endpoint:** `POST /pause_generation` + +**Request body:** + +| Field | Description | Defaults | Options | +| --- | --- | --- | --- | +| `mode` | Pause mode. | `abort` | `abort`, `retract`, `in_place` | + +**Modes:** + +- `abort`: Default behavior, identical to `abort` endpoint with `abort_all` set. Pending requests from `waiting_queue` and `running_queue` will be returned immediately to the caller. +- `retract`: Put engine in "paused" state. Move running requests back to waiting queue. KV cache can be flushed and recomputed later. +- `in_place`: Put engine in "paused" state without changing states of the requests. Running requests rely on availability of KV caches to continue, so any subsequent `flush_cache` call will be unsuccessful. + +### Continue Generation + +**Endpoint:** `POST /continue_generation` + +## Deterministic Inference + +In many RL stacks, rollout and training are implemented with different kernels or batching behavior. Even when weights are identical, token probabilities can drift, silently breaking the on-policy assumption. This is the training–inference mismatch problem. + +SGLang supports a deterministic inference mode that reduces non-determinism across batch shapes. This mitigates variance introduced by runtime batching and kernel selection. To further achieve true on-policy training, you need to modify the training engine to use the same deterministic kernels. For implementation details, see these miles examples: [True On-Policy](https://github.com/radixark/miles/tree/main/examples/true_on_policy) and [True On-Policy for VLM](https://github.com/radixark/miles/tree/main/examples/true_on_policy_vlm). For additional context, see the blog post [Let Speed Be With Stability: All-In-One Solution to Training-Inference Mismatch with Miles](https://github.com/zhaochenyang20/Awesome-ML-SYS-Tutorial/blob/main/rlhf/slime/mismatch/blog-en.md). + +**Server flag:** + +``` +--enable-deterministic-inference +``` + +For more details, see [Deterministic Inference](deterministic_inference.md) + +## Load Balancing Router + +SGLang Model Gateway is the recommended control plane for large‑scale RL rollouts. It provides async, non‑blocking request handling, cache‑aware load balancing, and fault‑tolerant routing across rollout and reward servers. This lets you keep GPUs saturated while avoiding long‑tail stalls and brittle, engine‑local concurrency logic. It has been deployed in the training of GLM 4.5+ models and proven to be highly efficient in production-level large-scale RL workloads. + +Key benefits for RL infrastructure: + +- **Async non-blocking efficiency**: SGLang’s native async server/router architecture (HTTPS/gRPC) manages concurrency automatically. This guarantees maximum GPU saturation and effective continuous batching without requiring complex, manual implementation by engineers. +- **Elasticity and fault tolerance**: By encapsulating the reward model and rollout as independent servers, SGLang decouples them logically and physically. This architecture provides robust disaster recovery for large-scale distributed training; if a server fails, the router automatically redirects traffic to healthy nodes, ensuring the training process continues without interruption. +- **Training–Inference alignment**: Using the SGLang Model Gateway for both training and inference ensures "What You See Is What You Get." This eliminates score discrepancies and the painful backend alignment issues often caused by using different engines for training versus deployment. +- **Dynamic load balancing and long-tail mitigation**: Unlike static partitioning, the SGLang Model Gateway enables request-level dynamic dispatching for multi-turn RL. It can distribute different turns of a conversation across different servers to balance workloads and eliminate long-tail latency caused by varying sequence lengths. + +For deployment and configuration, see: [SGLang Model Gateway](sgl_model_gateway.md) diff --git a/sglang/docs/advanced_features/speculative_decoding.md b/sglang/docs/advanced_features/speculative_decoding.md new file mode 100644 index 0000000000000000000000000000000000000000..121ae8d586b735f0b2ca7ccbcf77e54223d112a0 --- /dev/null +++ b/sglang/docs/advanced_features/speculative_decoding.md @@ -0,0 +1,568 @@ +# Speculative Decoding + +SGLang provides several speculative decoding options, including EAGLE-2/EAGLE-3, MTP, classic draft-model decoding, and an NGRAM-based variant. Our implementation aims to maximize speed and efficiency and is considered to be among the fastest in open-source LLM engines. + +## Summary + +### Jump to sections + +- [EAGLE Decoding](#eagle-decoding) + - [EAGLE-2 Decoding](#eagle-2-decoding) + - [EAGLE-2 Decoding with torch.compile](#eagle-2-decoding-with-torchcompile) + - [EAGLE-2 Decoding via Frequency-Ranked Speculative Sampling](#eagle-2-decoding-via-frequency-ranked-speculative-sampling) + - [EAGLE-3 Decoding](#eagle-3-decoding) +- [Multi Token Prediction](#multi-token-prediction) +- [Standalone Speculative Decoding (Small Draft Model)](#standalone-speculative-decoding-small-draft-model) +- [Speculative Decoding V2 (Overlap Scheduler)](#speculative-decoding-v2-overlap-scheduler) +- [Ngram Speculative Decoding](#ngram-speculative-decoding) +- [Full Parameter Reference](#full-parameter-reference) +- [OOM Troubleshooting](#oom-troubleshooting) +- [References](#references) + +### Quick guidance + +- **Best speed/quality (recommended)**: Use **EAGLE-3** with `--speculative-algorithm EAGLE3`. +- **Strong default / broad compatibility**: Use **EAGLE-2** with `--speculative-algorithm EAGLE`. +- **Lower `lm_head` overhead for EAGLE-2**: Enable **FR-Spec** with `--speculative-token-map`. +- **Model is MTP-enabled**: Use **MTP via speculative decoding** (often with small `speculative_num_steps/topk/num_draft_tokens`, see the example section). +- **You have a smaller draft LLM**: Use **STANDALONE** (`--speculative-algorithm STANDALONE`). +- **No extra model available**: Use **NGRAM** (`--speculative-algorithm NGRAM`, CUDA-only). +- **Want overlap scheduler (experimental)**: Enable **SpecV2** with `SGLANG_ENABLE_SPEC_V2=True` (requires `--speculative-eagle-topk 1`). + +### Method comparison (mini table) + +| Method | Draft source | Separate draft model? | How to enable | Notes / constraints | +|---|---|---:|---|---| +| EAGLE-2 | EAGLE draft model (feature drafting + tree) | Typically yes | `--speculative-algorithm EAGLE` + `--speculative-draft-model-path ...` | Tune `--speculative-num-steps`, `--speculative-eagle-topk`, `--speculative-num-draft-tokens` | +| EAGLE-2 + `torch.compile` | Same as EAGLE-2 | Typically yes | Add `--enable-torch-compile` (optionally `--torch-compile-max-bs`) | Benefit varies by hardware/model; benchmark to verify | +| EAGLE-2 + FR-Spec | Same as EAGLE-2 + token subset | Typically yes | Add `--speculative-token-map ...` | Reduces `lm_head` overhead with high-frequency token vocab | +| EAGLE-3 | EAGLE3 draft model | Yes | `--speculative-algorithm EAGLE3` + `--speculative-draft-model-path ...` | Best throughput in the benchmark below | +| MTP | Built-in multi-token heads (model-specific) | Often no | See **Multi Token Prediction** section | Uses speculative workflow; draft path may be auto-handled for some models | +| STANDALONE | Smaller draft LLM (token-level) | Yes | `--speculative-algorithm STANDALONE` + `--speculative-draft-model-path ...` | Does **not** support `--enable-dp-attention` | +| SpecV2 (experimental) | V2 workers + overlap scheduler | N/A | `SGLANG_ENABLE_SPEC_V2=True` | Only supports `--speculative-eagle-topk 1`; applies to `EAGLE`, `EAGLE3`, `STANDALONE` | +| NGRAM | Ngram cache from previous tokens | No | `--speculative-algorithm NGRAM` | CUDA-only; no `--enable-dp-attention`; disables overlap scheduler & mixed chunked prefill | + +### Performance Highlights + +Please see below for the huge improvements on throughput for LLaMA-Instruct 3.1 8B tested on MT bench that can be achieved via EAGLE3 decoding. +For further details please see the [EAGLE3 paper](https://arxiv.org/pdf/2503.01840). + +| Method | Throughput (tokens/s) | +|--------|----------------| +| SGLang (w/o speculative, 1x H100) | 158.34 tokens/s | +| SGLang + EAGLE-2 (1x H100) | 244.10 tokens/s | +| SGLang + EAGLE-3 (1x H100) | 373.25 tokens/s | + +--- + +## EAGLE Decoding + +To enable EAGLE speculative decoding the following parameters are relevant: + +| Parameter | Description | Default | +|---|---|---| +| `--speculative-draft-model-path` | Draft model path/weights. **Typically required** for EAGLE/EAGLE3 and STANDALONE. For some MTP-enabled models, this can be omitted. | `None` | +| `--speculative-num-steps` | Depth of autoregressive drafting. Increases speculation range but risks rejection cascades. | Auto (`5` for Llama/Grok; `3` for many other models) | +| `--speculative-eagle-topk` | Branching factor per step. Improves candidate diversity and acceptance rate, but increases memory/compute consumption. | Auto (`4` for Llama/Grok; `1` for many other models) | +| `--speculative-num-draft-tokens` | Maximum parallel verification capacity. Allows deeper tree evaluation but increases GPU memory usage. | Auto (`8` for Llama/Grok; `4` for many other models). If `topk=1`, it is adjusted to `num_steps + 1`. | +| `--speculative-accept-threshold-single` | Acceptance threshold for single-token verification. Lower values accept more aggressively. | `1.0` | +| `--speculative-accept-threshold-acc` | Accumulated acceptance threshold across steps. | `1.0` | +| `--speculative-attention-mode` | Attention mode for speculative operations (`prefill` or `decode`), affecting both target verification and draft extension. | `"prefill"` | +| `--speculative-draft-attention-backend` | Override attention backend for the draft model. | `None` (same as target) | +| `--speculative-draft-model-quantization` | Quantization method for the draft model. Use `"unquant"` to force no quantization even when the target model is quantized. | Same as target model | +| `--speculative-draft-model-revision` | Specific revision/commit of the draft model to load. | `None` (auto-set to `"main"` when `--speculative-draft-model-path` is set and revision is omitted) | +| `--speculative-draft-load-format` | Load format for the draft model weights. | `None` | + +These parameters are mostly the same for EAGLE-2 and EAGLE-3. `--speculative-token-map` is ignored for EAGLE-3 models. +For `--speculative-num-steps`, `--speculative-eagle-topk`, and `--speculative-num-draft-tokens`: leave all three unset to use auto-tuning, or set all three explicitly when tuning. + +You can find the best combinations of these parameters with [bench_speculative.py](https://github.com/sgl-project/sglang/blob/main/scripts/playground/bench_speculative.py). + + +### EAGLE-2 Decoding + +You can enable EAGLE-2 Decoding by setting `--speculative-algorithm EAGLE` and choosing an appropriate model. + +**Launch the server:** + +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Llama-2-7b-chat-hf \ + --speculative-algorithm EAGLE \ + --speculative-draft-model-path lmsys/sglang-EAGLE-llama2-chat-7B \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 4 \ + --speculative-num-draft-tokens 16 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="meta-llama/Llama-2-7b-chat-hf", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +### EAGLE-2 Decoding with `torch.compile` + +You can optionally enable `torch.compile` to apply kernel-level optimizations (operator fusion, autotune) to the draft model. The actual speedup depends on your hardware, model architecture, and batch size. In some configurations (e.g., small draft models on H100 where cuBLAS is already optimal and CUDA graphs are enabled), the benefit may be negligible. We recommend benchmarking with and without this flag on your specific setup to verify whether it helps. + +To enable it, add `--enable-torch-compile` and optionally set `--torch-compile-max-bs`: + +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Llama-2-7b-chat-hf \ + --speculative-algorithm EAGLE \ + --speculative-draft-model-path lmsys/sglang-EAGLE-llama2-chat-7B \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 4 \ + --speculative-num-draft-tokens 16 \ + --mem-fraction-static 0.7 \ + --enable-torch-compile \ + --torch-compile-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="meta-llama/Llama-2-7b-chat-hf", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +### EAGLE-2 Decoding via Frequency-Ranked Speculative Sampling + +By employing a truncated high-frequency token vocabulary in the draft model, EAGLE speculative decoding reduces `lm_head` computational overhead while accelerating the pipeline without quality degradation. For more details, check out [the paper](https://arxiv.org/pdf/2502.14856). + +In our implementation, set `--speculative-token-map` to enable the optimization. You can get the high-frequency tokens in FR-Spec from [this model](https://huggingface.co/thunlp/LLaMA3-Instruct-8B-FR-Spec). Or you can obtain high-frequency tokens by directly downloading these tokens from [this repo](https://github.com/thunlp/FR-Spec/tree/main?tab=readme-ov-file#prepare-fr-spec-vocabulary-subset). + +Thanks for the contribution from [Weilin Zhao](https://github.com/Achazwl) and [Zhousx](https://github.com/Zhou-sx). + +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3-8B-Instruct \ + --speculative-algorithm EAGLE \ + --speculative-draft-model-path lmsys/sglang-EAGLE-LLaMA3-Instruct-8B \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 4 \ + --speculative-num-draft-tokens 16 \ + --speculative-token-map thunlp/LLaMA3-Instruct-8B-FR-Spec/freq_32768.pt \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --dtype float16 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="meta-llama/Meta-Llama-3-8B-Instruct", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +### EAGLE-3 Decoding + +You can enable EAGLE-3 decoding by setting `--speculative-algorithm EAGLE3` and choosing an appropriate model. + +```bash +python3 -m sglang.launch_server \ + --model meta-llama/Meta-Llama-3.1-8B-Instruct \ + --speculative-algorithm EAGLE3 \ + --speculative-draft-model-path jamesliu1/sglang-EAGLE3-Llama-3.1-Instruct-8B \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 4 \ + --speculative-num-draft-tokens 16 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --dtype float16 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="meta-llama/Meta-Llama-3.1-8B-Instruct", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +## Multi Token Prediction + +We support [MTP (Multi-Token Prediction)](https://arxiv.org/pdf/2404.19737) in SGLang by using speculative decoding. We use `XiaomiMiMo/MiMo-7B-RL` as an example here (for DeepSeek MTP usage, refer to [deepseek_v32 doc](../basic_usage/deepseek_v32.md#multi-token-prediction)). + +```bash +python3 -m sglang.launch_server \ + --model XiaomiMiMo/MiMo-7B-RL \ + --host 0.0.0.0 \ + --trust-remote-code \ + --speculative-algorithm EAGLE \ + --speculative-num-steps 1 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 2 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import requests + +url = "http://localhost:30000/v1/chat/completions" + +data = { + "model": "XiaomiMiMo/MiMo-7B-RL", + "messages": [{"role": "user", "content": "What is the capital of France?"}], +} + +response = requests.post(url, json=data) +print(response.json()) +``` + +--- + +## Standalone Speculative Decoding (Small Draft Model) + +Besides EAGLE/MTP, SGLang also supports **token-level speculative decoding** using a smaller **draft model**. Enable it with `--speculative-algorithm STANDALONE` and provide a draft model via `--speculative-draft-model-path`. + +Relevant parameters: + +| Parameter | Description | Default | +|---|---|---| +| `--speculative-draft-model-path` | Draft model weights (smaller than the target model). | `None` | +| `--speculative-num-steps` | Draft depth (how many steps the draft model runs autoregressively). | `3` (auto default for STANDALONE) | +| `--speculative-eagle-topk` | Branching factor (token candidates per step). | `1` (auto default for STANDALONE) | +| `--speculative-num-draft-tokens` | Verification capacity. | `4` (auto default for STANDALONE) | +| `--speculative-draft-model-quantization` | Quantization for the draft model. Use `"unquant"` to disable quantization on the draft even when the target is quantized. | Same as target | + +> **Note:** Standalone speculative decoding currently **does not support** `--enable-dp-attention`. + +```bash +python3 -m sglang.launch_server \ + --model Qwen/Qwen2.5-7B-Instruct \ + --speculative-algorithm STANDALONE \ + --speculative-draft-model-path Qwen/Qwen2.5-1.5B-Instruct \ + --speculative-num-steps 4 \ + --speculative-eagle-topk 2 \ + --speculative-num-draft-tokens 7 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="Qwen/Qwen2.5-7B-Instruct", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +## Speculative Decoding V2 (Overlap Scheduler) + +SGLang provides an **experimental Speculative Decoding V2** implementation that enables an overlap scheduler and uses V2 speculative workers (e.g. `StandaloneWorkerV2`, `EAGLEWorkerV2`). + +To enable it, set the environment variable: +- `SGLANG_ENABLE_SPEC_V2=True` + +Notes: +- SpecV2 currently only supports `--speculative-eagle-topk 1`. When SpecV2 is enabled, **set `--speculative-eagle-topk 1` explicitly**. +- If you explicitly set `--speculative-eagle-topk > 1`, the server will error. +- If you omit `--speculative-eagle-topk`, auto-tuning may pick `topk > 1` for some models (e.g. Llama). This is incompatible with SpecV2 and may not always trigger an immediate config error, so set `--speculative-eagle-topk 1` explicitly. +- This applies to `EAGLE`, `EAGLE3`, and `STANDALONE`. + +```bash +SGLANG_ENABLE_SPEC_V2=True python3 -m sglang.launch_server \ + --model Qwen/Qwen2.5-7B-Instruct \ + --speculative-algorithm STANDALONE \ + --speculative-draft-model-path Qwen/Qwen2.5-1.5B-Instruct \ + --speculative-num-steps 4 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 5 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="Qwen/Qwen2.5-7B-Instruct", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +## Ngram Speculative Decoding + +SGLang also supports **ngram-based speculative decoding** (no separate draft model). It retrieves draft tokens from an ngram cache built from previously generated tokens, and then verifies them with the target model. + +Enable it with: +- `--speculative-algorithm NGRAM` + +### Ngram-specific parameters + +| Parameter | Description | Default | +|---|---|---| +| `--speculative-num-draft-tokens` | Number of draft tokens verified per step. If omitted, defaults to `--speculative-ngram-max-match-window-size`. | `12` (with default ngram settings) | +| `--speculative-ngram-min-match-window-size` | Minimum matching window size. | `1` | +| `--speculative-ngram-max-match-window-size` | Maximum matching window size. | `12` | +| `--speculative-ngram-min-bfs-breadth` | Minimum BFS breadth. | `1` | +| `--speculative-ngram-max-bfs-breadth` | Maximum BFS breadth. | `10` | +| `--speculative-ngram-match-type` | Match type: `"BFS"` or `"PROB"`. | `"BFS"` | +| `--speculative-ngram-branch-length` | How many recent tokens to insert into the cache. | `18` | +| `--speculative-ngram-capacity` | Cache capacity (number of entries). | `10,000,000` | + +Notes: +- Ngram speculative decoding **only supports CUDA**. +- It currently **does not support** `--enable-dp-attention`. +- It disables the overlap scheduler and mixed chunked prefill. +- If `--speculative-ngram-max-bfs-breadth > 1` (thus `speculative_eagle_topk > 1`) and `page_size > 1`, use `--attention-backend flashinfer`; otherwise the server will error. +- Optional: set `SGLANG_NGRAM_FORCE_GREEDY_VERIFY=True` to force greedy verification. + +```bash +python3 -m sglang.launch_server \ + --model Qwen/Qwen2.5-7B-Instruct \ + --speculative-algorithm NGRAM \ + --speculative-num-draft-tokens 16 \ + --speculative-ngram-max-match-window-size 12 \ + --speculative-ngram-max-bfs-breadth 10 \ + --mem-fraction-static 0.7 \ + --cuda-graph-max-bs 8 \ + --log-level warning +``` + +**Send a request:** + +```python +import openai + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="None") + +response = client.chat.completions.create( + model="Qwen/Qwen2.5-7B-Instruct", + messages=[ + {"role": "user", "content": "List 3 countries and their capitals."}, + ], + temperature=0, + max_tokens=64, +) + +print(response.choices[0].message.content) +``` + +--- + +## Full Parameter Reference + +Below is a comprehensive list of all speculative decoding parameters available in SGLang: + +### Core parameters + +| Parameter | Type | Default | Description | +|---|---|---|---| +| `--speculative-algorithm` | `str` | `None` | Algorithm to use: `EAGLE`, `EAGLE3`, `STANDALONE`, `NGRAM`, `NEXTN` (alias of `EAGLE`) | +| `--speculative-draft-model-path` | `str` | `None` | Path to the draft model weights | +| `--speculative-draft-model-revision` | `str` | `None` | Specific revision/commit of the draft model (`"main"` is auto-used when draft path is set and revision is omitted) | +| `--speculative-draft-load-format` | `str` | `None` | Load format for draft model weights | +| `--speculative-num-steps` | `int` | `None` (auto-chosen when omitted) | Autoregressive drafting depth | +| `--speculative-eagle-topk` | `int` | `None` (auto-chosen when omitted) | Branching factor per drafting step | +| `--speculative-num-draft-tokens` | `int` | `None` (auto-chosen when omitted) | Maximum number of draft tokens for verification | +| `--speculative-accept-threshold-single` | `float` | `1.0` | Single-token acceptance threshold | +| `--speculative-accept-threshold-acc` | `float` | `1.0` | Accumulated acceptance threshold | +| `--speculative-token-map` | `str` | `None` | Path to FR-Spec high-frequency token map | +| `--speculative-attention-mode` | `str` | `"prefill"` | Attention mode for speculative operations (`"prefill"` or `"decode"`) | +| `--speculative-draft-attention-backend` | `str` | `None` | Override attention backend for the draft model | +| `--speculative-moe-runner-backend` | `str` | `None` | MoE runner backend for the draft model | +| `--speculative-moe-a2a-backend` | `str` | `None` | MoE all-to-all backend for the draft model | +| `--speculative-draft-model-quantization` | `str` | Same as target | Quantization for the draft model (`"unquant"` to disable) | + +### Ngram-specific parameters + +| Parameter | Type | Default | Description | +|---|---|---|---| +| `--speculative-ngram-min-match-window-size` | `int` | `1` | Minimum ngram matching window | +| `--speculative-ngram-max-match-window-size` | `int` | `12` | Maximum ngram matching window | +| `--speculative-ngram-min-bfs-breadth` | `int` | `1` | Minimum BFS breadth | +| `--speculative-ngram-max-bfs-breadth` | `int` | `10` | Maximum BFS breadth | +| `--speculative-ngram-match-type` | `str` | `"BFS"` | Match type: `"BFS"` or `"PROB"` | +| `--speculative-ngram-branch-length` | `int` | `18` | Recent tokens to insert into cache | +| `--speculative-ngram-capacity` | `int` | `10,000,000` | Cache capacity | + +### Environment variables + +| Variable | Default | Description | +|---|---|---| +| `SGLANG_ENABLE_SPEC_V2` | `False` | Enable Speculative Decoding V2 (overlap scheduler) | +| `SGLANG_NGRAM_FORCE_GREEDY_VERIFY` | `False` | Force greedy verification for ngram decoding | + +### Other related flags + +| Parameter | Description | +|---|---| +| `--enable-multi-layer-eagle` | Enable multi-layer EAGLE (auto-enabled for MiMoV2 and Step3p5 models) | +| `--enable-torch-compile` | Enable `torch.compile` for kernel-level optimizations | +| `--torch-compile-max-bs` | Maximum batch size for `torch.compile` | + +--- + +## OOM Troubleshooting + +> [!WARNING] +> **Out of Memory (OOM)?** Speculative decoding may increase GPU memory usage because the draft tree, CUDA graphs, and verification-related buffers consume additional VRAM. If you encounter OOM errors, try the following adjustments. + +### Step 1: Lower static memory fraction (most effective) + +```bash +--mem-fraction-static 0.5 # when omitted, this value is auto-computed +``` + +- `--mem-fraction-static` controls the memory budget for model weights + KV cache pool. +- Lowering it directly increases dynamic headroom for activations and CUDA graph buffers. +- If omitted, SGLang auto-estimates this value from other settings, and those auto settings can still be too aggressive for some workloads. + +### Step 2: Reduce CUDA graph batch size + +```bash +# Fewer CUDA graph captures = less memory reserved +--cuda-graph-max-bs 4 # or even 2 for tight memory situations +``` + +- If omitted, `--cuda-graph-max-bs` is auto-selected based on GPU memory and TP size, and can be much larger on high-memory GPUs. + +### Step 3: Reduce draft tree size + +These three parameters directly control how much memory the draft tree consumes: + +```bash +# Before (aggressive, high memory) +--speculative-num-steps 5 --speculative-eagle-topk 8 --speculative-num-draft-tokens 64 + +# After (conservative, lower memory) +--speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 +``` + +### Step 4: Limit concurrent requests + +```bash +# Fewer concurrent requests lowers in-flight load and can reduce OOM risk +--max-running-requests 4 +``` + +### Quick OOM recovery recipe + +If you're hitting OOM and just want something that works, start with this minimal configuration and scale up: + +```bash +python3 -m sglang.launch_server \ + --model \ + --speculative-algorithm EAGLE \ + --speculative-draft-model-path \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 4 \ + --cuda-graph-max-bs 2 \ + --mem-fraction-static 0.5 \ + --max-running-requests 4 \ + --log-level warning +``` + +Then gradually increase `--speculative-num-draft-tokens`, `--speculative-eagle-topk`, and `--cuda-graph-max-bs`. Increase `--mem-fraction-static` last, only after the run is stable. + +--- + +## References + +EAGLE process is as follows: + +- Within EAGLE the draft model predicts the next feature vector, i.e. the last hidden state of the original LLM, using the feature sequence $(f_1, ..., f_k)$ and the token sequence $(t_2, ..., t_{k+1})$. +- The next token is then sampled from $p_{k+2}=\text{LMHead}(f_{k+1})$. Afterwards, the two sequences are extended in a tree style—branching out multiple potential continuations, with the branching factor per step controlled by the `speculative_eagle_topk` parameter—to ensure a more coherent connection of context, and are given as input again. +- In SGLang's EAGLE-2 implementation, the draft tree is expanded for the configured steps and then reranked to select the top `speculative_num_draft_tokens` final nodes as draft tokens. +- EAGLE-3 removes the feature prediction objective, incorporates low and mid-layer features, and is trained in an on-policy manner. + +This enhances drafting accuracy by operating on features instead of tokens for more regular inputs and by additionally passing tokens from the next timestep to reduce sampling randomness. For more details, see the [EAGLE-2](https://arxiv.org/abs/2406.16858) and [EAGLE-3](https://arxiv.org/abs/2503.01840) papers. + +For guidance on how to train your own EAGLE model please see the [EAGLE repo](https://github.com/SafeAILab/EAGLE/tree/main?tab=readme-ov-file#train). For EAGLE-3 training specifically, check out [SpecForge](https://github.com/sgl-project/SpecForge), the SGLang team's training framework designed for EAGLE-3 speculative decoding models with seamless porting to SGLang serving. See the [SpecForge documentation](https://docs.sglang.ai/SpecForge/) and [blog post](https://lmsys.org/blog/2025-07-25-spec-forge) for details. diff --git a/sglang/docs/advanced_features/structured_outputs_for_reasoning_models.ipynb b/sglang/docs/advanced_features/structured_outputs_for_reasoning_models.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..cfc07fd0162984cd8be5bb6f3237429ee8fd5047 --- /dev/null +++ b/sglang/docs/advanced_features/structured_outputs_for_reasoning_models.ipynb @@ -0,0 +1,841 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Structured Outputs For Reasoning Models\n", + "\n", + "When working with reasoning models that use special tokens like `...` to denote reasoning sections, you might want to allow free-form text within these sections while still enforcing grammar constraints on the rest of the output.\n", + "\n", + "SGLang provides a feature to disable grammar restrictions within reasoning sections. This is particularly useful for models that need to perform complex reasoning steps before providing a structured output.\n", + "\n", + "To enable this feature, use the `--reasoning-parser` flag which decide the think_end_token, such as ``, when launching the server. You can also specify the reasoning parser using the `--reasoning-parser` flag.\n", + "\n", + "## Supported Models\n", + "\n", + "Currently, SGLang supports the following reasoning models:\n", + "- [DeepSeek R1 series](https://huggingface.co/collections/deepseek-ai/deepseek-r1-678e1e131c0169c0bc89728d): The reasoning content is wrapped with `` and `` tags.\n", + "- [QwQ](https://huggingface.co/Qwen/QwQ-32B): The reasoning content is wrapped with `` and `` tags.\n", + "\n", + "\n", + "## Usage\n", + "\n", + "## OpenAI Compatible API" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specify the `--grammar-backend`, `--reasoning-parser` option." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import openai\n", + "import os\n", + "\n", + "from sglang.test.doc_patch import launch_server_cmd\n", + "from sglang.utils import wait_for_server, print_highlight, terminate_process\n", + "\n", + "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\"\n", + "\n", + "\n", + "server_process, port = launch_server_cmd(\n", + " \"python -m sglang.launch_server --model-path deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --reasoning-parser deepseek-r1 --log-level warning\"\n", + ")\n", + "\n", + "wait_for_server(f\"http://localhost:{port}\", process=server_process)\n", + "client = openai.Client(base_url=f\"http://127.0.0.1:{port}/v1\", api_key=\"None\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### JSON\n", + "\n", + "you can directly define a JSON schema or use [Pydantic](https://docs.pydantic.dev/latest/) to define and validate the response." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using Pydantic**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pydantic import BaseModel, Field\n", + "\n", + "\n", + "# Define the schema using Pydantic\n", + "class CapitalInfo(BaseModel):\n", + " name: str = Field(..., pattern=r\"^\\w+$\", description=\"Name of the capital city\")\n", + " population: int = Field(..., description=\"Population of the capital city\")\n", + "\n", + "\n", + "response = client.chat.completions.create(\n", + " model=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\",\n", + " messages=[\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Give me the information and population of the capital of France in the JSON format.\",\n", + " },\n", + " ],\n", + " temperature=0,\n", + " max_tokens=2048,\n", + " response_format={\n", + " \"type\": \"json_schema\",\n", + " \"json_schema\": {\n", + " \"name\": \"foo\",\n", + " # convert the pydantic model to json schema\n", + " \"schema\": CapitalInfo.model_json_schema(),\n", + " },\n", + " },\n", + ")\n", + "\n", + "print_highlight(\n", + " f\"reasoing_content: {response.choices[0].message.reasoning_content}\\n\\ncontent: {response.choices[0].message.content}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**JSON Schema Directly**\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "json_schema = json.dumps(\n", + " {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"name\": {\"type\": \"string\", \"pattern\": \"^[\\\\w]+$\"},\n", + " \"population\": {\"type\": \"integer\"},\n", + " },\n", + " \"required\": [\"name\", \"population\"],\n", + " }\n", + ")\n", + "\n", + "response = client.chat.completions.create(\n", + " model=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\",\n", + " messages=[\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Give me the information and population of the capital of France in the JSON format.\",\n", + " },\n", + " ],\n", + " temperature=0,\n", + " max_tokens=2048,\n", + " response_format={\n", + " \"type\": \"json_schema\",\n", + " \"json_schema\": {\"name\": \"foo\", \"schema\": json.loads(json_schema)},\n", + " },\n", + ")\n", + "\n", + "print_highlight(\n", + " f\"reasoing_content: {response.choices[0].message.reasoning_content}\\n\\ncontent: {response.choices[0].message.content}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EBNF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ebnf_grammar = \"\"\"\n", + "root ::= city | description\n", + "city ::= \"London\" | \"Paris\" | \"Berlin\" | \"Rome\"\n", + "description ::= city \" is \" status\n", + "status ::= \"the capital of \" country\n", + "country ::= \"England\" | \"France\" | \"Germany\" | \"Italy\"\n", + "\"\"\"\n", + "\n", + "response = client.chat.completions.create(\n", + " model=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\",\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": \"You are a helpful geography bot.\"},\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Give me the information and population of the capital of France in the JSON format.\",\n", + " },\n", + " ],\n", + " temperature=0,\n", + " max_tokens=2048,\n", + " extra_body={\"ebnf\": ebnf_grammar},\n", + ")\n", + "\n", + "print_highlight(\n", + " f\"reasoing_content: {response.choices[0].message.reasoning_content}\\n\\ncontent: {response.choices[0].message.content}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Regular expression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = client.chat.completions.create(\n", + " model=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\",\n", + " messages=[\n", + " {\"role\": \"assistant\", \"content\": \"What is the capital of France?\"},\n", + " ],\n", + " temperature=0,\n", + " max_tokens=2048,\n", + " extra_body={\"regex\": \"(Paris|London)\"},\n", + ")\n", + "\n", + "print_highlight(\n", + " f\"reasoing_content: {response.choices[0].message.reasoning_content}\\n\\ncontent: {response.choices[0].message.content}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Structural Tag" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tool_get_current_weather = {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"get_current_weather\",\n", + " \"description\": \"Get the current weather in a given location\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"city\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The city to find the weather for, e.g. 'San Francisco'\",\n", + " },\n", + " \"state\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"the two-letter abbreviation for the state that the city is\"\n", + " \" in, e.g. 'CA' which would mean 'California'\",\n", + " },\n", + " \"unit\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The unit to fetch the temperature in\",\n", + " \"enum\": [\"celsius\", \"fahrenheit\"],\n", + " },\n", + " },\n", + " \"required\": [\"city\", \"state\", \"unit\"],\n", + " },\n", + " },\n", + "}\n", + "\n", + "tool_get_current_date = {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"get_current_date\",\n", + " \"description\": \"Get the current date and time for a given timezone\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"timezone\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The timezone to fetch the current date and time for, e.g. 'America/New_York'\",\n", + " }\n", + " },\n", + " \"required\": [\"timezone\"],\n", + " },\n", + " },\n", + "}\n", + "\n", + "schema_get_current_weather = tool_get_current_weather[\"function\"][\"parameters\"]\n", + "schema_get_current_date = tool_get_current_date[\"function\"][\"parameters\"]\n", + "\n", + "\n", + "def get_messages():\n", + " return [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": f\"\"\"\n", + "# Tool Instructions\n", + "- Always execute python code in messages that you share.\n", + "- When looking for real time information use relevant functions if available else fallback to brave_search\n", + "You have access to the following functions:\n", + "Use the function 'get_current_weather' to: Get the current weather in a given location\n", + "{tool_get_current_weather[\"function\"]}\n", + "Use the function 'get_current_date' to: Get the current date and time for a given timezone\n", + "{tool_get_current_date[\"function\"]}\n", + "If a you choose to call a function ONLY reply in the following format:\n", + "<{{start_tag}}={{function_name}}>{{parameters}}{{end_tag}}\n", + "where\n", + "start_tag => ` a JSON dict with the function argument name as key and function argument value as value.\n", + "end_tag => ``\n", + "Here is an example,\n", + "{{\"example_name\": \"example_value\"}}\n", + "Reminder:\n", + "- Function calls MUST follow the specified format\n", + "- Required parameters MUST be specified\n", + "- Only call one function at a time\n", + "- Put the entire function call reply on one line\n", + "- Always add your sources when using search results to answer the user query\n", + "You are a helpful assistant.\"\"\",\n", + " },\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"You are in New York. Please get the current date and time, and the weather.\",\n", + " },\n", + " ]\n", + "\n", + "\n", + "messages = get_messages()\n", + "\n", + "response = client.chat.completions.create(\n", + " model=\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\",\n", + " messages=messages,\n", + " response_format={\n", + " \"type\": \"structural_tag\",\n", + " \"max_new_tokens\": 2048,\n", + " \"structures\": [\n", + " {\n", + " \"begin\": \"\",\n", + " \"schema\": schema_get_current_weather,\n", + " \"end\": \"\",\n", + " },\n", + " {\n", + " \"begin\": \"\",\n", + " \"schema\": schema_get_current_date,\n", + " \"end\": \"\",\n", + " },\n", + " ],\n", + " \"triggers\": [\" Note: For native API, as a work-around, you need to set `require_reasoning` argument to `True` to ensure the model will think before generating the structured output. It's not required for chat-completion API." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### JSON" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Using Pydantic**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from pydantic import BaseModel, Field\n", + "from transformers import AutoTokenizer\n", + "\n", + "tokenizer = AutoTokenizer.from_pretrained(\"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B\")\n", + "\n", + "\n", + "# Define the schema using Pydantic\n", + "class CapitalInfo(BaseModel):\n", + " name: str = Field(..., pattern=r\"^\\w+$\", description=\"Name of the capital city\")\n", + " population: int = Field(..., description=\"Population of the capital city\")\n", + "\n", + "\n", + "messages = [\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Give me the information and population of the capital of France in the JSON format.\",\n", + " },\n", + "]\n", + "text = tokenizer.apply_chat_template(\n", + " messages, tokenize=False, add_generation_prompt=True, return_dict=False\n", + ")\n", + "# Make API request\n", + "response = requests.post(\n", + " f\"http://localhost:{port}/generate\",\n", + " json={\n", + " \"text\": text,\n", + " \"require_reasoning\": True,\n", + " \"sampling_params\": {\n", + " \"temperature\": 0,\n", + " \"max_new_tokens\": 2048,\n", + " \"json_schema\": json.dumps(CapitalInfo.model_json_schema()),\n", + " },\n", + " },\n", + ")\n", + "print(response.json())\n", + "\n", + "\n", + "reasoing_content = response.json()[\"text\"].split(\"
\")[0]\n", + "content = response.json()[\"text\"].split(\"\")[1]\n", + "print_highlight(f\"reasoing_content: {reasoing_content}\\n\\ncontent: {content}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**JSON Schema Directly**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "json_schema = json.dumps(\n", + " {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"name\": {\"type\": \"string\", \"pattern\": \"^[\\\\w]+$\"},\n", + " \"population\": {\"type\": \"integer\"},\n", + " },\n", + " \"required\": [\"name\", \"population\"],\n", + " }\n", + ")\n", + "\n", + "# JSON\n", + "text = tokenizer.apply_chat_template(\n", + " messages, tokenize=False, add_generation_prompt=True, return_dict=False\n", + ")\n", + "response = requests.post(\n", + " f\"http://localhost:{port}/generate\",\n", + " json={\n", + " \"text\": text,\n", + " \"require_reasoning\": True,\n", + " \"sampling_params\": {\n", + " \"temperature\": 0,\n", + " \"max_new_tokens\": 2048,\n", + " \"json_schema\": json_schema,\n", + " },\n", + " },\n", + ")\n", + "\n", + "print_highlight(response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### EBNF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " f\"http://localhost:{port}/generate\",\n", + " json={\n", + " \"text\": \"Give me the information of the capital of France.\",\n", + " \"require_reasoning\": True,\n", + " \"sampling_params\": {\n", + " \"max_new_tokens\": 2048,\n", + " \"temperature\": 0,\n", + " \"n\": 3,\n", + " \"ebnf\": (\n", + " \"root ::= city | description\\n\"\n", + " 'city ::= \"London\" | \"Paris\" | \"Berlin\" | \"Rome\"\\n'\n", + " 'description ::= city \" is \" status\\n'\n", + " 'status ::= \"the capital of \" country\\n'\n", + " 'country ::= \"England\" | \"France\" | \"Germany\" | \"Italy\"'\n", + " ),\n", + " },\n", + " \"stream\": False,\n", + " \"return_logprob\": False,\n", + " },\n", + ")\n", + "\n", + "print(response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Regular expression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response = requests.post(\n", + " f\"http://localhost:{port}/generate\",\n", + " json={\n", + " \"text\": \"Paris is the capital of\",\n", + " \"require_reasoning\": True,\n", + " \"sampling_params\": {\n", + " \"temperature\": 0,\n", + " \"max_new_tokens\": 2048,\n", + " \"regex\": \"(France|England)\",\n", + " },\n", + " },\n", + ")\n", + "print(response.json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Structural Tag" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "text = tokenizer.apply_chat_template(\n", + " messages, tokenize=False, add_generation_prompt=True, return_dict=False\n", + ")\n", + "payload = {\n", + " \"text\": text,\n", + " \"require_reasoning\": True,\n", + " \"sampling_params\": {\n", + " \"max_new_tokens\": 2048,\n", + " \"structural_tag\": json.dumps(\n", + " {\n", + " \"type\": \"structural_tag\",\n", + " \"structures\": [\n", + " {\n", + " \"begin\": \"\",\n", + " \"schema\": schema_get_current_weather,\n", + " \"end\": \"\",\n", + " },\n", + " {\n", + " \"begin\": \"\",\n", + " \"schema\": schema_get_current_date,\n", + " \"end\": \"\",\n", + " },\n", + " ],\n", + " \"triggers\": [\"\",\n", + " \"schema\": schema_get_current_weather,\n", + " \"end\": \"\",\n", + " },\n", + " {\n", + " \"begin\": \"\",\n", + " \"schema\": schema_get_current_date,\n", + " \"end\": \"\",\n", + " },\n", + " ],\n", + " \"triggers\": [\"*(recommended)* | 8 x H200 | +| | 8 x B200 | +| | 8 x MI300X | +| | 2 x 8 x H100/800/20 | +| | Xeon 6980P CPU | +| **Full precision ([BF16](https://huggingface.co/unsloth/DeepSeek-R1-0528-BF16))** (upcast from original FP8) | 2 x 8 x H200 | +| | 2 x 8 x MI300X | +| | 4 x 8 x H100/800/20 | +| | 4 x 8 x A100/A800 | +| **Quantized weights ([INT8](https://huggingface.co/meituan/DeepSeek-R1-Channel-INT8))** | 16 x A100/800 | +| | 32 x L40S | +| | Xeon 6980P CPU | +| | 4 x Atlas 800I A3 | +| **Quantized weights ([W4A8](https://huggingface.co/novita/Deepseek-R1-0528-W4AFP8))** | 8 x H20/100, 4 x H200 | +| **Quantized weights ([AWQ](https://huggingface.co/QuixiAI/DeepSeek-R1-0528-AWQ))** | 8 x H100/800/20 | +| | 8 x A100/A800 | +| **Quantized weights ([MXFP4](https://huggingface.co/amd/DeepSeek-R1-MXFP4-Preview))** | 8, 4 x MI355X/350X | +| **Quantized weights ([NVFP4](https://huggingface.co/nvidia/DeepSeek-R1-0528-NVFP4-v2))** | 8, 4 x B200 | + + + +```{important} +The official DeepSeek V3 is already in FP8 format, so you should not run it with any quantization arguments like `--quantization fp8`. +``` + +Detailed commands for reference: + +- [8 x H200](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#using-docker-recommended) +- [4 x B200, 8 x B200](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-one-b200-node) +- [8 x MI300X](../platforms/amd_gpu.md#running-deepseek-v3) +- [2 x 8 x H200](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-two-h208-nodes) +- [4 x 8 x A100](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-four-a1008-nodes) +- [8 x A100 (AWQ)](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-8-a100a800-with-awq-quantization) +- [16 x A100 (INT8)](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-16-a100a800-with-int8-quantization) +- [32 x L40S (INT8)](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-32-l40s-with-int8-quantization) +- [Xeon 6980P CPU](../platforms/cpu_server.md#example-running-deepseek-r1) +- [4 x Atlas 800I A3 (int8)](../platforms/ascend_npu_deepseek_example.md#running-deepseek-with-pd-disaggregation-on-4-x-atlas-800i-a3) + +### Download Weights +If you encounter errors when starting the server, ensure the weights have finished downloading. It's recommended to download them beforehand or restart multiple times until all weights are downloaded. Please refer to [DeepSeek V3](https://huggingface.co/deepseek-ai/DeepSeek-V3-Base#61-inference-with-deepseek-infer-demo-example-only) official guide to download the weights. + +### Launch with one node of 8 x H200 +Please refer to [the example](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#installation--launch). + +### Running examples on Multi-Node + +- [Deploying DeepSeek on GB200 NVL72 with PD and Large Scale EP](https://lmsys.org/blog/2025-06-16-gb200-part-1/) ([Part I](https://lmsys.org/blog/2025-06-16-gb200-part-1/), [Part II](https://lmsys.org/blog/2025-09-25-gb200-part-2/)) - Comprehensive guide on GB200 optimizations. + +- [Deploying DeepSeek with PD Disaggregation and Large-Scale Expert Parallelism on 96 H100 GPUs](https://lmsys.org/blog/2025-05-05-deepseek-pd-ep/) - Guide on PD disaggregation and large-scale EP. + +- [Serving with two H20*8 nodes](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-two-h208-nodes). + +- [Best Practices for Serving DeepSeek-R1 on H20](https://lmsys.org/blog/2025-09-26-sglang-ant-group/) - Comprehensive guide on H20 optimizations, deployment and performance. + +- [Serving with two H200*8 nodes and docker](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-two-h2008-nodes-and-docker). + +- [Serving with four A100*8 nodes](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-four-a1008-nodes). + +## Optimizations + +### Multi-head Latent Attention (MLA) Throughput Optimizations + +**Description**: [MLA](https://arxiv.org/pdf/2405.04434) is an innovative attention mechanism introduced by the DeepSeek team, aimed at improving inference efficiency. SGLang has implemented specific optimizations for this, including: + +- **Weight Absorption**: By applying the associative law of matrix multiplication to reorder computation steps, this method balances computation and memory access and improves efficiency in the decoding phase. + +- **MLA Attention Backends**: Currently SGLang supports different optimized MLA attention backends, including [FlashAttention3](https://github.com/Dao-AILab/flash-attention), [Flashinfer](https://docs.flashinfer.ai/api/attention.html#flashinfer-mla), [FlashMLA](https://github.com/deepseek-ai/FlashMLA), [CutlassMLA](https://github.com/sgl-project/sglang/pull/5390), **TRTLLM MLA** (optimized for Blackwell architecture), and [Triton](https://github.com/triton-lang/triton) backends. The default FA3 provides good performance across wide workloads. + +- **FP8 Quantization**: W8A8 FP8 and KV Cache FP8 quantization enables efficient FP8 inference. Additionally, we have implemented Batched Matrix Multiplication (BMM) operator to facilitate FP8 inference in MLA with weight absorption. + +- **CUDA Graph & Torch.compile**: Both MLA and Mixture of Experts (MoE) are compatible with CUDA Graph and Torch.compile, which reduces latency and accelerates decoding speed for small batch sizes. + +- **Chunked Prefix Cache**: Chunked prefix cache optimization can increase throughput by cutting prefix cache into chunks, processing them with multi-head attention and merging their states. Its improvement can be significant when doing chunked prefill on long sequences. Currently this optimization is only available for FlashAttention3 backend. + +Overall, with these optimizations, we have achieved up to **7x** acceleration in output throughput compared to the previous version. + +

+ Multi-head Latent Attention for DeepSeek Series Models +

+ +**Usage**: MLA optimization is enabled by default. + +**Reference**: Check [Blog](https://lmsys.org/blog/2024-09-04-sglang-v0-3/#deepseek-multi-head-latent-attention-mla-throughput-optimizations) and [Slides](https://github.com/sgl-project/sgl-learning-materials/blob/main/slides/lmsys_1st_meetup_deepseek_mla.pdf) for more details. + +### Data Parallelism Attention + +**Description**: This optimization involves data parallelism (DP) for the MLA attention mechanism of DeepSeek Series Models, which allows for a significant reduction in the KV cache size, enabling larger batch sizes. Each DP worker independently handles different types of batches (prefill, decode, idle), which are then synchronized before and after processing through the Mixture-of-Experts (MoE) layer. If you do not use DP attention, KV cache will be duplicated among all TP ranks. + +

+ Data Parallelism Attention for DeepSeek Series Models +

+ +With data parallelism attention enabled, we have achieved up to **1.9x** decoding throughput improvement compared to the previous version. + +

+ Data Parallelism Attention Performance Comparison +

+ +**Usage**: +- Append `--enable-dp-attention --tp 8 --dp 8` to the server arguments when using 8 H200 GPUs. This optimization improves peak throughput in high batch size scenarios where the server is limited by KV cache capacity. +- DP and TP attention can be flexibly combined. For example, to deploy DeepSeek-V3/R1 on 2 nodes with 8 H100 GPUs each, you can specify `--enable-dp-attention --tp 16 --dp 2`. This configuration runs attention with 2 DP groups, each containing 8 TP GPUs. + +```{caution} +Data parallelism attention is not recommended for low-latency, small-batch use cases. It is optimized for high-throughput scenarios with large batch sizes. +``` + +**Reference**: Check [Blog](https://lmsys.org/blog/2024-12-04-sglang-v0-4/#data-parallelism-attention-for-deepseek-models). + +### Multi-Node Tensor Parallelism + +**Description**: For users with limited memory on a single node, SGLang supports serving DeepSeek Series Models, including DeepSeek V3, across multiple nodes using tensor parallelism. This approach partitions the model parameters across multiple GPUs or nodes to handle models that are too large for one node's memory. + +**Usage**: Check [here](https://github.com/sgl-project/sglang/tree/main/benchmark/deepseek_v3#example-serving-with-2-h208) for usage examples. + +### Block-wise FP8 + +**Description**: SGLang implements block-wise FP8 quantization with two key optimizations: + +- **Activation**: E4M3 format using per-token-per-128-channel sub-vector scales with online casting. + +- **Weight**: Per-128x128-block quantization for better numerical stability. + +- **DeepGEMM**: The [DeepGEMM](https://github.com/deepseek-ai/DeepGEMM) kernel library optimized for FP8 matrix multiplications. + +**Usage**: The activation and weight optimization above are turned on by default for DeepSeek V3 models. DeepGEMM is enabled by default on NVIDIA Hopper/Blackwell GPUs and disabled by default on other devices. DeepGEMM can also be manually turned off by setting the environment variable `SGLANG_ENABLE_JIT_DEEPGEMM=0`. + +```{tip} +Before serving the DeepSeek model, precompile the DeepGEMM kernels to improve first-run performance. The precompilation process typically takes around 10 minutes to complete. +``` + +```bash +python3 -m sglang.compile_deep_gemm --model deepseek-ai/DeepSeek-V3 --tp 8 --trust-remote-code +``` + +### Multi-token Prediction +**Description**: SGLang implements DeepSeek V3 Multi-Token Prediction (MTP) based on [EAGLE speculative decoding](https://docs.sglang.io/advanced_features/speculative_decoding.html#EAGLE-Decoding). With this optimization, the decoding speed can be improved by **1.8x** for batch size 1 and **1.5x** for batch size 32 respectively on H200 TP8 setting. + +**Usage**: +Add `--speculative-algorithm EAGLE`. Other flags, like `--speculative-num-steps`, `--speculative-eagle-topk` and `--speculative-num-draft-tokens` are optional. For example: +``` +python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3-0324 \ + --speculative-algorithm EAGLE \ + --trust-remote-code \ + --tp 8 +``` +- The default configuration for DeepSeek models is `--speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4`. The best configuration for `--speculative-num-steps`, `--speculative-eagle-topk` and `--speculative-num-draft-tokens` can be searched with [bench_speculative.py](https://github.com/sgl-project/sglang/blob/main/scripts/playground/bench_speculative.py) script for given batch size. The minimum configuration is `--speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2`, which can achieve speedup for larger batch sizes. +- Most MLA attention backends fully support MTP usage. See [MLA Backends](../advanced_features/attention_backend.md#mla-backends) for details. + +```{note} +To enable DeepSeek MTP for large batch sizes (>48), you need to adjust some parameters (Reference [this discussion](https://github.com/sgl-project/sglang/issues/4543#issuecomment-2737413756)): +- Adjust `--max-running-requests` to a larger number. The default value is `48` for MTP. For larger batch sizes, you should increase this value beyond the default value. +- Set `--cuda-graph-bs`. It's a list of batch sizes for cuda graph capture. The [default captured batch sizes for speculative decoding](https://github.com/sgl-project/sglang/blob/main/python/sglang/srt/server_args.py#L888-L895) is 48. You can customize this by including more batch sizes. +``` + +```{tip} +To enable the experimental overlap scheduler for EAGLE speculative decoding, set the environment variable `SGLANG_ENABLE_SPEC_V2=1`. This can improve performance by enabling overlap scheduling between draft and verification stages. +``` + + +### Reasoning Content for DeepSeek R1 & V3.1 + +See [Reasoning Parser](https://docs.sglang.io/advanced_features/separate_reasoning.html) and [Thinking Parameter for DeepSeek V3.1](https://docs.sglang.io/basic_usage/openai_api_completions.html#Example:-DeepSeek-V3-Models). + + +### Function calling for DeepSeek Models + +Add arguments `--tool-call-parser deepseekv3` and `--chat-template ./examples/chat_template/tool_chat_template_deepseekv3.jinja`(recommended) to enable this feature. For example (running on 1 * H20 node): + +``` +python3 -m sglang.launch_server \ + --model deepseek-ai/DeepSeek-V3-0324 \ + --tp 8 \ + --port 30000 \ + --host 0.0.0.0 \ + --mem-fraction-static 0.9 \ + --tool-call-parser deepseekv3 \ + --chat-template ./examples/chat_template/tool_chat_template_deepseekv3.jinja +``` + +Sample Request: + +``` +curl "http://127.0.0.1:30000/v1/chat/completions" \ +-H "Content-Type: application/json" \ +-d '{"temperature": 0, "max_tokens": 100, "model": "deepseek-ai/DeepSeek-V3-0324", "tools": [{"type": "function", "function": {"name": "query_weather", "description": "Get weather of a city, the user should supply a city first", "parameters": {"type": "object", "properties": {"city": {"type": "string", "description": "The city, e.g. Beijing"}}, "required": ["city"]}}}], "messages": [{"role": "user", "content": "How'\''s the weather like in Qingdao today"}]}' +``` + +Expected Response + +``` +{"id":"6501ef8e2d874006bf555bc80cddc7c5","object":"chat.completion","created":1745993638,"model":"deepseek-ai/DeepSeek-V3-0324","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning_content":null,"tool_calls":[{"id":"0","index":null,"type":"function","function":{"name":"query_weather","arguments":"{\"city\": \"Qingdao\"}"}}]},"logprobs":null,"finish_reason":"tool_calls","matched_stop":null}],"usage":{"prompt_tokens":116,"total_tokens":138,"completion_tokens":22,"prompt_tokens_details":null}} + +``` +Sample Streaming Request: +``` +curl "http://127.0.0.1:30000/v1/chat/completions" \ +-H "Content-Type: application/json" \ +-d '{"temperature": 0, "max_tokens": 100, "model": "deepseek-ai/DeepSeek-V3-0324","stream":true,"tools": [{"type": "function", "function": {"name": "query_weather", "description": "Get weather of a city, the user should supply a city first", "parameters": {"type": "object", "properties": {"city": {"type": "string", "description": "The city, e.g. Beijing"}}, "required": ["city"]}}}], "messages": [{"role": "user", "content": "How'\''s the weather like in Qingdao today"}]}' +``` +Expected Streamed Chunks (simplified for clarity): +``` +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"{\""}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"city"}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"\":\""}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"Q"}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"ing"}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"dao"}}]}}]} +data: {"choices":[{"delta":{"tool_calls":[{"function":{"arguments":"\"}"}}]}}]} +data: {"choices":[{"delta":{"tool_calls":null}}], "finish_reason": "tool_calls"} +data: [DONE] +``` +The client needs to concatenate all arguments fragments to reconstruct the complete tool call: +``` +{"city": "Qingdao"} +``` + +```{important} +1. Use a lower `"temperature"` value for better results. +2. To receive more consistent tool call results, it is recommended to use `--chat-template examples/chat_template/tool_chat_template_deepseekv3.jinja`. It provides an improved unified prompt. +``` + + +### Thinking Budget for DeepSeek R1 + +In SGLang, we can implement thinking budget with `CustomLogitProcessor`. + +Launch a server with `--enable-custom-logit-processor` flag on. + +``` +python3 -m sglang.launch_server --model deepseek-ai/DeepSeek-R1 --tp 8 --port 30000 --host 0.0.0.0 --mem-fraction-static 0.9 --disable-cuda-graph --reasoning-parser deepseek-r1 --enable-custom-logit-processor +``` + +Sample Request: + +```python +import openai +from rich.pretty import pprint +from sglang.srt.sampling.custom_logit_processor import DeepSeekR1ThinkingBudgetLogitProcessor + + +client = openai.Client(base_url="http://127.0.0.1:30000/v1", api_key="*") +response = client.chat.completions.create( + model="deepseek-ai/DeepSeek-R1", + messages=[ + { + "role": "user", + "content": "Question: Is Paris the Capital of France?", + } + ], + max_tokens=1024, + extra_body={ + "custom_logit_processor": DeepSeekR1ThinkingBudgetLogitProcessor().to_str(), + "custom_params": { + "thinking_budget": 512, + }, + }, +) +pprint(response) +``` + +## FAQ + +**Q: Model loading is taking too long, and I'm encountering an NCCL timeout. What should I do?** + +A: If you're experiencing extended model loading times and an NCCL timeout, you can try increasing the timeout duration. Add the argument `--dist-timeout 3600` when launching your model. This will set the timeout to one hour, which often resolves the issue. diff --git a/sglang/docs/basic_usage/qwen3_5.md b/sglang/docs/basic_usage/qwen3_5.md new file mode 100644 index 0000000000000000000000000000000000000000..06f7b615eef590cb54cccff5ca339ed6534ebfe1 --- /dev/null +++ b/sglang/docs/basic_usage/qwen3_5.md @@ -0,0 +1,76 @@ +# Qwen 3.5 Usage + +Qwen 3.5 is Alibaba's latest generation LLM featuring a hybrid attention architecture, advanced MoE with shared experts, and native multimodal capabilities. + +Key architecture features: +- **Hybrid Attention**: Gated Delta Networks (linear, O(n) complexity) combined with full attention every 4th layer for high associative recall +- **MoE with Shared Experts**: Top-8 active out of 64 routed experts plus a dedicated shared expert for universal features +- **Multimodal**: DeepStack Vision Transformer with Conv3d for native image and video understanding + +## Launch Qwen 3.5 with SGLang + +### Dense Model + +To serve `Qwen/Qwen3.5-397B-A17B` on 8 GPUs: + +```bash +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3.5-397B-A17B \ + --tp 8 \ + --trust-remote-code +``` + +### AMD GPU (MI300X / MI325X / MI35X) + +On AMD Instinct GPUs, use the `triton` attention backend. Both the full attention layers and the Gated Delta Net (linear attention) layers use Triton-based kernels on ROCm: + +```bash +SGLANG_USE_AITER=1 python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3.5-397B-A17B \ + --tp 8 \ + --attention-backend triton \ + --trust-remote-code +``` + +```{tip} +Set `SGLANG_USE_AITER=1` to enable AMD's optimized aiter kernels for MoE and GEMM operations. +``` + +### Configuration Tips + +- `--attention-backend`: Use `triton` on AMD GPUs for Qwen 3.5. The hybrid attention architecture (Gated Delta Networks + full attention) works best with the Triton backend on ROCm. The linear attention (GDN) layers always use Triton kernels internally via the `GDNAttnBackend`. +- `--watchdog-timeout`: Increase to `1200` or higher for this large model, as weight loading takes significant time. +- `--model-loader-extra-config '{"enable_multithread_load": true}'`: Enables parallel weight loading for faster startup. + +### Reasoning and Tool Calling + +Qwen 3.5 supports reasoning and tool calling via the Qwen3 parsers: + +```bash +python3 -m sglang.launch_server \ + --model-path Qwen/Qwen3.5-397B-A17B \ + --tp 8 \ + --trust-remote-code \ + --reasoning-parser qwen3 \ + --tool-call-parser qwen3_coder +``` + +## Accuracy Evaluation + +You can evaluate the model accuracy using `lm-eval`: + +```bash +pip install lm-eval[api] + +lm_eval --model local-completions \ + --model_args '{"base_url": "http://localhost:8000/v1/completions", "model": "Qwen/Qwen3.5-397B-A17B", "num_concurrent": 256, "max_retries": 10, "max_gen_toks": 2048}' \ + --tasks gsm8k \ + --batch_size auto \ + --num_fewshot 5 \ + --trust_remote_code +``` + +## Additional Resources + +- [AMD Day 0 Support for Qwen 3.5 on AMD Instinct GPUs](https://www.amd.com/en/developer/resources/technical-articles/2026/day-0-support-for-qwen-3-5-on-amd-instinct-gpus.html) +- [HuggingFace Model Card](https://huggingface.co/Qwen/Qwen3.5-397B-A17B) diff --git a/sglang/docs/performance_dashboard/README.md b/sglang/docs/performance_dashboard/README.md new file mode 100644 index 0000000000000000000000000000000000000000..857dc26a8dfce13ca85cb44eb30be61ac3676ad4 --- /dev/null +++ b/sglang/docs/performance_dashboard/README.md @@ -0,0 +1,147 @@ +# SGLang Performance Dashboard + +A web-based dashboard for visualizing SGLang nightly test performance metrics. + +## Features + +- **Performance Trends**: View throughput, latency, and TTFT trends over time +- **Model Comparison**: Compare performance across different models and configurations +- **Filtering**: Filter by GPU configuration, model, variant, and batch size +- **Interactive Charts**: Zoom, pan, and hover for detailed metrics +- **Run History**: View recent benchmark runs with links to GitHub Actions + +## Quick Start + +### Option 1: Run with Local Server (Recommended) + +For live data from GitHub Actions artifacts: + +```bash +# Install requirements +pip install requests + +# Run the server +python server.py --fetch-on-start + +# Visit http://localhost:8000 +``` + +The server provides: +- Automatic fetching of metrics from GitHub +- Caching to reduce API calls +- `/api/metrics` endpoint for the frontend + +### Option 2: Fetch Data Manually + +Use the fetch script to download metrics data: + +```bash +# Fetch last 30 days of metrics +python fetch_metrics.py --output metrics_data.json + +# Fetch a specific run +python fetch_metrics.py --run-id 21338741812 --output single_run.json + +# Fetch only scheduled (nightly) runs +python fetch_metrics.py --scheduled-only --days 7 +``` + +## GitHub Token + +To download artifacts from GitHub, you need authentication: + +1. **Using `gh` CLI** (recommended): + ```bash + gh auth login + ``` + +2. **Using environment variable**: + ```bash + export GITHUB_TOKEN=your_token_here + ``` + +Without a token, the dashboard will show run metadata but not detailed benchmark results. + +## Data Structure + +The metrics JSON has this structure: + +```json +{ + "run_id": "21338741812", + "run_date": "2026-01-25T22:24:02.090218+00:00", + "commit_sha": "5cdb391...", + "branch": "main", + "results": [ + { + "gpu_config": "8-gpu-h200", + "partition": 0, + "model": "deepseek-ai/DeepSeek-V3.1", + "variant": "TP8+MTP", + "benchmarks": [ + { + "batch_size": 1, + "input_len": 4096, + "output_len": 512, + "latency_ms": 2400.72, + "input_throughput": 21408.64, + "output_throughput": 231.74, + "overall_throughput": 1919.43, + "ttft_ms": 191.32, + "acc_length": 3.19 + } + ] + } + ] +} +``` + +## Deployment + +### GitHub Pages + +The dashboard can be deployed to GitHub Pages for public access: + +1. Copy the dashboard files to `docs/performance_dashboard/` +2. Enable GitHub Pages in repository settings +3. Set up a GitHub Action to periodically update metrics data + +### Self-Hosted + +For a self-hosted deployment with live data: + +1. Set up a server running `server.py` +2. Configure a cron job or systemd timer to refresh data +3. Optionally put behind nginx/caddy for SSL + +## Metrics Explained + +- **Overall Throughput**: Total tokens (input + output) processed per second +- **Input Throughput**: Input tokens processed per second (prefill speed) +- **Output Throughput**: Output tokens generated per second (decode speed) +- **Latency**: End-to-end time to complete the request +- **TTFT**: Time to First Token - time until the first output token +- **Acc Length**: Acceptance length for speculative decoding (MTP variants) + +## Contributing + +To add support for new metrics or visualizations: + +1. Update `fetch_metrics.py` if data collection needs changes +2. Modify `app.js` to add new chart types or filters +3. Update `index.html` for UI changes + +## Troubleshooting + +**No data displayed** +- Check browser console for errors +- Verify GitHub API is accessible +- Try running with `server.py --fetch-on-start` + +**API rate limits** +- Use a GitHub token for higher limits +- The server caches data for 5 minutes + +**Charts not rendering** +- Ensure Chart.js is loading from CDN +- Check for JavaScript errors in console diff --git a/sglang/docs/performance_dashboard/app.js b/sglang/docs/performance_dashboard/app.js new file mode 100644 index 0000000000000000000000000000000000000000..8bfb12b2ed0cef9f17bd36d8855a6f33086f2953 --- /dev/null +++ b/sglang/docs/performance_dashboard/app.js @@ -0,0 +1,1056 @@ +// SGLang Performance Dashboard Application + +const GITHUB_REPO = 'sgl-project/sglang'; +const WORKFLOW_NAME = 'nightly-test-nvidia.yml'; +const ARTIFACT_PREFIX = 'consolidated-metrics-'; + +// Chart instances (array for batch-separated charts) +let activeCharts = []; + +// Data storage +let allMetricsData = []; +let currentModel = null; +let currentMetricType = 'throughput'; // throughput, latency, ttft, inputThroughput + +// Metric type definitions +const metricTypes = { + // Text/VLM metrics + throughput: { label: 'Overall Throughput', unit: 'tokens/sec', field: 'throughput', type: 'text' }, + outputThroughput: { label: 'Output Throughput', unit: 'tokens/sec', field: 'outputThroughput', type: 'text' }, + inputThroughput: { label: 'Input Throughput', unit: 'tokens/sec', field: 'inputThroughput', type: 'text' }, + latency: { label: 'Latency', unit: 'ms', field: 'latency', type: 'text' }, + ttft: { label: 'Time to First Token', unit: 'ms', field: 'ttft', type: 'text' }, + accLength: { label: 'Accept Length', unit: 'tokens', field: 'accLength', filterInvalid: true, type: 'text' }, + // Diffusion metrics + e2eMs: { label: 'End-to-End Time', unit: 'ms', field: 'e2e_ms', type: 'diffusion' }, + avgDenoiseMs: { label: 'Avg Denoise Time', unit: 'ms', field: 'avg_denoise_ms', type: 'diffusion' }, + medianDenoiseMs: { label: 'Median Denoise Time', unit: 'ms', field: 'median_denoise_ms', type: 'diffusion' } +}; + +// Chart.js default configuration for dark theme +Chart.defaults.color = '#94a3b8'; +Chart.defaults.borderColor = '#1e293b'; + +const chartColors = [ + '#22d3ee', '#34d399', '#fbbf24', '#f87171', '#a78bfa', + '#67e8f9', '#6ee7b7', '#fcd34d', '#fca5a5', '#c4b5fd' +]; + +// Initialize the dashboard +async function init() { + try { + await loadData(); + document.getElementById('loading').style.display = 'none'; + document.getElementById('content').style.display = 'block'; + populateFilters(); + updateStats(); + updateCharts(); + updateRunsTable(); + } catch (error) { + console.error('Failed to initialize dashboard:', error); + document.getElementById('loading').style.display = 'none'; + document.getElementById('error').style.display = 'block'; + document.getElementById('error-message').textContent = error.message; + } +} + +// Load data from local server API or GitHub +async function loadData() { + // Try local server API first (if running server.py) + try { + const response = await fetch('/api/metrics', { headers: getAuthHeaders() }); + if (response.ok) { + const data = await response.json(); + if (data.length > 0 && data[0].results && data[0].results.length > 0) { + allMetricsData = data; + console.log(`Loaded ${data.length} records from local API`); + allMetricsData.sort((a, b) => new Date(b.run_date) - new Date(a.run_date)); + return; + } + } + } catch (error) { + console.log('Local API not available, trying GitHub API'); + } + + // Try to load from GitHub API + const runs = await fetchWorkflowRuns(); + const metricsPromises = runs.map(run => fetchMetricsForRun(run)); + const results = await Promise.allSettled(metricsPromises); + + allMetricsData = results + .filter(r => r.status === 'fulfilled' && r.value !== null) + .map(r => r.value); + + if (allMetricsData.length === 0) { + throw new Error('No metrics data available. Please run the server.py with --fetch-on-start to fetch data from GitHub.'); + } + + // Sort by date descending + allMetricsData.sort((a, b) => new Date(b.run_date) - new Date(a.run_date)); +} + +// Fetch workflow runs from GitHub API +async function fetchWorkflowRuns() { + const response = await fetch( + `https://api.github.com/repos/${GITHUB_REPO}/actions/workflows/${WORKFLOW_NAME}/runs?status=completed&per_page=30`, + { + headers: { + 'Accept': 'application/vnd.github.v3+json' + } + } + ); + + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status}`); + } + + const data = await response.json(); + return data.workflow_runs || []; +} + +// Fetch metrics artifact for a specific run +async function fetchMetricsForRun(run) { + try { + // Get artifacts for this run + const artifactsResponse = await fetch( + `https://api.github.com/repos/${GITHUB_REPO}/actions/runs/${run.id}/artifacts`, + { + headers: { + 'Accept': 'application/vnd.github.v3+json' + } + } + ); + + if (!artifactsResponse.ok) return null; + + const artifactsData = await artifactsResponse.json(); + const metricsArtifact = artifactsData.artifacts.find( + a => a.name.startsWith(ARTIFACT_PREFIX) + ); + + if (!metricsArtifact) return null; + + // Note: GitHub API doesn't allow direct artifact download without authentication + // For public access, we would need to use a proxy or pre-process the data + // For now, return run metadata - in production, use a backend to fetch artifacts + return { + run_id: run.id.toString(), + run_date: run.created_at, + commit_sha: run.head_sha, + branch: run.head_branch, + artifact_id: metricsArtifact.id, + results: [] // Would be populated from artifact content + }; + } catch (error) { + console.warn(`Failed to fetch metrics for run ${run.id}:`, error); + return null; + } +} + +// Helper function to detect if result is diffusion type +function isDiffusionResult(result) { + return result.test_type === 'diffusion' || (result.tests && !result.benchmarks); +} + +// Populate filter dropdowns +function populateFilters() { + const gpuConfigs = new Set(); + const models = new Set(); + const testNames = new Set(); // For diffusion tests + const batchSizes = new Set(); + const ioLengths = new Set(); + + allMetricsData.forEach(run => { + run.results.forEach(result => { + gpuConfigs.add(result.gpu_config); + + // Handle diffusion results + if (isDiffusionResult(result)) { + models.add(result.test_suite || 'diffusion'); + if (result.tests) { + result.tests.forEach(test => { + testNames.add(test.test_name); + }); + } + } + // Handle text/VLM results + else { + models.add(result.model); + // Try new structure first (benchmarks_by_io_len), fall back to flat benchmarks + if (result.benchmarks_by_io_len) { + Object.entries(result.benchmarks_by_io_len).forEach(([ioKey, ioData]) => { + ioLengths.add(ioKey); + ioData.benchmarks.forEach(bench => { + batchSizes.add(bench.batch_size); + }); + }); + } else if (result.benchmarks) { + result.benchmarks.forEach(bench => { + batchSizes.add(bench.batch_size); + if (bench.input_len && bench.output_len) { + ioLengths.add(`${bench.input_len}_${bench.output_len}`); + } + }); + } + } + }); + }); + + // No "all" option for GPU and Model - populate with first value selected + const gpuArray = Array.from(gpuConfigs).sort(); + const modelArray = Array.from(models).sort(); + + populateSelectNoAll('gpu-filter', gpuArray); + populateSelectNoAll('model-filter', modelArray); + populateSelect('batch-filter', Array.from(batchSizes).sort((a, b) => a - b)); + populateSelectWithLabels('io-len-filter', sortIoLengths(Array.from(ioLengths)), formatIoLenLabel); + + // Set initial values (first option) + if (gpuArray.length > 0) { + document.getElementById('gpu-filter').value = gpuArray[0]; + } + if (modelArray.length > 0) { + document.getElementById('model-filter').value = modelArray[0]; + currentModel = modelArray[0]; + } + + // Update variants based on selected model + updateVariantFilter(); + // Update IO length filter based on selected GPU/model + updateIoLenFilter(); + + // Create metric type tabs + createMetricTabs(); +} + +// Format input/output length key for display +function formatIoLenLabel(ioKey) { + if (!ioKey) return 'Unknown'; + const parts = ioKey.split('_'); + if (parts.length === 2) { + return `In: ${parts[0]}, Out: ${parts[1]}`; + } + return ioKey; +} + +// Sort IO length keys numerically (by input length, then output length) +function sortIoLengths(ioLengths) { + return ioLengths.filter(key => key && key.includes('_')).sort((a, b) => { + const [aIn, aOut] = a.split('_').map(Number); + const [bIn, bOut] = b.split('_').map(Number); + if (isNaN(aIn) || isNaN(bIn)) return 0; + return (aIn - bIn) || (aOut - bOut); + }); +} + +// Populate select with custom label formatting +function populateSelectWithLabels(selectId, options, labelFormatter) { + const select = document.getElementById(selectId); + options.forEach(option => { + const opt = document.createElement('option'); + opt.value = option; + opt.textContent = labelFormatter ? labelFormatter(option) : option; + select.appendChild(opt); + }); +} + +// Update IO length filter based on selected GPU and model +function updateIoLenFilter() { + const gpuFilterEl = document.getElementById('gpu-filter'); + const modelFilterEl = document.getElementById('model-filter'); + const ioLenSelect = document.getElementById('io-len-filter'); + if (!gpuFilterEl || !modelFilterEl || !ioLenSelect) return; + + const gpuFilter = gpuFilterEl.value; + const modelFilter = modelFilterEl.value; + + const ioLengths = new Set(); + + allMetricsData.forEach(run => { + run.results.forEach(result => { + if (result.gpu_config === gpuFilter && result.model === modelFilter) { + if (result.benchmarks_by_io_len) { + Object.keys(result.benchmarks_by_io_len).forEach(ioKey => { + ioLengths.add(ioKey); + }); + } else if (result.benchmarks) { + result.benchmarks.forEach(bench => { + if (bench.input_len && bench.output_len) { + ioLengths.add(`${bench.input_len}_${bench.output_len}`); + } + }); + } + } + }); + }); + + const ioLenArray = sortIoLengths(Array.from(ioLengths)); + const currentIoLen = ioLenSelect.value; + + // Clear and repopulate + ioLenSelect.innerHTML = ''; + ioLenArray.forEach(ioLen => { + const opt = document.createElement('option'); + opt.value = ioLen; + opt.textContent = formatIoLenLabel(ioLen); + ioLenSelect.appendChild(opt); + }); + + // Try to restore previous selection if still valid + if (ioLenArray.includes(currentIoLen)) { + ioLenSelect.value = currentIoLen; + } else { + ioLenSelect.value = 'all'; + } +} + +// Update variant filter based on selected GPU and model +function updateVariantFilter() { + const gpuFilter = document.getElementById('gpu-filter').value; + const modelFilter = document.getElementById('model-filter').value; + + const variants = new Set(); + + allMetricsData.forEach(run => { + run.results.forEach(result => { + if (result.gpu_config === gpuFilter && result.model === modelFilter) { + // Use 'default' for null/undefined variants + variants.add(result.variant || 'default'); + } + }); + }); + + const variantArray = Array.from(variants).sort(); + const variantSelect = document.getElementById('variant-filter'); + const currentVariant = variantSelect.value; + + // Clear and repopulate + variantSelect.innerHTML = ''; + variantArray.forEach(variant => { + const opt = document.createElement('option'); + opt.value = variant; + opt.textContent = variant; + variantSelect.appendChild(opt); + }); + + // Try to restore previous selection if still valid + if (variantArray.includes(currentVariant)) { + variantSelect.value = currentVariant; + } else { + variantSelect.value = 'all'; + } +} + +function populateSelect(selectId, options) { + const select = document.getElementById(selectId); + options.forEach(option => { + const opt = document.createElement('option'); + opt.value = option; + opt.textContent = option; + select.appendChild(opt); + }); +} + +function populateSelectNoAll(selectId, options) { + const select = document.getElementById(selectId); + // Remove the "all" option if present + while (select.options.length > 0) { + select.remove(0); + } + options.forEach(option => { + const opt = document.createElement('option'); + opt.value = option; + opt.textContent = option; + select.appendChild(opt); + }); +} + +function createMetricTabs() { + const tabsContainer = document.getElementById('metric-tabs'); + tabsContainer.innerHTML = ''; + + // Detect if current data is diffusion or text + const isDiffusion = detectCurrentDataType() === 'diffusion'; + const dataType = isDiffusion ? 'diffusion' : 'text'; + + // Filter metrics based on data type + const relevantMetrics = Object.entries(metricTypes).filter(([key, metric]) => + metric.type === dataType + ); + + relevantMetrics.forEach(([key, metric], index) => { + const tab = document.createElement('div'); + tab.className = index === 0 ? 'tab active' : 'tab'; + tab.textContent = metric.label; + tab.dataset.metric = key; + tab.onclick = () => selectMetricTab(key, tab); + tabsContainer.appendChild(tab); + }); + + // Set initial metric type + if (relevantMetrics.length > 0) { + currentMetricType = relevantMetrics[0][0]; + } +} + +function detectCurrentDataType() { + // Check if currently selected model/GPU config has diffusion data + const gpuFilter = document.getElementById('gpu-filter')?.value; + const modelFilter = currentModel; + + if (!gpuFilter || !modelFilter) return 'text'; + + for (const run of allMetricsData) { + for (const result of run.results) { + if (result.gpu_config === gpuFilter) { + const resultModel = result.test_suite || result.model; + if (resultModel === modelFilter && isDiffusionResult(result)) { + return 'diffusion'; + } + } + } + } + return 'text'; +} + +function selectMetricTab(metricKey, tabElement) { + document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); + tabElement.classList.add('active'); + currentMetricType = metricKey; + + // Update chart title + const metric = metricTypes[metricKey]; + document.getElementById('metric-title').textContent = `${metric.label} (${metric.unit})`; + + updateCharts(); +} + +// Handle model filter dropdown change +function handleModelFilterChange(model) { + currentModel = model; + // Update variant filter based on new model selection + updateVariantFilter(); + // Update IO length filter based on new model selection + updateIoLenFilter(); + // Recreate metric tabs in case data type changed (text vs diffusion) + createMetricTabs(); + updateCharts(); +} + +// Handle GPU filter change +function handleGpuFilterChange() { + // Update variant filter based on new GPU selection + updateVariantFilter(); + // Update IO length filter based on new GPU selection + updateIoLenFilter(); + // Recreate metric tabs in case data type changed (text vs diffusion) + createMetricTabs(); + updateCharts(); +} + +// Update summary stats +function updateStats() { + const statsRow = document.getElementById('stats-row'); + const latestRun = allMetricsData[0]; + + if (!latestRun) { + statsRow.innerHTML = ''; + const noDataDiv = document.createElement('div'); + noDataDiv.className = 'no-data'; + noDataDiv.textContent = 'No data available'; + statsRow.appendChild(noDataDiv); + return; + } + + const totalModels = new Set(latestRun.results.map(r => r.model)).size; + const totalBenchmarks = latestRun.results.reduce((sum, r) => { + // Count benchmarks from either structure + if (r.benchmarks_by_io_len) { + return sum + Object.values(r.benchmarks_by_io_len).reduce( + (ioSum, ioData) => ioSum + ioData.benchmarks.length, 0 + ); + } + return sum + (r.benchmarks ? r.benchmarks.length : 0); + }, 0); + + statsRow.innerHTML = ''; // Clear previous stats + + const addStat = (label, value) => { + const card = document.createElement('div'); + card.className = 'stat-card'; + const labelEl = document.createElement('div'); + labelEl.className = 'label'; + labelEl.textContent = label; + const valueEl = document.createElement('div'); + valueEl.className = 'value'; + valueEl.textContent = value; + card.appendChild(labelEl); + card.appendChild(valueEl); + statsRow.appendChild(card); + }; + + addStat('Total Runs', allMetricsData.length); + addStat('Models Tested', totalModels); + addStat('Benchmarks', totalBenchmarks); +} + +// Update charts based on current filters and selected metric type +function updateCharts() { + const gpuFilter = document.getElementById('gpu-filter').value; + const modelFilter = currentModel; + const variantFilter = document.getElementById('variant-filter').value; + const ioLenFilter = document.getElementById('io-len-filter').value; + const batchFilter = document.getElementById('batch-filter').value; + + // Prepare data for charts - grouped by batch size + const chartDataByBatch = prepareChartDataByBatch(gpuFilter, modelFilter, variantFilter, ioLenFilter, batchFilter); + + // Update chart for the selected metric type + updateMetricChart(chartDataByBatch, currentMetricType); +} + +function prepareChartData(gpuFilter, modelFilter, variantFilter, ioLenFilter, batchFilter) { + const seriesMap = new Map(); + + allMetricsData.forEach(run => { + const runDate = new Date(run.run_date); + + run.results.forEach(result => { + // Apply filters + if (result.gpu_config !== gpuFilter) return; + if (result.model !== modelFilter) return; + if (variantFilter !== 'all' && result.variant !== variantFilter) return; + + // Helper function to process a benchmark entry + const processBenchmark = (bench, ioKey) => { + if (batchFilter !== 'all' && bench.batch_size !== parseInt(batchFilter)) return; + + const ioLabel = ioKey ? `, ${formatIoLenLabel(ioKey)}` : ''; + const seriesKey = `${result.model.split('/').pop()} (${result.variant}, BS=${bench.batch_size}${ioLabel})`; + + if (!seriesMap.has(seriesKey)) { + seriesMap.set(seriesKey, { + label: seriesKey, + data: [], + model: result.model, + variant: result.variant, + batchSize: bench.batch_size, + ioKey: ioKey + }); + } + + seriesMap.get(seriesKey).data.push({ + x: runDate, + throughput: bench.overall_throughput, + outputThroughput: bench.output_throughput, + latency: bench.latency_ms, + ttft: bench.ttft_ms, + inputThroughput: bench.input_throughput, + accLength: bench.acc_length, + runId: run.run_id + }); + }; + + // Use benchmarks_by_io_len if available + if (result.benchmarks_by_io_len) { + Object.entries(result.benchmarks_by_io_len).forEach(([ioKey, ioData]) => { + if (ioLenFilter !== 'all' && ioKey !== ioLenFilter) return; + ioData.benchmarks.forEach(bench => processBenchmark(bench, ioKey)); + }); + } else if (result.benchmarks) { + result.benchmarks.forEach(bench => { + const benchIoKey = bench.input_len && bench.output_len + ? `${bench.input_len}_${bench.output_len}` + : null; + if (ioLenFilter !== 'all' && benchIoKey !== ioLenFilter) return; + processBenchmark(bench, benchIoKey); + }); + } + }); + }); + + // Sort data points by date + seriesMap.forEach(series => { + series.data.sort((a, b) => a.x - b.x); + }); + + return Array.from(seriesMap.values()); +} + +// Prepare chart data grouped by batch size - each batch size is a separate series +function prepareChartDataByBatch(gpuFilter, modelFilter, variantFilter, ioLenFilter, batchFilter) { + const batchDataMap = new Map(); // batch_size -> Map of variant -> data + const testDataMap = new Map(); // For diffusion: test_name -> data + + allMetricsData.forEach(run => { + const runDate = new Date(run.run_date); + + run.results.forEach(result => { + // Apply filters - GPU and Model are required (no "all" option) + if (result.gpu_config !== gpuFilter) return; + + // Handle diffusion results + if (isDiffusionResult(result)) { + const resultModel = result.test_suite || 'diffusion'; + if (resultModel !== modelFilter) return; + + if (result.tests) { + result.tests.forEach(test => { + const testName = test.test_name; + if (!testDataMap.has(testName)) { + testDataMap.set(testName, { + label: testName, + data: [], + model: resultModel, + testName: testName + }); + } + + testDataMap.get(testName).data.push({ + x: runDate, + e2e_ms: test.e2e_ms, + avg_denoise_ms: test.avg_denoise_ms, + median_denoise_ms: test.median_denoise_ms, + runId: run.run_id + }); + }); + } + return; + } + + // Handle text/VLM results + if (result.model !== modelFilter) return; + if (variantFilter !== 'all' && result.variant !== variantFilter) return; + + // Use benchmarks_by_io_len if available, otherwise fall back to flat benchmarks + if (result.benchmarks_by_io_len) { + Object.entries(result.benchmarks_by_io_len).forEach(([ioKey, ioData]) => { + // Apply IO length filter + if (ioLenFilter !== 'all' && ioKey !== ioLenFilter) return; + + ioData.benchmarks.forEach(bench => { + if (batchFilter !== 'all' && bench.batch_size !== parseInt(batchFilter)) return; + + const batchSize = bench.batch_size; + const variantLabel = result.variant || 'default'; + // Include IO length in series key when showing all lengths + const seriesKey = ioLenFilter === 'all' + ? `${variantLabel} (${formatIoLenLabel(ioKey)})` + : variantLabel; + + if (!batchDataMap.has(batchSize)) { + batchDataMap.set(batchSize, new Map()); + } + + const variantMap = batchDataMap.get(batchSize); + if (!variantMap.has(seriesKey)) { + variantMap.set(seriesKey, { + label: seriesKey, + data: [], + model: result.model, + variant: result.variant, + batchSize: batchSize, + ioKey: ioKey + }); + } + + variantMap.get(seriesKey).data.push({ + x: runDate, + throughput: bench.overall_throughput, + outputThroughput: bench.output_throughput, + latency: bench.latency_ms, + ttft: bench.ttft_ms, + inputThroughput: bench.input_throughput, + accLength: bench.acc_length, + runId: run.run_id + }); + }); + }); + } else if (result.benchmarks) { + // Fall back to flat benchmarks for backward compatibility + result.benchmarks.forEach(bench => { + // Apply IO length filter using flat structure + const benchIoKey = bench.input_len && bench.output_len + ? `${bench.input_len}_${bench.output_len}` + : null; + if (ioLenFilter !== 'all' && benchIoKey !== ioLenFilter) return; + if (batchFilter !== 'all' && bench.batch_size !== parseInt(batchFilter)) return; + + const batchSize = bench.batch_size; + const variantLabel = result.variant || 'default'; + // Include IO length in series key when showing all lengths + const seriesKey = ioLenFilter === 'all' && benchIoKey + ? `${variantLabel} (${formatIoLenLabel(benchIoKey)})` + : variantLabel; + + if (!batchDataMap.has(batchSize)) { + batchDataMap.set(batchSize, new Map()); + } + + const variantMap = batchDataMap.get(batchSize); + if (!variantMap.has(seriesKey)) { + variantMap.set(seriesKey, { + label: seriesKey, + data: [], + model: result.model, + variant: result.variant, + batchSize: batchSize, + ioKey: benchIoKey + }); + } + + variantMap.get(seriesKey).data.push({ + x: runDate, + throughput: bench.overall_throughput, + outputThroughput: bench.output_throughput, + latency: bench.latency_ms, + ttft: bench.ttft_ms, + inputThroughput: bench.input_throughput, + accLength: bench.acc_length, + runId: run.run_id + }); + }); + } + }); + }); + + // Sort data points by date and convert to array format + const result = {}; + + // For diffusion data, use test names as "batch sizes" + if (testDataMap.size > 0) { + testDataMap.forEach((series, testName) => { + series.data.sort((a, b) => a.x - b.x); + result[testName] = [series]; // Each test is its own series + }); + return result; + } + + // For text/VLM data, use batch sizes + batchDataMap.forEach((variantMap, batchSize) => { + variantMap.forEach(series => { + series.data.sort((a, b) => a.x - b.x); + }); + result[batchSize] = Array.from(variantMap.values()); + }); + + return result; +} + +// Unified chart update function for any metric type +function updateMetricChart(chartDataByBatch, metricType) { + const container = document.getElementById('charts-container'); + container.innerHTML = ''; + + // Destroy existing charts + activeCharts.forEach(chart => chart.destroy()); + activeCharts = []; + + const metric = metricTypes[metricType]; + const isDiffusion = metric.type === 'diffusion'; + + // For diffusion, keys are test names; for text, keys are batch sizes + const keys = Object.keys(chartDataByBatch); + if (!isDiffusion) { + keys.sort((a, b) => parseInt(a) - parseInt(b)); + } else { + keys.sort(); // Alphabetical sort for test names + } + const batchSizes = keys; // Keep variable name for compatibility + + if (batchSizes.length === 0) { + container.innerHTML = '
No data available for the selected filters
'; + return; + } + + let hasAnyData = false; + + batchSizes.forEach(batchSize => { + const chartData = chartDataByBatch[batchSize]; + + const ctx_datasets = chartData.map((series, index) => { + // Filter data points - for metrics like accLength, exclude invalid values (-1 or null) + let dataPoints = series.data.map(d => ({ x: d.x, y: d[metric.field] })); + if (metric.filterInvalid) { + dataPoints = dataPoints.filter(d => d.y != null && d.y !== -1 && d.y > 0); + } + return { + label: series.label, + data: dataPoints, + borderColor: chartColors[index % chartColors.length], + backgroundColor: chartColors[index % chartColors.length] + '20', + tension: 0.1, + fill: false + }; + }).filter(dataset => dataset.data.length > 0); // Remove empty datasets + + // Skip this batch size if no valid data + if (ctx_datasets.length === 0) { + return; + } + + hasAnyData = true; + + const chartWrapper = document.createElement('div'); + chartWrapper.className = 'batch-chart-wrapper'; + + const title = document.createElement('div'); + title.className = 'batch-chart-title'; + // For diffusion, show test name; for text, show batch size + title.textContent = isDiffusion ? `Test: ${batchSize}` : `Batch Size: ${batchSize}`; + chartWrapper.appendChild(title); + + const chartContainer = document.createElement('div'); + chartContainer.className = 'chart-container'; + const canvas = document.createElement('canvas'); + chartContainer.appendChild(canvas); + chartWrapper.appendChild(chartContainer); + container.appendChild(chartWrapper); + + const ctx = canvas.getContext('2d'); + + const chart = new Chart(ctx, { + type: 'line', + data: { datasets: ctx_datasets }, + options: getChartOptions(metric.unit) + }); + activeCharts.push(chart); + }); + + // Show message if no valid data for this metric + if (!hasAnyData) { + container.innerHTML = `
No valid ${metric.label.toLowerCase()} data available for the selected filters
`; + } +} + +function getChartOptions(yAxisLabel) { + return { + responsive: true, + maintainAspectRatio: false, + interaction: { + mode: 'index', + intersect: false + }, + plugins: { + legend: { + position: 'bottom', + labels: { + boxWidth: 12, + padding: 10, + font: { size: 11 } + } + }, + tooltip: { + backgroundColor: '#1a2332', + borderColor: 'rgba(148, 163, 184, 0.1)', + borderWidth: 1, + titleFont: { size: 13, family: "'DM Sans', sans-serif" }, + bodyFont: { size: 12, family: "'JetBrains Mono', monospace" }, + padding: 14, + cornerRadius: 8 + } + }, + scales: { + x: { + type: 'time', + time: { + unit: 'day', + displayFormats: { + day: 'MMM d' + } + }, + grid: { + color: 'rgba(148, 163, 184, 0.06)' + } + }, + y: { + title: { + display: true, + text: yAxisLabel + }, + grid: { + color: 'rgba(148, 163, 184, 0.06)' + } + } + } + }; +} + +// Escape HTML to prevent XSS +function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; +} + +// Update runs table +function updateRunsTable() { + const tbody = document.getElementById('runs-table-body'); + tbody.innerHTML = ''; + + allMetricsData.slice(0, 10).forEach(run => { + const models = new Set(run.results.map(r => r.model.split('/').pop())); + const date = new Date(run.run_date); + + const row = document.createElement('tr'); + + // Create cells safely to prevent XSS + const dateCell = document.createElement('td'); + dateCell.textContent = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; + + const runIdCell = document.createElement('td'); + const runLink = document.createElement('a'); + runLink.href = `https://github.com/${GITHUB_REPO}/actions/runs/${encodeURIComponent(run.run_id)}`; + runLink.target = '_blank'; + runLink.className = 'run-link'; + runLink.textContent = run.run_id; + runIdCell.appendChild(runLink); + + const commitCell = document.createElement('td'); + const commitCode = document.createElement('code'); + commitCode.textContent = run.commit_sha.substring(0, 7); + commitCell.appendChild(commitCode); + + const branchCell = document.createElement('td'); + branchCell.textContent = run.branch; + + const modelsCell = document.createElement('td'); + Array.from(models).forEach((model, index) => { + if (index > 0) modelsCell.appendChild(document.createTextNode(' ')); + const badge = document.createElement('span'); + badge.className = 'model-badge'; + badge.textContent = model; + modelsCell.appendChild(badge); + }); + + row.appendChild(dateCell); + row.appendChild(runIdCell); + row.appendChild(commitCell); + row.appendChild(branchCell); + row.appendChild(modelsCell); + + tbody.appendChild(row); + }); +} + +// Refresh data +async function refreshData() { + document.getElementById('content').style.display = 'none'; + document.getElementById('loading').style.display = 'flex'; + await init(); +} + +// Format numbers for display +function formatNumber(num) { + if (num >= 1000) { + return (num / 1000).toFixed(1) + 'k'; + } + return num.toFixed(1); +} + +// Authentication state +let authToken = sessionStorage.getItem('dashboard_auth_token') || null; + +// Get auth headers for API requests +function getAuthHeaders() { + const headers = {}; + if (authToken) { + headers['Authorization'] = `Bearer ${authToken}`; + } + return headers; +} + +// Check if server requires authentication and show/hide login accordingly +async function checkAuthAndInit() { + const loginOverlay = document.getElementById('login-overlay'); + const dashboardContainer = document.getElementById('dashboard-container'); + + try { + const response = await fetch('/api/auth-check'); + if (response.ok) { + const data = await response.json(); + if (!data.auth_required) { + // No auth required - skip login, show dashboard directly + loginOverlay.style.display = 'none'; + dashboardContainer.style.display = 'block'; + init(); + return; + } + } + } catch (e) { + // Server not available (e.g. static hosting) - skip login + loginOverlay.style.display = 'none'; + dashboardContainer.style.display = 'block'; + init(); + return; + } + + // Auth is required - check if we have a valid token from a previous session + if (authToken) { + try { + const testResponse = await fetch('/api/metrics', { + headers: getAuthHeaders() + }); + if (testResponse.ok) { + loginOverlay.style.display = 'none'; + dashboardContainer.style.display = 'block'; + init(); + return; + } + } catch (e) { + // Token invalid or expired + } + // Clear invalid token + authToken = null; + sessionStorage.removeItem('dashboard_auth_token'); + } + + // Show login form + loginOverlay.style.display = 'flex'; + dashboardContainer.style.display = 'none'; +} + +// Handle login form submission +async function handleLogin(event) { + event.preventDefault(); + + const username = document.getElementById('login-username').value; + const password = document.getElementById('login-password').value; + const errorEl = document.getElementById('login-error'); + const loginBtn = document.getElementById('login-btn'); + + errorEl.textContent = ''; + loginBtn.disabled = true; + loginBtn.textContent = 'Signing in...'; + + try { + const response = await fetch('/api/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username, password }) + }); + + const data = await response.json(); + + if (response.ok && data.token) { + authToken = data.token; + sessionStorage.setItem('dashboard_auth_token', authToken); + + document.getElementById('login-overlay').style.display = 'none'; + document.getElementById('dashboard-container').style.display = 'block'; + init(); + } else { + errorEl.textContent = data.error || 'Invalid username or password'; + } + } catch (e) { + errorEl.textContent = 'Unable to connect to server'; + } finally { + loginBtn.disabled = false; + loginBtn.textContent = 'Sign In'; + } + + return false; +} + +// Initialize on page load +document.addEventListener('DOMContentLoaded', checkAuthAndInit); diff --git a/sglang/docs/performance_dashboard/fetch_metrics.py b/sglang/docs/performance_dashboard/fetch_metrics.py new file mode 100644 index 0000000000000000000000000000000000000000..264e7f334c0dc3611774008d633a5eec012c30f0 --- /dev/null +++ b/sglang/docs/performance_dashboard/fetch_metrics.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +""" +Fetch and process SGLang nightly test metrics from GitHub Actions artifacts. + +This script fetches consolidated metrics from GitHub Actions workflow runs +and outputs them as JSON for the performance dashboard. + +Usage: + python fetch_metrics.py --output metrics_data.json + python fetch_metrics.py --output metrics_data.json --days 30 + python fetch_metrics.py --output metrics_data.json --run-id 21338741812 +""" + +import argparse +import io +import json +import os +import sys +import zipfile +from datetime import datetime, timedelta, timezone +from pathlib import Path +from typing import Optional + +import requests + +GITHUB_REPO = "sgl-project/sglang" +WORKFLOW_NAME = "nightly-test-nvidia.yml" +ARTIFACT_PREFIX = "consolidated-metrics-" + + +def get_github_token() -> Optional[str]: + """Get GitHub token from environment or gh CLI.""" + # Check environment variable first + token = os.environ.get("GITHUB_TOKEN") + if token: + return token + + # Try gh CLI + try: + import subprocess + + result = subprocess.run( + ["gh", "auth", "token"], + capture_output=True, + text=True, + check=True, + ) + return result.stdout.strip() + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + return None + + +def get_headers(token: Optional[str]) -> dict: + """Get request headers with optional authentication.""" + headers = { + "Accept": "application/vnd.github.v3+json", + } + if token: + headers["Authorization"] = f"Bearer {token}" + return headers + + +def fetch_workflow_runs( + token: Optional[str], + days: int = 30, + event: Optional[str] = None, +) -> list: + """Fetch completed workflow runs from GitHub Actions.""" + url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/workflows/{WORKFLOW_NAME}/runs" + + params = { + "status": "completed", + "per_page": 100, + } + + if event: + params["event"] = event + + response = requests.get(url, headers=get_headers(token), params=params, timeout=30) + response.raise_for_status() + + runs = response.json().get("workflow_runs", []) + + # Filter by date + cutoff = datetime.now(timezone.utc) - timedelta(days=days) + runs = [ + run + for run in runs + if datetime.fromisoformat(run["created_at"].replace("Z", "+00:00")) > cutoff + ] + + return runs + + +def fetch_run_artifacts(token: Optional[str], run_id: int) -> list: + """Fetch artifacts for a specific workflow run.""" + url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/runs/{run_id}/artifacts" + + response = requests.get(url, headers=get_headers(token), timeout=30) + response.raise_for_status() + + return response.json().get("artifacts", []) + + +def download_artifact(token: Optional[str], artifact_id: int) -> Optional[bytes]: + """Download an artifact by ID.""" + if not token: + print(f"Warning: GitHub token required to download artifacts", file=sys.stderr) + return None + + url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/artifacts/{artifact_id}/zip" + + headers = get_headers(token) + response = requests.get(url, headers=headers, allow_redirects=True, timeout=60) + + if response.status_code == 200: + return response.content + + print( + f"Failed to download artifact {artifact_id}: {response.status_code}", + file=sys.stderr, + ) + return None + + +def extract_metrics_from_zip(zip_content: bytes) -> Optional[dict]: + """Extract metrics JSON from a zip file.""" + try: + with zipfile.ZipFile(io.BytesIO(zip_content)) as zf: + # Find the JSON file in the archive + json_files = [f for f in zf.namelist() if f.endswith(".json")] + if not json_files: + return None + + with zf.open(json_files[0]) as f: + return json.load(f) + except (zipfile.BadZipFile, json.JSONDecodeError) as e: + print(f"Failed to extract metrics: {e}", file=sys.stderr) + return None + + +def fetch_metrics_for_run(token: Optional[str], run: dict) -> Optional[dict]: + """Fetch metrics for a single workflow run.""" + run_id = run["id"] + print(f"Fetching metrics for run {run_id}...", file=sys.stderr) + + artifacts = fetch_run_artifacts(token, run_id) + + # Find consolidated metrics artifact + metrics_artifact = None + for artifact in artifacts: + if artifact["name"].startswith(ARTIFACT_PREFIX): + metrics_artifact = artifact + break + + if not metrics_artifact: + print(f"No consolidated metrics found for run {run_id}", file=sys.stderr) + return None + + # Download and extract + zip_content = download_artifact(token, metrics_artifact["id"]) + if not zip_content: + return None + + metrics = extract_metrics_from_zip(zip_content) + if not metrics: + return None + + # Ensure required fields are present + if "run_id" not in metrics: + metrics["run_id"] = str(run_id) + if "run_date" not in metrics: + metrics["run_date"] = run["created_at"] + if "commit_sha" not in metrics: + metrics["commit_sha"] = run["head_sha"] + if "branch" not in metrics: + metrics["branch"] = run["head_branch"] + + return metrics + + +def fetch_single_run(token: Optional[str], run_id: int) -> Optional[dict]: + """Fetch metrics for a single run by ID.""" + url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/runs/{run_id}" + + response = requests.get(url, headers=get_headers(token), timeout=30) + response.raise_for_status() + + run = response.json() + return fetch_metrics_for_run(token, run) + + +def main(): + parser = argparse.ArgumentParser( + description="Fetch SGLang nightly test metrics from GitHub Actions" + ) + parser.add_argument( + "--output", + "-o", + type=str, + default="metrics_data.json", + help="Output JSON file path", + ) + parser.add_argument( + "--days", + type=int, + default=30, + help="Number of days to fetch (default: 30)", + ) + parser.add_argument( + "--run-id", + type=int, + help="Fetch a specific run by ID", + ) + parser.add_argument( + "--event", + type=str, + choices=["schedule", "workflow_dispatch", "push"], + help="Filter by trigger event type", + ) + parser.add_argument( + "--scheduled-only", + action="store_true", + help="Only fetch scheduled (nightly) runs", + ) + + args = parser.parse_args() + + token = get_github_token() + if not token: + print( + "Warning: No GitHub token found. Some features may be limited.", + file=sys.stderr, + ) + print( + "Set GITHUB_TOKEN env var or login with 'gh auth login'", + file=sys.stderr, + ) + + all_metrics = [] + + if args.run_id: + # Fetch single run + metrics = fetch_single_run(token, args.run_id) + if metrics: + all_metrics.append(metrics) + else: + # Fetch multiple runs + event = "schedule" if args.scheduled_only else args.event + runs = fetch_workflow_runs(token, days=args.days, event=event) + print(f"Found {len(runs)} workflow runs", file=sys.stderr) + + for run in runs: + metrics = fetch_metrics_for_run(token, run) + if metrics: + all_metrics.append(metrics) + + # Sort by date descending + all_metrics.sort(key=lambda x: x.get("run_date", ""), reverse=True) + + # Write output + output_path = Path(args.output) + with open(output_path, "w") as f: + json.dump(all_metrics, f, indent=2) + + print(f"Wrote {len(all_metrics)} metrics records to {output_path}", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/sglang/docs/performance_dashboard/index.html b/sglang/docs/performance_dashboard/index.html new file mode 100644 index 0000000000000000000000000000000000000000..1c5b57bafe3896938e57547c16ae7d30fc123fdd --- /dev/null +++ b/sglang/docs/performance_dashboard/index.html @@ -0,0 +1,946 @@ + + + + + + SGLang Performance Dashboard + + + + + + + + + + + + + + + + diff --git a/sglang/docs/performance_dashboard/server.py b/sglang/docs/performance_dashboard/server.py new file mode 100644 index 0000000000000000000000000000000000000000..1e025ce856e3a76da23bbbbd5ff052d25d0a57c6 --- /dev/null +++ b/sglang/docs/performance_dashboard/server.py @@ -0,0 +1,422 @@ +#!/usr/bin/env python3 +""" +Simple development server for the SGLang Performance Dashboard. + +This server: +1. Serves the static HTML/JS files +2. Provides an API endpoint to fetch metrics from GitHub +3. Caches metrics data to reduce API calls + +Usage: + python server.py + python server.py --port 8080 + python server.py --host 0.0.0.0 # Allow external access + python server.py --fetch-on-start + python server.py --username admin --password secret # Enable authentication + DASHBOARD_USERNAME=admin DASHBOARD_PASSWORD=secret python server.py # Via env vars + python server.py --refresh-interval 12 # Auto-refresh data every 12 hours +""" + +import argparse +import hashlib +import hmac +import http.server +import io +import json +import os +import secrets +import socketserver +import threading +import time +import zipfile +from datetime import datetime, timedelta, timezone +from pathlib import Path +from urllib.parse import urlparse + +import requests + +GITHUB_REPO = "sgl-project/sglang" +WORKFLOW_NAME = "nightly-test-nvidia.yml" +ARTIFACT_PREFIX = "consolidated-metrics-" + +# Cache for metrics data with thread-safe lock +cache_lock = threading.Lock() +metrics_cache = { + "data": [], + "last_updated": None, + "updating": False, +} + +CACHE_TTL = 300 # 5 minutes +REQUEST_TIMEOUT = 30 # seconds + +# Authentication configuration (set via CLI flags) +auth_config = { + "enabled": False, + "username": None, + "password_hash": None, # SHA-256 hash of the password + "active_tokens": {}, # token -> expiry timestamp +} +auth_lock = threading.Lock() +AUTH_TOKEN_TTL = 3600 # 1 hour + + +def hash_password(password): + """Hash a password using SHA-256 for constant-time comparison.""" + return hashlib.sha256(password.encode("utf-8")).hexdigest() + + +def create_auth_token(): + """Create a new session token.""" + token = secrets.token_hex(32) + with auth_lock: + # Clean up expired tokens + now = time.time() + auth_config["active_tokens"] = { + t: exp for t, exp in auth_config["active_tokens"].items() if exp > now + } + auth_config["active_tokens"][token] = now + AUTH_TOKEN_TTL + return token + + +def verify_auth_token(token): + """Verify a session token is valid and not expired.""" + if not token: + return False + with auth_lock: + expiry = auth_config["active_tokens"].get(token) + if expiry and expiry > time.time(): + return True + # Remove expired token + auth_config["active_tokens"].pop(token, None) + return False + + +def get_github_token(): + """Get GitHub token from environment or gh CLI.""" + token = os.environ.get("GITHUB_TOKEN") + if token: + return token + + try: + import subprocess + + result = subprocess.run( + ["gh", "auth", "token"], + capture_output=True, + text=True, + check=True, + ) + return result.stdout.strip() + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + return None + + +def fetch_metrics_from_github(days=30): + """Fetch metrics from GitHub Actions artifacts.""" + token = get_github_token() + headers = {"Accept": "application/vnd.github.v3+json"} + if token: + headers["Authorization"] = f"Bearer {token}" + + # Get workflow runs - only scheduled (nightly) runs, not workflow_dispatch + url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/workflows/{WORKFLOW_NAME}/runs" + params = {"status": "completed", "per_page": 50, "event": "schedule"} + + try: + response = requests.get( + url, headers=headers, params=params, timeout=REQUEST_TIMEOUT + ) + if not response.ok: + print(f"Failed to fetch workflow runs: {response.status_code}") + return [] + except requests.exceptions.RequestException as e: + print(f"Network error fetching workflow runs: {e}") + return [] + + runs = response.json().get("workflow_runs", []) + + # Filter by date + cutoff = datetime.now(timezone.utc) - timedelta(days=days) + runs = [ + run + for run in runs + if datetime.fromisoformat(run["created_at"].replace("Z", "+00:00")) > cutoff + ] + + all_metrics = [] + + for run in runs[:20]: # Limit to 20 most recent + run_id = run["id"] + + # Get artifacts + artifacts_url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/runs/{run_id}/artifacts" + try: + artifacts_resp = requests.get( + artifacts_url, headers=headers, timeout=REQUEST_TIMEOUT + ) + if not artifacts_resp.ok: + continue + except requests.exceptions.RequestException as e: + print(f"Network error fetching artifacts for run {run_id}: {e}") + continue + + artifacts = artifacts_resp.json().get("artifacts", []) + + # Find consolidated metrics + for artifact in artifacts: + if artifact["name"].startswith(ARTIFACT_PREFIX): + if not token: + # Without token, we can't download - return metadata only + all_metrics.append( + { + "run_id": str(run_id), + "run_date": run["created_at"], + "commit_sha": run["head_sha"], + "branch": run["head_branch"], + "results": [], + } + ) + break + + # Download artifact + download_url = f"https://api.github.com/repos/{GITHUB_REPO}/actions/artifacts/{artifact['id']}/zip" + try: + download_resp = requests.get( + download_url, + headers=headers, + allow_redirects=True, + timeout=REQUEST_TIMEOUT, + ) + except requests.exceptions.RequestException as e: + print(f"Network error downloading artifact: {e}") + break + + if download_resp.ok: + try: + with zipfile.ZipFile(io.BytesIO(download_resp.content)) as zf: + json_files = [ + f for f in zf.namelist() if f.endswith(".json") + ] + if json_files: + with zf.open(json_files[0]) as f: + metrics = json.load(f) + # Ensure required fields + metrics.setdefault("run_id", str(run_id)) + metrics.setdefault("run_date", run["created_at"]) + metrics.setdefault("commit_sha", run["head_sha"]) + metrics.setdefault("branch", run["head_branch"]) + all_metrics.append(metrics) + except (zipfile.BadZipFile, json.JSONDecodeError) as e: + print(f"Failed to process artifact: {e}") + break + + return all_metrics + + +def update_cache_async(): + """Update the metrics cache in background with thread safety.""" + with cache_lock: + if metrics_cache["updating"]: + return + metrics_cache["updating"] = True + + try: + data = fetch_metrics_from_github() + with cache_lock: + metrics_cache["data"] = data + metrics_cache["last_updated"] = time.time() + print(f"Cache updated with {len(data)} metrics records") + finally: + with cache_lock: + metrics_cache["updating"] = False + + +def start_periodic_refresh(interval_hours): + """Start a background thread that refreshes the cache periodically.""" + interval_seconds = interval_hours * 3600 + + def refresh_loop(): + while True: + time.sleep(interval_seconds) + print(f"Periodic refresh triggered (every {interval_hours}h)") + update_cache_async() + + thread = threading.Thread(target=refresh_loop, daemon=True) + thread.start() + print(f"Periodic refresh enabled: every {interval_hours} hours") + + +class DashboardHandler(http.server.SimpleHTTPRequestHandler): + """HTTP request handler for the dashboard.""" + + def __init__(self, *args, directory=None, **kwargs): + super().__init__(*args, directory=directory, **kwargs) + + def _send_json(self, data, status=200): + """Send a JSON response.""" + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Access-Control-Allow-Origin", "*") + self.end_headers() + self.wfile.write(json.dumps(data).encode()) + + def _check_auth(self): + """Check if request is authenticated. Returns True if OK, sends 401 and returns False otherwise.""" + if not auth_config["enabled"]: + return True + auth_header = self.headers.get("Authorization", "") + if auth_header.startswith("Bearer "): + token = auth_header[7:] + if verify_auth_token(token): + return True + self._send_json({"error": "Unauthorized"}, status=401) + return False + + def do_GET(self): + parsed = urlparse(self.path) + + # Prevent directory traversal attacks + if ".." in parsed.path or parsed.path.startswith("//"): + self.send_error(400, "Invalid path") + return + + if parsed.path == "/api/auth-check": + self.handle_auth_check() + elif parsed.path == "/api/metrics": + if self._check_auth(): + self.handle_metrics_api(parsed) + elif parsed.path == "/api/refresh": + if self._check_auth(): + self.handle_refresh_api() + else: + super().do_GET() + + def do_POST(self): + parsed = urlparse(self.path) + + if parsed.path == "/api/login": + self.handle_login() + else: + self.send_error(404, "Not Found") + + def handle_auth_check(self): + """Tell the frontend whether authentication is required.""" + self._send_json({"auth_required": auth_config["enabled"]}) + + def handle_login(self): + """Validate username/password and return a session token.""" + content_length = int(self.headers.get("Content-Length", 0)) + if content_length == 0 or content_length > 4096: + self._send_json({"error": "Invalid request"}, status=400) + return + + try: + body = json.loads(self.rfile.read(content_length)) + except (json.JSONDecodeError, ValueError): + self._send_json({"error": "Invalid JSON"}, status=400) + return + + username = body.get("username", "") + password = body.get("password", "") + + if hmac.compare_digest( + username, auth_config["username"] + ) and hmac.compare_digest( + hash_password(password), auth_config["password_hash"] + ): + token = create_auth_token() + self._send_json({"token": token}) + else: + self._send_json({"error": "Invalid username or password"}, status=401) + + def handle_metrics_api(self, parsed): + """Handle /api/metrics endpoint.""" + # Check cache with thread safety + with cache_lock: + cache_valid = ( + metrics_cache["last_updated"] + and time.time() - metrics_cache["last_updated"] < CACHE_TTL + ) + data = metrics_cache["data"].copy() + + if not cache_valid: + # Trigger background update + threading.Thread(target=update_cache_async, daemon=True).start() + + self._send_json(data) + + def handle_refresh_api(self): + """Handle /api/refresh endpoint.""" + threading.Thread(target=update_cache_async, daemon=True).start() + self._send_json({"status": "refreshing"}) + + def log_message(self, format, *args): + """Custom log format.""" + print(f"[{self.log_date_time_string()}] {args[0]}") + + +def main(): + parser = argparse.ArgumentParser(description="SGLang Performance Dashboard Server") + parser.add_argument("--port", type=int, default=8000, help="Port to serve on") + parser.add_argument( + "--host", + default="127.0.0.1", + help="Host to bind to (use 0.0.0.0 for external access)", + ) + parser.add_argument( + "--fetch-on-start", action="store_true", help="Fetch metrics on startup" + ) + parser.add_argument( + "--refresh-interval", + type=float, + default=12, + help="Auto-refresh interval in hours (default: 12, set to 0 to disable)", + ) + parser.add_argument( + "--username", + default=os.environ.get("DASHBOARD_USERNAME"), + help="Username for dashboard authentication (or set DASHBOARD_USERNAME env var)", + ) + parser.add_argument( + "--password", + default=os.environ.get("DASHBOARD_PASSWORD"), + help="Password for dashboard authentication (or set DASHBOARD_PASSWORD env var)", + ) + args = parser.parse_args() + + # Configure authentication if both username and password are provided + if args.username and args.password: + auth_config["enabled"] = True + auth_config["username"] = args.username + auth_config["password_hash"] = hash_password(args.password) + print(f"Authentication enabled for user: {args.username}") + elif args.username or args.password: + parser.error("Both --username and --password must be provided together") + + # Change to dashboard directory + dashboard_dir = Path(__file__).parent + os.chdir(dashboard_dir) + + if args.fetch_on_start: + print("Fetching initial metrics data...") + update_cache_async() + + if args.refresh_interval > 0: + start_periodic_refresh(args.refresh_interval) + + handler = lambda *a, **kw: DashboardHandler(*a, directory=str(dashboard_dir), **kw) + + with socketserver.TCPServer((args.host, args.port), handler) as httpd: + print(f"Serving dashboard at http://{args.host}:{args.port}") + print("Press Ctrl+C to stop") + try: + httpd.serve_forever() + except KeyboardInterrupt: + print("\nShutting down...") + + +if __name__ == "__main__": + main() diff --git a/sglang/docs/platforms/amd_gpu.md b/sglang/docs/platforms/amd_gpu.md new file mode 100644 index 0000000000000000000000000000000000000000..e3eae156bc3ca891aed296738c923c9c8a16dc0c --- /dev/null +++ b/sglang/docs/platforms/amd_gpu.md @@ -0,0 +1,194 @@ +# AMD GPUs + +This document describes how to run SGLang on AMD GPUs. If you encounter issues or have questions, please [open an issue](https://github.com/sgl-project/sglang/issues). + +## System Configuration + +When using AMD GPUs (such as MI300X), certain system-level optimizations help ensure stable performance. Here we take MI300X as an example. AMD provides official documentation for MI300X optimization and system tuning: + +- [AMD MI300X Tuning Guides](https://rocm.docs.amd.com/en/latest/how-to/tuning-guides/mi300x/index.html) +- [LLM inference performance validation on AMD Instinct MI300X](https://rocm.docs.amd.com/en/latest/how-to/rocm-for-ai/inference/vllm-benchmark.html) +- [AMD Instinct MI300X System Optimization](https://rocm.docs.amd.com/en/latest/how-to/system-optimization/mi300x.html) +- [AMD Instinct MI300X Workload Optimization](https://rocm.docs.amd.com/en/latest/how-to/rocm-for-ai/inference-optimization/workload.html) +- [Supercharge DeepSeek-R1 Inference on AMD Instinct MI300X](https://rocm.blogs.amd.com/artificial-intelligence/DeepSeekR1-Part2/README.html) + +**NOTE:** We strongly recommend reading these docs and guides entirely to fully utilize your system. + +Below are a few key settings to confirm or enable for SGLang: + +### Update GRUB Settings + +In `/etc/default/grub`, append the following to `GRUB_CMDLINE_LINUX`: + +```text +pci=realloc=off iommu=pt +``` + +Afterward, run `sudo update-grub` (or your distro’s equivalent) and reboot. + +### Disable NUMA Auto-Balancing + +```bash +sudo sh -c 'echo 0 > /proc/sys/kernel/numa_balancing' +``` + +You can automate or verify this change using [this helpful script](https://github.com/ROCm/triton/blob/rocm_env/scripts/amd/env_check.sh). + +Again, please go through the entire documentation to confirm your system is using the recommended configuration. + +## Install SGLang + +You can install SGLang using one of the methods below. + +### Install from Source + +```bash +# Use the last release branch +git clone -b v0.5.9 https://github.com/sgl-project/sglang.git +cd sglang + +# Compile sgl-kernel +pip install --upgrade pip +cd sgl-kernel +python setup_rocm.py install + +# Install sglang python package along with diffusion support +cd .. +rm -rf python/pyproject.toml && mv python/pyproject_other.toml python/pyproject.toml +pip install -e "python[all_hip]" +``` + +### Install Using Docker (Recommended) + +The docker images are available on Docker Hub at [lmsysorg/sglang](https://hub.docker.com/r/lmsysorg/sglang/tags), built from [rocm.Dockerfile](https://github.com/sgl-project/sglang/tree/main/docker). + +The steps below show how to build and use an image. + +1. Build the docker image. + If you use pre-built images, you can skip this step and replace `sglang_image` with the pre-built image names in the steps below. + + ```bash + docker build -t sglang_image -f rocm.Dockerfile . + ``` + +2. Create a convenient alias. + + ```bash + alias drun='docker run -it --rm --network=host --privileged --device=/dev/kfd --device=/dev/dri \ + --ipc=host --shm-size 16G --group-add video --cap-add=SYS_PTRACE \ + --security-opt seccomp=unconfined \ + -v $HOME/dockerx:/dockerx \ + -v /data:/data' + ``` + + If you are using RDMA, please note that: + - `--network host` and `--privileged` are required by RDMA. If you don't need RDMA, you can remove them. + - You may need to set `NCCL_IB_GID_INDEX` if you are using RoCE, for example: `export NCCL_IB_GID_INDEX=3`. + +3. Launch the server. + + **NOTE:** Replace `` below with your [huggingface hub token](https://huggingface.co/docs/hub/en/security-tokens). + + ```bash + drun -p 30000:30000 \ + -v ~/.cache/huggingface:/root/.cache/huggingface \ + --env "HF_TOKEN=" \ + sglang_image \ + python3 -m sglang.launch_server \ + --model-path NousResearch/Meta-Llama-3.1-8B \ + --host 0.0.0.0 \ + --port 30000 + ``` + +4. To verify the utility, you can run a benchmark in another terminal or refer to [other docs](https://docs.sglang.io/basic_usage/openai_api_completions.html) to send requests to the engine. + + ```bash + drun sglang_image \ + python3 -m sglang.bench_serving \ + --backend sglang \ + --dataset-name random \ + --num-prompts 4000 \ + --random-input 128 \ + --random-output 128 + ``` + +With your AMD system properly configured and SGLang installed, you can now fully leverage AMD hardware to power SGLang’s machine learning capabilities. + +## Quantization on AMD GPUs + +The [Quantization documentation](../advanced_features/quantization.md#platform-compatibility) has a full compatibility matrix. The short version: FP8, AWQ, MXFP4, W8A8, GPTQ, compressed-tensors, and Quark all work on AMD. Methods that depend on Marlin or NVIDIA-specific kernels (`awq_marlin`, `gptq_marlin`, `gguf`, `modelopt_fp8`, `modelopt_fp4`, `petit_nvfp4`) do not. + +A few things to keep in mind: + +- FP8 works via Aiter or Triton. Pre-quantized FP8 models like DeepSeek-V3/R1 work out of the box. +- AWQ uses Triton dequantization kernels on AMD. The faster Marlin path is not available. +- MXFP4 requires CDNA3/CDNA4 and `SGLANG_USE_AITER=1`. +- `quark_int4fp8_moe` is an AMD-only online quantization method for MoE models on CDNA3/CDNA4. + +Several of these backends are accelerated by [Aiter](https://github.com/ROCm/aiter). Enable it with: + +```bash +export SGLANG_USE_AITER=1 +``` + +Example -- serving an AWQ model: + +```bash +python3 -m sglang.launch_server \ + --model-path hugging-quants/Mixtral-8x7B-Instruct-v0.1-AWQ-INT4 \ + --trust-remote-code \ + --port 30000 --host 0.0.0.0 +``` + +Example -- FP8 online quantization: + +```bash +python3 -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --quantization fp8 \ + --port 30000 --host 0.0.0.0 +``` + +## Examples + +### Running DeepSeek-V3 + +The only difference when running DeepSeek-V3 is in how you start the server. Here's an example command: + +```bash +drun -p 30000:30000 \ + -v ~/.cache/huggingface:/root/.cache/huggingface \ + --ipc=host \ + --env "HF_TOKEN=" \ + sglang_image \ + python3 -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-V3 \ # <- here + --tp 8 \ + --trust-remote-code \ + --host 0.0.0.0 \ + --port 30000 +``` + +[Running DeepSeek-R1 on a single NDv5 MI300X VM](https://techcommunity.microsoft.com/blog/azurehighperformancecomputingblog/running-deepseek-r1-on-a-single-ndv5-mi300x-vm/4372726) could also be a good reference. + +### Running Llama3.1 + +Running Llama3.1 is nearly identical to running DeepSeek-V3. The only difference is in the model specified when starting the server, shown by the following example command: + +```bash +drun -p 30000:30000 \ + -v ~/.cache/huggingface:/root/.cache/huggingface \ + --ipc=host \ + --env "HF_TOKEN=" \ + sglang_image \ + python3 -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ # <- here + --tp 8 \ + --trust-remote-code \ + --host 0.0.0.0 \ + --port 30000 +``` + +### Warmup Step + +When the server displays `The server is fired up and ready to roll!`, it means the startup is successful. diff --git a/sglang/docs/platforms/ascend_contribution_guide.md b/sglang/docs/platforms/ascend_contribution_guide.md new file mode 100644 index 0000000000000000000000000000000000000000..a5e8f020f450fd9256d0d6377f2b3961aa500923 --- /dev/null +++ b/sglang/docs/platforms/ascend_contribution_guide.md @@ -0,0 +1,152 @@ +# Contribution Guide + +Welcome to **SGLang**! We appreciate your interest in contributing. This guide provides a concise overview of how to set up your environment, run tests, build documentation, and open a Pull Request (PR). Whether you’re fixing a small bug or developing a major feature, we encourage following these steps for a smooth contribution process. + +## Install SGLang from Source + +### Prepare Environment + +Before contributing, please ensure that your environment is set up correctly. Follow the steps in the [Installation Guide](../platforms/ascend_npu.md) to install the necessary dependencies. We recommend [using docker](../platforms/ascend_npu.md#method-2-using-docker-image) to build the environment. + +### Fork and clone the repository + +**Note**: New contributors do **not** have the write permission to push to the official SGLang repo. Please fork the repository under your GitHub account, then clone your fork locally. + +```bash +git clone https://github.com//sglang.git +# if you are using docker, the environment is already set up. +cd sglang +export PYTHONPATH=$PWD/python:$PYTHONPATH +``` + +## Format code with pre-commit + +We use [pre-commit](https://pre-commit.com/) to maintain consistent code style checks. Before pushing your changes, please run: + +```bash +pip3 install pre-commit +pre-commit install +pre-commit run --all-files +``` + +- **`pre-commit run --all-files`** manually runs all configured checks, applying fixes if possible. If it fails the first time, re-run it to ensure lint errors are fully resolved. Make sure your code passes all checks **before** creating a Pull Request. +- **Do not commit** directly to the `main` branch. Always create a new branch (e.g., `feature/my-new-feature`), push your changes, and open a PR from that branch. + +## Run and add unit tests + +If you add a new feature or fix a bug, please add corresponding unit tests to ensure coverage and prevent regression. +SGLang uses Python's built-in [unittest](https://docs.python.org/3/library/unittest.html) framework. +For detailed instructions on running tests and integrating them into CI, refer to [test/README.md](https://github.com/sgl-project/sglang/tree/main/test/README.md). + +## Write documentations + +We recommend new contributors start from writing documentation, which helps you quickly understand SGLang codebase. +For more details, please refer to [docs/README.md](https://github.com/sgl-project/sglang/tree/main/docs/README.md). + +## Test the accuracy +If your code changes the model output, please run the accuracy tests. A quick sanity check is the few-shot GSM8K. + +``` +# Launch a server +python3 -m sglang.launch_server --model Qwen/Qwen2-7B-Instruct + +# Evaluate +python3 -m sglang.test.few_shot_gsm8k --num-questions 200 +``` + +Please note that the above script is primarily a sanity check, not a rigorous accuracy or speed test. +This test can have significant variance (1%–5%) in accuracy due to batching and the non-deterministic nature of the inference engine. +Also, do not rely on the "Latency/Output throughput" from this script, as it is not a proper speed test. + +GSM8K is too easy for state-of-the-art models nowadays. Please try your own more challenging accuracy tests. +You can find additional accuracy eval examples in: +- [test_eval_accuracy_large.py](https://github.com/sgl-project/sglang/blob/main/test/srt/test_eval_accuracy_large.py) +- [test_moe_eval_accuracy_large.py](https://github.com/sgl-project/sglang/blob/main/test/srt/test_moe_eval_accuracy_large.py) + +## Benchmark the speed +Refer to [Benchmark and Profiling](../developer_guide/benchmark_and_profiling.md). + +## Requesting a review for merge +You can follow the pull request merge process described in [MAINTAINER.md](https://github.com/sgl-project/sglang/blob/main/.github/MAINTAINER.md). +You will need to work with the Merge Oncall, Codeowner, and other reviewers to get their approvals. +Then your PR can be merged. + +## How to Trigger CI Tests + +We have a lot of open PRs but limited CI machines, so only top and trusted contributors have permission to trigger CI tests. +Users with permission are listed in the [CI_PERMISSIONS.json](https://github.com/sgl-project/sglang/blob/main/.github/CI_PERMISSIONS.json) + +For CI to run on a pull request, it must have the "run-ci" label. Authorized users can add the label or rerun failed tests by commenting on the PR with one of these commands: + +- `/tag-run-ci-label`: Adds the "run-ci" label. Every future commit will trigger CI. +- `/rerun-failed-ci`: Reruns the failed or flaky tests from the most recent commit. +- `/tag-and-rerun-ci`: A single command that performs both `/tag-run-ci-label` and `/rerun-failed-ci`. +- `/rerun-stage `: Reruns a specific test stage without waiting for its dependencies. This is useful when you want to quickly validate a fix for a specific test failure instead of waiting ~30 minutes for preceding stages to complete. + +If you have permission, the [Slash Command Handler](https://github.com/sgl-project/sglang/actions/workflows/slash-command-handler.yml) will run your command and react with a 👍 to your comment. It may take up to a few minutes for the reaction to appear. Here’s a usage [example](https://github.com/sgl-project/sglang/pull/14253#issuecomment-3599509302). + +To avoid spamming a PR with too many `/rerun-failed-ci` comments, you can also trigger the command by editing an existing comment and adding any suffix (e.g., `/rerun-failed-ci try again`). + +Example of rerunning a single test stage: `/rerun-stage unit-test-backend-4-gpu`. + +If you don’t have permission, please ask maintainers to trigger CI for you. + +### CI rate limits + +Due to CI scheduling and limited resources, higher-priority PRs may preempt running jobs. In such cases, you may need to rerun the tests. + +We apply CI rate limits to prevent abuse and ensure fair usage of our CI resources. + +Each CI workflow has a default limit defined in its workflow configuration file. For example, in [pr-gate.yml](https://github.com/sgl-project/sglang/blob/main/.github/workflows/pr-gate.yml), the default cooldown period is 120 minutes, and each workflow can override it via the `cool-down-minutes` input parameter: + +```yaml +cool-down-minutes: + description: "Default cooldown period in minutes; 0 disables rate limiting" + type: number + default: 120 +``` + +Users listed in [CI_PERMISSIONS.json](https://github.com/sgl-project/sglang/blob/main/.github/CI_PERMISSIONS.json) may have a per-user cooldown interval. In practice, we use the minimum of the workflow’s default window and the user-specific interval. + + +## Code style guidance +- Avoid code duplication. If the same code snippet (more than five lines) appears multiple times, extract it into a shared function. +- Minimize device synchronization. Reduce expensive CPU-GPU synchronization operations, such as `tensor.item()` or `tensor.cpu()`, whenever possible. Use vectorized code. +- Prioritize extreme efficiency. SGLang is a runtime, and most of your code runs on the critical path for every request. Optimize all minor overheads as much as possible, especially in the model forward code. + - A common pattern is some runtime checks in the model forward pass (e.g., [this](https://github.com/sgl-project/sglang/blob/f1b0eda55c2c4838e8ab90a0fac7fb1e3d7064ab/python/sglang/srt/models/deepseek_v2.py#L486-L491)). These are very likely the same for every layer. Please cache the result as a single boolean value whenever possible. +- Make functions as pure as possible. Avoid in-place modification of arguments. +- Keep files concise. If a file exceeds 2,000 lines of code, split it into multiple smaller files. (e.g., `scheduler.py`, `scheduler_output_processor_mixin.py`) +- Keep tests run fast. + - If a single test file run longer than 500 seconds, split it into multiple smaller files (e.g., `test_eagle_infer_a.py`, `test_eagle_infer_b.py`). + - If a single job in a github workflow runs longer than 30 mins, split it into smaller jobs/steps. + - Reuse server launches in your unit tests to make tests run faster. +- When supporting new hardware or features, follow these guidelines: + - Do not drastically change existing code. + - Always prefer new files to introduce specific components for your new hardware (e.g., `allocator_ascend.py`). + - If you write multiple if/else blocks for new features, ensure the common path (e.g., NVIDIA hardware or the existing code path) is the first branch. + +## How to update sgl-kernel +Since sglang and sgl-kernel are separate Python packages, our current GitHub CI infrastructure does not support updating a kernel and using it immediately within the same pull request (PR). +To add a new kernel or modify an existing one in the sgl-kernel package, you must use multiple PRs. + +Follow these steps: + +1. Submit a PR to update the sgl-kernel source code without using it in sglang python package (e.g., [#8884](https://github.com/sgl-project/sglang/pull/8884/files)). +2. Bump the version of sgl-kernel (e.g., [#9220](https://github.com/sgl-project/sglang/pull/9220/files)). + - Once merged, this will trigger an automatic release of the sgl-kernel wheel to PyPI. + - If not urgent, you can wait for other people to release the wheel. A new version will typically be released within one week. +3. Apply the changes: + - Update the sgl-kernel version in `sglang/python/pyproject.toml` to use the modified kernels. + - Update the related caller code in the sglang to use the new kernel. + +## How to update sgl-kernel-npu + +Sgl-kernel-npu is the kernel package for Ascend NPU and is maintained in the [sgl-kernel-npu](https://github.com/sgl-project/sgl-kernel-npu) repository. if you want to add a new kernel and want to use it in sglang, please follow the steps in [Contribution Guide](https://github.com/sgl-project/sgl-kernel-npu/blob/main/docs/developer_guide/contribution_guide.md). + +## Tips for newcomers + +If you want to contribute but don’t have a specific idea in mind, pick issues labeled [“good first issue” or “help wanted”](https://github.com/sgl-project/sglang/issues?q=is%3Aissue+label%3A%22good+first+issue%22%2C%22help+wanted%22). These tasks typically have lower complexity and provide an excellent introduction to the codebase. Also check out this [code walk-through](https://github.com/zhaochenyang20/Awesome-ML-SYS-Tutorial/tree/main/sglang/code-walk-through) for a deeper look into SGLang’s workflow. + +If you have any questions or want to start a discussion, please feel free to ask in our [Slack channel](https://slack.sglang.io). + +Thank you for your interest in SGLang. Happy coding! diff --git a/sglang/docs/platforms/ascend_npu.md b/sglang/docs/platforms/ascend_npu.md new file mode 100644 index 0000000000000000000000000000000000000000..b2cce472f71d4f46cc00cd87c9f279c8fe274d3b --- /dev/null +++ b/sglang/docs/platforms/ascend_npu.md @@ -0,0 +1,244 @@ + +# SGLang installation with NPUs support + +You can install SGLang using any of the methods below. Please go through `System Settings` section to ensure the clusters are roaring at max performance. Feel free to leave an issue [here at sglang](https://github.com/sgl-project/sglang/issues) if you encounter any issues or have any problems. + +## Component Version Mapping For SGLang +| Component | Version | Obtain Way | +|-------------------|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| HDK | 25.3.RC1 | [link](https://hiascend.com/hardware/firmware-drivers/commercial?product=7&model=33) | +| CANN | 8.5.0 | [Obtain Images](#obtain-cann-image) | +| Pytorch Adapter | 7.3.0 | [link](https://gitcode.com/Ascend/pytorch/releases) | +| MemFabric | 1.0.5 | `pip install memfabric-hybrid==1.0.5` | +| Triton | 3.2.0 | `pip install triton-ascend`| +| SGLang NPU Kernel | NA | [link](https://github.com/sgl-project/sgl-kernel-npu/releases) | + + +### Obtain CANN Image +You can obtain the dependency of a specified version of CANN through an image. +```shell +# for Atlas 800I A3 and Ubuntu OS +docker pull quay.io/ascend/cann:8.5.0-a3-ubuntu22.04-py3.11 +# for Atlas 800I A2 and Ubuntu OS +docker pull quay.io/ascend/cann:8.5.0-910b-ubuntu22.04-py3.11 +``` + +## Preparing the Running Environment + +### Method 1: Installing from source with prerequisites + +#### Python Version + +Only `python==3.11` is supported currently. If you don't want to break system pre-installed python, try installing with [conda](https://github.com/conda/conda). + +```shell +conda create --name sglang_npu python=3.11 +conda activate sglang_npu +``` + +#### CANN + +Prior to start work with SGLang on Ascend you need to install CANN Toolkit, Kernels operator package and NNAL version 8.3.RC2 or higher, check the [installation guide](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/83RC1/softwareinst/instg/instg_0008.html?Mode=PmIns&InstallType=local&OS=openEuler&Software=cannToolKit) + +#### MemFabric-Hybrid + +If you want to use PD disaggregation mode, you need to install MemFabric-Hybrid. MemFabric-Hybrid is a drop-in replacement of Mooncake Transfer Engine that enables KV cache transfer on Ascend NPU clusters. + +```shell +pip install memfabric-hybrid==1.0.5 +``` + +#### Pytorch and Pytorch Framework Adaptor on Ascend + +```shell +PYTORCH_VERSION=2.8.0 +TORCHVISION_VERSION=0.23.0 +TORCH_NPU_VERSION=2.8.0 +pip install torch==$PYTORCH_VERSION torchvision==$TORCHVISION_VERSION --index-url https://download.pytorch.org/whl/cpu +pip install torch_npu==$TORCH_NPU_VERSION +``` + +If you are using other versions of `torch` and install `torch_npu`, check [installation guide](https://github.com/Ascend/pytorch/blob/master/README.md) + +#### Triton on Ascend + +We provide our own implementation of Triton for Ascend. + +```shell +pip install triton-ascend +``` +For installation of Triton on Ascend nightly builds or from sources, follow [installation guide](https://gitcode.com/Ascend/triton-ascend/blob/master/docs/sources/getting-started/installation.md) + +#### SGLang Kernels NPU +We provide SGL kernels for Ascend NPU, check [installation guide](https://github.com/sgl-project/sgl-kernel-npu/blob/main/python/sgl_kernel_npu/README.md). + +#### DeepEP-compatible Library +We provide a DeepEP-compatible Library as a drop-in replacement of deepseek-ai's DeepEP library, check the [installation guide](https://github.com/sgl-project/sgl-kernel-npu/blob/main/python/deep_ep/README.md). + +#### Installing SGLang from source + +```shell +# Use the last release branch +git clone https://github.com/sgl-project/sglang.git +cd sglang +mv python/pyproject_npu.toml python/pyproject.toml +pip install -e python[all_npu] +``` + +### Method 2: Using Docker Image +#### Obtain Image +You can download the SGLang image or build an image based on Dockerfile to obtain the Ascend NPU image. +1. Download SGLang image +```angular2html +dockerhub: docker.io/lmsysorg/sglang:$tag +# Main-based tag, change main to specific version like v0.5.6, +# you can get image for specific version +Atlas 800I A3 : {main}-cann8.5.0-a3 +Atlas 800I A2: {main}-cann8.5.0-910b +``` +2. Build an image based on Dockerfile +```shell +# Clone the SGLang repository +git clone https://github.com/sgl-project/sglang.git +cd sglang/docker + +# Build the docker image +# If there are network errors, please modify the Dockerfile to use offline dependencies or use a proxy +docker build -t -f npu.Dockerfile . +``` + +#### Create Docker +__Notice:__ `--privileged` and `--network=host` are required by RDMA, which is typically needed by Ascend NPU clusters. + +__Notice:__ The following docker command is based on Atlas 800I A3 machines. If you are using Atlas 800I A2, make sure only `davinci[0-7]` are mapped into container. + +```shell + +alias drun='docker run -it --rm --privileged --network=host --ipc=host --shm-size=16g \ + --device=/dev/davinci0 --device=/dev/davinci1 --device=/dev/davinci2 --device=/dev/davinci3 \ + --device=/dev/davinci4 --device=/dev/davinci5 --device=/dev/davinci6 --device=/dev/davinci7 \ + --device=/dev/davinci8 --device=/dev/davinci9 --device=/dev/davinci10 --device=/dev/davinci11 \ + --device=/dev/davinci12 --device=/dev/davinci13 --device=/dev/davinci14 --device=/dev/davinci15 \ + --device=/dev/davinci_manager --device=/dev/hisi_hdc \ + --volume /usr/local/sbin:/usr/local/sbin --volume /usr/local/Ascend/driver:/usr/local/Ascend/driver \ + --volume /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \ + --volume /etc/ascend_install.info:/etc/ascend_install.info \ + --volume /var/queue_schedule:/var/queue_schedule --volume ~/.cache/:/root/.cache/' + +# Add HF_TOKEN env for download model by SGLang. +drun --env "HF_TOKEN=" \ + \ + python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --attention-backend ascend +``` + +## System Settings + +### CPU performance power scheme + +The default power scheme on Ascend hardware is `ondemand` which could affect performance, changing it to `performance` is recommended. + +```shell +echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor + +# Make sure changes are applied successfully +cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # shows performance +``` + +### Disable NUMA balancing + +```shell +sudo sysctl -w kernel.numa_balancing=0 +# Check +cat /proc/sys/kernel/numa_balancing # shows 0 +``` + +### Prevent swapping out system memory + +```shell +sudo sysctl -w vm.swappiness=10 + +# Check +cat /proc/sys/vm/swappiness # shows 10 +``` + +## Running SGLang Service +### Running Service For Large Language Models +#### PD Mixed Scene +```shell +# Enabling CPU Affinity +export SGLANG_SET_CPU_AFFINITY=1 +python3 -m sglang.launch_server --model-path meta-llama/Llama-3.1-8B-Instruct --attention-backend ascend +``` + +#### PD Separation Scene +1. Launch Prefill Server +```shell +# Enabling CPU Affinity +export SGLANG_SET_CPU_AFFINITY=1 + +# PIP: recommended to config first Prefill Server IP +# PORT: one free port +# all sglang servers need to be config the same PIP and PORT, +export ASCEND_MF_STORE_URL="tcp://PIP:PORT" +# if you are Atlas 800I A2 hardware and use rdma for kv cache transfer, add this parameter +export ASCEND_MF_TRANSFER_PROTOCOL="device_rdma" +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode prefill \ + --disaggregation-transfer-backend ascend \ + --disaggregation-bootstrap-port 8995 \ + --attention-backend ascend \ + --device npu \ + --base-gpu-id 0 \ + --tp-size 1 \ + --host 127.0.0.1 \ + --port 8000 +``` + +2. Launch Decode Server +```shell +# PIP: recommended to config first Prefill Server IP +# PORT: one free port +# all sglang servers need to be config the same PIP and PORT, +export ASCEND_MF_STORE_URL="tcp://PIP:PORT" +# if you are Atlas 800I A2 hardware and use rdma for kv cache transfer, add this parameter +export ASCEND_MF_TRANSFER_PROTOCOL="device_rdma" +python3 -m sglang.launch_server \ + --model-path meta-llama/Llama-3.1-8B-Instruct \ + --disaggregation-mode decode \ + --disaggregation-transfer-backend ascend \ + --attention-backend ascend \ + --device npu \ + --base-gpu-id 1 \ + --tp-size 1 \ + --host 127.0.0.1 \ + --port 8001 +``` + +3. Launch Router +```shell +python3 -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://127.0.0.1:8000 8995 \ + --decode http://127.0.0.1:8001 \ + --host 127.0.0.1 \ + --port 6688 +``` + +### Running Service For Multimodal Language Models +#### PD Mixed Scene +```shell +python3 -m sglang.launch_server \ + --model-path Qwen3-VL-30B-A3B-Instruct \ + --host 127.0.0.1 \ + --port 8000 \ + --tp 4 \ + --device npu \ + --attention-backend ascend \ + --mm-attention-backend ascend_attn \ + --disable-radix-cache \ + --trust-remote-code \ + --enable-multimodal \ + --sampling-backend ascend +``` diff --git a/sglang/docs/platforms/ascend_npu_best_practice.md b/sglang/docs/platforms/ascend_npu_best_practice.md new file mode 100644 index 0000000000000000000000000000000000000000..fd9f119268944542a1606bf18b58fb58ab0b06da --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_best_practice.md @@ -0,0 +1,2547 @@ +# Best Practice on Ascend NPU + +This section describes the best practice data of mainstream LLM models such as DeepSeek and Qwen on the Ascend NPU. If +you encounter issues or have any questions, please [open an issue](https://github.com/sgl-project/sglang/issues). + +## DeepSeek Series Models + +### Low Latency + +| Model | Hardware | Cards | Deploy Mode | Dataset | TPOT | Quantization | Configuration | +|-------------------|---------------|-------|---------------|-----------|------|--------------|---------------------------------------------------------------------------------------| +| Deepseek-R1 | Atlas 800I A3 | 32 | PD Separation | 6K+1.6K | 20ms | W8A8 INT8 | [Optimal Configuration](#deepseek-r1-6k-1_6k-20ms-on-a3-32-cards-separation-mode) | +| Deepseek-R1 | Atlas 800I A3 | 32 | PD Separation | 3.9K+1K | 20ms | W8A8 INT8 | [Optimal Configuration](#deepseek-r1-3_9k-1k-20ms-on-a3-32-cards-separation-mode) | +| Deepseek-R1 | Atlas 800I A3 | 32 | PD Separation | 3.5K+1.5K | 20ms | W8A8 INT8 | [Optimal Configuration](#deepseek-r1-3_5k-1_5k-20ms-on-a3-32-cards-separation-mode) | +| Deepseek-R1 | Atlas 800I A3 | 32 | PD Separation | 3.5K+1K | 20ms | W8A8 INT8 | [Optimal Configuration](#deepseek-r1-3_5k-1k-20ms-on-a3-32-cards-separation-mode) | +| DeepSeek-V3.2-Exp | Atlas 800I A3 | 32 | PD Separation | 64K+3K | 30ms | W8A8 INT8 | [Optimal Configuration](#deepseek-v32-exp-64k-3k-30ms-on-a3-32-cards-separation-mode) | + +### High Throughput + +| Model | Hardware | Cards | Deploy Mode | Dataset | TPOT | Quantization | Configuration | +|-------------|---------------|-------|---------------|-----------|------|--------------|-------------------------------------------------------------------------------------| +| Deepseek-R1 | Atlas 800I A3 | 32 | PD Separation | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#deepseek-r1-3_5k-1_5k-50ms-on-a3-32-cards-separation-mode) | +| Deepseek-R1 | Atlas 800I A3 | 8 | PD Mixed | 2K+2K | 50ms | W4A8 INT8 | [Optimal Configuration](#deepseek-r1-2k-2k-50ms-on-a3-8-cards-mixed-mode) | +| Deepseek-R1 | Atlas 800I A3 | 16 | PD Separation | 2K+2K | 50ms | W4A8 INT8 | [Optimal Configuration](#deepseek-r1-2k-2k-50ms-on-a3-16-cards-separation-mode) | +| Deepseek-R1 | Atlas 800I A3 | 8 | PD Mixed | 3.5K+1.5K | 50ms | W4A8 INT8 | [Optimal Configuration](#deepseek-r1-3_5k-1_5k-50ms-on-a3-8-cards-mixed-mode) | +| Deepseek-R1 | Atlas 800I A3 | 16 | PD Separation | 3.5K+1.5K | 50ms | W4A8 INT8 | [Optimal Configuration](#deepseek-r1-3_5k-1_5k-50ms-on-a3-16-cards-separation-mode) | + +## Qwen Series Models + +### Low Latency + +| Model | Hardware | Cards | Deploy Mode | Dataset | TPOT | Quantization | Configuration | +|-----------------|---------------|-------|-------------|---------|------|--------------|--------------------------------------------------------------------------------| +| Qwen3-235B-A22B | Atlas 800I A3 | 8 | PD Mixed | 11K+1K | 10ms | BF16 | [Optimal Configuration](#qwen3-235b-a22b-11k-1k-10ms-on-a3-8-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A3 | 4 | PD Mixed | 6K+1.5K | 18ms | BF16 | [Optimal Configuration](#qwen3-32b-6k-1_5k-18ms-on-a3-4-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A3 | 4 | PD Mixed | 4K+1.5K | 11ms | BF16 | [Optimal Configuration](#qwen3-32b-4k-1_5k-11ms-on-a3-4-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A3 | 8 | PD Mixed | 18K+4K | 12ms | BF16 | [Optimal Configuration](#qwen3-32b-18k-4k-12ms-on-a3-8-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A2 | 8 | PD Mixed | 6K+1.5K | 18ms | W8A8 INT8 | [Optimal Configuration](#qwen3-32b-6k-1_5k-18ms-on-a2-8-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A2 | 8 | PD Mixed | 4K+1.5K | 11ms | BF16 | [Optimal Configuration](#qwen3-32b-4k-1_5k-11ms-on-a2-8-cards-mixed-mode) | + +### High Throughput + +| Model | Hardware | Cards | Deploy Mode | Dataset | TPOT | Quantization | Configuration | +|--------------------------------|---------------|-------|---------------|-----------|-------|--------------|--------------------------------------------------------------------------------------------------------| +| Qwen3-235B-A22B | Atlas 800I A3 | 24 | PD Separation | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-235b-a22b-3_5k-1_5k-50ms-on-a3-24-cards-separation-mode) | +| Qwen3-235B-A22B | Atlas 800I A3 | 8 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-235b-a22b-3_5k-1_5k-50ms-on-a3-8-cards-mixed-mode) | +| Qwen3-235B-A22B | Atlas 800I A3 | 8 | PD Mixed | 2K+2K | 100ms | W8A8 INT8 | [Optimal Configuration](#qwen3-235b-a22b-2k-2k-100ms-on-a3-8-cards-mixed-mode) | +| Qwen3-235B-A22B | Atlas 800I A3 | 8 | PD Mixed | 2K+2K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-235b-a22b-2k-2k-50ms-on-a3-8-cards-mixed-mode) | +| Qwen3-235B-A22B | Atlas 800I A3 | 16 | PD Mixed | 2K+2K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-235b-a22b-2k-2k-50ms-on-a3-16-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A3 | 2 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-32b-3_5k-1_5k-50ms-on-a3-2-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A3 | 2 | PD Mixed | 2K+2K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-32b-2k-2k-50ms-on-a3-2-cards-mixed-mode) | +| Qwen3-30B-A3B | Atlas 800I A3 | 1 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-30b-a3b-3_5k-1_5k-50ms-on-a3-1-card-mixed-mode) | +| Qwen3-Coder-480B-A35B-Instruct | Atlas 800I A3 | 24 | PD Separation | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-coder-480b-a35b-instruct-3_5k-1_5k-50ms-on-a3-24-cards-separation-mode) | +| Qwen3-Coder-480B-A35B-Instruct | Atlas 800I A3 | 16 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-coder-480b-a35b-instruct-3_5k-1_5k-50ms-on-a3-16-cards-mixed-mode) | +| Qwen3-Coder-480B-A35B-Instruct | Atlas 800I A3 | 8 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-coder-480b-a35b-instruct-3_5k-1_5k-50ms-on-a3-8-cards-mixed-mode) | +| Qwen3-Next-80B-A3B-Instruct | Atlas 800I A3 | 2 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-next-80B-a3b-instruct-3_5k-1_5k-50ms-on-a3-2-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A2 | 8 | PD Mixed | 3.5K+1.5K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-32b-3_5k-1_5k-50ms-on-a2-8-cards-mixed-mode) | +| Qwen3-32B | Atlas 800I A2 | 8 | PD Mixed | 2K+2K | 50ms | W8A8 INT8 | [Optimal Configuration](#qwen3-32b-2k-2k-50ms-on-a2-8-cards-mixed-mode) | + +## Optimal Configuration + +### DeepSeek-R1 3_5K-1_5K 50ms on A3 32 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +export SGLANG_SET_CPU_AFFINITY=1 +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24669" + +P_IP=('your prefill ip1' 'your prefill ip2') + +D_IP=('your decode ip1' 'your decode ip2') + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" +# prefill +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + export HCCL_BUFFSIZE=1536 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + export TASK_QUEUE_ENABLE=2 + + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill --host ${P_IP[$i]} \ + --port 8000 --disaggregation-bootstrap-port $((8998+$i)) --trust-remote-code --nnodes 1 --node-rank 0 \ + --tp-size 16 --mem-fraction-static 0.81 --attention-backend ascend --device npu --quantization modelslim \ + --disaggregation-transfer-backend ascend --max-running-requests 8 --context-length 8192 --disable-radix-cache \ + --chunked-prefill-size -1 --max-prefill-tokens 28680 --moe-a2a-backend deepep --deepep-mode normal \ + --speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ + --dp-size 2 --enable-dp-attention --disable-shared-experts-fusion --dtype bfloat16 --enable-attn-tp-input-scattered + NODE_RANK=$i + break + fi +done + +# decode +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + export HCCL_BUFFSIZE=650 + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=78 + export TASK_QUEUE_ENABLE=1 + export SGLANG_SCHEDULER_SKIP_ALL_GATHER=1 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode --host ${D_IP[$i]} \ + --port 8001 --trust-remote-code --dist-init-addr ${D_IP[0]}:5000 --nnodes 2 --node-rank $i --tp-size 32 --dp-size 32 \ + --mem-fraction-static 0.815 --max-running-requests 832 --attention-backend ascend --device npu --quantization modelslim \ + --moe-a2a-backend deepep --enable-dp-attention --deepep-mode low_latency --enable-dp-lm-head --moe-dense-tp 1 \ + --cuda-graph-bs 12 14 16 18 20 22 24 26 --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --speculative-algorithm NEXTN --speculative-num-steps 2 --speculative-eagle-topk 1 --speculative-num-draft-tokens 3 \ + --tokenizer-worker-num 4 --prefill-round-robin-balance --disable-shared-experts-fusion --dtype bfloat16 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://P_IP:8000 8998 \ + --prefill http://P_IP:8000 8999 \ + --decode http://D_IP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 768 --random-input-len 3500 --random-output-len 1500 --num-prompts 3072 --random-range-ratio 1 --request-rate 16 +``` + +### DeepSeek-R1 6K-1_6K 20ms on A3 32 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 6K+1.6K + +TPOT: 20ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +export SGLANG_SET_CPU_AFFINITY=1 +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24669" + +P_IP=('your prefill ip1' 'your prefill ip2') + +D_IP=('your decode ip1' 'your decode ip2') + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" +# prefill +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + export HCCL_BUFFSIZE=1536 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + export TASK_QUEUE_ENABLE=2 + + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill --host ${P_IP[$i]} \ + --port 8000 --disaggregation-bootstrap-port $((8998+$i)) --trust-remote-code --nnodes 1 --node-rank 0 \ + --tp-size 16 --mem-fraction-static 0.81 --attention-backend ascend --device npu --quantization modelslim \ + --disaggregation-transfer-backend ascend --max-running-requests 4 --context-length 8192 --disable-radix-cache \ + --chunked-prefill-size -1 --max-prefill-tokens 28680 --moe-a2a-backend deepep --deepep-mode normal \ + --speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ + --dp-size 2 --enable-dp-attention --disable-shared-experts-fusion --dtype bfloat16 --enable-attn-tp-input-scattered + NODE_RANK=$i + break + fi +done + +# decode +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + export HCCL_BUFFSIZE=650 + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=12 + export TASK_QUEUE_ENABLE=1 + export SGLANG_SCHEDULER_SKIP_ALL_GATHER=1 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode --host ${D_IP[$i]} \ + --port 8001 --trust-remote-code --dist-init-addr DIP1:5000 --nnodes 2 --node-rank $i --tp-size 32 --dp-size 16 \ + --mem-fraction-static 0.75 --max-running-requests 32 --attention-backend ascend --device npu --quantization modelslim \ + --moe-a2a-backend deepep --enable-dp-attention --deepep-mode low_latency --enable-dp-lm-head --moe-dense-tp 1 \ + --cuda-graph-bs 2 4 6 --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --tokenizer-worker-num 4 --prefill-round-robin-balance --disable-shared-experts-fusion --dtype bfloat16 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://P_IP:8000 8998 \ + --prefill http://P_IP:8000 8999 \ + --decode http://D_IP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 32 --random-input-len 6000 --random-output-len 1600 --num-prompts 32 --random-range-ratio 1 +``` + +### DeepSeek-R1 3_9K-1K 20ms on A3 32 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.9K+1K + +TPOT: 20ms + +#### Model Deployment + +Please Turn to [DeepSeek-R1 6K-1_6K 20ms on A3 32 Cards Separation Mode](#deepseek-r1-6k-1_6k-20ms-on-a3-32-cards-separation-mode) + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 768 --random-input-len 3900 --random-output-len 1000 --num-prompts 768 --random-range-ratio 1 --request-rate 16 +``` + +### DeepSeek-R1 3_5K-1_5K 20ms on A3 32 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 20ms + +#### Model Deployment + +Please Turn to [DeepSeek-R1 6K-1_6K 20ms on A3 32 Cards Separation Mode](#deepseek-r1-6k-1_6k-20ms-on-a3-32-cards-separation-mode) + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```bash +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 768 --random-input-len 3500 --random-output-len 1500 --num-prompts 768 --random-range-ratio 1 --request-rate 16 +``` + +### DeepSeek-R1 3_5K-1K 20ms on A3 32 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1K + +TPOT: 20ms + +#### Model Deployment + +Please Turn to [DeepSeek-R1 6K-1_6K 20ms on A3 32 Cards Separation Mode](#deepseek-r1-6k-1_6k-20ms-on-a3-32-cards-separation-mode) + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 768 --random-input-len 3500 --random-output-len 1000 --num-prompts 768 --random-range-ratio 1 --request-rate 16 +``` + +### DeepSeek-R1 2K-2K 50ms on A3 8 Cards Mixed Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export SGLANG_SCHEDULER_DECREASE_PREFILL_IDLE=1 + +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=64 +export HCCL_BUFFSIZE=1600 +export DEEPEP_NORMAL_LONG_SEQ_ROUND=10 +export DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS=512 + +MODEL_PATH=xxx + +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_USE_FIA_NZ=1 +export ENABLE_MOE_NZ=1 + +python3 -m sglang.launch_server --model-path ${MODEL_PATH} \ +--tp 16 \ +--trust-remote-code \ +--attention-backend ascend \ +--device npu \ +--quantization modelslim \ +--watchdog-timeout 9000 \ +--host 127.0.0.1 --port 6699 \ +--cuda-graph-bs 4 8 16 \ +--mem-fraction-static 0.74 \ +--max-running-requests 256 \ +--disable-radix-cache --chunked-prefill-size -1 --max-prefill-tokens 1500 \ +--moe-a2a-backend deepep --deepep-mode auto \ +--enable-dp-attention --dp-size 16 --enable-dp-lm-head \ +--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ +--dtype bfloat16 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6699 --max-concurrency 256 --random-input-len 2048 --random-output-len 2048 --num-prompts 1024 --random-range-ratio 1 +``` + +### DeepSeek-R1 2K-2K 50ms on A3 16 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 16Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24667" + +P_IP=('your prefill ip1') + +D_IP=('your decode ip1') + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 +export ENABLE_MOE_NZ=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +# prefill +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + export HCCL_BUFFSIZE=1536 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + export TASK_QUEUE_ENABLE=2 + + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill --host ${P_IP[$i]} \ + --port 8000 --disaggregation-bootstrap-port $((8998+$i)) --trust-remote-code --nnodes 1 --node-rank 0 \ + --tp-size 16 --mem-fraction-static 0.6 --attention-backend ascend --device npu --quantization modelslim \ + --disaggregation-transfer-backend ascend --max-running-requests 8 --context-length 8192 --disable-radix-cache \ + --chunked-prefill-size 32768 --max-prefill-tokens 28680 --moe-a2a-backend deepep --deepep-mode normal \ + --speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ + --dp-size 2 --enable-dp-attention --disable-shared-experts-fusion --dtype bfloat16 + NODE_RANK=$i + break + fi +done + +# decode +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + export HCCL_BUFFSIZE=720 + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=96 + export TASK_QUEUE_ENABLE=1 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode --host ${D_IP[$i]} \ + --port 8001 --trust-remote-code --nnodes 1 --node-rank 0 --tp-size 16 --dp-size 16 \ + --mem-fraction-static 0.8 --max-running-requests 384 --attention-backend ascend --device npu --quantization modelslim \ + --moe-a2a-backend deepep --enable-dp-attention --deepep-mode low_latency --enable-dp-lm-head \ + --cuda-graph-bs 8 10 12 14 16 18 20 22 24 --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --prefill-round-robin-balance --disable-shared-experts-fusion --dtype bfloat16 --tokenizer-worker-num 4 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://P_IP:8000 8998 \ + --decode http://D_IP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 400 --random-input-len 2048 --random-output-len 2048 --num-prompts 3200 --random-range-ratio 1 --request-rate 8 +``` + +### DeepSeek-R1 3_5K-1_5K 50ms on A3 8 Cards Mixed Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +export STREAMS_PER_DEVICE=32 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export SGLANG_SCHEDULER_DECREASE_PREFILL_IDLE=1 +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=36 +export HCCL_BUFFSIZE=1600 +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_USE_FIA_NZ=1 +export ENABLE_MOE_NZ=1 + +MODEL_PATH=xxx + +python3 -m sglang.launch_server --model-path ${MODEL_PATH} \ +--tp 16 \ +--trust-remote-code \ +--attention-backend ascend \ +--device npu \ +--quantization modelslim \ +--watchdog-timeout 9000 \ +--host 127.0.0.1 --port 6699 \ +--cuda-graph-bs 8 16 24 28 32 36 \ +--mem-fraction-static 0.71 \ +--max-running-requests 144 \ +--context-length 8188 --disable-radix-cache --chunked-prefill-size -1 --max-prefill-tokens 9000 \ +--moe-a2a-backend deepep --deepep-mode auto \ +--enable-dp-attention --dp-size 4 --enable-dp-lm-head \ +--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ +--dtype bfloat16 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6699 --max-concurrency 144 --random-input-len 3500 --random-output-len 1500 --num-prompts 576 --random-range-ratio 1 +``` + +### DeepSeek-R1 3_5K-1_5K 50ms on A3 16 Cards Separation Mode + +Model: Deepseek R1 + +Hardware: Atlas 800I A3 16Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24667" + +P_IP=('your prefill ip1') + +D_IP=('your decode ip1') + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 +export ENABLE_MOE_NZ=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +# prefill +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + export HCCL_BUFFSIZE=1536 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + export TASK_QUEUE_ENABLE=2 + + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill --host ${P_IP[$i]} \ + --port 8000 --disaggregation-bootstrap-port $((8998+$i)) --trust-remote-code --nnodes 1 --node-rank 0 \ + --tp-size 16 --mem-fraction-static 0.6 --attention-backend ascend --device npu --quantization modelslim \ + --disaggregation-transfer-backend ascend --max-running-requests 8 --context-length 8192 --disable-radix-cache \ + --chunked-prefill-size -1 --max-prefill-tokens 28680 --moe-a2a-backend deepep --deepep-mode normal \ + --speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ + --dp-size 2 --enable-dp-attention --disable-shared-experts-fusion --dtype bfloat16 + NODE_RANK=$i + break + fi +done + +# decode +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + export HCCL_BUFFSIZE=720 + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=96 + export TASK_QUEUE_ENABLE=1 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode --host ${D_IP[$i]} \ + --port 8001 --trust-remote-code --nnodes 1 --node-rank 0 --tp-size 16 --dp-size 16 \ + --mem-fraction-static 0.8 --max-running-requests 384 --attention-backend ascend --device npu --quantization modelslim \ + --moe-a2a-backend deepep --enable-dp-attention --deepep-mode low_latency --enable-dp-lm-head \ + --cuda-graph-bs 8 10 12 14 16 18 20 22 24 --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --prefill-round-robin-balance --disable-shared-experts-fusion --dtype bfloat16 --tokenizer-worker-num 4 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://P_IP:8000 8998 \ + --decode http://D_IP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 384 --random-input-len 3500 --random-output-len 1500 --num-prompts 1536 --random-range-ratio 1 +``` + +### DeepSeek-V3.2-Exp 64K-3K 30ms on A3 32 Cards Separation Mode + +Model: DeepSeek-V3.2-Exp-W8A8 + +Hardware: Atlas 800I A3 32Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 64K+3K + +TPOT: 30ms + +#### Model Deployment + +Deploy Prefill Instance + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING + +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/op_api/lib/:${LD_LIBRARY_PATH} +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export ASCEND_HOME_PATH=/usr/local/Ascend/ascend-toolkit/latest + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +export HCCL_BUFFSIZE=1024 +export DEEPEP_NORMAL_LONG_SEQ_ROUND=5 +export DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS=512 + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 +export SGLANG_NPU_USE_MULTI_STREAM=1 +export HCCL_OP_EXPANSION_MODE=AIV + +IPs=('your prefill ip1' 'your prefill ip2') + +# get IP in current node +LOCAL_HOST=`hostname -I|awk -F " " '{print$1}'` +echo "LOCAL_HOST = " ${LOCAL_HOST} +# get node index +for i in "${!IPs[@]}"; +do + echo "LOCAL_HOST=${LOCAL_HOST}, IPs[${i}]=${IPs[$i]}" + if [ "$LOCAL_HOST" == "${IPs[$i]}" ]; then + echo "Node Rank : ${i}" + VC_TASK_INDEX=$i + break + fi +done + +IFNAMES=('xxx' 'xxx') + +export HCCL_SOCKET_IFNAME=${IFNAMES[$VC_TASK_INDEX]} +export GLOO_SOCKET_IFNAME=${HCCL_SOCKET_IFNAME} +echo "HCCL_SOCKET_IFNAME : ${HCCL_SOCKET_IFNAME}" +nnodes=${#IPs[@]} +tp_size=`expr 16 \* ${nnodes}` +export ASCEND_MF_STORE_URL=tcp://${IPs[0]}:24667 + +python3 -m sglang.launch_server --model-path ${MODEL_PATH} \ +--tp $tp_size \ +--trust-remote-code \ +--attention-backend ascend \ +--device npu \ +--watchdog-timeout 9000 \ +--host ${IPs[$VC_TASK_INDEX]} --port 8000 \ +--mem-fraction-static 0.73 \ +--disable-radix-cache --chunked-prefill-size -1 --max-prefill-tokens 68000 \ +--max-running-requests 1 \ +--moe-a2a-backend deepep --deepep-mode normal \ +--quantization modelslim \ +--disaggregation-transfer-backend ascend \ +--disaggregation-mode prefill \ +--disable-cuda-graph \ +--nnodes $nnodes --node-rank $VC_TASK_INDEX \ +--disaggregation-bootstrap-port 8995 \ +--enable-nsa-prefill-context-parallel --moe-dense-tp-size 1 \ +--speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ +--dist-init-addr ${IPs[0]}:10000 +``` + +Deploy Decode Instance + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/op_api/lib/:${LD_LIBRARY_PATH} +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH +export ASCEND_HOME_PATH=/usr/local/Ascend/ascend-toolkit/latest + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MULTI_STREAM=1 +export SGLANG_NPU_USE_MLAPO=1 +export HCCL_OP_EXPANSION_MODE=AIV +export SGLANG_SCHEDULER_SKIP_ALL_GATHER=1 +export TASK_QUEUE_ENABLE=0 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +IPs=('your decode ip1' 'your decode ip2') + +export prefill_ip=your prefill ip1 +# get IP in current node +LOCAL_HOST=`hostname -I|awk -F " " '{print$1}'` +echo "LOCAL_HOST = " ${LOCAL_HOST} +# get node index +for i in "${!IPs[@]}"; +do + echo "LOCAL_HOST=${LOCAL_HOST}, IPs[${i}]=${IPs[$i]}" + if [ "$LOCAL_HOST" == "${IPs[$i]}" ]; then + echo "Node Rank : ${i}" + VC_TASK_INDEX=$i + break + fi +done + +IFNAMES=('xxx' 'xxx') + +export HCCL_SOCKET_IFNAME=${IFNAMES[$VC_TASK_INDEX]} +export GLOO_SOCKET_IFNAME=${HCCL_SOCKET_IFNAME} +nnodes=${#IPs[@]} +tp_size=`expr 16 \* ${nnodes}` +export ASCEND_MF_STORE_URL=tcp://${prefill_ip}:24667 + +CHUNKED_SIZE=65536 +DP=8 +export HCCL_BUFFSIZE=400 +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=8 + +python3 -m sglang.launch_server --model-path ${MODEL_PATH} \ +--tp $tp_size \ +--dp ${DP} \ +--ep $tp_size \ +--moe-dense-tp-size 1 \ +--enable-dp-attention \ +--enable-dp-lm-head \ +--trust-remote-code \ +--attention-backend ascend \ +--device npu \ +--watchdog-timeout 9000 \ +--host ${IPs[$VC_TASK_INDEX]} --port 8001 \ +--mem-fraction-static 0.79 \ +--disable-radix-cache \ +--chunked-prefill-size -1 --max-prefill-tokens 68000 \ +--max-running-requests 32 \ +--cuda-graph-max-bs 4 \ +--moe-a2a-backend deepep \ +--deepep-mode low_latency \ +--quantization modelslim \ +--speculative-algorithm NEXTN --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ +--disaggregation-transfer-backend ascend \ +--disaggregation-mode decode \ +--prefill-round-robin-balance \ +--load-balance-method round_robin \ +--nnodes $nnodes --node-rank $VC_TASK_INDEX \ +--dist-init-addr ${IPs[0]}:10000 --load-balance-method decode_round_robin +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://PIP1:8000 8995 \ + --decode http://DIP1:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6688 --max-concurrency 32 --random-input-len 64000 --random-output-len 3000 --num-prompts 64 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 3_5K-1_5K 50ms on A3 24 Cards Separation Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 24Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING + +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=16 + +MODEL_PATH=xxx +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24667" +P_IP=('your prefill ip1') +D_IP=('your decode ip1' 'your decode ip2') +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_DP_ROUND_ROBIN=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + + +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + source /usr/local/Ascend/ascend-toolkit/set_env.sh + source /usr/local/Ascend/nnal/atb/set_env.sh + export DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS=1024 + export DEEPEP_NORMAL_LONG_SEQ_ROUND=16 + export HCCL_BUFFSIZE=4300 + export TASK_QUEUE_ENABLE=2 + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + export STREAMS_PER_DEVICE=32 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + + # P节点 + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill \ + --host ${P_IP[$i]} --port 8000 --disaggregation-bootstrap-port 8995 --trust-remote-code \ + --nnodes 1 --node-rank $i --tp-size 16 --dp-size 16 --mem-fraction-static 0.6 \ + --disable-radix-cache \ + --attention-backend ascend --device npu --quantization modelslim --disaggregation-transfer-backend ascend \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --speculative-draft-model-quantization unquant \ + --max-running-requests 128 --chunked-prefill-size 262144 --max-prefill-tokens 262144 \ + --enable-dp-attention \ + --moe-a2a-backend deepep --deepep-mode normal --dtype bfloat16 + NODE_RANK=$i + break + fi +done + + +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + source /usr/local/Ascend/ascend-toolkit/set_env.sh + source /usr/local/Ascend/nnal/atb/set_env.sh + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=24 + export HCCL_BUFFSIZE=512 + export HCCL_SOCKET_IFNAME=data0.3001 + export GLOO_SOCKET_IFNAME=data0.3001 + export STREAMS_PER_DEVICE=32 + + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode \ + --host ${D_IP[$i]} --port 8001 --trust-remote-code \ + --nnodes 2 --node-rank $i --tp-size 32 --dp-size 32 --mem-fraction-static 0.83 --max-running-requests 768 \ + --attention-backend ascend --device npu --quantization modelslim --enable-dp-attention \ + --moe-a2a-backend ascend_fuseep --cuda-graph-bs 6 8 12 15 18 20 22 24 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-draft-model-quantization unquant \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --dist-init-addr xxx:5000 \ + --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --prefill-round-robin-balance --enable-dp-lm-head --dtype bfloat16 --tokenizer-worker-num 4 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://PIP:8000 8995 \ + --decode http://DIP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang-oai --host 127.0.0.1 --port 7239 --max-concurrency 860 --random-input-len 3500 --random-output-len 1500 --num-prompts 3440 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 3_5K-1_5K 50ms on A3 8 Cards Mixed Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=1600 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_SCHEDULER_DECREASE_PREFILL_IDLE=2 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 272 --context-length 8192 --dtype bfloat16 \ + --chunked-prefill-size 32768 --max-prefill-tokens 32768 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --disable-radix-cache --moe-a2a-backend deepep --deepep-mode auto --speculative-draft-model-quantization unquant \ + --tp 16 --dp-size 16 --enable-dp-attention --enable-dp-lm-head --mem-fraction-static 0.8 --cuda-graph-bs 3 4 6 8 10 12 13 14 15 16 17 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 272 --random-input-len 3500 --random-output-len 1500 --num-prompts 1088 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 2K-2K 100ms on A3 8 Cards Mixed Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 100ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=1200 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 576 --context-length 8192 --dtype bfloat16 \ + --chunked-prefill-size 32768 --max-prefill-tokens 458880 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --disable-radix-cache --moe-a2a-backend deepep --deepep-mode auto --speculative-draft-model-quantization unquant \ + --tp 16 --dp-size 16 --enable-dp-attention --enable-dp-lm-head --mem-fraction-static 0.81 --cuda-graph-bs 8 16 20 24 32 36 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 576 --random-input-len 2000 --random-output-len 2000 --num-prompts 576 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 2K-2K 50ms on A3 8 Cards Mixed Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=2100 +export HCCL_SOCKET_IFNAME=xxx +export GLOO_SOCKET_IFNAME=xxx +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 480 --context-length 8192 --dtype bfloat16 \ + --chunked-prefill-size -1 --max-prefill-tokens 4096 --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --disable-radix-cache --moe-a2a-backend deepep --deepep-mode auto \ + --tp 16 --dp-size 16 --enable-dp-attention --enable-dp-lm-head --mem-fraction-static 0.75 --cuda-graph-bs 6 8 10 12 15 18 28 30 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 480 --random-input-len 2048 --random-output-len 2048 --num-prompts 480 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 2K-2K 50ms on A3 16 Cards Mixed Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 16Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=1600 +export HCCL_SOCKET_IFNAME=xxx +export GLOO_SOCKET_IFNAME=xxx +export HCCL_OP_EXPANSION_MODE="AIV" + +MIX_IP=('IP1' 'IP2') + +for i in "${!MIX_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${MIX_IP[$i]}" || "$LOCAL_HOST2" == "${MIX_IP[$i]}" ]]; + then + echo "${MIX_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + + python -m sglang.launch_server --model-path ${MODEL_PATH} \ + --host 127.0.0.1 --port 7439 --trust-remote-code \ + --nnodes 2 --node-rank $i --tp-size 32 --dp-size 32 --mem-fraction-static 0.8 --max-running-requests 768 \ + --attention-backend ascend --device npu --quantization modelslim --enable-dp-attention \ + --moe-a2a-backend deepep --deepep-mode auto --cuda-graph-bs 6 8 10 12 18 24 \ + --dist-init-addr ${MIX_IP[0]}:5000 --chunked-prefill-size 131072 --max-prefill-tokens 458880 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx --speculative-draft-model-quantization= unquant \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --context-length 8192 --disable-radix-cache \ + --enable-dp-lm-head --dtype bfloat16 + NODE_RANK=$i + break + fi +done + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 768 --random-input-len 2000 --random-output-len 2000 --num-prompts 768 --random-range-ratio 1 +``` + +### Qwen3-235B-A22B 11K-1K 10ms on A3 8 Cards Mixed Mode + +Model: Qwen3-235B-A22B-W8A8 + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 11K+1K + +TPOT: 10ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=1600 +export HCCL_SOCKET_IFNAME=xxx +export GLOO_SOCKET_IFNAME=xxx +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 1 --dtype bfloat16 \ + --chunked-prefill-size -1 --max-prefill-tokens 16384 --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --disable-radix-cache --enable-dp-lm-head \ + --tp 16 --mem-fraction-static 0.78 --cuda-graph-bs 1 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 1 --random-input-len 11000 --random-output-len 1000 --num-prompts 1 --random-range-ratio 1 +``` + +### Qwen3-32B 6K-1_5K 18ms on A3 4 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A3 4Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 6K+1.5K + +TPOT: 18ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=xxx +export GLOO_SOCKET_IFNAME=xxx +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu \ + --max-running-requests 32 \ + --disable-radix-cache \ + --chunked-prefill-size 24576 --max-prefill-tokens 65536 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --tp-size 8 --mem-fraction-static 0.72 --cuda-graph-bs 8 16 24 32 --dtype bfloat16 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 32 --random-output-len 1500 --random-input-len 6000 --num-prompts 32 --random-range-ratio 1 +``` + +### Qwen3-32B 4K-1_5K 11ms on A3 4 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A3 4Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 4K+1.5K + +TPOT: 11ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7339 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu \ + --max-running-requests 1 \ + --disable-radix-cache \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --chunked-prefill-size 24576 --max-prefill-tokens 65536 \ + --tp-size 8 --mem-fraction-static 0.72 --cuda-graph-bs 1 --dtype bfloat16 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --random-range-ratio 1 --max-concurrency 1 --random-output-len 1500 --random-input-len 4096 --num-prompts 4 +``` + +### Qwen3-32B 18K-4K 12ms on A3 8 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 18K+4K + +TPOT: 12ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7339 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu \ + --max-running-requests 1 \ + --disable-radix-cache --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --chunked-prefill-size -1 --max-prefill-tokens 65536 \ + --tp-size 16 --mem-fraction-static 0.72 --cuda-graph-bs 1 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7339 --random-range-ratio 1 --max-concurrency 1 --random-output-len 18000 --random-input-len 4000 --num-prompts 1 +``` + +### Qwen3-32B 3_5K-1_5K 50ms on A3 2 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A3 2Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7239 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 78 \ + --disable-radix-cache --speculative-draft-model-quantization unquant \ + --chunked-prefill-size -1 --max-prefill-tokens 49152 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --tp-size 4 --mem-fraction-static 0.72 --cuda-graph-bs 16 32 64 68 72 78 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 78 --random-output-len 1500 --random-input-len 3500 --num-prompts 312 --random-range-ratio 1 +``` + +### Qwen3-32B 2K-2K 50ms on A3 2 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A3 2Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7239 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 120 \ + --disable-radix-cache --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --chunked-prefill-size -1 --max-prefill-tokens 49152 \ + --tp-size 4 --mem-fraction-static 0.7 --cuda-graph-bs 54 60 66 72 78 84 90 108 114 120 --dtype bfloat16 + +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 120 --random-output-len 2000 --random-input-len 2000 --num-prompts 480 --random-range-ratio 1 +``` + +### Qwen3-30B-A3B 3_5K-1_5K 50ms on A3 1 Card Mixed Mode + +Model: Qwen3-30B-A3B-Instruct-2507 + +Hardware: Atlas 800I A3 1Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7239 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 192 \ + --disable-radix-cache \ + --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --chunked-prefill-size -1 --max-prefill-tokens 32768 \ + --tp-size 2 --mem-fraction-static 0.86 --cuda-graph-bs 42 88 96 132 144 156 172 178 192 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 156 --random-input-len 3500 --random-output-len 1500 --num-prompts 624 --random-range-ratio 1 +``` + +### Qwen3-Coder-480B-A35B-Instruct 3_5K-1_5K 50ms on A3 24 Cards Separation Mode + +Model: Qwen3-Coder-480B-A35B-Instruct + +Hardware: Atlas 800I A3 24Card + +DeployMode: PD Separation + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING + +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=16 + +MODEL_PATH=xxx +export ASCEND_MF_STORE_URL="tcp://PIP:24667" +P_IP=('PIP') +D_IP=('DIP1' 'DIP2') +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + + +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + source /usr/local/Ascend/ascend-toolkit/set_env.sh + source /usr/local/Ascend/nnal/atb/set_env.sh + export DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS=1024 + export DEEPEP_NORMAL_LONG_SEQ_ROUND=16 + export HCCL_BUFFSIZE=4300 + export TASK_QUEUE_ENABLE=2 + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + export STREAMS_PER_DEVICE=32 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill \ + --host ${P_IP[$i]} --port 8000 --disaggregation-bootstrap-port 8995 --trust-remote-code \ + --nnodes 1 --node-rank $i --tp-size 16 --dp-size 2 --mem-fraction-static 0.6 \ + --disable-radix-cache \ + --attention-backend ascend --device npu --quantization modelslim --disaggregation-transfer-backend ascend \ + --max-running-requests 128 --chunked-prefill-size 65536 --max-prefill-tokens 262144 \ + --enable-dp-attention \ + --moe-a2a-backend deepep --deepep-mode normal --dtype bfloat16 + NODE_RANK=$i + break + fi +done + +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + source /usr/local/Ascend/ascend-toolkit/set_env.sh + source /usr/local/Ascend/nnal/atb/set_env.sh + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=72 + export HCCL_BUFFSIZE=512 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + export STREAMS_PER_DEVICE=32 + + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode \ + --host ${D_IP[$i]} --port 8001 --trust-remote-code \ + --nnodes 2 --node-rank $i --tp-size 32 --dp-size 4 --mem-fraction-static 0.73 --max-running-requests 384 \ + --attention-backend ascend --device npu --quantization modelslim --enable-dp-attention \ + --moe-a2a-backend ascend_fuseep --cuda-graph-bs 16 32 48 56 64 72 80 88 96 \ + --dist-init-addr DIP1:5000 \ + --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --prefill-round-robin-balance --enable-dp-lm-head --dtype bfloat16 --tokenizer-worker-num 4 --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done + +``` + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://PIP:8000 8995 \ + --decode http://DIP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 410 --random-input-len 3500 --random-output-len 1500 --num-prompts 1640 --random-range-ratio 1 --request-rate 8 +``` + +### Qwen3-Coder-480B-A35B-Instruct 3_5K-1_5K 50ms on A3 16 Cards Mixed Mode + +Model: Qwen3-Coder-480B-A35B-Instruct + +Hardware: Atlas 800I A3 16Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=16 + +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=1800 +export HCCL_SOCKET_IFNAME=xxx +export GLOO_SOCKET_IFNAME=xxx +export HCCL_OP_EXPANSION_MODE="AIV" + +MIX_IP=('IP1' 'IP2') + +for i in "${!MIX_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${MIX_IP[$i]}" || "$LOCAL_HOST2" == "${MIX_IP[$i]}" ]]; + then + echo "${MIX_IP[$i]}" + + python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 2 --node-rank $i \ + --dist-init-addr 141.61.133.128:5000 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 288 --context-length 8192 --dtype bfloat16 \ + --chunked-prefill-size 114688 --max-prefill-tokens 458880 \ + --disable-radix-cache --moe-a2a-backend deepep --deepep-mode auto \ + --tp 32 --dp-size 4 --enable-dp-attention --enable-dp-lm-head --mem-fraction-static 0.7 --cuda-graph-bs 56 64 72 + NODE_RANK=$i + break + fi +done +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 288 --random-input-len 3500 --random-output-len 1500 --num-prompts 1152 --random-range-ratio 1 --request-rate 20 +``` + +### Qwen3-Coder-480B-A35B-Instruct 3_5K-1_5K 50ms on A3 8 Cards Mixed Mode + +Model: Qwen3-Coder-480B-A35B-Instruct + +Hardware: Atlas 800I A3 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=2100 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" + +python -m sglang.launch_server --model-path $MODEL_PATH \ +--host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ +--attention-backend ascend --device npu --quantization modelslim \ +--max-running-requests 80 --context-length 8192 --dtype bfloat16 \ +--chunked-prefill-size 28672 --max-prefill-tokens 458880 \ +--disable-radix-cache --moe-a2a-backend deepep --deepep-mode auto --enable-dp-attention --enable-dp-lm-head \ +--tp 16 --dp-size 4 --mem-fraction-static 0.7 --cuda-graph-bs 16 20 24 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 80 --random-input-len 3500 --random-output-len 1500 --num-prompts 320 --random-range-ratio 1 +``` + +### Qwen3-Next-80B-A3B-Instruct 3_5K-1_5K 50ms on A3 2 Cards Mixed Mode + +Model: Qwen3-Next-80B-A3B-Instruct + +Hardware: Atlas 800I A3 2Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +export cann_path=/usr/local/Ascend/ascend-toolkit/latest +source /usr/local/Ascend/driver/bin/setenv.bash +source ${cann_path}/../set_env.sh +source ${cann_path}/../../nnal/atb/set_env.sh +source ${cann_path}/opp/vendors/customize/bin/set_env.bash +export ASCEND_HOME_PATH=${cann_path} +source /usr/local/Ascend/8.5.0/bisheng_toolkit/set_env.sh + +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_ALGO="level0:NA;level1:ring" + +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=20 +export HCCL_BUFFSIZE=2000 + +python -m sglang.launch_server \ + --model-path /path/to/Qwen3-Next-80B-A3B-Instruct-W8A8-3 \ + --host 127.0.0.1 \ + --port 6699 \ + --tp-size 4 \ + --device npu \ + --attention-backend ascend \ + --mem-fraction-static 0.685 \ + --max-running-requests 80 \ + --watchdog-timeout 3600 \ + --disable-radix-cache \ + --cuda-graph-bs 80 \ + --max-prefill-tokens 28672 --max-total-tokens 450560 \ + --moe-a2a-backend deepep --deepep-mode auto \ + --quantization modelslim \ + --chunked-prefill-size -1 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 6699 --max-concurrency 80 --random-output-len 1536 --random-input-len 3584 --num-prompts 160 --random-range-ratio 1 +``` + +### Qwen3-32B 6K-1_5K 18ms on A2 8 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A2 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 6K+1.5K + +TPOT: 18ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7439 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 32 \ + --disable-radix-cache \ + --chunked-prefill-size 24576 --max-prefill-tokens 65536 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --tp-size 8 --mem-fraction-static 0.72 --cuda-graph-bs 8 16 24 32 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7439 --max-concurrency 32 --random-output-len 1500 --random-input-len 6000 --num-prompts 32 --random-range-ratio 1 +``` + +### Qwen3-32B 4K-1_5K 11ms on A2 8 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A2 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 4K+1.5K + +TPOT: 11ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7339 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu \ + --max-running-requests 32 \ + --disable-radix-cache \ + --speculative-draft-model-quantization unquant \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 4 --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ + --chunked-prefill-size -1 --max-prefill-tokens 65536 \ + --tp-size 8 --mem-fraction-static 0.72 --cuda-graph-bs 1 4 6 12 18 24 30 32 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7339 --random-range-ratio 1 --max-concurrency 1 --random-output-len 1500 --random-input-len 4096 --num-prompts 4 +``` + +### Qwen3-32B 3_5K-1_5K 50ms on A2 8 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A2 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 3.5K+1.5K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7239 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 78 \ + --disable-radix-cache --speculative-draft-model-quantization unquant \ + --chunked-prefill-size -1 --max-prefill-tokens 65536 \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 \ + --tp-size 4 --mem-fraction-static 0.72 --cuda-graph-bs 1 4 8 16 32 64 68 72 78 --dtype bfloat16 --base-gpu-id 4 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 78 --random-output-len 1500 --random-input-len 3500 --num-prompts 312 --random-range-ratio 1 +``` + +### Qwen3-32B 2K-2K 50ms on A2 8 Cards Mixed Mode + +Model: Qwen3-32B + +Hardware: Atlas 800I A2 8Card + +DeployMode: PD Mixed + +Dataset: random + +Input Output Length: 2K+2K + +TPOT: 50ms + +#### Model Deployment + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 + +export SGLANG_SET_CPU_AFFINITY=1 +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +source /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/customize/bin/set_env.bash +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +MODEL_PATH=xxx + +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` + +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" + +export HCCL_BUFFSIZE=400 +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo +export HCCL_OP_EXPANSION_MODE="AIV" +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server --model-path $MODEL_PATH \ + --host 127.0.0.1 --port 7239 --trust-remote-code --nnodes 1 --node-rank 0 \ + --attention-backend ascend --device npu --quantization modelslim \ + --max-running-requests 120 \ + --disable-radix-cache \ + --speculative-algorithm EAGLE3 --speculative-draft-model-path xxx \ + --speculative-num-steps 3 --speculative-eagle-topk 1 --speculative-num-draft-tokens 4 --speculative-draft-model-quantization unquant \ + --chunked-prefill-size -1 --max-prefill-tokens 49152 --base-gpu-id 4 \ + --tp-size 4 --mem-fraction-static 0.7 --cuda-graph-bs 54 60 66 72 78 84 90 108 114 120 --dtype bfloat16 +``` + +#### Benchmark + +We tested it based on the `RANDOM` dataset. + +```shell +python3 -m sglang.bench_serving --dataset-name random --backend sglang --host 127.0.0.1 --port 7239 --max-concurrency 120 --random-output-len 2000 --random-input-len 2000 --num-prompts 120 --random-range-ratio 1 +``` diff --git a/sglang/docs/platforms/ascend_npu_deepseek_example.md b/sglang/docs/platforms/ascend_npu_deepseek_example.md new file mode 100644 index 0000000000000000000000000000000000000000..267d6ce7622aa8131a0409a950c3df96359b4494 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_deepseek_example.md @@ -0,0 +1,299 @@ +## DeepSeek examples + +### Running DeepSeek-V3 + +#### Running DeepSeek in PD mixed mode on 1 x Atlas 800I A3. + +W4A8 Model weights could be found [here](https://modelers.cn/models/Modelers_Park/DeepSeek-R1-0528-w4a8). + +```shell +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +#Deepep communication settings +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=32 +export HCCL_BUFFSIZE=1600 + +#spec overlap +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + +#npu acceleration operator +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 + +python3 -m sglang.launch_server \ + --model-path ${MODEL_PATH} \ + --tp 16 \ + --trust-remote-code \ + --attention-backend ascend \ + --device npu \ + --quantization modelslim \ + --watchdog-timeout 9000 \ + --cuda-graph-bs 8 16 24 28 32 \ + --mem-fraction-static 0.68 \ + --max-running-requests 128 \ + --context-length 8188 \ + --disable-radix-cache \ + --chunked-prefill-size -1 \ + --max-prefill-tokens 16384 \ + --moe-a2a-backend deepep \ + --deepep-mode auto \ + --enable-dp-attention \ + --dp-size 4 \ + --enable-dp-lm-head \ + --speculative-algorithm NEXTN \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 4 \ + --dtype bfloat16 +``` + +#### Running DeepSeek with PD disaggregation mode on 2 x Atlas 800I A3. + +W4A8 Model weights could be found [here](https://modelers.cn/models/Modelers_Park/DeepSeek-R1-0528-w4a8). + +1. Prefill: + +```shell +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +#memfabric config store +export ASCEND_MF_STORE_URL="tcp://:" + +#Deepep communication settings +export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 +export HCCL_BUFFSIZE=1536 + +#npu acceleration operator +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 +export TASK_QUEUE_ENABLE=2 + +python -m sglang.launch_server \ + --model-path ${MODEL_PATH} \ + --host $PREFILL_HOST_IP \ + --port 8000 \ + --disaggregation-mode prefill \ + --disaggregation-bootstrap-port 8996 \ + --disaggregation-transfer-backend ascend \ + --trust-remote-code \ + --nnodes 1 \ + --node-rank 0 \ + --tp-size 16 \ + --mem-fraction-static 0.6 \ + --attention-backend ascend \ + --device npu \ + --quantization modelslim \ + --load-balance-method round_robin \ + --max-running-requests 8 \ + --context-length 8192 \ + --disable-radix-cache \ + --chunked-prefill-size -1 \ + --max-prefill-tokens 28680 \ + --moe-a2a-backend deepep \ + --deepep-mode normal \ + --speculative-algorithm NEXTN \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 4 \ + --dp-size 2 \ + --enable-dp-attention \ + --disable-shared-experts-fusion \ + --dtype bfloat16 +``` + +2. Decode: + +```shell +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +#memfabric config store +export ASCEND_MF_STORE_URL="tcp://:" + +#Deepep communication settings +export HCCL_BUFFSIZE=720 +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=88 + +#spec overlap +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + +#npu acceleration operator +unset TASK_QUEUE_ENABLE +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 + +# suggest max-running-requests <= max-cuda-graph-bs * dp_size, Because when this value is exceeded, performance will significantly degrade. +python -m sglang.launch_server \ + --model-path ${MODEL_PATH} \ + --disaggregation-mode decode \ + --host $DECODE_HOST_IP \ + --port 8001 \ + --trust-remote-code \ + --nnodes 1 \ + --node-rank 0 \ + --tp-size 16 \ + --dp-size 16 \ + --mem-fraction-static 0.8 \ + --max-running-requests 352 \ + --attention-backend ascend \ + --device npu \ + --quantization modelslim \ + --prefill-round-robin-balance \ + --moe-a2a-backend deepep \ + --enable-dp-attention \ + --deepep-mode low_latency \ + --enable-dp-lm-head \ + --cuda-graph-bs 8 10 12 14 16 18 20 22 \ + --disaggregation-transfer-backend ascend \ + --watchdog-timeout 9000 \ + --context-length 8192 \ + --speculative-algorithm NEXTN \ + --speculative-num-steps 3 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 4 \ + --disable-shared-experts-fusion \ + --dtype bfloat16 \ + --tokenizer-worker-num 4 +``` + +3. SGLang Model Gateway (former Router) + +```shell +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://:8000 8996 \ + --decode http://:8001 \ + --host 127.0.0.1 \ + --port 6688 +``` + +#### Running DeepSeek with PD disaggregation on 4 x Atlas 800I A3. + +W8A8 Model weights could be found [here](https://modelers.cn/models/State_Cloud/Deepseek-R1-bf16-hfd-w8a8). + +1. Prefill & Decode: + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +export SGLANG_SET_CPU_AFFINITY=1 +unset ASCEND_LAUNCH_BLOCKING +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh +export PATH=/usr/local/Ascend/8.5.0/compiler/bishengir/bin:$PATH + +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 + +export ASCEND_MF_STORE_URL="tcp://your prefill ip1:24669" + +P_IP=('your prefill ip1' 'your prefill ip2') + +D_IP=('your decode ip1' 'your decode ip2') + +MODEL_PATH=xxx + +export SGLANG_NPU_USE_MLAPO=1 +export SGLANG_USE_FIA_NZ=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +echo "${LOCAL_HOST1}" +echo "${LOCAL_HOST2}" +# prefill +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + export HCCL_BUFFSIZE=1536 + export DEEP_NORMAL_MODE_USE_INT8_QUANT=1 + export TASK_QUEUE_ENABLE=2 + + export HCCL_SOCKET_IFNAME=lo + export GLOO_SOCKET_IFNAME=lo + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode prefill --host ${P_IP[$i]} \ + --port 8000 --disaggregation-bootstrap-port $((8998+$i)) --trust-remote-code --nnodes 1 --node-rank 0 \ + --tp-size 16 --mem-fraction-static 0.81 --attention-backend ascend --device npu --quantization modelslim \ + --disaggregation-transfer-backend ascend --max-running-requests 8 --context-length 8192 --disable-radix-cache \ + --chunked-prefill-size -1 --max-prefill-tokens 28680 --moe-a2a-backend deepep --deepep-mode normal \ + --speculative-algorithm NEXTN --speculative-num-steps 1 --speculative-eagle-topk 1 --speculative-num-draft-tokens 2 \ + --dp-size 2 --enable-dp-attention --disable-shared-experts-fusion --dtype bfloat16 --enable-attn-tp-input-scattered + NODE_RANK=$i + break + fi +done + +# decode +for i in "${!D_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${D_IP[$i]}" || "$LOCAL_HOST2" == "${D_IP[$i]}" ]]; + then + echo "${D_IP[$i]}" + export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + export SGLANG_ENABLE_SPEC_V2=1 + export HCCL_BUFFSIZE=650 + export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=78 + export TASK_QUEUE_ENABLE=1 + export SGLANG_SCHEDULER_SKIP_ALL_GATHER=1 + export HCCL_SOCKET_IFNAME=xxx + export GLOO_SOCKET_IFNAME=xxx + python -m sglang.launch_server --model-path ${MODEL_PATH} --disaggregation-mode decode --host ${D_IP[$i]} \ + --port 8001 --trust-remote-code --dist-init-addr ${D_IP[0]}:5000 --nnodes 2 --node-rank $i --tp-size 32 --dp-size 32 \ + --mem-fraction-static 0.815 --max-running-requests 832 --attention-backend ascend --device npu --quantization modelslim \ + --moe-a2a-backend deepep --enable-dp-attention --deepep-mode low_latency --enable-dp-lm-head --moe-dense-tp 1 \ + --cuda-graph-bs 12 14 16 18 20 22 24 26 --disaggregation-transfer-backend ascend --watchdog-timeout 9000 --context-length 8192 \ + --speculative-algorithm NEXTN --speculative-num-steps 2 --speculative-eagle-topk 1 --speculative-num-draft-tokens 3 \ + --tokenizer-worker-num 4 --prefill-round-robin-balance --disable-shared-experts-fusion --dtype bfloat16 \ + --load-balance-method decode_round_robin + NODE_RANK=$i + break + fi +done +``` + +2. SGLang Model Gateway (former Router): + +```shell +export SGLANG_DP_ROUND_ROBIN=1 +python -m sglang_router.launch_router \ + --pd-disaggregation \ + --policy cache_aware \ + --prefill http://P_IP:8000 8998 \ + --prefill http://P_IP:8000 8999 \ + --decode http://D_IP:8001 \ + --host 127.0.0.1 \ + --port 6688 \ + --mini-lb +``` + +#### test gsm8k + +```python +from types import SimpleNamespace +from sglang.test.few_shot_gsm8k import run_eval + +def gsm8k(): + args = SimpleNamespace( + num_shots=5, + data_path=None, + num_questions=200, + max_new_tokens=512, + parallel=32, + host=f"http://127.0.0.1", + port=6688, + ) + metrics = run_eval(args) + print(f"{metrics=}") + print(f"{metrics['accuracy']=}") +if __name__ == "__main__": + gsm8k() +``` diff --git a/sglang/docs/platforms/ascend_npu_environment_variables.md b/sglang/docs/platforms/ascend_npu_environment_variables.md new file mode 100644 index 0000000000000000000000000000000000000000..fce333ba2022c5b8107805e6d75a5585500752f4 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_environment_variables.md @@ -0,0 +1,39 @@ +# Environment Variables + +SGLang supports various environment variables related to Ascend NPU that can be used to configure its runtime behavior. +This document provides a list of commonly used environment variables and aims to stay updated over time. + +## Directly Used in SGLang + +| Environment Variable | Description | Default Value | +|--------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| `SGLANG_NPU_USE_MLAPO` | Adopts the `MLAPO` fusion operator in attention
preprocessing stage of the MLA model. | `false` | +| `SGLANG_USE_FIA_NZ` | Reshapes KV Cache for FIA NZ format.
`SGLANG_USE_FIA_NZ` must be enabled with `SGLANG_NPU_USE_MLAPO` | `false` | +| `SGLANG_NPU_USE_MULTI_STREAM` | Enable dual-stream computation of shared experts
and routing experts in DeepSeek models.
Enable dual-stream computation in DeepSeek NSA Indexer. | `false` | +| `SGLANG_NPU_DISABLE_ACL_FORMAT_WEIGHT` | Disable cast model weight tensor to a specific NPU
ACL format. | `false` | +| `SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK` | The maximum number of dispatched tokens on each rank. | `128` | + +## Used in DeepEP Ascend + +| Environment Variable | Description | Default Value | +|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------|---------------| +| `DEEPEP_NORMAL_LONG_SEQ_PER_ROUND_TOKENS` | Enable ant-moving function in dispatch stage. Indicates
the number of tokens transmitted per round on each rank. | `8192` | +| `DEEPEP_NORMAL_LONG_SEQ_ROUND` | Enable ant-moving function in dispatch stage. Indicates
the number of rounds transmitted on each rank. | `1` | +| `DEEPEP_NORMAL_COMBINE_ENABLE_LONG_SEQ` | Enable ant-moving function in combine stage.
The value `0` means disabled. | `0` | +| `MOE_ENABLE_TOPK_NEG_ONE` | Needs to be enabled when the expert ID to be processed by
DEEPEP contains -1. | `0` | +| `DEEP_NORMAL_MODE_USE_INT8_QUANT` | Quantizes x to int8 and returns (tensor, scales) in dispatch operator. | `0` | + +## Others + +| Environment Variable | Description | Default Value | +|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| `TASK_QUEUE_ENABLE` | Used to control the optimization level of the dispatch queue
about the task_queue operator. [Detail](https://www.hiascend.com/document/detail/zh/Pytorch/730/comref/Envvariables/docs/zh/environment_variable_reference/TASK_QUEUE_ENABLE.md) | `1` | +| `INF_NAN_MODE_ENABLE` | Controls whether the chip uses saturation mode or INF_NAN mode. [Detail](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/800alpha001/apiref/envref/envref_07_0056.html) | `1` | +| `STREAMS_PER_DEVICE` | Configures the maximum number of streams for the stream pool. [Detail](https://www.hiascend.com/document/detail/zh/Pytorch/720/comref/Envvariables/Envir_041.html) | `32` | +| `PYTORCH_NPU_ALLOC_CONF` | Controls the behavior of the cache allocator.
This variable changes memory usage and may cause performance fluctuations. [Detail](https://www.hiascend.com/document/detail/zh/Pytorch/700/comref/Envvariables/Envir_012.html) | | +| `ASCEND_MF_STORE_URL` | The address of config store in MemFabric during PD separation,
which is generally set to the IP address of the P primary node
with an arbitrary port number. | | +| `ASCEND_LAUNCH_BLOCKING` | Controls whether synchronous mode is enabled during operator execution. [Detail](https://www.hiascend.com/document/detail/zh/Pytorch/710/comref/Envvariables/Envir_006.html) | `0` | +| `HCCL_OP_EXPANSION_MODE` | Configures the expansion position for communication algorithm scheduling. [Detail](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/800alpha001/apiref/envref/envref_07_0094.html) | | +| `HCCL_BUFFSIZE` | Controls the size of the buffer area for shared data between two NPUs.
The unit is MB, and the value must be greater than or equal to 1. [Detail](https://www.hiascend.com/document/detail/zh/Pytorch/60RC3/ptmoddevg/trainingmigrguide/performance_tuning_0047.html) | `200` | +| `HCCL_SOCKET_IFNAME` | Configures the name of the network card used by the Host
during HCCL initialization. [Detail](https://www.hiascend.com/document/detail/zh/canncommercial/81RC1/apiref/envvar/envref_07_0075.html) | | +| `GLOO_SOCKET_IFNAME` | Configures the network interface name for GLOO communication. | | diff --git a/sglang/docs/platforms/ascend_npu_glm5_examples.md b/sglang/docs/platforms/ascend_npu_glm5_examples.md new file mode 100644 index 0000000000000000000000000000000000000000..0adfe1d94e7bb7a50bcd5158490ddb5d07da7578 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_glm5_examples.md @@ -0,0 +1,194 @@ +# GLM-5 examples + +## Introduction + +The GLM (General Language Model) series is an open-source bilingual large language model family jointly developed by the KEG Laboratory of Tsinghua University and Zhipu AI. This series of models has performed outstandingly in the field of Chinese NLP with its unique unified pre-training framework and bilingual capabilities. [GLM-5](https://huggingface.co/zai-org/GLM-5) adopts the DeepSeek-V3/V3.2 architecture, including the sparse attention (DSA) and multi-token prediction (MTP). Ascend supports GLM-5 with 0Day based on the SGLang inference framework, achieving low-code seamless enablement and compatibility with the mainstream distributed parallel capabilities within the current SGLang framework. We welcome developers to download and experience it. + +## Environment Preparation + +### Model Weight + +- `GLM-5.0`(BF16 version): [Download model weight](https://www.modelscope.cn/models/ZhipuAI/GLM-5). +- `GLM-5.0-w4a8`(Quantized version without mtp): [Download model weight](https://modelers.cn/models/Eco-Tech/GLM-5-w4a8). +- You can use [msmodelslim](https://gitcode.com/Ascend/msmodelslim) to quantify the model naively. + + +### Installation + +The dependencies required for the NPU runtime environment have been integrated into a Docker image and uploaded to the quay.io platform. You can directly pull it. + +```{code-block} bash +#Atlas 800 A3 +docker pull swr.cn-southwest-2.myhuaweicloud.com/base_image/dockerhub/lmsysorg/sglang:cann8.5.0-a3-glm5 +#Atlas 800 A2 +docker pull swr.cn-southwest-2.myhuaweicloud.com/base_image/dockerhub/lmsysorg/sglang:cann8.5.0-910b-glm5 + +#start container +docker run -itd --shm-size=16g --privileged=true --name ${NAME} \ +--privileged=true --net=host \ +-v /var/queue_schedule:/var/queue_schedule \ +-v /etc/ascend_install.info:/etc/ascend_install.info \ +-v /usr/local/sbin:/usr/local/sbin \ +-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ +-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \ +--device=/dev/davinci0:/dev/davinci0 \ +--device=/dev/davinci1:/dev/avinci1 \ +--device=/dev/davinci2:/dev/davinci2 \ +--device=/dev/davinci3:/dev/davinci3 \ +--device=/dev/davinci4:/dev/davinci4 \ +--device=/dev/davinci5:/dev/davinci5 \ +--device=/dev/davinci6:/dev/davinci6 \ +--device=/dev/davinci7:/dev/davinci7 \ +--device=/dev/davinci8:/dev/davinci8 \ +--device=/dev/davinci9:/dev/davinci9 \ +--device=/dev/davinci10:/dev/davinci10 \ +--device=/dev/davinci11:/dev/davinci11 \ +--device=/dev/davinci12:/dev/davinci12 \ +--device=/dev/davinci13:/dev/davinci13 \ +--device=/dev/davinci14:/dev/davinci14 \ +--device=/dev/davinci15:/dev/davinci15 \ +--device=/dev/davinci_manager:/dev/davinci_manager \ +--device=/dev/hisi_hdc:/dev/hisi_hdc \ +--entrypoint=bash \ +swr.cn-southwest-2.myhuaweicloud.com/base_image/dockerhub/lmsysorg/sglang:${TAG} +``` + +Note: Using this image, you need to update transformers to main branch +``` shell +# reinstall transformers +pip install git+https://github.com/huggingface/transformers.git +``` + +## Deployment + +### Single-node Deployment + +- Quantized model `glm5_w4a8` can be deployed on 1 Atlas 800 A3 (64G × 16) . + +Run the following script to execute online inference. + +```shell +# high performance cpu +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_NPU_USE_MULTI_STREAM=1 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 16 --nnodes 1 --node-rank 0 \ + --chunked-prefill-size 16384 --max-prefill-tokens 280000 \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.7 \ + --port 8000 \ + --served-model-name glm-5 \ + --cuda-graph-bs 16 \ + --quantization modelslim \ + --moe-a2a-backend deepep --deepep-mode auto +``` + +### Multi-node Deployment + +- `GLM-5-bf16`: require at least 2 Atlas 800 A3 (64G × 16). + +**A3 series** + +Modify the IP of 2 nodes, then run the same scripts on two nodes. + +**node 0/1** + +```shell +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_NPU_USE_MULTI_STREAM=1 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV + +# Run command ifconfig on two nodes, find out which inet addr has same IP with your node IP. That is your public interface, which should be added here +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + + +P_IP=('your ip1' 'your ip2') +P_MASTER="${P_IP[0]}:your port" +export SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT=600 + +export SGLANG_ENABLE_SPEC_V2=1 +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 + +LOCAL_HOST1=`hostname -I|awk -F " " '{print$1}'` +LOCAL_HOST2=`hostname -I|awk -F " " '{print$2}'` +for i in "${!P_IP[@]}"; +do + if [[ "$LOCAL_HOST1" == "${P_IP[$i]}" || "$LOCAL_HOST2" == "${P_IP[$i]}" ]]; + then + echo "${P_IP[$i]}" + python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 32 --nnodes 2 --node-rank $i --dist-init-addr $P_MASTER \ + --chunked-prefill-size 16384 --max-prefill-tokens 131072 \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.8\ + --port 8000 \ + --served-model-name glm-5 \ + --cuda-graph-max-bs 16 \ + --disable-radix-cache + NODE_RANK=$i + break + fi +done + +``` + +### Prefill-Decode Disaggregation + +Not test yet. + +### Using Benchmark + +Refer to [Benchmark and Profiling](../developer_guide/benchmark_and_profiling.md) for details. diff --git a/sglang/docs/platforms/ascend_npu_quantization.md b/sglang/docs/platforms/ascend_npu_quantization.md new file mode 100644 index 0000000000000000000000000000000000000000..4c40fde6e170c6471a895735b8fdc376ae311df4 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_quantization.md @@ -0,0 +1,21 @@ +Quantization on Ascend. + +To load already quantized models, simply load the model weights and config. Again, if the model has been quantized offline, there's no need to add `--quantization` argument when starting the engine. The quantization method will be automatically parsed from the downloaded `quant_model_description.json` or `config.json` config. + +[ModelSlim on Ascend support](https://github.com/sgl-project/sglang/pull/14504): +- [x] W4A4 dynamic linear +- [x] W8A8 static linear +- [x] W8A8 dynamic linear +- [x] W4A8 dynamic MOE +- [x] W8A8 dynamic MOE + +[AWQ on Ascend support](https://github.com/sgl-project/sglang/pull/10158): +- [x] W4A16 linear +- [x] W8A16 linear # Need to test +- [x] W4A16 MOE # Need to test + +Compressed-tensors (LLM Compressor) on Ascend support: +- [x] [W4A8 dynamic MOE with/without activation clip](https://github.com/sgl-project/sglang/pull/14736) # Need to test +- [x] [W4A16 MOE](https://github.com/sgl-project/sglang/pull/12759) +- [x] [W8A8 dynamic linear](https://github.com/sgl-project/sglang/pull/14504) +- [x] [W8A8 dynamic MOE](https://github.com/sgl-project/sglang/pull/14504) diff --git a/sglang/docs/platforms/ascend_npu_qwen3_5_examples.md b/sglang/docs/platforms/ascend_npu_qwen3_5_examples.md new file mode 100644 index 0000000000000000000000000000000000000000..124b571f6083df54438681b41b75b7804c8daa7e --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_qwen3_5_examples.md @@ -0,0 +1,231 @@ +# Qwen3.5 examples + +## Environment Preparation + +### Installation + +The dependencies required for the NPU runtime environment have been integrated into a Docker image and uploaded to the quay.io platform. You can directly pull it. + +```{code-block} bash +#Atlas 800 A3 +docker pull quay.io/ascend/sglang:v0.5.9-cann8.5.0-a3 +#Atlas 800 A2 +docker pull quay.io/ascend/sglang:v0.5.9-cann8.5.0-910b + +#start container +docker run -itd --shm-size=16g --privileged=true --name ${NAME} \ +--privileged=true --net=host \ +-v /var/queue_schedule:/var/queue_schedule \ +-v /etc/ascend_install.info:/etc/ascend_install.info \ +-v /usr/local/sbin:/usr/local/sbin \ +-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ +-v /usr/local/Ascend/firmware:/usr/local/Ascend/firmware \ +--device=/dev/davinci0:/dev/davinci0 \ +--device=/dev/davinci1:/dev/davinci1 \ +--device=/dev/davinci2:/dev/davinci2 \ +--device=/dev/davinci3:/dev/davinci3 \ +--device=/dev/davinci4:/dev/davinci4 \ +--device=/dev/davinci5:/dev/davinci5 \ +--device=/dev/davinci6:/dev/davinci6 \ +--device=/dev/davinci7:/dev/davinci7 \ +--device=/dev/davinci8:/dev/davinci8 \ +--device=/dev/davinci9:/dev/davinci9 \ +--device=/dev/davinci10:/dev/davinci10 \ +--device=/dev/davinci11:/dev/davinci11 \ +--device=/dev/davinci12:/dev/davinci12 \ +--device=/dev/davinci13:/dev/davinci13 \ +--device=/dev/davinci14:/dev/davinci14 \ +--device=/dev/davinci15:/dev/davinci15 \ +--device=/dev/davinci_manager:/dev/davinci_manager \ +--device=/dev/hisi_hdc:/dev/hisi_hdc \ +--entrypoint=bash \ +quay.io/ascend/sglang:${tag} +``` + +## Deployment + +### Single-node Deployment + +Run the following script to execute online inference. + +#### Qwen3.5 397B + +```shell +# high performance cpu +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 16 --nnodes 1 --node-rank 0 \ + --chunked-prefill-size 4096 --max-prefill-tokens 280000 \ + --disable-radix-cache \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.7 \ + --port 8000 \ + --cuda-graph-bs 16 \ + --quantization modelslim \ + --enable-multimodal \ + --mm-attention-backend ascend_attn \ + --dtype bfloat16 +``` + +#### Qwen3.5 122B + +```shell +# high performance cpu +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 8 --nnodes 1 --node-rank 0 \ + --chunked-prefill-size 4096 --max-prefill-tokens 280000 \ + --disable-radix-cache \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.7 \ + --port 8000 \ + --cuda-graph-bs 16 \ + --quantization modelslim \ + --enable-multimodal \ + --mm-attention-backend ascend_attn \ + --dtype bfloat16 +``` + +#### Qwen3.5 35B + +```shell +# high performance cpu +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 2 --nnodes 1 --node-rank 0 \ + --chunked-prefill-size 4096 --max-prefill-tokens 280000 \ + --disable-radix-cache \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.7 \ + --port 8000 \ + --cuda-graph-bs 16 \ + --quantization modelslim \ + --enable-multimodal \ + --mm-attention-backend ascend_attn \ + --dtype bfloat16 +``` + +#### Qwen3.5 27B + +```shell +# high performance cpu +echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor +sysctl -w vm.swappiness=0 +sysctl -w kernel.numa_balancing=0 +sysctl -w kernel.sched_migration_cost_ns=50000 +# bind cpu +export SGLANG_SET_CPU_AFFINITY=1 + +unset https_proxy +unset http_proxy +unset HTTPS_PROXY +unset HTTP_PROXY +unset ASCEND_LAUNCH_BLOCKING +# cann +source /usr/local/Ascend/ascend-toolkit/set_env.sh +source /usr/local/Ascend/nnal/atb/set_env.sh + +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1000 +export HCCL_OP_EXPANSION_MODE=AIV +export HCCL_SOCKET_IFNAME=lo +export GLOO_SOCKET_IFNAME=lo + +python3 -m sglang.launch_server \ + --model-path $MODEL_PATH \ + --attention-backend ascend \ + --device npu \ + --tp-size 2 \ + --chunked-prefill-size -1 --max-prefill-tokens 120000 \ + --disable-radix-cache \ + --trust-remote-code \ + --host 127.0.0.1 \ + --mem-fraction-static 0.8 \ + --port 8000 \ + --cuda-graph-bs 32 \ + --enable-multimodal \ + --mm-attention-backend ascend_attn +``` + +### Prefill-Decode Disaggregation + +Not test yet. + +### Using Benchmark + +Refer to [Benchmark and Profiling](../developer_guide/benchmark_and_profiling.md) for details. diff --git a/sglang/docs/platforms/ascend_npu_qwen3_examples.md b/sglang/docs/platforms/ascend_npu_qwen3_examples.md new file mode 100644 index 0000000000000000000000000000000000000000..5278a22a10012cefd5069f7776dc9f23d737b0a0 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_qwen3_examples.md @@ -0,0 +1,116 @@ +## Qwen3 examples + +### Running Qwen3 + +#### Running Qwen3-32B on 1 x Atlas 800I A3. + +Model weights could be found [here](https://huggingface.co/Qwen/Qwen3-32B) + +```shell +export SGLANG_SET_CPU_AFFINITY=1 +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1536 +export HCCL_OP_EXPANSION_MODE=AIV + +python -m sglang.launch_server \ + --device npu \ + --attention-backend ascend \ + --trust-remote-code \ + --tp-size 4 \ + --model-path Qwen/Qwen3-32B \ + --mem-fraction-static 0.8 +``` + +#### Running Qwen3-32B on 1 x Atlas 800I A3 with Qwen3-32B-Eagle3. + +Model weights could be found [here](https://huggingface.co/Qwen/Qwen3-32B) + +Speculative model weights could be found [here](https://huggingface.co/Zhihu-ai/Zhi-Create-Qwen3-32B-Eagle3) + +```shell +export SGLANG_SET_CPU_AFFINITY=1 +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_OP_EXPANSION_MODE=AIV +export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1 +export SGLANG_ENABLE_SPEC_V2=1 + +python -m sglang.launch_server \ + --device npu \ + --attention-backend ascend \ + --trust-remote-code \ + --tp-size 4 \ + --model-path Qwen/Qwen3-32B \ + --mem-fraction-static 0.8 \ + --speculative-algorithm EAGLE3 \ + --speculative-draft-model-path Qwen/Qwen3-32B-Eagle3 \ + --speculative-num-steps 1 \ + --speculative-eagle-topk 1 \ + --speculative-num-draft-tokens 2 +``` + +#### Running Qwen3-30B-A3B MOE on 1 x Atlas 800I A3. + +Model weights could be found [here](https://huggingface.co/Qwen/Qwen3-30B-A3B) + +```shell +export SGLANG_SET_CPU_AFFINITY=1 +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1536 +export HCCL_OP_EXPANSION_MODE=AIV +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=32 +export SGLANG_DEEPEP_BF16_DISPATCH=1 + +python -m sglang.launch_server \ + --device npu \ + --attention-backend ascend \ + --trust-remote-code \ + --tp-size 4 \ + --model-path Qwen/Qwen3-30B-A3B \ + --mem-fraction-static 0.8 +``` + +#### Running Qwen3-235B-A22B-Instruct-2507 MOE on 1 x Atlas 800I A3. + +Model weights could be found [here](https://huggingface.co/Qwen/Qwen3-235B-A22B-Instruct-2507) + +```shell +export SGLANG_SET_CPU_AFFINITY=1 +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1536 +export SGLANG_DEEPEP_NUM_MAX_DISPATCH_TOKENS_PER_RANK=32 +export SGLANG_DEEPEP_BF16_DISPATCH=1 + +python -m sglang.launch_server \ + --model-path Qwen/Qwen3-235B-A22B-Instruct-2507 \ + --tp-size 16 \ + --trust-remote-code \ + --attention-backend ascend \ + --device npu \ + --watchdog-timeout 9000 \ + --mem-fraction-static 0.8 +``` + +#### Running Qwen3-VL-8B-Instruct on 1 x Atlas 800I A3. + +Model weights could be found [here](https://huggingface.co/Qwen/Qwen3-VL-8B-Instruct) + +```shell +export SGLANG_SET_CPU_AFFINITY=1 +export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True +export STREAMS_PER_DEVICE=32 +export HCCL_BUFFSIZE=1536 +export HCCL_OP_EXPANSION_MODE=AIV + +python -m sglang.launch_server \ + --enable-multimodal \ + --attention-backend ascend \ + --mm-attention-backend ascend_attn \ + --trust-remote-code \ + --tp-size 4 \ + --model-path Qwen/Qwen3-VL-8B-Instruct \ + --mem-fraction-static 0.8 +``` diff --git a/sglang/docs/platforms/ascend_npu_support.rst b/sglang/docs/platforms/ascend_npu_support.rst new file mode 100644 index 0000000000000000000000000000000000000000..cd64c58f6cd557c718ca227f719d0f434cd28203 --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_support.rst @@ -0,0 +1,17 @@ +Ascend NPUs +=============================================================== + +.. toctree:: + :maxdepth: 1 + + ascend_npu.md + ascend_npu_support_features.md + ascend_npu_support_models.md + ascend_npu_deepseek_example.md + ascend_npu_qwen3_examples.md + mindspore_backend.md + ascend_contribution_guide.md + ascend_npu_best_practice.md + ascend_npu_qwen3_5_examples.md + ascend_npu_glm5_examples.md + ascend_npu_environment_variables.md diff --git a/sglang/docs/platforms/ascend_npu_support_features.md b/sglang/docs/platforms/ascend_npu_support_features.md new file mode 100644 index 0000000000000000000000000000000000000000..1749f525374b7645e27c29fd0933244a3b5232dc --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_support_features.md @@ -0,0 +1,487 @@ +# Support Features on Ascend NPU + +This section describes the basic functions and features supported by the Ascend NPU.If you encounter issues or have any +questions, please [open an issue](https://github.com/sgl-project/sglang/issues). + +If you want to know the meaning and usage of each parameter, +click [Server Arguments](https://docs.sglang.io/advanced_features/server_arguments.html). + +## Model and tokenizer + +| Argument | Defaults | Options | Server supported | +|----------------------------------------|----------|---------------------------------------|:----------------:| +| `--model-path`
`--model` | `None` | Type: str | A2, A3 | +| `--tokenizer-path` | `None` | Type: str | A2, A3 | +| `--tokenizer-mode` | `auto` | `auto`, `slow` | A2, A3 | +| `--tokenizer-worker-num` | `1` | Type: int | A2, A3 | +| `--skip-tokenizer-init` | `False` | bool flag (set to enable) | A2, A3 | +| `--load-format` | `auto` | `auto`, `safetensors` | A2, A3 | +| `--model-loader-`
`extra-config` | {} | Type: str | A2, A3 | +| `--trust-remote-code` | `False` | bool flag (set to enable) | A2, A3 | +| `--context-length` | `None` | Type: int | A2, A3 | +| `--is-embedding` | `False` | bool flag (set to enable) | A2, A3 | +| `--enable-multimodal` | `None` | bool flag (set to enable) | A2, A3 | +| `--revision` | `None` | Type: str | A2, A3 | +| `--model-impl` | `auto` | `auto`, `sglang`,
`transformers` | A2, A3 | + +## HTTP server + +| Argument | Defaults | Options | Server supported | +|------------------------|-------------|---------------------------|:----------------:| +| `--host` | `127.0.0.1` | Type: str | A2, A3 | +| `--port` | `30000` | Type: int | A2, A3 | +| `--skip-server-warmup` | `False` | bool flag (set to enable) | A2, A3 | +| `--warmups` | `None` | Type: str | A2, A3 | +| `--nccl-port` | `None` | Type: int | A2, A3 | +| `--fastapi-root-path` | `None` | Type: str | A2, A3 | +| `--grpc-mode` | `False` | bool flag (set to enable) | A2, A3 | + +## Quantization and data type + +| Argument | Defaults | Options | Server supported | +|---------------------------------------------|----------|-----------------------------------------|:----------------:| +| `--dtype` | `auto` | `auto`,
`float16`,
`bfloat16` | A2, A3 | +| `--quantization` | `None` | `modelslim` | A2, A3 | +| `--quantization-param-path` | `None` | Type: str | Special For GPU | +| `--kv-cache-dtype` | `auto` | `auto` | A2, A3 | +| `--enable-fp32-lm-head` | `False` | bool flag
(set to enable) | A2, A3 | +| `--modelopt-quant` | `None` | Type: str | Special For GPU | +| `--modelopt-checkpoint-`
`restore-path` | `None` | Type: str | Special For GPU | +| `--modelopt-checkpoint-`
`save-path` | `None` | Type: str | Special For GPU | +| `--modelopt-export-path` | `None` | Type: str | Special For GPU | +| `--quantize-and-serve` | `False` | bool flag
(set to enable) | Special For GPU | +| `--rl-quant-profile` | `None` | Type: str | Special For GPU | + +## Memory and scheduling + +| Argument | Defaults | Options | Server supported | +|-----------------------------------------------------|----------|--------------------------------|:----------------:| +| `--mem-fraction-static` | `None` | Type: float | A2, A3 | +| `--max-running-requests` | `None` | Type: int | A2, A3 | +| `--prefill-max-requests` | `None` | Type: int | A2, A3 | +| `--max-queued-requests` | `None` | Type: int | A2, A3 | +| `--max-total-tokens` | `None` | Type: int | A2, A3 | +| `--chunked-prefill-size` | `None` | Type: int | A2, A3 | +| `--max-prefill-tokens` | `16384` | Type: int | A2, A3 | +| `--schedule-policy` | `fcfs` | `lpm`, `fcfs` | A2, A3 | +| `--enable-priority-`
`scheduling` | `False` | bool flag
(set to enable) | A2, A3 | +| `--schedule-low-priority-`
`values-first` | `False` | bool flag
(set to enable) | A2, A3 | +| `--priority-scheduling-`
`preemption-threshold` | `10` | Type: int | A2, A3 | +| `--schedule-conservativeness` | `1.0` | Type: float | A2, A3 | +| `--page-size` | `128` | Type: int | A2, A3 | +| `--swa-full-tokens-ratio` | `0.8` | Type: float | A2, A3 | +| `--disable-hybrid-swa-memory` | `False` | bool flag
(set to enable) | A2, A3 | +| `--abort-on-priority-`
`when-disabled` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-dynamic-chunking` | `False` | bool flag
(set to enable) | A2, A3 | + +## Runtime options + +| Argument | Defaults | Options | Server supported | +|----------------------------------------------------|----------|---------------------------|:----------------:| +| `--device` | `None` | Type: str | A2, A3 | +| `--tensor-parallel-size`
`--tp-size` | `1` | Type: int | A2, A3 | +| `--pipeline-parallel-size`
`--pp-size` | `1` | Type: int | A2, A3 | +| `--pp-max-micro-batch-size` | `None` | Type: int | A2, A3 | +| `--pp-async-batch-depth` | `None` | Type: int | A2, A3 | +| `--stream-interval` | `1` | Type: int | A2, A3 | +| `--stream-output` | `False` | bool flag (set to enable) | A2, A3 | +| `--random-seed` | `None` | Type: int | A2, A3 | +| `--constrained-json-`
`whitespace-pattern` | `None` | Type: str | A2, A3 | +| `--constrained-json-`
`disable-any-whitespace` | `False` | bool flag (set to enable) | A2, A3 | +| `--watchdog-timeout` | `300` | Type: float | A2, A3 | +| `--soft-watchdog-timeout` | `300` | Type: float | A2, A3 | +| `--dist-timeout` | `None` | Type: int | A2, A3 | +| `--base-gpu-id` | `0` | Type: int | A2, A3 | +| `--gpu-id-step` | `1` | Type: int | A2, A3 | +| `--sleep-on-idle` | `False` | bool flag (set to enable) | A2, A3 | +| `--custom-sigquit-handler` | `None` | Optional[Callable] | A2, A3 | + +## Logging + +| Argument | Defaults | Options | Server supported | +|----------------------------------------------------|-------------------|--------------------------------|:----------------:| +| `--log-level` | `info` | Type: str | A2, A3 | +| `--log-level-http` | `None` | Type: str | A2, A3 | +| `--log-requests` | `False` | bool flag
(set to enable) | A2, A3 | +| `--log-requests-level` | `2` | `0`, `1`, `2`, `3` | A2, A3 | +| `--log-requests-format` | text | text, json | A2, A3 | +| `--crash-dump-folder` | `None` | Type: str | A2, A3 | +| `--enable-metrics` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-metrics-for-`
`all-schedulers` | `False` | bool flag
(set to enable) | A2, A3 | +| `--tokenizer-metrics-`
`custom-labels-header` | `x-custom-labels` | Type: str | A2, A3 | +| `--tokenizer-metrics-`
`allowed-custom-labels` | `None` | List[str] | A2, A3 | +| `--bucket-time-to-`
`first-token` | `None` | List[float] | A2, A3 | +| `--bucket-inter-token-`
`latency` | `None` | List[float] | A2, A3 | +| `--bucket-e2e-request-`
`latency` | `None` | List[float] | A2, A3 | +| `--collect-tokens-`
`histogram` | `False` | bool flag
(set to enable) | A2, A3 | +| `--prompt-tokens-buckets` | `None` | List[str] | A2, A3 | +| `--generation-tokens-buckets` | `None` | List[str] | A2, A3 | +| `--gc-warning-threshold-secs` | `0.0` | Type: float | A2, A3 | +| `--decode-log-interval` | `40` | Type: int | A2, A3 | +| `--enable-request-time-`
`stats-logging` | `False` | bool flag
(set to enable) | A2, A3 | +| `--kv-events-config` | `None` | Type: str | Special for GPU | +| `--enable-trace` | `False` | bool flag
(set to enable) | A2, A3 | +| `--oltp-traces-endpoint` | `localhost:4317` | Type: str | A2, A3 | + +## RequestMetricsExporter configuration + +| Argument | Defaults | Options | Server supported | +|---------------------------------------|----------|--------------------------------|:----------------:| +| `--export-metrics-to-`
`file` | `False` | bool flag
(set to enable) | A2, A3 | +| `--export-metrics-to-`
`file-dir` | `None` | Type: str | A2, A3 | + +## API related + +| Argument | Defaults | Options | Server supported | +|-------------------------|-----------|--------------------------------|:----------------:| +| `--api-key` | `None` | Type: str | A2, A3 | +| `--admin-api-key` | `None` | Type: str | A2, A3 | +| `--served-model-name` | `None` | Type: str | A2, A3 | +| `--weight-version` | `default` | Type: str | A2, A3 | +| `--chat-template` | `None` | Type: str | A2, A3 | +| `--completion-template` | `None` | Type: str | A2, A3 | +| `--enable-cache-report` | `False` | bool flag
(set to enable) | A2, A3 | +| `--reasoning-parser` | `None` | `deepseek-r1` | A2, A3 | +| `--tool-call-parser` | `None` | `llama`,`pythonic` | A2, A3 | +| `--sampling-defaults` | `model` | `openai`, `model` | A2, A3 | + +## Data parallelism + +| Argument | Defaults | Options | Server supported | +|----------------------------------------|---------------|-----------------------------------------------------------|:----------------:| +| `--data-parallel-size`
`--dp-size` | `1` | Type: int | A2, A3 | +| `--load-balance-method` | `round_robin` | `round_robin`,
`total_requests`,
`total_tokens` | A2, A3 | +| `--prefill-round-robin-balance` | `False` | bool flag
(set to enable) | A2, A3 | + +## Multi-node distributed serving + +| Argument | Defaults | Options | Server supported | +|-------------------------------------------|----------|-----------|:----------------:| +| `--dist-init-addr`
`--nccl-init-addr` | `None` | Type: str | A2, A3 | +| `--nnodes` | `1` | Type: int | A2, A3 | +| `--node-rank` | `0` | Type: int | A2, A3 | + +## Model override args + +| Argument | Defaults | Options | Server supported | +|--------------------------------------|----------|-----------|:----------------:| +| `--json-model-override-`
`args` | `{}` | Type: str | A2, A3 | +| `--preferred-sampling-`
`params` | `None` | Type: str | A2, A3 | + +## LoRA + +| Argument | Defaults | Options | Server supported | +|--------------------------|----------|-------------------------------------|:----------------:| +| `--enable-lora` | `False` | Bool flag
(set to enable) | A2, A3 | +| `--max-lora-rank` | `None` | Type: int | A2, A3 | +| `--lora-target-modules` | `None` | `all` | A2, A3 | +| `--lora-paths` | `None` | Type: List[str] /
JSON objects | A2, A3 | +| `--max-loras-per-batch` | `8` | Type: int | A2, A3 | +| `--max-loaded-loras` | `None` | Type: int | A2, A3 | +| `--lora-eviction-policy` | `lru` | `lru`,
`fifo` | A2, A3 | +| `--lora-backend` | `triton` | `triton` | A2, A3 | +| `--max-lora-chunk-size` | `16` | `16`, `32`,
`64`, `128` | Special for GPU | + +## Kernel Backends (Attention, Sampling, Grammar, GEMM) + +| Argument | Defaults | Options | Server supported | +|----------------------------------------|-------------------|------------------------------------------------------------------------------------------------|:----------------:| +| `--attention-backend` | `None` | `ascend` | A2, A3 | +| `--prefill-attention-backend` | `None` | `ascend` | A2, A3 | +| `--decode-attention-backend` | `None` | `ascend` | A2, A3 | +| `--sampling-backend` | `None` | `pytorch`,
`ascend` | A2, A3 | +| `--grammar-backend` | `None` | `xgrammar` | A2, A3 | +| `--mm-attention-backend` | `None` | `ascend_attn` | A2, A3 | +| `--nsa-prefill-backend` | `flashmla_sparse` | `flashmla_sparse`,
`flashmla_decode`,
`fa3`,
`tilelang`,
`aiter` | Special for GPU | +| `--nsa-decode-backend` | `fa3` | `flashmla_prefill`,
`flashmla_kv`,
`fa3`,
`tilelang`,
`aiter` | Special for GPU | +| `--fp8-gemm-backend` | `auto` | `auto`,
`deep_gemm`,
`flashinfer_trtllm`,
`flashinfer_cutlass`,
`flashinfer_deepgemm`,
`cutlass`,
`triton`,
`aiter` | Special for GPU | +| `--disable-flashinfer-`
`autotune` | `False` | bool flag
(set to enable) | Special for GPU | + +## Speculative decoding + +| Argument | Defaults | Options | Server supported | +|------------------------------------------------------------------|-----------|--------------------------|:----------------:| +| `--speculative-algorithm` | `None` | `EAGLE3`,
`NEXTN` | A2, A3 | +| `--speculative-draft-model-path`
`--speculative-draft-model` | `None` | Type: str | A2, A3 | +| `--speculative-draft-model-`
`revision` | `None` | Type: str | A2, A3 | +| `--speculative-draft-load-format` | `None` | `auto` | A2, A3 | +| `--speculative-num-steps` | `None` | Type: int | A2, A3 | +| `--speculative-eagle-topk` | `None` | Type: int | A2, A3 | +| `--speculative-num-draft-tokens` | `None` | Type: int | A2, A3 | +| `--speculative-accept-`
`threshold-single` | `1.0` | Type: float | Special for GPU | +| `--speculative-accept-`
`threshold-acc` | `1.0` | Type: float | Special for GPU | +| `--speculative-token-map` | `None` | Type: str | A2, A3 | +| `--speculative-attention-`
`mode` | `prefill` | `prefill`,
`decode` | A2, A3 | +| `--speculative-moe-runner-`
`backend` | `None` | `auto` | A2, A3 | +| `--speculative-moe-a2a-`
`backend` | `None` | `ascend_fuseep` | A2, A3 | +| `--speculative-draft-attention-backend` | `None` | `ascend` | A2, A3 | +| `--speculative-draft-model-quantization` | `None` | `unquant` | A2, A3 | + +## Ngram speculative decoding + +| Argument | Defaults | Options | Server supported | +|----------------------------------------------------|------------|--------------------|:----------------:| +| `--speculative-ngram-`
`min-match-window-size` | `1` | Type: int | Experimental | +| `--speculative-ngram-`
`max-match-window-size` | `12` | Type: int | Experimental | +| `--speculative-ngram-`
`min-bfs-breadth` | `1` | Type: int | Experimental | +| `--speculative-ngram-`
`max-bfs-breadth` | `10` | Type: int | Experimental | +| `--speculative-ngram-`
`match-type` | `BFS` | `BFS`,
`PROB` | Experimental | +| `--speculative-ngram-`
`branch-length` | `18` | Type: int | Experimental | +| `--speculative-ngram-`
`capacity` | `10000000` | Type: int | Experimental | + +## Expert parallelism + +| Argument | Defaults | Options | Server supported | +|-------------------------------------------------------|-----------|---------------------------------------------|:----------------:| +| `--expert-parallel-size`
`--ep-size`
`--ep` | `1` | Type: int | A2, A3 | +| `--moe-a2a-backend` | `none` | `none`,
`deepep`,
`ascend_fuseep` | A2, A3 | +| `--moe-runner-backend` | `auto` | `auto`, `triton` | A2, A3 | +| `--flashinfer-mxfp4-`
`moe-precision` | `default` | `default`,
`bf16` | Special for GPU | +| `--enable-flashinfer-`
`allreduce-fusion` | `False` | bool flag
(set to enable) | Special for GPU | +| `--deepep-mode` | `auto` | `normal`,
`low_latency`,
`auto` | A2, A3 | +| `--deepep-config` | `None` | Type: str | Special for GPU | +| `--ep-num-redundant-experts` | `0` | Type: int | A2, A3 | +| `--ep-dispatch-algorithm` | `None` | Type: str | A2, A3 | +| `--init-expert-location` | `trivial` | Type: str | A2, A3 | +| `--enable-eplb` | `False` | bool flag
(set to enable) | A2, A3 | +| `--eplb-algorithm` | `auto` | Type: str | A2, A3 | +| `--eplb-rebalance-layers-`
`per-chunk` | `None` | Type: int | A2, A3 | +| `--eplb-min-rebalancing-`
`utilization-threshold` | `1.0` | Type: float | A2, A3 | +| `--expert-distribution-`
`recorder-mode` | `None` | Type: str | A2, A3 | +| `--expert-distribution-`
`recorder-buffer-size` | `None` | Type: int | A2, A3 | +| `--enable-expert-distribution-`
`metrics` | `False` | bool flag (set to enable) | A2, A3 | +| `--moe-dense-tp-size` | `None` | Type: int | A2, A3 | +| `--elastic-ep-backend` | `None` | `none`, `mooncake` | Special for GPU | +| `--mooncake-ib-device` | `None` | Type: str | Special for GPU | + +## Mamba Cache + +| Argument | Defaults | Options | Server supported | +|------------------------------|-----------|-----------------------------------------------|:----------------:| +| `--max-mamba-cache-size` | `None` | Type: int | A2, A3 | +| `--mamba-ssm-dtype` | `float32` | `float32`,
`bfloat16` | A2, A3 | +| `--mamba-full-memory-ratio` | `0.2` | Type: float | A2, A3 | +| `--mamba-scheduler-strategy` | `auto` | `auto`,
`no_buffer`,
`extra_buffer` | A2, A3 | +| `--mamba-track-interval` | `256` | Type: int | A2, A3 | + +## Hierarchical cache + +| Argument | Defaults | Options | Server supported | +|-------------------------------------------------|-----------------|---------------------------------------------------------------------|:----------------:| +| `--enable-hierarchical-`
`cache` | `False` | bool flag
(set to enable) | A2, A3 | +| `--hicache-ratio` | `2.0` | Type: float | A2, A3 | +| `--hicache-size` | `0` | Type: int | A2, A3 | +| `--hicache-write-policy` | `write_through` | `write_back`,
`write_through`,
`write_through_selective` | A2, A3 | +| `--radix-eviction-policy` | `lru` | `lru`, `lfu` | A2, A3 | +| `--hicache-io-backend` | `kernel` | `kernel_ascend`,
`direct` | A2, A3 | +| `--hicache-mem-layout` | `layer_first` | `page_first_direct`,
`page_first_kv_split` | A2, A3 | +| `--hicache-storage-`
`backend` | `None` | `file` | A2, A3 | +| `--hicache-storage-`
`prefetch-policy` | `best_effort` | `best_effort`,
`wait_complete`,
`timeout` | Special for GPU | +| `--hicache-storage-`
`backend-extra-config` | `None` | Type: str | Special for GPU | + +## LMCache + +| Argument | Defaults | Options | Server supported | +|--------------------|----------|--------------------------------|:----------------:| +| `--enable-lmcache` | `False` | bool flag
(set to enable) | Special for GPU | + +## Offloading + +| Argument | Defaults | Options | Server supported | +|---------------------------|----------|-----------|:----------------:| +| `--cpu-offload-gb` | `0` | Type: int | A2, A3 | +| `--offload-group-size` | `-1` | Type: int | A2, A3 | +| `--offload-num-in-group` | `1` | Type: int | A2, A3 | +| `--offload-prefetch-step` | `1` | Type: int | A2, A3 | +| `--offload-mode` | `cpu` | Type: str | A2, A3 | + +## Args for multi-item scoring + +| Argument | Defaults | Options | Server supported | +|----------------------------------|----------|-----------|:----------------:| +| `--multi-item-scoring-delimiter` | `None` | Type: int | A2, A3 | + +## Optimization/debug options + +| Argument | Defaults | Options | Server supported | +|---------------------------------------------------------|----------|--------------------------------|:----------------:| +| `--disable-radix-cache` | `False` | bool flag
(set to enable) | A2, A3 | +| `--cuda-graph-max-bs` | `None` | Type: int | A2, A3 | +| `--cuda-graph-bs` | `None` | List[int] | A2, A3 | +| `--disable-cuda-graph` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-cuda-graph-`
`padding` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-profile-`
`cuda-graph` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-cudagraph-gc` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-nccl-nvls` | `False` | bool flag
(set to enable) | Special for GPU | +| `--enable-symm-mem` | `False` | bool flag
(set to enable) | Special for GPU | +| `--disable-flashinfer-`
`cutlass-moe-fp4-allgather` | `False` | bool flag
(set to enable) | Special for GPU | +| `--enable-tokenizer-`
`batch-encode` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-tokenizer-`
`batch-encode` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-outlines-`
`disk-cache` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-custom-`
`all-reduce` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-mscclpp` | `False` | bool flag
(set to enable) | Special for GPU | +| `--enable-torch-`
`symm-mem` | `False` | bool flag
(set to enable) | Special for GPU | +| `--disable-overlap`
`-schedule` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-mixed-`
`chunk` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-dp-attention` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-dp-lm-head` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-two-`
`batch-overlap` | `False` | bool flag
(set to enable) | Planned | +| `--enable-single-`
`batch-overlap` | `False` | bool flag
(set to enable) | A2, A3 | +| `--tbo-token-`
`distribution-threshold` | `0.48` | Type: float | Planned | +| `--enable-torch-`
`compile` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-torch-`
`compile-debug-mode` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-piecewise-`
`cuda-graph` | `False` | bool flag
(set to enable) | A2, A3 | +| `--piecewise-cuda-`
`graph-tokens` | `None` | Type: JSON
list | A2, A3 | +| `--piecewise-cuda-`
`graph-compiler` | `eager` | ["eager", "inductor"] | A2, A3 | +| `--torch-compile-max-bs` | `32` | Type: int | A2, A3 | +| `--piecewise-cuda-`
`graph-max-tokens` | `4096` | Type: int | A2, A3 | +| `--torchao-config` | `` | Type: str | Special for GPU | +| `--enable-nan-detection` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-p2p-check` | `False` | bool flag
(set to enable) | Special for GPU | +| `--triton-attention-`
`reduce-in-fp32` | `False` | bool flag
(set to enable) | Special for GPU | +| `--triton-attention-`
`num-kv-splits` | `8` | Type: int | Special for GPU | +| `--triton-attention-`
`split-tile-size` | `None` | Type: int | Special for GPU | +| `--delete-ckpt-`
`after-loading` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-memory-saver` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-weights-`
`cpu-backup` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-draft-weights-`
`cpu-backup` | `False` | bool flag
(set to enable) | A2, A3 | +| `--allow-auto-truncate` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-custom-`
`logit-processor` | `False` | bool flag
(set to enable) | A2, A3 | +| `--flashinfer-mla-`
`disable-ragged` | `False` | bool flag
(set to enable) | Special for GPU | +| `--disable-shared-`
`experts-fusion` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-chunked-`
`prefix-cache` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disable-fast-`
`image-processor` | `False` | bool flag
(set to enable) | A2, A3 | +| `--keep-mm-feature-`
`on-device` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-return-`
`hidden-states` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-return-`
`routed-experts` | `False` | bool flag
(set to enable) | A2, A3 | +| `--scheduler-recv-`
`interval` | `1` | Type: int | A2, A3 | +| `--numa-node` | `None` | List[int] | A2, A3 | +| `--rl-on-policy-target` | `None` | `fsdp` | Planned | +| `--enable-layerwise-`
`nvtx-marker` | `False` | bool flag
(set to enable) | Special for GPU | +| `--enable-attn-tp-`
`input-scattered` | `False` | bool flag
(set to enable) | Experimental | +| `--enable-nsa-prefill-`
`context-parallel` | `False` | bool flag
(set to enable) | A2, A3 | +| `--enable-fused-qk-`
`norm-rope` | `False` | bool flag
(set to enable) | Special for GPU | + +## Dynamic batch tokenizer + +| Argument | Defaults | Options | Server supported | +|--------------------------------------------------|----------|--------------------------------|:----------------:| +| `--enable-dynamic-`
`batch-tokenizer` | `False` | bool flag
(set to enable) | A2, A3 | +| `--dynamic-batch-`
`tokenizer-batch-size` | `32` | Type: int | A2, A3 | +| `--dynamic-batch-`
`tokenizer-batch-timeout` | `0.002` | Type: float | A2, A3 | + +## Debug tensor dumps + +| Argument | Defaults | Options | Server supported | +|--------------------------------------------|----------|-----------|:----------------:| +| `--debug-tensor-dump-`
`output-folder` | `None` | Type: str | A2, A3 | +| `--debug-tensor-dump-`
`layers` | `None` | List[int] | A2, A3 | +| `--debug-tensor-dump-`
`input-file` | `None` | Type: str | A2, A3 | + +## PD disaggregation + +| Argument | Defaults | Options | Server supported | +|---------------------------------------------------------|------------|---------------------------------------|:----------------:| +| `--disaggregation-mode` | `null` | `null`,
`prefill`,
`decode` | A2, A3 | +| `--disaggregation-transfer-backend` | `mooncake` | `ascend` | A2, A3 | +| `--disaggregation-bootstrap-port` | `8998` | Type: int | A2, A3 | +| `--disaggregation-decode-tp` | `None` | Type: int | A2, A3 | +| `--disaggregation-decode-dp` | `None` | Type: int | A2, A3 | +| `--disaggregation-ib-device` | `None` | Type: str | Special for GPU | +| `--disaggregation-decode-`
`enable-offload-kvcache` | `False` | bool flag
(set to enable) | A2, A3 | +| `--disaggregation-decode-`
`enable-fake-auto` | `False` | bool flag
(set to enable) | A2, A3 | +| `--num-reserved-decode-tokens` | `512` | Type: int | A2, A3 | +| `--disaggregation-decode-`
`polling-interval` | `1` | Type: int | A2, A3 | + +## Encode prefill disaggregation + +| Argument | Defaults | Options | Server supported | +|------------------------------|--------------------|----------------------------------------------------------------|:----------------:| +| `--encoder-only` | `False` | bool flag
(set to enable) | A2, A3 | +| `--language-only` | `False` | bool flag
(set to enable) | A2, A3 | +| `--encoder-transfer-backend` | `zmq_to_scheduler` | `zmq_to_scheduler`,
`zmq_to_tokenizer`,
`mooncake` | A2, A3 | +| `--encoder-urls` | `[]` | List[str] | A2, A3 | + +## Custom weight loader + +| Argument | Defaults | Options | Server supported | +|-------------------------------------------------------------------------|----------|---------------------------------|:----------------:| +| `--custom-weight-loader` | `None` | List[str] | A2, A3 | +| `--weight-loader-disable-`
`mmap` | `False` | bool flag
(set to enable) | A2, A3 | +| `--remote-instance-weight-`
`loader-seed-instance-ip` | `None` | Type: str | A2, A3 | +| `--remote-instance-weight-`
`loader-seed-instance-service-port` | `None` | Type: int | A2, A3 | +| `--remote-instance-weight-`
`loader-send-weights-group-ports` | `None` | Type: JSON
list | A2, A3 | +| `--remote-instance-weight-`
`loader-backend` | `nccl` | `transfer_engine`,
`nccl` | A2, A3 | +| `--remote-instance-weight-`
`loader-start-seed-via-transfer-engine` | `False` | bool flag
(set to enable) | Special for GPU | + +## For PD-Multiplexing + +| Argument | Defaults | Options | Server supported | +|-----------------------|----------|--------------------------------|:----------------:| +| `--enable-pdmux` | `False` | bool flag
(set to enable) | Special for GPU | +| `--pdmux-config-path` | `None` | Type: str | Special for GPU | +| `--sm-group-num` | `8` | Type: int | Special for GPU | + +## For Multi-Modal + +| Argument | Defaults | Options | Server supported | +|-----------------------------------------------|----------|--------------------------------|:----------------:| +| `--mm-max-concurrent-calls` | 32 | Type: int | A2, A3 | +| `--mm-per-request-timeout` | 10.0 | Type: float | A2, A3 | +| `--enable-broadcast-mm-`
`inputs-process` | `False` | bool flag
(set to enable) | A2, A3 | +| `--mm-process-config` | `None` | Type: JSON / Dict | A2, A3 | +| `--mm-enable-dp-encoder` | `False` | bool flag
(set to enable) | A2, A3 | +| `--limit-mm-data-per-request` | `None` | Type: JSON / Dict | A2, A3 | + +## For checkpoint decryption + +| Argument | Defaults | Options | Server supported | +|---------------------------------|----------|--------------------------------|:----------------:| +| `--decrypted-config-file` | `None` | Type: str | A2, A3 | +| `--decrypted-draft-config-file` | `None` | Type: str | A2, A3 | +| `--enable-prefix-mm-cache` | `False` | bool flag
(set to enable) | A2, A3 | + +## For deterministic inference + +| Argument | Defaults | Options | Server supported | +|-------------------------------------------|----------|--------------------------------|:----------------:| +| `--enable-deterministic-`
`inference` | `False` | bool flag
(set to enable) | Planned | + +## For registering hooks + +| Argument | Defaults | Options | Server supported | +|-------------------|----------|-----------------|:----------------:| +| `--forward-hooks` | `None` | Type: JSON list | A2, A3 | + +## Configuration file support + +| Argument | Defaults | Options | Server supported | +|------------|----------|-----------|:----------------:| +| `--config` | `None` | Type: str | A2, A3 | + +## Other Params + +The following parameters are not supported because the third-party components that depend on are not compatible with the +NPU, like Ktransformer, checkpoint-engine etc. + +| Argument | Defaults | Options | +|-------------------------------------------------------------------|-----------|---------------------------| +| `--checkpoint-engine-`
`wait-weights-`
`before-ready` | `False` | bool flag (set to enable) | +| `--kt-weight-path` | `None` | Type: str | +| `--kt-method` | `AMXINT4` | Type: str | +| `--kt-cpuinfer` | `None` | Type: int | +| `--kt-threadpool-count` | 2 | Type: int | +| `--kt-num-gpu-experts` | `None` | Type: int | +| `--kt-max-deferred-`
`experts-per-token` | `None` | Type: int | + +The following parameters have some functional deficiencies on community + +| Argument | Defaults | Options | +|---------------------------------------|----------|--------------------------------| +| `--enable-double-sparsity` | `False` | bool flag
(set to enable) | +| `--ds-channel-config-path` | `None` | Type: str | +| `--ds-heavy-channel-num` | `32` | Type: int | +| `--ds-heavy-token-num` | `256` | Type: int | +| `--ds-heavy-channel-type` | `qk` | Type: str | +| `--ds-sparse-decode-`
`threshold` | `4096` | Type: int | +| `--tool-server` | `None` | Type: str | diff --git a/sglang/docs/platforms/ascend_npu_support_models.md b/sglang/docs/platforms/ascend_npu_support_models.md new file mode 100644 index 0000000000000000000000000000000000000000..a30b6d21aadbafb98d8a284cb0a7394dee17f65e --- /dev/null +++ b/sglang/docs/platforms/ascend_npu_support_models.md @@ -0,0 +1,110 @@ +# Support Models on Ascend NPU + +This section describes the models supported on the Ascend NPU, including Large Language Models, Multimodal Language +Models, Embedding Models, Reward Models and Rerank Models. Mainstream DeepSeek/Qwen/GLM series are included. +You are welcome to enable various models based on your business requirements. + +## Large Language Models + +| Models | Model Family | A2 Supported | A3 Supported | +|--------------------------------------------|--------------------------------|:----------------------------------------:|:----------------------------------------:| +| DeepSeek V3/V3.1 | DeepSeek | **** | **** | +| DeepSeek-V3.2-Exp-W8A8 | DeepSeek | **** | **** | +| DeepSeek-R1-0528-W8A8 | DeepSeek | **** | **** | +| DeepSeek-V2-Lite-W8A8 | DeepSeek | **** | **** | +| Qwen/Qwen3-30B-A3B-Instruct-2507 | Qwen | **** | **** | +| Qwen/Qwen3-32B | Qwen | **** | **** | +| Qwen/Qwen3-0.6B | Qwen | **** | **** | +| Qwen3-235B-A22B-W8A8 | Qwen | **** | **** | +| Qwen/Qwen3-Next-80B-A3B-Instruct | Qwen | **** | **** | +| Qwen3-Coder-480B-A35B-Instruct-w8a8-QuaRot | Qwen | **** | **** | +| Qwen/Qwen2.5-7B-Instruct | Qwen | **** | **** | +| QWQ-32B-W8A8 | Qwen | **** | **** | +| meta-llama/Llama-4-Scout-17B-16E-Instruct | Llama | **** | **** | +| AI-ModelScope/Llama-3.1-8B-Instruct | Llama | **** | **** | +| LLM-Research/llama-2-7b | Llama | **** | **** | +| LLM-Research/Llama-3.2-1B-Instruct | Llama | **** | **** | +| mistralai/Mistral-7B-Instruct-v0.2 | Mistral | **** | **** | +| google/gemma-3-4b-it | Gemma | **** | **** | +| microsoft/Phi-4-multimodal-instruct | Phi | **** | **** | +| allenai/OLMoE-1B-7B-0924 | OLMoE | **** | **** | +| stabilityai/stablelm-2-1_6b | StableLM | **** | **** | +| CohereForAI/c4ai-command-r-v01 | Command-R | **** | **** | +| huihui-ai/grok-2 | Grok | **** | **** | +| ZhipuAI/chatglm2-6b | ChatGLM | **** | **** | +| Shanghai_AI_Laboratory/internlm2-7b | InternLM 2 | **** | **** | +| LGAI-EXAONE/EXAONE-3.5-7.8B-Instruct | ExaONE 3 | **** | **** | +| xverse/XVERSE-MoE-A36B | XVERSE | **** | **** | +| HuggingFaceTB/SmolLM-1.7B | SmolLM | **** | **** | +| ZhipuAI/glm-4-9b-chat | GLM-4 | **** | **** | +| XiaomiMiMo/MiMo-7B-RL | MiMo | **** | **** | +| arcee-ai/AFM-4.5B-Base | Arcee AFM-4.5B | **** | **** | +| Howeee/persimmon-8b-chat | Persimmon | **** | **** | +| inclusionAI/Ling-lite | Ling | **** | **** | +| ibm-granite/granite-3.1-8b-instruct | Granite | **** | **** | +| ibm-granite/granite-3.0-3b-a800m-instruct | Granite MoE | **** | **** | +| AI-ModelScope/dbrx-instruct | DBRX (Databricks) | **** | **** | +| baichuan-inc/Baichuan2-13B-Chat | Baichuan 2 (7B, 13B) | **** | **** | +| baidu/ERNIE-4.5-21B-A3B-PT | ERNIE-4.5 (4.5, 4.5MoE series) | **** | **** | +| OpenBMB/MiniCPM3-4B | MiniCPM (v3, 4B) | **** | **** | +| Kimi/Kimi-K2-Thinking | Kimi | **** | **** | +| openai/gpt-oss-120b | GPTOSS | **** | **** | +| allenai/OLMo-2-1124-7B-Instruct | OLMo | **** | **** | +| minimax/MiniMax-M2 | MiniMax-M2 | **** | **** | +| upstage/SOLAR-10.7B-Instruct-v1.0 | Solar | **** | **** | +| bigcode/starcoder2-7b | StarCoder2 | **** | **** | +| arcee-ai/Trinity-Mini | Trinity (Nano, Mini) | **** | **** | + +## Multimodal Language Models + +| Models | Model Family (Variants) | A2 Supported | A3 Supported | +|-----------------------------------------------|---------------------------|:----------------------------------------:|:----------------------------------------:| +| Qwen/Qwen2.5-VL-3B-Instruct | Qwen-VL | **** | **** | +| Qwen/Qwen2.5-VL-72B-Instruct | Qwen-VL | **** | **** | +| Qwen/Qwen3-VL-30B-A3B-Instruct | Qwen-VL | **** | **** | +| Qwen/Qwen3-VL-8B-Instruct | Qwen-VL | **** | **** | +| Qwen/Qwen3-VL-4B-Instruct | Qwen-VL | **** | **** | +| Qwen/Qwen3-VL-235B-A22B-Instruct | Qwen-VL | **** | **** | +| deepseek-ai/deepseek-vl2 | DeepSeek-VL2 | **** | **** | +| deepseek-ai/Janus-Pro-1B | Janus-Pro (1B, 7B) | **** | **** | +| deepseek-ai/Janus-Pro-7B | Janus-Pro (1B, 7B) | **** | **** | +| openbmb/MiniCPM-V-2_6 | MiniCPM-V / MiniCPM-o | **** | **** | +| openbmb/MiniCPM-o-2_6 | MiniCPM-V / MiniCPM-o | **** | **** | +| google/gemma-3-4b-it | Gemma 3 (Multimodal) | **** | **** | +| mistralai/Mistral-Small-3.1-24B-Instruct-2503 | Mistral-Small-3.1-24B | **** | **** | +| microsoft/Phi-4-multimodal-instruct | Phi-4-multimodal-instruct | **** | **** | +| XiaomiMiMo/MiMo-VL-7B-RL | MiMo-VL (7B) | **** | **** | +| AI-ModelScope/llava-v1.6-34b | LLaVA (v1.5 & v1.6) | **** | **** | +| lmms-lab/llava-next-72b | LLaVA-NeXT (8B, 72B) | **** | **** | +| lmms-lab/llava-onevision-qwen2-7b-ov | LLaVA-OneVision | **** | **** | +| Kimi/Kimi-VL-A3B-Instruct | Kimi-VL (A3B) | **** | **** | +| ZhipuAI/GLM-4.5V | GLM-4.5V (106B) | **** | **** | +| LLM-Research/Llama-3.2-11B-Vision-Instruct | Llama 3.2 Vision (11B) | **** | **** | +| rednote-hilab/dots.ocr | DotsVLM-OCR | **** | **** | + +## Embedding Models + +| Models | Model Family | A2 Supported | A3 Supported | +|-------------------------------------------|--------------------------|:----------------------------------------:|:----------------------------------------:| +| intfloat/e5-mistral-7b-instruct | E5 (Llama/Mistral based) | **** | **** | +| iic/gte_Qwen2-1.5B-instruct | GTE-Qwen2 | **** | **** | +| Qwen/Qwen3-Embedding-8B | Qwen3-Embedding | **** | **** | +| Alibaba-NLP/gme-Qwen2-VL-2B-Instruct | GME (Multimodal) | **** | **** | +| AI-ModelScope/clip-vit-large-patch14-336 | CLIP | **** | **** | +| BAAI/bge-large-en-v1.5 | BGE | **** | **** | + +## Reward Models + +| Models | Model Family | A2 Supported | A3 Supported | +|------------------------------------------------|---------------------------|------------------------------------------|:----------------------------------------:| +| Skywork/Skywork-Reward-Llama-3.1-8B-v0.2 | Llama3.1 Reward | **** | **** | +| Shanghai_AI_Laboratory/internlm2-7b-reward | InternLM 2 Reward | **** | **** | +| Qwen/Qwen2.5-Math-RM-72B | Qwen2.5 Reward - Math | **** | **** | +| Howeee/Qwen2.5-1.5B-apeach | Qwen2.5 Reward - Sequence | **** | **** | +| AI-ModelScope/Skywork-Reward-Gemma-2-27B-v0.2 | Gemma 2-27B Reward | **** | **** | + +## Rerank Models + +| Models | Model Family | A2 Supported | A3 Supported | +|-------------------------|--------------|:----------------------------------------:|:----------------------------------------:| +| BAAI/bge-reranker-v2-m3 | BGE-Reranker | **** | **** | diff --git a/sglang/docs/platforms/cpu_server.md b/sglang/docs/platforms/cpu_server.md new file mode 100644 index 0000000000000000000000000000000000000000..14b468ff0f76bc762610926cd553fc19dc7368d1 --- /dev/null +++ b/sglang/docs/platforms/cpu_server.md @@ -0,0 +1,318 @@ +# CPU Servers + +The document addresses how to set up the [SGLang](https://github.com/sgl-project/sglang) environment and run LLM inference on CPU servers. +SGLang is enabled and optimized on the CPUs equipped with Intel® AMX® Instructions, +which are 4th generation or newer Intel® Xeon® Scalable Processors. + +## Optimized Model List + +A list of popular LLMs are optimized and run efficiently on CPU, +including the most notable open-source models like Llama series, Qwen series, +and DeepSeek series like DeepSeek-R1 and DeepSeek-V3.1-Terminus. + +| Model Name | BF16 | W8A8_INT8 | FP8 | +|:---:|:---:|:---:|:---:| +| DeepSeek-R1 | | [meituan/DeepSeek-R1-Channel-INT8](https://huggingface.co/meituan/DeepSeek-R1-Channel-INT8) | [deepseek-ai/DeepSeek-R1](https://huggingface.co/deepseek-ai/DeepSeek-R1) | +| DeepSeek-V3.1-Terminus | | [IntervitensInc/DeepSeek-V3.1-Terminus-Channel-int8](https://huggingface.co/IntervitensInc/DeepSeek-V3.1-Terminus-Channel-int8) | [deepseek-ai/DeepSeek-V3.1-Terminus](https://huggingface.co/deepseek-ai/DeepSeek-V3.1-Terminus) | +| Llama-3.2-3B | [meta-llama/Llama-3.2-3B-Instruct](https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct) | [RedHatAI/Llama-3.2-3B-quantized.w8a8](https://huggingface.co/RedHatAI/Llama-3.2-3B-Instruct-quantized.w8a8) | | +| Llama-3.1-8B | [meta-llama/Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) | [RedHatAI/Meta-Llama-3.1-8B-quantized.w8a8](https://huggingface.co/RedHatAI/Meta-Llama-3.1-8B-quantized.w8a8) | | +| QwQ-32B | | [RedHatAI/QwQ-32B-quantized.w8a8](https://huggingface.co/RedHatAI/QwQ-32B-quantized.w8a8) | | +| DeepSeek-Distilled-Llama | | [RedHatAI/DeepSeek-R1-Distill-Llama-70B-quantized.w8a8](https://huggingface.co/RedHatAI/DeepSeek-R1-Distill-Llama-70B-quantized.w8a8) | | +| Qwen3-235B | | | [Qwen/Qwen3-235B-A22B-FP8](https://huggingface.co/Qwen/Qwen3-235B-A22B-FP8) | + +**Note:** The model identifiers listed in the table above +have been verified on 6th Gen Intel® Xeon® P-core platforms. + +## Installation + +### Install Using Docker + +It is recommended to use Docker for setting up the SGLang environment. +A [Dockerfile](https://github.com/sgl-project/sglang/blob/main/docker/xeon.Dockerfile) is provided to facilitate the installation. +Replace `` below with your [HuggingFace access token](https://huggingface.co/docs/hub/en/security-tokens). + +```bash +# Clone the SGLang repository +git clone https://github.com/sgl-project/sglang.git +cd sglang/docker + +# Build the docker image +docker build -t sglang-cpu:latest -f xeon.Dockerfile . + +# Initiate a docker container +docker run \ + -it \ + --privileged \ + --ipc=host \ + --network=host \ + -v /dev/shm:/dev/shm \ + -v ~/.cache/huggingface:/root/.cache/huggingface \ + -p 30000:30000 \ + -e "HF_TOKEN=" \ + sglang-cpu:latest /bin/bash +``` + +### Install From Source + +If you prefer to install SGLang in a bare metal environment, +the setup process is as follows: + +Please install the required packages and libraries beforehand if +they are not already present on your system. +You can refer to the Ubuntu-based installation commands in +[the Dockerfile](https://github.com/sgl-project/sglang/blob/main/docker/xeon.Dockerfile#L11) +for guidance. + +1. Install `uv` package manager, then create and activate a virtual environment: + +```bash +# Taking '/opt' as the example uv env folder, feel free to change it as needed +cd /opt +curl -LsSf https://astral.sh/uv/install.sh | sh +source $HOME/.local/bin/env +uv venv --python 3.12 +source .venv/bin/activate +``` + +2. Create a config file to direct the installation channel + (a.k.a. index-url) of `torch` related packages: + +```bash +vim .venv/uv.toml +``` + +Press 'a' to enter insert mode of `vim`, paste the following content into the created file + +```file +[[index]] +name = "torch" +url = "https://download.pytorch.org/whl/cpu" + +[[index]] +name = "torchvision" +url = "https://download.pytorch.org/whl/cpu" + +[[index]] +name = "torchaudio" +url = "https://download.pytorch.org/whl/cpu" + +[[index]] +name = "triton" +url = "https://download.pytorch.org/whl/cpu" + +``` + +Save the file (in `vim`, press 'esc' to exit insert mode, then ':x+Enter'), +and set it as the default `uv` config. + +```bash +export UV_CONFIG_FILE=/opt/.venv/uv.toml +``` + +3. Clone the `sglang` source code and build the packages + +```bash +# Clone the SGLang code +git clone https://github.com/sgl-project/sglang.git +cd sglang +git checkout + +# Use dedicated toml file +cd python +cp pyproject_cpu.toml pyproject.toml +# Install SGLang dependent libs, and build SGLang main package +uv pip install --upgrade pip setuptools +uv pip install . + +# Build the CPU backend kernels +cd ../sgl-kernel +cp pyproject_cpu.toml pyproject.toml +uv pip install . +``` + +4. Set the required environment variables + +```bash +export SGLANG_USE_CPU_ENGINE=1 + +# Set 'LD_LIBRARY_PATH' and 'LD_PRELOAD' to ensure the libs can be loaded by sglang processes +export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu +export LD_PRELOAD=${LD_PRELOAD}:/opt/.venv/lib/libiomp5.so:${LD_LIBRARY_PATH}/libtcmalloc.so.4:${LD_LIBRARY_PATH}/libtbbmalloc.so.2 +``` + +Notes: + +- Note that the environment variable `SGLANG_USE_CPU_ENGINE=1` + is required to enable the SGLang service with the CPU engine. + +- If you encounter code compilation issues during the `sgl-kernel` building process, + please check your `gcc` and `g++` versions and upgrade them if they are outdated. + It is recommended to use `gcc-13` and `g++-13` as they have been verified + in the official Docker container. + +- The system library path is typically located in one of the following directories: + `~/.local/lib/`, `/usr/local/lib/`, `/usr/local/lib64/`, `/usr/lib/`, `/usr/lib64/` + and `/usr/lib/x86_64-linux-gnu/`. In the above example commands, `/usr/lib/x86_64-linux-gnu` + is used. Please adjust the path according to your server configuration. + +- It is recommended to add the following to your `~/.bashrc` file to + avoid setting these variables every time you open a new terminal: + + ```bash + source .venv/bin/activate + export SGLANG_USE_CPU_ENGINE=1 + export LD_LIBRARY_PATH= + export LD_PRELOAD= + ``` + +## Launch of the Serving Engine + +Example command to launch SGLang serving: + +```bash +python -m sglang.launch_server \ + --model \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device cpu \ + --host 0.0.0.0 \ + --tp 6 +``` + +Notes: + +1. For running W8A8 quantized models, please add the flag `--quantization w8a8_int8`. + +2. The flag `--tp 6` specifies that tensor parallelism will be applied using 6 ranks (TP6). + The number of TP specified is how many TP ranks will be used during the execution. + On a CPU platform, a TP rank means a sub-NUMA cluster (SNC). + Usually we can get the SNC information (How many available) from the Operating System with e.g. `lscpu` command. + + If the specified TP rank number differs from the total SNC count, + the system will automatically utilize the first `n` SNCs. + Note that `n` cannot exceed the total SNC number, doing so will result in an error. + + To specify the cores to be used, we need to explicitly set the environment variable `SGLANG_CPU_OMP_THREADS_BIND`. + For example, if we want to run the SGLang service using the first 40 cores of each SNC on a Xeon® 6980P server, + which has 43-43-42 cores on the 3 SNCs of a socket, we should set: + + ```bash + export SGLANG_CPU_OMP_THREADS_BIND="0-39|43-82|86-125|128-167|171-210|214-253" + ``` + + Please beware that with SGLANG_CPU_OMP_THREADS_BIND set, + the available memory amounts of the ranks may not be determined in prior. + You may need to set proper `--max-total-tokens` to avoid the out-of-memory error. + +3. For optimizing decoding with torch.compile, please add the flag `--enable-torch-compile`. + To specify the maximum batch size when using `torch.compile`, set the flag `--torch-compile-max-bs`. + For example, `--enable-torch-compile --torch-compile-max-bs 4` means using `torch.compile` + and setting the maximum batch size to 4. Currently the maximum applicable batch size + for optimizing with `torch.compile` is 16. + +4. A warmup step is automatically triggered when the service is started. + The server is ready when you see the log `The server is fired up and ready to roll!`. + +## Benchmarking with Requests + +You can benchmark the performance via the `bench_serving` script. +Run the command in another terminal. An example command would be: + +```bash +python -m sglang.bench_serving \ + --dataset-name random \ + --random-input-len 1024 \ + --random-output-len 1024 \ + --num-prompts 1 \ + --request-rate inf \ + --random-range-ratio 1.0 +``` + +Detailed parameter descriptions are available via the command: + +```bash +python -m sglang.bench_serving -h +``` + +Additionally, requests can be formatted using +[the OpenAI Completions API](https://docs.sglang.io/basic_usage/openai_api_completions.html) +and sent via the command line (e.g., using `curl`) or through your own scripts. + +## Example Usage Commands + +Large Language Models can range from fewer than 1 billion to several hundred billion parameters. +Dense models larger than 20B are expected to run on flagship 6th Gen Intel® Xeon® processors +with dual sockets and a total of 6 sub-NUMA clusters. Dense models of approximately 10B parameters or fewer, +or MoE (Mixture of Experts) models with fewer than 10B activated parameters, can run on more common +4th generation or newer Intel® Xeon® processors, or utilize a single socket of the flagship 6th Gen Intel® Xeon® processors. + +### Example: Running DeepSeek-V3.1-Terminus + +An example command to launch service of W8A8_INT8 DeepSeek-V3.1-Terminus on a Xeon® 6980P server: + +```bash +python -m sglang.launch_server \ + --model IntervitensInc/DeepSeek-V3.1-Terminus-Channel-int8 \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device cpu \ + --quantization w8a8_int8 \ + --host 0.0.0.0 \ + --enable-torch-compile \ + --torch-compile-max-bs 4 \ + --tp 6 +``` + +Similarly, an example command to launch service of FP8 DeepSeek-V3.1-Terminus would be: + +```bash +python -m sglang.launch_server \ + --model deepseek-ai/DeepSeek-V3.1-Terminus \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device cpu \ + --host 0.0.0.0 \ + --enable-torch-compile \ + --torch-compile-max-bs 4 \ + --tp 6 +``` + +Note: Please set `--torch-compile-max-bs` to the maximum desired batch size for your deployment, +which can be up to 16. The value `4` in the examples is illustrative. + +### Example: Running Llama-3.2-3B + +An example command to launch service of Llama-3.2-3B with BF16 precision: + +```bash +python -m sglang.launch_server \ + --model meta-llama/Llama-3.2-3B-Instruct \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device cpu \ + --host 0.0.0.0 \ + --enable-torch-compile \ + --torch-compile-max-bs 16 \ + --tp 2 +``` + +The example command to launch service of W8A8_INT8 version of Llama-3.2-3B: + +```bash +python -m sglang.launch_server \ + --model RedHatAI/Llama-3.2-3B-quantized.w8a8 \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device cpu \ + --quantization w8a8_int8 \ + --host 0.0.0.0 \ + --enable-torch-compile \ + --torch-compile-max-bs 16 \ + --tp 2 +``` + +Note: The `--torch-compile-max-bs` and `--tp` settings are examples that should be adjusted for your setup. +For instance, use `--tp 3` to utilize 1 socket with 3 sub-NUMA clusters on an Intel® Xeon® 6980P server. + +Once the server have been launched, you can test it using the `bench_serving` command or create +your own commands or scripts following [the benchmarking example](#benchmarking-with-requests). diff --git a/sglang/docs/platforms/mindspore_backend.md b/sglang/docs/platforms/mindspore_backend.md new file mode 100644 index 0000000000000000000000000000000000000000..d0df08ea3fd702ae41211ff402c253060429621c --- /dev/null +++ b/sglang/docs/platforms/mindspore_backend.md @@ -0,0 +1,151 @@ +# MindSpore Models + +## Introduction + +MindSpore is a high-performance AI framework optimized for Ascend NPUs. This doc guides users to run MindSpore models in SGLang. + +## Requirements + +MindSpore currently only supports Ascend NPU devices. Users need to first install Ascend CANN software packages. +The CANN software packages can be downloaded from the [Ascend Official Website](https://www.hiascend.com). The recommended version is 8.3.RC2. + +## Supported Models + +Currently, the following models are supported: + +- **Qwen3**: Dense and MoE models +- **DeepSeek V3/R1** +- *More models coming soon...* + +## Installation + +> **Note**: Currently, MindSpore models are provided by an independent package `sgl-mindspore`. Support for MindSpore is built upon current SGLang support for Ascend NPU platform. Please first [install SGLang for Ascend NPU](ascend_npu.md) and then install `sgl-mindspore`: + +```shell +git clone https://github.com/mindspore-lab/sgl-mindspore.git +cd sgl-mindspore +pip install -e . +``` + + +## Run Model + +Current SGLang-MindSpore supports Qwen3 and DeepSeek V3/R1 models. This doc uses Qwen3-8B as an example. + +### Offline infer + +Use the following script for offline infer: + +```python +import sglang as sgl + +# Initialize the engine with MindSpore backend +llm = sgl.Engine( + model_path="/path/to/your/model", # Local model path + device="npu", # Use NPU device + model_impl="mindspore", # MindSpore implementation + attention_backend="ascend", # Attention backend + tp_size=1, # Tensor parallelism size + dp_size=1 # Data parallelism size +) + +# Generate text +prompts = [ + "Hello, my name is", + "The capital of France is", + "The future of AI is" +] + +sampling_params = {"temperature": 0, "top_p": 0.9} +outputs = llm.generate(prompts, sampling_params) + +for prompt, output in zip(prompts, outputs): + print(f"Prompt: {prompt}") + print(f"Generated: {output['text']}") + print("---") +``` + +### Start server + +Launch a server with MindSpore backend: + +```bash +# Basic server startup +python3 -m sglang.launch_server \ + --model-path /path/to/your/model \ + --host 0.0.0.0 \ + --device npu \ + --model-impl mindspore \ + --attention-backend ascend \ + --tp-size 1 \ + --dp-size 1 +``` + +For distributed server with multiple nodes: + +```bash +# Multi-node distributed server +python3 -m sglang.launch_server \ + --model-path /path/to/your/model \ + --host 0.0.0.0 \ + --device npu \ + --model-impl mindspore \ + --attention-backend ascend \ + --dist-init-addr 127.0.0.1:29500 \ + --nnodes 2 \ + --node-rank 0 \ + --tp-size 4 \ + --dp-size 2 +``` + +## Troubleshooting + +#### Debug Mode + +Enable sglang debug logging by log-level argument. + +```bash +python3 -m sglang.launch_server \ + --model-path /path/to/your/model \ + --host 0.0.0.0 \ + --device npu \ + --model-impl mindspore \ + --attention-backend ascend \ + --log-level DEBUG +``` + +Enable mindspore info and debug logging by setting environments. + +```bash +export GLOG_v=1 # INFO +export GLOG_v=0 # DEBUG +``` + +#### Explicitly select devices + +Use the following environment variable to explicitly select the devices to use. + +```shell +export ASCEND_RT_VISIBLE_DEVICES=4,5,6,7 # to set device +``` + +#### Some communication environment issues + +In case of some environment with special communication environment, users need set some environment variables. + +```shell +export MS_ENABLE_LCCL=off # current not support LCCL communication mode in SGLang-MindSpore +``` + +#### Some dependencies of protobuf + +In case of some environment with special protobuf version, users need set some environment variables to avoid binary version mismatch. + +```shell +export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python # to avoid protobuf binary version mismatch +``` + +## Support +For MindSpore-specific issues: + +- Refer to the [MindSpore documentation](https://www.mindspore.cn/) diff --git a/sglang/docs/platforms/mthreads_gpu.md b/sglang/docs/platforms/mthreads_gpu.md new file mode 100644 index 0000000000000000000000000000000000000000..3538df31898a73a59a05a2cbf1c27f0e526a7534 --- /dev/null +++ b/sglang/docs/platforms/mthreads_gpu.md @@ -0,0 +1,25 @@ +# Moore Threads GPUs + +This document describes how run SGLang on Moore Threads GPUs. If you encounter issues or have questions, please [open an issue](https://github.com/sgl-project/sglang/issues). + +## Install SGLang + +You can install SGLang using one of the methods below. + +### Install from Source + +```bash +# Use the default branch +git clone https://github.com/sgl-project/sglang.git +cd sglang + +# Compile sgl-kernel +pip install --upgrade pip +cd sgl-kernel +python setup_musa.py install + +# Install sglang python package +cd .. +rm -f python/pyproject.toml && mv python/pyproject_other.toml python/pyproject.toml +pip install -e "python[all_musa]" +``` diff --git a/sglang/docs/platforms/nvidia_jetson.md b/sglang/docs/platforms/nvidia_jetson.md new file mode 100644 index 0000000000000000000000000000000000000000..ba3b68ae82409aef1ae7d12af6549bc0d40c7ff2 --- /dev/null +++ b/sglang/docs/platforms/nvidia_jetson.md @@ -0,0 +1,80 @@ +# NVIDIA Jetson Orin + +## Prerequisites + +Before starting, ensure the following: + +- [**NVIDIA Jetson AGX Orin Devkit**](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/) is set up with **JetPack 6.1** or later. +- **CUDA Toolkit** and **cuDNN** are installed. +- Verify that the Jetson AGX Orin is in **high-performance mode**: +```bash +sudo nvpmodel -m 0 +``` +* * * * * +## Installing and running SGLang with Jetson Containers +Clone the jetson-containers github repository: +``` +git clone https://github.com/dusty-nv/jetson-containers.git +``` +Run the installation script: +``` +bash jetson-containers/install.sh +``` +Build the container image: +``` +jetson-containers build sglang +``` +Run the container: +``` +jetson-containers run $(autotag sglang) +``` +Or you can also manually run a container with this command: +``` +docker run --runtime nvidia -it --rm --network=host IMAGE_NAME +``` +* * * * * + +Running Inference +----------------------------------------- + +Launch the server: +```bash +python -m sglang.launch_server \ + --model-path deepseek-ai/DeepSeek-R1-Distill-Llama-8B \ + --device cuda \ + --dtype half \ + --attention-backend flashinfer \ + --mem-fraction-static 0.8 \ + --context-length 8192 +``` +The quantization and limited context length (`--dtype half --context-length 8192`) are due to the limited computational resources in [Nvidia jetson kit](https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/). A detailed explanation can be found in [Server Arguments](../advanced_features/server_arguments.md). + +After launching the engine, refer to [Chat completions](https://docs.sglang.io/basic_usage/openai_api_completions.html#Usage) to test the usability. +* * * * * +Running quantization with TorchAO +------------------------------------- +TorchAO is suggested to NVIDIA Jetson Orin. +```bash +python -m sglang.launch_server \ + --model-path meta-llama/Meta-Llama-3.1-8B-Instruct \ + --device cuda \ + --dtype bfloat16 \ + --attention-backend flashinfer \ + --mem-fraction-static 0.8 \ + --context-length 8192 \ + --torchao-config int4wo-128 +``` +This enables TorchAO's int4 weight-only quantization with a 128-group size. The usage of `--torchao-config int4wo-128` is also for memory efficiency. + + +* * * * * +Structured output with XGrammar +------------------------------- +Please refer to [SGLang doc structured output](../advanced_features/structured_outputs.ipynb). +* * * * * + +Thanks to the support from [Nurgaliyev Shakhizat](https://github.com/shahizat), [Dustin Franklin](https://github.com/dusty-nv) and [Johnny Núñez Cano](https://github.com/johnnynunez). + +References +---------- +- [NVIDIA Jetson AGX Orin Documentation](https://developer.nvidia.com/embedded/jetson-agx-orin) diff --git a/sglang/docs/platforms/tpu.md b/sglang/docs/platforms/tpu.md new file mode 100644 index 0000000000000000000000000000000000000000..ede5335134c571aa99021c9b19ccb7f1c1737c27 --- /dev/null +++ b/sglang/docs/platforms/tpu.md @@ -0,0 +1,477 @@ +# TPU + +SGLang supports high-performance TPU inference through the SGLang-JAX backend, which is specifically optimized for Google Cloud TPUs. The JAX-based implementation delivers exceptional throughput and low latency for Large Language Model (LLM) serving workloads on TPU hardware. + +For TPU-specific issues or feature requests, please visit the [sglang-jax GitHub issues page](https://github.com/sgl-project/sglang-jax/issues). + +**NOTE:** SGLang TPU support is implemented via the SGLang-JAX backend, a dedicated JAX-based inference engine maintained as a separate repository at [https://github.com/sgl-project/sglang-jax](https://github.com/sgl-project/sglang-jax). + +## System Requirements + +### Supported TPU Hardware + +| TPU Type | HBM Memory | Availability | +|----------|-----------|--------------| +| TPU v6e | 32 GB | Google Cloud | +| TPU v7 | 96 GB per core | Google Cloud | + +### Software Requirements + +- **Python:** 3.12 or higher +- **JAX:** Latest version with TPU support +- **Environment:** Google Cloud TPU VM or compatible TPU runtime +- **Optional:** SkyPilot for simplified cloud deployment + +## Feature Support Matrix + +SGLang-JAX provides comprehensive TPU-optimized features for production LLM serving: + +| Feature | Support Status | Description | +|---------|---------------|-------------| +| High-Throughput Continuous Batching | ✅ | Dynamic request batching for maximum TPU utilization | +| Radix Tree KV Cache | ✅ | Memory-efficient prefix sharing between requests | +| FlashAttention Backend | ✅ | TPU-optimized attention kernel for long sequences | +| Tensor Parallelism | ✅ | Distribute models across multiple TPU cores | +| Paged Attention | ✅ | Flexible KV cache management with paging | +| Speculative Decoding (EAGLE/EAGLE3) | ✅ | 20-40% throughput improvement for compatible models | +| Chunked Prefill | ✅ | Mixed prefill-decode batching | +| OpenAI-Compatible API | ✅ | Drop-in replacement for OpenAI API | +| Data Parallel Attention | 🚧 | In development - Attention computation with data parallelism | +| Quantization | 🚧 | In development - Model quantization for reduced memory usage | +| Multi-LoRA | 🚧 | In development - Serve multiple LoRA adapters simultaneously | + +### Attention Backend Comparison + +| Backend | Paged Attention | Spec Decoding | MLA | Sliding Window | +|---------|----------------|---------------|-----|----------------| +| FlashAttention (fa) | ✅ | ✅ | ❌ | ✅ | +| Native | ❌ | ❌ | ❌ | ❌ | + +**NOTE:** FlashAttention backend is recommended for production workloads due to superior memory efficiency and performance. + +## Optimized Model List + +The following models have been tested and optimized for TPU deployment: + +| Model Family | Performance Status | +|--------------|-------------------| +| [Qwen 3](https://huggingface.co/Qwen) | ⭐ Recommended for production | +| [Qwen 3 MoE](https://huggingface.co/Qwen) | ⭐ Best performance | +| [Qwen 2](https://huggingface.co/Qwen) | Needs improvement | +| [Qwen 2 MoE](https://huggingface.co/Qwen) | Needs improvement | +| [Qwen 1.5](https://huggingface.co/Qwen) | Needs improvement | +| [Llama/LLaMA](https://huggingface.co/meta-llama) | Needs improvement | +| [Grok-2](https://huggingface.co/xai-org) | Needs improvement | +| [Gemma 2](https://huggingface.co/google) | Verified on TPU | +| Bailing MoE | Needs improvement | + +## Installation + +### Method 1: Using PyPI (Recommended) + +```bash +pip install sglang-jax +``` + +### Method 2: From Source + +```bash +git clone https://github.com/sgl-project/sglang-jax +cd sglang-jax +uv venv --python 3.12 && source .venv/bin/activate +uv pip install -e "python[all]" +``` + +### Method 3: Using Docker + +**NOTE:** Docker support for TPU is currently under development. Please use PyPI or source installation methods. + +### Method 4: Cloud TPU with SkyPilot + +[SkyPilot](https://github.com/skypilot-org/skypilot) provides simplified deployment on Google Cloud TPU: + +1. Install SkyPilot and configure GCP access (see [SkyPilot documentation](https://skypilot.readthedocs.io/)) + +2. Create a SkyPilot configuration file: + +
+SkyPilot YAML: sglang-jax.sky.yaml + +```yaml +# sglang-jax.sky.yaml +resources: + accelerators: tpu-v6e-4 + accelerator_args: + tpu_vm: True + runtime_version: v2-alpha-tpuv6e + +run: | + git clone https://github.com/sgl-project/sglang-jax.git + cd sglang-jax + uv venv --python 3.12 + source .venv/bin/activate + uv pip install -e "python[all]" +``` + +
+ +3. Launch your TPU cluster: + +```bash +# Standard deployment +sky launch -c sglang-jax sglang-jax.sky.yaml --infra=gcp + +# With spot instances for cost savings +sky launch -c sglang-jax sglang-jax.sky.yaml --infra=gcp --use-spot +``` + +## Launch of the Serving Engine + +### Basic Example: Qwen-7B + +```bash +JAX_COMPILATION_CACHE_DIR=/tmp/jit_cache python3 -u -m sgl_jax.launch_server \ + --model-path Qwen/Qwen-7B-Chat \ + --trust-remote-code \ + --dist-init-addr=0.0.0.0:10011 \ + --nnodes=1 \ + --tp-size=4 \ + --device=tpu \ + --random-seed=3 \ + --node-rank=0 \ + --mem-fraction-static=0.8 \ + --max-prefill-tokens=8192 \ + --download-dir=/tmp \ + --dtype=bfloat16 \ + --skip-server-warmup \ + --host 0.0.0.0 \ + --port 30000 +``` + +**Key Parameters Explained:** + +1. `JAX_COMPILATION_CACHE_DIR=/tmp/jit_cache` - Enables JIT compilation caching to accelerate server startup on subsequent runs +2. `--tp-size=4` - Tensor parallelism size; match this to your TPU core count (typically 1, 4, or 8) +3. `--device=tpu` - Specifies TPU device (this is the default for sglang-jax) +4. `--dtype=bfloat16` - Uses bfloat16 precision, which TPUs are optimized for +5. `--mem-fraction-static=0.8` - Allocates 80% of TPU HBM for static memory (adjustable from 0.2 to 0.9) +6. `--max-prefill-tokens=8192` - Maximum number of tokens processed in the prefill phase + +### High-Performance Configuration: Qwen3-8B + +For production workloads with optimal throughput: + +```bash +python3 -u -m sgl_jax.launch_server \ + --model-path Qwen/Qwen3-8B \ + --trust-remote-code \ + --tp-size=4 \ + --device=tpu \ + --mem-fraction-static=0.8 \ + --chunked-prefill-size=2048 \ + --dtype=bfloat16 \ + --max-running-requests=256 \ + --page-size=128 \ + --attention-backend=fa +``` + +### Advanced: Speculative Decoding (EAGLE3) + +Speculative decoding can improve throughput by 20-40% for compatible models: + +```bash +python3 -u -m sgl_jax.launch_server \ + --model-path Qwen/Qwen3-32B \ + --trust-remote-code \ + --device=tpu \ + --tp-size=4 \ + --mem-fraction-static=0.8 \ + --max-prefill-tokens=4096 \ + --attention-backend=fa \ + --dtype=bfloat16 \ + --port=30000 \ + --host=0.0.0.0 \ + --disable-overlap-schedule \ + --speculative-algorithm=EAGLE3 \ + --speculative-draft-model-path=AngelSlim/Qwen3-32B_eagle3 \ + --page-size=64 \ + --speculative-eagle-topk=1 \ + --speculative-num-steps=3 \ + --speculative-num-draft-tokens=4 +``` + +**NOTE:** Speculative decoding is currently supported for Qwen3 and LLaMA model families. See the [Speculative Decoding documentation](https://github.com/sgl-project/sglang-jax/blob/main/docs/features/speculative_decoding.md) for detailed configuration guidance. + + +### Multi-Node Distributed Serving + +For large models requiring multiple TPU VMs: + +```bash +# Node 0 (coordinator) +python3 -m sgl_jax.launch_server \ + --model-path MODEL_PATH \ + --dist-init-addr=NODE0_IP:10011 \ + --nnodes=2 \ + --node-rank=0 \ + --tp-size=8 \ + [other parameters...] + +# Node 1 (worker) +python3 -m sgl_jax.launch_server \ + --model-path MODEL_PATH \ + --dist-init-addr=NODE0_IP:10011 \ + --nnodes=2 \ + --node-rank=1 \ + --tp-size=8 \ + [other parameters...] +``` + +## Benchmarking with Requests + +### Throughput Testing + +Basic throughput benchmark: + +```bash +python3 -m sgl_jax.bench_serving \ + --backend sgl-jax \ + --dataset-name random \ + --num-prompts=100 \ + --random-input=512 \ + --random-output=128 \ + --max-concurrency=8 \ + --random-range-ratio=1 \ + --warmup-requests=0 +``` + +### Latency Testing + +Measure single-batch latency: + +```bash +python3 -m sgl_jax.bench_one_batch_server \ + --base-url http://127.0.0.1:30000 \ + --model-path Qwen/Qwen-7B-Chat \ + --batch-size=32 \ + --input-len=256 \ + --output-len=32 +``` + +### Comprehensive Benchmark Script + +For systematic performance evaluation across different configurations: + +```bash +#!/bin/bash +set -e + +backend=${1:-sgl-jax} +num_prompts_per_concurrency=3 +input_seq_lens=(1024 4096 8192) +output_seq_lens=(1 1024) +max_concurrencies=(8 16 32 64 128 256) + +for input_seq_len in "${input_seq_lens[@]}"; do + for output_seq_len in "${output_seq_lens[@]}"; do + echo "=======================================" + echo "Testing ISL/OSL: $input_seq_len/$output_seq_len" + echo "=======================================" + for max_concurrency in "${max_concurrencies[@]}"; do + num_prompts=$((num_prompts_per_concurrency * max_concurrency)) + python3 -m sgl_jax.bench_serving \ + --backend ${backend} \ + --dataset-name random \ + --num-prompts ${num_prompts} \ + --random-input ${input_seq_len} \ + --random-output ${output_seq_len} \ + --max-concurrency ${max_concurrency} \ + --random-range-ratio 1 \ + --disable-ignore-eos \ + --warmup-requests 0 + done + done +done +``` + +For detailed help on all benchmark parameters: + +```bash +python3 -m sgl_jax.bench_serving --help +``` + +See the [Benchmark and Profiling Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/developer_guide/benchmark_and_profiling.md) for advanced benchmarking techniques and profiling with JAX Profiler. + +## Performance Optimization + +### Memory Optimization + +**Reduce memory usage:** +- Lower `--mem-fraction-static` (from 0.8 → 0.5 → 0.3) +- Decrease `--max-prefill-tokens` (from 16384 → 8192 → 4096) +- Reduce `--max-running-requests` + +**Handle OOM errors:** +- Start with conservative memory settings (`--mem-fraction-static=0.5`) +- Gradually increase until you find the optimal balance +- Increase `--page-size` for better memory locality (1 → 16 → 64 → 128) + +### Throughput Optimization + +To maximize tokens per second: + +- Use FlashAttention backend: `--attention-backend=fa` +- Enable speculative decoding (EAGLE3) for Qwen3 models (20-40% improvement) +- Increase `--max-running-requests` to 256+ +- Set `--mem-fraction-static` to 0.8+ (if memory allows) +- Use larger page sizes (64-128) +- Enable chunked prefill: `--chunked-prefill-size=2048` + +### Latency Optimization + +To minimize time-to-first-token (TTFT) and inter-token latency: + +- Reduce `--page-size` to 1-4 +- Lower `--max-running-requests` (16-32) for smaller batches +- Reduce `--chunked-prefill-size` +- Use conservative memory settings to avoid GC pauses + +### TPU-Specific Optimizations + +1. **JIT Compilation Cache:** + ```bash + export JAX_COMPILATION_CACHE_DIR=/tmp/jit_cache + ``` + Always set this environment variable to cache compiled kernels and accelerate server startup. + +2. **Data Type Optimization:** + Use `--dtype=bfloat16` for TPU native optimization. TPUs are specifically designed for bfloat16 computations. + +3. **Tensor Parallelism:** + Match `--tp-size` to your TPU core configuration (1, 4, or 8) for optimal model distribution. + +4. **Attention Backend:** + Always use `--attention-backend=fa` (FlashAttention) for production workloads. + +## Troubleshooting + +### OOM (Out of Memory) Errors + +If you encounter out-of-memory errors: + +1. Reduce `--mem-fraction-static` from 0.8 to 0.5 or lower +2. Decrease `--max-prefill-tokens` from 8192 to 4096 or 2048 +3. Lower `--max-running-requests` to reduce concurrent batch size +4. Increase `--page-size` for better memory layout efficiency + +### Compilation Long-Time + +If the server takes too long to start: + +1. Ensure `JAX_COMPILATION_CACHE_DIR` is properly set +2. Understand that the first run requires JIT compilation (this is normal) +3. Subsequent runs will be significantly faster with cached compilations +4. Consider using `--skip-server-warmup` to defer compilation until first request + +### Low Throughput + +If you're not achieving expected throughput: + +1. Verify `--tp-size` matches your TPU core configuration +2. Check that `--attention-backend=fa` is enabled +3. Increase `--max-running-requests` to enable larger batch formation +4. Consider enabling speculative decoding for compatible models +5. Ensure memory settings allow for sufficient batch sizes + +### Connection Issues + +If clients cannot connect to the server: + +1. Ensure `--host=0.0.0.0` for external access (not just `127.0.0.1`) +2. Verify firewall rules allow traffic on the specified port (default: 30000) +3. Check that the server process is running: `curl http://localhost:30000/health` + +## Advanced Features + +### Speculative Decoding + +SGLang-JAX supports EAGLE and EAGLE3 speculative decoding algorithms for Qwen3 and LLaMA model families. Speculative decoding can improve throughput by 20-40% without affecting output quality. + +See the [Speculative Decoding documentation](https://github.com/sgl-project/sglang-jax/blob/main/docs/features/speculative_decoding.md) for detailed configuration and supported model combinations. + +### Chunked Prefill + +Enable mixed prefill-decode batching for better TPU utilization: + +```bash +--chunked-prefill-size=2048 --enable-mixed-chunk +``` + +This allows the scheduler to mix prefill operations with decode operations in the same batch, improving overall throughput. + +### Custom Attention Backends + +SGLang-JAX supports a plugin-based attention backend system. You can implement custom attention kernels optimized for specific use cases. + +See the [Attention Backend documentation](https://github.com/sgl-project/sglang-jax/blob/main/docs/features/attention_backend.md) for implementation details. + +### Environment Verification + +Verify your TPU setup before deploying: + +```bash +python -c "from sgl_jax import check_env; check_env.check_env()" +``` + +This command checks: +- Installed package versions +- TPU device availability and specifications +- System resources and configuration +- Compatibility of settings + +## Contributing + +We welcome contributions to improve TPU support in SGLang-JAX! + +### Areas for Contribution + +**Check the [Development Roadmap](https://github.com/sgl-project/sglang-jax/issues/190)** to see planned features and find opportunities to contribute new functionality. + +Current contribution areas include: + +- Performance optimizations for specific TPU generations +- Support for additional model architectures +- Documentation improvements and examples +- Bug reports and fixes +- Benchmark results and performance analysis + +### How to Contribute + +1. Visit the [sglang-jax repository](https://github.com/sgl-project/sglang-jax) +2. Read the [Contribution Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/developer_guide/contribution_guide.md) +3. Join the [SGL-JAX Slack community](https://sgl-fru7574.slack.com/archives/C09EBE5HT5X) for discussions +4. Report issues at [sglang-jax/issues](https://github.com/sgl-project/sglang-jax/issues) + +### Testing on TPU + +For contributors who need TPU access for testing: + +- Refer to the [TPU Resources Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/developer_guide/tpu_resources_guide.md) for information on accessing TPU hardware +- Use SkyPilot with spot instances for cost-effective testing +- Follow the [Benchmark and Profiling Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/developer_guide/benchmark_and_profiling.md) for performance validation + +## References + +### Documentation + +- [SGLang-JAX Repository](https://github.com/sgl-project/sglang-jax) +- [SGLang-JAX Installation Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/get_started/install.md) +- [Qwen Models Quick Start](https://github.com/sgl-project/sglang-jax/blob/main/docs/basic_usage/qwen.md) +- [Benchmark and Profiling Guide](https://github.com/sgl-project/sglang-jax/blob/main/docs/developer_guide/benchmark_and_profiling.md) +- [Speculative Decoding](https://github.com/sgl-project/sglang-jax/blob/main/docs/features/speculative_decoding.md) + +### External Resources + +- [JAX Documentation](https://jax.readthedocs.io/) +- [Google Cloud TPU Documentation](https://cloud.google.com/tpu/docs) +- [SkyPilot Documentation](https://skypilot.readthedocs.io/) diff --git a/sglang/docs/platforms/xpu.md b/sglang/docs/platforms/xpu.md new file mode 100644 index 0000000000000000000000000000000000000000..88fa1552c7900c68115d942685ae931fee5642cb --- /dev/null +++ b/sglang/docs/platforms/xpu.md @@ -0,0 +1,92 @@ +# XPU + +The document addresses how to set up the [SGLang](https://github.com/sgl-project/sglang) environment and run LLM inference on Intel GPU, [see more context about Intel GPU support within PyTorch ecosystem](https://docs.pytorch.org/docs/stable/notes/get_start_xpu.html). + +Specifically, SGLang is optimized for [Intel® Arc™ Pro B-Series Graphics](https://www.intel.com/content/www/us/en/ark/products/series/242616/intel-arc-pro-b-series-graphics.html) and [ +Intel® Arc™ B-Series Graphics](https://www.intel.com/content/www/us/en/ark/products/series/240391/intel-arc-b-series-graphics.html). + +## Optimized Model List + +A list of LLMs have been optimized on Intel GPU, and more are on the way: + +| Model Name | BF16 | +|:---:|:---:| +| Llama-3.2-3B | [meta-llama/Llama-3.2-3B-Instruct](https://huggingface.co/meta-llama/Llama-3.2-3B-Instruct) | +| Llama-3.1-8B | [meta-llama/Llama-3.1-8B-Instruct](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) | +| Qwen2.5-1.5B | [Qwen/Qwen2.5-1.5B](https://huggingface.co/Qwen/Qwen2.5-1.5B) | + +**Note:** The model identifiers listed in the table above +have been verified on [Intel® Arc™ B580 Graphics](https://www.intel.com/content/www/us/en/products/sku/241598/intel-arc-b580-graphics/specifications.html). + +## Installation + +### Install From Source + +Currently SGLang XPU only supports installation from source. Please refer to ["Getting Started on Intel GPU"](https://docs.pytorch.org/docs/stable/notes/get_start_xpu.html) to install XPU dependency. + +```bash +# Create and activate a conda environment +conda create -n sgl-xpu python=3.12 -y +conda activate sgl-xpu + +# Set PyTorch XPU as primary pip install channel to avoid installing the larger CUDA-enabled version and prevent potential runtime issues. +pip3 install torch==2.9.0+xpu torchao torchvision torchaudio pytorch-triton-xpu==3.5.0 --index-url https://download.pytorch.org/whl/xpu +pip3 install xgrammar --no-deps # xgrammar will introduce CUDA-enabled triton which might conflict with XPU + +# Clone the SGLang code +git clone https://github.com/sgl-project/sglang.git +cd sglang +git checkout + +# Use dedicated toml file +cd python +cp pyproject_xpu.toml pyproject.toml +# Install SGLang dependent libs, and build SGLang main package +pip install --upgrade pip setuptools +pip install -v . +``` + +### Install Using Docker + +The docker for XPU is under active development. Please stay tuned. + +## Launch of the Serving Engine + +Example command to launch SGLang serving: + +```bash +python -m sglang.launch_server \ + --model \ + --trust-remote-code \ + --disable-overlap-schedule \ + --device xpu \ + --host 0.0.0.0 \ + --tp 2 \ # using multi GPUs + --attention-backend intel_xpu \ # using intel optimized XPU attention backend + --page-size \ # intel_xpu attention backend supports [32, 64, 128] +``` + +## Benchmarking with Requests + +You can benchmark the performance via the `bench_serving` script. +Run the command in another terminal. + +```bash +python -m sglang.bench_serving \ + --dataset-name random \ + --random-input-len 1024 \ + --random-output-len 1024 \ + --num-prompts 1 \ + --request-rate inf \ + --random-range-ratio 1.0 +``` + +The detail explanations of the parameters can be looked up by the command: + +```bash +python -m sglang.bench_serving -h +``` + +Additionally, the requests can be formed with +[OpenAI Completions API](https://docs.sglang.io/basic_usage/openai_api_completions.html) +and sent via the command line (e.g. using `curl`) or via your own script. diff --git a/sglang/docs/release_lookup/README.md b/sglang/docs/release_lookup/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3472ded2f21fdf13900b275d18526cb54b5e8cdf --- /dev/null +++ b/sglang/docs/release_lookup/README.md @@ -0,0 +1,39 @@ +# SGLang Release Lookup Tool + +This tool allows users to find the earliest release that contains a specific PR or commit. +It runs entirely in the browser using a static JSON index generated from the git history. + +## Usage + +1. **Generate the Index**: + Run the Python script to generate the `release_index.json` file from your local git repository. + + ```bash + python3 generate_index.py --output release_index.json + ``` + + This script: + - Finds all tags matching `v*` and `gateway-v*`. + - Sorts them by creation date. + - Traverses the history to find which release first introduced each commit and PR. + - Extracts PR numbers from commit messages. + +2. **Open the Tool**: + Open `index.html` in your browser. + + ```bash + # You can open it directly if your browser supports local file fetch (Firefox usually does), + # or serve it locally: + python3 -m http.server + # Then go to http://localhost:8000/index.html + ``` + +## Files + +- `index.html`: The UI for the lookup tool. +- `generate_index.py`: Script to build the index. +- `release_index.json`: The index file used by the UI. + +## Logic + +The tool determines the "earliest release" based on the tag creation date. It traverses tags from oldest to newest. Any commit reachable from a tag (that wasn't reachable from a previous tag) is assigned to that release. diff --git a/sglang/docs/release_lookup/generate_index.py b/sglang/docs/release_lookup/generate_index.py new file mode 100644 index 0000000000000000000000000000000000000000..d8415e41dedaa5fc40d26a99f6aea4fc17983be6 --- /dev/null +++ b/sglang/docs/release_lookup/generate_index.py @@ -0,0 +1,222 @@ +import argparse +import json +import os +import re +import subprocess +import sys +from datetime import datetime + +# Short hash length for commits (7 is git's default short hash) +SHORT_HASH_LEN = 8 +COMMIT_CHUNK_SIZE = 1000 + + +def run_git(cmd): + try: + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT) + return output.decode("utf-8", errors="replace").strip() + except subprocess.CalledProcessError as e: + print(f"Error running cmd: {cmd}\n{e.output.decode('utf-8', errors='replace')}") + sys.exit(1) + + +def is_stable_release(tag_name): + """Check if tag is a stable release (not rc/alpha/beta).""" + # Skip release candidates, alpha, beta versions + if re.search(r"(rc|alpha|beta)\d*$", tag_name, re.IGNORECASE): + return False + return True + + +def get_tags(): + # Get tags sorted by creator date + cmd = [ + "git", + "tag", + "--list", + "v*", + "gateway-v*", + "--sort=creatordate", + "--format=%(refname:short)|%(creatordate:iso8601)|%(objectname)", + ] + raw = run_git(cmd) + tags = [] + if not raw: + return [] + for line in raw.split("\n"): + parts = line.split("|") + if len(parts) >= 3: + name, date, commit = parts[0], parts[1], parts[2] + # Skip non-stable releases (rc, alpha, beta) + if not is_stable_release(name): + continue + tag_type = "gateway" if name.startswith("gateway-") else "main" + tags.append( + {"name": name, "date": date, "commit": commit, "type": tag_type} + ) + return tags + + +def extract_pr_num(message): + lines = message.strip().split("\n") + first_line = lines[0] + + m = re.search(r"\(#(\d+)\)$", first_line) + if m: + return m.group(1) + + m = re.search(r"Merge pull request #(\d+)", message) + if m: + return m.group(1) + + return None + + +def process_tag_line(tags, commit_map, pr_map, tag_type, tag_to_idx): + """Process a single release line (main or gateway) independently.""" + seen_commits = set() + + for tag in tags: + tag_name = tag["name"] + print(f"Processing {tag_name}...") + + commits = run_git(["git", "rev-list", tag_name]).split("\n") + + new_commits = [] + for c in commits: + c = c.strip() + if not c: + continue + if c in seen_commits: + continue + new_commits.append(c) + seen_commits.add(c) + + if not new_commits: + continue + + for i in range(0, len(new_commits), COMMIT_CHUNK_SIZE): + chunk = new_commits[i : i + COMMIT_CHUNK_SIZE] + + cmd = ["git", "show", "-s", "--format=%H|%B%n--END-COMMIT--"] + chunk + raw_logs = run_git(cmd) + + entries = raw_logs.split("--END-COMMIT--\n") + for log_entry in entries: + if not log_entry.strip(): + continue + parts = log_entry.split("|", 1) + if len(parts) < 2: + continue + sha = parts[0].strip() + msg = parts[1].strip() + + tag_idx = tag_to_idx[tag_name] + + # Store release index using full SHA as key + if sha not in commit_map: + commit_map[sha] = {} + commit_map[sha][tag_type] = tag_idx + + pr = extract_pr_num(msg) + if pr: + if pr not in pr_map: + pr_map[pr] = {} + if tag_type not in pr_map[pr]: + pr_map[pr][tag_type] = tag_idx + + +def main(): + parser = argparse.ArgumentParser( + description="Generate lookup index for sglang releases" + ) + parser.add_argument( + "--output", default="release_index.json", help="Output JSON file" + ) + args = parser.parse_args() + + tags = get_tags() + print(f"Found {len(tags)} tags.") + + main_tags = [t for t in tags if t["type"] == "main"] + gateway_tags = [t for t in tags if t["type"] == "gateway"] + + print(f" - {len(main_tags)} main tags") + print(f" - {len(gateway_tags)} gateway tags") + + # Build tag list and index mapping + # Tags array: [name, date, type] for each tag + tag_list = [] + tag_to_idx = {} + + for tag in tags: + tag_to_idx[tag["name"]] = len(tag_list) + # Compact format: [name, date, type (0=main, 1=gateway)] + tag_list.append( + [tag["name"], tag["date"], 1 if tag["type"] == "gateway" else 0] + ) + + pr_map = {} + commit_map_full = {} + + process_tag_line(main_tags, commit_map_full, pr_map, "m", tag_to_idx) + process_tag_line(gateway_tags, commit_map_full, pr_map, "g", tag_to_idx) + + # Convert full SHAs to short SHAs, checking for collisions + commit_map = {} + short_to_full_map = {} + for full_sha, data in commit_map_full.items(): + short_sha = full_sha[:SHORT_HASH_LEN] + if short_sha in short_to_full_map and short_to_full_map[short_sha] != full_sha: + print( + f"CRITICAL: Short SHA collision detected for '{short_sha}'\n" + f" Commit 1: {short_to_full_map[short_sha]}\n" + f" Commit 2: {full_sha}\n" + "Please increase SHORT_HASH_LEN and re-run.", + file=sys.stderr, + ) + sys.exit(1) + commit_map[short_sha] = data + short_to_full_map[short_sha] = full_sha + + # Compact output format: + # - tags: array of [name, date, type] + # - prs: {pr_num: tag_idx} or {pr_num: {m: idx, g: idx}} + # - commits: {short_hash: tag_idx} or {short_hash: {m: idx, g: idx}} + + # Simplify single-entry dicts to just the value + def simplify_map(m): + result = {} + for k, v in m.items(): + if len(v) == 1: + # Single entry: just store the index directly with type prefix + key_type, idx = list(v.items())[0] + result[k] = f"{key_type}{idx}" + else: + # Multiple entries: keep as dict + result[k] = v + return result + + output_data = { + "t": tag_list, # tags + "p": simplify_map(pr_map), # prs + "c": simplify_map(commit_map), # commits + "g": datetime.now().isoformat(), # generated_at + } + + # Write minified JSON with a trailing newline for formatter compatibility. + json_str = json.dumps(output_data, separators=(",", ":")) + + with open(args.output, "w", encoding="utf-8") as f: + f.write(json_str) + f.write("\n") + + json_size = os.path.getsize(args.output) + + print(f"Index generated at {args.output}") + print(f"Stats: {len(tag_list)} tags, {len(pr_map)} PRs, {len(commit_map)} commits.") + print(f"Size: {json_size/1024:.1f} KB") + + +if __name__ == "__main__": + main() diff --git a/sglang/docs/release_lookup/index.html b/sglang/docs/release_lookup/index.html new file mode 100644 index 0000000000000000000000000000000000000000..dc8219de5590818186ecead347e5bf231ba49b0a --- /dev/null +++ b/sglang/docs/release_lookup/index.html @@ -0,0 +1,515 @@ + + + + + + SGLang Release Lookup + + + + +
+

Release Lookup

+

Find which SGLang release first included your PR or commit.

+ +
+ + +
+ + + +
+ +
Initializing...
+
+ + + + + diff --git a/sglang/docs/release_lookup/release_index.json b/sglang/docs/release_lookup/release_index.json new file mode 100644 index 0000000000000000000000000000000000000000..4a8606e2499af95fbc26e3152a43e7b33930c5d7 --- /dev/null +++ b/sglang/docs/release_lookup/release_index.json @@ -0,0 +1 @@ +{"t":[["v0.1.3","2024-01-16 05:55:25 +0000",0],["v0.1.5","2024-01-17 18:37:02 -0800",0],["v0.1.6","2024-01-21 01:45:02 -0800",0],["v0.1.7","2024-01-21 10:31:02 +0000",0],["v0.1.8","2024-01-24 03:33:34 -0800",0],["v0.1.9","2024-01-24 11:37:25 +0000",0],["v0.1.10","2024-01-30 15:37:52 +0000",0],["v0.1.11","2024-02-03 02:50:13 -0800",0],["v0.1.12","2024-02-11 06:43:45 -0800",0],["v0.1.13","2024-03-11 05:49:27 -0700",0],["v0.1.14","2024-03-22 13:42:22 -0700",0],["v0.1.15","2024-05-12 14:22:33 -0700",0],["v0.1.16","2024-05-13 17:29:17 -0700",0],["v0.1.17","2024-06-07 19:49:18 -0700",0],["v0.1.18","2024-07-04 06:27:29 +0000",0],["v0.1.19","2024-07-09 02:23:14 -0700",0],["v0.1.20","2024-07-13 17:27:55 -0700",0],["v0.1.21","2024-07-15 13:10:53 -0700",0],["v0.1.22","2024-07-20 03:39:50 -0700",0],["v0.1.23","2024-07-23 13:49:34 -0700",0],["v0.1.24","2024-07-24 15:55:01 -0700",0],["v0.2.0","2024-07-25 08:03:36 -0700",0],["v0.2.5","2024-07-27 05:56:30 +1000",0],["v0.2.6","2024-07-27 20:29:33 -0700",0],["v0.2.7","2024-07-30 20:41:10 +1000",0],["v0.2.8","2024-08-01 14:18:26 -0700",0],["v0.2.9","2024-08-02 01:45:48 -0700",0],["v0.2.9.post1","2024-08-02 12:08:00 -0700",0],["v0.2.10","2024-08-04 16:52:51 -0700",0],["v0.2.11","2024-08-07 20:47:53 +0800",0],["v0.2.12","2024-08-12 20:59:38 +1000",0],["v0.2.13","2024-08-16 03:50:43 +1000",0],["v0.2.14","2024-08-27 00:28:24 +1000",0],["v0.2.14.post1","2024-08-28 21:16:47 +1000",0],["v0.2.14.post2","2024-08-28 18:46:33 +0000",0],["v0.2.15","2024-09-01 22:22:38 -0700",0],["v0.3.0","2024-09-04 04:21:21 -0700",0],["v0.3.1.post1","2024-09-17 01:47:31 -0700",0],["v0.3.1.post2","2024-09-19 02:03:38 -0700",0],["v0.3.1.post3","2024-09-21 11:17:45 +0800",0],["v0.3.2","2024-09-25 14:17:09 +0800",0],["v0.3.3","2024-10-08 12:58:41 -0700",0],["v0.3.3.post1","2024-10-11 07:56:16 -0700",0],["v0.3.4","2024-10-19 08:17:41 -0700",0],["v0.3.4.post1","2024-10-21 21:16:43 -0700",0],["v0.3.4.post2","2024-10-25 11:07:19 -0700",0],["v0.3.5","2024-11-03 13:48:11 -0800",0],["v0.3.5.post1","2024-11-13 10:27:12 -0800",0],["v0.3.5.post2","2024-11-15 06:54:00 -0800",0],["v0.3.6","2024-11-22 19:27:30 +0800",0],["v0.3.6.post1","2024-11-25 17:31:37 -0800",0],["v0.3.6.post2","2024-11-27 03:35:30 -0800",0],["v0.3.6.post3","2024-11-30 01:41:16 +0800",0],["v0.4.0","2024-12-03 11:55:41 -0800",0],["v0.4.0.post1","2024-12-06 06:08:19 -0800",0],["v0.4.0.post2","2024-12-21 21:16:34 +0800",0],["v0.4.1","2024-12-26 07:14:51 +0800",0],["v0.4.1.post1","2024-12-28 00:11:06 +0800",0],["v0.4.1.post2","2024-12-30 00:11:46 +0800",0],["v0.4.1.post3","2024-12-29 14:25:53 -0800",0],["v0.4.1.post4","2025-01-06 01:29:54 +0800",0],["v0.4.1.post5","2025-01-11 23:10:02 +0800",0],["v0.4.1.post6","2025-01-15 16:23:42 +0800",0],["v0.4.1.post7","2025-01-20 21:50:55 +0800",0],["v0.4.2","2025-01-27 21:42:05 +0800",0],["v0.4.2.post1","2025-01-31 20:35:55 +0800",0],["v0.4.2.post2","2025-02-05 17:35:02 +0800",0],["v0.4.2.post3","2025-02-07 08:20:03 -0800",0],["v0.4.2.post4","2025-02-10 14:12:16 +0800",0],["v0.4.3","2025-02-14 09:43:14 +0800",0],["v0.4.3.post1","2025-02-17 21:58:19 +0800",0],["v0.4.3.post2","2025-02-18 02:48:30 +0800",0],["v0.4.3.post3","2025-03-05 17:26:10 -0800",0],["v0.4.3.post4","2025-03-06 12:50:28 -0800",0],["v0.4.4","2025-03-13 02:49:58 -0700",0],["v0.4.4.post1","2025-03-13 17:53:46 -0700",0],["v0.4.4.post2","2025-03-26 19:58:00 -0700",0],["v0.4.4.post3","2025-03-28 23:21:24 -0700",0],["v0.4.4.post4","2025-04-05 15:36:17 -0700",0],["v0.4.5","2025-04-07 00:35:00 -0700",0],["v0.4.5.post1","2025-04-15 23:00:07 -0700",0],["v0.4.5.post2","2025-04-20 14:12:37 -0700",0],["v0.4.5.post3","2025-04-21 18:16:20 -0700",0],["v0.4.6","2025-04-27 14:07:05 -0700",0],["v0.4.6.post1","2025-04-28 12:57:08 -0700",0],["v0.4.6.post2","2025-04-30 22:04:40 -0700",0],["v0.4.6.post3","2025-05-09 15:38:47 -0700",0],["v0.4.6.post4","2025-05-13 01:57:51 -0700",0],["v0.4.6.post5","2025-05-24 00:48:05 -0700",0],["v0.4.7","2025-06-10 01:56:20 -0700",0],["v0.4.7.post1","2025-06-16 15:20:29 -0700",0],["v0.4.8","2025-06-23 23:14:22 -0700",0],["v0.4.8.post1","2025-06-26 02:21:12 -0700",0],["v0.4.9","2025-07-05 17:40:29 -0700",0],["gateway-v0.1.5","2025-07-06 22:54:17 -0700",1],["v0.4.9.post1","2025-07-09 00:28:17 -0700",0],["v0.4.9.post2","2025-07-11 21:11:20 -0700",0],["gateway-v0.1.6","2025-07-20 23:13:20 -0700",1],["v0.4.9.post3","2025-07-22 15:55:48 -0700",0],["v0.4.9.post4","2025-07-25 17:12:47 -0700",0],["v0.4.9.post5","2025-07-28 02:11:06 -0700",0],["v0.4.9.post6","2025-07-29 02:30:07 -0700",0],["v0.4.10","2025-07-31 20:50:17 +0800",0],["gateway-v0.1.7","2025-07-31 11:24:12 -0700",1],["gateway-v0.1.8","2025-07-31 19:00:23 -0700",1],["v0.4.10.post1","2025-08-01 12:07:30 +0800",0],["v0.4.10.post2","2025-08-03 03:43:29 -0700",0],["gateway-v0.1.9","2025-08-07 09:29:12 -0700",1],["v0.5.1","2025-08-23 07:09:26 -0700",0],["v0.5.1.post1","2025-08-24 01:14:17 -0700",0],["v0.5.1.post2","2025-08-25 03:45:09 -0700",0],["v0.5.1.post3","2025-08-27 15:42:42 -0700",0],["v0.5.2","2025-09-11 16:09:20 -0700",0],["v0.5.3","2025-10-06 20:07:02 +0800",0],["v0.5.3.post1","2025-10-09 15:19:59 -0700",0],["gateway-v0.2.0","2025-10-14 22:10:30 -0400",1],["v0.5.3.post2","2025-10-15 16:49:14 -0700",0],["v0.5.3.post3","2025-10-16 13:14:55 -0700",0],["gateway-v0.2.1","2025-10-20 21:08:45 -0700",1],["v0.5.4","2025-10-23 18:01:40 -0700",0],["v0.5.4.post1","2025-10-27 09:35:20 +0800",0],["gateway-v0.2.2","2025-10-30 14:40:13 -0700",1],["v0.5.4.post2","2025-10-31 17:38:50 -0700",0],["v0.5.4.post3","2025-11-04 18:32:11 -0800",0],["v0.5.5","2025-11-07 00:46:19 +0800",0],["v0.5.5.post1","2025-11-10 11:53:43 -0800",0],["v0.5.5.post2","2025-11-12 20:35:20 +0800",0],["gateway-v0.2.3","2025-11-14 19:04:20 -0800",1],["v0.5.5.post3","2025-11-16 17:55:38 -0800",0],["v0.5.6","2025-12-02 17:17:13 -0800",0],["v0.5.6.post1","2025-12-08 13:41:01 -0800",0],["gateway-v0.2.4","2025-12-09 16:36:17 -0800",1],["v0.5.6.post2","2025-12-11 12:29:52 -0800",0],["gateway-v0.3.0","2025-12-24 16:25:05 -0500",1],["v0.5.7","2026-01-01 10:59:48 +0800",0],["gateway-v0.3.1","2026-01-08 21:50:34 -0800",1],["v0.5.8","2026-01-23 09:58:11 -0800",0],["v0.5.8.post1","2026-02-05 20:56:52 +0800",0]],"p":{"10":{"m":0,"g":94},"8":{"m":0,"g":94},"7":{"m":0,"g":94},"6":{"m":0,"g":94},"4":{"m":0,"g":94},"3":{"m":0,"g":94},"2":{"m":0,"g":94},"1":{"m":0,"g":94},"32":{"m":1,"g":94},"18":{"m":1,"g":94},"30":{"m":1,"g":94},"20":{"m":1,"g":94},"19":{"m":1,"g":94},"9":{"m":1,"g":94},"17":{"m":1,"g":94},"16":{"m":1,"g":94},"15":{"m":1,"g":94},"12":{"m":1,"g":94},"11":{"m":1,"g":94},"68":{"m":2,"g":94},"67":{"m":2,"g":94},"64":{"m":2,"g":94},"63":{"m":2,"g":94},"58":{"m":2,"g":94},"57":{"m":2,"g":94},"36":{"m":2,"g":94},"52":{"m":2,"g":94},"50":{"m":2,"g":94},"49":{"m":2,"g":94},"47":{"m":2,"g":94},"46":{"m":2,"g":94},"45":{"m":2,"g":94},"42":{"m":2,"g":94},"34":{"m":2,"g":94},"33":{"m":2,"g":94},"93":{"m":4,"g":94},"92":{"m":4,"g":94},"90":{"m":4,"g":94},"87":{"m":4,"g":94},"84":{"m":4,"g":94},"83":{"m":4,"g":94},"82":{"m":4,"g":94},"75":{"m":4,"g":94},"80":{"m":4,"g":94},"72":{"m":4,"g":94},"37":{"m":4,"g":94},"71":{"m":4,"g":94},"113":{"m":6,"g":94},"121":{"m":6,"g":94},"120":{"m":6,"g":94},"118":{"m":6,"g":94},"114":{"m":6,"g":94},"117":{"m":6,"g":94},"108":{"m":6,"g":94},"103":{"m":6,"g":94},"101":{"m":6,"g":94},"98":{"m":6,"g":94},"48":{"m":6,"g":94},"97":{"m":6,"g":94},"95":{"m":6,"g":94},"134":{"m":7,"g":94},"133":{"m":7,"g":94},"132":{"m":7,"g":94},"112":{"m":7,"g":94},"129":{"m":7,"g":94},"125":{"m":7,"g":94},"119":{"m":7,"g":94},"116":{"m":7,"g":94},"178":{"m":8,"g":94},"177":{"m":8,"g":94},"172":{"m":8,"g":94},"174":{"m":8,"g":94},"168":{"m":8,"g":94},"170":{"m":8,"g":94},"162":{"m":8,"g":94},"160":{"m":8,"g":94},"156":{"m":8,"g":94},"155":{"m":8,"g":94},"130":{"m":8,"g":94},"141":{"m":8,"g":94},"153":{"m":8,"g":94},"148":{"m":8,"g":94},"146":{"m":8,"g":94},"144":{"m":8,"g":94},"142":{"m":8,"g":94},"137":{"m":8,"g":94},"136":{"m":8,"g":94},"280":{"m":9,"g":94},"279":{"m":9,"g":94},"230":{"m":9,"g":94},"277":{"m":9,"g":94},"278":{"m":9,"g":94},"256":{"m":9,"g":94},"222":{"m":9,"g":94},"261":{"m":9,"g":94},"275":{"m":9,"g":94},"263":{"m":9,"g":94},"201":{"m":9,"g":94},"224":{"m":9,"g":94},"253":{"m":9,"g":94},"226":{"m":9,"g":94},"195":{"m":9,"g":94},"198":{"m":9,"g":94},"225":{"m":9,"g":94},"219":{"m":9,"g":94},"193":{"m":9,"g":94},"210":{"m":9,"g":94},"207":{"m":9,"g":94},"200":{"m":9,"g":94},"196":{"m":9,"g":94},"189":{"m":9,"g":94},"186":{"m":9,"g":94},"184":{"m":9,"g":94},"181":{"m":9,"g":94},"182":{"m":9,"g":94},"324":{"m":10,"g":94},"323":{"m":10,"g":94},"301":{"m":10,"g":94},"304":{"m":10,"g":94},"311":{"m":10,"g":94},"291":{"m":10,"g":94},"290":{"m":10,"g":94},"288":{"m":10,"g":94},"286":{"m":10,"g":94},"287":{"m":10,"g":94},"282":{"m":10,"g":94},"242":{"m":10,"g":94},"281":{"m":10,"g":94},"431":{"m":11,"g":94},"430":{"m":11,"g":94},"429":{"m":11,"g":94},"428":{"m":11,"g":94},"427":{"m":11,"g":94},"422":{"m":11,"g":94},"420":{"m":11,"g":94},"380":{"m":11,"g":94},"416":{"m":11,"g":94},"415":{"m":11,"g":94},"412":{"m":11,"g":94},"411":{"m":11,"g":94},"381":{"m":11,"g":94},"392":{"m":11,"g":94},"390":{"m":11,"g":94},"406":{"m":11,"g":94},"399":{"m":11,"g":94},"395":{"m":11,"g":94},"394":{"m":11,"g":94},"382":{"m":11,"g":94},"385":{"m":11,"g":94},"378":{"m":11,"g":94},"372":{"m":11,"g":94},"375":{"m":11,"g":94},"364":{"m":11,"g":94},"370":{"m":11,"g":94},"368":{"m":11,"g":94},"369":{"m":11,"g":94},"358":{"m":11,"g":94},"355":{"m":11,"g":94},"354":{"m":11,"g":94},"346":{"m":11,"g":94},"338":{"m":11,"g":94},"345":{"m":11,"g":94},"343":{"m":11,"g":94},"315":{"m":11,"g":94},"332":{"m":11,"g":94},"337":{"m":11,"g":94},"331":{"m":11,"g":94},"329":{"m":11,"g":94},"293":{"m":11,"g":94},"327":{"m":11,"g":94},"326":{"m":11,"g":94},"298":{"m":11,"g":94},"438":{"m":12,"g":94},"437":{"m":12,"g":94},"426":{"m":12,"g":94},"436":{"m":12,"g":94},"434":{"m":12,"g":94},"418":{"m":12,"g":94},"433":{"m":12,"g":94},"363":{"m":12,"g":94},"432":{"m":12,"g":94},"515":{"m":13,"g":94},"514":{"m":13,"g":94},"505":{"m":13,"g":94},"512":{"m":13,"g":94},"502":{"m":13,"g":94},"500":{"m":13,"g":94},"511":{"m":13,"g":94},"493":{"m":13,"g":94},"491":{"m":13,"g":94},"492":{"m":13,"g":94},"488":{"m":13,"g":94},"486":{"m":13,"g":94},"480":{"m":13,"g":94},"484":{"m":13,"g":94},"477":{"m":13,"g":94},"475":{"m":13,"g":94},"476":{"m":13,"g":94},"440":{"m":13,"g":94},"471":{"m":13,"g":94},"463":{"m":13,"g":94},"470":{"m":13,"g":94},"460":{"m":13,"g":94},"459":{"m":13,"g":94},"458":{"m":13,"g":94},"457":{"m":13,"g":94},"456":{"m":13,"g":94},"250":{"m":13,"g":94},"451":{"m":13,"g":94},"449":{"m":13,"g":94},"448":{"m":13,"g":94},"447":{"m":13,"g":94},"446":{"m":13,"g":94},"441":{"m":13,"g":94},"419":{"m":13,"g":94},"579":{"m":14,"g":94},"585":{"m":14,"g":94},"583":{"m":14,"g":94},"578":{"m":14,"g":94},"577":{"m":14,"g":94},"576":{"m":14,"g":94},"574":{"m":14,"g":94},"545":{"m":14,"g":94},"571":{"m":14,"g":94},"569":{"m":14,"g":94},"568":{"m":14,"g":94},"567":{"m":14,"g":94},"566":{"m":14,"g":94},"564":{"m":14,"g":94},"563":{"m":14,"g":94},"561":{"m":14,"g":94},"560":{"m":14,"g":94},"559":{"m":14,"g":94},"558":{"m":14,"g":94},"557":{"m":14,"g":94},"556":{"m":14,"g":94},"554":{"m":14,"g":94},"550":{"m":14,"g":94},"553":{"m":14,"g":94},"551":{"m":14,"g":94},"546":{"m":14,"g":94},"542":{"m":14,"g":94},"540":{"m":14,"g":94},"539":{"m":14,"g":94},"538":{"m":14,"g":94},"517":{"m":14,"g":94},"531":{"m":14,"g":94},"516":{"m":14,"g":94},"526":{"m":14,"g":94},"525":{"m":14,"g":94},"524":{"m":14,"g":94},"518":{"m":14,"g":94},"605":{"m":15,"g":94},"503":{"m":15,"g":94},"530":{"m":15,"g":94},"603":{"m":15,"g":94},"598":{"m":15,"g":94},"602":{"m":15,"g":94},"604":{"m":15,"g":94},"601":{"m":15,"g":94},"600":{"m":15,"g":94},"599":{"m":15,"g":94},"586":{"m":15,"g":94},"594":{"m":15,"g":94},"593":{"m":15,"g":94},"592":{"m":15,"g":94},"588":{"m":15,"g":94},"618":{"m":16,"g":94},"616":{"m":16,"g":94},"615":{"m":16,"g":94},"614":{"m":16,"g":94},"613":{"m":16,"g":94},"612":{"m":16,"g":94},"611":{"m":16,"g":94},"610":{"m":16,"g":94},"609":{"m":16,"g":94},"607":{"m":16,"g":94},"626":{"m":17,"g":94},"625":{"m":17,"g":94},"623":{"m":17,"g":94},"621":{"m":17,"g":94},"620":{"m":17,"g":94},"619":{"m":17,"g":94},"677":{"m":18,"g":94},"676":{"m":18,"g":94},"675":{"m":18,"g":94},"664":{"m":18,"g":94},"673":{"m":18,"g":94},"671":{"m":18,"g":94},"669":{"m":18,"g":94},"668":{"m":18,"g":94},"667":{"m":18,"g":94},"640":{"m":18,"g":94},"666":{"m":18,"g":94},"665":{"m":18,"g":94},"663":{"m":18,"g":94},"662":{"m":18,"g":94},"661":{"m":18,"g":94},"660":{"m":18,"g":94},"659":{"m":18,"g":94},"655":{"m":18,"g":94},"657":{"m":18,"g":94},"658":{"m":18,"g":94},"656":{"m":18,"g":94},"654":{"m":18,"g":94},"653":{"m":18,"g":94},"651":{"m":18,"g":94},"650":{"m":18,"g":94},"648":{"m":18,"g":94},"647":{"m":18,"g":94},"649":{"m":18,"g":94},"646":{"m":18,"g":94},"645":{"m":18,"g":94},"643":{"m":18,"g":94},"642":{"m":18,"g":94},"617":{"m":18,"g":94},"638":{"m":18,"g":94},"637":{"m":18,"g":94},"636":{"m":18,"g":94},"635":{"m":18,"g":94},"632":{"m":18,"g":94},"633":{"m":18,"g":94},"624":{"m":18,"g":94},"630":{"m":18,"g":94},"631":{"m":18,"g":94},"629":{"m":18,"g":94},"628":{"m":18,"g":94},"627":{"m":18,"g":94},"705":{"m":19,"g":94},"704":{"m":19,"g":94},"701":{"m":19,"g":94},"702":{"m":19,"g":94},"700":{"m":19,"g":94},"698":{"m":19,"g":94},"697":{"m":19,"g":94},"696":{"m":19,"g":94},"695":{"m":19,"g":94},"694":{"m":19,"g":94},"692":{"m":19,"g":94},"691":{"m":19,"g":94},"690":{"m":19,"g":94},"689":{"m":19,"g":94},"688":{"m":19,"g":94},"687":{"m":19,"g":94},"686":{"m":19,"g":94},"685":{"m":19,"g":94},"684":{"m":19,"g":94},"682":{"m":19,"g":94},"681":{"m":19,"g":94},"679":{"m":19,"g":94},"670":{"m":19,"g":94},"678":{"m":19,"g":94},"718":{"m":20,"g":94},"717":{"m":20,"g":94},"716":{"m":20,"g":94},"715":{"m":20,"g":94},"714":{"m":20,"g":94},"713":{"m":20,"g":94},"712":{"m":20,"g":94},"711":{"m":20,"g":94},"708":{"m":20,"g":94},"709":{"m":20,"g":94},"707":{"m":20,"g":94},"706":{"m":20,"g":94},"730":{"m":21,"g":94},"729":{"m":21,"g":94},"728":{"m":21,"g":94},"727":{"m":21,"g":94},"726":{"m":21,"g":94},"725":{"m":21,"g":94},"720":{"m":21,"g":94},"723":{"m":21,"g":94},"724":{"m":21,"g":94},"722":{"m":21,"g":94},"721":{"m":21,"g":94},"719":{"m":21,"g":94},"755":{"m":22,"g":94},"754":{"m":22,"g":94},"753":{"m":22,"g":94},"752":{"m":22,"g":94},"751":{"m":22,"g":94},"740":{"m":22,"g":94},"743":{"m":22,"g":94},"742":{"m":22,"g":94},"739":{"m":22,"g":94},"741":{"m":22,"g":94},"736":{"m":22,"g":94},"734":{"m":22,"g":94},"733":{"m":22,"g":94},"731":{"m":22,"g":94},"779":{"m":23,"g":94},"778":{"m":23,"g":94},"776":{"m":23,"g":94},"775":{"m":23,"g":94},"774":{"m":23,"g":94},"773":{"m":23,"g":94},"772":{"m":23,"g":94},"766":{"m":23,"g":94},"770":{"m":23,"g":94},"769":{"m":23,"g":94},"767":{"m":23,"g":94},"761":{"m":23,"g":94},"763":{"m":23,"g":94},"762":{"m":23,"g":94},"760":{"m":23,"g":94},"757":{"m":23,"g":94},"693":{"m":23,"g":94},"830":{"m":24,"g":94},"829":{"m":24,"g":94},"828":{"m":24,"g":94},"825":{"m":24,"g":94},"826":{"m":24,"g":94},"823":{"m":24,"g":94},"824":{"m":24,"g":94},"822":{"m":24,"g":94},"821":{"m":24,"g":94},"820":{"m":24,"g":94},"819":{"m":24,"g":94},"807":{"m":24,"g":94},"817":{"m":24,"g":94},"814":{"m":24,"g":94},"815":{"m":24,"g":94},"812":{"m":24,"g":94},"809":{"m":24,"g":94},"699":{"m":24,"g":94},"806":{"m":24,"g":94},"802":{"m":24,"g":94},"805":{"m":24,"g":94},"803":{"m":24,"g":94},"800":{"m":24,"g":94},"799":{"m":24,"g":94},"797":{"m":24,"g":94},"793":{"m":24,"g":94},"796":{"m":24,"g":94},"795":{"m":24,"g":94},"794":{"m":24,"g":94},"792":{"m":24,"g":94},"791":{"m":24,"g":94},"790":{"m":24,"g":94},"789":{"m":24,"g":94},"788":{"m":24,"g":94},"787":{"m":24,"g":94},"786":{"m":24,"g":94},"785":{"m":24,"g":94},"784":{"m":24,"g":94},"783":{"m":24,"g":94},"781":{"m":24,"g":94},"877":{"m":25,"g":94},"872":{"m":25,"g":94},"873":{"m":25,"g":94},"871":{"m":25,"g":94},"870":{"m":25,"g":94},"869":{"m":25,"g":94},"864":{"m":25,"g":94},"862":{"m":25,"g":94},"861":{"m":25,"g":94},"860":{"m":25,"g":94},"811":{"m":25,"g":94},"852":{"m":25,"g":94},"858":{"m":25,"g":94},"856":{"m":25,"g":94},"855":{"m":25,"g":94},"850":{"m":25,"g":94},"848":{"m":25,"g":94},"843":{"m":25,"g":94},"842":{"m":25,"g":94},"838":{"m":25,"g":94},"840":{"m":25,"g":94},"890":{"m":26,"g":94},"886":{"m":26,"g":94},"889":{"m":26,"g":94},"888":{"m":26,"g":94},"883":{"m":26,"g":94},"882":{"m":26,"g":94},"880":{"m":26,"g":94},"879":{"m":26,"g":94},"749":{"m":26,"g":94},"878":{"m":26,"g":94},"876":{"m":26,"g":94},"875":{"m":26,"g":94},"899":{"m":27,"g":94},"896":{"m":27,"g":94},"895":{"m":27,"g":94},"894":{"m":27,"g":94},"884":{"m":27,"g":94},"891":{"m":27,"g":94},"923":{"m":28,"g":94},"916":{"m":28,"g":94},"920":{"m":28,"g":94},"918":{"m":28,"g":94},"917":{"m":28,"g":94},"915":{"m":28,"g":94},"905":{"m":28,"g":94},"914":{"m":28,"g":94},"912":{"m":28,"g":94},"911":{"m":28,"g":94},"909":{"m":28,"g":94},"866":{"m":28,"g":94},"904":{"m":28,"g":94},"908":{"m":28,"g":94},"900":{"m":28,"g":94},"970":{"m":29,"g":94},"966":{"m":29,"g":94},"967":{"m":29,"g":94},"960":{"m":29,"g":94},"965":{"m":29,"g":94},"964":{"m":29,"g":94},"963":{"m":29,"g":94},"932":{"m":29,"g":94},"936":{"m":29,"g":94},"957":{"m":29,"g":94},"953":{"m":29,"g":94},"948":{"m":29,"g":94},"941":{"m":29,"g":94},"940":{"m":29,"g":94},"835":{"m":29,"g":94},"934":{"m":29,"g":94},"935":{"m":29,"g":94},"928":{"m":29,"g":94},"927":{"m":29,"g":94},"926":{"m":29,"g":94},"925":{"m":29,"g":94},"921":{"m":29,"g":94},"1048":{"m":30,"g":94},"1052":{"m":30,"g":94},"1051":{"m":30,"g":94},"1049":{"m":30,"g":94},"1050":{"m":30,"g":94},"1033":{"m":30,"g":94},"1046":{"m":30,"g":94},"1047":{"m":30,"g":94},"1044":{"m":30,"g":94},"1045":{"m":30,"g":94},"1039":{"m":30,"g":94},"1037":{"m":30,"g":94},"1038":{"m":30,"g":94},"1025":{"m":30,"g":94},"1034":{"m":30,"g":94},"1031":{"m":30,"g":94},"1027":{"m":30,"g":94},"1029":{"m":30,"g":94},"1028":{"m":30,"g":94},"1022":{"m":30,"g":94},"1024":{"m":30,"g":94},"907":{"m":30,"g":94},"1021":{"m":30,"g":94},"1020":{"m":30,"g":94},"1019":{"m":30,"g":94},"990":{"m":30,"g":94},"1014":{"m":30,"g":94},"1010":{"m":30,"g":94},"1009":{"m":30,"g":94},"1007":{"m":30,"g":94},"959":{"m":30,"g":94},"997":{"m":30,"g":94},"1005":{"m":30,"g":94},"1002":{"m":30,"g":94},"1001":{"m":30,"g":94},"994":{"m":30,"g":94},"995":{"m":30,"g":94},"988":{"m":30,"g":94},"993":{"m":30,"g":94},"973":{"m":30,"g":94},"992":{"m":30,"g":94},"985":{"m":30,"g":94},"981":{"m":30,"g":94},"987":{"m":30,"g":94},"983":{"m":30,"g":94},"984":{"m":30,"g":94},"982":{"m":30,"g":94},"971":{"m":30,"g":94},"980":{"m":30,"g":94},"977":{"m":30,"g":94},"968":{"m":30,"g":94},"969":{"m":30,"g":94},"976":{"m":30,"g":94},"975":{"m":30,"g":94},"1111":{"m":31,"g":94},"1113":{"m":31,"g":94},"1112":{"m":31,"g":94},"1110":{"m":31,"g":94},"1107":{"m":31,"g":94},"1040":{"m":31,"g":94},"1106":{"m":31,"g":94},"1077":{"m":31,"g":94},"1104":{"m":31,"g":94},"1092":{"m":31,"g":94},"1103":{"m":31,"g":94},"1090":{"m":31,"g":94},"1082":{"m":31,"g":94},"1099":{"m":31,"g":94},"1095":{"m":31,"g":94},"1098":{"m":31,"g":94},"1096":{"m":31,"g":94},"1094":{"m":31,"g":94},"1088":{"m":31,"g":94},"1086":{"m":31,"g":94},"1084":{"m":31,"g":94},"1056":{"m":31,"g":94},"1081":{"m":31,"g":94},"1006":{"m":31,"g":94},"1079":{"m":31,"g":94},"1078":{"m":31,"g":94},"1074":{"m":31,"g":94},"1053":{"m":31,"g":94},"1070":{"m":31,"g":94},"1060":{"m":31,"g":94},"1066":{"m":31,"g":94},"1068":{"m":31,"g":94},"1057":{"m":31,"g":94},"1155":{"m":32,"g":94},"1201":{"m":32,"g":94},"1219":{"m":32,"g":94},"1212":{"m":32,"g":94},"1218":{"m":32,"g":94},"1217":{"m":32,"g":94},"1215":{"m":32,"g":94},"1214":{"m":32,"g":94},"1204":{"m":32,"g":94},"1213":{"m":32,"g":94},"1210":{"m":32,"g":94},"1211":{"m":32,"g":94},"1209":{"m":32,"g":94},"1208":{"m":32,"g":94},"1186":{"m":32,"g":94},"1205":{"m":32,"g":94},"1207":{"m":32,"g":94},"1199":{"m":32,"g":94},"1202":{"m":32,"g":94},"1198":{"m":32,"g":94},"1194":{"m":32,"g":94},"1193":{"m":32,"g":94},"1123":{"m":32,"g":94},"1185":{"m":32,"g":94},"1184":{"m":32,"g":94},"1180":{"m":32,"g":94},"1168":{"m":32,"g":94},"1179":{"m":32,"g":94},"1167":{"m":32,"g":94},"1170":{"m":32,"g":94},"1177":{"m":32,"g":94},"1171":{"m":32,"g":94},"1157":{"m":32,"g":94},"1166":{"m":32,"g":94},"1154":{"m":32,"g":94},"1165":{"m":32,"g":94},"1148":{"m":32,"g":94},"1164":{"m":32,"g":94},"1134":{"m":32,"g":94},"1138":{"m":32,"g":94},"1035":{"m":32,"g":94},"1144":{"m":32,"g":94},"1143":{"m":32,"g":94},"1141":{"m":32,"g":94},"1140":{"m":32,"g":94},"1139":{"m":32,"g":94},"1136":{"m":32,"g":94},"1133":{"m":32,"g":94},"1131":{"m":32,"g":94},"1013":{"m":32,"g":94},"1122":{"m":32,"g":94},"1119":{"m":32,"g":94},"1115":{"m":32,"g":94},"1114":{"m":32,"g":94},"1242":{"m":33,"g":94},"1239":{"m":33,"g":94},"1233":{"m":33,"g":94},"1237":{"m":33,"g":94},"1225":{"m":33,"g":94},"1236":{"m":33,"g":94},"1231":{"m":33,"g":94},"1230":{"m":33,"g":94},"1227":{"m":33,"g":94},"1222":{"m":33,"g":94},"1223":{"m":33,"g":94},"1125":{"m":33,"g":94},"1250":{"m":34,"g":94},"1252":{"m":34,"g":94},"1249":{"m":34,"g":94},"1234":{"m":34,"g":94},"1247":{"m":34,"g":94},"1232":{"m":34,"g":94},"1244":{"m":34,"g":94},"1243":{"m":34,"g":94},"1295":{"m":35,"g":94},"1297":{"m":35,"g":94},"1296":{"m":35,"g":94},"1294":{"m":35,"g":94},"1293":{"m":35,"g":94},"1291":{"m":35,"g":94},"1290":{"m":35,"g":94},"1277":{"m":35,"g":94},"1284":{"m":35,"g":94},"1288":{"m":35,"g":94},"1286":{"m":35,"g":94},"1289":{"m":35,"g":94},"1285":{"m":35,"g":94},"1280":{"m":35,"g":94},"1262":{"m":35,"g":94},"1282":{"m":35,"g":94},"1276":{"m":35,"g":94},"1256":{"m":35,"g":94},"1269":{"m":35,"g":94},"1267":{"m":35,"g":94},"1258":{"m":35,"g":94},"1261":{"m":35,"g":94},"1260":{"m":35,"g":94},"1253":{"m":35,"g":94},"1255":{"m":35,"g":94},"1254":{"m":35,"g":94},"1327":{"m":36,"g":94},"1326":{"m":36,"g":94},"1320":{"m":36,"g":94},"1319":{"m":36,"g":94},"1318":{"m":36,"g":94},"1317":{"m":36,"g":94},"1313":{"m":36,"g":94},"1299":{"m":36,"g":94},"1308":{"m":36,"g":94},"1306":{"m":36,"g":94},"1304":{"m":36,"g":94},"1445":{"m":37,"g":94},"1444":{"m":37,"g":94},"1442":{"m":37,"g":94},"1420":{"m":37,"g":94},"1441":{"m":37,"g":94},"1440":{"m":37,"g":94},"1438":{"m":37,"g":94},"1432":{"m":37,"g":94},"1433":{"m":37,"g":94},"1431":{"m":37,"g":94},"1430":{"m":37,"g":94},"1428":{"m":37,"g":94},"1429":{"m":37,"g":94},"1427":{"m":37,"g":94},"1422":{"m":37,"g":94},"1426":{"m":37,"g":94},"1425":{"m":37,"g":94},"1418":{"m":37,"g":94},"1392":{"m":37,"g":94},"1414":{"m":37,"g":94},"1412":{"m":37,"g":94},"1411":{"m":37,"g":94},"1409":{"m":37,"g":94},"1408":{"m":37,"g":94},"1407":{"m":37,"g":94},"1406":{"m":37,"g":94},"1307":{"m":37,"g":94},"1397":{"m":37,"g":94},"1402":{"m":37,"g":94},"1403":{"m":37,"g":94},"1401":{"m":37,"g":94},"1399":{"m":37,"g":94},"1393":{"m":37,"g":94},"1381":{"m":37,"g":94},"1390":{"m":37,"g":94},"1389":{"m":37,"g":94},"1367":{"m":37,"g":94},"1385":{"m":37,"g":94},"1378":{"m":37,"g":94},"1380":{"m":37,"g":94},"1379":{"m":37,"g":94},"1376":{"m":37,"g":94},"1375":{"m":37,"g":94},"1373":{"m":37,"g":94},"1371":{"m":37,"g":94},"1370":{"m":37,"g":94},"1368":{"m":37,"g":94},"1300":{"m":37,"g":94},"1363":{"m":37,"g":94},"1360":{"m":37,"g":94},"1361":{"m":37,"g":94},"1341":{"m":37,"g":94},"1357":{"m":37,"g":94},"1298":{"m":37,"g":94},"1346":{"m":37,"g":94},"1281":{"m":37,"g":94},"1345":{"m":37,"g":94},"1339":{"m":37,"g":94},"1340":{"m":37,"g":94},"1337":{"m":37,"g":94},"1336":{"m":37,"g":94},"1328":{"m":37,"g":94},"1470":{"m":38,"g":94},"1469":{"m":38,"g":94},"1464":{"m":38,"g":94},"1458":{"m":38,"g":94},"1457":{"m":38,"g":94},"1454":{"m":38,"g":94},"1453":{"m":38,"g":94},"1452":{"m":38,"g":94},"1449":{"m":38,"g":94},"1451":{"m":38,"g":94},"1450":{"m":38,"g":94},"1448":{"m":38,"g":94},"1447":{"m":38,"g":94},"1483":{"m":39,"g":94},"1484":{"m":39,"g":94},"1482":{"m":39,"g":94},"1476":{"m":39,"g":94},"1475":{"m":39,"g":94},"1305":{"m":39,"g":94},"1472":{"m":39,"g":94},"1512":{"m":40,"g":94},"1511":{"m":40,"g":94},"1508":{"m":40,"g":94},"1510":{"m":40,"g":94},"1503":{"m":40,"g":94},"1499":{"m":40,"g":94},"1502":{"m":40,"g":94},"1500":{"m":40,"g":94},"1497":{"m":40,"g":94},"1496":{"m":40,"g":94},"1494":{"m":40,"g":94},"1490":{"m":40,"g":94},"1492":{"m":40,"g":94},"1491":{"m":40,"g":94},"1489":{"m":40,"g":94},"1456":{"m":40,"g":94},"1488":{"m":40,"g":94},"1486":{"m":40,"g":94},"1481":{"m":40,"g":94},"1605":{"m":41,"g":94},"1606":{"m":41,"g":94},"1604":{"m":41,"g":94},"1598":{"m":41,"g":94},"1603":{"m":41,"g":94},"1597":{"m":41,"g":94},"1594":{"m":41,"g":94},"1596":{"m":41,"g":94},"1595":{"m":41,"g":94},"1593":{"m":41,"g":94},"1567":{"m":41,"g":94},"1592":{"m":41,"g":94},"1591":{"m":41,"g":94},"1590":{"m":41,"g":94},"1589":{"m":41,"g":94},"1587":{"m":41,"g":94},"1586":{"m":41,"g":94},"1585":{"m":41,"g":94},"1584":{"m":41,"g":94},"1573":{"m":41,"g":94},"1582":{"m":41,"g":94},"1583":{"m":41,"g":94},"1581":{"m":41,"g":94},"1576":{"m":41,"g":94},"1561":{"m":41,"g":94},"1572":{"m":41,"g":94},"1577":{"m":41,"g":94},"1580":{"m":41,"g":94},"1574":{"m":41,"g":94},"1563":{"m":41,"g":94},"1569":{"m":41,"g":94},"1568":{"m":41,"g":94},"1566":{"m":41,"g":94},"1562":{"m":41,"g":94},"1559":{"m":41,"g":94},"1536":{"m":41,"g":94},"1557":{"m":41,"g":94},"1556":{"m":41,"g":94},"1555":{"m":41,"g":94},"1553":{"m":41,"g":94},"1554":{"m":41,"g":94},"1549":{"m":41,"g":94},"1552":{"m":41,"g":94},"1550":{"m":41,"g":94},"1548":{"m":41,"g":94},"1547":{"m":41,"g":94},"1545":{"m":41,"g":94},"1544":{"m":41,"g":94},"1543":{"m":41,"g":94},"1541":{"m":41,"g":94},"1539":{"m":41,"g":94},"1538":{"m":41,"g":94},"1537":{"m":41,"g":94},"1534":{"m":41,"g":94},"1531":{"m":41,"g":94},"1532":{"m":41,"g":94},"1530":{"m":41,"g":94},"1495":{"m":41,"g":94},"1520":{"m":41,"g":94},"1521":{"m":41,"g":94},"1528":{"m":41,"g":94},"1525":{"m":41,"g":94},"1529":{"m":41,"g":94},"1524":{"m":41,"g":94},"1513":{"m":41,"g":94},"1636":{"m":42,"g":94},"1635":{"m":42,"g":94},"1634":{"m":42,"g":94},"1633":{"m":42,"g":94},"1632":{"m":42,"g":94},"1631":{"m":42,"g":94},"1626":{"m":42,"g":94},"1579":{"m":42,"g":94},"1611":{"m":42,"g":94},"1607":{"m":42,"g":94},"1629":{"m":42,"g":94},"1625":{"m":42,"g":94},"1619":{"m":42,"g":94},"1620":{"m":42,"g":94},"1615":{"m":42,"g":94},"1714":{"m":43,"g":94},"1713":{"m":43,"g":94},"1712":{"m":43,"g":94},"1710":{"m":43,"g":94},"1709":{"m":43,"g":94},"1707":{"m":43,"g":94},"1706":{"m":43,"g":94},"1705":{"m":43,"g":94},"1704":{"m":43,"g":94},"1703":{"m":43,"g":94},"1684":{"m":43,"g":94},"1702":{"m":43,"g":94},"1701":{"m":43,"g":94},"1700":{"m":43,"g":94},"1699":{"m":43,"g":94},"1694":{"m":43,"g":94},"1697":{"m":43,"g":94},"1696":{"m":43,"g":94},"1690":{"m":43,"g":94},"1679":{"m":43,"g":94},"1689":{"m":43,"g":94},"1688":{"m":43,"g":94},"1599":{"m":43,"g":94},"1687":{"m":43,"g":94},"1686":{"m":43,"g":94},"1685":{"m":43,"g":94},"1677":{"m":43,"g":94},"1676":{"m":43,"g":94},"1681":{"m":43,"g":94},"1674":{"m":43,"g":94},"1672":{"m":43,"g":94},"1671":{"m":43,"g":94},"1670":{"m":43,"g":94},"1658":{"m":43,"g":94},"1667":{"m":43,"g":94},"1666":{"m":43,"g":94},"1665":{"m":43,"g":94},"1459":{"m":43,"g":94},"1663":{"m":43,"g":94},"1662":{"m":43,"g":94},"1661":{"m":43,"g":94},"1659":{"m":43,"g":94},"1650":{"m":43,"g":94},"1656":{"m":43,"g":94},"1652":{"m":43,"g":94},"1654":{"m":43,"g":94},"1653":{"m":43,"g":94},"1651":{"m":43,"g":94},"1648":{"m":43,"g":94},"1480":{"m":43,"g":94},"1645":{"m":43,"g":94},"1642":{"m":43,"g":94},"1638":{"m":43,"g":94},"1614":{"m":43,"g":94},"1749":{"m":44,"g":94},"1748":{"m":44,"g":94},"1551":{"m":44,"g":94},"1746":{"m":44,"g":94},"1737":{"m":44,"g":94},"1738":{"m":44,"g":94},"1743":{"m":44,"g":94},"1741":{"m":44,"g":94},"1740":{"m":44,"g":94},"1736":{"m":44,"g":94},"1735":{"m":44,"g":94},"1734":{"m":44,"g":94},"1727":{"m":44,"g":94},"1726":{"m":44,"g":94},"1725":{"m":44,"g":94},"1724":{"m":44,"g":94},"1722":{"m":44,"g":94},"1721":{"m":44,"g":94},"1720":{"m":44,"g":94},"1718":{"m":44,"g":94},"1716":{"m":44,"g":94},"1796":{"m":45,"g":94},"1795":{"m":45,"g":94},"1797":{"m":45,"g":94},"1794":{"m":45,"g":94},"1787":{"m":45,"g":94},"1793":{"m":45,"g":94},"1780":{"m":45,"g":94},"1789":{"m":45,"g":94},"1785":{"m":45,"g":94},"1783":{"m":45,"g":94},"1778":{"m":45,"g":94},"1782":{"m":45,"g":94},"1779":{"m":45,"g":94},"1776":{"m":45,"g":94},"1774":{"m":45,"g":94},"1773":{"m":45,"g":94},"1772":{"m":45,"g":94},"1771":{"m":45,"g":94},"1769":{"m":45,"g":94},"1768":{"m":45,"g":94},"1766":{"m":45,"g":94},"1767":{"m":45,"g":94},"1765":{"m":45,"g":94},"1760":{"m":45,"g":94},"1758":{"m":45,"g":94},"1747":{"m":45,"g":94},"1908":{"m":46,"g":94},"1907":{"m":46,"g":94},"1906":{"m":46,"g":94},"1902":{"m":46,"g":94},"1905":{"m":46,"g":94},"1904":{"m":46,"g":94},"1903":{"m":46,"g":94},"1899":{"m":46,"g":94},"1896":{"m":46,"g":94},"1895":{"m":46,"g":94},"1894":{"m":46,"g":94},"1892":{"m":46,"g":94},"1890":{"m":46,"g":94},"1888":{"m":46,"g":94},"1889":{"m":46,"g":94},"1886":{"m":46,"g":94},"1885":{"m":46,"g":94},"1883":{"m":46,"g":94},"1873":{"m":46,"g":94},"1882":{"m":46,"g":94},"1881":{"m":46,"g":94},"1879":{"m":46,"g":94},"1878":{"m":46,"g":94},"1877":{"m":46,"g":94},"1875":{"m":46,"g":94},"1871":{"m":46,"g":94},"1867":{"m":46,"g":94},"1866":{"m":46,"g":94},"1754":{"m":46,"g":94},"1856":{"m":46,"g":94},"1859":{"m":46,"g":94},"1860":{"m":46,"g":94},"1861":{"m":46,"g":94},"1858":{"m":46,"g":94},"1855":{"m":46,"g":94},"1852":{"m":46,"g":94},"1851":{"m":46,"g":94},"1846":{"m":46,"g":94},"1850":{"m":46,"g":94},"1847":{"m":46,"g":94},"1845":{"m":46,"g":94},"1842":{"m":46,"g":94},"1836":{"m":46,"g":94},"1838":{"m":46,"g":94},"1840":{"m":46,"g":94},"1839":{"m":46,"g":94},"1827":{"m":46,"g":94},"1833":{"m":46,"g":94},"1835":{"m":46,"g":94},"1834":{"m":46,"g":94},"1822":{"m":46,"g":94},"1823":{"m":46,"g":94},"1830":{"m":46,"g":94},"1825":{"m":46,"g":94},"1790":{"m":46,"g":94},"1821":{"m":46,"g":94},"1820":{"m":46,"g":94},"1819":{"m":46,"g":94},"1810":{"m":46,"g":94},"1817":{"m":46,"g":94},"1816":{"m":46,"g":94},"1813":{"m":46,"g":94},"1811":{"m":46,"g":94},"1809":{"m":46,"g":94},"1808":{"m":46,"g":94},"1807":{"m":46,"g":94},"1805":{"m":46,"g":94},"1804":{"m":46,"g":94},"1803":{"m":46,"g":94},"1802":{"m":46,"g":94},"1801":{"m":46,"g":94},"1800":{"m":46,"g":94},"1786":{"m":46,"g":94},"1799":{"m":46,"g":94},"1798":{"m":46,"g":94},"1752":{"m":46,"g":94},"2022":{"m":47,"g":94},"2020":{"m":47,"g":94},"2018":{"m":47,"g":94},"1996":{"m":47,"g":94},"2015":{"m":47,"g":94},"2014":{"m":47,"g":94},"2013":{"m":47,"g":94},"1998":{"m":47,"g":94},"2011":{"m":47,"g":94},"2010":{"m":47,"g":94},"2009":{"m":47,"g":94},"2008":{"m":47,"g":94},"2006":{"m":47,"g":94},"2005":{"m":47,"g":94},"1994":{"m":47,"g":94},"2003":{"m":47,"g":94},"2004":{"m":47,"g":94},"2002":{"m":47,"g":94},"2001":{"m":47,"g":94},"2000":{"m":47,"g":94},"1999":{"m":47,"g":94},"1995":{"m":47,"g":94},"1997":{"m":47,"g":94},"1934":{"m":47,"g":94},"1980":{"m":47,"g":94},"1990":{"m":47,"g":94},"1988":{"m":47,"g":94},"1984":{"m":47,"g":94},"1986":{"m":47,"g":94},"1983":{"m":47,"g":94},"1981":{"m":47,"g":94},"1982":{"m":47,"g":94},"1977":{"m":47,"g":94},"1972":{"m":47,"g":94},"1976":{"m":47,"g":94},"1975":{"m":47,"g":94},"1974":{"m":47,"g":94},"1745":{"m":47,"g":94},"1973":{"m":47,"g":94},"1963":{"m":47,"g":94},"1966":{"m":47,"g":94},"1962":{"m":47,"g":94},"1961":{"m":47,"g":94},"1958":{"m":47,"g":94},"1957":{"m":47,"g":94},"1956":{"m":47,"g":94},"1955":{"m":47,"g":94},"1954":{"m":47,"g":94},"1933":{"m":47,"g":94},"1952":{"m":47,"g":94},"1951":{"m":47,"g":94},"1939":{"m":47,"g":94},"1941":{"m":47,"g":94},"1949":{"m":47,"g":94},"1940":{"m":47,"g":94},"1942":{"m":47,"g":94},"1891":{"m":47,"g":94},"1926":{"m":47,"g":94},"1922":{"m":47,"g":94},"1853":{"m":47,"g":94},"1924":{"m":47,"g":94},"1920":{"m":47,"g":94},"1916":{"m":47,"g":94},"1893":{"m":47,"g":94},"1915":{"m":47,"g":94},"1910":{"m":47,"g":94},"1909":{"m":47,"g":94},"2046":{"m":48,"g":94},"2044":{"m":48,"g":94},"2043":{"m":48,"g":94},"2030":{"m":48,"g":94},"2042":{"m":48,"g":94},"2038":{"m":48,"g":94},"1968":{"m":48,"g":94},"2039":{"m":48,"g":94},"2036":{"m":48,"g":94},"2034":{"m":48,"g":94},"2033":{"m":48,"g":94},"2031":{"m":48,"g":94},"2027":{"m":48,"g":94},"2028":{"m":48,"g":94},"2026":{"m":48,"g":94},"2024":{"m":48,"g":94},"2023":{"m":48,"g":94},"2120":{"m":49,"g":94},"2125":{"m":49,"g":94},"2122":{"m":49,"g":94},"2110":{"m":49,"g":94},"2118":{"m":49,"g":94},"2106":{"m":49,"g":94},"2115":{"m":49,"g":94},"2055":{"m":49,"g":94},"2111":{"m":49,"g":94},"2116":{"m":49,"g":94},"2107":{"m":49,"g":94},"2105":{"m":49,"g":94},"2104":{"m":49,"g":94},"2103":{"m":49,"g":94},"2073":{"m":49,"g":94},"2100":{"m":49,"g":94},"2067":{"m":49,"g":94},"2096":{"m":49,"g":94},"2095":{"m":49,"g":94},"2093":{"m":49,"g":94},"2094":{"m":49,"g":94},"2091":{"m":49,"g":94},"2088":{"m":49,"g":94},"2089":{"m":49,"g":94},"2086":{"m":49,"g":94},"2085":{"m":49,"g":94},"2083":{"m":49,"g":94},"2078":{"m":49,"g":94},"2069":{"m":49,"g":94},"2075":{"m":49,"g":94},"2074":{"m":49,"g":94},"2072":{"m":49,"g":94},"2071":{"m":49,"g":94},"2070":{"m":49,"g":94},"2068":{"m":49,"g":94},"2062":{"m":49,"g":94},"2056":{"m":49,"g":94},"2066":{"m":49,"g":94},"2061":{"m":49,"g":94},"2065":{"m":49,"g":94},"2064":{"m":49,"g":94},"2063":{"m":49,"g":94},"1849":{"m":49,"g":94},"2053":{"m":49,"g":94},"2051":{"m":49,"g":94},"1970":{"m":49,"g":94},"2050":{"m":49,"g":94},"2049":{"m":49,"g":94},"1876":{"m":49,"g":94},"2048":{"m":49,"g":94},"2047":{"m":49,"g":94},"2189":{"m":50,"g":94},"2188":{"m":50,"g":94},"2187":{"m":50,"g":94},"2052":{"m":50,"g":94},"2184":{"m":50,"g":94},"2176":{"m":50,"g":94},"2186":{"m":50,"g":94},"2171":{"m":50,"g":94},"2185":{"m":50,"g":94},"2183":{"m":50,"g":94},"2173":{"m":50,"g":94},"2182":{"m":50,"g":94},"2180":{"m":50,"g":94},"2175":{"m":50,"g":94},"2174":{"m":50,"g":94},"2170":{"m":50,"g":94},"2169":{"m":50,"g":94},"2167":{"m":50,"g":94},"2164":{"m":50,"g":94},"2163":{"m":50,"g":94},"2162":{"m":50,"g":94},"2158":{"m":50,"g":94},"2161":{"m":50,"g":94},"2159":{"m":50,"g":94},"2156":{"m":50,"g":94},"2154":{"m":50,"g":94},"2157":{"m":50,"g":94},"2155":{"m":50,"g":94},"2153":{"m":50,"g":94},"2152":{"m":50,"g":94},"2148":{"m":50,"g":94},"2147":{"m":50,"g":94},"2146":{"m":50,"g":94},"2144":{"m":50,"g":94},"2143":{"m":50,"g":94},"2142":{"m":50,"g":94},"2114":{"m":50,"g":94},"2139":{"m":50,"g":94},"2138":{"m":50,"g":94},"2136":{"m":50,"g":94},"2137":{"m":50,"g":94},"2134":{"m":50,"g":94},"2081":{"m":50,"g":94},"2121":{"m":50,"g":94},"2130":{"m":50,"g":94},"2124":{"m":50,"g":94},"2092":{"m":50,"g":94},"2127":{"m":50,"g":94},"2077":{"m":50,"g":94},"2126":{"m":50,"g":94},"2214":{"m":51,"g":94},"2222":{"m":51,"g":94},"2221":{"m":51,"g":94},"2217":{"m":51,"g":94},"2210":{"m":51,"g":94},"2212":{"m":51,"g":94},"2208":{"m":51,"g":94},"2207":{"m":51,"g":94},"2204":{"m":51,"g":94},"2206":{"m":51,"g":94},"2201":{"m":51,"g":94},"2199":{"m":51,"g":94},"2196":{"m":51,"g":94},"2198":{"m":51,"g":94},"2195":{"m":51,"g":94},"2197":{"m":51,"g":94},"2259":{"m":52,"g":94},"2257":{"m":52,"g":94},"2256":{"m":52,"g":94},"2254":{"m":52,"g":94},"2253":{"m":52,"g":94},"2252":{"m":52,"g":94},"2251":{"m":52,"g":94},"2250":{"m":52,"g":94},"2239":{"m":52,"g":94},"2242":{"m":52,"g":94},"2238":{"m":52,"g":94},"2231":{"m":52,"g":94},"2233":{"m":52,"g":94},"2235":{"m":52,"g":94},"2234":{"m":52,"g":94},"2232":{"m":52,"g":94},"2228":{"m":52,"g":94},"2123":{"m":52,"g":94},"2223":{"m":52,"g":94},"2224":{"m":52,"g":94},"2226":{"m":52,"g":94},"2191":{"m":52,"g":94},"2218":{"m":52,"g":94},"2338":{"m":53,"g":94},"2339":{"m":53,"g":94},"2300":{"m":53,"g":94},"2335":{"m":53,"g":94},"2327":{"m":53,"g":94},"2324":{"m":53,"g":94},"2328":{"m":53,"g":94},"2329":{"m":53,"g":94},"2325":{"m":53,"g":94},"2281":{"m":53,"g":94},"2319":{"m":53,"g":94},"2318":{"m":53,"g":94},"2314":{"m":53,"g":94},"2311":{"m":53,"g":94},"2310":{"m":53,"g":94},"2309":{"m":53,"g":94},"2279":{"m":53,"g":94},"2306":{"m":53,"g":94},"2305":{"m":53,"g":94},"2304":{"m":53,"g":94},"2301":{"m":53,"g":94},"2302":{"m":53,"g":94},"2299":{"m":53,"g":94},"2298":{"m":53,"g":94},"2241":{"m":53,"g":94},"2295":{"m":53,"g":94},"2292":{"m":53,"g":94},"2179":{"m":53,"g":94},"2293":{"m":53,"g":94},"2290":{"m":53,"g":94},"2244":{"m":53,"g":94},"2288":{"m":53,"g":94},"2289":{"m":53,"g":94},"2287":{"m":53,"g":94},"2284":{"m":53,"g":94},"2286":{"m":53,"g":94},"2285":{"m":53,"g":94},"2282":{"m":53,"g":94},"2215":{"m":53,"g":94},"2280":{"m":53,"g":94},"2274":{"m":53,"g":94},"2266":{"m":53,"g":94},"2265":{"m":53,"g":94},"2269":{"m":53,"g":94},"2243":{"m":53,"g":94},"2268":{"m":53,"g":94},"2225":{"m":53,"g":94},"2261":{"m":53,"g":94},"2375":{"m":54,"g":94},"2377":{"m":54,"g":94},"2363":{"m":54,"g":94},"2374":{"m":54,"g":94},"2373":{"m":54,"g":94},"2369":{"m":54,"g":94},"2357":{"m":54,"g":94},"2360":{"m":54,"g":94},"2370":{"m":54,"g":94},"2371":{"m":54,"g":94},"2368":{"m":54,"g":94},"2359":{"m":54,"g":94},"2364":{"m":54,"g":94},"2355":{"m":54,"g":94},"2342":{"m":54,"g":94},"2352":{"m":54,"g":94},"2308":{"m":54,"g":94},"2323":{"m":54,"g":94},"2350":{"m":54,"g":94},"2340":{"m":54,"g":94},"2349":{"m":54,"g":94},"2341":{"m":54,"g":94},"2348":{"m":54,"g":94},"2525":{"m":55,"g":94},"2528":{"m":55,"g":94},"2524":{"m":55,"g":94},"2517":{"m":55,"g":94},"2516":{"m":55,"g":94},"2515":{"m":55,"g":94},"2502":{"m":55,"g":94},"2500":{"m":55,"g":94},"2499":{"m":55,"g":94},"2438":{"m":55,"g":94},"2426":{"m":55,"g":94},"2457":{"m":55,"g":94},"2467":{"m":55,"g":94},"2495":{"m":55,"g":94},"2494":{"m":55,"g":94},"2493":{"m":55,"g":94},"2492":{"m":55,"g":94},"2491":{"m":55,"g":94},"2476":{"m":55,"g":94},"2490":{"m":55,"g":94},"2489":{"m":55,"g":94},"2486":{"m":55,"g":94},"2487":{"m":55,"g":94},"2481":{"m":55,"g":94},"2485":{"m":55,"g":94},"2484":{"m":55,"g":94},"2483":{"m":55,"g":94},"2479":{"m":55,"g":94},"2473":{"m":55,"g":94},"2469":{"m":55,"g":94},"2464":{"m":55,"g":94},"2466":{"m":55,"g":94},"2463":{"m":55,"g":94},"2462":{"m":55,"g":94},"2459":{"m":55,"g":94},"2456":{"m":55,"g":94},"2444":{"m":55,"g":94},"2455":{"m":55,"g":94},"2454":{"m":55,"g":94},"2442":{"m":55,"g":94},"2453":{"m":55,"g":94},"2452":{"m":55,"g":94},"2437":{"m":55,"g":94},"2449":{"m":55,"g":94},"2448":{"m":55,"g":94},"2425":{"m":55,"g":94},"2447":{"m":55,"g":94},"2436":{"m":55,"g":94},"2441":{"m":55,"g":94},"2440":{"m":55,"g":94},"2435":{"m":55,"g":94},"2434":{"m":55,"g":94},"2433":{"m":55,"g":94},"2424":{"m":55,"g":94},"2412":{"m":55,"g":94},"2422":{"m":55,"g":94},"2419":{"m":55,"g":94},"2417":{"m":55,"g":94},"2416":{"m":55,"g":94},"2410":{"m":55,"g":94},"2393":{"m":55,"g":94},"2413":{"m":55,"g":94},"2411":{"m":55,"g":94},"2398":{"m":55,"g":94},"2409":{"m":55,"g":94},"2408":{"m":55,"g":94},"2407":{"m":55,"g":94},"2406":{"m":55,"g":94},"2405":{"m":55,"g":94},"2404":{"m":55,"g":94},"2403":{"m":55,"g":94},"2401":{"m":55,"g":94},"2397":{"m":55,"g":94},"2394":{"m":55,"g":94},"2382":{"m":55,"g":94},"2330":{"m":55,"g":94},"2392":{"m":55,"g":94},"2391":{"m":55,"g":94},"2388":{"m":55,"g":94},"2390":{"m":55,"g":94},"2387":{"m":55,"g":94},"2380":{"m":55,"g":94},"2379":{"m":55,"g":94},"2378":{"m":55,"g":94},"2582":{"m":56,"g":94},"2581":{"m":56,"g":94},"2580":{"m":56,"g":94},"2579":{"m":56,"g":94},"2575":{"m":56,"g":94},"2566":{"m":56,"g":94},"2563":{"m":56,"g":94},"2553":{"m":56,"g":94},"2545":{"m":56,"g":94},"2547":{"m":56,"g":94},"2543":{"m":56,"g":94},"2509":{"m":56,"g":94},"2523":{"m":56,"g":94},"2529":{"m":56,"g":94},"2541":{"m":56,"g":94},"2616":{"m":57,"g":94},"2617":{"m":57,"g":94},"2615":{"m":57,"g":94},"2610":{"m":57,"g":94},"2611":{"m":57,"g":94},"2612":{"m":57,"g":94},"2608":{"m":57,"g":94},"2606":{"m":57,"g":94},"2586":{"m":57,"g":94},"2605":{"m":57,"g":94},"2603":{"m":57,"g":94},"2564":{"m":57,"g":94},"2570":{"m":57,"g":94},"2521":{"m":57,"g":94},"2598":{"m":57,"g":94},"2574":{"m":57,"g":94},"2565":{"m":57,"g":94},"2597":{"m":57,"g":94},"2596":{"m":57,"g":94},"2526":{"m":57,"g":94},"2557":{"m":57,"g":94},"2594":{"m":57,"g":94},"2555":{"m":57,"g":94},"2560":{"m":57,"g":94},"2592":{"m":57,"g":94},"2590":{"m":57,"g":94},"2589":{"m":57,"g":94},"2643":{"m":58,"g":94},"2641":{"m":58,"g":94},"2637":{"m":58,"g":94},"2635":{"m":58,"g":94},"2640":{"m":58,"g":94},"2639":{"m":58,"g":94},"2638":{"m":58,"g":94},"2609":{"m":58,"g":94},"2544":{"m":58,"g":94},"2631":{"m":58,"g":94},"2628":{"m":58,"g":94},"2633":{"m":58,"g":94},"2614":{"m":58,"g":94},"2626":{"m":58,"g":94},"2624":{"m":58,"g":94},"2625":{"m":58,"g":94},"2623":{"m":58,"g":94},"2622":{"m":58,"g":94},"2475":{"m":58,"g":94},"2618":{"m":58,"g":94},"2647":{"m":59,"g":94},"2648":{"m":59,"g":94},"2646":{"m":59,"g":94},"2636":{"m":59,"g":94},"2645":{"m":59,"g":94},"2644":{"m":59,"g":94},"2713":{"m":60,"g":94},"2688":{"m":60,"g":94},"2735":{"m":60,"g":94},"2733":{"m":60,"g":94},"2731":{"m":60,"g":94},"2571":{"m":60,"g":94},"2726":{"m":60,"g":94},"2727":{"m":60,"g":94},"2722":{"m":60,"g":94},"2717":{"m":60,"g":94},"2601":{"m":60,"g":94},"2716":{"m":60,"g":94},"2711":{"m":60,"g":94},"2714":{"m":60,"g":94},"2704":{"m":60,"g":94},"2707":{"m":60,"g":94},"2712":{"m":60,"g":94},"2150":{"m":60,"g":94},"2709":{"m":60,"g":94},"2695":{"m":60,"g":94},"2705":{"m":60,"g":94},"2663":{"m":60,"g":94},"2697":{"m":60,"g":94},"2692":{"m":60,"g":94},"2691":{"m":60,"g":94},"2690":{"m":60,"g":94},"2689":{"m":60,"g":94},"2685":{"m":60,"g":94},"2684":{"m":60,"g":94},"2683":{"m":60,"g":94},"2682":{"m":60,"g":94},"2680":{"m":60,"g":94},"2678":{"m":60,"g":94},"2679":{"m":60,"g":94},"2676":{"m":60,"g":94},"2674":{"m":60,"g":94},"2672":{"m":60,"g":94},"2670":{"m":60,"g":94},"2667":{"m":60,"g":94},"2669":{"m":60,"g":94},"2664":{"m":60,"g":94},"2642":{"m":60,"g":94},"2666":{"m":60,"g":94},"2654":{"m":60,"g":94},"2655":{"m":60,"g":94},"2656":{"m":60,"g":94},"2652":{"m":60,"g":94},"2651":{"m":60,"g":94},"2650":{"m":60,"g":94},"2649":{"m":60,"g":94},"2840":{"m":61,"g":94},"2837":{"m":61,"g":94},"2836":{"m":61,"g":94},"2804":{"m":61,"g":94},"2730":{"m":61,"g":94},"2826":{"m":61,"g":94},"2835":{"m":61,"g":94},"2822":{"m":61,"g":94},"2819":{"m":61,"g":94},"2833":{"m":61,"g":94},"2830":{"m":61,"g":94},"2787":{"m":61,"g":94},"2816":{"m":61,"g":94},"2813":{"m":61,"g":94},"2809":{"m":61,"g":94},"2792":{"m":61,"g":94},"2789":{"m":61,"g":94},"2773":{"m":61,"g":94},"2784":{"m":61,"g":94},"2723":{"m":61,"g":94},"2780":{"m":61,"g":94},"2779":{"m":61,"g":94},"2771":{"m":61,"g":94},"2774":{"m":61,"g":94},"2761":{"m":61,"g":94},"2770":{"m":61,"g":94},"2767":{"m":61,"g":94},"2758":{"m":61,"g":94},"2757":{"m":61,"g":94},"2513":{"m":61,"g":94},"2535":{"m":61,"g":94},"2756":{"m":61,"g":94},"2745":{"m":61,"g":94},"2748":{"m":61,"g":94},"2752":{"m":61,"g":94},"2751":{"m":61,"g":94},"2750":{"m":61,"g":94},"2899":{"m":62,"g":94},"2887":{"m":62,"g":94},"2888":{"m":62,"g":94},"2881":{"m":62,"g":94},"2885":{"m":62,"g":94},"2879":{"m":62,"g":94},"2878":{"m":62,"g":94},"2875":{"m":62,"g":94},"2630":{"m":62,"g":94},"2870":{"m":62,"g":94},"2869":{"m":62,"g":94},"2863":{"m":62,"g":94},"2868":{"m":62,"g":94},"2867":{"m":62,"g":94},"2862":{"m":62,"g":94},"2866":{"m":62,"g":94},"2865":{"m":62,"g":94},"2828":{"m":62,"g":94},"2859":{"m":62,"g":94},"2858":{"m":62,"g":94},"2861":{"m":62,"g":94},"2857":{"m":62,"g":94},"2860":{"m":62,"g":94},"2856":{"m":62,"g":94},"2851":{"m":62,"g":94},"2853":{"m":62,"g":94},"2854":{"m":62,"g":94},"2852":{"m":62,"g":94},"2786":{"m":62,"g":94},"2848":{"m":62,"g":94},"2850":{"m":62,"g":94},"2846":{"m":62,"g":94},"2843":{"m":62,"g":94},"2841":{"m":62,"g":94},"3009":{"m":63,"g":94},"2993":{"m":63,"g":94},"3010":{"m":63,"g":94},"3006":{"m":63,"g":94},"3008":{"m":63,"g":94},"3003":{"m":63,"g":94},"2998":{"m":63,"g":94},"3005":{"m":63,"g":94},"3004":{"m":63,"g":94},"3001":{"m":63,"g":94},"2996":{"m":63,"g":94},"2997":{"m":63,"g":94},"2995":{"m":63,"g":94},"2991":{"m":63,"g":94},"2992":{"m":63,"g":94},"2990":{"m":63,"g":94},"2396":{"m":63,"g":94},"2983":{"m":63,"g":94},"2988":{"m":63,"g":94},"2839":{"m":63,"g":94},"2982":{"m":63,"g":94},"2986":{"m":63,"g":94},"2987":{"m":63,"g":94},"2985":{"m":63,"g":94},"2984":{"m":63,"g":94},"2981":{"m":63,"g":94},"2975":{"m":63,"g":94},"2980":{"m":63,"g":94},"2979":{"m":63,"g":94},"2978":{"m":63,"g":94},"2976":{"m":63,"g":94},"2974":{"m":63,"g":94},"2973":{"m":63,"g":94},"2972":{"m":63,"g":94},"2958":{"m":63,"g":94},"2956":{"m":63,"g":94},"2901":{"m":63,"g":94},"2971":{"m":63,"g":94},"2785":{"m":63,"g":94},"2966":{"m":63,"g":94},"2967":{"m":63,"g":94},"2964":{"m":63,"g":94},"2963":{"m":63,"g":94},"2960":{"m":63,"g":94},"2941":{"m":63,"g":94},"2894":{"m":63,"g":94},"2942":{"m":63,"g":94},"2944":{"m":63,"g":94},"2954":{"m":63,"g":94},"2952":{"m":63,"g":94},"2951":{"m":63,"g":94},"2947":{"m":63,"g":94},"2948":{"m":63,"g":94},"2949":{"m":63,"g":94},"2950":{"m":63,"g":94},"2945":{"m":63,"g":94},"2907":{"m":63,"g":94},"2938":{"m":63,"g":94},"2937":{"m":63,"g":94},"2806":{"m":63,"g":94},"2876":{"m":63,"g":94},"2930":{"m":63,"g":94},"2928":{"m":63,"g":94},"2920":{"m":63,"g":94},"2926":{"m":63,"g":94},"2927":{"m":63,"g":94},"2925":{"m":63,"g":94},"2924":{"m":63,"g":94},"2923":{"m":63,"g":94},"2821":{"m":63,"g":94},"2910":{"m":63,"g":94},"2922":{"m":63,"g":94},"2919":{"m":63,"g":94},"2917":{"m":63,"g":94},"2915":{"m":63,"g":94},"2911":{"m":63,"g":94},"2909":{"m":63,"g":94},"2908":{"m":63,"g":94},"2511":{"m":63,"g":94},"2906":{"m":63,"g":94},"2904":{"m":63,"g":94},"2902":{"m":63,"g":94},"2872":{"m":63,"g":94},"2897":{"m":63,"g":94},"3180":{"m":64,"g":94},"3179":{"m":64,"g":94},"3178":{"m":64,"g":94},"3175":{"m":64,"g":94},"3176":{"m":64,"g":94},"3174":{"m":64,"g":94},"3146":{"m":64,"g":94},"3173":{"m":64,"g":94},"3170":{"m":64,"g":94},"3167":{"m":64,"g":94},"3156":{"m":64,"g":94},"3134":{"m":64,"g":94},"3162":{"m":64,"g":94},"3144":{"m":64,"g":94},"3155":{"m":64,"g":94},"2700":{"m":64,"g":94},"3154":{"m":64,"g":94},"3153":{"m":64,"g":94},"3152":{"m":64,"g":94},"3150":{"m":64,"g":94},"3151":{"m":64,"g":94},"3149":{"m":64,"g":94},"3147":{"m":64,"g":94},"3145":{"m":64,"g":94},"3085":{"m":64,"g":94},"3047":{"m":64,"g":94},"3143":{"m":64,"g":94},"3139":{"m":64,"g":94},"3135":{"m":64,"g":94},"3138":{"m":64,"g":94},"3113":{"m":64,"g":94},"3133":{"m":64,"g":94},"3132":{"m":64,"g":94},"3130":{"m":64,"g":94},"3129":{"m":64,"g":94},"3128":{"m":64,"g":94},"3127":{"m":64,"g":94},"3126":{"m":64,"g":94},"3125":{"m":64,"g":94},"3124":{"m":64,"g":94},"3121":{"m":64,"g":94},"3110":{"m":64,"g":94},"3109":{"m":64,"g":94},"3107":{"m":64,"g":94},"3096":{"m":64,"g":94},"3037":{"m":64,"g":94},"3105":{"m":64,"g":94},"3097":{"m":64,"g":94},"3095":{"m":64,"g":94},"3094":{"m":64,"g":94},"3070":{"m":64,"g":94},"3093":{"m":64,"g":94},"2742":{"m":64,"g":94},"3087":{"m":64,"g":94},"3086":{"m":64,"g":94},"3084":{"m":64,"g":94},"3083":{"m":64,"g":94},"3081":{"m":64,"g":94},"3080":{"m":64,"g":94},"3079":{"m":64,"g":94},"3078":{"m":64,"g":94},"3074":{"m":64,"g":94},"3030":{"m":64,"g":94},"3071":{"m":64,"g":94},"3069":{"m":64,"g":94},"3068":{"m":64,"g":94},"3067":{"m":64,"g":94},"3061":{"m":64,"g":94},"3062":{"m":64,"g":94},"3063":{"m":64,"g":94},"2989":{"m":64,"g":94},"3060":{"m":64,"g":94},"3045":{"m":64,"g":94},"3038":{"m":64,"g":94},"3058":{"m":64,"g":94},"3057":{"m":64,"g":94},"3055":{"m":64,"g":94},"3056":{"m":64,"g":94},"3054":{"m":64,"g":94},"3053":{"m":64,"g":94},"3052":{"m":64,"g":94},"3051":{"m":64,"g":94},"3048":{"m":64,"g":94},"3046":{"m":64,"g":94},"3039":{"m":64,"g":94},"3036":{"m":64,"g":94},"3035":{"m":64,"g":94},"3033":{"m":64,"g":94},"3027":{"m":64,"g":94},"3026":{"m":64,"g":94},"3025":{"m":64,"g":94},"3014":{"m":64,"g":94},"3018":{"m":64,"g":94},"2939":{"m":64,"g":94},"3022":{"m":64,"g":94},"3021":{"m":64,"g":94},"3017":{"m":64,"g":94},"3015":{"m":64,"g":94},"3020":{"m":64,"g":94},"3019":{"m":64,"g":94},"3016":{"m":64,"g":94},"3013":{"m":64,"g":94},"3012":{"m":64,"g":94},"3233":{"m":65,"g":94},"3231":{"m":65,"g":94},"3232":{"m":65,"g":94},"3224":{"m":65,"g":94},"3230":{"m":65,"g":94},"3229":{"m":65,"g":94},"3227":{"m":65,"g":94},"3218":{"m":65,"g":94},"3217":{"m":65,"g":94},"3216":{"m":65,"g":94},"3214":{"m":65,"g":94},"3213":{"m":65,"g":94},"3212":{"m":65,"g":94},"2977":{"m":65,"g":94},"3190":{"m":65,"g":94},"3169":{"m":65,"g":94},"3192":{"m":65,"g":94},"3183":{"m":65,"g":94},"3166":{"m":65,"g":94},"3171":{"m":65,"g":94},"3181":{"m":65,"g":94},"3313":{"m":66,"g":94},"3312":{"m":66,"g":94},"3306":{"m":66,"g":94},"3305":{"m":66,"g":94},"3299":{"m":66,"g":94},"3294":{"m":66,"g":94},"3293":{"m":66,"g":94},"3292":{"m":66,"g":94},"3287":{"m":66,"g":94},"3288":{"m":66,"g":94},"3161":{"m":66,"g":94},"3273":{"m":66,"g":94},"3276":{"m":66,"g":94},"3274":{"m":66,"g":94},"3272":{"m":66,"g":94},"3270":{"m":66,"g":94},"3269":{"m":66,"g":94},"3268":{"m":66,"g":94},"3205":{"m":66,"g":94},"3207":{"m":66,"g":94},"3259":{"m":66,"g":94},"3261":{"m":66,"g":94},"3114":{"m":66,"g":94},"3255":{"m":66,"g":94},"3252":{"m":66,"g":94},"3251":{"m":66,"g":94},"3250":{"m":66,"g":94},"3249":{"m":66,"g":94},"3248":{"m":66,"g":94},"3246":{"m":66,"g":94},"3221":{"m":66,"g":94},"3242":{"m":66,"g":94},"3240":{"m":66,"g":94},"3238":{"m":66,"g":94},"3236":{"m":66,"g":94},"3235":{"m":66,"g":94},"3228":{"m":66,"g":94},"3369":{"m":67,"g":94},"3378":{"m":67,"g":94},"3376":{"m":67,"g":94},"3374":{"m":67,"g":94},"3373":{"m":67,"g":94},"3372":{"m":67,"g":94},"3366":{"m":67,"g":94},"3356":{"m":67,"g":94},"3300":{"m":67,"g":94},"3355":{"m":67,"g":94},"3314":{"m":67,"g":94},"3350":{"m":67,"g":94},"3347":{"m":67,"g":94},"3352":{"m":67,"g":94},"3349":{"m":67,"g":94},"3338":{"m":67,"g":94},"3337":{"m":67,"g":94},"3335":{"m":67,"g":94},"3332":{"m":67,"g":94},"3325":{"m":67,"g":94},"3327":{"m":67,"g":94},"3324":{"m":67,"g":94},"3168":{"m":67,"g":94},"3317":{"m":67,"g":94},"3309":{"m":67,"g":94},"3459":{"m":68,"g":94},"3457":{"m":68,"g":94},"3413":{"m":68,"g":94},"3453":{"m":68,"g":94},"3452":{"m":68,"g":94},"3442":{"m":68,"g":94},"3441":{"m":68,"g":94},"3440":{"m":68,"g":94},"3439":{"m":68,"g":94},"3437":{"m":68,"g":94},"3410":{"m":68,"g":94},"3435":{"m":68,"g":94},"3433":{"m":68,"g":94},"3431":{"m":68,"g":94},"3430":{"m":68,"g":94},"3425":{"m":68,"g":94},"3422":{"m":68,"g":94},"3421":{"m":68,"g":94},"3408":{"m":68,"g":94},"3415":{"m":68,"g":94},"3411":{"m":68,"g":94},"3412":{"m":68,"g":94},"3407":{"m":68,"g":94},"3404":{"m":68,"g":94},"3346":{"m":68,"g":94},"3382":{"m":68,"g":94},"3386":{"m":68,"g":94},"3275":{"m":68,"g":94},"3556":{"m":69,"g":94},"3555":{"m":69,"g":94},"3550":{"m":69,"g":94},"3553":{"m":69,"g":94},"3543":{"m":69,"g":94},"3534":{"m":69,"g":94},"3541":{"m":69,"g":94},"3536":{"m":69,"g":94},"3529":{"m":69,"g":94},"3530":{"m":69,"g":94},"3267":{"m":69,"g":94},"3450":{"m":69,"g":94},"3503":{"m":69,"g":94},"3493":{"m":69,"g":94},"3523":{"m":69,"g":94},"3522":{"m":69,"g":94},"3405":{"m":69,"g":94},"3502":{"m":69,"g":94},"3420":{"m":69,"g":94},"3495":{"m":69,"g":94},"3496":{"m":69,"g":94},"3499":{"m":69,"g":94},"3498":{"m":69,"g":94},"3497":{"m":69,"g":94},"3500":{"m":69,"g":94},"3492":{"m":69,"g":94},"3490":{"m":69,"g":94},"3418":{"m":69,"g":94},"3364":{"m":69,"g":94},"3473":{"m":69,"g":94},"3469":{"m":69,"g":94},"3468":{"m":69,"g":94},"3466":{"m":69,"g":94},"3638":{"m":70,"g":94},"3636":{"m":70,"g":94},"3634":{"m":70,"g":94},"3632":{"m":70,"g":94},"3619":{"m":70,"g":94},"3617":{"m":70,"g":94},"3260":{"m":70,"g":94},"3532":{"m":70,"g":94},"3597":{"m":70,"g":94},"3535":{"m":70,"g":94},"3258":{"m":70,"g":94},"3598":{"m":70,"g":94},"3564":{"m":70,"g":94},"3594":{"m":70,"g":94},"3592":{"m":70,"g":94},"3591":{"m":70,"g":94},"3589":{"m":70,"g":94},"3587":{"m":70,"g":94},"3582":{"m":70,"g":94},"3548":{"m":70,"g":94},"3584":{"m":70,"g":94},"3505":{"m":70,"g":94},"3581":{"m":70,"g":94},"3563":{"m":70,"g":94},"3363":{"m":70,"g":94},"3558":{"m":70,"g":94},"3557":{"m":70,"g":94},"3645":{"m":71,"g":94},"3644":{"m":71,"g":94},"3643":{"m":71,"g":94},"3639":{"m":71,"g":94},"4114":{"m":72,"g":94},"4099":{"m":72,"g":94},"4101":{"m":72,"g":94},"3211":{"m":72,"g":94},"3029":{"m":72,"g":94},"4110":{"m":72,"g":94},"4105":{"m":72,"g":94},"4109":{"m":72,"g":94},"4103":{"m":72,"g":94},"4108":{"m":72,"g":94},"4107":{"m":72,"g":94},"4102":{"m":72,"g":94},"4100":{"m":72,"g":94},"4012":{"m":72,"g":94},"4081":{"m":72,"g":94},"3986":{"m":72,"g":94},"4075":{"m":72,"g":94},"3990":{"m":72,"g":94},"3790":{"m":72,"g":94},"3941":{"m":72,"g":94},"4077":{"m":72,"g":94},"4074":{"m":72,"g":94},"4066":{"m":72,"g":94},"4071":{"m":72,"g":94},"4065":{"m":72,"g":94},"4016":{"m":72,"g":94},"3607":{"m":72,"g":94},"3712":{"m":72,"g":94},"3948":{"m":72,"g":94},"3954":{"m":72,"g":94},"4030":{"m":72,"g":94},"4051":{"m":72,"g":94},"4046":{"m":72,"g":94},"4053":{"m":72,"g":94},"4052":{"m":72,"g":94},"4023":{"m":72,"g":94},"4000":{"m":72,"g":94},"4049":{"m":72,"g":94},"4044":{"m":72,"g":94},"4043":{"m":72,"g":94},"4033":{"m":72,"g":94},"4039":{"m":72,"g":94},"3999":{"m":72,"g":94},"4034":{"m":72,"g":94},"4032":{"m":72,"g":94},"4027":{"m":72,"g":94},"4025":{"m":72,"g":94},"3264":{"m":72,"g":94},"4031":{"m":72,"g":94},"4029":{"m":72,"g":94},"4021":{"m":72,"g":94},"3988":{"m":72,"g":94},"4014":{"m":72,"g":94},"3826":{"m":72,"g":94},"4010":{"m":72,"g":94},"4008":{"m":72,"g":94},"3987":{"m":72,"g":94},"3822":{"m":72,"g":94},"3993":{"m":72,"g":94},"3406":{"m":72,"g":94},"3994":{"m":72,"g":94},"3992":{"m":72,"g":94},"3991":{"m":72,"g":94},"3893":{"m":72,"g":94},"3989":{"m":72,"g":94},"3985":{"m":72,"g":94},"3982":{"m":72,"g":94},"3979":{"m":72,"g":94},"3976":{"m":72,"g":94},"3977":{"m":72,"g":94},"3975":{"m":72,"g":94},"3967":{"m":72,"g":94},"3966":{"m":72,"g":94},"3963":{"m":72,"g":94},"3852":{"m":72,"g":94},"3566":{"m":72,"g":94},"3678":{"m":72,"g":94},"3950":{"m":72,"g":94},"3870":{"m":72,"g":94},"3613":{"m":72,"g":94},"3866":{"m":72,"g":94},"3861":{"m":72,"g":94},"3934":{"m":72,"g":94},"3933":{"m":72,"g":94},"3593":{"m":72,"g":94},"3922":{"m":72,"g":94},"3925":{"m":72,"g":94},"3914":{"m":72,"g":94},"3905":{"m":72,"g":94},"3897":{"m":72,"g":94},"3907":{"m":72,"g":94},"3898":{"m":72,"g":94},"3903":{"m":72,"g":94},"3791":{"m":72,"g":94},"3900":{"m":72,"g":94},"3894":{"m":72,"g":94},"3298":{"m":72,"g":94},"3860":{"m":72,"g":94},"3845":{"m":72,"g":94},"3602":{"m":72,"g":94},"3865":{"m":72,"g":94},"3843":{"m":72,"g":94},"3519":{"m":72,"g":94},"3841":{"m":72,"g":94},"3857":{"m":72,"g":94},"3709":{"m":72,"g":94},"3803":{"m":72,"g":94},"3787":{"m":72,"g":94},"3237":{"m":72,"g":94},"3641":{"m":72,"g":94},"3741":{"m":72,"g":94},"3799":{"m":72,"g":94},"3801":{"m":72,"g":94},"3821":{"m":72,"g":94},"3829":{"m":72,"g":94},"3828":{"m":72,"g":94},"3818":{"m":72,"g":94},"3730":{"m":72,"g":94},"3785":{"m":72,"g":94},"3813":{"m":72,"g":94},"3809":{"m":72,"g":94},"2693":{"m":72,"g":94},"3795":{"m":72,"g":94},"3116":{"m":72,"g":94},"3115":{"m":72,"g":94},"3562":{"m":72,"g":94},"3117":{"m":72,"g":94},"3766":{"m":72,"g":94},"3777":{"m":72,"g":94},"3348":{"m":72,"g":94},"3223":{"m":72,"g":94},"3772":{"m":72,"g":94},"3773":{"m":72,"g":94},"3771":{"m":72,"g":94},"3733":{"m":72,"g":94},"3754":{"m":72,"g":94},"3432":{"m":72,"g":94},"3761":{"m":72,"g":94},"3740":{"m":72,"g":94},"3680":{"m":72,"g":94},"3747":{"m":72,"g":94},"3737":{"m":72,"g":94},"3588":{"m":72,"g":94},"3652":{"m":72,"g":94},"3732":{"m":72,"g":94},"3705":{"m":72,"g":94},"3731":{"m":72,"g":94},"3722":{"m":72,"g":94},"3727":{"m":72,"g":94},"3710":{"m":72,"g":94},"3677":{"m":72,"g":94},"3601":{"m":72,"g":94},"3692":{"m":72,"g":94},"3700":{"m":72,"g":94},"3706":{"m":72,"g":94},"3628":{"m":72,"g":94},"3698":{"m":72,"g":94},"3657":{"m":72,"g":94},"3665":{"m":72,"g":94},"3635":{"m":72,"g":94},"3676":{"m":72,"g":94},"3663":{"m":72,"g":94},"3629":{"m":72,"g":94},"3654":{"m":72,"g":94},"3624":{"m":72,"g":94},"3567":{"m":72,"g":94},"3616":{"m":72,"g":94},"3650":{"m":72,"g":94},"4140":{"m":73,"g":94},"4142":{"m":73,"g":94},"4147":{"m":73,"g":94},"4134":{"m":73,"g":94},"4135":{"m":73,"g":94},"4138":{"m":73,"g":94},"4137":{"m":73,"g":94},"4132":{"m":73,"g":94},"4128":{"m":73,"g":94},"4126":{"m":73,"g":94},"4129":{"m":73,"g":94},"4131":{"m":73,"g":94},"4038":{"m":73,"g":94},"4111":{"m":73,"g":94},"4113":{"m":73,"g":94},"4117":{"m":73,"g":94},"4121":{"m":73,"g":94},"4041":{"m":74,"g":94},"4381":{"m":74,"g":94},"4377":{"m":74,"g":94},"4376":{"m":74,"g":94},"4374":{"m":74,"g":94},"4367":{"m":74,"g":94},"4086":{"m":74,"g":94},"4356":{"m":74,"g":94},"3679":{"m":74,"g":94},"3814":{"m":74,"g":94},"3835":{"m":74,"g":94},"3844":{"m":74,"g":94},"3896":{"m":74,"g":94},"3959":{"m":74,"g":94},"3980":{"m":74,"g":94},"3962":{"m":74,"g":94},"3961":{"m":74,"g":94},"4026":{"m":74,"g":94},"4079":{"m":74,"g":94},"4359":{"m":74,"g":94},"4212":{"m":74,"g":94},"4295":{"m":74,"g":94},"4342":{"m":74,"g":94},"4335":{"m":74,"g":94},"4329":{"m":74,"g":94},"4362":{"m":74,"g":94},"4348":{"m":74,"g":94},"4326":{"m":74,"g":94},"4354":{"m":74,"g":94},"4355":{"m":74,"g":94},"4352":{"m":74,"g":94},"4350":{"m":74,"g":94},"4278":{"m":74,"g":94},"4082":{"m":74,"g":94},"3203":{"m":74,"g":94},"4340":{"m":74,"g":94},"4337":{"m":74,"g":94},"3911":{"m":74,"g":94},"4334":{"m":74,"g":94},"4331":{"m":74,"g":94},"4333":{"m":74,"g":94},"4104":{"m":74,"g":94},"4215":{"m":74,"g":94},"4327":{"m":74,"g":94},"4297":{"m":74,"g":94},"4323":{"m":74,"g":94},"4321":{"m":74,"g":94},"4317":{"m":74,"g":94},"4229":{"m":74,"g":94},"4220":{"m":74,"g":94},"4311":{"m":74,"g":94},"4299":{"m":74,"g":94},"4287":{"m":74,"g":94},"4290":{"m":74,"g":94},"4199":{"m":74,"g":94},"4291":{"m":74,"g":94},"4136":{"m":74,"g":94},"4288":{"m":74,"g":94},"4284":{"m":74,"g":94},"4277":{"m":74,"g":94},"4279":{"m":74,"g":94},"4275":{"m":74,"g":94},"4272":{"m":74,"g":94},"4261":{"m":74,"g":94},"4256":{"m":74,"g":94},"4267":{"m":74,"g":94},"4262":{"m":74,"g":94},"4258":{"m":74,"g":94},"4255":{"m":74,"g":94},"4231":{"m":74,"g":94},"4144":{"m":74,"g":94},"4252":{"m":74,"g":94},"4206":{"m":74,"g":94},"3958":{"m":74,"g":94},"4165":{"m":74,"g":94},"4250":{"m":74,"g":94},"4230":{"m":74,"g":94},"4238":{"m":74,"g":94},"4243":{"m":74,"g":94},"4242":{"m":74,"g":94},"4241":{"m":74,"g":94},"4237":{"m":74,"g":94},"4235":{"m":74,"g":94},"4228":{"m":74,"g":94},"4217":{"m":74,"g":94},"3148":{"m":74,"g":94},"4218":{"m":74,"g":94},"4224":{"m":74,"g":94},"4193":{"m":74,"g":94},"3631":{"m":74,"g":94},"4225":{"m":74,"g":94},"4223":{"m":74,"g":94},"4213":{"m":74,"g":94},"4222":{"m":74,"g":94},"4219":{"m":74,"g":94},"4124":{"m":74,"g":94},"4216":{"m":74,"g":94},"4211":{"m":74,"g":94},"4210":{"m":74,"g":94},"3749":{"m":74,"g":94},"4203":{"m":74,"g":94},"4181":{"m":74,"g":94},"4200":{"m":74,"g":94},"4198":{"m":74,"g":94},"4197":{"m":74,"g":94},"4164":{"m":74,"g":94},"4195":{"m":74,"g":94},"4194":{"m":74,"g":94},"4189":{"m":74,"g":94},"4185":{"m":74,"g":94},"4187":{"m":74,"g":94},"4186":{"m":74,"g":94},"4178":{"m":74,"g":94},"4174":{"m":74,"g":94},"4179":{"m":74,"g":94},"4177":{"m":74,"g":94},"4176":{"m":74,"g":94},"4170":{"m":74,"g":94},"4168":{"m":74,"g":94},"4166":{"m":74,"g":94},"4162":{"m":74,"g":94},"4163":{"m":74,"g":94},"3888":{"m":74,"g":94},"4089":{"m":74,"g":94},"3786":{"m":74,"g":94},"3694":{"m":74,"g":94},"4152":{"m":74,"g":94},"4154":{"m":74,"g":94},"4151":{"m":74,"g":94},"4148":{"m":74,"g":94},"4402":{"m":75,"g":94},"4397":{"m":75,"g":94},"4399":{"m":75,"g":94},"4269":{"m":75,"g":94},"4320":{"m":75,"g":94},"4398":{"m":75,"g":94},"4393":{"m":75,"g":94},"4390":{"m":75,"g":94},"4392":{"m":75,"g":94},"4375":{"m":75,"g":94},"4669":{"m":76,"g":94},"4743":{"m":76,"g":94},"4797":{"m":76,"g":94},"4782":{"m":76,"g":94},"4777":{"m":76,"g":94},"4775":{"m":76,"g":94},"4784":{"m":76,"g":94},"4566":{"m":76,"g":94},"4728":{"m":76,"g":94},"4755":{"m":76,"g":94},"4753":{"m":76,"g":94},"4752":{"m":76,"g":94},"4751":{"m":76,"g":94},"4310":{"m":76,"g":94},"4705":{"m":76,"g":94},"4435":{"m":76,"g":94},"4695":{"m":76,"g":94},"4691":{"m":76,"g":94},"4738":{"m":76,"g":94},"4735":{"m":76,"g":94},"4744":{"m":76,"g":94},"3023":{"m":76,"g":94},"4737":{"m":76,"g":94},"3899":{"m":76,"g":94},"4609":{"m":76,"g":94},"4736":{"m":76,"g":94},"4716":{"m":76,"g":94},"4721":{"m":76,"g":94},"4731":{"m":76,"g":94},"4720":{"m":76,"g":94},"4396":{"m":76,"g":94},"4605":{"m":76,"g":94},"4680":{"m":76,"g":94},"4631":{"m":76,"g":94},"4698":{"m":76,"g":94},"4064":{"m":76,"g":94},"4525":{"m":76,"g":94},"4661":{"m":76,"g":94},"4610":{"m":76,"g":94},"4608":{"m":76,"g":94},"4685":{"m":76,"g":94},"4679":{"m":76,"g":94},"4643":{"m":76,"g":94},"3984":{"m":76,"g":94},"4660":{"m":76,"g":94},"4676":{"m":76,"g":94},"4670":{"m":76,"g":94},"4677":{"m":76,"g":94},"4674":{"m":76,"g":94},"4556":{"m":76,"g":94},"4665":{"m":76,"g":94},"4596":{"m":76,"g":94},"4639":{"m":76,"g":94},"4664":{"m":76,"g":94},"4582":{"m":76,"g":94},"4654":{"m":76,"g":94},"4637":{"m":76,"g":94},"4641":{"m":76,"g":94},"4613":{"m":76,"g":94},"4640":{"m":76,"g":94},"4558":{"m":76,"g":94},"4622":{"m":76,"g":94},"4592":{"m":76,"g":94},"4571":{"m":76,"g":94},"3446":{"m":76,"g":94},"4577":{"m":76,"g":94},"4549":{"m":76,"g":94},"4583":{"m":76,"g":94},"4514":{"m":76,"g":94},"4232":{"m":76,"g":94},"4515":{"m":76,"g":94},"4557":{"m":76,"g":94},"4553":{"m":76,"g":94},"4274":{"m":76,"g":94},"4521":{"m":76,"g":94},"4247":{"m":76,"g":94},"4532":{"m":76,"g":94},"4441":{"m":76,"g":94},"4538":{"m":76,"g":94},"4541":{"m":76,"g":94},"4542":{"m":76,"g":94},"4500":{"m":76,"g":94},"4531":{"m":76,"g":94},"3682":{"m":76,"g":94},"4458":{"m":76,"g":94},"4486":{"m":76,"g":94},"4507":{"m":76,"g":94},"4522":{"m":76,"g":94},"4520":{"m":76,"g":94},"4505":{"m":76,"g":94},"4482":{"m":76,"g":94},"4517":{"m":76,"g":94},"4513":{"m":76,"g":94},"4510":{"m":76,"g":94},"4499":{"m":76,"g":94},"4495":{"m":76,"g":94},"4446":{"m":76,"g":94},"4480":{"m":76,"g":94},"4067":{"m":76,"g":94},"4485":{"m":76,"g":94},"4418":{"m":76,"g":94},"4493":{"m":76,"g":94},"2798":{"m":76,"g":94},"4372":{"m":76,"g":94},"4483":{"m":76,"g":94},"4386":{"m":76,"g":94},"2797":{"m":76,"g":94},"3612":{"m":76,"g":94},"4448":{"m":76,"g":94},"4465":{"m":76,"g":94},"4474":{"m":76,"g":94},"4479":{"m":76,"g":94},"4424":{"m":76,"g":94},"4202":{"m":76,"g":94},"4484":{"m":76,"g":94},"4481":{"m":76,"g":94},"4477":{"m":76,"g":94},"4472":{"m":76,"g":94},"4363":{"m":76,"g":94},"4470":{"m":76,"g":94},"4469":{"m":76,"g":94},"4383":{"m":76,"g":94},"4468":{"m":76,"g":94},"4467":{"m":76,"g":94},"4466":{"m":76,"g":94},"4449":{"m":76,"g":94},"4464":{"m":76,"g":94},"4460":{"m":76,"g":94},"4368":{"m":76,"g":94},"4459":{"m":76,"g":94},"4447":{"m":76,"g":94},"4423":{"m":76,"g":94},"4391":{"m":76,"g":94},"4413":{"m":76,"g":94},"4454":{"m":76,"g":94},"4453":{"m":76,"g":94},"4455":{"m":76,"g":94},"4452":{"m":76,"g":94},"4451":{"m":76,"g":94},"4442":{"m":76,"g":94},"4439":{"m":76,"g":94},"4438":{"m":76,"g":94},"4437":{"m":76,"g":94},"4302":{"m":76,"g":94},"4427":{"m":76,"g":94},"4419":{"m":76,"g":94},"3964":{"m":76,"g":94},"4400":{"m":76,"g":94},"4009":{"m":76,"g":94},"4403":{"m":76,"g":94},"4878":{"m":77,"g":94},"4874":{"m":77,"g":94},"4873":{"m":77,"g":94},"4831":{"m":77,"g":94},"4872":{"m":77,"g":94},"4768":{"m":77,"g":94},"4871":{"m":77,"g":94},"4866":{"m":77,"g":94},"4749":{"m":77,"g":94},"4864":{"m":77,"g":94},"4772":{"m":77,"g":94},"4834":{"m":77,"g":94},"4492":{"m":77,"g":94},"4863":{"m":77,"g":94},"4855":{"m":77,"g":94},"4853":{"m":77,"g":94},"4840":{"m":77,"g":94},"4740":{"m":77,"g":94},"4750":{"m":77,"g":94},"4687":{"m":77,"g":94},"4729":{"m":77,"g":94},"4712":{"m":77,"g":94},"4704":{"m":77,"g":94},"4688":{"m":77,"g":94},"4681":{"m":77,"g":94},"4648":{"m":77,"g":94},"4832":{"m":77,"g":94},"4528":{"m":77,"g":94},"4597":{"m":77,"g":94},"4487":{"m":77,"g":94},"3949":{"m":77,"g":94},"4844":{"m":77,"g":94},"4846":{"m":77,"g":94},"4843":{"m":77,"g":94},"4799":{"m":77,"g":94},"4788":{"m":77,"g":94},"4809":{"m":77,"g":94},"4837":{"m":77,"g":94},"3969":{"m":77,"g":94},"4835":{"m":77,"g":94},"4815":{"m":77,"g":94},"4819":{"m":77,"g":94},"4770":{"m":77,"g":94},"4833":{"m":77,"g":94},"4830":{"m":77,"g":94},"4694":{"m":77,"g":94},"4826":{"m":77,"g":94},"4825":{"m":77,"g":94},"4828":{"m":77,"g":94},"4827":{"m":77,"g":94},"4823":{"m":77,"g":94},"4341":{"m":77,"g":94},"4638":{"m":77,"g":94},"4813":{"m":77,"g":94},"4764":{"m":77,"g":94},"4706":{"m":77,"g":94},"4745":{"m":77,"g":94},"4565":{"m":77,"g":94},"4804":{"m":77,"g":94},"4506":{"m":77,"g":94},"4388":{"m":77,"g":94},"4628":{"m":77,"g":94},"4719":{"m":77,"g":94},"5091":{"m":78,"g":94},"5080":{"m":78,"g":94},"5089":{"m":78,"g":94},"5079":{"m":78,"g":94},"5088":{"m":78,"g":94},"5052":{"m":78,"g":94},"5050":{"m":78,"g":94},"5074":{"m":78,"g":94},"4535":{"m":78,"g":94},"5072":{"m":78,"g":94},"4918":{"m":78,"g":94},"4996":{"m":78,"g":94},"4995":{"m":78,"g":94},"4994":{"m":78,"g":94},"5060":{"m":78,"g":94},"5057":{"m":78,"g":94},"5056":{"m":78,"g":94},"4625":{"m":78,"g":94},"5049":{"m":78,"g":94},"5051":{"m":78,"g":94},"5039":{"m":78,"g":94},"4796":{"m":78,"g":94},"5046":{"m":78,"g":94},"5048":{"m":78,"g":94},"5036":{"m":78,"g":94},"4992":{"m":78,"g":94},"5005":{"m":78,"g":94},"5024":{"m":78,"g":94},"5030":{"m":78,"g":94},"5020":{"m":78,"g":94},"4727":{"m":78,"g":94},"5009":{"m":78,"g":94},"5011":{"m":78,"g":94},"4817":{"m":78,"g":94},"5008":{"m":78,"g":94},"4951":{"m":78,"g":94},"4861":{"m":78,"g":94},"4989":{"m":78,"g":94},"4581":{"m":78,"g":94},"4915":{"m":78,"g":94},"4977":{"m":78,"g":94},"4958":{"m":78,"g":94},"4767":{"m":78,"g":94},"4959":{"m":78,"g":94},"4954":{"m":78,"g":94},"4953":{"m":78,"g":94},"4950":{"m":78,"g":94},"4754":{"m":78,"g":94},"4944":{"m":78,"g":94},"4928":{"m":78,"g":94},"4913":{"m":78,"g":94},"4936":{"m":78,"g":94},"4883":{"m":78,"g":94},"4925":{"m":78,"g":94},"4933":{"m":78,"g":94},"4932":{"m":78,"g":94},"4931":{"m":78,"g":94},"4902":{"m":78,"g":94},"4930":{"m":78,"g":94},"4927":{"m":78,"g":94},"4926":{"m":78,"g":94},"4896":{"m":78,"g":94},"4914":{"m":78,"g":94},"4908":{"m":78,"g":94},"4909":{"m":78,"g":94},"4890":{"m":78,"g":94},"4899":{"m":78,"g":94},"4898":{"m":78,"g":94},"4530":{"m":78,"g":94},"4891":{"m":78,"g":94},"4889":{"m":78,"g":94},"4886":{"m":78,"g":94},"4795":{"m":78,"g":94},"4845":{"m":78,"g":94},"4882":{"m":78,"g":94},"5117":{"m":79,"g":94},"5106":{"m":79,"g":94},"5092":{"m":79,"g":94},"5097":{"m":79,"g":94},"5445":{"m":80,"g":94},"5113":{"m":80,"g":94},"5425":{"m":80,"g":94},"5397":{"m":80,"g":94},"5398":{"m":80,"g":94},"5038":{"m":80,"g":94},"5211":{"m":80,"g":94},"5264":{"m":80,"g":94},"5436":{"m":80,"g":94},"5344":{"m":80,"g":94},"5431":{"m":80,"g":94},"5434":{"m":80,"g":94},"5430":{"m":80,"g":94},"5419":{"m":80,"g":94},"5420":{"m":80,"g":94},"5423":{"m":80,"g":94},"5422":{"m":80,"g":94},"5415":{"m":80,"g":94},"5416":{"m":80,"g":94},"5351":{"m":80,"g":94},"5412":{"m":80,"g":94},"5352":{"m":80,"g":94},"5214":{"m":80,"g":94},"5406":{"m":80,"g":94},"5401":{"m":80,"g":94},"5400":{"m":80,"g":94},"5381":{"m":80,"g":94},"5399":{"m":80,"g":94},"5395":{"m":80,"g":94},"5279":{"m":80,"g":94},"5291":{"m":80,"g":94},"5368":{"m":80,"g":94},"5393":{"m":80,"g":94},"5263":{"m":80,"g":94},"5392":{"m":80,"g":94},"5371":{"m":80,"g":94},"5385":{"m":80,"g":94},"5370":{"m":80,"g":94},"5384":{"m":80,"g":94},"5326":{"m":80,"g":94},"5003":{"m":80,"g":94},"5367":{"m":80,"g":94},"5364":{"m":80,"g":94},"5277":{"m":80,"g":94},"5360":{"m":80,"g":94},"5359":{"m":80,"g":94},"5161":{"m":80,"g":94},"5328":{"m":80,"g":94},"5357":{"m":80,"g":94},"5342":{"m":80,"g":94},"5343":{"m":80,"g":94},"5322":{"m":80,"g":94},"5341":{"m":80,"g":94},"5337":{"m":80,"g":94},"5336":{"m":80,"g":94},"5333":{"m":80,"g":94},"5332":{"m":80,"g":94},"5331":{"m":80,"g":94},"5327":{"m":80,"g":94},"4848":{"m":80,"g":94},"5294":{"m":80,"g":94},"5321":{"m":80,"g":94},"4884":{"m":80,"g":94},"5210":{"m":80,"g":94},"5317":{"m":80,"g":94},"5316":{"m":80,"g":94},"5315":{"m":80,"g":94},"5120":{"m":80,"g":94},"5299":{"m":80,"g":94},"5311":{"m":80,"g":94},"5142":{"m":80,"g":94},"5271":{"m":80,"g":94},"5065":{"m":80,"g":94},"5310":{"m":80,"g":94},"5308":{"m":80,"g":94},"5307":{"m":80,"g":94},"5306":{"m":80,"g":94},"5304":{"m":80,"g":94},"5303":{"m":80,"g":94},"5302":{"m":80,"g":94},"5298":{"m":80,"g":94},"5301":{"m":80,"g":94},"5300":{"m":80,"g":94},"5290":{"m":80,"g":94},"5292":{"m":80,"g":94},"5289":{"m":80,"g":94},"5288":{"m":80,"g":94},"5287":{"m":80,"g":94},"5286":{"m":80,"g":94},"5280":{"m":80,"g":94},"5193":{"m":80,"g":94},"5244":{"m":80,"g":94},"5265":{"m":80,"g":94},"5254":{"m":80,"g":94},"5262":{"m":80,"g":94},"5127":{"m":80,"g":94},"5228":{"m":80,"g":94},"5259":{"m":80,"g":94},"5245":{"m":80,"g":94},"5216":{"m":80,"g":94},"5167":{"m":80,"g":94},"5213":{"m":80,"g":94},"5215":{"m":80,"g":94},"5204":{"m":80,"g":94},"4880":{"m":80,"g":94},"5086":{"m":80,"g":94},"5190":{"m":80,"g":94},"4444":{"m":80,"g":94},"5209":{"m":80,"g":94},"5196":{"m":80,"g":94},"5207":{"m":80,"g":94},"5171":{"m":80,"g":94},"5144":{"m":80,"g":94},"5102":{"m":80,"g":94},"5194":{"m":80,"g":94},"5128":{"m":80,"g":94},"5185":{"m":80,"g":94},"5189":{"m":80,"g":94},"4058":{"m":80,"g":94},"5179":{"m":80,"g":94},"5180":{"m":80,"g":94},"5176":{"m":80,"g":94},"5110":{"m":80,"g":94},"5068":{"m":80,"g":94},"5173":{"m":80,"g":94},"5175":{"m":80,"g":94},"5174":{"m":80,"g":94},"3972":{"m":80,"g":94},"5159":{"m":80,"g":94},"4938":{"m":80,"g":94},"5139":{"m":80,"g":94},"4911":{"m":80,"g":94},"5150":{"m":80,"g":94},"5155":{"m":80,"g":94},"4686":{"m":80,"g":94},"5158":{"m":80,"g":94},"5151":{"m":80,"g":94},"5115":{"m":80,"g":94},"5152":{"m":80,"g":94},"4760":{"m":80,"g":94},"5103":{"m":80,"g":94},"5147":{"m":80,"g":94},"5083":{"m":80,"g":94},"5140":{"m":80,"g":94},"5145":{"m":80,"g":94},"4984":{"m":80,"g":94},"5137":{"m":80,"g":94},"5133":{"m":80,"g":94},"5090":{"m":80,"g":94},"5126":{"m":80,"g":94},"5582":{"m":81,"g":94},"5581":{"m":81,"g":94},"4947":{"m":81,"g":94},"5571":{"m":81,"g":94},"5564":{"m":81,"g":94},"5568":{"m":81,"g":94},"5432":{"m":81,"g":94},"5149":{"m":81,"g":94},"5562":{"m":81,"g":94},"5543":{"m":81,"g":94},"5561":{"m":81,"g":94},"5546":{"m":81,"g":94},"5549":{"m":81,"g":94},"5504":{"m":81,"g":94},"5475":{"m":81,"g":94},"5460":{"m":81,"g":94},"5547":{"m":81,"g":94},"5534":{"m":81,"g":94},"5545":{"m":81,"g":94},"5548":{"m":81,"g":94},"5340":{"m":81,"g":94},"5540":{"m":81,"g":94},"5544":{"m":81,"g":94},"5542":{"m":81,"g":94},"4693":{"m":81,"g":94},"5476":{"m":81,"g":94},"5497":{"m":81,"g":94},"5461":{"m":81,"g":94},"5473":{"m":81,"g":94},"5518":{"m":81,"g":94},"5440":{"m":81,"g":94},"4836":{"m":81,"g":94},"5512":{"m":81,"g":94},"5373":{"m":81,"g":94},"5426":{"m":81,"g":94},"5511":{"m":81,"g":94},"5500":{"m":81,"g":94},"5503":{"m":81,"g":94},"5496":{"m":81,"g":94},"5493":{"m":81,"g":94},"5205":{"m":81,"g":94},"5479":{"m":81,"g":94},"4887":{"m":81,"g":94},"5480":{"m":81,"g":94},"5481":{"m":81,"g":94},"5484":{"m":81,"g":94},"5489":{"m":81,"g":94},"4982":{"m":81,"g":94},"5345":{"m":81,"g":94},"5467":{"m":81,"g":94},"5463":{"m":81,"g":94},"5447":{"m":81,"g":94},"5449":{"m":81,"g":94},"5444":{"m":81,"g":94},"5611":{"m":82,"g":94},"5510":{"m":82,"g":94},"5610":{"m":82,"g":94},"5580":{"m":82,"g":94},"5604":{"m":82,"g":94},"5609":{"m":82,"g":94},"5608":{"m":82,"g":94},"5477":{"m":82,"g":94},"5589":{"m":82,"g":94},"5598":{"m":82,"g":94},"5488":{"m":82,"g":94},"5037":{"m":82,"g":94},"5021":{"m":82,"g":94},"4980":{"m":82,"g":94},"4937":{"m":82,"g":94},"4718":{"m":82,"g":94},"4590":{"m":82,"g":94},"3443":{"m":82,"g":94},"5348":{"m":82,"g":94},"5570":{"m":82,"g":94},"5318":{"m":82,"g":94},"5590":{"m":82,"g":94},"5319":{"m":82,"g":94},"5241":{"m":82,"g":94},"5188":{"m":82,"g":94},"5141":{"m":82,"g":94},"5019":{"m":82,"g":94},"5016":{"m":82,"g":94},"4859":{"m":82,"g":94},"4852":{"m":82,"g":94},"4675":{"m":82,"g":94},"4733":{"m":82,"g":94},"5378":{"m":82,"g":94},"5224":{"m":82,"g":94},"4226":{"m":82,"g":94},"5433":{"m":82,"g":94},"5588":{"m":82,"g":94},"5452":{"m":82,"g":94},"5586":{"m":82,"g":94},"5575":{"m":82,"g":94},"5417":{"m":82,"g":94},"5531":{"m":82,"g":94},"5526":{"m":82,"g":94},"5521":{"m":82,"g":94},"5559":{"m":82,"g":94},"5560":{"m":82,"g":94},"5567":{"m":82,"g":94},"5574":{"m":82,"g":94},"5795":{"m":83,"g":94},"5691":{"m":83,"g":94},"5790":{"m":83,"g":94},"5791":{"m":83,"g":94},"5769":{"m":83,"g":94},"5789":{"m":83,"g":94},"5787":{"m":83,"g":94},"5786":{"m":83,"g":94},"5785":{"m":83,"g":94},"5779":{"m":83,"g":94},"5777":{"m":83,"g":94},"5774":{"m":83,"g":94},"5776":{"m":83,"g":94},"5772":{"m":83,"g":94},"3744":{"m":83,"g":94},"4986":{"m":83,"g":94},"4971":{"m":83,"g":94},"4870":{"m":83,"g":94},"5633":{"m":83,"g":94},"5599":{"m":83,"g":94},"5565":{"m":83,"g":94},"5509":{"m":83,"g":94},"5687":{"m":83,"g":94},"5592":{"m":83,"g":94},"5607":{"m":83,"g":94},"5730":{"m":83,"g":94},"5697":{"m":83,"g":94},"5748":{"m":83,"g":94},"5682":{"m":83,"g":94},"5685":{"m":83,"g":94},"5716":{"m":83,"g":94},"5720":{"m":83,"g":94},"5722":{"m":83,"g":94},"5728":{"m":83,"g":94},"5733":{"m":83,"g":94},"5736":{"m":83,"g":94},"5756":{"m":83,"g":94},"5760":{"m":83,"g":94},"5552":{"m":83,"g":94},"5718":{"m":83,"g":94},"5719":{"m":83,"g":94},"5737":{"m":83,"g":94},"5740":{"m":83,"g":94},"5753":{"m":83,"g":94},"5754":{"m":83,"g":94},"5750":{"m":83,"g":94},"5723":{"m":83,"g":94},"5704":{"m":83,"g":94},"5738":{"m":83,"g":94},"5715":{"m":83,"g":94},"5078":{"m":83,"g":94},"4491":{"m":83,"g":94},"5706":{"m":83,"g":94},"5648":{"m":83,"g":94},"5684":{"m":83,"g":94},"5707":{"m":83,"g":94},"5349":{"m":83,"g":94},"5688":{"m":83,"g":94},"5686":{"m":83,"g":94},"5683":{"m":83,"g":94},"5667":{"m":83,"g":94},"5677":{"m":83,"g":94},"5530":{"m":83,"g":94},"5671":{"m":83,"g":94},"5670":{"m":83,"g":94},"5435":{"m":83,"g":94},"5669":{"m":83,"g":94},"5666":{"m":83,"g":94},"5281":{"m":83,"g":94},"5601":{"m":83,"g":94},"5619":{"m":83,"g":94},"5628":{"m":83,"g":94},"5649":{"m":83,"g":94},"5646":{"m":83,"g":94},"5638":{"m":83,"g":94},"5634":{"m":83,"g":94},"5272":{"m":83,"g":94},"5641":{"m":83,"g":94},"5632":{"m":83,"g":94},"5640":{"m":83,"g":94},"5624":{"m":83,"g":94},"5622":{"m":83,"g":94},"5620":{"m":83,"g":94},"5618":{"m":83,"g":94},"5615":{"m":83,"g":94},"5578":{"m":83,"g":94},"5845":{"m":84,"g":94},"5849":{"m":84,"g":94},"5854":{"m":84,"g":94},"5823":{"m":84,"g":94},"5847":{"m":84,"g":94},"5816":{"m":84,"g":94},"5798":{"m":84,"g":94},"5850":{"m":84,"g":94},"5851":{"m":84,"g":94},"5846":{"m":84,"g":94},"5726":{"m":84,"g":94},"5839":{"m":84,"g":94},"5842":{"m":84,"g":94},"5833":{"m":84,"g":94},"5838":{"m":84,"g":94},"5551":{"m":84,"g":94},"5825":{"m":84,"g":94},"5276":{"m":84,"g":94},"5482":{"m":84,"g":94},"5771":{"m":84,"g":94},"5809":{"m":84,"g":94},"5807":{"m":84,"g":94},"5690":{"m":84,"g":94},"5390":{"m":84,"g":94},"5788":{"m":84,"g":94},"5643":{"m":84,"g":94},"5796":{"m":84,"g":94},"5797":{"m":84,"g":94},"5939":{"m":85,"g":94},"5934":{"m":85,"g":94},"5881":{"m":85,"g":94},"5915":{"m":85,"g":94},"5930":{"m":85,"g":94},"5724":{"m":85,"g":94},"5783":{"m":85,"g":94},"5933":{"m":85,"g":94},"5932":{"m":85,"g":94},"5912":{"m":85,"g":94},"5909":{"m":85,"g":94},"5917":{"m":85,"g":94},"5919":{"m":85,"g":94},"5910":{"m":85,"g":94},"5905":{"m":85,"g":94},"5383":{"m":85,"g":94},"5903":{"m":85,"g":94},"5900":{"m":85,"g":94},"5899":{"m":85,"g":94},"5870":{"m":85,"g":94},"5830":{"m":85,"g":94},"5901":{"m":85,"g":94},"5898":{"m":85,"g":94},"5861":{"m":85,"g":94},"5696":{"m":85,"g":94},"5725":{"m":85,"g":94},"5893":{"m":85,"g":94},"5793":{"m":85,"g":94},"5896":{"m":85,"g":94},"5746":{"m":85,"g":94},"5895":{"m":85,"g":94},"5841":{"m":85,"g":94},"5836":{"m":85,"g":94},"5894":{"m":85,"g":94},"5880":{"m":85,"g":94},"5875":{"m":85,"g":94},"5859":{"m":85,"g":94},"4115":{"m":85,"g":94},"4949":{"m":85,"g":94},"5820":{"m":85,"g":94},"5868":{"m":85,"g":94},"5860":{"m":85,"g":94},"5801":{"m":85,"g":94},"5857":{"m":85,"g":94},"6165":{"m":86,"g":94},"5778":{"m":86,"g":94},"6162":{"m":86,"g":94},"6089":{"m":86,"g":94},"6141":{"m":86,"g":94},"5822":{"m":86,"g":94},"6101":{"m":86,"g":94},"5745":{"m":86,"g":94},"6132":{"m":86,"g":94},"6131":{"m":86,"g":94},"6112":{"m":86,"g":94},"6129":{"m":86,"g":94},"6123":{"m":86,"g":94},"6097":{"m":86,"g":94},"5662":{"m":86,"g":94},"5764":{"m":86,"g":94},"6119":{"m":86,"g":94},"5626":{"m":86,"g":94},"6091":{"m":86,"g":94},"5572":{"m":86,"g":94},"5232":{"m":86,"g":94},"5219":{"m":86,"g":94},"5121":{"m":86,"g":94},"6077":{"m":86,"g":94},"6111":{"m":86,"g":94},"6038":{"m":86,"g":94},"6079":{"m":86,"g":94},"6034":{"m":86,"g":94},"6102":{"m":86,"g":94},"6105":{"m":86,"g":94},"5993":{"m":86,"g":94},"6075":{"m":86,"g":94},"6063":{"m":86,"g":94},"5233":{"m":86,"g":94},"5014":{"m":86,"g":94},"6084":{"m":86,"g":94},"3853":{"m":86,"g":94},"6010":{"m":86,"g":94},"6039":{"m":86,"g":94},"5655":{"m":86,"g":94},"6062":{"m":86,"g":94},"6004":{"m":86,"g":94},"6045":{"m":86,"g":94},"5885":{"m":86,"g":94},"5751":{"m":86,"g":94},"6057":{"m":86,"g":94},"6048":{"m":86,"g":94},"6047":{"m":86,"g":94},"6046":{"m":86,"g":94},"5081":{"m":86,"g":94},"5752":{"m":86,"g":94},"5996":{"m":86,"g":94},"5428":{"m":86,"g":94},"5555":{"m":86,"g":94},"5587":{"m":86,"g":94},"5781":{"m":86,"g":94},"6018":{"m":86,"g":94},"6002":{"m":86,"g":94},"5997":{"m":86,"g":94},"5679":{"m":86,"g":94},"5957":{"m":86,"g":94},"6012":{"m":86,"g":94},"5992":{"m":86,"g":94},"5998":{"m":86,"g":94},"5991":{"m":86,"g":94},"5986":{"m":86,"g":94},"5977":{"m":86,"g":94},"5975":{"m":86,"g":94},"5681":{"m":86,"g":94},"5969":{"m":86,"g":94},"5968":{"m":86,"g":94},"5350":{"m":86,"g":94},"5967":{"m":86,"g":94},"5908":{"m":86,"g":94},"5960":{"m":86,"g":94},"5782":{"m":86,"g":94},"5956":{"m":86,"g":94},"5945":{"m":86,"g":94},"5944":{"m":86,"g":94},"5952":{"m":86,"g":94},"5953":{"m":86,"g":94},"5834":{"m":86,"g":94},"5921":{"m":86,"g":94},"6245":{"m":87,"g":94},"6259":{"m":87,"g":94},"6252":{"m":87,"g":94},"5084":{"m":87,"g":94},"5657":{"m":87,"g":94},"6247":{"m":87,"g":94},"6235":{"m":87,"g":94},"6251":{"m":87,"g":94},"6042":{"m":87,"g":94},"6248":{"m":87,"g":94},"6225":{"m":87,"g":94},"5922":{"m":87,"g":94},"6241":{"m":87,"g":94},"6243":{"m":87,"g":94},"6244":{"m":87,"g":94},"6223":{"m":87,"g":94},"6206":{"m":87,"g":94},"6209":{"m":87,"g":94},"6231":{"m":87,"g":94},"6212":{"m":87,"g":94},"6201":{"m":87,"g":94},"6213":{"m":87,"g":94},"5558":{"m":87,"g":94},"6154":{"m":87,"g":94},"6043":{"m":87,"g":94},"6204":{"m":87,"g":94},"6202":{"m":87,"g":94},"6178":{"m":87,"g":94},"6198":{"m":87,"g":94},"6192":{"m":87,"g":94},"6188":{"m":87,"g":94},"6032":{"m":87,"g":94},"6199":{"m":87,"g":94},"5621":{"m":87,"g":94},"6196":{"m":87,"g":94},"6195":{"m":87,"g":94},"6073":{"m":87,"g":94},"6169":{"m":87,"g":94},"6191":{"m":87,"g":94},"6190":{"m":87,"g":94},"6186":{"m":87,"g":94},"5654":{"m":87,"g":94},"6180":{"m":87,"g":94},"6179":{"m":87,"g":94},"6184":{"m":87,"g":94},"6183":{"m":87,"g":94},"4701":{"m":87,"g":94},"6181":{"m":87,"g":94},"6146":{"m":87,"g":94},"6114":{"m":87,"g":94},"6118":{"m":87,"g":94},"6016":{"m":87,"g":94},"6566":{"m":88,"g":94},"6567":{"m":88,"g":94},"6485":{"m":88,"g":94},"6560":{"m":88,"g":94},"6550":{"m":88,"g":94},"6533":{"m":88,"g":94},"6562":{"m":88,"g":94},"6524":{"m":88,"g":94},"6347":{"m":88,"g":94},"6558":{"m":88,"g":94},"6521":{"m":88,"g":94},"6507":{"m":88,"g":94},"6474":{"m":88,"g":94},"6452":{"m":88,"g":94},"6404":{"m":88,"g":94},"6493":{"m":88,"g":94},"6355":{"m":88,"g":94},"6535":{"m":88,"g":94},"6536":{"m":88,"g":94},"6059":{"m":88,"g":94},"6532":{"m":88,"g":94},"6120":{"m":88,"g":94},"6522":{"m":88,"g":94},"6520":{"m":88,"g":94},"6469":{"m":88,"g":94},"6482":{"m":88,"g":94},"6308":{"m":88,"g":94},"6388":{"m":88,"g":94},"6492":{"m":88,"g":94},"6504":{"m":88,"g":94},"6019":{"m":88,"g":94},"6457":{"m":88,"g":94},"6499":{"m":88,"g":94},"6510":{"m":88,"g":94},"6508":{"m":88,"g":94},"5759":{"m":88,"g":94},"6419":{"m":88,"g":94},"6275":{"m":88,"g":94},"6503":{"m":88,"g":94},"5573":{"m":88,"g":94},"6445":{"m":88,"g":94},"6461":{"m":88,"g":94},"6467":{"m":88,"g":94},"6468":{"m":88,"g":94},"6476":{"m":88,"g":94},"6311":{"m":88,"g":94},"6487":{"m":88,"g":94},"5339":{"m":88,"g":94},"6381":{"m":88,"g":94},"6214":{"m":88,"g":94},"6475":{"m":88,"g":94},"6472":{"m":88,"g":94},"6447":{"m":88,"g":94},"6385":{"m":88,"g":94},"6444":{"m":88,"g":94},"6405":{"m":88,"g":94},"6429":{"m":88,"g":94},"6412":{"m":88,"g":94},"6387":{"m":88,"g":94},"6386":{"m":88,"g":94},"6326":{"m":88,"g":94},"6438":{"m":88,"g":94},"6321":{"m":88,"g":94},"4957":{"m":88,"g":94},"6440":{"m":88,"g":94},"6431":{"m":88,"g":94},"6098":{"m":88,"g":94},"6414":{"m":88,"g":94},"6430":{"m":88,"g":94},"6417":{"m":88,"g":94},"6137":{"m":88,"g":94},"6401":{"m":88,"g":94},"6400":{"m":88,"g":94},"5974":{"m":88,"g":94},"6325":{"m":88,"g":94},"6323":{"m":88,"g":94},"6333":{"m":88,"g":94},"6397":{"m":88,"g":94},"6396":{"m":88,"g":94},"6395":{"m":88,"g":94},"6339":{"m":88,"g":94},"6383":{"m":88,"g":94},"6392":{"m":88,"g":94},"6331":{"m":88,"g":94},"6391":{"m":88,"g":94},"6365":{"m":88,"g":94},"6250":{"m":88,"g":94},"6187":{"m":88,"g":94},"6379":{"m":88,"g":94},"6377":{"m":88,"g":94},"6362":{"m":88,"g":94},"6364":{"m":88,"g":94},"6330":{"m":88,"g":94},"6290":{"m":88,"g":94},"6041":{"m":88,"g":94},"6284":{"m":88,"g":94},"6257":{"m":88,"g":94},"6108":{"m":88,"g":94},"6134":{"m":88,"g":94},"6107":{"m":88,"g":94},"4741":{"m":88,"g":94},"6348":{"m":88,"g":94},"6211":{"m":88,"g":94},"6175":{"m":88,"g":94},"6366":{"m":88,"g":94},"6373":{"m":88,"g":94},"6356":{"m":88,"g":94},"6368":{"m":88,"g":94},"6324":{"m":88,"g":94},"6316":{"m":88,"g":94},"5099":{"m":88,"g":94},"6361":{"m":88,"g":94},"6360":{"m":88,"g":94},"6358":{"m":88,"g":94},"6359":{"m":88,"g":94},"6121":{"m":88,"g":94},"5694":{"m":88,"g":94},"6334":{"m":88,"g":94},"6136":{"m":88,"g":94},"6336":{"m":88,"g":94},"6327":{"m":88,"g":94},"6302":{"m":88,"g":94},"6147":{"m":88,"g":94},"6317":{"m":88,"g":94},"6216":{"m":88,"g":94},"6298":{"m":88,"g":94},"6109":{"m":88,"g":94},"5914":{"m":88,"g":94},"6009":{"m":88,"g":94},"6274":{"m":88,"g":94},"6283":{"m":88,"g":94},"6300":{"m":88,"g":94},"6138":{"m":88,"g":94},"6282":{"m":88,"g":94},"6276":{"m":88,"g":94},"6273":{"m":88,"g":94},"6115":{"m":88,"g":94},"7038":{"m":89,"g":94},"6833":{"m":89,"g":94},"7029":{"m":89,"g":94},"7027":{"m":89,"g":94},"6980":{"m":89,"g":94},"6964":{"m":89,"g":94},"7023":{"m":89,"g":94},"7018":{"m":89,"g":94},"7017":{"m":89,"g":94},"6741":{"m":89,"g":94},"6987":{"m":89,"g":94},"7015":{"m":89,"g":94},"7013":{"m":89,"g":94},"6884":{"m":89,"g":94},"6992":{"m":89,"g":94},"6998":{"m":89,"g":94},"7008":{"m":89,"g":94},"7007":{"m":89,"g":94},"6958":{"m":89,"g":94},"6557":{"m":89,"g":94},"6990":{"m":89,"g":94},"6960":{"m":89,"g":94},"6973":{"m":89,"g":94},"6983":{"m":89,"g":94},"6929":{"m":89,"g":94},"6977":{"m":89,"g":94},"6967":{"m":89,"g":94},"6981":{"m":89,"g":94},"6979":{"m":89,"g":94},"6976":{"m":89,"g":94},"6970":{"m":89,"g":94},"6937":{"m":89,"g":94},"6965":{"m":89,"g":94},"6974":{"m":89,"g":94},"6966":{"m":89,"g":94},"6956":{"m":89,"g":94},"6963":{"m":89,"g":94},"6926":{"m":89,"g":94},"6968":{"m":89,"g":94},"6853":{"m":89,"g":94},"6957":{"m":89,"g":94},"6955":{"m":89,"g":94},"6916":{"m":89,"g":94},"6885":{"m":89,"g":94},"6950":{"m":89,"g":94},"6953":{"m":89,"g":94},"6220":{"m":89,"g":94},"6866":{"m":89,"g":94},"6895":{"m":89,"g":94},"6874":{"m":89,"g":94},"6915":{"m":89,"g":94},"6924":{"m":89,"g":94},"6945":{"m":89,"g":94},"6369":{"m":89,"g":94},"5955":{"m":89,"g":94},"6912":{"m":89,"g":94},"6910":{"m":89,"g":94},"6944":{"m":89,"g":94},"6943":{"m":89,"g":94},"6942":{"m":89,"g":94},"6939":{"m":89,"g":94},"6767":{"m":89,"g":94},"6879":{"m":89,"g":94},"6922":{"m":89,"g":94},"6932":{"m":89,"g":94},"6934":{"m":89,"g":94},"6931":{"m":89,"g":94},"6930":{"m":89,"g":94},"6838":{"m":89,"g":94},"6458":{"m":89,"g":94},"6877":{"m":89,"g":94},"6887":{"m":89,"g":94},"6890":{"m":89,"g":94},"6764":{"m":89,"g":94},"6170":{"m":89,"g":94},"6837":{"m":89,"g":94},"6868":{"m":89,"g":94},"6865":{"m":89,"g":94},"6851":{"m":89,"g":94},"6846":{"m":89,"g":94},"6820":{"m":89,"g":94},"6277":{"m":89,"g":94},"6861":{"m":89,"g":94},"6878":{"m":89,"g":94},"6736":{"m":89,"g":94},"6852":{"m":89,"g":94},"6460":{"m":89,"g":94},"6659":{"m":89,"g":94},"6858":{"m":89,"g":94},"6745":{"m":89,"g":94},"5929":{"m":89,"g":94},"6735":{"m":89,"g":94},"6816":{"m":89,"g":94},"6818":{"m":89,"g":94},"6671":{"m":89,"g":94},"6456":{"m":89,"g":94},"6766":{"m":89,"g":94},"6093":{"m":89,"g":94},"6812":{"m":89,"g":94},"6811":{"m":89,"g":94},"6815":{"m":89,"g":94},"6813":{"m":89,"g":94},"6780":{"m":89,"g":94},"5382":{"m":89,"g":94},"6805":{"m":89,"g":94},"6699":{"m":89,"g":94},"6803":{"m":89,"g":94},"6804":{"m":89,"g":94},"6799":{"m":89,"g":94},"6800":{"m":89,"g":94},"5981":{"m":89,"g":94},"6421":{"m":89,"g":94},"6797":{"m":89,"g":94},"6795":{"m":89,"g":94},"6787":{"m":89,"g":94},"6794":{"m":89,"g":94},"6788":{"m":89,"g":94},"6791":{"m":89,"g":94},"6792":{"m":89,"g":94},"6734":{"m":89,"g":94},"6408":{"m":89,"g":94},"6786":{"m":89,"g":94},"6785":{"m":89,"g":94},"6782":{"m":89,"g":94},"6784":{"m":89,"g":94},"6679":{"m":89,"g":94},"6772":{"m":89,"g":94},"6289":{"m":89,"g":94},"6509":{"m":89,"g":94},"6737":{"m":89,"g":94},"6761":{"m":89,"g":94},"6765":{"m":89,"g":94},"6727":{"m":89,"g":94},"6265":{"m":89,"g":94},"6748":{"m":89,"g":94},"6746":{"m":89,"g":94},"6742":{"m":89,"g":94},"6728":{"m":89,"g":94},"6680":{"m":89,"g":94},"6437":{"m":89,"g":94},"6729":{"m":89,"g":94},"6545":{"m":89,"g":94},"6705":{"m":89,"g":94},"6715":{"m":89,"g":94},"6725":{"m":89,"g":94},"6718":{"m":89,"g":94},"6720":{"m":89,"g":94},"6726":{"m":89,"g":94},"6676":{"m":89,"g":94},"6709":{"m":89,"g":94},"6719":{"m":89,"g":94},"6479":{"m":89,"g":94},"6668":{"m":89,"g":94},"6682":{"m":89,"g":94},"6711":{"m":89,"g":94},"6710":{"m":89,"g":94},"6712":{"m":89,"g":94},"6706":{"m":89,"g":94},"6703":{"m":89,"g":94},"6697":{"m":89,"g":94},"6649":{"m":89,"g":94},"6685":{"m":89,"g":94},"6689":{"m":89,"g":94},"6693":{"m":89,"g":94},"6655":{"m":89,"g":94},"6260":{"m":89,"g":94},"6627":{"m":89,"g":94},"6687":{"m":89,"g":94},"6582":{"m":89,"g":94},"6672":{"m":89,"g":94},"6678":{"m":89,"g":94},"6380":{"m":89,"g":94},"6665":{"m":89,"g":94},"6673":{"m":89,"g":94},"6007":{"m":89,"g":94},"6473":{"m":89,"g":94},"6677":{"m":89,"g":94},"6661":{"m":89,"g":94},"6660":{"m":89,"g":94},"6638":{"m":89,"g":94},"6606":{"m":89,"g":94},"6662":{"m":89,"g":94},"6652":{"m":89,"g":94},"6658":{"m":89,"g":94},"6403":{"m":89,"g":94},"6601":{"m":89,"g":94},"6640":{"m":89,"g":94},"6450":{"m":89,"g":94},"6650":{"m":89,"g":94},"6585":{"m":89,"g":94},"6648":{"m":89,"g":94},"6634":{"m":89,"g":94},"6646":{"m":89,"g":94},"6643":{"m":89,"g":94},"6547":{"m":89,"g":94},"6631":{"m":89,"g":94},"6603":{"m":89,"g":94},"6263":{"m":89,"g":94},"6639":{"m":89,"g":94},"6635":{"m":89,"g":94},"6620":{"m":89,"g":94},"6629":{"m":89,"g":94},"6628":{"m":89,"g":94},"6617":{"m":89,"g":94},"6306":{"m":89,"g":94},"6599":{"m":89,"g":94},"6611":{"m":89,"g":94},"6598":{"m":89,"g":94},"6597":{"m":89,"g":94},"6581":{"m":89,"g":94},"6610":{"m":89,"g":94},"6575":{"m":89,"g":94},"6609":{"m":89,"g":94},"6594":{"m":89,"g":94},"6587":{"m":89,"g":94},"6596":{"m":89,"g":94},"6595":{"m":89,"g":94},"6593":{"m":89,"g":94},"6586":{"m":89,"g":94},"6571":{"m":89,"g":94},"6439":{"m":89,"g":94},"6527":{"m":89,"g":94},"6588":{"m":89,"g":94},"6570":{"m":89,"g":94},"6546":{"m":89,"g":94},"6537":{"m":89,"g":94},"6494":{"m":89,"g":94},"5961":{"m":89,"g":94},"6543":{"m":89,"g":94},"4068":{"m":89,"g":94},"6577":{"m":89,"g":94},"6578":{"m":89,"g":94},"6477":{"m":89,"g":94},"6564":{"m":89,"g":94},"6576":{"m":89,"g":94},"7248":{"m":90,"g":94},"7244":{"m":90,"g":94},"7247":{"m":90,"g":94},"6058":{"m":90,"g":94},"7234":{"m":90,"g":94},"7245":{"m":90,"g":94},"7231":{"m":90,"g":94},"7239":{"m":90,"g":94},"7232":{"m":90,"g":94},"7207":{"m":90,"g":94},"7213":{"m":90,"g":94},"7228":{"m":90,"g":94},"7221":{"m":90,"g":94},"7218":{"m":90,"g":94},"6378":{"m":90,"g":94},"7217":{"m":90,"g":94},"7215":{"m":90,"g":94},"7214":{"m":90,"g":94},"7210":{"m":90,"g":94},"7163":{"m":90,"g":94},"7205":{"m":90,"g":94},"7204":{"m":90,"g":94},"7202":{"m":90,"g":94},"7200":{"m":90,"g":94},"7196":{"m":90,"g":94},"7198":{"m":90,"g":94},"7195":{"m":90,"g":94},"7186":{"m":90,"g":94},"7180":{"m":90,"g":94},"7189":{"m":90,"g":94},"7191":{"m":90,"g":94},"7190":{"m":90,"g":94},"7184":{"m":90,"g":94},"7181":{"m":90,"g":94},"7177":{"m":90,"g":94},"7178":{"m":90,"g":94},"7175":{"m":90,"g":94},"7172":{"m":90,"g":94},"7173":{"m":90,"g":94},"7161":{"m":90,"g":94},"7150":{"m":90,"g":94},"7153":{"m":90,"g":94},"7170":{"m":90,"g":94},"7165":{"m":90,"g":94},"7156":{"m":90,"g":94},"7020":{"m":90,"g":94},"7157":{"m":90,"g":94},"6814":{"m":90,"g":94},"7154":{"m":90,"g":94},"7155":{"m":90,"g":94},"7152":{"m":90,"g":94},"7146":{"m":90,"g":94},"7145":{"m":90,"g":94},"7056":{"m":90,"g":94},"7058":{"m":90,"g":94},"7140":{"m":90,"g":94},"7134":{"m":90,"g":94},"6026":{"m":90,"g":94},"7092":{"m":90,"g":94},"7126":{"m":90,"g":94},"7119":{"m":90,"g":94},"7115":{"m":90,"g":94},"6919":{"m":90,"g":94},"7093":{"m":90,"g":94},"6994":{"m":90,"g":94},"6824":{"m":90,"g":94},"7079":{"m":90,"g":94},"6106":{"m":90,"g":94},"7091":{"m":90,"g":94},"7097":{"m":90,"g":94},"6870":{"m":90,"g":94},"7067":{"m":90,"g":94},"7076":{"m":90,"g":94},"7046":{"m":90,"g":94},"7054":{"m":90,"g":94},"7073":{"m":90,"g":94},"6031":{"m":90,"g":94},"7071":{"m":90,"g":94},"6579":{"m":90,"g":94},"7066":{"m":90,"g":94},"6716":{"m":90,"g":94},"7064":{"m":90,"g":94},"7049":{"m":90,"g":94},"7063":{"m":90,"g":94},"6947":{"m":90,"g":94},"7057":{"m":90,"g":94},"7061":{"m":90,"g":94},"7060":{"m":90,"g":94},"7021":{"m":90,"g":94},"7053":{"m":90,"g":94},"7037":{"m":90,"g":94},"7051":{"m":90,"g":94},"6999":{"m":90,"g":94},"7045":{"m":90,"g":94},"7043":{"m":90,"g":94},"7040":{"m":90,"g":94},"7493":{"m":91,"g":94},"7490":{"m":91,"g":94},"7376":{"m":91,"g":94},"7487":{"m":91,"g":94},"7347":{"m":91,"g":94},"7269":{"m":91,"g":94},"7449":{"m":91,"g":94},"7469":{"m":91,"g":94},"7378":{"m":91,"g":94},"7481":{"m":91,"g":94},"7382":{"m":91,"g":94},"7480":{"m":91,"g":94},"7456":{"m":91,"g":94},"7479":{"m":91,"g":94},"7397":{"m":91,"g":94},"7472":{"m":91,"g":94},"7457":{"m":91,"g":94},"7290":{"m":91,"g":94},"6821":{"m":91,"g":94},"7454":{"m":91,"g":94},"7451":{"m":91,"g":94},"7445":{"m":91,"g":94},"7361":{"m":91,"g":94},"7391":{"m":91,"g":94},"7441":{"m":91,"g":94},"7327":{"m":91,"g":94},"7406":{"m":91,"g":94},"7414":{"m":91,"g":94},"7408":{"m":91,"g":94},"7412":{"m":91,"g":94},"7351":{"m":91,"g":94},"7420":{"m":91,"g":94},"7409":{"m":91,"g":94},"7425":{"m":91,"g":94},"6984":{"m":91,"g":94},"7394":{"m":91,"g":94},"7396":{"m":91,"g":94},"7400":{"m":91,"g":94},"7329":{"m":91,"g":94},"7401":{"m":91,"g":94},"7403":{"m":91,"g":94},"7402":{"m":91,"g":94},"7285":{"m":91,"g":94},"7219":{"m":91,"g":94},"7360":{"m":91,"g":94},"7399":{"m":91,"g":94},"7398":{"m":91,"g":94},"6389":{"m":91,"g":94},"7372":{"m":91,"g":94},"5485":{"m":91,"g":94},"7393":{"m":91,"g":94},"7356":{"m":91,"g":94},"7326":{"m":91,"g":94},"7322":{"m":91,"g":94},"7371":{"m":91,"g":94},"7364":{"m":91,"g":94},"7159":{"m":91,"g":94},"7370":{"m":91,"g":94},"7343":{"m":91,"g":94},"7366":{"m":91,"g":94},"7362":{"m":91,"g":94},"7242":{"m":91,"g":94},"7363":{"m":91,"g":94},"7303":{"m":91,"g":94},"7354":{"m":91,"g":94},"7099":{"m":91,"g":94},"7333":{"m":91,"g":94},"7331":{"m":91,"g":94},"7284":{"m":91,"g":94},"7096":{"m":91,"g":94},"7319":{"m":91,"g":94},"7003":{"m":91,"g":94},"7301":{"m":91,"g":94},"7297":{"m":91,"g":94},"7251":{"m":91,"g":94},"7300":{"m":91,"g":94},"6614":{"m":91,"g":94},"7267":{"m":91,"g":94},"7264":{"m":91,"g":94},"7237":{"m":91,"g":94},"7289":{"m":91,"g":94},"7288":{"m":91,"g":94},"7286":{"m":91,"g":94},"6842":{"m":91,"g":94},"7283":{"m":91,"g":94},"7164":{"m":91,"g":94},"7022":{"m":91,"g":94},"6081":{"m":91,"g":94},"7265":{"m":91,"g":94},"7160":{"m":91,"g":94},"7179":{"m":91,"g":94},"7167":{"m":91,"g":94},"7252":{"m":91,"g":94},"7122":{"m":91,"g":94},"7233":{"m":91,"g":94},"7125":{"m":91,"g":94},"7559":{"m":92,"g":94},"7541":{"m":92,"g":94},"7542":{"m":92,"g":94},"7544":{"m":92,"g":94},"7549":{"m":92,"g":94},"7543":{"m":92,"g":94},"7527":{"m":92,"g":94},"7531":{"m":92,"g":94},"7148":{"m":92,"g":94},"7499":{"m":92,"g":94},"7507":{"m":92,"g":94},"7513":{"m":92,"g":94},"7521":{"m":92,"g":94},"7520":{"m":92,"g":94},"6793":{"m":92,"g":94},"6721":{"m":92,"g":94},"7386":{"m":92,"g":94},"7522":{"m":92,"g":94},"6641":{"m":92,"g":94},"6626":{"m":92,"g":94},"7498":{"m":92,"g":94},"7512":{"m":92,"g":94},"7510":{"m":92,"g":94},"7516":{"m":92,"g":94},"7508":{"m":92,"g":94},"7437":{"m":92,"g":94},"7489":{"m":92,"g":94},"7505":{"m":92,"g":94},"6717":{"m":92,"g":94},"7277":{"m":92,"g":94},"7422":{"m":92,"g":94},"7439":{"m":92,"g":94},"7236":{"m":92,"g":94},"7423":{"m":92,"g":94},"7268":{"m":92,"g":94},"7802":{"m":93,"g":94},"7801":{"m":93,"g":94},"7799":{"m":93,"g":94},"7792":{"m":93,"g":94},"7800":{"m":93,"g":94},"7756":{"m":93,"g":94},"7790":{"m":93,"g":94},"7757":{"m":93,"g":94},"7786":{"m":93,"g":94},"7222":{"m":93,"g":94},"7787":{"m":93,"g":94},"7784":{"m":93,"g":94},"7444":{"m":93,"g":94},"7623":{"m":93,"g":94},"7782":{"m":93,"g":94},"7596":{"m":93,"g":94},"7772":{"m":93,"g":94},"7705":{"m":93,"g":94},"7745":{"m":93,"g":94},"7778":{"m":93,"g":94},"7419":{"m":93,"g":94},"7418":{"m":93,"g":94},"7748":{"m":93,"g":94},"7764":{"m":93,"g":94},"7741":{"m":93,"g":94},"7729":{"m":93,"g":94},"7390":{"m":93,"g":94},"7759":{"m":93,"g":94},"7751":{"m":93,"g":94},"7754":{"m":93,"g":94},"7755":{"m":93,"g":94},"7744":{"m":93,"g":94},"7752":{"m":93,"g":94},"7723":{"m":93,"g":94},"7673":{"m":93,"g":94},"7740":{"m":93,"g":94},"7681":{"m":93,"g":94},"6771":{"m":93,"g":94},"7647":{"m":93,"g":94},"7750":{"m":93,"g":94},"7722":{"m":93,"g":94},"7738":{"m":93,"g":94},"7278":{"m":93,"g":94},"7731":{"m":93,"g":94},"7735":{"m":93,"g":94},"6770":{"m":93,"g":94},"7734":{"m":93,"g":94},"7714":{"m":93,"g":94},"6698":{"m":93,"g":94},"7462":{"m":93,"g":94},"6549":{"m":93,"g":94},"7621":{"m":93,"g":94},"6512":{"m":93,"g":94},"7292":{"m":93,"g":94},"7416":{"m":93,"g":94},"7717":{"m":93,"g":94},"7677":{"m":93,"g":94},"7683":{"m":93,"g":94},"7697":{"m":93,"g":94},"7635":{"m":93,"g":94},"7642":{"m":93,"g":94},"7698":{"m":93,"g":94},"7684":{"m":93,"g":94},"7688":{"m":93,"g":94},"7676":{"m":93,"g":94},"7629":{"m":93,"g":94},"6985":{"m":93,"g":94},"7675":{"m":93,"g":94},"7486":{"m":93,"g":94},"7671":{"m":93,"g":94},"7648":{"m":93,"g":94},"7318":{"m":93,"g":94},"7663":{"m":93,"g":94},"7627":{"m":93,"g":94},"7632":{"m":93,"g":94},"7524":{"m":93,"g":94},"7643":{"m":93,"g":94},"7640":{"m":93,"g":94},"7539":{"m":93,"g":94},"7176":{"m":93,"g":94},"7580":{"m":93,"g":94},"7628":{"m":93,"g":94},"7619":{"m":93,"g":94},"7432":{"m":93,"g":94},"7636":{"m":93,"g":94},"7630":{"m":93,"g":94},"7624":{"m":93,"g":94},"7625":{"m":93,"g":94},"7036":{"m":93,"g":94},"7620":{"m":93,"g":94},"7310":{"m":93,"g":94},"7309":{"m":93,"g":94},"7618":{"m":93,"g":94},"7598":{"m":93,"g":94},"7446":{"m":93,"g":94},"7584":{"m":93,"g":94},"7552":{"m":93,"g":94},"7308":{"m":93,"g":94},"6769":{"m":93,"g":94},"6563":{"m":93,"g":94},"7612":{"m":93,"g":94},"7588":{"m":93,"g":94},"7610":{"m":93,"g":94},"7581":{"m":93,"g":94},"7225":{"m":93,"g":94},"7577":{"m":93,"g":94},"7540":{"m":93,"g":94},"7208":{"m":93,"g":94},"7569":{"m":93,"g":94},"7573":{"m":93,"g":94},"7575":{"m":93,"g":94},"7330":{"m":93,"g":94},"7882":{"m":95,"g":97},"7880":{"m":95,"g":97},"7660":{"m":95,"g":97},"7846":{"m":95,"g":97},"7818":{"m":95,"g":97},"7866":{"m":95,"g":97},"7724":{"m":95,"g":97},"7830":{"m":95,"g":97},"7579":{"m":95,"g":97},"7840":{"m":95,"g":97},"7864":{"m":95,"g":97},"7860":{"m":95,"g":97},"7832":{"m":95,"g":97},"7853":{"m":95,"g":97},"7850":{"m":95,"g":97},"7129":{"m":95,"g":97},"7762":{"m":95,"g":97},"7821":{"m":95,"g":97},"7187":{"m":95,"g":97},"7816":{"m":95,"g":97},"7798":{"m":95,"g":94},"7797":{"m":95,"g":94},"7313":{"m":95,"g":94},"7689":{"m":95,"g":94},"7813":{"m":95,"g":94},"6094":{"m":95,"g":94},"7794":{"m":95,"g":94},"7812":{"m":95,"g":94},"7733":{"m":95,"g":94},"5246":{"m":95,"g":94},"7785":{"m":95,"g":94},"7709":{"m":95,"g":94},"7793":{"m":95,"g":94},"7803":{"m":95,"g":94},"7796":{"m":95,"g":94},"7963":{"m":96,"g":97},"7971":{"m":96,"g":97},"7960":{"m":96,"g":97},"7969":{"m":96,"g":97},"7970":{"m":96,"g":97},"7962":{"m":96,"g":97},"7968":{"m":96,"g":97},"7964":{"m":96,"g":97},"7932":{"m":96,"g":97},"7961":{"m":96,"g":97},"7953":{"m":96,"g":97},"7795":{"m":96,"g":97},"7940":{"m":96,"g":97},"7775":{"m":96,"g":97},"7791":{"m":96,"g":97},"6449":{"m":96,"g":97},"7922":{"m":96,"g":97},"7907":{"m":96,"g":97},"5888":{"m":96,"g":97},"7904":{"m":96,"g":97},"7608":{"m":96,"g":97},"7899":{"m":96,"g":97},"7898":{"m":96,"g":97},"7838":{"m":96,"g":97},"7885":{"m":96,"g":97},"7872":{"m":96,"g":97},"7895":{"m":96,"g":97},"8265":{"m":98,"g":103},"8260":{"m":98,"g":103},"7822":{"m":98,"g":103},"8059":{"m":98,"g":103},"8257":{"m":98,"g":103},"7484":{"m":98,"g":103},"8221":{"m":98,"g":103},"8237":{"m":98,"g":103},"8231":{"m":98,"g":103},"8202":{"m":98,"g":103},"8204":{"m":98,"g":103},"8209":{"m":98,"g":97},"8208":{"m":98,"g":97},"8107":{"m":98,"g":97},"8193":{"m":98,"g":97},"8200":{"m":98,"g":97},"8195":{"m":98,"g":97},"7935":{"m":98,"g":97},"8184":{"m":98,"g":97},"8197":{"m":98,"g":97},"8067":{"m":98,"g":97},"8163":{"m":98,"g":97},"8183":{"m":98,"g":97},"7983":{"m":98,"g":97},"8182":{"m":98,"g":97},"8181":{"m":98,"g":97},"7825":{"m":98,"g":97},"8178":{"m":98,"g":97},"8176":{"m":98,"g":97},"7312":{"m":98,"g":97},"6230":{"m":98,"g":97},"7999":{"m":98,"g":97},"8115":{"m":98,"g":97},"8175":{"m":98,"g":97},"8172":{"m":98,"g":97},"8019":{"m":98,"g":97},"8167":{"m":98,"g":97},"8170":{"m":98,"g":97},"8169":{"m":98,"g":97},"8103":{"m":98,"g":97},"8161":{"m":98,"g":97},"8171":{"m":98,"g":97},"8168":{"m":98,"g":97},"8166":{"m":98,"g":97},"8165":{"m":98,"g":97},"7966":{"m":98,"g":97},"8157":{"m":98,"g":97},"8160":{"m":98,"g":97},"8158":{"m":98,"g":97},"8028":{"m":98,"g":97},"7931":{"m":98,"g":97},"8048":{"m":98,"g":97},"7302":{"m":98,"g":97},"6881":{"m":98,"g":97},"8155":{"m":98,"g":97},"7661":{"m":98,"g":97},"7987":{"m":98,"g":97},"8113":{"m":98,"g":97},"8147":{"m":98,"g":97},"8142":{"m":98,"g":97},"8136":{"m":98,"g":97},"8141":{"m":98,"g":97},"7704":{"m":98,"g":97},"7820":{"m":98,"g":97},"7889":{"m":98,"g":97},"7506":{"m":98,"g":97},"7959":{"m":98,"g":97},"8127":{"m":98,"g":97},"7924":{"m":98,"g":97},"7030":{"m":98,"g":97},"8117":{"m":98,"g":97},"8102":{"m":98,"g":97},"8046":{"m":98,"g":97},"7884":{"m":98,"g":97},"7989":{"m":98,"g":97},"8105":{"m":98,"g":97},"8110":{"m":98,"g":97},"8108":{"m":98,"g":97},"8100":{"m":98,"g":97},"7597":{"m":98,"g":97},"8075":{"m":98,"g":97},"7992":{"m":98,"g":97},"7634":{"m":98,"g":97},"8098":{"m":98,"g":97},"8090":{"m":98,"g":97},"8086":{"m":98,"g":97},"8077":{"m":98,"g":97},"8001":{"m":98,"g":97},"7760":{"m":98,"g":97},"8029":{"m":98,"g":97},"8058":{"m":98,"g":97},"5163":{"m":98,"g":97},"8045":{"m":98,"g":97},"8047":{"m":98,"g":97},"7943":{"m":98,"g":97},"8052":{"m":98,"g":97},"6556":{"m":98,"g":97},"8022":{"m":98,"g":97},"8002":{"m":98,"g":97},"8023":{"m":98,"g":97},"8044":{"m":98,"g":97},"7887":{"m":98,"g":97},"8035":{"m":98,"g":97},"7897":{"m":98,"g":97},"7982":{"m":98,"g":97},"8006":{"m":98,"g":97},"7649":{"m":98,"g":97},"7653":{"m":98,"g":97},"8005":{"m":98,"g":97},"7874":{"m":98,"g":97},"8021":{"m":98,"g":97},"8010":{"m":98,"g":97},"7902":{"m":98,"g":97},"7862":{"m":98,"g":97},"7844":{"m":98,"g":97},"7997":{"m":98,"g":97},"7367":{"m":98,"g":97},"7749":{"m":98,"g":97},"7952":{"m":98,"g":97},"7988":{"m":98,"g":97},"7814":{"m":98,"g":97},"7978":{"m":98,"g":97},"7985":{"m":98,"g":97},"7975":{"m":98,"g":97},"7972":{"m":98,"g":97},"7950":{"m":98,"g":97},"8305":{"m":99,"g":103},"8370":{"m":99,"g":103},"8333":{"m":99,"g":103},"8367":{"m":99,"g":103},"8363":{"m":99,"g":103},"8359":{"m":99,"g":103},"8332":{"m":99,"g":103},"8357":{"m":99,"g":103},"8344":{"m":99,"g":103},"7858":{"m":99,"g":103},"8353":{"m":99,"g":103},"8341":{"m":99,"g":103},"8000":{"m":99,"g":103},"7135":{"m":99,"g":103},"8266":{"m":99,"g":103},"8280":{"m":99,"g":103},"6619":{"m":99,"g":103},"8233":{"m":99,"g":103},"8334":{"m":99,"g":103},"8307":{"m":99,"g":103},"8300":{"m":99,"g":103},"8299":{"m":99,"g":103},"8301":{"m":99,"g":103},"8310":{"m":99,"g":103},"8298":{"m":99,"g":103},"8315":{"m":99,"g":103},"8303":{"m":99,"g":103},"8317":{"m":99,"g":103},"8235":{"m":99,"g":103},"8070":{"m":99,"g":103},"7562":{"m":99,"g":103},"8043":{"m":99,"g":103},"7685":{"m":99,"g":103},"8304":{"m":99,"g":103},"8240":{"m":99,"g":103},"8262":{"m":99,"g":103},"7708":{"m":99,"g":103},"8133":{"m":99,"g":103},"8302":{"m":99,"g":103},"8295":{"m":99,"g":103},"8130":{"m":99,"g":103},"8288":{"m":99,"g":103},"8282":{"m":99,"g":103},"8264":{"m":99,"g":103},"8261":{"m":99,"g":103},"8284":{"m":99,"g":103},"8272":{"m":99,"g":103},"8458":{"m":100,"g":103},"8457":{"m":100,"g":103},"8449":{"m":100,"g":103},"8456":{"m":100,"g":103},"8445":{"m":100,"g":103},"8441":{"m":100,"g":103},"8442":{"m":100,"g":103},"8224":{"m":100,"g":103},"8352":{"m":100,"g":103},"8416":{"m":100,"g":103},"6338":{"m":100,"g":103},"8415":{"m":100,"g":103},"8422":{"m":100,"g":103},"8425":{"m":100,"g":103},"8419":{"m":100,"g":103},"8417":{"m":100,"g":103},"8316":{"m":100,"g":103},"7603":{"m":100,"g":103},"8213":{"m":100,"g":103},"8414":{"m":100,"g":103},"8062":{"m":100,"g":103},"8258":{"m":100,"g":103},"8406":{"m":100,"g":103},"8407":{"m":100,"g":103},"8405":{"m":100,"g":103},"8156":{"m":100,"g":103},"8241":{"m":100,"g":103},"8397":{"m":100,"g":103},"7720":{"m":100,"g":103},"8351":{"m":100,"g":103},"8395":{"m":100,"g":103},"8382":{"m":100,"g":103},"8392":{"m":100,"g":103},"8036":{"m":100,"g":103},"7739":{"m":100,"g":103},"7974":{"m":100,"g":103},"7976":{"m":100,"g":103},"8403":{"m":100,"g":103},"8401":{"m":100,"g":103},"8372":{"m":100,"g":103},"8394":{"m":100,"g":103},"8396":{"m":100,"g":103},"8314":{"m":100,"g":103},"8350":{"m":100,"g":103},"8381":{"m":100,"g":103},"6003":{"m":100,"g":103},"7737":{"m":100,"g":103},"8267":{"m":100,"g":103},"8343":{"m":100,"g":103},"7000":{"m":100,"g":103},"8356":{"m":100,"g":103},"8374":{"m":100,"g":103},"8517":{"m":101,"g":103},"8489":{"m":101,"g":103},"8482":{"m":101,"g":103},"7973":{"m":101,"g":103},"8426":{"m":101,"g":103},"8413":{"m":101,"g":103},"8486":{"m":101,"g":103},"8485":{"m":101,"g":103},"8477":{"m":101,"g":103},"8480":{"m":101,"g":103},"8478":{"m":101,"g":103},"8476":{"m":101,"g":103},"8469":{"m":101,"g":103},"8473":{"m":101,"g":103},"8421":{"m":101,"g":103},"7273":{"m":101,"g":103},"8453":{"m":101,"g":103},"8467":{"m":101,"g":103},"7565":{"m":101,"g":103},"8465":{"m":101,"g":103},"8125":{"m":101,"g":103},"8608":{"m":102,"g":103},"8590":{"m":102,"g":103},"8583":{"m":102,"g":103},"8604":{"m":102,"g":103},"8515":{"m":102,"g":103},"8603":{"m":102,"g":103},"8550":{"m":102,"g":103},"7211":{"m":102,"g":103},"8533":{"m":102,"g":103},"8404":{"m":102,"g":103},"8599":{"m":102,"g":103},"8514":{"m":102,"g":103},"8365":{"m":102,"g":103},"8544":{"m":102,"g":103},"8541":{"m":102,"g":103},"8564":{"m":102,"g":103},"8479":{"m":102,"g":103},"7280":{"m":102,"g":103},"8584":{"m":102,"g":103},"8154":{"m":102,"g":103},"8461":{"m":102,"g":103},"6869":{"m":102,"g":103},"8562":{"m":102,"g":103},"8545":{"m":102,"g":103},"8560":{"m":102,"g":103},"8516":{"m":102,"g":103},"8498":{"m":102,"g":103},"8448":{"m":102,"g":103},"8431":{"m":102,"g":103},"8537":{"m":102,"g":103},"8483":{"m":102,"g":103},"8531":{"m":102,"g":103},"8535":{"m":102,"g":103},"8499":{"m":102,"g":103},"8528":{"m":102,"g":103},"8527":{"m":102,"g":103},"8652":{"m":105,"g":107},"8051":{"m":105,"g":107},"8318":{"m":105,"g":107},"8636":{"m":105,"g":107},"8450":{"m":105,"g":107},"8645":{"m":105,"g":104},"8640":{"m":105,"g":104},"8644":{"m":105,"g":104},"8308":{"m":105,"g":104},"8270":{"m":105,"g":104},"8083":{"m":105,"g":104},"8642":{"m":105,"g":104},"8532":{"m":105,"g":104},"8632":{"m":105,"g":104},"8598":{"m":105,"g":104},"8630":{"m":105,"g":104},"8634":{"m":105,"g":104},"8488":{"m":105,"g":104},"8633":{"m":105,"g":104},"6227":{"m":105,"g":104},"8577":{"m":105,"g":104},"8628":{"m":105,"g":103},"8629":{"m":105,"g":103},"8626":{"m":105,"g":103},"8623":{"m":105,"g":103},"8611":{"m":105,"g":103},"8595":{"m":105,"g":103},"8727":{"m":106,"g":107},"8723":{"m":106,"g":107},"8579":{"m":106,"g":107},"8567":{"m":106,"g":107},"8718":{"m":106,"g":107},"8444":{"m":106,"g":107},"8547":{"m":106,"g":107},"8683":{"m":106,"g":107},"8631":{"m":106,"g":107},"7379":{"m":106,"g":107},"8719":{"m":106,"g":107},"8306":{"m":106,"g":107},"8650":{"m":106,"g":107},"8721":{"m":106,"g":107},"8524":{"m":106,"g":107},"8709":{"m":106,"g":107},"8722":{"m":106,"g":107},"7369":{"m":106,"g":107},"8714":{"m":106,"g":107},"8705":{"m":106,"g":107},"8693":{"m":106,"g":107},"8717":{"m":106,"g":107},"8713":{"m":106,"g":107},"8701":{"m":106,"g":107},"8711":{"m":106,"g":107},"8706":{"m":106,"g":107},"8704":{"m":106,"g":107},"8691":{"m":106,"g":107},"8512":{"m":106,"g":107},"7434":{"m":106,"g":107},"8688":{"m":106,"g":107},"8694":{"m":106,"g":107},"8364":{"m":106,"g":107},"8238":{"m":106,"g":107},"8618":{"m":106,"g":107},"8522":{"m":106,"g":107},"8668":{"m":106,"g":107},"8648":{"m":106,"g":107},"8679":{"m":106,"g":107},"8686":{"m":106,"g":107},"8684":{"m":106,"g":107},"8685":{"m":106,"g":107},"8647":{"m":106,"g":107},"8094":{"m":106,"g":107},"8664":{"m":106,"g":107},"8543":{"m":106,"g":107},"8665":{"m":106,"g":107},"8013":{"m":106,"g":107},"8643":{"m":106,"g":107},"8658":{"m":106,"g":107},"8511":{"m":106,"g":107},"8635":{"m":106,"g":107},"8653":{"m":106,"g":107},"9533":{"m":108,"g":115},"9532":{"m":108,"g":115},"9372":{"m":108,"g":115},"9485":{"m":108,"g":115},"9478":{"m":108,"g":115},"8034":{"m":108,"g":115},"9473":{"m":108,"g":115},"9525":{"m":108,"g":115},"9530":{"m":108,"g":115},"8946":{"m":108,"g":115},"9004":{"m":108,"g":115},"9241":{"m":108,"g":115},"9211":{"m":108,"g":115},"9503":{"m":108,"g":115},"9519":{"m":108,"g":115},"9456":{"m":108,"g":115},"7699":{"m":108,"g":115},"9200":{"m":108,"g":115},"9516":{"m":108,"g":115},"9127":{"m":108,"g":115},"9513":{"m":108,"g":115},"8624":{"m":108,"g":115},"8865":{"m":108,"g":115},"9109":{"m":108,"g":115},"9452":{"m":108,"g":115},"9507":{"m":108,"g":115},"9303":{"m":108,"g":115},"9331":{"m":108,"g":115},"9497":{"m":108,"g":115},"9494":{"m":108,"g":115},"9475":{"m":108,"g":115},"9480":{"m":108,"g":115},"9487":{"m":108,"g":115},"9491":{"m":108,"g":115},"9482":{"m":108,"g":115},"9492":{"m":108,"g":115},"9483":{"m":108,"g":115},"9333":{"m":108,"g":115},"9474":{"m":108,"g":115},"8616":{"m":108,"g":115},"9356":{"m":108,"g":115},"8593":{"m":108,"g":115},"9468":{"m":108,"g":115},"9467":{"m":108,"g":115},"9470":{"m":108,"g":115},"9469":{"m":108,"g":115},"9455":{"m":108,"g":115},"9463":{"m":108,"g":115},"9464":{"m":108,"g":115},"9462":{"m":108,"g":115},"9461":{"m":108,"g":115},"9458":{"m":108,"g":115},"9454":{"m":108,"g":115},"9427":{"m":108,"g":115},"9433":{"m":108,"g":115},"7604":{"m":108,"g":115},"8521":{"m":108,"g":115},"9392":{"m":108,"g":115},"9395":{"m":108,"g":115},"9238":{"m":108,"g":115},"9384":{"m":108,"g":115},"9430":{"m":108,"g":115},"9346":{"m":108,"g":115},"9399":{"m":108,"g":115},"9251":{"m":108,"g":115},"9388":{"m":108,"g":115},"9261":{"m":108,"g":115},"9420":{"m":108,"g":115},"9416":{"m":108,"g":115},"9415":{"m":108,"g":115},"9413":{"m":108,"g":115},"9371":{"m":108,"g":115},"9339":{"m":108,"g":115},"9357":{"m":108,"g":115},"9377":{"m":108,"g":115},"9381":{"m":108,"g":115},"9404":{"m":108,"g":115},"9359":{"m":108,"g":115},"9336":{"m":108,"g":115},"9249":{"m":108,"g":115},"9409":{"m":108,"g":115},"8690":{"m":108,"g":115},"9278":{"m":108,"g":115},"9391":{"m":108,"g":115},"9106":{"m":108,"g":115},"7375":{"m":108,"g":115},"9385":{"m":108,"g":115},"9383":{"m":108,"g":115},"9378":{"m":108,"g":115},"9380":{"m":108,"g":115},"9376":{"m":108,"g":115},"9350":{"m":108,"g":115},"9368":{"m":108,"g":115},"9344":{"m":108,"g":115},"9369":{"m":108,"g":115},"9367":{"m":108,"g":115},"9370":{"m":108,"g":115},"9364":{"m":108,"g":115},"9360":{"m":108,"g":115},"9335":{"m":108,"g":115},"9361":{"m":108,"g":115},"9354":{"m":108,"g":115},"6295":{"m":108,"g":115},"9353":{"m":108,"g":115},"9348":{"m":108,"g":115},"9327":{"m":108,"g":115},"9332":{"m":108,"g":115},"9326":{"m":108,"g":115},"8990":{"m":108,"g":115},"7019":{"m":108,"g":115},"9321":{"m":108,"g":115},"9317":{"m":108,"g":115},"9299":{"m":108,"g":115},"9322":{"m":108,"g":115},"9306":{"m":108,"g":115},"9320":{"m":108,"g":115},"9059":{"m":108,"g":115},"8936":{"m":108,"g":115},"9284":{"m":108,"g":115},"9313":{"m":108,"g":115},"9316":{"m":108,"g":115},"9315":{"m":108,"g":115},"8829":{"m":108,"g":115},"9011":{"m":108,"g":115},"9289":{"m":108,"g":115},"9310":{"m":108,"g":115},"9307":{"m":108,"g":115},"9298":{"m":108,"g":115},"9276":{"m":108,"g":115},"9293":{"m":108,"g":115},"6307":{"m":108,"g":115},"9245":{"m":108,"g":115},"9287":{"m":108,"g":115},"9286":{"m":108,"g":115},"8289":{"m":108,"g":115},"9281":{"m":108,"g":115},"8520":{"m":108,"g":115},"9272":{"m":108,"g":115},"9271":{"m":108,"g":115},"9279":{"m":108,"g":115},"9131":{"m":108,"g":115},"9242":{"m":108,"g":115},"9260":{"m":108,"g":115},"9268":{"m":108,"g":115},"9067":{"m":108,"g":115},"9264":{"m":108,"g":115},"9237":{"m":108,"g":115},"9232":{"m":108,"g":115},"9006":{"m":108,"g":115},"8893":{"m":108,"g":115},"9049":{"m":108,"g":115},"8846":{"m":108,"g":115},"9252":{"m":108,"g":115},"8027":{"m":108,"g":115},"9258":{"m":108,"g":115},"7758":{"m":108,"g":115},"9165":{"m":108,"g":115},"7667":{"m":108,"g":115},"9247":{"m":108,"g":115},"9246":{"m":108,"g":115},"8663":{"m":108,"g":115},"8268":{"m":108,"g":115},"9243":{"m":108,"g":115},"9236":{"m":108,"g":115},"9201":{"m":108,"g":115},"9198":{"m":108,"g":115},"9231":{"m":108,"g":115},"9220":{"m":108,"g":115},"9223":{"m":108,"g":115},"9222":{"m":108,"g":115},"8777":{"m":108,"g":115},"8790":{"m":108,"g":115},"9215":{"m":108,"g":115},"9218":{"m":108,"g":115},"9214":{"m":108,"g":115},"9208":{"m":108,"g":115},"9213":{"m":108,"g":115},"9207":{"m":108,"g":115},"9177":{"m":108,"g":115},"8849":{"m":108,"g":115},"9206":{"m":108,"g":115},"9205":{"m":108,"g":115},"9183":{"m":108,"g":115},"9204":{"m":108,"g":115},"9203":{"m":108,"g":115},"9202":{"m":108,"g":115},"9197":{"m":108,"g":115},"9008":{"m":108,"g":115},"8795":{"m":108,"g":115},"9191":{"m":108,"g":115},"9194":{"m":108,"g":115},"9060":{"m":108,"g":115},"8913":{"m":108,"g":115},"9185":{"m":108,"g":115},"8112":{"m":108,"g":115},"9065":{"m":108,"g":115},"8018":{"m":108,"g":115},"7687":{"m":108,"g":115},"7631":{"m":108,"g":115},"7004":{"m":108,"g":115},"8852":{"m":108,"g":115},"8808":{"m":108,"g":115},"8818":{"m":108,"g":115},"9154":{"m":108,"g":115},"9101":{"m":108,"g":115},"9162":{"m":108,"g":115},"9136":{"m":108,"g":115},"9171":{"m":108,"g":115},"9169":{"m":108,"g":115},"9159":{"m":108,"g":115},"8951":{"m":108,"g":115},"9161":{"m":108,"g":115},"8840":{"m":108,"g":115},"9134":{"m":108,"g":115},"9042":{"m":108,"g":115},"7957":{"m":108,"g":115},"9069":{"m":108,"g":115},"9028":{"m":108,"g":115},"8910":{"m":108,"g":115},"9149":{"m":108,"g":115},"9133":{"m":108,"g":115},"9126":{"m":108,"g":115},"9150":{"m":108,"g":115},"8484":{"m":108,"g":115},"9111":{"m":108,"g":115},"9146":{"m":108,"g":115},"9093":{"m":108,"g":115},"9088":{"m":108,"g":115},"8588":{"m":108,"g":115},"9137":{"m":108,"g":115},"8884":{"m":108,"g":115},"8651":{"m":108,"g":115},"9130":{"m":108,"g":115},"9129":{"m":108,"g":115},"8660":{"m":108,"g":115},"9119":{"m":108,"g":115},"8619":{"m":108,"g":115},"8610":{"m":108,"g":115},"8700":{"m":108,"g":115},"9125":{"m":108,"g":115},"9121":{"m":108,"g":115},"9014":{"m":108,"g":115},"9118":{"m":108,"g":115},"9122":{"m":108,"g":115},"9107":{"m":108,"g":115},"9113":{"m":108,"g":115},"9114":{"m":108,"g":115},"9021":{"m":108,"g":115},"9103":{"m":108,"g":115},"9077":{"m":108,"g":115},"9096":{"m":108,"g":115},"9005":{"m":108,"g":115},"9075":{"m":108,"g":115},"9097":{"m":108,"g":115},"9032":{"m":108,"g":115},"8766":{"m":108,"g":115},"9087":{"m":108,"g":115},"8293":{"m":108,"g":115},"9095":{"m":108,"g":115},"9084":{"m":108,"g":115},"8992":{"m":108,"g":115},"9089":{"m":108,"g":115},"9043":{"m":108,"g":115},"9086":{"m":108,"g":115},"9030":{"m":108,"g":115},"9053":{"m":108,"g":115},"8638":{"m":108,"g":115},"8731":{"m":108,"g":115},"9083":{"m":108,"g":115},"8752":{"m":108,"g":115},"9081":{"m":108,"g":115},"9082":{"m":108,"g":115},"8866":{"m":108,"g":115},"9080":{"m":108,"g":115},"8973":{"m":108,"g":115},"9063":{"m":108,"g":115},"9079":{"m":108,"g":115},"9066":{"m":108,"g":115},"7216":{"m":108,"g":115},"9051":{"m":108,"g":115},"9047":{"m":108,"g":115},"9057":{"m":108,"g":115},"9050":{"m":108,"g":115},"9054":{"m":108,"g":115},"9048":{"m":108,"g":115},"8997":{"m":108,"g":115},"9046":{"m":108,"g":115},"9044":{"m":108,"g":115},"9031":{"m":108,"g":115},"9037":{"m":108,"g":115},"9036":{"m":108,"g":115},"9034":{"m":108,"g":115},"9035":{"m":108,"g":115},"9033":{"m":108,"g":115},"8079":{"m":108,"g":115},"8794":{"m":108,"g":115},"9024":{"m":108,"g":115},"9027":{"m":108,"g":115},"9029":{"m":108,"g":115},"7626":{"m":108,"g":115},"9022":{"m":108,"g":115},"8940":{"m":108,"g":115},"8996":{"m":108,"g":115},"9018":{"m":108,"g":115},"9017":{"m":108,"g":115},"9019":{"m":108,"g":115},"8340":{"m":108,"g":115},"8991":{"m":108,"g":115},"8915":{"m":108,"g":115},"8245":{"m":108,"g":115},"9013":{"m":108,"g":115},"9007":{"m":108,"g":115},"9012":{"m":108,"g":115},"9003":{"m":108,"g":115},"9010":{"m":108,"g":115},"9001":{"m":108,"g":115},"8329":{"m":108,"g":115},"8355":{"m":108,"g":115},"8877":{"m":108,"g":115},"8995":{"m":108,"g":115},"8998":{"m":108,"g":115},"8878":{"m":108,"g":115},"6752":{"m":108,"g":115},"8673":{"m":108,"g":115},"8798":{"m":108,"g":115},"8687":{"m":108,"g":115},"8600":{"m":108,"g":115},"8966":{"m":108,"g":115},"8851":{"m":108,"g":115},"8984":{"m":108,"g":115},"8962":{"m":108,"g":115},"8987":{"m":108,"g":115},"8994":{"m":108,"g":115},"8993":{"m":108,"g":115},"8989":{"m":108,"g":115},"8667":{"m":108,"g":115},"8983":{"m":108,"g":115},"8980":{"m":108,"g":115},"8330":{"m":108,"g":115},"8770":{"m":108,"g":115},"8724":{"m":108,"g":115},"8988":{"m":108,"g":115},"8986":{"m":108,"g":115},"8785":{"m":108,"g":115},"8371":{"m":108,"g":115},"8982":{"m":108,"g":115},"8978":{"m":108,"g":115},"8981":{"m":108,"g":115},"8772":{"m":108,"g":115},"8971":{"m":108,"g":115},"8968":{"m":108,"g":115},"8972":{"m":108,"g":115},"7279":{"m":108,"g":115},"8941":{"m":108,"g":115},"8959":{"m":108,"g":115},"8757":{"m":108,"g":115},"8960":{"m":108,"g":115},"8958":{"m":108,"g":115},"8692":{"m":108,"g":115},"6555":{"m":108,"g":115},"8894":{"m":108,"g":115},"8957":{"m":108,"g":115},"8955":{"m":108,"g":115},"7657":{"m":108,"g":115},"8944":{"m":108,"g":115},"8799":{"m":108,"g":115},"8932":{"m":108,"g":115},"8952":{"m":108,"g":115},"8953":{"m":108,"g":115},"8947":{"m":108,"g":115},"8950":{"m":108,"g":115},"8720":{"m":108,"g":115},"8703":{"m":108,"g":115},"8923":{"m":108,"g":115},"8850":{"m":108,"g":115},"8933":{"m":108,"g":115},"8937":{"m":108,"g":115},"8929":{"m":108,"g":115},"8928":{"m":108,"g":115},"8925":{"m":108,"g":115},"8927":{"m":108,"g":115},"8908":{"m":108,"g":115},"8844":{"m":108,"g":107},"8916":{"m":108,"g":107},"8912":{"m":108,"g":107},"8698":{"m":108,"g":107},"8869":{"m":108,"g":107},"8898":{"m":108,"g":107},"8895":{"m":108,"g":107},"8041":{"m":108,"g":107},"5949":{"m":108,"g":107},"8888":{"m":108,"g":107},"8292":{"m":108,"g":107},"8787":{"m":108,"g":107},"8369":{"m":108,"g":107},"8697":{"m":108,"g":107},"8834":{"m":108,"g":107},"8883":{"m":108,"g":107},"8847":{"m":108,"g":107},"8539":{"m":108,"g":107},"8837":{"m":108,"g":107},"8880":{"m":108,"g":107},"8881":{"m":108,"g":107},"8811":{"m":108,"g":107},"8872":{"m":108,"g":107},"8861":{"m":108,"g":107},"8860":{"m":108,"g":107},"8868":{"m":108,"g":107},"8815":{"m":108,"g":107},"8859":{"m":108,"g":107},"8853":{"m":108,"g":107},"8843":{"m":108,"g":107},"8753":{"m":108,"g":107},"8751":{"m":108,"g":107},"8838":{"m":108,"g":107},"8144":{"m":108,"g":107},"8680":{"m":108,"g":107},"8839":{"m":108,"g":107},"8828":{"m":108,"g":107},"8836":{"m":108,"g":107},"8824":{"m":108,"g":107},"8809":{"m":108,"g":107},"8832":{"m":108,"g":107},"8681":{"m":108,"g":107},"8827":{"m":108,"g":107},"8823":{"m":108,"g":107},"8817":{"m":108,"g":107},"8804":{"m":108,"g":107},"8782":{"m":108,"g":107},"8802":{"m":108,"g":107},"8800":{"m":108,"g":107},"8797":{"m":108,"g":107},"8596":{"m":108,"g":107},"8779":{"m":108,"g":107},"8780":{"m":108,"g":107},"8744":{"m":108,"g":107},"8571":{"m":108,"g":107},"8212":{"m":108,"g":107},"8255":{"m":108,"g":107},"8776":{"m":108,"g":107},"8773":{"m":108,"g":107},"8771":{"m":108,"g":107},"8762":{"m":108,"g":107},"8768":{"m":108,"g":107},"8639":{"m":108,"g":107},"8552":{"m":108,"g":107},"8749":{"m":108,"g":107},"8294":{"m":108,"g":107},"8738":{"m":108,"g":107},"8437":{"m":108,"g":107},"8745":{"m":108,"g":107},"8733":{"m":108,"g":107},"8735":{"m":108,"g":107},"8737":{"m":108,"g":107},"8662":{"m":108,"g":107},"7114":{"m":108,"g":107},"8678":{"m":108,"g":107},"8732":{"m":108,"g":107},"8729":{"m":108,"g":107},"8676":{"m":108,"g":107},"8699":{"m":108,"g":107},"9558":{"m":109,"g":115},"9557":{"m":109,"g":115},"9549":{"m":109,"g":115},"9544":{"m":109,"g":115},"9547":{"m":109,"g":115},"9546":{"m":109,"g":115},"9592":{"m":110,"g":115},"9591":{"m":110,"g":115},"9589":{"m":110,"g":115},"9587":{"m":110,"g":115},"9581":{"m":110,"g":115},"9578":{"m":110,"g":115},"9229":{"m":110,"g":115},"9536":{"m":110,"g":115},"9535":{"m":110,"g":115},"9559":{"m":110,"g":115},"9560":{"m":110,"g":115},"7317":{"m":110,"g":115},"9576":{"m":110,"g":115},"9429":{"m":110,"g":115},"9565":{"m":110,"g":115},"9498":{"m":110,"g":115},"9716":{"m":111,"g":115},"9708":{"m":111,"g":115},"9340":{"m":111,"g":115},"9703":{"m":111,"g":115},"9702":{"m":111,"g":115},"9695":{"m":111,"g":115},"9683":{"m":111,"g":115},"9700":{"m":111,"g":115},"9676":{"m":111,"g":115},"9694":{"m":111,"g":115},"9693":{"m":111,"g":115},"9679":{"m":111,"g":115},"9678":{"m":111,"g":115},"9397":{"m":111,"g":115},"9495":{"m":111,"g":115},"9677":{"m":111,"g":115},"9446":{"m":111,"g":115},"9071":{"m":111,"g":115},"9597":{"m":111,"g":115},"9555":{"m":111,"g":115},"9583":{"m":111,"g":115},"9564":{"m":111,"g":115},"9658":{"m":111,"g":115},"9665":{"m":111,"g":115},"9648":{"m":111,"g":115},"9637":{"m":111,"g":115},"9649":{"m":111,"g":115},"9647":{"m":111,"g":115},"9656":{"m":111,"g":115},"9523":{"m":111,"g":115},"9606":{"m":111,"g":115},"9635":{"m":111,"g":115},"9630":{"m":111,"g":115},"9640":{"m":111,"g":115},"9636":{"m":111,"g":115},"9301":{"m":111,"g":115},"8328":{"m":111,"g":115},"9632":{"m":111,"g":115},"9629":{"m":111,"g":115},"9628":{"m":111,"g":115},"9623":{"m":111,"g":115},"9622":{"m":111,"g":115},"9608":{"m":111,"g":115},"8901":{"m":111,"g":115},"9613":{"m":111,"g":115},"9190":{"m":111,"g":115},"9554":{"m":111,"g":115},"9500":{"m":111,"g":115},"9436":{"m":111,"g":115},"9568":{"m":111,"g":115},"10221":{"m":112,"g":115},"10340":{"m":112,"g":115},"10303":{"m":112,"g":115},"10331":{"m":112,"g":115},"10339":{"m":112,"g":115},"10330":{"m":112,"g":115},"10327":{"m":112,"g":115},"10338":{"m":112,"g":115},"10254":{"m":112,"g":115},"10264":{"m":112,"g":115},"10280":{"m":112,"g":115},"10335":{"m":112,"g":115},"10322":{"m":112,"g":115},"10328":{"m":112,"g":115},"10326":{"m":112,"g":115},"10233":{"m":112,"g":115},"10297":{"m":112,"g":115},"10314":{"m":112,"g":115},"10311":{"m":112,"g":115},"10310":{"m":112,"g":115},"10299":{"m":112,"g":115},"9090":{"m":112,"g":115},"10229":{"m":112,"g":115},"10239":{"m":112,"g":115},"9881":{"m":112,"g":115},"10294":{"m":112,"g":115},"10292":{"m":112,"g":115},"10282":{"m":112,"g":115},"10184":{"m":112,"g":115},"10241":{"m":112,"g":115},"9662":{"m":112,"g":115},"10252":{"m":112,"g":115},"9940":{"m":112,"g":115},"10251":{"m":112,"g":115},"10256":{"m":112,"g":115},"10250":{"m":112,"g":115},"10262":{"m":112,"g":115},"9954":{"m":112,"g":115},"10173":{"m":112,"g":115},"10060":{"m":112,"g":115},"10253":{"m":112,"g":115},"10093":{"m":112,"g":115},"10240":{"m":112,"g":115},"8803":{"m":112,"g":115},"10246":{"m":112,"g":115},"9795":{"m":112,"g":115},"10245":{"m":112,"g":115},"10242":{"m":112,"g":115},"10236":{"m":112,"g":115},"10234":{"m":112,"g":115},"10213":{"m":112,"g":115},"10238":{"m":112,"g":115},"10210":{"m":112,"g":115},"10220":{"m":112,"g":115},"10214":{"m":112,"g":115},"9960":{"m":112,"g":115},"10208":{"m":112,"g":115},"10212":{"m":112,"g":115},"10209":{"m":112,"g":115},"10207":{"m":112,"g":115},"10205":{"m":112,"g":115},"9300":{"m":112,"g":115},"10193":{"m":112,"g":115},"10127":{"m":112,"g":115},"10188":{"m":112,"g":115},"10165":{"m":112,"g":115},"10169":{"m":112,"g":115},"4422":{"m":112,"g":115},"9900":{"m":112,"g":115},"10191":{"m":112,"g":115},"7995":{"m":112,"g":115},"10185":{"m":112,"g":115},"10149":{"m":112,"g":115},"9522":{"m":112,"g":115},"10182":{"m":112,"g":115},"10181":{"m":112,"g":115},"9839":{"m":112,"g":115},"10176":{"m":112,"g":115},"9595":{"m":112,"g":115},"10166":{"m":112,"g":115},"9925":{"m":112,"g":115},"10156":{"m":112,"g":115},"10161":{"m":112,"g":115},"10159":{"m":112,"g":115},"10131":{"m":112,"g":115},"10028":{"m":112,"g":115},"10155":{"m":112,"g":115},"9871":{"m":112,"g":115},"9434":{"m":112,"g":115},"10148":{"m":112,"g":115},"6226":{"m":112,"g":115},"10013":{"m":112,"g":115},"10147":{"m":112,"g":115},"9981":{"m":112,"g":115},"9989":{"m":112,"g":115},"10108":{"m":112,"g":115},"10123":{"m":112,"g":115},"7843":{"m":112,"g":115},"10090":{"m":112,"g":115},"10104":{"m":112,"g":115},"8801":{"m":112,"g":115},"10040":{"m":112,"g":115},"10141":{"m":112,"g":115},"10095":{"m":112,"g":115},"10144":{"m":112,"g":115},"9971":{"m":112,"g":115},"10134":{"m":112,"g":115},"10135":{"m":112,"g":115},"10074":{"m":112,"g":115},"10128":{"m":112,"g":115},"10126":{"m":112,"g":115},"10113":{"m":112,"g":115},"10096":{"m":112,"g":115},"10056":{"m":112,"g":115},"10101":{"m":112,"g":115},"9969":{"m":112,"g":115},"9741":{"m":112,"g":115},"9477":{"m":112,"g":115},"10117":{"m":112,"g":115},"10102":{"m":112,"g":115},"10116":{"m":112,"g":115},"10068":{"m":112,"g":115},"9956":{"m":112,"g":115},"10041":{"m":112,"g":115},"10058":{"m":112,"g":115},"10107":{"m":112,"g":115},"10100":{"m":112,"g":115},"9834":{"m":112,"g":115},"9861":{"m":112,"g":115},"9764":{"m":112,"g":115},"9269":{"m":112,"g":115},"9620":{"m":112,"g":115},"6905":{"m":112,"g":115},"10032":{"m":112,"g":115},"10097":{"m":112,"g":115},"10029":{"m":112,"g":115},"10039":{"m":112,"g":115},"10092":{"m":112,"g":115},"10086":{"m":112,"g":115},"10057":{"m":112,"g":115},"10047":{"m":112,"g":115},"9842":{"m":112,"g":115},"9965":{"m":112,"g":115},"10069":{"m":112,"g":115},"9884":{"m":112,"g":115},"10087":{"m":112,"g":115},"8622":{"m":112,"g":115},"8555":{"m":112,"g":115},"10080":{"m":112,"g":115},"10079":{"m":112,"g":115},"10043":{"m":112,"g":115},"10007":{"m":112,"g":115},"7182":{"m":112,"g":115},"8725":{"m":112,"g":115},"8867":{"m":112,"g":115},"9567":{"m":112,"g":115},"5255":{"m":112,"g":115},"10006":{"m":112,"g":115},"9534":{"m":112,"g":115},"9934":{"m":112,"g":115},"9931":{"m":112,"g":115},"9801":{"m":112,"g":115},"10049":{"m":112,"g":115},"10055":{"m":112,"g":115},"9964":{"m":112,"g":115},"10052":{"m":112,"g":115},"10050":{"m":112,"g":115},"8677":{"m":112,"g":115},"10008":{"m":112,"g":115},"9951":{"m":112,"g":115},"9957":{"m":112,"g":115},"9938":{"m":112,"g":115},"9634":{"m":112,"g":115},"9886":{"m":112,"g":115},"9973":{"m":112,"g":115},"9846":{"m":112,"g":115},"10003":{"m":112,"g":115},"10004":{"m":112,"g":115},"9997":{"m":112,"g":115},"10016":{"m":112,"g":115},"9993":{"m":112,"g":115},"9994":{"m":112,"g":115},"9999":{"m":112,"g":115},"10000":{"m":112,"g":115},"9996":{"m":112,"g":115},"9988":{"m":112,"g":115},"9986":{"m":112,"g":115},"9733":{"m":112,"g":115},"9314":{"m":112,"g":115},"9978":{"m":112,"g":115},"9914":{"m":112,"g":115},"9460":{"m":112,"g":115},"9958":{"m":112,"g":115},"9906":{"m":112,"g":115},"9953":{"m":112,"g":115},"9937":{"m":112,"g":115},"9959":{"m":112,"g":115},"9955":{"m":112,"g":115},"9755":{"m":112,"g":115},"9952":{"m":112,"g":115},"9671":{"m":112,"g":115},"7912":{"m":112,"g":115},"9895":{"m":112,"g":115},"9905":{"m":112,"g":115},"9927":{"m":112,"g":115},"9946":{"m":112,"g":115},"9912":{"m":112,"g":115},"9869":{"m":112,"g":115},"8747":{"m":112,"g":115},"9939":{"m":112,"g":115},"9929":{"m":112,"g":115},"9932":{"m":112,"g":115},"9705":{"m":112,"g":115},"9909":{"m":112,"g":115},"9920":{"m":112,"g":115},"9921":{"m":112,"g":115},"9879":{"m":112,"g":115},"9919":{"m":112,"g":115},"9916":{"m":112,"g":115},"9907":{"m":112,"g":115},"9844":{"m":112,"g":115},"9913":{"m":112,"g":115},"9902":{"m":112,"g":115},"8118":{"m":112,"g":115},"9875":{"m":112,"g":115},"9893":{"m":112,"g":115},"9878":{"m":112,"g":115},"9803":{"m":112,"g":115},"9876":{"m":112,"g":115},"9874":{"m":112,"g":115},"9783":{"m":112,"g":115},"9882":{"m":112,"g":115},"9857":{"m":112,"g":115},"9862":{"m":112,"g":115},"9864":{"m":112,"g":115},"8964":{"m":112,"g":115},"9794":{"m":112,"g":115},"9858":{"m":112,"g":115},"9852":{"m":112,"g":115},"9847":{"m":112,"g":115},"9073":{"m":112,"g":115},"9850":{"m":112,"g":115},"9797":{"m":112,"g":115},"9661":{"m":112,"g":115},"9841":{"m":112,"g":115},"9750":{"m":112,"g":115},"9709":{"m":112,"g":115},"8909":{"m":112,"g":115},"9840":{"m":112,"g":115},"9824":{"m":112,"g":115},"9835":{"m":112,"g":115},"9837":{"m":112,"g":115},"9836":{"m":112,"g":115},"9831":{"m":112,"g":115},"9830":{"m":112,"g":115},"9761":{"m":112,"g":115},"9828":{"m":112,"g":115},"9827":{"m":112,"g":115},"9826":{"m":112,"g":115},"9822":{"m":112,"g":115},"9802":{"m":112,"g":115},"9820":{"m":112,"g":115},"9746":{"m":112,"g":115},"9817":{"m":112,"g":115},"9815":{"m":112,"g":115},"9807":{"m":112,"g":115},"8345":{"m":112,"g":115},"9809":{"m":112,"g":115},"9670":{"m":112,"g":115},"9556":{"m":112,"g":115},"9675":{"m":112,"g":115},"9712":{"m":112,"g":115},"9793":{"m":112,"g":115},"9216":{"m":112,"g":115},"8375":{"m":112,"g":115},"9663":{"m":112,"g":115},"9715":{"m":112,"g":115},"9692":{"m":112,"g":115},"9776":{"m":112,"g":115},"9792":{"m":112,"g":115},"9786":{"m":112,"g":115},"9789":{"m":112,"g":115},"9788":{"m":112,"g":115},"9757":{"m":112,"g":115},"9784":{"m":112,"g":115},"9777":{"m":112,"g":115},"9749":{"m":112,"g":115},"9772":{"m":112,"g":115},"8750":{"m":112,"g":115},"6287":{"m":112,"g":115},"6407":{"m":112,"g":115},"9355":{"m":112,"g":115},"9770":{"m":112,"g":115},"8236":{"m":112,"g":115},"9759":{"m":112,"g":115},"9745":{"m":112,"g":115},"9721":{"m":112,"g":115},"9735":{"m":112,"g":115},"9573":{"m":112,"g":115},"9673":{"m":112,"g":115},"9740":{"m":112,"g":115},"9739":{"m":112,"g":115},"9684":{"m":112,"g":115},"9732":{"m":112,"g":115},"9730":{"m":112,"g":115},"9728":{"m":112,"g":115},"9615":{"m":112,"g":115},"9505":{"m":112,"g":115},"9724":{"m":112,"g":115},"9720":{"m":112,"g":115},"11263":{"m":113,"g":115},"11259":{"m":113,"g":115},"11061":{"m":113,"g":115},"11235":{"m":113,"g":115},"11240":{"m":113,"g":115},"11209":{"m":113,"g":115},"11254":{"m":113,"g":115},"11242":{"m":113,"g":115},"11252":{"m":113,"g":115},"11251":{"m":113,"g":115},"10048":{"m":113,"g":115},"10042":{"m":113,"g":115},"11248":{"m":113,"g":115},"11247":{"m":113,"g":115},"10996":{"m":113,"g":115},"11206":{"m":113,"g":115},"11228":{"m":113,"g":115},"11237":{"m":113,"g":115},"11222":{"m":113,"g":115},"11174":{"m":113,"g":115},"11162":{"m":113,"g":115},"10571":{"m":113,"g":115},"11229":{"m":113,"g":115},"11137":{"m":113,"g":115},"9624":{"m":113,"g":115},"11194":{"m":113,"g":115},"11225":{"m":113,"g":115},"11063":{"m":113,"g":115},"11217":{"m":113,"g":115},"11215":{"m":113,"g":115},"11140":{"m":113,"g":115},"11213":{"m":113,"g":115},"11012":{"m":113,"g":115},"11096":{"m":113,"g":115},"11011":{"m":113,"g":115},"11178":{"m":113,"g":115},"11196":{"m":113,"g":115},"10741":{"m":113,"g":115},"11198":{"m":113,"g":115},"10517":{"m":113,"g":115},"10838":{"m":113,"g":115},"10859":{"m":113,"g":115},"10609":{"m":113,"g":115},"10855":{"m":113,"g":115},"11090":{"m":113,"g":115},"10780":{"m":113,"g":115},"10892":{"m":113,"g":115},"11166":{"m":113,"g":115},"11192":{"m":113,"g":115},"11189":{"m":113,"g":115},"10873":{"m":113,"g":115},"11173":{"m":113,"g":115},"11167":{"m":113,"g":115},"10637":{"m":113,"g":115},"11185":{"m":113,"g":115},"11161":{"m":113,"g":115},"9537":{"m":113,"g":115},"10830":{"m":113,"g":115},"10133":{"m":113,"g":115},"11138":{"m":113,"g":115},"11179":{"m":113,"g":115},"11176":{"m":113,"g":115},"11159":{"m":113,"g":115},"11170":{"m":113,"g":115},"11175":{"m":113,"g":115},"11124":{"m":113,"g":115},"11171":{"m":113,"g":115},"11164":{"m":113,"g":115},"11130":{"m":113,"g":115},"11163":{"m":113,"g":115},"10837":{"m":113,"g":115},"11152":{"m":113,"g":115},"10988":{"m":113,"g":115},"11160":{"m":113,"g":115},"10422":{"m":113,"g":115},"10263":{"m":113,"g":115},"11156":{"m":113,"g":115},"10508":{"m":113,"g":115},"10779":{"m":113,"g":115},"10768":{"m":113,"g":115},"11132":{"m":113,"g":115},"11148":{"m":113,"g":115},"11149":{"m":113,"g":115},"10559":{"m":113,"g":115},"11135":{"m":113,"g":115},"10720":{"m":113,"g":115},"11145":{"m":113,"g":115},"11123":{"m":113,"g":115},"11143":{"m":113,"g":115},"11120":{"m":113,"g":115},"10512":{"m":113,"g":115},"10271":{"m":113,"g":115},"11005":{"m":113,"g":115},"10760":{"m":113,"g":115},"11128":{"m":113,"g":115},"11075":{"m":113,"g":115},"10985":{"m":113,"g":115},"11111":{"m":113,"g":115},"11115":{"m":113,"g":115},"11114":{"m":113,"g":115},"10735":{"m":113,"g":115},"11112":{"m":113,"g":115},"10972":{"m":113,"g":115},"11080":{"m":113,"g":115},"11113":{"m":113,"g":115},"11071":{"m":113,"g":115},"11081":{"m":113,"g":115},"11102":{"m":113,"g":115},"11101":{"m":113,"g":115},"10846":{"m":113,"g":115},"11094":{"m":113,"g":115},"11067":{"m":113,"g":115},"11099":{"m":113,"g":115},"11087":{"m":113,"g":115},"10991":{"m":113,"g":115},"11085":{"m":113,"g":115},"11070":{"m":113,"g":115},"11092":{"m":113,"g":115},"10729":{"m":113,"g":115},"9642":{"m":113,"g":115},"10816":{"m":113,"g":115},"11083":{"m":113,"g":115},"10875":{"m":113,"g":115},"11082":{"m":113,"g":115},"11079":{"m":113,"g":115},"10611":{"m":113,"g":115},"11076":{"m":113,"g":115},"11073":{"m":113,"g":115},"10975":{"m":113,"g":115},"11069":{"m":113,"g":115},"11056":{"m":113,"g":115},"10976":{"m":113,"g":115},"11054":{"m":113,"g":115},"11050":{"m":113,"g":115},"11022":{"m":113,"g":115},"9614":{"m":113,"g":115},"11010":{"m":113,"g":115},"10591":{"m":113,"g":115},"11015":{"m":113,"g":115},"10940":{"m":113,"g":115},"10701":{"m":113,"g":115},"11036":{"m":113,"g":115},"11038":{"m":113,"g":115},"10986":{"m":113,"g":115},"11033":{"m":113,"g":115},"11017":{"m":113,"g":115},"11003":{"m":113,"g":115},"11013":{"m":113,"g":115},"10543":{"m":113,"g":115},"10555":{"m":113,"g":115},"10964":{"m":113,"g":115},"11009":{"m":113,"g":115},"10999":{"m":113,"g":115},"10978":{"m":113,"g":115},"10995":{"m":113,"g":115},"10997":{"m":113,"g":115},"10550":{"m":113,"g":115},"10565":{"m":113,"g":115},"10616":{"m":113,"g":115},"10751":{"m":113,"g":115},"10930":{"m":113,"g":115},"10981":{"m":113,"g":115},"10112":{"m":113,"g":115},"10980":{"m":113,"g":115},"10982":{"m":113,"g":115},"10551":{"m":113,"g":115},"10965":{"m":113,"g":115},"10944":{"m":113,"g":115},"10971":{"m":113,"g":115},"10941":{"m":113,"g":115},"10495":{"m":113,"g":115},"10372":{"m":113,"g":115},"10970":{"m":113,"g":115},"10947":{"m":113,"g":115},"10968":{"m":113,"g":115},"10967":{"m":113,"g":115},"10963":{"m":113,"g":115},"10960":{"m":113,"g":115},"10958":{"m":113,"g":115},"10956":{"m":113,"g":115},"10955":{"m":113,"g":115},"10749":{"m":113,"g":115},"10927":{"m":113,"g":115},"10936":{"m":113,"g":115},"10192":{"m":113,"g":115},"10939":{"m":113,"g":115},"10935":{"m":113,"g":115},"10929":{"m":113,"g":115},"10932":{"m":113,"g":115},"10898":{"m":113,"g":115},"10612":{"m":113,"g":115},"10923":{"m":113,"g":115},"10926":{"m":113,"g":115},"10899":{"m":113,"g":115},"10883":{"m":113,"g":115},"10910":{"m":113,"g":115},"10924":{"m":113,"g":115},"10132":{"m":113,"g":115},"10881":{"m":113,"g":115},"10894":{"m":113,"g":115},"10915":{"m":113,"g":115},"10376":{"m":113,"g":115},"10778":{"m":113,"g":115},"10872":{"m":113,"g":115},"10885":{"m":113,"g":115},"10895":{"m":113,"g":115},"10845":{"m":113,"g":115},"10880":{"m":113,"g":115},"10572":{"m":113,"g":115},"10861":{"m":113,"g":115},"10876":{"m":113,"g":115},"10877":{"m":113,"g":115},"10534":{"m":113,"g":115},"10827":{"m":113,"g":115},"10832":{"m":113,"g":115},"10786":{"m":113,"g":115},"10860":{"m":113,"g":115},"10718":{"m":113,"g":115},"10829":{"m":113,"g":115},"10828":{"m":113,"g":115},"10825":{"m":113,"g":115},"10826":{"m":113,"g":115},"10822":{"m":113,"g":115},"10824":{"m":113,"g":115},"10823":{"m":113,"g":115},"10787":{"m":113,"g":115},"10820":{"m":113,"g":115},"10794":{"m":113,"g":115},"10799":{"m":113,"g":115},"10818":{"m":113,"g":115},"10540":{"m":113,"g":115},"10504":{"m":113,"g":115},"10761":{"m":113,"g":115},"10814":{"m":113,"g":115},"10812":{"m":113,"g":115},"10259":{"m":113,"g":115},"10323":{"m":113,"g":115},"10581":{"m":113,"g":115},"10773":{"m":113,"g":115},"10792":{"m":113,"g":115},"10791":{"m":113,"g":115},"10770":{"m":113,"g":115},"10783":{"m":113,"g":115},"10782":{"m":113,"g":115},"10715":{"m":113,"g":115},"10705":{"m":113,"g":115},"10776":{"m":113,"g":115},"10777":{"m":113,"g":115},"10771":{"m":113,"g":115},"10774":{"m":113,"g":115},"10767":{"m":113,"g":115},"10756":{"m":113,"g":115},"10765":{"m":113,"g":115},"10574":{"m":113,"g":115},"10556":{"m":113,"g":115},"10130":{"m":113,"g":115},"10762":{"m":113,"g":115},"10541":{"m":113,"g":115},"10281":{"m":113,"g":115},"10759":{"m":113,"g":115},"10300":{"m":113,"g":115},"10755":{"m":113,"g":115},"10732":{"m":113,"g":115},"10758":{"m":113,"g":115},"10757":{"m":113,"g":115},"10727":{"m":113,"g":115},"10754":{"m":113,"g":115},"10724":{"m":113,"g":115},"10753":{"m":113,"g":115},"10737":{"m":113,"g":115},"10728":{"m":113,"g":115},"10730":{"m":113,"g":115},"9849":{"m":113,"g":115},"10731":{"m":113,"g":115},"10709":{"m":113,"g":115},"10699":{"m":113,"g":115},"10678":{"m":113,"g":115},"10695":{"m":113,"g":115},"10694":{"m":113,"g":115},"10717":{"m":113,"g":115},"10714":{"m":113,"g":115},"10716":{"m":113,"g":115},"10385":{"m":113,"g":115},"10317":{"m":113,"g":115},"10706":{"m":113,"g":115},"10592":{"m":113,"g":115},"10697":{"m":113,"g":115},"10696":{"m":113,"g":115},"10651":{"m":113,"g":115},"10688":{"m":113,"g":115},"10686":{"m":113,"g":115},"10685":{"m":113,"g":115},"10673":{"m":113,"g":115},"10684":{"m":113,"g":115},"10680":{"m":113,"g":115},"10681":{"m":113,"g":115},"10683":{"m":113,"g":115},"10645":{"m":113,"g":115},"10677":{"m":113,"g":115},"10679":{"m":113,"g":115},"10648":{"m":113,"g":115},"10671":{"m":113,"g":115},"10675":{"m":113,"g":115},"10666":{"m":113,"g":115},"10670":{"m":113,"g":115},"10668":{"m":113,"g":115},"10664":{"m":113,"g":115},"10661":{"m":113,"g":115},"10522":{"m":113,"g":115},"10653":{"m":113,"g":115},"10634":{"m":113,"g":115},"10650":{"m":113,"g":115},"10321":{"m":113,"g":115},"10647":{"m":113,"g":115},"10081":{"m":113,"g":115},"10633":{"m":113,"g":115},"10319":{"m":113,"g":115},"10630":{"m":113,"g":115},"10631":{"m":113,"g":115},"10632":{"m":113,"g":115},"10586":{"m":113,"g":115},"10553":{"m":113,"g":115},"9873":{"m":113,"g":115},"10629":{"m":113,"g":115},"10628":{"m":113,"g":115},"10621":{"m":113,"g":115},"9947":{"m":113,"g":115},"10579":{"m":113,"g":115},"10595":{"m":113,"g":115},"10610":{"m":113,"g":115},"10622":{"m":113,"g":115},"10624":{"m":113,"g":115},"10222":{"m":113,"g":115},"9979":{"m":113,"g":115},"8274":{"m":113,"g":115},"10604":{"m":113,"g":115},"10525":{"m":113,"g":115},"10596":{"m":113,"g":115},"10273":{"m":113,"g":115},"10563":{"m":113,"g":115},"10190":{"m":113,"g":115},"10558":{"m":113,"g":115},"10526":{"m":113,"g":115},"9987":{"m":113,"g":115},"10584":{"m":113,"g":115},"9976":{"m":113,"g":115},"10171":{"m":113,"g":115},"10548":{"m":113,"g":115},"8813":{"m":113,"g":115},"10545":{"m":113,"g":115},"10523":{"m":113,"g":115},"10459":{"m":113,"g":115},"10529":{"m":113,"g":115},"8746":{"m":113,"g":115},"10538":{"m":113,"g":115},"10494":{"m":113,"g":115},"9928":{"m":113,"g":115},"10474":{"m":113,"g":115},"10530":{"m":113,"g":115},"10528":{"m":113,"g":115},"10524":{"m":113,"g":115},"10511":{"m":113,"g":115},"10506":{"m":113,"g":115},"10515":{"m":113,"g":115},"10491":{"m":113,"g":115},"10500":{"m":113,"g":115},"10507":{"m":113,"g":115},"10466":{"m":113,"g":115},"10498":{"m":113,"g":115},"10499":{"m":113,"g":115},"10493":{"m":113,"g":115},"10487":{"m":113,"g":115},"10230":{"m":113,"g":115},"10336":{"m":113,"g":115},"10203":{"m":113,"g":115},"10434":{"m":113,"g":115},"8863":{"m":113,"g":115},"10486":{"m":113,"g":115},"10484":{"m":113,"g":115},"10286":{"m":113,"g":115},"10481":{"m":113,"g":115},"10478":{"m":113,"g":115},"10479":{"m":113,"g":115},"10475":{"m":113,"g":115},"10473":{"m":113,"g":115},"10476":{"m":113,"g":115},"8189":{"m":113,"g":115},"9657":{"m":113,"g":115},"10375":{"m":113,"g":115},"9887":{"m":113,"g":115},"8710":{"m":113,"g":115},"10471":{"m":113,"g":115},"10470":{"m":113,"g":115},"10468":{"m":113,"g":115},"10465":{"m":113,"g":115},"10440":{"m":113,"g":115},"10456":{"m":113,"g":115},"10439":{"m":113,"g":115},"10463":{"m":113,"g":115},"10458":{"m":113,"g":115},"10457":{"m":113,"g":115},"10401":{"m":113,"g":115},"10358":{"m":113,"g":115},"10449":{"m":113,"g":115},"9343":{"m":113,"g":115},"10452":{"m":113,"g":115},"10450":{"m":113,"g":115},"10445":{"m":113,"g":115},"9626":{"m":113,"g":115},"9768":{"m":113,"g":115},"10143":{"m":113,"g":115},"10441":{"m":113,"g":115},"10437":{"m":113,"g":115},"9338":{"m":113,"g":115},"10435":{"m":113,"g":115},"10201":{"m":113,"g":115},"10432":{"m":113,"g":115},"10129":{"m":113,"g":115},"10433":{"m":113,"g":115},"10426":{"m":113,"g":115},"10425":{"m":113,"g":115},"10429":{"m":113,"g":115},"10431":{"m":113,"g":115},"10428":{"m":113,"g":115},"9962":{"m":113,"g":115},"10076":{"m":113,"g":115},"8627":{"m":113,"g":115},"10419":{"m":113,"g":115},"6539":{"m":113,"g":115},"10270":{"m":113,"g":115},"9948":{"m":113,"g":115},"10157":{"m":113,"g":115},"10313":{"m":113,"g":115},"10369":{"m":113,"g":115},"10318":{"m":113,"g":115},"10404":{"m":113,"g":115},"10228":{"m":113,"g":115},"10414":{"m":113,"g":115},"10410":{"m":113,"g":115},"10411":{"m":113,"g":115},"10412":{"m":113,"g":115},"9748":{"m":113,"g":115},"9382":{"m":113,"g":115},"10406":{"m":113,"g":115},"10392":{"m":113,"g":115},"10403":{"m":113,"g":115},"10400":{"m":113,"g":115},"10397":{"m":113,"g":115},"10398":{"m":113,"g":115},"9984":{"m":113,"g":115},"10395":{"m":113,"g":115},"10394":{"m":113,"g":115},"10332":{"m":113,"g":115},"10377":{"m":113,"g":115},"10379":{"m":113,"g":115},"10380":{"m":113,"g":115},"10387":{"m":113,"g":115},"10244":{"m":113,"g":115},"10386":{"m":113,"g":115},"10391":{"m":113,"g":115},"10361":{"m":113,"g":115},"10390":{"m":113,"g":115},"10388":{"m":113,"g":115},"10343":{"m":113,"g":115},"10333":{"m":113,"g":115},"9023":{"m":113,"g":115},"10099":{"m":113,"g":115},"10219":{"m":113,"g":115},"10370":{"m":113,"g":115},"10368":{"m":113,"g":115},"10180":{"m":113,"g":115},"10355":{"m":113,"g":115},"8215":{"m":113,"g":115},"8778":{"m":113,"g":115},"10351":{"m":113,"g":115},"10362":{"m":113,"g":115},"10359":{"m":113,"g":115},"10360":{"m":113,"g":115},"10356":{"m":113,"g":115},"10031":{"m":113,"g":115},"10283":{"m":113,"g":115},"10346":{"m":113,"g":115},"10352":{"m":113,"g":115},"9774":{"m":113,"g":115},"10296":{"m":113,"g":115},"9199":{"m":113,"g":115},"10345":{"m":113,"g":115},"10349":{"m":113,"g":115},"10347":{"m":113,"g":115},"11324":{"m":114,"g":115},"11369":{"m":114,"g":115},"11364":{"m":114,"g":115},"11394":{"m":114,"g":115},"11387":{"m":114,"g":115},"11376":{"m":114,"g":115},"11375":{"m":114,"g":115},"11373":{"m":114,"g":115},"11309":{"m":114,"g":115},"11366":{"m":114,"g":115},"11359":{"m":114,"g":115},"11353":{"m":114,"g":115},"10979":{"m":114,"g":115},"11350":{"m":114,"g":115},"11327":{"m":114,"g":115},"11342":{"m":114,"g":115},"11339":{"m":114,"g":115},"11341":{"m":114,"g":115},"11340":{"m":114,"g":115},"11336":{"m":114,"g":115},"11323":{"m":114,"g":115},"10909":{"m":114,"g":115},"11264":{"m":114,"g":115},"9812":{"m":114,"g":115},"11318":{"m":114,"g":115},"11007":{"m":114,"g":115},"11321":{"m":114,"g":115},"10937":{"m":114,"g":115},"11312":{"m":114,"g":115},"11211":{"m":114,"g":115},"9545":{"m":114,"g":115},"11314":{"m":114,"g":115},"11316":{"m":114,"g":115},"11126":{"m":114,"g":115},"11315":{"m":114,"g":115},"10710":{"m":114,"g":115},"11230":{"m":114,"g":115},"11200":{"m":114,"g":115},"11304":{"m":114,"g":115},"11310":{"m":114,"g":115},"11311":{"m":114,"g":115},"11297":{"m":114,"g":115},"11205":{"m":114,"g":115},"11307":{"m":114,"g":115},"11223":{"m":114,"g":115},"11306":{"m":114,"g":115},"11305":{"m":114,"g":115},"11001":{"m":114,"g":115},"11027":{"m":114,"g":115},"11288":{"m":114,"g":115},"11303":{"m":114,"g":115},"11302":{"m":114,"g":115},"11068":{"m":114,"g":115},"11301":{"m":114,"g":115},"11300":{"m":114,"g":115},"11290":{"m":114,"g":115},"11210":{"m":114,"g":115},"11231":{"m":114,"g":115},"11294":{"m":114,"g":115},"10949":{"m":114,"g":115},"11095":{"m":114,"g":115},"11283":{"m":114,"g":115},"11281":{"m":114,"g":115},"11286":{"m":114,"g":115},"11282":{"m":114,"g":115},"11261":{"m":114,"g":115},"11238":{"m":114,"g":115},"11279":{"m":114,"g":115},"11280":{"m":114,"g":115},"11276":{"m":114,"g":115},"11277":{"m":114,"g":115},"11182":{"m":114,"g":115},"11268":{"m":114,"g":115},"11274":{"m":114,"g":115},"11270":{"m":114,"g":115},"7149":{"m":114,"g":115},"11262":{"m":114,"g":115},"11219":{"m":114,"g":115},"11680":{"m":116,"g":118},"11676":{"m":116,"g":118},"11684":{"m":116,"g":118},"11667":{"m":116,"g":118},"11674":{"m":116,"g":118},"11681":{"m":116,"g":118},"11621":{"m":116,"g":118},"11367":{"m":116,"g":118},"11653":{"m":116,"g":118},"11660":{"m":116,"g":118},"11659":{"m":116,"g":118},"11585":{"m":116,"g":118},"11293":{"m":116,"g":118},"11458":{"m":116,"g":118},"11590":{"m":116,"g":118},"11636":{"m":116,"g":118},"11579":{"m":116,"g":118},"8247":{"m":116,"g":118},"10423":{"m":116,"g":118},"11642":{"m":116,"g":115},"11638":{"m":116,"g":115},"11628":{"m":116,"g":115},"11639":{"m":116,"g":115},"11351":{"m":116,"g":115},"11627":{"m":116,"g":115},"11633":{"m":116,"g":115},"11631":{"m":116,"g":115},"11622":{"m":116,"g":115},"11625":{"m":116,"g":115},"11623":{"m":116,"g":115},"11624":{"m":116,"g":115},"11619":{"m":116,"g":115},"11605":{"m":116,"g":115},"11620":{"m":116,"g":115},"11617":{"m":116,"g":115},"11453":{"m":116,"g":115},"11561":{"m":116,"g":115},"11434":{"m":116,"g":115},"10721":{"m":116,"g":115},"11586":{"m":116,"g":115},"11556":{"m":116,"g":115},"11603":{"m":116,"g":115},"11593":{"m":116,"g":115},"11601":{"m":116,"g":115},"11449":{"m":116,"g":115},"11600":{"m":116,"g":115},"11597":{"m":116,"g":115},"11598":{"m":116,"g":115},"11566":{"m":116,"g":115},"11591":{"m":116,"g":115},"11588":{"m":116,"g":115},"11587":{"m":116,"g":115},"11580":{"m":116,"g":115},"11583":{"m":116,"g":115},"11582":{"m":116,"g":115},"11041":{"m":116,"g":115},"11542":{"m":116,"g":115},"11535":{"m":116,"g":115},"11565":{"m":116,"g":115},"11413":{"m":116,"g":115},"11539":{"m":116,"g":115},"11572":{"m":116,"g":115},"11573":{"m":116,"g":115},"11534":{"m":116,"g":115},"11571":{"m":116,"g":115},"11564":{"m":116,"g":115},"11537":{"m":116,"g":115},"11538":{"m":116,"g":115},"11521":{"m":116,"g":115},"11562":{"m":116,"g":115},"11308":{"m":116,"g":115},"11557":{"m":116,"g":115},"11441":{"m":116,"g":115},"11483":{"m":116,"g":115},"11531":{"m":116,"g":115},"11549":{"m":116,"g":115},"11553":{"m":116,"g":115},"11547":{"m":116,"g":115},"11507":{"m":116,"g":115},"11419":{"m":116,"g":115},"11444":{"m":116,"g":115},"11442":{"m":116,"g":115},"11548":{"m":116,"g":115},"11530":{"m":116,"g":115},"11527":{"m":116,"g":115},"11201":{"m":116,"g":115},"11528":{"m":116,"g":115},"11457":{"m":116,"g":115},"11544":{"m":116,"g":115},"11460":{"m":116,"g":115},"11505":{"m":116,"g":115},"11385":{"m":116,"g":115},"11214":{"m":116,"g":115},"11493":{"m":116,"g":115},"11512":{"m":116,"g":115},"11432":{"m":116,"g":115},"11485":{"m":116,"g":115},"11511":{"m":116,"g":115},"5889":{"m":116,"g":115},"11520":{"m":116,"g":115},"11516":{"m":116,"g":115},"11498":{"m":116,"g":115},"11474":{"m":116,"g":115},"11515":{"m":116,"g":115},"11514":{"m":116,"g":115},"11331":{"m":116,"g":115},"11509":{"m":116,"g":115},"11443":{"m":116,"g":115},"11452":{"m":116,"g":115},"11503":{"m":116,"g":115},"11502":{"m":116,"g":115},"11497":{"m":116,"g":115},"11501":{"m":116,"g":115},"11500":{"m":116,"g":115},"11332":{"m":116,"g":115},"11499":{"m":116,"g":115},"11465":{"m":116,"g":115},"10577":{"m":116,"g":115},"11479":{"m":116,"g":115},"11221":{"m":116,"g":115},"10172":{"m":116,"g":115},"11478":{"m":116,"g":115},"11481":{"m":116,"g":115},"11476":{"m":116,"g":115},"11489":{"m":116,"g":115},"10062":{"m":116,"g":115},"11398":{"m":116,"g":115},"10635":{"m":116,"g":115},"9804":{"m":116,"g":115},"11454":{"m":116,"g":115},"11019":{"m":116,"g":115},"8919":{"m":116,"g":115},"11462":{"m":116,"g":115},"11428":{"m":116,"g":115},"11470":{"m":116,"g":115},"11427":{"m":116,"g":115},"11467":{"m":116,"g":115},"11448":{"m":116,"g":115},"10312":{"m":116,"g":115},"9991":{"m":116,"g":115},"11455":{"m":116,"g":115},"11450":{"m":116,"g":115},"11360":{"m":116,"g":115},"11368":{"m":116,"g":115},"11445":{"m":116,"g":115},"11438":{"m":116,"g":115},"11439":{"m":116,"g":115},"11399":{"m":116,"g":115},"11435":{"m":116,"g":115},"11313":{"m":116,"g":115},"10745":{"m":116,"g":115},"11411":{"m":116,"g":115},"11433":{"m":116,"g":115},"11437":{"m":116,"g":115},"11436":{"m":116,"g":115},"11345":{"m":116,"g":115},"9256":{"m":116,"g":115},"11381":{"m":116,"g":115},"11361":{"m":116,"g":115},"11420":{"m":116,"g":115},"11144":{"m":116,"g":115},"10734":{"m":116,"g":115},"10969":{"m":116,"g":115},"9045":{"m":116,"g":115},"11414":{"m":116,"g":115},"11388":{"m":116,"g":115},"11363":{"m":116,"g":115},"11365":{"m":116,"g":115},"11389":{"m":116,"g":115},"11401":{"m":116,"g":115},"11285":{"m":116,"g":115},"11693":{"m":117,"g":118},"11543":{"m":117,"g":118},"11687":{"m":117,"g":118},"11706":{"m":117,"g":118},"11510":{"m":117,"g":118},"11488":{"m":117,"g":118},"11370":{"m":117,"g":118},"11692":{"m":117,"g":118},"11663":{"m":117,"g":118},"10912":{"m":117,"g":118},"11679":{"m":117,"g":118},"11689":{"m":117,"g":118},"11686":{"m":117,"g":118},"10248":{"m":117,"g":118},"9493":{"m":117,"g":118},"12027":{"m":119,"g":121},"12009":{"m":119,"g":121},"12030":{"m":119,"g":121},"12029":{"m":119,"g":121},"11616":{"m":119,"g":121},"12028":{"m":119,"g":121},"9366":{"m":119,"g":121},"11891":{"m":119,"g":121},"10158":{"m":119,"g":121},"12024":{"m":119,"g":121},"11765":{"m":119,"g":121},"12022":{"m":119,"g":121},"12018":{"m":119,"g":121},"12021":{"m":119,"g":121},"11755":{"m":119,"g":121},"11981":{"m":119,"g":121},"12015":{"m":119,"g":121},"12014":{"m":119,"g":121},"11937":{"m":119,"g":121},"11988":{"m":119,"g":121},"11866":{"m":119,"g":121},"11821":{"m":119,"g":121},"12004":{"m":119,"g":121},"11985":{"m":119,"g":121},"11944":{"m":119,"g":121},"10652":{"m":119,"g":121},"11965":{"m":119,"g":121},"11906":{"m":119,"g":121},"11990":{"m":119,"g":121},"11299":{"m":119,"g":121},"11322":{"m":119,"g":121},"11811":{"m":119,"g":121},"11955":{"m":119,"g":121},"11978":{"m":119,"g":121},"10869":{"m":119,"g":121},"11921":{"m":119,"g":121},"11563":{"m":119,"g":121},"11980":{"m":119,"g":121},"11977":{"m":119,"g":121},"10750":{"m":119,"g":121},"11956":{"m":119,"g":121},"11723":{"m":119,"g":121},"11967":{"m":119,"g":121},"11953":{"m":119,"g":121},"9651":{"m":119,"g":121},"10606":{"m":119,"g":121},"11908":{"m":119,"g":121},"10154":{"m":119,"g":121},"11929":{"m":119,"g":121},"11717":{"m":119,"g":121},"11922":{"m":119,"g":121},"11945":{"m":119,"g":121},"11790":{"m":119,"g":121},"11926":{"m":119,"g":121},"11940":{"m":119,"g":121},"11935":{"m":119,"g":121},"11934":{"m":119,"g":121},"11377":{"m":119,"g":121},"11933":{"m":119,"g":121},"11876":{"m":119,"g":121},"11844":{"m":119,"g":121},"11287":{"m":119,"g":121},"11918":{"m":119,"g":121},"11915":{"m":119,"g":121},"11702":{"m":119,"g":121},"11482":{"m":119,"g":121},"10700":{"m":119,"g":121},"11902":{"m":119,"g":121},"11295":{"m":119,"g":121},"11416":{"m":119,"g":121},"11895":{"m":119,"g":121},"11570":{"m":119,"g":121},"11487":{"m":119,"g":121},"11878":{"m":119,"g":121},"11885":{"m":119,"g":118},"11664":{"m":119,"g":118},"10656":{"m":119,"g":118},"11843":{"m":119,"g":118},"11845":{"m":119,"g":118},"11859":{"m":119,"g":118},"11887":{"m":119,"g":118},"11838":{"m":119,"g":118},"11886":{"m":119,"g":118},"11826":{"m":119,"g":118},"11882":{"m":119,"g":118},"11875":{"m":119,"g":118},"11881":{"m":119,"g":118},"11868":{"m":119,"g":118},"11807":{"m":119,"g":118},"11867":{"m":119,"g":118},"11823":{"m":119,"g":118},"11847":{"m":119,"g":118},"11862":{"m":119,"g":118},"10691":{"m":119,"g":118},"11776":{"m":119,"g":118},"11822":{"m":119,"g":118},"11849":{"m":119,"g":118},"11396":{"m":119,"g":118},"11846":{"m":119,"g":118},"11747":{"m":119,"g":118},"10801":{"m":119,"g":118},"11722":{"m":119,"g":118},"11594":{"m":119,"g":118},"11780":{"m":119,"g":118},"11733":{"m":119,"g":118},"10510":{"m":119,"g":118},"11508":{"m":119,"g":118},"11787":{"m":119,"g":118},"11832":{"m":119,"g":118},"11778":{"m":119,"g":118},"11612":{"m":119,"g":118},"11810":{"m":119,"g":118},"11831":{"m":119,"g":118},"11815":{"m":119,"g":118},"11606":{"m":119,"g":118},"11835":{"m":119,"g":118},"10994":{"m":119,"g":118},"11147":{"m":119,"g":118},"11833":{"m":119,"g":118},"11834":{"m":119,"g":118},"11652":{"m":119,"g":118},"11819":{"m":119,"g":118},"11827":{"m":119,"g":118},"11805":{"m":119,"g":118},"5162":{"m":119,"g":118},"11786":{"m":119,"g":118},"11804":{"m":119,"g":118},"11808":{"m":119,"g":118},"11091":{"m":119,"g":118},"11818":{"m":119,"g":118},"10788":{"m":119,"g":118},"11817":{"m":119,"g":118},"11328":{"m":119,"g":118},"11555":{"m":119,"g":118},"11618":{"m":119,"g":118},"11670":{"m":119,"g":118},"11688":{"m":119,"g":118},"11773":{"m":119,"g":118},"11813":{"m":119,"g":118},"11000":{"m":119,"g":118},"11710":{"m":119,"g":118},"11749":{"m":119,"g":118},"11772":{"m":119,"g":118},"11506":{"m":119,"g":118},"11797":{"m":119,"g":118},"11781":{"m":119,"g":118},"11803":{"m":119,"g":118},"11801":{"m":119,"g":118},"10152":{"m":119,"g":118},"11669":{"m":119,"g":118},"11793":{"m":119,"g":118},"11665":{"m":119,"g":118},"11799":{"m":119,"g":118},"11798":{"m":119,"g":118},"11794":{"m":119,"g":118},"11784":{"m":119,"g":118},"11783":{"m":119,"g":118},"11614":{"m":119,"g":118},"11788":{"m":119,"g":118},"9170":{"m":119,"g":118},"11666":{"m":119,"g":118},"11613":{"m":119,"g":118},"11611":{"m":119,"g":118},"11607":{"m":119,"g":118},"11685":{"m":119,"g":118},"11519":{"m":119,"g":118},"11782":{"m":119,"g":118},"11777":{"m":119,"g":118},"11682":{"m":119,"g":118},"11775":{"m":119,"g":118},"11738":{"m":119,"g":118},"10725":{"m":119,"g":118},"11540":{"m":119,"g":118},"11767":{"m":119,"g":118},"11768":{"m":119,"g":118},"11766":{"m":119,"g":118},"11735":{"m":119,"g":118},"11730":{"m":119,"g":118},"11643":{"m":119,"g":118},"11062":{"m":119,"g":118},"11724":{"m":119,"g":118},"11746":{"m":119,"g":118},"11739":{"m":119,"g":118},"11740":{"m":119,"g":118},"11732":{"m":119,"g":118},"11734":{"m":119,"g":118},"11541":{"m":119,"g":118},"11728":{"m":119,"g":118},"11731":{"m":119,"g":118},"11727":{"m":119,"g":118},"11729":{"m":119,"g":118},"11677":{"m":119,"g":118},"10911":{"m":119,"g":118},"12169":{"m":120,"g":121},"12177":{"m":120,"g":121},"12170":{"m":120,"g":121},"12167":{"m":120,"g":121},"12171":{"m":120,"g":121},"12164":{"m":120,"g":121},"12168":{"m":120,"g":121},"12129":{"m":120,"g":121},"12166":{"m":120,"g":121},"11047":{"m":120,"g":121},"11632":{"m":120,"g":121},"10399":{"m":120,"g":121},"12142":{"m":120,"g":121},"12106":{"m":120,"g":121},"12156":{"m":120,"g":121},"12155":{"m":120,"g":121},"12152":{"m":120,"g":121},"12154":{"m":120,"g":121},"11615":{"m":120,"g":121},"11494":{"m":120,"g":121},"12113":{"m":120,"g":121},"12116":{"m":120,"g":121},"12136":{"m":120,"g":121},"12147":{"m":120,"g":121},"12141":{"m":120,"g":121},"11991":{"m":120,"g":121},"12097":{"m":120,"g":121},"12139":{"m":120,"g":121},"12138":{"m":120,"g":121},"12118":{"m":120,"g":121},"12133":{"m":120,"g":121},"11936":{"m":120,"g":121},"12132":{"m":120,"g":121},"11993":{"m":120,"g":121},"12130":{"m":120,"g":121},"12125":{"m":120,"g":121},"12101":{"m":120,"g":121},"11814":{"m":120,"g":121},"12127":{"m":120,"g":121},"12115":{"m":120,"g":121},"12126":{"m":120,"g":121},"12098":{"m":120,"g":121},"11962":{"m":120,"g":121},"12119":{"m":120,"g":121},"12124":{"m":120,"g":121},"11869":{"m":120,"g":121},"12110":{"m":120,"g":121},"12096":{"m":120,"g":121},"12083":{"m":120,"g":121},"12103":{"m":120,"g":121},"12105":{"m":120,"g":121},"12087":{"m":120,"g":121},"9501":{"m":120,"g":121},"11379":{"m":120,"g":121},"12058":{"m":120,"g":121},"12054":{"m":120,"g":121},"11877":{"m":120,"g":121},"12070":{"m":120,"g":121},"8464":{"m":120,"g":121},"12093":{"m":120,"g":121},"12071":{"m":120,"g":121},"12000":{"m":120,"g":121},"12091":{"m":120,"g":121},"12089":{"m":120,"g":121},"12086":{"m":120,"g":121},"11560":{"m":120,"g":121},"12084":{"m":120,"g":121},"12034":{"m":120,"g":121},"11924":{"m":120,"g":121},"11884":{"m":120,"g":121},"12025":{"m":120,"g":121},"11958":{"m":120,"g":121},"12067":{"m":120,"g":121},"11999":{"m":120,"g":121},"12046":{"m":120,"g":121},"12049":{"m":120,"g":121},"12063":{"m":120,"g":121},"12064":{"m":120,"g":121},"12053":{"m":120,"g":121},"11800":{"m":120,"g":121},"12056":{"m":120,"g":121},"12019":{"m":120,"g":121},"11853":{"m":120,"g":121},"12031":{"m":120,"g":121},"12041":{"m":120,"g":121},"10953":{"m":120,"g":121},"11759":{"m":120,"g":121},"12042":{"m":120,"g":121},"12037":{"m":120,"g":121},"11745":{"m":120,"g":121},"12038":{"m":120,"g":121},"11909":{"m":120,"g":121},"11816":{"m":120,"g":121},"11795":{"m":120,"g":121},"12003":{"m":120,"g":121},"9936":{"m":120,"g":121},"11964":{"m":120,"g":121},"12439":{"m":122,"g":127},"11874":{"m":122,"g":127},"12475":{"m":122,"g":127},"12469":{"m":122,"g":127},"11987":{"m":122,"g":127},"12430":{"m":122,"g":127},"12473":{"m":122,"g":127},"12297":{"m":122,"g":127},"12341":{"m":122,"g":127},"12428":{"m":122,"g":127},"12429":{"m":122,"g":127},"12066":{"m":122,"g":127},"12275":{"m":122,"g":127},"11757":{"m":122,"g":127},"11931":{"m":122,"g":127},"12470":{"m":122,"g":127},"12415":{"m":122,"g":127},"12266":{"m":122,"g":127},"12463":{"m":122,"g":127},"12328":{"m":122,"g":127},"12369":{"m":122,"g":127},"12256":{"m":122,"g":127},"12449":{"m":122,"g":127},"12452":{"m":122,"g":127},"12413":{"m":122,"g":127},"10889":{"m":122,"g":127},"12422":{"m":122,"g":127},"12436":{"m":122,"g":127},"12437":{"m":122,"g":127},"12410":{"m":122,"g":127},"12384":{"m":122,"g":127},"12307":{"m":122,"g":127},"10566":{"m":122,"g":127},"12405":{"m":122,"g":127},"12425":{"m":122,"g":127},"12401":{"m":122,"g":127},"12300":{"m":122,"g":127},"11224":{"m":122,"g":127},"11116":{"m":122,"g":127},"12399":{"m":122,"g":121},"12290":{"m":122,"g":121},"12242":{"m":122,"g":121},"12368":{"m":122,"g":121},"12403":{"m":122,"g":121},"12386":{"m":122,"g":121},"12409":{"m":122,"g":121},"12375":{"m":122,"g":121},"12404":{"m":122,"g":121},"12281":{"m":122,"g":121},"12185":{"m":122,"g":121},"12012":{"m":122,"g":121},"12364":{"m":122,"g":121},"12395":{"m":122,"g":121},"11960":{"m":122,"g":121},"12377":{"m":122,"g":121},"11897":{"m":122,"g":121},"11969":{"m":122,"g":121},"12394":{"m":122,"g":121},"11806":{"m":122,"g":121},"12319":{"m":122,"g":121},"12123":{"m":122,"g":121},"12358":{"m":122,"g":121},"12362":{"m":122,"g":121},"12135":{"m":122,"g":121},"12378":{"m":122,"g":121},"12174":{"m":122,"g":121},"12340":{"m":122,"g":121},"12195":{"m":122,"g":121},"11910":{"m":122,"g":121},"12216":{"m":122,"g":121},"12050":{"m":122,"g":121},"12153":{"m":122,"g":121},"12094":{"m":122,"g":121},"12182":{"m":122,"g":121},"12354":{"m":122,"g":121},"12350":{"m":122,"g":121},"12348":{"m":122,"g":121},"11737":{"m":122,"g":121},"12346":{"m":122,"g":121},"12325":{"m":122,"g":121},"12095":{"m":122,"g":121},"12347":{"m":122,"g":121},"12345":{"m":122,"g":121},"11709":{"m":122,"g":121},"12343":{"m":122,"g":121},"12315":{"m":122,"g":121},"12338":{"m":122,"g":121},"11673":{"m":122,"g":121},"12002":{"m":122,"g":121},"12336":{"m":122,"g":121},"12312":{"m":122,"g":121},"12317":{"m":122,"g":121},"12276":{"m":122,"g":121},"12294":{"m":122,"g":121},"12314":{"m":122,"g":121},"12144":{"m":122,"g":121},"10874":{"m":122,"g":121},"12269":{"m":122,"g":121},"9825":{"m":122,"g":121},"12313":{"m":122,"g":121},"12311":{"m":122,"g":121},"12259":{"m":122,"g":121},"12241":{"m":122,"g":121},"12308":{"m":122,"g":121},"12299":{"m":122,"g":121},"12271":{"m":122,"g":121},"12296":{"m":122,"g":121},"12295":{"m":122,"g":121},"12285":{"m":122,"g":121},"12233":{"m":122,"g":121},"11928":{"m":122,"g":121},"12188":{"m":122,"g":121},"12283":{"m":122,"g":121},"12231":{"m":122,"g":121},"12284":{"m":122,"g":121},"12274":{"m":122,"g":121},"12257":{"m":122,"g":121},"12268":{"m":122,"g":121},"12267":{"m":122,"g":121},"12206":{"m":122,"g":121},"12247":{"m":122,"g":121},"10804":{"m":122,"g":121},"12230":{"m":122,"g":121},"12229":{"m":122,"g":121},"12252":{"m":122,"g":121},"12249":{"m":122,"g":121},"7873":{"m":122,"g":121},"10567":{"m":122,"g":121},"11177":{"m":122,"g":121},"11655":{"m":122,"g":121},"12245":{"m":122,"g":121},"11517":{"m":122,"g":121},"10654":{"m":122,"g":121},"12222":{"m":122,"g":121},"11994":{"m":122,"g":121},"12176":{"m":122,"g":121},"11708":{"m":122,"g":121},"12235":{"m":122,"g":121},"12161":{"m":122,"g":121},"12234":{"m":122,"g":121},"11142":{"m":122,"g":121},"12006":{"m":122,"g":121},"11592":{"m":122,"g":121},"11656":{"m":122,"g":121},"12186":{"m":122,"g":121},"12209":{"m":122,"g":121},"12205":{"m":122,"g":121},"12107":{"m":122,"g":121},"12112":{"m":122,"g":121},"10153":{"m":122,"g":121},"12117":{"m":122,"g":121},"12080":{"m":122,"g":121},"9403":{"m":122,"g":121},"12192":{"m":122,"g":121},"12173":{"m":122,"g":121},"12159":{"m":122,"g":121},"12057":{"m":122,"g":121},"12639":{"m":123,"g":127},"12572":{"m":123,"g":127},"12656":{"m":123,"g":127},"12456":{"m":123,"g":127},"12585":{"m":123,"g":127},"12648":{"m":123,"g":127},"12650":{"m":123,"g":127},"12640":{"m":123,"g":127},"12645":{"m":123,"g":127},"12647":{"m":123,"g":127},"12642":{"m":123,"g":127},"12641":{"m":123,"g":127},"12628":{"m":123,"g":127},"12634":{"m":123,"g":127},"12633":{"m":123,"g":127},"12632":{"m":123,"g":127},"12593":{"m":123,"g":127},"12616":{"m":123,"g":127},"12594":{"m":123,"g":127},"12592":{"m":123,"g":127},"11456":{"m":123,"g":127},"12615":{"m":123,"g":127},"12599":{"m":123,"g":127},"12522":{"m":123,"g":127},"10183":{"m":123,"g":127},"12598":{"m":123,"g":127},"6318":{"m":123,"g":127},"11131":{"m":123,"g":127},"11974":{"m":123,"g":127},"12580":{"m":123,"g":127},"12597":{"m":123,"g":127},"11760":{"m":123,"g":127},"12462":{"m":123,"g":127},"12165":{"m":123,"g":127},"12111":{"m":123,"g":127},"12547":{"m":123,"g":127},"12270":{"m":123,"g":127},"12044":{"m":123,"g":127},"12519":{"m":123,"g":127},"12571":{"m":123,"g":127},"12301":{"m":123,"g":127},"12569":{"m":123,"g":127},"12550":{"m":123,"g":127},"12549":{"m":123,"g":127},"12553":{"m":123,"g":127},"12524":{"m":123,"g":127},"12560":{"m":123,"g":127},"12227":{"m":123,"g":127},"12548":{"m":123,"g":127},"11330":{"m":123,"g":127},"12564":{"m":123,"g":127},"12561":{"m":123,"g":127},"12060":{"m":123,"g":127},"12536":{"m":123,"g":127},"12541":{"m":123,"g":127},"12532":{"m":123,"g":127},"12530":{"m":123,"g":127},"12523":{"m":123,"g":127},"12367":{"m":123,"g":127},"12502":{"m":123,"g":127},"12521":{"m":123,"g":127},"12515":{"m":123,"g":127},"12453":{"m":123,"g":127},"12481":{"m":123,"g":127},"12506":{"m":123,"g":127},"11917":{"m":123,"g":127},"12511":{"m":123,"g":127},"10078":{"m":123,"g":127},"12505":{"m":123,"g":127},"12507":{"m":123,"g":127},"11133":{"m":123,"g":127},"11052":{"m":123,"g":127},"12499":{"m":123,"g":127},"12391":{"m":123,"g":127},"12488":{"m":123,"g":127},"12412":{"m":123,"g":127},"11966":{"m":123,"g":127},"12238":{"m":123,"g":127},"12423":{"m":123,"g":127},"12500":{"m":123,"g":127},"12480":{"m":123,"g":127},"12485":{"m":123,"g":127},"12435":{"m":123,"g":127},"12483":{"m":123,"g":127},"12482":{"m":123,"g":127},"12226":{"m":123,"g":127},"12334":{"m":123,"g":127},"12739":{"m":124,"g":127},"12778":{"m":124,"g":127},"12440":{"m":124,"g":127},"12760":{"m":124,"g":127},"12565":{"m":124,"g":127},"12674":{"m":124,"g":127},"12646":{"m":124,"g":127},"12240":{"m":124,"g":127},"12508":{"m":124,"g":127},"12737":{"m":124,"g":127},"12693":{"m":124,"g":127},"12752":{"m":124,"g":127},"12744":{"m":124,"g":127},"12736":{"m":124,"g":127},"12748":{"m":124,"g":127},"12741":{"m":124,"g":127},"12742":{"m":124,"g":127},"12738":{"m":124,"g":127},"11892":{"m":124,"g":127},"12721":{"m":124,"g":127},"12734":{"m":124,"g":127},"12723":{"m":124,"g":127},"12716":{"m":124,"g":127},"12732":{"m":124,"g":127},"12611":{"m":124,"g":127},"12728":{"m":124,"g":127},"12729":{"m":124,"g":127},"12718":{"m":124,"g":127},"12651":{"m":124,"g":127},"12711":{"m":124,"g":127},"12713":{"m":124,"g":127},"12714":{"m":124,"g":127},"12712":{"m":124,"g":127},"12658":{"m":124,"g":127},"12673":{"m":124,"g":127},"12710":{"m":124,"g":127},"12709":{"m":124,"g":127},"12406":{"m":124,"g":127},"12586":{"m":124,"g":127},"12631":{"m":124,"g":127},"12699":{"m":124,"g":127},"12484":{"m":124,"g":127},"12677":{"m":124,"g":127},"12696":{"m":124,"g":127},"12708":{"m":124,"g":127},"12609":{"m":124,"g":127},"12702":{"m":124,"g":127},"12455":{"m":124,"g":127},"12691":{"m":124,"g":127},"12687":{"m":124,"g":127},"11641":{"m":124,"g":127},"12680":{"m":124,"g":127},"10044":{"m":124,"g":127},"12668":{"m":124,"g":127},"12175":{"m":124,"g":127},"12670":{"m":124,"g":127},"8784":{"m":124,"g":127},"12486":{"m":124,"g":127},"12638":{"m":124,"g":127},"12353":{"m":124,"g":127},"13000":{"m":125,"g":127},"12908":{"m":125,"g":127},"12952":{"m":125,"g":127},"13010":{"m":125,"g":127},"11850":{"m":125,"g":127},"12781":{"m":125,"g":127},"12224":{"m":125,"g":127},"13013":{"m":125,"g":127},"13009":{"m":125,"g":127},"13001":{"m":125,"g":127},"13005":{"m":125,"g":127},"12996":{"m":125,"g":127},"12999":{"m":125,"g":127},"12966":{"m":125,"g":127},"12984":{"m":125,"g":127},"12982":{"m":125,"g":127},"10225":{"m":125,"g":127},"10702":{"m":125,"g":127},"11719":{"m":125,"g":127},"12916":{"m":125,"g":127},"12239":{"m":125,"g":127},"12883":{"m":125,"g":127},"12912":{"m":125,"g":127},"12604":{"m":125,"g":127},"12934":{"m":125,"g":127},"9528":{"m":125,"g":127},"12931":{"m":125,"g":127},"12959":{"m":125,"g":127},"12926":{"m":125,"g":127},"12803":{"m":125,"g":127},"12957":{"m":125,"g":127},"12943":{"m":125,"g":127},"12834":{"m":125,"g":127},"12956":{"m":125,"g":127},"12554":{"m":125,"g":127},"12946":{"m":125,"g":127},"12948":{"m":125,"g":127},"12940":{"m":125,"g":127},"11812":{"m":125,"g":127},"12928":{"m":125,"g":127},"12927":{"m":125,"g":127},"12839":{"m":125,"g":127},"10775":{"m":125,"g":127},"12917":{"m":125,"g":127},"12920":{"m":125,"g":127},"12332":{"m":125,"g":127},"12919":{"m":125,"g":127},"12448":{"m":125,"g":127},"12906":{"m":125,"g":127},"12907":{"m":125,"g":127},"12911":{"m":125,"g":127},"12895":{"m":125,"g":127},"12905":{"m":125,"g":127},"12904":{"m":125,"g":127},"12865":{"m":125,"g":127},"12900":{"m":125,"g":127},"12896":{"m":125,"g":127},"12891":{"m":125,"g":127},"12897":{"m":125,"g":127},"12889":{"m":125,"g":127},"12870":{"m":125,"g":127},"12361":{"m":125,"g":127},"12811":{"m":125,"g":127},"12888":{"m":125,"g":127},"12832":{"m":125,"g":127},"12843":{"m":125,"g":127},"12886":{"m":125,"g":127},"12798":{"m":125,"g":127},"12868":{"m":125,"g":127},"12853":{"m":125,"g":127},"12846":{"m":125,"g":127},"12582":{"m":125,"g":127},"12805":{"m":125,"g":127},"12849":{"m":125,"g":127},"12859":{"m":125,"g":127},"12852":{"m":125,"g":127},"12851":{"m":125,"g":127},"12856":{"m":125,"g":127},"12801":{"m":125,"g":127},"12822":{"m":125,"g":127},"12431":{"m":125,"g":127},"12825":{"m":125,"g":127},"12836":{"m":125,"g":127},"12374":{"m":125,"g":127},"12812":{"m":125,"g":127},"12816":{"m":125,"g":127},"12090":{"m":125,"g":127},"12758":{"m":125,"g":127},"12520":{"m":125,"g":127},"12765":{"m":125,"g":127},"12761":{"m":125,"g":127},"12763":{"m":125,"g":127},"12776":{"m":125,"g":127},"12772":{"m":125,"g":127},"12788":{"m":125,"g":127},"12576":{"m":125,"g":127},"12782":{"m":125,"g":127},"12794":{"m":125,"g":127},"12715":{"m":125,"g":127},"12795":{"m":125,"g":127},"12724":{"m":125,"g":127},"12279":{"m":125,"g":127},"12717":{"m":125,"g":127},"8243":{"m":125,"g":127},"11904":{"m":125,"g":127},"12684":{"m":125,"g":127},"12764":{"m":125,"g":127},"12363":{"m":125,"g":127},"11051":{"m":125,"g":127},"12749":{"m":125,"g":127},"13129":{"m":126,"g":127},"10808":{"m":126,"g":127},"12617":{"m":126,"g":127},"7906":{"m":126,"g":127},"13149":{"m":126,"g":127},"7886":{"m":126,"g":127},"9790":{"m":126,"g":127},"13120":{"m":126,"g":127},"12458":{"m":126,"g":127},"11961":{"m":126,"g":127},"13137":{"m":126,"g":127},"12860":{"m":126,"g":127},"13136":{"m":126,"g":127},"13135":{"m":126,"g":127},"13077":{"m":126,"g":127},"13132":{"m":126,"g":127},"13131":{"m":126,"g":127},"13133":{"m":126,"g":127},"12942":{"m":126,"g":127},"12817":{"m":126,"g":127},"13095":{"m":126,"g":127},"12666":{"m":126,"g":127},"12396":{"m":126,"g":127},"13118":{"m":126,"g":127},"12872":{"m":126,"g":127},"12997":{"m":126,"g":127},"12863":{"m":126,"g":127},"13114":{"m":126,"g":127},"13039":{"m":126,"g":127},"11856":{"m":126,"g":127},"13105":{"m":126,"g":127},"13056":{"m":126,"g":127},"12583":{"m":126,"g":127},"13093":{"m":126,"g":127},"12660":{"m":126,"g":127},"13090":{"m":126,"g":127},"12866":{"m":126,"g":127},"12915":{"m":126,"g":127},"13018":{"m":126,"g":127},"13092":{"m":126,"g":127},"11645":{"m":126,"g":127},"13041":{"m":126,"g":127},"10862":{"m":126,"g":127},"13088":{"m":126,"g":127},"12814":{"m":126,"g":127},"12941":{"m":126,"g":127},"12994":{"m":126,"g":127},"13076":{"m":126,"g":127},"13015":{"m":126,"g":127},"13063":{"m":126,"g":127},"12199":{"m":126,"g":127},"12983":{"m":126,"g":127},"13037":{"m":126,"g":127},"12689":{"m":126,"g":127},"11609":{"m":126,"g":127},"12976":{"m":126,"g":127},"13050":{"m":126,"g":127},"12980":{"m":126,"g":127},"11938":{"m":126,"g":127},"13057":{"m":126,"g":127},"13053":{"m":126,"g":127},"13036":{"m":126,"g":127},"13043":{"m":126,"g":127},"13029":{"m":126,"g":127},"12885":{"m":126,"g":127},"12518":{"m":126,"g":127},"13035":{"m":126,"g":127},"13027":{"m":126,"g":127},"13028":{"m":126,"g":127},"12218":{"m":126,"g":127},"12753":{"m":126,"g":127},"12869":{"m":126,"g":127},"12993":{"m":126,"g":127},"13012":{"m":126,"g":127},"13366":{"m":128,"g":131},"13389":{"m":128,"g":131},"13387":{"m":128,"g":131},"12903":{"m":128,"g":131},"13388":{"m":128,"g":131},"12874":{"m":128,"g":131},"13386":{"m":128,"g":131},"13385":{"m":128,"g":131},"13384":{"m":128,"g":131},"13381":{"m":128,"g":131},"13335":{"m":128,"g":131},"13228":{"m":128,"g":131},"13371":{"m":128,"g":131},"13339":{"m":128,"g":131},"12978":{"m":128,"g":131},"13332":{"m":128,"g":131},"13263":{"m":128,"g":131},"13375":{"m":128,"g":131},"13344":{"m":128,"g":131},"13373":{"m":128,"g":131},"13372":{"m":128,"g":131},"13336":{"m":128,"g":131},"13369":{"m":128,"g":131},"13348":{"m":128,"g":131},"13199":{"m":128,"g":131},"13179":{"m":128,"g":131},"12310":{"m":128,"g":131},"11870":{"m":128,"g":131},"13358":{"m":128,"g":131},"13101":{"m":128,"g":131},"13321":{"m":128,"g":131},"13355":{"m":128,"g":131},"13351":{"m":128,"g":131},"13181":{"m":128,"g":131},"13341":{"m":128,"g":131},"13325":{"m":128,"g":131},"12329":{"m":128,"g":131},"13337":{"m":128,"g":131},"12001":{"m":128,"g":131},"12692":{"m":128,"g":131},"12443":{"m":128,"g":131},"13331":{"m":128,"g":131},"13330":{"m":128,"g":131},"13329":{"m":128,"g":131},"10568":{"m":128,"g":131},"13306":{"m":128,"g":131},"13297":{"m":128,"g":131},"13326":{"m":128,"g":131},"13323":{"m":128,"g":131},"13287":{"m":128,"g":131},"13322":{"m":128,"g":131},"7415":{"m":128,"g":131},"13286":{"m":128,"g":131},"13285":{"m":128,"g":131},"13259":{"m":128,"g":131},"13320":{"m":128,"g":131},"13295":{"m":128,"g":131},"13318":{"m":128,"g":131},"13314":{"m":128,"g":131},"13226":{"m":128,"g":131},"13278":{"m":128,"g":131},"13279":{"m":128,"g":131},"12612":{"m":128,"g":131},"12871":{"m":128,"g":131},"13317":{"m":128,"g":131},"13294":{"m":128,"g":131},"13316":{"m":128,"g":131},"13315":{"m":128,"g":131},"13312":{"m":128,"g":127},"13091":{"m":128,"g":127},"13100":{"m":128,"g":127},"13311":{"m":128,"g":127},"13310":{"m":128,"g":127},"13045":{"m":128,"g":127},"13293":{"m":128,"g":127},"13305":{"m":128,"g":127},"13170":{"m":128,"g":127},"13298":{"m":128,"g":127},"13274":{"m":128,"g":127},"13235":{"m":128,"g":127},"13272":{"m":128,"g":127},"13260":{"m":128,"g":127},"10573":{"m":128,"g":127},"10665":{"m":128,"g":127},"13236":{"m":128,"g":127},"12777":{"m":128,"g":127},"13277":{"m":128,"g":127},"13288":{"m":128,"g":127},"13254":{"m":128,"g":127},"13284":{"m":128,"g":127},"13283":{"m":128,"g":127},"13242":{"m":128,"g":127},"12191":{"m":128,"g":127},"12605":{"m":128,"g":127},"12623":{"m":128,"g":127},"12622":{"m":128,"g":127},"12620":{"m":128,"g":127},"13113":{"m":128,"g":127},"13247":{"m":128,"g":127},"13237":{"m":128,"g":127},"13265":{"m":128,"g":127},"11589":{"m":128,"g":127},"13261":{"m":128,"g":127},"13256":{"m":128,"g":127},"13257":{"m":128,"g":127},"13255":{"m":128,"g":127},"13096":{"m":128,"g":127},"13221":{"m":128,"g":127},"13213":{"m":128,"g":127},"13246":{"m":128,"g":127},"13243":{"m":128,"g":127},"13186":{"m":128,"g":127},"13239":{"m":128,"g":127},"13097":{"m":128,"g":127},"12392":{"m":128,"g":127},"13222":{"m":128,"g":127},"13188":{"m":128,"g":127},"13218":{"m":128,"g":127},"13087":{"m":128,"g":127},"13142":{"m":128,"g":127},"11595":{"m":128,"g":127},"13210":{"m":128,"g":127},"12774":{"m":128,"g":127},"13211":{"m":128,"g":127},"13220":{"m":128,"g":127},"13171":{"m":128,"g":127},"13215":{"m":128,"g":127},"13212":{"m":128,"g":127},"10485":{"m":128,"g":127},"12543":{"m":128,"g":127},"12201":{"m":128,"g":127},"12376":{"m":128,"g":127},"13155":{"m":128,"g":127},"13148":{"m":128,"g":127},"13190":{"m":128,"g":127},"13178":{"m":128,"g":127},"13102":{"m":128,"g":127},"13154":{"m":128,"g":127},"12975":{"m":128,"g":127},"13163":{"m":128,"g":127},"13172":{"m":128,"g":127},"13150":{"m":128,"g":127},"10973":{"m":128,"g":127},"12288":{"m":128,"g":127},"13162":{"m":128,"g":127},"12215":{"m":128,"g":127},"13104":{"m":128,"g":127},"13164":{"m":128,"g":127},"13127":{"m":128,"g":127},"12979":{"m":128,"g":127},"13128":{"m":128,"g":127},"12998":{"m":128,"g":127},"13075":{"m":128,"g":127},"10907":{"m":128,"g":127},"13153":{"m":128,"g":127},"12214":{"m":128,"g":127},"14316":{"m":129,"g":131},"14324":{"m":129,"g":131},"14323":{"m":129,"g":131},"14317":{"m":129,"g":131},"14309":{"m":129,"g":131},"14319":{"m":129,"g":131},"14262":{"m":129,"g":131},"14315":{"m":129,"g":131},"14249":{"m":129,"g":131},"11423":{"m":129,"g":131},"14278":{"m":129,"g":131},"14299":{"m":129,"g":131},"13089":{"m":129,"g":131},"14133":{"m":129,"g":131},"14269":{"m":129,"g":131},"14281":{"m":129,"g":131},"14287":{"m":129,"g":131},"14286":{"m":129,"g":131},"14283":{"m":129,"g":131},"14252":{"m":129,"g":131},"14244":{"m":129,"g":131},"14279":{"m":129,"g":131},"14276":{"m":129,"g":131},"13738":{"m":129,"g":131},"14047":{"m":129,"g":131},"14274":{"m":129,"g":131},"14257":{"m":129,"g":131},"14254":{"m":129,"g":131},"13700":{"m":129,"g":131},"14267":{"m":129,"g":131},"14261":{"m":129,"g":131},"14172":{"m":129,"g":131},"14263":{"m":129,"g":131},"14259":{"m":129,"g":131},"14260":{"m":129,"g":131},"14222":{"m":129,"g":131},"14232":{"m":129,"g":131},"13968":{"m":129,"g":131},"14256":{"m":129,"g":131},"14255":{"m":129,"g":131},"13880":{"m":129,"g":131},"13794":{"m":129,"g":131},"14247":{"m":129,"g":131},"13843":{"m":129,"g":131},"14250":{"m":129,"g":131},"14245":{"m":129,"g":131},"14243":{"m":129,"g":131},"14241":{"m":129,"g":131},"14240":{"m":129,"g":131},"14237":{"m":129,"g":131},"14152":{"m":129,"g":131},"14179":{"m":129,"g":131},"14229":{"m":129,"g":131},"14230":{"m":129,"g":131},"13693":{"m":129,"g":131},"14228":{"m":129,"g":131},"14122":{"m":129,"g":131},"14088":{"m":129,"g":131},"13887":{"m":129,"g":131},"14219":{"m":129,"g":131},"14218":{"m":129,"g":131},"14214":{"m":129,"g":131},"14212":{"m":129,"g":131},"14211":{"m":129,"g":131},"14173":{"m":129,"g":131},"14165":{"m":129,"g":131},"14123":{"m":129,"g":131},"14186":{"m":129,"g":131},"14180":{"m":129,"g":131},"14167":{"m":129,"g":131},"14044":{"m":129,"g":131},"14182":{"m":129,"g":131},"14183":{"m":129,"g":131},"14181":{"m":129,"g":131},"14003":{"m":129,"g":131},"14034":{"m":129,"g":131},"14153":{"m":129,"g":131},"14187":{"m":129,"g":131},"12181":{"m":129,"g":131},"14155":{"m":129,"g":131},"14104":{"m":129,"g":131},"13873":{"m":129,"g":131},"14059":{"m":129,"g":131},"14140":{"m":129,"g":131},"13646":{"m":129,"g":131},"13841":{"m":129,"g":131},"14171":{"m":129,"g":131},"13907":{"m":129,"g":131},"14065":{"m":129,"g":131},"14166":{"m":129,"g":131},"14005":{"m":129,"g":131},"12494":{"m":129,"g":131},"14163":{"m":129,"g":131},"14156":{"m":129,"g":131},"14148":{"m":129,"g":131},"14161":{"m":129,"g":131},"14052":{"m":129,"g":131},"14150":{"m":129,"g":131},"14157":{"m":129,"g":131},"14154":{"m":129,"g":131},"14147":{"m":129,"g":131},"14146":{"m":129,"g":131},"14145":{"m":129,"g":131},"14136":{"m":129,"g":131},"13956":{"m":129,"g":131},"13759":{"m":129,"g":131},"14151":{"m":129,"g":131},"14135":{"m":129,"g":131},"14130":{"m":129,"g":131},"14119":{"m":129,"g":131},"14131":{"m":129,"g":131},"14129":{"m":129,"g":131},"14121":{"m":129,"g":131},"12306":{"m":129,"g":131},"14124":{"m":129,"g":131},"14113":{"m":129,"g":131},"14117":{"m":129,"g":131},"13377":{"m":129,"g":131},"13488":{"m":129,"g":131},"14111":{"m":129,"g":131},"12558":{"m":129,"g":131},"10712":{"m":129,"g":131},"14106":{"m":129,"g":131},"14067":{"m":129,"g":131},"14096":{"m":129,"g":131},"14094":{"m":129,"g":131},"13724":{"m":129,"g":131},"13904":{"m":129,"g":131},"14076":{"m":129,"g":131},"13936":{"m":129,"g":131},"14006":{"m":129,"g":131},"14082":{"m":129,"g":131},"13205":{"m":129,"g":131},"14079":{"m":129,"g":131},"14036":{"m":129,"g":131},"13944":{"m":129,"g":131},"13749":{"m":129,"g":131},"14069":{"m":129,"g":131},"13946":{"m":129,"g":131},"14048":{"m":129,"g":131},"13960":{"m":129,"g":131},"14057":{"m":129,"g":131},"13425":{"m":129,"g":131},"13854":{"m":129,"g":131},"14002":{"m":129,"g":131},"13855":{"m":129,"g":131},"14040":{"m":129,"g":131},"13895":{"m":129,"g":131},"13976":{"m":129,"g":131},"13814":{"m":129,"g":131},"13965":{"m":129,"g":131},"14026":{"m":129,"g":131},"14017":{"m":129,"g":131},"14033":{"m":129,"g":131},"14030":{"m":129,"g":131},"14028":{"m":129,"g":131},"13761":{"m":129,"g":131},"14027":{"m":129,"g":131},"14025":{"m":129,"g":131},"13824":{"m":129,"g":131},"12277":{"m":129,"g":131},"13941":{"m":129,"g":131},"13983":{"m":129,"g":131},"14018":{"m":129,"g":131},"14007":{"m":129,"g":131},"14022":{"m":129,"g":131},"14019":{"m":129,"g":131},"14021":{"m":129,"g":131},"13937":{"m":129,"g":131},"13990":{"m":129,"g":131},"14020":{"m":129,"g":131},"13966":{"m":129,"g":131},"13872":{"m":129,"g":131},"14016":{"m":129,"g":131},"14013":{"m":129,"g":131},"14015":{"m":129,"g":131},"14014":{"m":129,"g":131},"14012":{"m":129,"g":131},"13151":{"m":129,"g":131},"13892":{"m":129,"g":131},"14000":{"m":129,"g":131},"14009":{"m":129,"g":131},"13766":{"m":129,"g":131},"13754":{"m":129,"g":131},"12491":{"m":129,"g":131},"13994":{"m":129,"g":131},"13991":{"m":129,"g":131},"13977":{"m":129,"g":131},"13203":{"m":129,"g":131},"12588":{"m":129,"g":131},"13922":{"m":129,"g":131},"13852":{"m":129,"g":131},"13963":{"m":129,"g":131},"10071":{"m":129,"g":131},"13961":{"m":129,"g":131},"13962":{"m":129,"g":131},"13958":{"m":129,"g":131},"7725":{"m":129,"g":131},"13925":{"m":129,"g":131},"12786":{"m":129,"g":131},"13954":{"m":129,"g":131},"13951":{"m":129,"g":131},"13950":{"m":129,"g":131},"13945":{"m":129,"g":131},"13942":{"m":129,"g":131},"12969":{"m":129,"g":131},"13910":{"m":129,"g":131},"13866":{"m":129,"g":131},"13903":{"m":129,"g":131},"13421":{"m":129,"g":131},"13851":{"m":129,"g":131},"13544":{"m":129,"g":131},"13938":{"m":129,"g":131},"13935":{"m":129,"g":131},"13933":{"m":129,"g":131},"13859":{"m":129,"g":131},"13931":{"m":129,"g":131},"13928":{"m":129,"g":131},"13927":{"m":129,"g":131},"13657":{"m":129,"g":131},"13081":{"m":129,"g":131},"12078":{"m":129,"g":131},"13921":{"m":129,"g":131},"13905":{"m":129,"g":131},"13916":{"m":129,"g":131},"13642":{"m":129,"g":131},"13908":{"m":129,"g":131},"13848":{"m":129,"g":131},"13793":{"m":129,"g":131},"13901":{"m":129,"g":131},"13827":{"m":129,"g":131},"13889":{"m":129,"g":131},"13890":{"m":129,"g":131},"13888":{"m":129,"g":131},"11893":{"m":129,"g":131},"13891":{"m":129,"g":131},"13870":{"m":129,"g":131},"13874":{"m":129,"g":131},"13860":{"m":129,"g":131},"13871":{"m":129,"g":131},"13572":{"m":129,"g":131},"10275":{"m":129,"g":131},"13487":{"m":129,"g":131},"13786":{"m":129,"g":131},"13834":{"m":129,"g":131},"13822":{"m":129,"g":131},"13783":{"m":129,"g":131},"13763":{"m":129,"g":131},"13752":{"m":129,"g":131},"13864":{"m":129,"g":131},"13865":{"m":129,"g":131},"13853":{"m":129,"g":131},"10027":{"m":129,"g":131},"13745":{"m":129,"g":131},"13858":{"m":129,"g":131},"13612":{"m":129,"g":131},"11871":{"m":129,"g":131},"13713":{"m":129,"g":131},"13508":{"m":129,"g":131},"13846":{"m":129,"g":131},"13819":{"m":129,"g":131},"13245":{"m":129,"g":131},"13751":{"m":129,"g":131},"13833":{"m":129,"g":131},"13831":{"m":129,"g":131},"13792":{"m":129,"g":131},"13829":{"m":129,"g":131},"13800":{"m":129,"g":131},"13656":{"m":129,"g":131},"13820":{"m":129,"g":131},"13201":{"m":129,"g":131},"13650":{"m":129,"g":131},"13816":{"m":129,"g":131},"13601":{"m":129,"g":131},"13810":{"m":129,"g":131},"13802":{"m":129,"g":131},"13815":{"m":129,"g":131},"13813":{"m":129,"g":131},"13687":{"m":129,"g":131},"13806":{"m":129,"g":131},"13781":{"m":129,"g":131},"13791":{"m":129,"g":131},"13180":{"m":129,"g":131},"13718":{"m":129,"g":131},"13787":{"m":129,"g":131},"13764":{"m":129,"g":131},"13709":{"m":129,"g":131},"13776":{"m":129,"g":131},"13777":{"m":129,"g":131},"13727":{"m":129,"g":131},"13676":{"m":129,"g":131},"13690":{"m":129,"g":131},"13547":{"m":129,"g":131},"13533":{"m":129,"g":131},"13769":{"m":129,"g":131},"13478":{"m":129,"g":131},"13736":{"m":129,"g":131},"13706":{"m":129,"g":131},"13768":{"m":129,"g":131},"13704":{"m":129,"g":131},"13720":{"m":129,"g":131},"13714":{"m":129,"g":131},"12759":{"m":129,"g":131},"9405":{"m":129,"g":131},"13506":{"m":129,"g":131},"13756":{"m":129,"g":131},"13669":{"m":129,"g":131},"13729":{"m":129,"g":131},"13702":{"m":129,"g":131},"13746":{"m":129,"g":131},"13484":{"m":129,"g":131},"12690":{"m":129,"g":131},"13701":{"m":129,"g":131},"12949":{"m":129,"g":131},"13707":{"m":129,"g":131},"13694":{"m":129,"g":131},"13466":{"m":129,"g":131},"13739":{"m":129,"g":131},"13737":{"m":129,"g":131},"13735":{"m":129,"g":131},"13734":{"m":129,"g":131},"13733":{"m":129,"g":131},"13407":{"m":129,"g":131},"13649":{"m":129,"g":131},"13705":{"m":129,"g":131},"13630":{"m":129,"g":131},"13719":{"m":129,"g":131},"13327":{"m":129,"g":131},"13647":{"m":129,"g":131},"13708":{"m":129,"g":131},"13498":{"m":129,"g":131},"13590":{"m":129,"g":131},"13679":{"m":129,"g":131},"13564":{"m":129,"g":131},"13686":{"m":129,"g":131},"13177":{"m":129,"g":131},"13665":{"m":129,"g":131},"13675":{"m":129,"g":131},"13640":{"m":129,"g":131},"13587":{"m":129,"g":131},"13596":{"m":129,"g":131},"13555":{"m":129,"g":131},"13619":{"m":129,"g":131},"13301":{"m":129,"g":131},"12672":{"m":129,"g":131},"13683":{"m":129,"g":131},"13685":{"m":129,"g":131},"13627":{"m":129,"g":131},"13678":{"m":129,"g":131},"13677":{"m":129,"g":131},"13659":{"m":129,"g":131},"13667":{"m":129,"g":131},"13610":{"m":129,"g":131},"11526":{"m":129,"g":131},"13038":{"m":129,"g":131},"13600":{"m":129,"g":131},"13459":{"m":129,"g":131},"13666":{"m":129,"g":131},"12964":{"m":129,"g":131},"13655":{"m":129,"g":131},"13524":{"m":129,"g":131},"11577":{"m":129,"g":131},"13663":{"m":129,"g":131},"13637":{"m":129,"g":131},"13634":{"m":129,"g":131},"13644":{"m":129,"g":131},"13197":{"m":129,"g":131},"13617":{"m":129,"g":131},"13633":{"m":129,"g":131},"13453":{"m":129,"g":131},"13614":{"m":129,"g":131},"13554":{"m":129,"g":131},"13583":{"m":129,"g":131},"13328":{"m":129,"g":131},"13253":{"m":129,"g":131},"13248":{"m":129,"g":131},"12379":{"m":129,"g":131},"13528":{"m":129,"g":131},"13613":{"m":129,"g":131},"13429":{"m":129,"g":131},"13562":{"m":129,"g":131},"13055":{"m":129,"g":131},"13603":{"m":129,"g":131},"13604":{"m":129,"g":131},"13357":{"m":129,"g":131},"13570":{"m":129,"g":131},"13577":{"m":129,"g":131},"13465":{"m":129,"g":131},"13049":{"m":129,"g":131},"13448":{"m":129,"g":131},"13589":{"m":129,"g":131},"13567":{"m":129,"g":131},"13568":{"m":129,"g":131},"13413":{"m":129,"g":131},"13558":{"m":129,"g":131},"13557":{"m":129,"g":131},"13542":{"m":129,"g":131},"13481":{"m":129,"g":131},"12740":{"m":129,"g":131},"13551":{"m":129,"g":131},"13452":{"m":129,"g":131},"9234":{"m":129,"g":131},"13047":{"m":129,"g":131},"13548":{"m":129,"g":131},"13543":{"m":129,"g":131},"13541":{"m":129,"g":131},"13489":{"m":129,"g":131},"13495":{"m":129,"g":131},"13540":{"m":129,"g":131},"13537":{"m":129,"g":131},"13534":{"m":129,"g":131},"13536":{"m":129,"g":131},"13532":{"m":129,"g":131},"13527":{"m":129,"g":131},"13474":{"m":129,"g":131},"13525":{"m":129,"g":131},"13522":{"m":129,"g":131},"13521":{"m":129,"g":131},"13519":{"m":129,"g":131},"13516":{"m":129,"g":131},"12962":{"m":129,"g":131},"13513":{"m":129,"g":131},"13512":{"m":129,"g":131},"13510":{"m":129,"g":131},"13509":{"m":129,"g":131},"13168":{"m":129,"g":131},"13157":{"m":129,"g":131},"13501":{"m":129,"g":131},"13126":{"m":129,"g":131},"13496":{"m":129,"g":131},"13374":{"m":129,"g":131},"13491":{"m":129,"g":131},"13482":{"m":129,"g":131},"13486":{"m":129,"g":131},"13393":{"m":129,"g":131},"13460":{"m":129,"g":131},"13094":{"m":129,"g":131},"13479":{"m":129,"g":131},"13476":{"m":129,"g":131},"12149":{"m":129,"g":131},"13289":{"m":129,"g":131},"13473":{"m":129,"g":131},"13258":{"m":129,"g":131},"13229":{"m":129,"g":131},"13462":{"m":129,"g":131},"13444":{"m":129,"g":131},"13458":{"m":129,"g":131},"13449":{"m":129,"g":131},"13455":{"m":129,"g":131},"13140":{"m":129,"g":131},"13463":{"m":129,"g":131},"13264":{"m":129,"g":131},"12359":{"m":129,"g":131},"13461":{"m":129,"g":131},"13457":{"m":129,"g":131},"13173":{"m":129,"g":131},"13456":{"m":129,"g":131},"13273":{"m":129,"g":131},"13022":{"m":129,"g":131},"13450":{"m":129,"g":131},"13447":{"m":129,"g":131},"13445":{"m":129,"g":131},"13443":{"m":129,"g":131},"13418":{"m":129,"g":131},"13217":{"m":129,"g":131},"5879":{"m":129,"g":131},"11900":{"m":129,"g":131},"13144":{"m":129,"g":131},"13379":{"m":129,"g":131},"13282":{"m":129,"g":131},"13420":{"m":129,"g":131},"13416":{"m":129,"g":131},"13415":{"m":129,"g":131},"13399":{"m":129,"g":131},"13004":{"m":129,"g":131},"13324":{"m":129,"g":131},"13112":{"m":129,"g":131},"11644":{"m":129,"g":131},"13398":{"m":129,"g":131},"13396":{"m":129,"g":131},"13345":{"m":129,"g":131},"13338":{"m":129,"g":131},"12065":{"m":129,"g":131},"13391":{"m":129,"g":131},"13383":{"m":129,"g":131},"14670":{"m":130,"g":131},"14650":{"m":130,"g":131},"14457":{"m":130,"g":131},"14657":{"m":130,"g":131},"14667":{"m":130,"g":131},"14634":{"m":130,"g":131},"14664":{"m":130,"g":131},"14663":{"m":130,"g":131},"14658":{"m":130,"g":131},"14497":{"m":130,"g":131},"14651":{"m":130,"g":131},"14649":{"m":130,"g":131},"14356":{"m":130,"g":131},"14629":{"m":130,"g":131},"14558":{"m":130,"g":131},"12527":{"m":130,"g":131},"14632":{"m":130,"g":131},"14606":{"m":130,"g":131},"12551":{"m":130,"g":131},"14625":{"m":130,"g":131},"14556":{"m":130,"g":131},"14585":{"m":130,"g":131},"14618":{"m":130,"g":131},"14203":{"m":130,"g":131},"14452":{"m":130,"g":131},"14612":{"m":130,"g":131},"14609":{"m":130,"g":131},"14604":{"m":130,"g":131},"14608":{"m":130,"g":131},"14605":{"m":130,"g":131},"14600":{"m":130,"g":131},"14591":{"m":130,"g":131},"14386":{"m":130,"g":131},"14573":{"m":130,"g":131},"14551":{"m":130,"g":131},"14141":{"m":130,"g":131},"14590":{"m":130,"g":131},"14588":{"m":130,"g":131},"14587":{"m":130,"g":131},"14586":{"m":130,"g":131},"14517":{"m":130,"g":131},"14455":{"m":130,"g":131},"14553":{"m":130,"g":131},"13573":{"m":130,"g":131},"14132":{"m":130,"g":131},"14185":{"m":130,"g":131},"14576":{"m":130,"g":131},"14577":{"m":130,"g":131},"13725":{"m":130,"g":131},"13998":{"m":130,"g":131},"14569":{"m":130,"g":131},"14412":{"m":130,"g":131},"14544":{"m":130,"g":131},"14561":{"m":130,"g":131},"14560":{"m":130,"g":131},"14559":{"m":130,"g":131},"14337":{"m":130,"g":131},"14555":{"m":130,"g":131},"14494":{"m":130,"g":131},"14476":{"m":130,"g":131},"14205":{"m":130,"g":131},"14557":{"m":130,"g":131},"14447":{"m":130,"g":131},"14552":{"m":130,"g":131},"14518":{"m":130,"g":131},"14538":{"m":130,"g":131},"14520":{"m":130,"g":131},"14535":{"m":130,"g":131},"14493":{"m":130,"g":131},"14464":{"m":130,"g":131},"14543":{"m":130,"g":131},"13897":{"m":130,"g":131},"14505":{"m":130,"g":131},"14539":{"m":130,"g":131},"13115":{"m":130,"g":131},"14533":{"m":130,"g":131},"12324":{"m":130,"g":131},"14290":{"m":130,"g":131},"14528":{"m":130,"g":131},"14530":{"m":130,"g":131},"11791":{"m":130,"g":131},"14522":{"m":130,"g":131},"14465":{"m":130,"g":131},"14521":{"m":130,"g":131},"14291":{"m":130,"g":131},"14427":{"m":130,"g":131},"14516":{"m":130,"g":131},"14514":{"m":130,"g":131},"14513":{"m":130,"g":131},"14512":{"m":130,"g":131},"14312":{"m":130,"g":131},"14405":{"m":130,"g":131},"14420":{"m":130,"g":131},"14460":{"m":130,"g":131},"14508":{"m":130,"g":131},"13607":{"m":130,"g":131},"14507":{"m":130,"g":131},"12471":{"m":130,"g":131},"14093":{"m":130,"g":131},"14234":{"m":130,"g":131},"13434":{"m":130,"g":131},"14506":{"m":130,"g":131},"14471":{"m":130,"g":131},"14459":{"m":130,"g":131},"14466":{"m":130,"g":131},"14456":{"m":130,"g":131},"14097":{"m":130,"g":131},"14499":{"m":130,"g":131},"13584":{"m":130,"g":131},"14364":{"m":130,"g":131},"13861":{"m":130,"g":131},"13996":{"m":130,"g":131},"14472":{"m":130,"g":131},"14484":{"m":130,"g":131},"14444":{"m":130,"g":131},"14475":{"m":130,"g":131},"14463":{"m":130,"g":131},"14473":{"m":130,"g":131},"14468":{"m":130,"g":131},"13836":{"m":130,"g":131},"14421":{"m":130,"g":131},"14432":{"m":130,"g":131},"14251":{"m":130,"g":131},"14450":{"m":130,"g":131},"14445":{"m":130,"g":131},"14446":{"m":130,"g":131},"8287":{"m":130,"g":131},"14348":{"m":130,"g":131},"14350":{"m":130,"g":131},"14441":{"m":130,"g":131},"14325":{"m":130,"g":131},"14440":{"m":130,"g":131},"14438":{"m":130,"g":131},"14143":{"m":130,"g":131},"14434":{"m":130,"g":131},"14366":{"m":130,"g":131},"14430":{"m":130,"g":131},"14429":{"m":130,"g":131},"14225":{"m":130,"g":131},"14409":{"m":130,"g":131},"14213":{"m":130,"g":131},"14224":{"m":130,"g":131},"14334":{"m":130,"g":131},"14399":{"m":130,"g":131},"12446":{"m":130,"g":131},"13359":{"m":130,"g":131},"14383":{"m":130,"g":131},"14394":{"m":130,"g":131},"14381":{"m":130,"g":131},"12309":{"m":130,"g":131},"14393":{"m":130,"g":131},"12316":{"m":130,"g":131},"14292":{"m":130,"g":131},"14392":{"m":130,"g":131},"14272":{"m":130,"g":131},"13731":{"m":130,"g":131},"14359":{"m":130,"g":131},"14377":{"m":130,"g":131},"14330":{"m":130,"g":131},"14277":{"m":130,"g":131},"14375":{"m":130,"g":131},"14374":{"m":130,"g":131},"14253":{"m":130,"g":131},"14372":{"m":130,"g":131},"14226":{"m":130,"g":131},"14371":{"m":130,"g":131},"14326":{"m":130,"g":131},"9660":{"m":130,"g":131},"12330":{"m":130,"g":131},"14355":{"m":130,"g":131},"13585":{"m":130,"g":131},"14362":{"m":130,"g":131},"14271":{"m":130,"g":131},"14295":{"m":130,"g":131},"13980":{"m":130,"g":131},"14347":{"m":130,"g":131},"14333":{"m":130,"g":131},"12441":{"m":130,"g":131},"14344":{"m":130,"g":131},"14265":{"m":130,"g":131},"14335":{"m":130,"g":131},"14336":{"m":130,"g":131},"13350":{"m":130,"g":131},"14266":{"m":130,"g":131},"14329":{"m":130,"g":131},"13812":{"m":130,"g":131},"14195":{"m":130,"g":131},"14321":{"m":130,"g":131},"13710":{"m":130,"g":131},"14858":{"m":132,"g":133},"14620":{"m":132,"g":133},"14304":{"m":132,"g":133},"14917":{"m":132,"g":133},"14307":{"m":132,"g":133},"14887":{"m":132,"g":133},"14911":{"m":132,"g":133},"14910":{"m":132,"g":133},"14852":{"m":132,"g":133},"14889":{"m":132,"g":133},"14890":{"m":132,"g":133},"14900":{"m":132,"g":133},"14899":{"m":132,"g":133},"12287":{"m":132,"g":133},"14878":{"m":132,"g":133},"14541":{"m":132,"g":133},"13641":{"m":132,"g":133},"14828":{"m":132,"g":133},"14827":{"m":132,"g":133},"14853":{"m":132,"g":133},"14876":{"m":132,"g":133},"14880":{"m":132,"g":133},"14877":{"m":132,"g":133},"14856":{"m":132,"g":133},"14875":{"m":132,"g":133},"14861":{"m":132,"g":133},"14845":{"m":132,"g":133},"14871":{"m":132,"g":133},"14313":{"m":132,"g":133},"14554":{"m":132,"g":133},"14865":{"m":132,"g":133},"14811":{"m":132,"g":133},"14836":{"m":132,"g":133},"14848":{"m":132,"g":133},"14854":{"m":132,"g":133},"14849":{"m":132,"g":133},"14844":{"m":132,"g":133},"14851":{"m":132,"g":133},"14850":{"m":132,"g":133},"14847":{"m":132,"g":133},"14442":{"m":132,"g":133},"14841":{"m":132,"g":133},"14796":{"m":132,"g":133},"14638":{"m":132,"g":133},"14823":{"m":132,"g":133},"14801":{"m":132,"g":133},"14837":{"m":132,"g":133},"14045":{"m":132,"g":133},"14833":{"m":132,"g":133},"14829":{"m":132,"g":133},"14769":{"m":132,"g":133},"14712":{"m":132,"g":133},"14716":{"m":132,"g":133},"14830":{"m":132,"g":133},"14834":{"m":132,"g":133},"14812":{"m":132,"g":133},"14831":{"m":132,"g":133},"14806":{"m":132,"g":133},"14822":{"m":132,"g":133},"14819":{"m":132,"g":133},"14710":{"m":132,"g":133},"14807":{"m":132,"g":133},"14770":{"m":132,"g":133},"14793":{"m":132,"g":133},"14808":{"m":132,"g":133},"14697":{"m":132,"g":133},"14720":{"m":132,"g":133},"14803":{"m":132,"g":133},"14788":{"m":132,"g":133},"14794":{"m":132,"g":133},"9650":{"m":132,"g":133},"14786":{"m":132,"g":133},"14784":{"m":132,"g":133},"14725":{"m":132,"g":133},"14777":{"m":132,"g":133},"14761":{"m":132,"g":133},"14759":{"m":132,"g":133},"14064":{"m":132,"g":133},"14768":{"m":132,"g":133},"14756":{"m":132,"g":133},"14744":{"m":132,"g":133},"14687":{"m":132,"g":133},"14763":{"m":132,"g":131},"14177":{"m":132,"g":131},"14758":{"m":132,"g":131},"14669":{"m":132,"g":131},"14740":{"m":132,"g":131},"14753":{"m":132,"g":131},"14698":{"m":132,"g":131},"14379":{"m":132,"g":131},"14752":{"m":132,"g":131},"14751":{"m":132,"g":131},"14745":{"m":132,"g":131},"12953":{"m":132,"g":131},"14743":{"m":132,"g":131},"14738":{"m":132,"g":131},"14733":{"m":132,"g":131},"12039":{"m":132,"g":131},"13432":{"m":132,"g":131},"14461":{"m":132,"g":131},"14686":{"m":132,"g":131},"14601":{"m":132,"g":131},"14622":{"m":132,"g":131},"14714":{"m":132,"g":131},"14707":{"m":132,"g":131},"14699":{"m":132,"g":131},"14647":{"m":132,"g":131},"14648":{"m":132,"g":131},"14683":{"m":132,"g":131},"14678":{"m":132,"g":131},"14676":{"m":132,"g":131},"14529":{"m":132,"g":131},"14689":{"m":132,"g":131},"14627":{"m":132,"g":131},"14679":{"m":132,"g":131},"14469":{"m":132,"g":131},"14614":{"m":132,"g":131},"14653":{"m":132,"g":131},"13147":{"m":132,"g":131},"14652":{"m":132,"g":131},"13334":{"m":132,"g":131},"14489":{"m":132,"g":131},"14675":{"m":132,"g":131},"14671":{"m":132,"g":131},"16253":{"m":134,"g":135},"16107":{"m":134,"g":135},"16244":"m134","16241":{"m":134,"g":135},"16211":{"m":134,"g":135},"16153":{"m":134,"g":135},"15942":{"m":134,"g":135},"16140":{"m":134,"g":135},"16142":{"m":134,"g":135},"16141":{"m":134,"g":135},"16129":{"m":134,"g":135},"10959":{"m":134,"g":135},"15888":{"m":134,"g":135},"16114":{"m":134,"g":135},"16131":{"m":134,"g":135},"16133":{"m":134,"g":135},"16053":{"m":134,"g":135},"16130":{"m":134,"g":135},"16105":{"m":134,"g":135},"15187":{"m":134,"g":135},"16123":{"m":134,"g":135},"15813":{"m":134,"g":135},"16081":{"m":134,"g":135},"15896":{"m":134,"g":135},"15877":{"m":134,"g":135},"15800":{"m":134,"g":135},"15985":{"m":134,"g":135},"16103":{"m":134,"g":135},"16099":{"m":134,"g":135},"15921":{"m":134,"g":135},"16101":{"m":134,"g":135},"16100":{"m":134,"g":135},"16098":{"m":134,"g":135},"16097":{"m":134,"g":135},"16094":{"m":134,"g":135},"16096":{"m":134,"g":135},"16093":{"m":134,"g":135},"15057":{"m":134,"g":135},"14838":{"m":134,"g":135},"16061":{"m":134,"g":135},"16066":{"m":134,"g":135},"16087":{"m":134,"g":135},"16069":{"m":134,"g":135},"16085":{"m":134,"g":135},"16062":{"m":134,"g":135},"14414":{"m":134,"g":135},"16047":{"m":134,"g":135},"15805":{"m":134,"g":135},"16054":{"m":134,"g":135},"16003":{"m":134,"g":135},"16046":{"m":134,"g":135},"16051":{"m":134,"g":135},"16038":{"m":134,"g":135},"16041":{"m":134,"g":135},"16039":{"m":134,"g":135},"16037":{"m":134,"g":135},"16035":{"m":134,"g":135},"16036":{"m":134,"g":135},"16010":{"m":134,"g":135},"14280":{"m":134,"g":135},"16028":{"m":134,"g":135},"16017":{"m":134,"g":135},"14873":{"m":134,"g":135},"15922":{"m":134,"g":135},"16016":{"m":134,"g":135},"15939":{"m":134,"g":135},"15998":{"m":134,"g":135},"15928":{"m":134,"g":135},"16008":{"m":134,"g":135},"16002":{"m":134,"g":135},"16013":{"m":134,"g":135},"16004":{"m":134,"g":135},"15615":{"m":134,"g":135},"15992":{"m":134,"g":135},"15991":{"m":134,"g":135},"16001":{"m":134,"g":135},"15945":{"m":134,"g":135},"15990":{"m":134,"g":135},"15988":{"m":134,"g":135},"15987":{"m":134,"g":135},"15891":{"m":134,"g":135},"15216":{"m":134,"g":135},"15693":{"m":134,"g":135},"15353":{"m":134,"g":135},"15835":{"m":134,"g":135},"15806":{"m":134,"g":135},"15937":{"m":134,"g":135},"15986":{"m":134,"g":135},"12596":{"m":134,"g":135},"15919":{"m":134,"g":135},"15947":{"m":134,"g":135},"15925":{"m":134,"g":135},"15936":{"m":134,"g":135},"15886":{"m":134,"g":135},"15943":{"m":134,"g":135},"15935":{"m":134,"g":135},"15934":{"m":134,"g":135},"15933":{"m":134,"g":135},"14736":{"m":134,"g":135},"15923":{"m":134,"g":135},"15907":{"m":134,"g":135},"15887":{"m":134,"g":135},"15920":{"m":134,"g":135},"15918":{"m":134,"g":135},"15905":{"m":134,"g":135},"15850":{"m":134,"g":135},"15915":{"m":134,"g":135},"15398":{"m":134,"g":135},"15914":{"m":134,"g":135},"15916":{"m":134,"g":135},"15913":{"m":134,"g":135},"15911":{"m":134,"g":135},"15910":{"m":134,"g":135},"14750":{"m":134,"g":135},"15906":{"m":134,"g":135},"15778":{"m":134,"g":135},"15844":{"m":134,"g":135},"15812":{"m":134,"g":135},"15842":{"m":134,"g":135},"15881":{"m":134,"g":135},"15874":{"m":134,"g":135},"15889":{"m":134,"g":135},"15846":{"m":134,"g":135},"14209":{"m":134,"g":135},"15849":{"m":134,"g":135},"15817":{"m":134,"g":135},"15870":{"m":134,"g":135},"15867":{"m":134,"g":135},"14644":{"m":134,"g":135},"15518":{"m":134,"g":135},"15821":{"m":134,"g":135},"15369":{"m":134,"g":135},"15858":{"m":134,"g":135},"15857":{"m":134,"g":135},"15820":{"m":134,"g":135},"15851":{"m":134,"g":135},"15701":{"m":134,"g":135},"15791":{"m":134,"g":135},"15847":{"m":134,"g":135},"15522":{"m":134,"g":135},"15796":{"m":134,"g":135},"15826":{"m":134,"g":135},"15822":{"m":134,"g":135},"15772":{"m":134,"g":135},"15356":{"m":134,"g":135},"15759":{"m":134,"g":135},"15827":{"m":134,"g":135},"15488":{"m":134,"g":135},"15815":{"m":134,"g":135},"15818":{"m":134,"g":135},"15802":{"m":134,"g":135},"15666":{"m":134,"g":135},"15709":{"m":134,"g":135},"14741":{"m":134,"g":135},"15803":{"m":134,"g":135},"15409":{"m":134,"g":135},"15798":{"m":134,"g":135},"15811":{"m":134,"g":135},"15720":{"m":134,"g":135},"15736":{"m":134,"g":135},"15801":{"m":134,"g":135},"15555":{"m":134,"g":135},"15770":{"m":134,"g":135},"11469":{"m":134,"g":135},"15586":{"m":134,"g":135},"15596":{"m":134,"g":135},"14032":{"m":134,"g":135},"15787":{"m":134,"g":135},"15700":{"m":134,"g":135},"15781":{"m":134,"g":133},"15149":{"m":134,"g":133},"15775":{"m":134,"g":133},"15782":{"m":134,"g":133},"15758":{"m":134,"g":133},"15745":{"m":134,"g":133},"15750":{"m":134,"g":133},"15780":{"m":134,"g":133},"15741":{"m":134,"g":133},"14137":{"m":134,"g":133},"15390":{"m":134,"g":133},"15718":{"m":134,"g":133},"15769":{"m":134,"g":133},"15768":{"m":134,"g":133},"15653":{"m":134,"g":133},"15652":{"m":134,"g":133},"15752":{"m":134,"g":133},"15747":{"m":134,"g":133},"15748":{"m":134,"g":133},"15743":{"m":134,"g":133},"15740":{"m":134,"g":133},"15655":{"m":134,"g":133},"15706":{"m":134,"g":133},"15459":{"m":134,"g":133},"15689":{"m":134,"g":133},"15593":{"m":134,"g":133},"15704":{"m":134,"g":133},"15691":{"m":134,"g":133},"15656":{"m":134,"g":133},"15717":{"m":134,"g":133},"15715":{"m":134,"g":133},"15722":{"m":134,"g":133},"15716":{"m":134,"g":133},"15719":{"m":134,"g":133},"11828":{"m":134,"g":133},"15500":{"m":134,"g":133},"15622":{"m":134,"g":133},"15624":{"m":134,"g":133},"15705":{"m":134,"g":133},"15177":{"m":134,"g":133},"15702":{"m":134,"g":133},"15538":{"m":134,"g":133},"15667":{"m":134,"g":133},"15695":{"m":134,"g":133},"15696":{"m":134,"g":133},"15606":{"m":134,"g":133},"15273":{"m":134,"g":133},"15672":{"m":134,"g":133},"15694":{"m":134,"g":133},"15469":{"m":134,"g":133},"12968":{"m":134,"g":133},"15644":{"m":134,"g":133},"15692":{"m":134,"g":133},"14570":{"m":134,"g":133},"15091":{"m":134,"g":133},"15646":{"m":134,"g":133},"15633":{"m":134,"g":133},"15688":{"m":134,"g":133},"15684":{"m":134,"g":133},"15312":{"m":134,"g":133},"15600":{"m":134,"g":133},"15463":{"m":134,"g":133},"15460":{"m":134,"g":133},"14983":{"m":134,"g":133},"15563":{"m":134,"g":133},"15582":{"m":134,"g":133},"14628":{"m":134,"g":133},"15539":{"m":134,"g":133},"15570":{"m":134,"g":133},"15635":{"m":134,"g":133},"15590":{"m":134,"g":133},"13576":{"m":134,"g":133},"15632":{"m":134,"g":133},"15621":{"m":134,"g":133},"15368":{"m":134,"g":133},"15611":{"m":134,"g":133},"15610":{"m":134,"g":133},"15572":{"m":134,"g":133},"15573":{"m":134,"g":133},"15616":{"m":134,"g":133},"15613":{"m":134,"g":133},"15607":{"m":134,"g":133},"15612":{"m":134,"g":133},"15164":{"m":134,"g":133},"15566":{"m":134,"g":133},"15599":{"m":134,"g":133},"15589":{"m":134,"g":133},"15588":{"m":134,"g":133},"15587":{"m":134,"g":133},"15565":{"m":134,"g":133},"15581":{"m":134,"g":133},"15585":{"m":134,"g":133},"15230":{"m":134,"g":133},"15427":{"m":134,"g":133},"15553":{"m":134,"g":133},"15583":{"m":134,"g":133},"15580":{"m":134,"g":133},"15569":{"m":134,"g":133},"14901":{"m":134,"g":133},"15564":{"m":134,"g":133},"15578":{"m":134,"g":133},"15579":{"m":134,"g":133},"15509":{"m":134,"g":133},"15540":{"m":134,"g":133},"15568":{"m":134,"g":133},"15558":{"m":134,"g":133},"12162":{"m":134,"g":133},"15531":{"m":134,"g":133},"15111":{"m":134,"g":133},"15432":{"m":134,"g":133},"15554":{"m":134,"g":133},"15556":{"m":134,"g":133},"15537":{"m":134,"g":133},"15520":{"m":134,"g":133},"15447":{"m":134,"g":133},"15324":{"m":134,"g":133},"15436":{"m":134,"g":133},"14134":{"m":134,"g":133},"15552":{"m":134,"g":133},"15526":{"m":134,"g":133},"15547":{"m":134,"g":133},"15413":{"m":134,"g":133},"15515":{"m":134,"g":133},"15544":{"m":134,"g":133},"15542":{"m":134,"g":133},"15418":{"m":134,"g":133},"15479":{"m":134,"g":133},"15533":{"m":134,"g":133},"15534":{"m":134,"g":133},"15530":{"m":134,"g":133},"15511":{"m":134,"g":133},"15536":{"m":134,"g":133},"15320":{"m":134,"g":133},"14091":{"m":134,"g":133},"15464":{"m":134,"g":133},"15484":{"m":134,"g":133},"15172":{"m":134,"g":133},"15178":{"m":134,"g":133},"15498":{"m":134,"g":133},"15333":{"m":134,"g":133},"15267":{"m":134,"g":133},"15507":{"m":134,"g":133},"15510":{"m":134,"g":133},"15485":{"m":134,"g":133},"15473":{"m":134,"g":133},"15505":{"m":134,"g":133},"15504":{"m":134,"g":133},"15503":{"m":134,"g":133},"15497":{"m":134,"g":133},"15040":{"m":134,"g":133},"15296":{"m":134,"g":133},"15496":{"m":134,"g":133},"15495":{"m":134,"g":133},"15494":{"m":134,"g":133},"15491":{"m":134,"g":133},"15022":{"m":134,"g":133},"14164":{"m":134,"g":133},"15348":{"m":134,"g":133},"15406":{"m":134,"g":133},"15483":{"m":134,"g":133},"15166":{"m":134,"g":133},"14138":{"m":134,"g":133},"15408":{"m":134,"g":133},"15416":{"m":134,"g":133},"15219":{"m":134,"g":133},"15478":{"m":134,"g":133},"15382":{"m":134,"g":133},"12995":{"m":134,"g":133},"15394":{"m":134,"g":133},"15458":{"m":134,"g":133},"15262":{"m":134,"g":133},"15437":{"m":134,"g":133},"14395":{"m":134,"g":133},"15253":{"m":134,"g":133},"15415":{"m":134,"g":133},"15433":{"m":134,"g":133},"13402":{"m":134,"g":133},"13760":{"m":134,"g":133},"15340":{"m":134,"g":133},"13782":{"m":134,"g":133},"15423":{"m":134,"g":133},"15425":{"m":134,"g":133},"15287":{"m":134,"g":133},"15207":{"m":134,"g":133},"15410":{"m":134,"g":133},"15371":{"m":134,"g":133},"15429":{"m":134,"g":133},"15431":{"m":134,"g":133},"14723":{"m":134,"g":133},"14843":{"m":134,"g":133},"14353":{"m":134,"g":133},"15424":{"m":134,"g":133},"14354":{"m":134,"g":133},"15318":{"m":134,"g":133},"14781":{"m":134,"g":133},"15421":{"m":134,"g":133},"15352":{"m":134,"g":133},"15395":{"m":134,"g":133},"15401":{"m":134,"g":133},"15407":{"m":134,"g":133},"15400":{"m":134,"g":133},"15396":{"m":134,"g":133},"15404":{"m":134,"g":133},"15397":{"m":134,"g":133},"12921":{"m":134,"g":133},"15298":{"m":134,"g":133},"15141":{"m":134,"g":133},"15379":{"m":134,"g":133},"15306":{"m":134,"g":133},"14270":{"m":134,"g":133},"15384":{"m":134,"g":133},"15361":{"m":134,"g":133},"15372":{"m":134,"g":133},"12967":{"m":134,"g":133},"15290":{"m":134,"g":133},"14501":{"m":134,"g":133},"15049":{"m":134,"g":133},"15354":{"m":134,"g":133},"15337":{"m":134,"g":133},"15278":{"m":134,"g":133},"15131":{"m":134,"g":133},"15205":{"m":134,"g":133},"15307":{"m":134,"g":133},"14860":{"m":134,"g":133},"15176":{"m":134,"g":133},"15277":{"m":134,"g":133},"15328":{"m":134,"g":133},"15120":{"m":134,"g":133},"15241":{"m":134,"g":133},"15308":{"m":134,"g":133},"15336":{"m":134,"g":133},"15316":{"m":134,"g":133},"15335":{"m":134,"g":133},"15329":{"m":134,"g":133},"15186":{"m":134,"g":133},"15222":{"m":134,"g":133},"15198":{"m":134,"g":133},"15189":{"m":134,"g":133},"15326":{"m":134,"g":133},"15237":{"m":134,"g":133},"15138":{"m":134,"g":133},"14918":{"m":134,"g":133},"11914":{"m":134,"g":133},"15304":{"m":134,"g":133},"15223":{"m":134,"g":133},"15233":{"m":134,"g":133},"15314":{"m":134,"g":133},"12333":{"m":134,"g":133},"15071":{"m":134,"g":133},"15284":{"m":134,"g":133},"14449":{"m":134,"g":133},"14357":{"m":134,"g":133},"15088":{"m":134,"g":133},"14376":{"m":134,"g":133},"15155":{"m":134,"g":133},"13571":{"m":134,"g":133},"15283":{"m":134,"g":133},"15218":{"m":134,"g":133},"15297":{"m":134,"g":133},"15258":{"m":134,"g":133},"15280":{"m":134,"g":133},"15293":{"m":134,"g":133},"15292":{"m":134,"g":133},"15291":{"m":134,"g":133},"15282":{"m":134,"g":133},"15242":{"m":134,"g":133},"14997":{"m":134,"g":133},"14934":{"m":134,"g":133},"15281":{"m":134,"g":133},"14857":{"m":134,"g":133},"14975":{"m":134,"g":133},"14936":{"m":134,"g":133},"15234":{"m":134,"g":133},"15270":{"m":134,"g":133},"15232":{"m":134,"g":133},"15192":{"m":134,"g":133},"15100":{"m":134,"g":133},"9337":{"m":134,"g":133},"15239":{"m":134,"g":133},"15220":{"m":134,"g":133},"14866":{"m":134,"g":133},"14415":{"m":134,"g":133},"15180":{"m":134,"g":133},"15225":{"m":134,"g":133},"15162":{"m":134,"g":133},"14990":{"m":134,"g":133},"15229":{"m":134,"g":133},"15231":{"m":134,"g":133},"15204":{"m":134,"g":133},"15092":{"m":134,"g":133},"15224":{"m":134,"g":133},"13410":{"m":134,"g":133},"15212":{"m":134,"g":133},"15185":{"m":134,"g":133},"15153":{"m":134,"g":133},"14820":{"m":134,"g":133},"15201":{"m":134,"g":133},"15127":{"m":134,"g":133},"15191":{"m":134,"g":133},"15190":{"m":134,"g":133},"15196":{"m":134,"g":133},"15193":{"m":134,"g":133},"15160":{"m":134,"g":133},"15047":{"m":134,"g":133},"15017":{"m":134,"g":133},"15163":{"m":134,"g":133},"15152":{"m":134,"g":133},"14906":{"m":134,"g":133},"15116":{"m":134,"g":133},"14862":{"m":134,"g":133},"15174":{"m":134,"g":133},"9324":{"m":134,"g":133},"15170":{"m":134,"g":133},"15005":{"m":134,"g":133},"13914":{"m":134,"g":133},"15158":{"m":134,"g":133},"15156":{"m":134,"g":133},"15154":{"m":134,"g":133},"15144":{"m":134,"g":133},"14778":{"m":134,"g":133},"15147":{"m":134,"g":133},"15146":{"m":134,"g":133},"15130":{"m":134,"g":133},"14907":{"m":134,"g":133},"14764":{"m":134,"g":133},"14792":{"m":134,"g":133},"15142":{"m":134,"g":133},"15139":{"m":134,"g":133},"15101":{"m":134,"g":133},"14938":{"m":134,"g":133},"15134":{"m":134,"g":133},"15058":{"m":134,"g":133},"15086":{"m":134,"g":133},"15099":{"m":134,"g":133},"15098":{"m":134,"g":133},"14953":{"m":134,"g":133},"15052":{"m":134,"g":133},"15044":{"m":134,"g":133},"15125":{"m":134,"g":133},"15110":{"m":134,"g":133},"14791":{"m":134,"g":133},"15113":{"m":134,"g":133},"15117":{"m":134,"g":133},"15124":{"m":134,"g":133},"15121":{"m":134,"g":133},"14874":{"m":134,"g":133},"15106":{"m":134,"g":133},"15090":{"m":134,"g":133},"15114":{"m":134,"g":133},"12263":{"m":134,"g":133},"13969":{"m":134,"g":133},"14961":{"m":134,"g":133},"15062":{"m":134,"g":133},"15053":{"m":134,"g":133},"14881":{"m":134,"g":133},"15108":{"m":134,"g":133},"15048":{"m":134,"g":133},"14294":{"m":134,"g":133},"15084":{"m":134,"g":133},"14969":{"m":134,"g":133},"15096":{"m":134,"g":133},"15061":{"m":134,"g":133},"15095":{"m":134,"g":133},"15094":{"m":134,"g":133},"15093":{"m":134,"g":133},"14943":{"m":134,"g":133},"15087":{"m":134,"g":133},"14993":{"m":134,"g":133},"14956":{"m":134,"g":133},"15056":{"m":134,"g":133},"15066":{"m":134,"g":133},"15085":{"m":134,"g":133},"15064":{"m":134,"g":133},"14935":{"m":134,"g":133},"15065":{"m":134,"g":133},"14998":{"m":134,"g":133},"14201":{"m":134,"g":133},"14940":{"m":134,"g":133},"15054":{"m":134,"g":133},"15055":{"m":134,"g":133},"15080":{"m":134,"g":133},"15079":{"m":134,"g":133},"14742":{"m":134,"g":133},"15074":{"m":134,"g":133},"15072":{"m":134,"g":133},"13740":{"m":134,"g":133},"15069":{"m":134,"g":133},"15060":{"m":134,"g":133},"15059":{"m":134,"g":133},"14422":{"m":134,"g":133},"14855":{"m":134,"g":133},"14423":{"m":134,"g":133},"15027":{"m":134,"g":133},"13989":{"m":134,"g":133},"14924":{"m":134,"g":133},"14659":{"m":134,"g":133},"15002":{"m":134,"g":133},"15034":{"m":134,"g":133},"14485":{"m":134,"g":133},"13876":{"m":134,"g":133},"15037":{"m":134,"g":133},"15036":{"m":134,"g":133},"15032":{"m":134,"g":133},"15031":{"m":134,"g":133},"15030":{"m":134,"g":133},"15028":{"m":134,"g":133},"15035":{"m":134,"g":133},"14939":{"m":134,"g":133},"15024":{"m":134,"g":133},"15033":{"m":134,"g":133},"15009":{"m":134,"g":133},"14957":{"m":134,"g":133},"14955":{"m":134,"g":133},"15015":{"m":134,"g":133},"15023":{"m":134,"g":133},"15021":{"m":134,"g":133},"14992":{"m":134,"g":133},"14976":{"m":134,"g":133},"14966":{"m":134,"g":133},"14933":{"m":134,"g":133},"14795":{"m":134,"g":133},"15020":{"m":134,"g":133},"15010":{"m":134,"g":133},"15014":{"m":134,"g":133},"14869":{"m":134,"g":133},"14989":{"m":134,"g":133},"14958":{"m":134,"g":133},"14951":{"m":134,"g":133},"15004":{"m":134,"g":133},"15001":{"m":134,"g":133},"15000":{"m":134,"g":133},"14999":{"m":134,"g":133},"14996":{"m":134,"g":133},"14995":{"m":134,"g":133},"14987":{"m":134,"g":133},"14945":{"m":134,"g":133},"14985":{"m":134,"g":133},"14534":{"m":134,"g":133},"14916":{"m":134,"g":133},"14959":{"m":134,"g":133},"14937":{"m":134,"g":133},"13798":{"m":134,"g":133},"14572":{"m":134,"g":133},"14949":{"m":134,"g":133},"14842":{"m":134,"g":133},"13699":{"m":134,"g":133},"14944":{"m":134,"g":133},"14888":{"m":134,"g":133},"14893":{"m":134,"g":133},"14892":{"m":134,"g":133},"14941":{"m":134,"g":133},"14894":{"m":134,"g":133},"14839":{"m":134,"g":133},"11852":{"m":134,"g":133},"14870":{"m":134,"g":133},"14358":{"m":134,"g":133},"14923":{"m":134,"g":133},"14891":{"m":134,"g":133},"14909":{"m":134,"g":133},"14467":{"m":134,"g":133},"14927":{"m":134,"g":133},"14931":{"m":134,"g":133},"13730":{"m":134,"g":133},"14932":{"m":134,"g":133},"14748":{"m":134,"g":133},"14525":{"m":134,"g":133},"14771":{"m":134,"g":133},"14074":{"m":134,"g":133},"14922":{"m":134,"g":133},"13125":{"m":134,"g":133},"14921":{"m":134,"g":133},"14928":{"m":134,"g":133},"14925":{"m":134,"g":133},"17458":"m136","17569":"m136","17591":"m136","17553":"m136","15859":"m136","17460":"m136","17474":"m136","17541":"m136","17518":"m136","17539":"m136","16366":"m136","17514":"m136","17536":"m136","17529":"m136","17534":"m136","17442":"m136","17493":"m136","17528":"m136","17524":"m136","16927":"m136","17486":"m136","17519":"m136","17416":"m136","17490":"m136","17517":"m136","17394":"m136","17498":"m136","16034":"m136","17510":"m136","17166":"m136","16919":"m136","17108":"m136","17417":"m136","16670":"m136","17355":"m136","17399":"m136","17400":"m136","17397":"m136","17372":"m136","16396":"m136","17457":"m136","17462":"m136","17466":"m136","17425":"m136","17465":"m136","17452":"m136","17386":"m136","17293":"m136","17455":"m136","17251":"m136","17444":"m136","17443":"m136","17439":"m136","17290":"m136","17291":"m136","17313":"m136","17436":"m136","17428":"m136","17289":"m136","17334":"m136","17403":"m136","17429":"m136","17247":"m136","17205":"m136","17288":"m136","17419":"m136","17414":"m136","17409":"m136","17358":"m136","11657":"m136","17382":"m136","17160":"m136","17179":"m136","17327":"m136","17385":"m136","17302":"m136","17339":"m136","15325":"m136","17364":"m136","16880":"m136","17378":"m136","17376":"m136","17370":"m136","17043":"m136","17088":"m136","17336":"m136","17367":"m136","17366":"m136","17363":"m136","17329":"m136","17049":"m136","17345":"m136","17116":"m136","17142":"m136","17220":"m136","16567":"m136","17305":"m136","17309":"m136","17158":"m136","17177":"m136","17332":"m136","17238":"m136","17245":"m136","17241":"m136","16412":"m136","17325":"m136","16744":"m136","17317":"m136","17319":"m136","16961":"m136","15347":"m136","17315":"m136","17306":"m136","15512":"m136","17308":"m136","17235":"m136","15631":"m136","14197":"m136","16649":"m136","17296":"m136","17212":"m136","16534":"m136","17295":"m136","17236":"m136","17281":"m136","16974":"m136","17287":"m136","17182":"m136","17264":"m136","16152":"m136","17261":"m136","17250":"m136","17234":"m136","17225":"m136","17256":"m136","17257":"m136","17048":"m136","14883":"m136","17191":"m136","17252":"m136","16561":"m136","17248":"m136","17249":"m136","16879":"m136","17045":"m136","17047":"m136","17044":"m136","16951":"m136","17242":"m136","16354":"m136","16817":"m136","16824":"m136","17232":"m136","17230":"m136","17233":"m136","17165":"m136","16925":"m136","17187":"m136","17217":"m136","16842":"m136","13672":"m136","15551":"m136","17133":"m136","17016":"m136","17200":"m136","17038":"m136","13216":"m136","17143":"m136","17105":"m136","17184":"m136","17173":"m136","17051":"m136","16934":"m136","17186":"m136","16121":"m136","17180":"m136","15513":"m136","17041":"m136","14565":"m136","17100":"m136","14579":"m136","17178":"m136","16882":"m136","16826":"m136","16369":"m136","17176":"m136","17174":"m136","11028":"m136","15455":"m136","17170":"m136","10598":"m136","17091":"m136","17168":"m136","17167":"m136","16568":"m136","15789":"m136","17163":"m136","17099":"m136","17126":"m136","16965":"m136","17111":"m136","17113":"m136","17020":"m136","17064":"m136","17103":"m136","17092":"m136","16949":"m136","17056":"m136","17075":"m136","17061":"m136","17028":"m136","17101":"m136","17052":"m136","12497":"m136","14504":"m136","17087":"m136","16278":"m136","16971":"m136","16976":"m136","16403":"m136","17058":"m136","17077":"m136","16264":"m136","7392":"m136","16732":"m136","16899":"m136","16569":"m136","17013":"m136","16941":"m136","16962":"m136","16888":"m136","15908":"m136","16989":"m136","17046":"m136","17030":"m136","17027":"m136","17054":"m136","16898":"m136","16994":"m136","16841":"m136","17002":"m136","14108":"m136","17022":"m136","17005":"m136","16982":"m136","16894":"m136","16953":"m136","17019":"m136","16886":"m136","16259":"m136","16924":"m136","16986":"m136","16790":"m136","16935":"m136","16884":"m136","16967":"m136","16766":"m136","16564":"m136","16767":"m136","16648":"m136","16252":"m136","16940":"m136","15853":"m136","16765":"m136","16978":"m136","16981":"m136","16980":"m136","16979":"m136","16977":"m136","16973":"m136","16970":"m136","16192":"m136","16348":"m136","16963":"m136","15271":"m136","16933":"m136","16480":"m136","16922":"m136","16916":"m136","16912":"m136","16019":"m136","16559":"m136","16677":"m136","16930":"m136","16932":"m136","16536":"m136","16850":"m136","16915":"m136","16896":"m136","16820":"m136","15268":"m136","12909":"m136","16908":"m136","16906":"m136","16851":"m136","14867":"m136","16895":"m136","16300":"m136","16864":"m136","16889":"m136","15182":"m136","16876":"m136","16258":"m136","16835":"m136","16345":"m136","16878":"m136","16867":"m136","16273":"m136","16757":"m136","16865":"m136","16877":"m136","16863":"m136","16667":"m136","16788":"m136","16397":"m136","16737":"m136","16872":"m136","16871":"m136","16870":"m136","15790":"m136","15927":"m136","15227":"m136","16226":"m136","16844":"m136","16838":"m136","16849":"m136","16333":"m136","16779":"m136","16854":"m136","16862":"m136","16572":"m136","16805":"m136","16723":"m136","13715":"m136","16853":"m136","16637":"m136","16852":"m136","16847":"m136","16848":"m136","16845":"m136","16698":"m136","16825":"m136","16837":"m136","16840":"m136","16839":"m136","16831":"m136","16830":"m136","16679":"m136","16810":"m136","16783":"m136","16587":"m136","16821":"m136","16804":"m136","15753":"m136","13947":"m136","16275":"m136","16814":"m136","16813":"m136","16812":"m136","16811":"m136","14655":"m136","16325":"m136","16708":"m136","16760":"m136","16792":"m136","11349":"m136","16458":"m136","16743":"m136","16768":"m136","16721":"m136","16778":"m136","16774":"m136","16686":"m136","16378":"m136","16588":"m136","16446":"m136","16773":"m136","16380":"m136","16254":{"m":136,"g":135},"16720":{"m":136,"g":135},"16560":{"m":136,"g":135},"16764":{"m":136,"g":135},"16763":{"m":136,"g":135},"16759":{"m":136,"g":135},"16715":{"m":136,"g":135},"16756":{"m":136,"g":135},"16754":{"m":136,"g":135},"16752":{"m":136,"g":135},"16751":{"m":136,"g":135},"16749":{"m":136,"g":135},"16748":{"m":136,"g":135},"16675":{"m":136,"g":135},"16746":{"m":136,"g":135},"16409":{"m":136,"g":135},"13681":{"m":136,"g":135},"16745":{"m":136,"g":135},"16741":{"m":136,"g":135},"16014":{"m":136,"g":135},"16739":{"m":136,"g":135},"16719":{"m":136,"g":135},"16668":{"m":136,"g":135},"16738":{"m":136,"g":135},"16709":{"m":136,"g":135},"16735":{"m":136,"g":135},"16622":{"m":136,"g":135},"16635":{"m":136,"g":135},"16733":{"m":136,"g":135},"16730":{"m":136,"g":135},"16729":{"m":136,"g":135},"16519":{"m":136,"g":135},"16706":{"m":136,"g":135},"16115":{"m":136,"g":135},"16634":{"m":136,"g":135},"16535":{"m":136,"g":135},"16452":{"m":136,"g":135},"16533":{"m":136,"g":135},"16531":{"m":136,"g":135},"16529":{"m":136,"g":135},"15627":{"m":136,"g":135},"16608":{"m":136,"g":135},"16693":{"m":136,"g":135},"16155":{"m":136,"g":135},"16505":{"m":136,"g":135},"16697":{"m":136,"g":135},"16555":{"m":136,"g":135},"16669":{"m":136,"g":135},"16625":{"m":136,"g":135},"16695":{"m":136,"g":135},"16678":{"m":136,"g":135},"16692":{"m":136,"g":135},"16629":{"m":136,"g":135},"16680":{"m":136,"g":135},"16445":{"m":136,"g":135},"16306":{"m":136,"g":135},"16652":{"m":136,"g":135},"15343":{"m":136,"g":135},"16095":{"m":136,"g":135},"15151":{"m":136,"g":135},"16681":{"m":136,"g":135},"16674":{"m":136,"g":135},"16457":{"m":136,"g":135},"16426":{"m":136,"g":135},"16676":{"m":136,"g":135},"16658":{"m":136,"g":135},"16672":{"m":136,"g":135},"16633":{"m":136,"g":135},"16671":{"m":136,"g":135},"15712":{"m":136,"g":135},"16660":{"m":136,"g":135},"16664":{"m":136,"g":135},"16657":{"m":136,"g":135},"16661":{"m":136,"g":135},"16618":{"m":136,"g":135},"16179":{"m":136,"g":135},"16599":{"m":136,"g":135},"15238":{"m":136,"g":135},"16532":{"m":136,"g":135},"16654":{"m":136,"g":135},"16651":{"m":136,"g":135},"16203":{"m":136,"g":135},"13602":{"m":136,"g":135},"16620":{"m":136,"g":135},"16514":{"m":136,"g":135},"16631":{"m":136,"g":135},"16630":{"m":136,"g":135},"16619":{"m":136,"g":135},"16527":{"m":136,"g":135},"15938":{"m":136,"g":135},"16582":{"m":136,"g":135},"16418":{"m":136,"g":135},"16459":{"m":136,"g":135},"16465":{"m":136,"g":135},"16468":{"m":136,"g":135},"16566":{"m":136,"g":135},"16617":{"m":136,"g":135},"16597":{"m":136,"g":135},"16504":{"m":136,"g":135},"16593":{"m":136,"g":135},"16118":{"m":136,"g":135},"15439":{"m":136,"g":135},"16609":{"m":136,"g":135},"16453":{"m":136,"g":135},"16499":{"m":136,"g":135},"16606":{"m":136,"g":135},"16603":{"m":136,"g":135},"16576":{"m":136,"g":135},"16596":{"m":136,"g":135},"16598":{"m":136,"g":135},"16601":{"m":136,"g":135},"16594":{"m":136,"g":135},"16442":{"m":136,"g":135},"16422":{"m":136,"g":135},"16223":{"m":136,"g":135},"16425":{"m":136,"g":135},"16589":{"m":136,"g":135},"16592":{"m":136,"g":135},"16583":{"m":136,"g":135},"16585":{"m":136,"g":135},"16591":{"m":136,"g":135},"16326":{"m":136,"g":135},"16523":{"m":136,"g":135},"16420":{"m":136,"g":135},"16548":{"m":136,"g":135},"16549":{"m":136,"g":135},"16575":{"m":136,"g":135},"16507":{"m":136,"g":135},"16570":{"m":136,"g":135},"16463":{"m":136,"g":135},"14215":{"m":136,"g":135},"13518":{"m":136,"g":135},"16455":{"m":136,"g":135},"16496":{"m":136,"g":135},"16540":{"m":136,"g":135},"16201":{"m":136,"g":135},"15456":{"m":136,"g":135},"16421":{"m":136,"g":135},"16466":{"m":136,"g":135},"16539":{"m":136,"g":135},"16417":{"m":136,"g":135},"16502":{"m":136,"g":135},"16415":{"m":136,"g":135},"16467":{"m":136,"g":135},"16399":{"m":136,"g":135},"14112":{"m":136,"g":135},"15492":{"m":136,"g":135},"16538":{"m":136,"g":135},"6135":{"m":136,"g":135},"16528":{"m":136,"g":135},"16416":{"m":136,"g":135},"16419":{"m":136,"g":135},"16434":{"m":136,"g":135},"16525":{"m":136,"g":135},"16520":{"m":136,"g":135},"16086":{"m":136,"g":135},"16524":{"m":136,"g":135},"15677":{"m":136,"g":135},"16477":{"m":136,"g":135},"16356":{"m":136,"g":135},"16513":{"m":136,"g":135},"15663":{"m":136,"g":135},"16516":{"m":136,"g":135},"16482":{"m":136,"g":135},"16511":{"m":136,"g":135},"16280":{"m":136,"g":135},"16509":{"m":136,"g":135},"16508":{"m":136,"g":135},"16492":{"m":136,"g":135},"16469":{"m":136,"g":135},"16138":{"m":136,"g":135},"16481":{"m":136,"g":135},"14474":{"m":136,"g":135},"16367":{"m":136,"g":135},"16475":{"m":136,"g":135},"16478":{"m":136,"g":135},"16479":{"m":136,"g":135},"16474":{"m":136,"g":135},"16447":{"m":136,"g":135},"16471":{"m":136,"g":135},"16456":{"m":136,"g":135},"16382":{"m":136,"g":135},"14051":{"m":136,"g":135},"16042":{"m":136,"g":135},"16424":{"m":136,"g":135},"16460":{"m":136,"g":135},"16464":{"m":136,"g":135},"16454":{"m":136,"g":135},"16088":{"m":136,"g":135},"16387":{"m":136,"g":135},"16386":{"m":136,"g":135},"16451":{"m":136,"g":135},"16450":{"m":136,"g":135},"16448":{"m":136,"g":135},"16389":{"m":136,"g":135},"16180":{"m":136,"g":135},"16441":{"m":136,"g":135},"16444":{"m":136,"g":135},"16437":{"m":136,"g":135},"16310":{"m":136,"g":135},"16435":{"m":136,"g":135},"16433":{"m":136,"g":135},"16432":{"m":136,"g":135},"16375":{"m":136,"g":135},"16330":{"m":136,"g":135},"15836":{"m":136,"g":135},"16430":{"m":136,"g":135},"16414":{"m":136,"g":135},"16429":{"m":136,"g":135},"16427":{"m":136,"g":135},"16413":{"m":136,"g":135},"16408":{"m":136,"g":135},"16411":{"m":136,"g":135},"16334":{"m":136,"g":135},"16127":{"m":136,"g":135},"16323":{"m":136,"g":135},"14066":{"m":136,"g":135},"16405":{"m":136,"g":135},"16406":{"m":136,"g":135},"16401":{"m":136,"g":135},"16400":{"m":136,"g":135},"16347":{"m":136,"g":135},"16349":{"m":136,"g":135},"16390":{"m":136,"g":135},"16392":{"m":136,"g":135},"16374":{"m":136,"g":135},"16391":{"m":136,"g":135},"16381":{"m":136,"g":135},"16376":{"m":136,"g":135},"16373":{"m":136,"g":135},"16359":{"m":136,"g":135},"16268":{"m":136,"g":135},"16365":{"m":136,"g":135},"16368":{"m":136,"g":135},"16363":{"m":136,"g":135},"16358":{"m":136,"g":135},"16343":{"m":136,"g":135},"16357":{"m":136,"g":135},"16355":{"m":136,"g":135},"16352":{"m":136,"g":135},"16064":{"m":136,"g":135},"15434":{"m":136,"g":135},"16353":{"m":136,"g":135},"16341":{"m":136,"g":135},"16351":{"m":136,"g":135},"16269":{"m":136,"g":135},"16350":{"m":136,"g":135},"16340":{"m":136,"g":135},"16339":{"m":136,"g":135},"16335":{"m":136,"g":135},"16344":{"m":136,"g":135},"15941":{"m":136,"g":135},"16342":{"m":136,"g":135},"16164":{"m":136,"g":135},"16304":{"m":136,"g":135},"16303":{"m":136,"g":135},"16338":{"m":136,"g":135},"16219":{"m":136,"g":135},"16337":{"m":136,"g":135},"15640":{"m":136,"g":135},"16311":{"m":136,"g":135},"16332":{"m":136,"g":135},"15175":{"m":136,"g":135},"16328":{"m":136,"g":135},"16009":{"m":136,"g":135},"13592":{"m":136,"g":135},"16272":{"m":136,"g":135},"16283":{"m":136,"g":135},"16257":{"m":136,"g":135},"16177":{"m":136,"g":135},"15560":{"m":136,"g":135},"16324":{"m":136,"g":135},"16317":{"m":136,"g":135},"16296":{"m":136,"g":135},"16321":{"m":136,"g":135},"16316":{"m":136,"g":135},"16313":{"m":136,"g":135},"16318":{"m":136,"g":135},"16320":{"m":136,"g":135},"16319":{"m":136,"g":135},"16314":{"m":136,"g":135},"16315":{"m":136,"g":135},"16312":{"m":136,"g":135},"16287":{"m":136,"g":135},"16277":{"m":136,"g":135},"16308":{"m":136,"g":135},"16092":{"m":136,"g":135},"16128":{"m":136,"g":135},"16305":{"m":136,"g":135},"16301":{"m":136,"g":135},"13959":{"m":136,"g":135},"16248":{"m":136,"g":135},"16292":{"m":136,"g":135},"16298":{"m":136,"g":135},"16227":{"m":136,"g":135},"16213":{"m":136,"g":135},"16267":{"m":136,"g":135},"16144":{"m":136,"g":135},"16222":{"m":136,"g":135},"15345":{"m":136,"g":135},"16270":{"m":136,"g":135},"16285":{"m":136,"g":135},"14636":{"m":136,"g":135},"16263":{"m":136,"g":135},"16265":{"m":136,"g":135},"15995":{"m":136,"g":135},"16162":{"m":136,"g":135},"16262":{"m":136,"g":135},"16261":{"m":136,"g":135},"16260":{"m":136,"g":135},"16251":{"m":136,"g":135},"16247":{"m":136,"g":135},"16250":{"m":136,"g":135},"16243":{"m":136,"g":135},"14085":{"m":136,"g":135},"16171":{"m":136,"g":135},"16245":{"m":136,"g":135},"16238":{"m":136,"g":135},"15814":{"m":136,"g":135},"16239":{"m":136,"g":135},"16240":{"m":136,"g":135},"16236":{"m":136,"g":135},"16233":{"m":136,"g":135},"16202":{"m":136,"g":135},"16228":{"m":136,"g":135},"16018":{"m":136,"g":135},"16195":{"m":136,"g":135},"16111":{"m":136,"g":135},"13394":{"m":136,"g":135},"16204":{"m":136,"g":135},"16214":{"m":136,"g":135},"16221":{"m":136,"g":135},"16178":{"m":136,"g":135},"16187":{"m":136,"g":135},"16209":{"m":136,"g":135},"15597":{"m":136,"g":135},"16117":{"m":136,"g":135},"15878":{"m":136,"g":135},"16200":{"m":136,"g":135},"15946":{"m":136,"g":135},"16198":{"m":136,"g":135},"16172":{"m":136,"g":135},"15575":{"m":136,"g":135},"16174":{"m":136,"g":135},"16156":{"m":136,"g":135},"15754":{"m":136,"g":135},"14920":{"m":136,"g":135},"16050":{"m":136,"g":135},"16181":{"m":136,"g":135},"16183":{"m":136,"g":135},"16182":{"m":136,"g":135},"14416":{"m":136,"g":135},"16168":{"m":136,"g":135},"16175":{"m":136,"g":135},"16166":{"m":136,"g":135},"16161":{"m":136,"g":135},"16163":{"m":136,"g":135},"16165":{"m":136,"g":135},"16110":{"m":136,"g":135},"16173":{"m":136,"g":135},"16159":{"m":136,"g":135},"16150":{"m":136,"g":135},"16160":{"m":136,"g":135},"16158":{"m":136,"g":135},"16149":{"m":136,"g":135},"16124":{"m":136,"g":135},"15730":{"m":136,"g":135},"13978":{"m":136,"g":135},"12625":{"m":136,"g":135},"16154":{"m":136,"g":135},"18298":"m137","18111":"m137"},"c":{"2ccd9fd8":{"m":0,"g":94},"46b7ea7c":{"m":0,"g":94},"70359bf3":{"m":0,"g":94},"01ca82d7":{"m":0,"g":94},"4bd8233f":{"m":0,"g":94},"08ab2a16":{"m":0,"g":94},"f652494d":{"m":0,"g":94},"30720e73":{"m":0,"g":94},"331848de":{"m":0,"g":94},"93eeb543":{"m":0,"g":94},"ead5b39f":{"m":0,"g":94},"22085081":{"m":0,"g":94},"f6d40df0":{"m":0,"g":94},"22ec7bc2":{"m":1,"g":94},"c0454b32":{"m":1,"g":94},"8024fc5e":{"m":1,"g":94},"70528762":{"m":1,"g":94},"71d30d6d":{"m":1,"g":94},"f9d72381":{"m":1,"g":94},"bf51ddc6":{"m":1,"g":94},"fd7c4792":{"m":1,"g":94},"c4707f1b":{"m":1,"g":94},"ffe4aaee":{"m":1,"g":94},"5b27a1dc":{"m":1,"g":94},"e71d4ab3":{"m":1,"g":94},"fbf42263":{"m":1,"g":94},"cc3ada98":{"m":2,"g":94},"a837166e":{"m":2,"g":94},"11f3cca6":{"m":2,"g":94},"ca13f3b8":{"m":2,"g":94},"0b2efc2a":{"m":2,"g":94},"f30abd09":{"m":2,"g":94},"40ab1f01":{"m":2,"g":94},"199e82a1":{"m":2,"g":94},"23471f9a":{"m":2,"g":94},"61d4c939":{"m":2,"g":94},"98a3e8ef":{"m":2,"g":94},"2b079f89":{"m":2,"g":94},"05b4c398":{"m":2,"g":94},"dafafe5b":{"m":2,"g":94},"b240f751":{"m":2,"g":94},"501f9444":{"m":2,"g":94},"723f0421":{"m":3,"g":94},"585eabab":{"m":3,"g":94},"c70b3cfa":{"m":4,"g":94},"489796c7":{"m":4,"g":94},"fa7a696d":{"m":4,"g":94},"bef0b359":{"m":4,"g":94},"c6576e82":{"m":4,"g":94},"99258181":{"m":4,"g":94},"3de54a1b":{"m":4,"g":94},"7358fa64":{"m":4,"g":94},"9a16fea0":{"m":4,"g":94},"9e037c82":{"m":4,"g":94},"9076386d":{"m":4,"g":94},"959c4174":{"m":4,"g":94},"94e05770":{"m":4,"g":94},"63e97e5e":{"m":4,"g":94},"e08bca28":{"m":4,"g":94},"cd3ccb2e":{"m":4,"g":94},"3f5c2f4c":{"m":4,"g":94},"007eeb4e":{"m":4,"g":94},"e8f2b155":{"m":4,"g":94},"6dceab4d":{"m":5,"g":94},"a49dc52b":{"m":6,"g":94},"873d0e85":{"m":6,"g":94},"1d0fbe8e":{"m":6,"g":94},"97aa9b32":{"m":6,"g":94},"06175286":{"m":6,"g":94},"4ea92f83":{"m":6,"g":94},"6b0af285":{"m":6,"g":94},"6f560c76":{"m":6,"g":94},"cd687233":{"m":6,"g":94},"81561f8e":{"m":6,"g":94},"3a581e99":{"m":6,"g":94},"0147f940":{"m":6,"g":94},"23950056":{"m":6,"g":94},"93414c82":{"m":6,"g":94},"ed7c7eca":{"m":6,"g":94},"0c457bae":{"m":6,"g":94},"d3fc86a4":{"m":6,"g":94},"01ee0fbc":{"m":6,"g":94},"711d3435":{"m":6,"g":94},"f6bfe3aa":{"m":7,"g":94},"e095b162":{"m":7,"g":94},"67be11c7":{"m":7,"g":94},"cd8c3ccd":{"m":7,"g":94},"9c121f2a":{"m":7,"g":94},"03e04b23":{"m":7,"g":94},"86442530":{"m":7,"g":94},"79cb018e":{"m":7,"g":94},"c7af9f73":{"m":7,"g":94},"876db8dc":{"m":7,"g":94},"ad82bac6":{"m":7,"g":94},"71b54eea":{"m":7,"g":94},"74b3bfaa":{"m":7,"g":94},"4a634cf6":{"m":7,"g":94},"624b21e7":{"m":8,"g":94},"c51020cf":{"m":8,"g":94},"50afed4e":{"m":8,"g":94},"4d303c4f":{"m":8,"g":94},"37b42297":{"m":8,"g":94},"cba50273":{"m":8,"g":94},"a6aa46dd":{"m":8,"g":94},"405f26b0":{"m":8,"g":94},"b1a3a454":{"m":8,"g":94},"79e6b84b":{"m":8,"g":94},"26c34941":{"m":8,"g":94},"cb8e1982":{"m":8,"g":94},"23f05005":{"m":8,"g":94},"a7334aee":{"m":8,"g":94},"ee1df26a":{"m":8,"g":94},"3ae78a09":{"m":8,"g":94},"ccbe1e67":{"m":8,"g":94},"e2bf732b":{"m":8,"g":94},"322421fa":{"m":8,"g":94},"8ff870bf":{"m":8,"g":94},"26f0bedc":{"m":8,"g":94},"82fa69b3":{"m":8,"g":94},"8fb7459e":{"m":8,"g":94},"bb3a3b66":{"m":8,"g":94},"45d6592d":{"m":8,"g":94},"4aa5dd2c":{"m":9,"g":94},"13662fd5":{"m":9,"g":94},"d5ae2eba":{"m":9,"g":94},"1b355479":{"m":9,"g":94},"faba293a":{"m":9,"g":94},"89885b31":{"m":9,"g":94},"64fe3115":{"m":9,"g":94},"a7ace9c8":{"m":9,"g":94},"a833de05":{"m":9,"g":94},"30d67b2b":{"m":9,"g":94},"b0b722ee":{"m":9,"g":94},"01b07ea3":{"m":9,"g":94},"dfb13ac4":{"m":9,"g":94},"ec90b9c0":{"m":9,"g":94},"9759d927":{"m":9,"g":94},"8d0a7fae":{"m":9,"g":94},"c4e9ebe3":{"m":9,"g":94},"3c2c5869":{"m":9,"g":94},"4cb9aaed":{"m":9,"g":94},"9de9a468":{"m":9,"g":94},"ce3b2610":{"m":9,"g":94},"91e03633":{"m":9,"g":94},"2a74748b":{"m":9,"g":94},"63ba630b":{"m":9,"g":94},"6493256b":{"m":9,"g":94},"06008bc2":{"m":9,"g":94},"bb824da4":{"m":9,"g":94},"93121324":{"m":9,"g":94},"c97fdae4":{"m":9,"g":94},"51104cd4":{"m":10,"g":94},"e2b2f0a2":{"m":10,"g":94},"b57abe16":{"m":10,"g":94},"e57f0792":{"m":10,"g":94},"08df63a6":{"m":10,"g":94},"77835756":{"m":10,"g":94},"ed315799":{"m":10,"g":94},"92e2d74f":{"m":10,"g":94},"d9b3b018":{"m":10,"g":94},"745ea007":{"m":10,"g":94},"ad1dd746":{"m":10,"g":94},"eb4308c4":{"m":10,"g":94},"b2eb0805":{"m":10,"g":94},"72bb3443":{"m":11,"g":94},"2d580e7a":{"m":11,"g":94},"3fc97f67":{"m":11,"g":94},"abc548c7":{"m":11,"g":94},"aee4f523":{"m":11,"g":94},"7023f413":{"m":11,"g":94},"09deb20d":{"m":11,"g":94},"33b242df":{"m":11,"g":94},"a511a2d0":{"m":11,"g":94},"6ec65f45":{"m":11,"g":94},"e2c31fca":{"m":11,"g":94},"d5de20a3":{"m":11,"g":94},"4a1c6ae2":{"m":11,"g":94},"14522e6a":{"m":11,"g":94},"183df472":{"m":11,"g":94},"5c5aba59":{"m":11,"g":94},"ba67101f":{"m":11,"g":94},"95c4e0df":{"m":11,"g":94},"19818b9c":{"m":11,"g":94},"9216b106":{"m":11,"g":94},"da19434c":{"m":11,"g":94},"150d7020":{"m":11,"g":94},"9acc6e35":{"m":11,"g":94},"cf9d8efd":{"m":11,"g":94},"1bf1cf19":{"m":11,"g":94},"e822e590":{"m":11,"g":94},"ca4f1ab8":{"m":11,"g":94},"2b6d9991":{"m":11,"g":94},"65501a9c":{"m":11,"g":94},"db611066":{"m":11,"g":94},"c93293c5":{"m":11,"g":94},"62b3812b":{"m":11,"g":94},"550a4f78":{"m":11,"g":94},"ff99c38a":{"m":11,"g":94},"c9de3e16":{"m":11,"g":94},"ed27a6b9":{"m":11,"g":94},"463c6632":{"m":11,"g":94},"b0890631":{"m":11,"g":94},"cb389c91":{"m":11,"g":94},"eddaa2b5":{"m":11,"g":94},"2af565b3":{"m":11,"g":94},"3842eba5":{"m":11,"g":94},"24e59f53":{"m":11,"g":94},"75235419":{"m":11,"g":94},"64ee9c03":{"m":11,"g":94},"30d17840":{"m":11,"g":94},"ce216c80":{"m":11,"g":94},"e0ae5d42":{"m":12,"g":94},"32de16ce":{"m":12,"g":94},"0992d85f":{"m":12,"g":94},"5dc55a5f":{"m":12,"g":94},"4231a42f":{"m":12,"g":94},"455c9ccc":{"m":12,"g":94},"39191c85":{"m":12,"g":94},"562b8857":{"m":12,"g":94},"04c0b214":{"m":12,"g":94},"6e09cf6a":{"m":12,"g":94},"e8a2327d":{"m":13,"g":94},"91f93f14":{"m":13,"g":94},"f70f7258":{"m":13,"g":94},"c0ae70c8":{"m":13,"g":94},"87260b7b":{"m":13,"g":94},"651a23ee":{"m":13,"g":94},"bf3e271f":{"m":13,"g":94},"3bc01ac1":{"m":13,"g":94},"9f009261":{"m":13,"g":94},"159cc741":{"m":13,"g":94},"7d1ebc2d":{"m":13,"g":94},"83525a1d":{"m":13,"g":94},"80a33ce8":{"m":13,"g":94},"1a57e416":{"m":13,"g":94},"adc97426":{"m":13,"g":94},"0463f7fb":{"m":13,"g":94},"565d7274":{"m":13,"g":94},"09de730d":{"m":13,"g":94},"55c16436":{"m":13,"g":94},"2b605ab1":{"m":13,"g":94},"947bda73":{"m":13,"g":94},"f06e90c2":{"m":13,"g":94},"2cea6146":{"m":13,"g":94},"44c998fc":{"m":13,"g":94},"3167d8da":{"m":13,"g":94},"0fafc560":{"m":13,"g":94},"19d2135c":{"m":13,"g":94},"ced77c66":{"m":13,"g":94},"8dbdc018":{"m":13,"g":94},"3e684be7":{"m":13,"g":94},"ec380dfd":{"m":13,"g":94},"5b647543":{"m":13,"g":94},"8210ec60":{"m":13,"g":94},"5be9eb8a":{"m":13,"g":94},"c05956e5":{"m":13,"g":94},"d75dc20f":{"m":13,"g":94},"690d162d":{"m":13,"g":94},"664287b2":{"m":13,"g":94},"2f11936f":{"m":14,"g":94},"63fbef98":{"m":14,"g":94},"2a754e57":{"m":14,"g":94},"96c503eb":{"m":14,"g":94},"441cca77":{"m":14,"g":94},"c7709d3a":{"m":14,"g":94},"9380f50f":{"m":14,"g":94},"95dc093b":{"m":14,"g":94},"d9ac6392":{"m":14,"g":94},"26294b2f":{"m":14,"g":94},"75b31a2a":{"m":14,"g":94},"11616fc6":{"m":14,"g":94},"9ce89bc1":{"m":14,"g":94},"badf3fa0":{"m":14,"g":94},"945aa9be":{"m":14,"g":94},"2e6e62e1":{"m":14,"g":94},"a385ee27":{"m":14,"g":94},"eb1ae6ae":{"m":14,"g":94},"2187f362":{"m":14,"g":94},"9465b668":{"m":14,"g":94},"05471f21":{"m":14,"g":94},"1fa15099":{"m":14,"g":94},"303ef888":{"m":14,"g":94},"92cb93f3":{"m":14,"g":94},"e94e60d6":{"m":14,"g":94},"d2f8bfb2":{"m":14,"g":94},"b7e2f800":{"m":14,"g":94},"09593e9b":{"m":14,"g":94},"53a7ebd8":{"m":14,"g":94},"ad5f04d6":{"m":14,"g":94},"bbec01c9":{"m":14,"g":94},"40e53d65":{"m":14,"g":94},"fb9296f0":{"m":14,"g":94},"1374334d":{"m":14,"g":94},"94aead9e":{"m":14,"g":94},"9c902b19":{"m":14,"g":94},"111991fe":{"m":14,"g":94},"a8c787d2":{"m":14,"g":94},"5f283991":{"m":14,"g":94},"b6667a53":{"m":14,"g":94},"542bc733":{"m":14,"g":94},"f6dbd240":{"m":14,"g":94},"ad872feb":{"m":15,"g":94},"da2e5d65":{"m":15,"g":94},"ce62dc73":{"m":15,"g":94},"02b72586":{"m":15,"g":94},"d557e9f3":{"m":15,"g":94},"740c46a1":{"m":15,"g":94},"b3868722":{"m":15,"g":94},"710f614e":{"m":15,"g":94},"f25b76c0":{"m":15,"g":94},"f4e885b7":{"m":15,"g":94},"0877f1e7":{"m":15,"g":94},"5304b4ef":{"m":15,"g":94},"26908d95":{"m":15,"g":94},"c0982ac5":{"m":15,"g":94},"dc1b8bcf":{"m":15,"g":94},"5a57b8ad":{"m":15,"g":94},"d737da5f":{"m":15,"g":94},"ac113887":{"m":15,"g":94},"dc8cef1d":{"m":15,"g":94},"5d264a90":{"m":16,"g":94},"5949b1ca":{"m":16,"g":94},"0feca02d":{"m":16,"g":94},"10143e1a":{"m":16,"g":94},"65c65776":{"m":16,"g":94},"66581596":{"m":16,"g":94},"396a6924":{"m":16,"g":94},"af4e7910":{"m":16,"g":94},"519e20cf":{"m":16,"g":94},"d9a69029":{"m":16,"g":94},"56f5fc4a":{"m":17,"g":94},"6a2941f4":{"m":17,"g":94},"5ac8b806":{"m":17,"g":94},"bae9541e":{"m":17,"g":94},"a56858ba":{"m":17,"g":94},"564a898a":{"m":17,"g":94},"2b4c6462":{"m":18,"g":94},"f424e76d":{"m":18,"g":94},"490a1f39":{"m":18,"g":94},"06487f12":{"m":18,"g":94},"39c57317":{"m":18,"g":94},"9592a1f3":{"m":18,"g":94},"35759efa":{"m":18,"g":94},"8f4b1559":{"m":18,"g":94},"e3046ea3":{"m":18,"g":94},"49c5e0ec":{"m":18,"g":94},"ec2150b2":{"m":18,"g":94},"7620cd37":{"m":18,"g":94},"50a53887":{"m":18,"g":94},"11c8efff":{"m":18,"g":94},"e87c7fd5":{"m":18,"g":94},"630479c3":{"m":18,"g":94},"51fda143":{"m":18,"g":94},"dc4e4a6a":{"m":18,"g":94},"2d96da81":{"m":18,"g":94},"c126a6cc":{"m":18,"g":94},"ac971ff6":{"m":18,"g":94},"e1792cca":{"m":18,"g":94},"1b7adbb5":{"m":18,"g":94},"a9ef49c1":{"m":18,"g":94},"21ba3a88":{"m":18,"g":94},"9c5cac24":{"m":18,"g":94},"5960a6e5":{"m":18,"g":94},"b050d928":{"m":18,"g":94},"6a4dc996":{"m":18,"g":94},"d774acad":{"m":18,"g":94},"d93388da":{"m":18,"g":94},"476584cb":{"m":18,"g":94},"abd5385a":{"m":18,"g":94},"3de2f30a":{"m":18,"g":94},"4efcc59d":{"m":18,"g":94},"2e341cd4":{"m":18,"g":94},"a8552cb1":{"m":18,"g":94},"a470e60c":{"m":18,"g":94},"5f90e076":{"m":18,"g":94},"8832ecb1":{"m":18,"g":94},"5ff60eda":{"m":18,"g":94},"c1930022":{"m":18,"g":94},"fe3be159":{"m":18,"g":94},"0aa189f1":{"m":18,"g":94},"f6b29f69":{"m":18,"g":94},"c9ee3d35":{"m":18,"g":94},"41d1f677":{"m":18,"g":94},"444a0244":{"m":19,"g":94},"fa7ccb33":{"m":19,"g":94},"26868443":{"m":19,"g":94},"824a77d0":{"m":19,"g":94},"cf99eab7":{"m":19,"g":94},"9fdea29d":{"m":19,"g":94},"df7c4c19":{"m":19,"g":94},"c3f1aac8":{"m":19,"g":94},"d198791f":{"m":19,"g":94},"c07526e4":{"m":19,"g":94},"7b597475":{"m":19,"g":94},"5303c1ed":{"m":19,"g":94},"65bd1338":{"m":19,"g":94},"eedc12e1":{"m":19,"g":94},"5a4ef2b5":{"m":19,"g":94},"9dab947d":{"m":19,"g":94},"33ee97b0":{"m":19,"g":94},"6a846bb1":{"m":19,"g":94},"0fdb3127":{"m":19,"g":94},"5ad033a0":{"m":19,"g":94},"77e592e8":{"m":19,"g":94},"caaad53b":{"m":19,"g":94},"69d19188":{"m":19,"g":94},"4b4a67f8":{"m":19,"g":94},"0ac94c36":{"m":19,"g":94},"459abad2":{"m":20,"g":94},"30d8e130":{"m":20,"g":94},"08a3bd19":{"m":20,"g":94},"321a963b":{"m":20,"g":94},"e17deb27":{"m":20,"g":94},"2d3ae4e1":{"m":20,"g":94},"75f4ccb7":{"m":20,"g":94},"83d2b30d":{"m":20,"g":94},"4367f4bb":{"m":20,"g":94},"00e4baa7":{"m":20,"g":94},"4cd64b8e":{"m":20,"g":94},"01d66ae2":{"m":20,"g":94},"a523a3c1":{"m":20,"g":94},"9f94728f":{"m":20,"g":94},"1a491d00":{"m":21,"g":94},"8fbba3de":{"m":21,"g":94},"ae0f6130":{"m":21,"g":94},"60105897":{"m":21,"g":94},"926ac01b":{"m":21,"g":94},"25c881a0":{"m":21,"g":94},"04ec6ba2":{"m":21,"g":94},"d63f13c1":{"m":21,"g":94},"fded6744":{"m":21,"g":94},"6e453940":{"m":21,"g":94},"97e0f7d2":{"m":21,"g":94},"d5146bae":{"m":21,"g":94},"5bd06b45":{"m":22,"g":94},"9a611827":{"m":22,"g":94},"eeb24821":{"m":22,"g":94},"3e455b01":{"m":22,"g":94},"8628ab9c":{"m":22,"g":94},"1b77670f":{"m":22,"g":94},"768e05d0":{"m":22,"g":94},"01fbb11b":{"m":22,"g":94},"05d216da":{"m":22,"g":94},"6b32bb1c":{"m":22,"g":94},"40facad5":{"m":22,"g":94},"da504445":{"m":22,"g":94},"252e0f7b":{"m":22,"g":94},"7f6f2f0f":{"m":22,"g":94},"7802df1e":{"m":22,"g":94},"bc1154c3":{"m":23,"g":94},"752e6430":{"m":23,"g":94},"30db99b3":{"m":23,"g":94},"0a409bd4":{"m":23,"g":94},"e4db4e5b":{"m":23,"g":94},"bbc07c41":{"m":23,"g":94},"a036d419":{"m":23,"g":94},"f95e6617":{"m":23,"g":94},"de854fb5":{"m":23,"g":94},"f64b2a9b":{"m":23,"g":94},"9f95dcc6":{"m":23,"g":94},"0736b270":{"m":23,"g":94},"3fdab919":{"m":23,"g":94},"ba29504b":{"m":23,"g":94},"a72342f1":{"m":23,"g":94},"c3c74bf8":{"m":23,"g":94},"d9fccfef":{"m":23,"g":94},"679ebcbb":{"m":23,"g":94},"1edd4e07":{"m":24,"g":94},"62c673c4":{"m":24,"g":94},"377c5dc9":{"m":24,"g":94},"f52eda35":{"m":24,"g":94},"b579ecf0":{"m":24,"g":94},"e7487b08":{"m":24,"g":94},"ae5c0fc4":{"m":24,"g":94},"a30d5d75":{"m":24,"g":94},"17af39c5":{"m":24,"g":94},"daf593a3":{"m":24,"g":94},"bece265f":{"m":24,"g":94},"cdcbde5f":{"m":24,"g":94},"21e22b9e":{"m":24,"g":94},"a50c8a14":{"m":24,"g":94},"db6089e6":{"m":24,"g":94},"3520f75f":{"m":24,"g":94},"c8e9fed8":{"m":24,"g":94},"084fa54d":{"m":24,"g":94},"eba458bd":{"m":24,"g":94},"3d1cb0af":{"m":24,"g":94},"7d352b4f":{"m":24,"g":94},"87064015":{"m":24,"g":94},"7cd4f244":{"m":24,"g":94},"98111fbe":{"m":24,"g":94},"2ec39ab7":{"m":24,"g":94},"8f6274c8":{"m":24,"g":94},"325a06c2":{"m":24,"g":94},"79f81629":{"m":24,"g":94},"b688fd85":{"m":24,"g":94},"5bd89924":{"m":24,"g":94},"8d908a93":{"m":24,"g":94},"dd7e8b94":{"m":24,"g":94},"1f013d64":{"m":24,"g":94},"628e1fa7":{"m":24,"g":94},"c71880f8":{"m":24,"g":94},"bcb6611a":{"m":24,"g":94},"fa2aa0db":{"m":24,"g":94},"6a387a69":{"m":24,"g":94},"27f5ce0a":{"m":24,"g":94},"94862579":{"m":24,"g":94},"68e52626":{"m":24,"g":94},"e4d3333c":{"m":25,"g":94},"6f221d4c":{"m":25,"g":94},"aba6f51f":{"m":25,"g":94},"7f6c690b":{"m":25,"g":94},"40e6f513":{"m":25,"g":94},"40756776":{"m":25,"g":94},"9e8d2c7f":{"m":25,"g":94},"c9bff5fc":{"m":25,"g":94},"b04444ac":{"m":25,"g":94},"3d617a21":{"m":25,"g":94},"c020f9ce":{"m":25,"g":94},"ca600e8c":{"m":25,"g":94},"0c0c8137":{"m":25,"g":94},"90286d85":{"m":25,"g":94},"5e7dd984":{"m":25,"g":94},"bc3eaac2":{"m":25,"g":94},"a78d98de":{"m":25,"g":94},"7d5ed7c6":{"m":25,"g":94},"a6c7ebbb":{"m":25,"g":94},"bb0501c0":{"m":25,"g":94},"6b0f2e90":{"m":25,"g":94},"30a9b2ef":{"m":26,"g":94},"3cadecf0":{"m":26,"g":94},"e90e3a50":{"m":26,"g":94},"fbd6b94d":{"m":26,"g":94},"4c8093c8":{"m":26,"g":94},"ae7ee01a":{"m":26,"g":94},"76e59088":{"m":26,"g":94},"12ce3bef":{"m":26,"g":94},"4013a4e1":{"m":26,"g":94},"60340a36":{"m":26,"g":94},"70c78cfb":{"m":26,"g":94},"72b6ea88":{"m":26,"g":94},"b906c015":{"m":27,"g":94},"9319cd13":{"m":27,"g":94},"046c2b33":{"m":27,"g":94},"6b8f66ef":{"m":27,"g":94},"7937a886":{"m":27,"g":94},"2e218b9e":{"m":27,"g":94},"141e8c71":{"m":28,"g":94},"d53dcf9c":{"m":28,"g":94},"bb66cc4c":{"m":28,"g":94},"975adb80":{"m":28,"g":94},"0d4f3a9f":{"m":28,"g":94},"afd411d0":{"m":28,"g":94},"e1eae1fd":{"m":28,"g":94},"f4d9953d":{"m":28,"g":94},"4f005250":{"m":28,"g":94},"995af5a5":{"m":28,"g":94},"53985645":{"m":28,"g":94},"70cc0749":{"m":28,"g":94},"7dd8a7e6":{"m":28,"g":94},"947402c8":{"m":28,"g":94},"8c5382e6":{"m":28,"g":94},"001b0bdd":{"m":28,"g":94},"dc9d06d8":{"m":29,"g":94},"c31f084c":{"m":29,"g":94},"a01ddd96":{"m":29,"g":94},"7fa54a1a":{"m":29,"g":94},"05abd126":{"m":29,"g":94},"5f6fa04a":{"m":29,"g":94},"58a09708":{"m":29,"g":94},"ff68ae85":{"m":29,"g":94},"795eab6d":{"m":29,"g":94},"41bb1ab1":{"m":29,"g":94},"87e8c090":{"m":29,"g":94},"ad56e684":{"m":29,"g":94},"ffb15744":{"m":29,"g":94},"a9c833d5":{"m":29,"g":94},"94e01151":{"m":29,"g":94},"b216a545":{"m":29,"g":94},"fde83405":{"m":29,"g":94},"fd7926e4":{"m":29,"g":94},"399cad91":{"m":29,"g":94},"0a4f5f9b":{"m":29,"g":94},"3bc99e6f":{"m":29,"g":94},"ebf69964":{"m":29,"g":94},"b0ad0c1b":{"m":30,"g":94},"c877292c":{"m":30,"g":94},"0c1c72a0":{"m":30,"g":94},"41598e0d":{"m":30,"g":94},"89f23a51":{"m":30,"g":94},"cb99ba4f":{"m":30,"g":94},"32f61443":{"m":30,"g":94},"fb1f28cb":{"m":30,"g":94},"fb7421db":{"m":30,"g":94},"14b64930":{"m":30,"g":94},"82076370":{"m":30,"g":94},"7de60345":{"m":30,"g":94},"d84c5e70":{"m":30,"g":94},"d7854120":{"m":30,"g":94},"7b6a5332":{"m":30,"g":94},"4080e822":{"m":30,"g":94},"c245b789":{"m":30,"g":94},"9dae4078":{"m":30,"g":94},"fcc0f5ed":{"m":30,"g":94},"a97df791":{"m":30,"g":94},"33d61356":{"m":30,"g":94},"94752ac8":{"m":30,"g":94},"43fbb6d9":{"m":30,"g":94},"54fb1c80":{"m":30,"g":94},"b68c4c07":{"m":30,"g":94},"e712837d":{"m":30,"g":94},"7599bade":{"m":30,"g":94},"62757db6":{"m":30,"g":94},"73fa2d49":{"m":30,"g":94},"61728884":{"m":30,"g":94},"9cf0a5ba":{"m":30,"g":94},"b16e856f":{"m":30,"g":94},"05c50a82":{"m":30,"g":94},"b568df5d":{"m":30,"g":94},"10bca45b":{"m":30,"g":94},"b91a4cb1":{"m":30,"g":94},"95a28019":{"m":30,"g":94},"e040a245":{"m":30,"g":94},"9f662501":{"m":30,"g":94},"ab787594":{"m":30,"g":94},"228cf475":{"m":30,"g":94},"3a79613c":{"m":30,"g":94},"1ac304ee":{"m":30,"g":94},"20a4f927":{"m":30,"g":94},"0de7c2d0":{"m":30,"g":94},"6ed4e3b8":{"m":30,"g":94},"00023d62":{"m":30,"g":94},"c62d560c":{"m":30,"g":94},"2b8257f3":{"m":30,"g":94},"7623091d":{"m":30,"g":94},"f724f1f1":{"m":30,"g":94},"6db27f7b":{"m":30,"g":94},"4d929107":{"m":30,"g":94},"fbe0c818":{"m":30,"g":94},"5bd95374":{"m":31,"g":94},"0cb099e2":{"m":31,"g":94},"93d4e354":{"m":31,"g":94},"9195d136":{"m":31,"g":94},"14cb544d":{"m":31,"g":94},"e86b1ccb":{"m":31,"g":94},"8d2d876f":{"m":31,"g":94},"326df4ba":{"m":31,"g":94},"6767e222":{"m":31,"g":94},"73cf6834":{"m":31,"g":94},"1c2b5f52":{"m":31,"g":94},"96a2093e":{"m":31,"g":94},"a34dd86a":{"m":31,"g":94},"67c0d832":{"m":31,"g":94},"a59636bb":{"m":31,"g":94},"fe502432":{"m":31,"g":94},"f14569f6":{"m":31,"g":94},"8f790ac1":{"m":31,"g":94},"616b59f3":{"m":31,"g":94},"c8423ca3":{"m":31,"g":94},"e205527c":{"m":31,"g":94},"0909bb0d":{"m":31,"g":94},"ad3e4f16":{"m":31,"g":94},"312e8492":{"m":31,"g":94},"95f5fbf1":{"m":31,"g":94},"cebd78d8":{"m":31,"g":94},"0076f115":{"m":31,"g":94},"f7fb68d2":{"m":31,"g":94},"396a13e6":{"m":31,"g":94},"65915f9f":{"m":31,"g":94},"162f3ccb":{"m":31,"g":94},"65e89bae":{"m":31,"g":94},"6a38efa8":{"m":31,"g":94},"c5fe11a8":{"m":32,"g":94},"75ce37f4":{"m":32,"g":94},"97589a60":{"m":32,"g":94},"632d506d":{"m":32,"g":94},"3579162a":{"m":32,"g":94},"7514b9f8":{"m":32,"g":94},"158e8f1e":{"m":32,"g":94},"d3efcb39":{"m":32,"g":94},"2c615d12":{"m":32,"g":94},"61bb223e":{"m":32,"g":94},"15f1a49d":{"m":32,"g":94},"308d0240":{"m":32,"g":94},"ab4990e4":{"m":32,"g":94},"90227800":{"m":32,"g":94},"30b4f771":{"m":32,"g":94},"66e7dcaf":{"m":32,"g":94},"bc4c7a35":{"m":32,"g":94},"1cb4da5c":{"m":32,"g":94},"e61d13ac":{"m":32,"g":94},"b20daf98":{"m":32,"g":94},"f6af3a65":{"m":32,"g":94},"c9064e6f":{"m":32,"g":94},"a5b14ad0":{"m":32,"g":94},"5fafcac0":{"m":32,"g":94},"364d3d72":{"m":32,"g":94},"5623826f":{"m":32,"g":94},"83e23c69":{"m":32,"g":94},"ac1b74fa":{"m":32,"g":94},"068e9eae":{"m":32,"g":94},"d6aeb9fa":{"m":32,"g":94},"1fb94599":{"m":32,"g":94},"bea2bb9e":{"m":32,"g":94},"cd10654e":{"m":32,"g":94},"350a8160":{"m":32,"g":94},"6242c399":{"m":32,"g":94},"04707b09":{"m":32,"g":94},"ff2cfdb1":{"m":32,"g":94},"a8ae6403":{"m":32,"g":94},"d8476818":{"m":32,"g":94},"df191254":{"m":32,"g":94},"b997a18d":{"m":32,"g":94},"d8627ed1":{"m":32,"g":94},"fa13b95d":{"m":32,"g":94},"3c1f5a92":{"m":32,"g":94},"57d0bd91":{"m":32,"g":94},"cdc8d607":{"m":32,"g":94},"9208591f":{"m":32,"g":94},"5d0d40d0":{"m":32,"g":94},"f624f6a6":{"m":32,"g":94},"3694f8f9":{"m":32,"g":94},"5a261bd0":{"m":32,"g":94},"6aa8ad14":{"m":32,"g":94},"26e9c12c":{"m":32,"g":94},"87a0db82":{"m":32,"g":94},"f25f4dfd":{"m":33,"g":94},"184ae1c6":{"m":33,"g":94},"198974cd":{"m":33,"g":94},"6cc38b2b":{"m":33,"g":94},"1ece2cda":{"m":33,"g":94},"c8a9e791":{"m":33,"g":94},"3602692c":{"m":33,"g":94},"909f3436":{"m":33,"g":94},"5ff25cdf":{"m":33,"g":94},"2f1d9283":{"m":33,"g":94},"c61a1b6f":{"m":33,"g":94},"9935f97b":{"m":33,"g":94},"13ac95b8":{"m":34,"g":94},"492143bf":{"m":34,"g":94},"0a97d796":{"m":34,"g":94},"c411f32e":{"m":34,"g":94},"bf53bf51":{"m":34,"g":94},"b1a540ec":{"m":34,"g":94},"66975360":{"m":34,"g":94},"6c498313":{"m":34,"g":94},"99994427":{"m":35,"g":94},"6def9b01":{"m":35,"g":94},"47f20da2":{"m":35,"g":94},"4a9f8ea4":{"m":35,"g":94},"58fa6076":{"m":35,"g":94},"6487ef64":{"m":35,"g":94},"9b080524":{"m":35,"g":94},"32a4141d":{"m":35,"g":94},"08360553":{"m":35,"g":94},"00b19f19":{"m":35,"g":94},"6cb32ef9":{"m":35,"g":94},"761b2ceb":{"m":35,"g":94},"54772f78":{"m":35,"g":94},"1b5d56f7":{"m":35,"g":94},"d134c139":{"m":35,"g":94},"6cc9c525":{"m":35,"g":94},"52cefdbf":{"m":35,"g":94},"51c554d8":{"m":35,"g":94},"79ece2c5":{"m":35,"g":94},"55f5976b":{"m":35,"g":94},"b7f83410":{"m":35,"g":94},"f414352a":{"m":35,"g":94},"a362340b":{"m":35,"g":94},"381dd57b":{"m":35,"g":94},"8153168c":{"m":35,"g":94},"6c34d633":{"m":35,"g":94},"5ab9418f":{"m":36,"g":94},"843e63d8":{"m":36,"g":94},"a63c8275":{"m":36,"g":94},"dc67d976":{"m":36,"g":94},"1e495e08":{"m":36,"g":94},"12cb115d":{"m":36,"g":94},"c500f96b":{"m":36,"g":94},"474317f2":{"m":36,"g":94},"f64eae3a":{"m":36,"g":94},"a5a134f3":{"m":36,"g":94},"2561ed01":{"m":36,"g":94},"90a26be3":{"m":37,"g":94},"1f4b5f77":{"m":37,"g":94},"76524b70":{"m":37,"g":94},"3a6e0418":{"m":37,"g":94},"2fa5cec7":{"m":37,"g":94},"27b557ae":{"m":37,"g":94},"93dffd69":{"m":37,"g":94},"2abe4f1c":{"m":37,"g":94},"37963394":{"m":37,"g":94},"899cf5c4":{"m":37,"g":94},"e79f6cd7":{"m":37,"g":94},"9ba1f097":{"m":37,"g":94},"282681b8":{"m":37,"g":94},"58cafe23":{"m":37,"g":94},"9463bc13":{"m":37,"g":94},"e3fc4658":{"m":37,"g":94},"33b54e7c":{"m":37,"g":94},"30b404ce":{"m":37,"g":94},"70b68029":{"m":37,"g":94},"f3d32f88":{"m":37,"g":94},"8779da95":{"m":37,"g":94},"ad0ff62a":{"m":37,"g":94},"9a903a87":{"m":37,"g":94},"68be2f6d":{"m":37,"g":94},"b912de11":{"m":37,"g":94},"eb02c161":{"m":37,"g":94},"71221692":{"m":37,"g":94},"c33d82a2":{"m":37,"g":94},"8234e663":{"m":37,"g":94},"debbdb51":{"m":37,"g":94},"3efa7981":{"m":37,"g":94},"2a71be5e":{"m":37,"g":94},"44621377":{"m":37,"g":94},"fec185ce":{"m":37,"g":94},"c03cece4":{"m":37,"g":94},"15c75e41":{"m":37,"g":94},"224200e3":{"m":37,"g":94},"8c0efa51":{"m":37,"g":94},"144bc70f":{"m":37,"g":94},"46094e0c":{"m":37,"g":94},"3a6e8b6d":{"m":37,"g":94},"fbb4754c":{"m":37,"g":94},"6c7cb903":{"m":37,"g":94},"dff2860a":{"m":37,"g":94},"e72275cf":{"m":37,"g":94},"fec2d122":{"m":37,"g":94},"8d1095db":{"m":37,"g":94},"743007e1":{"m":37,"g":94},"9144ed10":{"m":37,"g":94},"69b3bb9a":{"m":37,"g":94},"689ff588":{"m":37,"g":94},"a7c47e0f":{"m":37,"g":94},"e4d68afc":{"m":37,"g":94},"c9b75917":{"m":37,"g":94},"662ecd93":{"m":37,"g":94},"8e6bdf85":{"m":37,"g":94},"05bea688":{"m":37,"g":94},"ab4a83b2":{"m":37,"g":94},"62f15eea":{"m":37,"g":94},"79794af5":{"m":37,"g":94},"3494b32c":{"m":37,"g":94},"eda7c090":{"m":37,"g":94},"5ce55aee":{"m":38,"g":94},"2d346a57":{"m":38,"g":94},"446ea332":{"m":38,"g":94},"8f527e29":{"m":38,"g":94},"7f24ea95":{"m":38,"g":94},"1acccb36":{"m":38,"g":94},"aa2750be":{"m":38,"g":94},"5e62a6b7":{"m":38,"g":94},"5752f25e":{"m":38,"g":94},"7c162fa9":{"m":38,"g":94},"36078fb2":{"m":38,"g":94},"b3710d2c":{"m":38,"g":94},"c6b6d2e7":{"m":38,"g":94},"82136eb0":{"m":39,"g":94},"b8ccaf4d":{"m":39,"g":94},"a68cb201":{"m":39,"g":94},"014982b5":{"m":39,"g":94},"a6db8862":{"m":39,"g":94},"b4408b0d":{"m":39,"g":94},"2cd7e181":{"m":39,"g":94},"37c5899f":{"m":40,"g":94},"f39a0197":{"m":40,"g":94},"3c93187c":{"m":40,"g":94},"fb2d0680":{"m":40,"g":94},"067d8e16":{"m":40,"g":94},"e6692bf4":{"m":40,"g":94},"28b4d8e1":{"m":40,"g":94},"bc068e96":{"m":40,"g":94},"8d4ed42a":{"m":40,"g":94},"2854a5ea":{"m":40,"g":94},"42a2d82b":{"m":40,"g":94},"e4780cf8":{"m":40,"g":94},"39bb49d1":{"m":40,"g":94},"6f3cf129":{"m":40,"g":94},"13f1357e":{"m":40,"g":94},"2a99993c":{"m":40,"g":94},"167591e8":{"m":40,"g":94},"441c22db":{"m":40,"g":94},"ce636ac4":{"m":40,"g":94},"7b69d91b":{"m":41,"g":94},"e8613df0":{"m":41,"g":94},"c5325aba":{"m":41,"g":94},"ebbc42d9":{"m":41,"g":94},"3ff64113":{"m":41,"g":94},"2b302b93":{"m":41,"g":94},"68f8b60d":{"m":41,"g":94},"6a5b352a":{"m":41,"g":94},"565b05f0":{"m":41,"g":94},"b6aad70a":{"m":41,"g":94},"551a3a9d":{"m":41,"g":94},"91877a9f":{"m":41,"g":94},"f7cce751":{"m":41,"g":94},"17e998f1":{"m":41,"g":94},"c98e84c2":{"m":41,"g":94},"9c064bf7":{"m":41,"g":94},"58d1082e":{"m":41,"g":94},"4d086719":{"m":41,"g":94},"9244f27f":{"m":41,"g":94},"2422de51":{"m":41,"g":94},"521f862d":{"m":41,"g":94},"34c32d28":{"m":41,"g":94},"dde8bb16":{"m":41,"g":94},"8ac3ccc0":{"m":41,"g":94},"9b0926ce":{"m":41,"g":94},"1c1bdc76":{"m":41,"g":94},"6bfdb403":{"m":41,"g":94},"f8fb4ce9":{"m":41,"g":94},"5d0ba403":{"m":41,"g":94},"04b262cd":{"m":41,"g":94},"2432ad40":{"m":41,"g":94},"45473d4b":{"m":41,"g":94},"114bbc86":{"m":41,"g":94},"32eb6e96":{"m":41,"g":94},"e0b5dbce":{"m":41,"g":94},"e6852b0d":{"m":41,"g":94},"4ae0969c":{"m":41,"g":94},"317631ca":{"m":41,"g":94},"b5648353":{"m":41,"g":94},"2c7d0a5b":{"m":41,"g":94},"8cdc76f6":{"m":41,"g":94},"f202ed97":{"m":41,"g":94},"100f5b8b":{"m":41,"g":94},"619bb6dd":{"m":41,"g":94},"b88ea90d":{"m":41,"g":94},"99ec439d":{"m":41,"g":94},"0f4fb19b":{"m":41,"g":94},"63ba2f8d":{"m":41,"g":94},"36d5acfc":{"m":41,"g":94},"3f0fe08d":{"m":41,"g":94},"55b974f9":{"m":41,"g":94},"f86c1e61":{"m":41,"g":94},"acaffd23":{"m":41,"g":94},"04868543":{"m":41,"g":94},"fd9ad817":{"m":41,"g":94},"e165a9fc":{"m":41,"g":94},"4e4459b9":{"m":41,"g":94},"065bb947":{"m":41,"g":94},"f42e9bfb":{"m":41,"g":94},"840c5dbc":{"m":41,"g":94},"63e845d0":{"m":41,"g":94},"9aa6553d":{"m":41,"g":94},"b1e330bc":{"m":41,"g":94},"4353acb4":{"m":41,"g":94},"9ae1db0b":{"m":41,"g":94},"00c7e636":{"m":42,"g":94},"23cc66f7":{"m":42,"g":94},"5d09ca57":{"m":42,"g":94},"81c33274":{"m":42,"g":94},"f13d86f9":{"m":42,"g":94},"aba9eae4":{"m":42,"g":94},"bbd72bfc":{"m":42,"g":94},"b503881b":{"m":42,"g":94},"58093b86":{"m":42,"g":94},"8275049c":{"m":42,"g":94},"5476ccad":{"m":42,"g":94},"b040ed71":{"m":42,"g":94},"c9e66586":{"m":42,"g":94},"e11ab79e":{"m":42,"g":94},"01fdb2f3":{"m":42,"g":94},"c996e8cc":{"m":42,"g":94},"087257ea":{"m":43,"g":94},"736f0402":{"m":43,"g":94},"769bf11c":{"m":43,"g":94},"3db43d1b":{"m":43,"g":94},"f0f8a769":{"m":43,"g":94},"2bcfba1b":{"m":43,"g":94},"bc12d403":{"m":43,"g":94},"392f2863":{"m":43,"g":94},"6d0fa73e":{"m":43,"g":94},"9e0dac1a":{"m":43,"g":94},"a95d5589":{"m":43,"g":94},"d17d19e5":{"m":43,"g":94},"dd3809fa":{"m":43,"g":94},"7feba415":{"m":43,"g":94},"30ee3630":{"m":43,"g":94},"e5db40dc":{"m":43,"g":94},"b1709305":{"m":43,"g":94},"5ab20cce":{"m":43,"g":94},"02f7f3e4":{"m":43,"g":94},"2782132b":{"m":43,"g":94},"d19cc0b9":{"m":43,"g":94},"b0facb33":{"m":43,"g":94},"ecb8bad2":{"m":43,"g":94},"dbec2f18":{"m":43,"g":94},"e4b367ba":{"m":43,"g":94},"d10b933a":{"m":43,"g":94},"9116b289":{"m":43,"g":94},"a5114b6f":{"m":43,"g":94},"b6b40946":{"m":43,"g":94},"f1088e0f":{"m":43,"g":94},"175afed3":{"m":43,"g":94},"4a292f67":{"m":43,"g":94},"cd0be748":{"m":43,"g":94},"56503d9b":{"m":43,"g":94},"02bc9579":{"m":43,"g":94},"24f3e151":{"m":43,"g":94},"6790240c":{"m":43,"g":94},"061e5463":{"m":43,"g":94},"0c1e8796":{"m":43,"g":94},"869f1c02":{"m":43,"g":94},"2725f8da":{"m":43,"g":94},"da1ffed6":{"m":43,"g":94},"48761171":{"m":43,"g":94},"c3f2fc5a":{"m":43,"g":94},"7ee6c259":{"m":43,"g":94},"9610fcd4":{"m":43,"g":94},"31fad29a":{"m":43,"g":94},"9da5a60b":{"m":43,"g":94},"69aa937a":{"m":43,"g":94},"5d638c92":{"m":43,"g":94},"e37cdab0":{"m":43,"g":94},"1d9deeac":{"m":43,"g":94},"dafb6a52":{"m":43,"g":94},"862cd265":{"m":43,"g":94},"1f26e8b8":{"m":44,"g":94},"5e1558f1":{"m":44,"g":94},"94cde109":{"m":44,"g":94},"00611286":{"m":44,"g":94},"e68b9e76":{"m":44,"g":94},"7ce36068":{"m":44,"g":94},"efb099cd":{"m":44,"g":94},"09603c6d":{"m":44,"g":94},"cf470fea":{"m":44,"g":94},"45d5af24":{"m":44,"g":94},"b121bc03":{"m":44,"g":94},"e12358dc":{"m":44,"g":94},"554fbf93":{"m":44,"g":94},"b48edff6":{"m":44,"g":94},"593b19f2":{"m":44,"g":94},"59cbf476":{"m":44,"g":94},"95946271":{"m":44,"g":94},"5c4ce656":{"m":44,"g":94},"cbbc82b7":{"m":44,"g":94},"8bee20f8":{"m":44,"g":94},"12cad0fe":{"m":44,"g":94},"b6cd9036":{"m":44,"g":94},"30643fed":{"m":45,"g":94},"e646c590":{"m":45,"g":94},"c555ce2c":{"m":45,"g":94},"40900bae":{"m":45,"g":94},"a2f5e755":{"m":45,"g":94},"2148914e":{"m":45,"g":94},"def55bc8":{"m":45,"g":94},"86a2c473":{"m":45,"g":94},"1701b0db":{"m":45,"g":94},"384d85ba":{"m":45,"g":94},"60597219":{"m":45,"g":94},"fc82f5a7":{"m":45,"g":94},"0089c4bc":{"m":45,"g":94},"72e7b57a":{"m":45,"g":94},"87a7cfa0":{"m":45,"g":94},"8f8f96a6":{"m":45,"g":94},"05b3bf5e":{"m":45,"g":94},"3f5ac88d":{"m":45,"g":94},"0d800090":{"m":45,"g":94},"b7d05594":{"m":45,"g":94},"80a90547":{"m":45,"g":94},"9af7b88e":{"m":45,"g":94},"fbcbb263":{"m":45,"g":94},"2fce449b":{"m":45,"g":94},"ad4125d1":{"m":45,"g":94},"17536e7e":{"m":45,"g":94},"65859754":{"m":46,"g":94},"2ce32db6":{"m":46,"g":94},"793b79db":{"m":46,"g":94},"1363b519":{"m":46,"g":94},"0abbf289":{"m":46,"g":94},"c17c5781":{"m":46,"g":94},"916b3cdd":{"m":46,"g":94},"838dcda1":{"m":46,"g":94},"efbc116a":{"m":46,"g":94},"6aed0445":{"m":46,"g":94},"908dd7f9":{"m":46,"g":94},"f4cd8040":{"m":46,"g":94},"be7986e0":{"m":46,"g":94},"5a5f1843":{"m":46,"g":94},"7b394e5f":{"m":46,"g":94},"3b60558d":{"m":46,"g":94},"5a9a4f41":{"m":46,"g":94},"72e979bf":{"m":46,"g":94},"146f6134":{"m":46,"g":94},"660ecb73":{"m":46,"g":94},"2565cb0f":{"m":46,"g":94},"066e8a4e":{"m":46,"g":94},"2134f089":{"m":46,"g":94},"a54f278d":{"m":46,"g":94},"d1b31b06":{"m":46,"g":94},"d59a4782":{"m":46,"g":94},"104bf260":{"m":46,"g":94},"3bf3d011":{"m":46,"g":94},"d86a2d65":{"m":46,"g":94},"16eb33ff":{"m":46,"g":94},"61cf00e1":{"m":46,"g":94},"b9fd178f":{"m":46,"g":94},"d8e9d61f":{"m":46,"g":94},"a2e0424a":{"m":46,"g":94},"8ce202a4":{"m":46,"g":94},"d913d52c":{"m":46,"g":94},"0ab7bcaf":{"m":46,"g":94},"438526a8":{"m":46,"g":94},"f7102fbd":{"m":46,"g":94},"a7a0a688":{"m":46,"g":94},"2d4ce1b7":{"m":46,"g":94},"4ba815b8":{"m":46,"g":94},"5f65e2b8":{"m":46,"g":94},"4e2af03c":{"m":46,"g":94},"3184aa95":{"m":46,"g":94},"b548801d":{"m":46,"g":94},"539df95d":{"m":46,"g":94},"5e00ddeb":{"m":46,"g":94},"54dd3ea1":{"m":46,"g":94},"d04899d7":{"m":46,"g":94},"5010e0d2":{"m":46,"g":94},"5e6c3265":{"m":46,"g":94},"680cad20":{"m":46,"g":94},"0a24eb85":{"m":46,"g":94},"3839be29":{"m":46,"g":94},"6e13b650":{"m":46,"g":94},"6fcd6d7d":{"m":46,"g":94},"c77762d5":{"m":46,"g":94},"51c81e33":{"m":46,"g":94},"eaade87a":{"m":46,"g":94},"86fc0d79":{"m":46,"g":94},"1be853ee":{"m":46,"g":94},"86e0dde5":{"m":46,"g":94},"2b809788":{"m":46,"g":94},"9d6fb084":{"m":46,"g":94},"ced362f7":{"m":46,"g":94},"9084a864":{"m":46,"g":94},"6aa94b96":{"m":46,"g":94},"c2650748":{"m":46,"g":94},"07bf2e84":{"m":46,"g":94},"a628dd8e":{"m":46,"g":94},"1e890341":{"m":46,"g":94},"715b16c1":{"m":46,"g":94},"9ce8e1a9":{"m":46,"g":94},"fb99aaa5":{"m":46,"g":94},"b77a02cd":{"m":46,"g":94},"f407fcf9":{"m":47,"g":94},"54479d6f":{"m":47,"g":94},"ba069a24":{"m":47,"g":94},"125b1199":{"m":47,"g":94},"eff468dd":{"m":47,"g":94},"a1bd7190":{"m":47,"g":94},"78c1d644":{"m":47,"g":94},"027e6524":{"m":47,"g":94},"b808a383":{"m":47,"g":94},"602ebc66":{"m":47,"g":94},"530ae1bd":{"m":47,"g":94},"befc6beb":{"m":47,"g":94},"59a5ba9b":{"m":47,"g":94},"86c37d01":{"m":47,"g":94},"f18b9c72":{"m":47,"g":94},"3e335743":{"m":47,"g":94},"0d94f1dd":{"m":47,"g":94},"e728258d":{"m":47,"g":94},"239eafbd":{"m":47,"g":94},"9d427265":{"m":47,"g":94},"00ffde20":{"m":47,"g":94},"ddeb9d42":{"m":47,"g":94},"aaf0a315":{"m":47,"g":94},"f9633fa9":{"m":47,"g":94},"087ab832":{"m":47,"g":94},"8169c6f4":{"m":47,"g":94},"3d043319":{"m":47,"g":94},"a8aad935":{"m":47,"g":94},"47ffe7af":{"m":47,"g":94},"b3523af8":{"m":47,"g":94},"1929c067":{"m":47,"g":94},"ed53ac84":{"m":47,"g":94},"520f0094":{"m":47,"g":94},"9c939a3d":{"m":47,"g":94},"549e8b83":{"m":47,"g":94},"a1f32867":{"m":47,"g":94},"760552e0":{"m":47,"g":94},"d9aada9d":{"m":47,"g":94},"f11eb90f":{"m":47,"g":94},"95a4ed12":{"m":47,"g":94},"d1150e9a":{"m":47,"g":94},"e3126e3c":{"m":47,"g":94},"a5095520":{"m":47,"g":94},"7ef0084b":{"m":47,"g":94},"f9a377f6":{"m":47,"g":94},"4ade15dd":{"m":47,"g":94},"8dc84da0":{"m":47,"g":94},"f16eb15d":{"m":47,"g":94},"5bc2508b":{"m":47,"g":94},"a71a44f2":{"m":47,"g":94},"691808d5":{"m":47,"g":94},"d32fba2a":{"m":47,"g":94},"67c424cc":{"m":47,"g":94},"1ae270c5":{"m":47,"g":94},"c77c1e05":{"m":47,"g":94},"dca87ec3":{"m":47,"g":94},"4b1d7a25":{"m":47,"g":94},"a5e0defb":{"m":47,"g":94},"96766101":{"m":47,"g":94},"a146d999":{"m":47,"g":94},"f5113e50":{"m":47,"g":94},"02755768":{"m":47,"g":94},"463d56bf":{"m":47,"g":94},"530ff541":{"m":47,"g":94},"3cd28092":{"m":47,"g":94},"704f8e8e":{"m":47,"g":94},"1853c352":{"m":47,"g":94},"32c9a7ec":{"m":48,"g":94},"b01df48c":{"m":48,"g":94},"c29b98e0":{"m":48,"g":94},"954f4e6b":{"m":48,"g":94},"2558d6a6":{"m":48,"g":94},"29ebe3df":{"m":48,"g":94},"f6dd6486":{"m":48,"g":94},"ea53c63b":{"m":48,"g":94},"a10d5309":{"m":48,"g":94},"aae5434b":{"m":48,"g":94},"c3eac1b0":{"m":48,"g":94},"b275ce00":{"m":48,"g":94},"13ce3e4b":{"m":48,"g":94},"df246e69":{"m":48,"g":94},"fb9fb351":{"m":48,"g":94},"c722d9bd":{"m":48,"g":94},"218ab361":{"m":48,"g":94},"9a00e6f4":{"m":49,"g":94},"4f8c3aea":{"m":49,"g":94},"2369e882":{"m":49,"g":94},"ad30d5cf":{"m":49,"g":94},"dfec7fca":{"m":49,"g":94},"8048c28c":{"m":49,"g":94},"30af7dfb":{"m":49,"g":94},"f6f71379":{"m":49,"g":94},"f35cb46c":{"m":49,"g":94},"7f8fcd39":{"m":49,"g":94},"5c6a41fa":{"m":49,"g":94},"722530fa":{"m":49,"g":94},"56a347f7":{"m":49,"g":94},"3295cd8a":{"m":49,"g":94},"5942dfc0":{"m":49,"g":94},"63a395b9":{"m":49,"g":94},"7d671e4a":{"m":49,"g":94},"699384cb":{"m":49,"g":94},"ffd20fcd":{"m":49,"g":94},"55bd97f3":{"m":49,"g":94},"e57c3e12":{"m":49,"g":94},"f239268f":{"m":49,"g":94},"929c7621":{"m":49,"g":94},"b7a065ea":{"m":49,"g":94},"b1104538":{"m":49,"g":94},"3b44bbee":{"m":49,"g":94},"80e2c4a8":{"m":49,"g":94},"66318ffe":{"m":49,"g":94},"76619261":{"m":49,"g":94},"2a3992b6":{"m":49,"g":94},"4af3f889":{"m":49,"g":94},"df7fe452":{"m":49,"g":94},"a7164b62":{"m":49,"g":94},"11668533":{"m":49,"g":94},"a9e90b4b":{"m":49,"g":94},"8c280cee":{"m":49,"g":94},"9c745d07":{"m":49,"g":94},"ebaa2f31":{"m":49,"g":94},"62832bb2":{"m":49,"g":94},"11f881d1":{"m":49,"g":94},"38625e21":{"m":49,"g":94},"c1f401fc":{"m":49,"g":94},"3b878863":{"m":49,"g":94},"f719d9ae":{"m":49,"g":94},"edad3731":{"m":49,"g":94},"976bc302":{"m":49,"g":94},"2f2e0743":{"m":49,"g":94},"2ffe0a73":{"m":49,"g":94},"cf248976":{"m":49,"g":94},"e5c67150":{"m":49,"g":94},"023d0a73":{"m":49,"g":94},"ac5a0f04":{"m":50,"g":94},"ea34350d":{"m":50,"g":94},"1605ae12":{"m":50,"g":94},"1aea19f6":{"m":50,"g":94},"1f76fc6e":{"m":50,"g":94},"7f076c2c":{"m":50,"g":94},"3c5538f7":{"m":50,"g":94},"10189d08":{"m":50,"g":94},"c4336b2b":{"m":50,"g":94},"4d62bca5":{"m":50,"g":94},"e1e595d7":{"m":50,"g":94},"5ada33ff":{"m":50,"g":94},"254fd130":{"m":50,"g":94},"538fa0ae":{"m":50,"g":94},"55842eb8":{"m":50,"g":94},"a866b65e":{"m":50,"g":94},"4b0a1c93":{"m":50,"g":94},"8e1adb84":{"m":50,"g":94},"dd44173d":{"m":50,"g":94},"8912b763":{"m":50,"g":94},"be0124bd":{"m":50,"g":94},"fe5d3e81":{"m":50,"g":94},"731146f6":{"m":50,"g":94},"fa271613":{"m":50,"g":94},"5652c565":{"m":50,"g":94},"e3938b2f":{"m":50,"g":94},"c211e7b6":{"m":50,"g":94},"d90c3d6b":{"m":50,"g":94},"9e8f8fbf":{"m":50,"g":94},"b509db58":{"m":50,"g":94},"dbe17293":{"m":50,"g":94},"84a1698d":{"m":50,"g":94},"32293a29":{"m":50,"g":94},"79216908":{"m":50,"g":94},"bbb81c24":{"m":50,"g":94},"52f58fc4":{"m":50,"g":94},"145c0ddc":{"m":50,"g":94},"505d7f71":{"m":50,"g":94},"cbedd1db":{"m":50,"g":94},"ad47749b":{"m":50,"g":94},"751c3a03":{"m":50,"g":94},"60769be1":{"m":50,"g":94},"a78d8f8d":{"m":50,"g":94},"c5f86501":{"m":50,"g":94},"d98fa1e9":{"m":50,"g":94},"865233e2":{"m":50,"g":94},"66d4859a":{"m":50,"g":94},"e1b63624":{"m":50,"g":94},"c35cd1f8":{"m":50,"g":94},"72f87b72":{"m":50,"g":94},"62a4a339":{"m":50,"g":94},"2797bc34":{"m":50,"g":94},"fed4c694":{"m":51,"g":94},"fb6e04a0":{"m":51,"g":94},"6997e28f":{"m":51,"g":94},"a0e58740":{"m":51,"g":94},"37c8a576":{"m":51,"g":94},"c754652f":{"m":51,"g":94},"0b46b951":{"m":51,"g":94},"2763c0a7":{"m":51,"g":94},"de3b67b7":{"m":51,"g":94},"19f33b32":{"m":51,"g":94},"30ce5b59":{"m":51,"g":94},"bc1f6fda":{"m":51,"g":94},"867e092f":{"m":51,"g":94},"88c7763f":{"m":51,"g":94},"e4118b15":{"m":51,"g":94},"ba4ee37f":{"m":51,"g":94},"fae4e5e9":{"m":52,"g":94},"afe1e465":{"m":52,"g":94},"f50a6cf4":{"m":52,"g":94},"fe97a2d4":{"m":52,"g":94},"8b48496a":{"m":52,"g":94},"4057ea82":{"m":52,"g":94},"4f2ee48e":{"m":52,"g":94},"71ff2728":{"m":52,"g":94},"b7038fec":{"m":52,"g":94},"65fdb289":{"m":52,"g":94},"b2ccf36d":{"m":52,"g":94},"d4fc1a70":{"m":52,"g":94},"db674e3d":{"m":52,"g":94},"fb915bd1":{"m":52,"g":94},"09798b36":{"m":52,"g":94},"b79fffdc":{"m":52,"g":94},"cd51758f":{"m":52,"g":94},"91e5dbf5":{"m":52,"g":94},"dd5eba4c":{"m":52,"g":94},"a4fd2f9b":{"m":52,"g":94},"92d1253e":{"m":52,"g":94},"a9ca297d":{"m":52,"g":94},"2a02185c":{"m":52,"g":94},"f8b03269":{"m":53,"g":94},"04957965":{"m":53,"g":94},"1228f7ca":{"m":53,"g":94},"fda628d8":{"m":53,"g":94},"07ec07ad":{"m":53,"g":94},"83b340e3":{"m":53,"g":94},"0639bf15":{"m":53,"g":94},"aa47f642":{"m":53,"g":94},"3ddb1c46":{"m":53,"g":94},"480e38a7":{"m":53,"g":94},"69e2d4fb":{"m":53,"g":94},"85e1a6f3":{"m":53,"g":94},"33deca81":{"m":53,"g":94},"18108abe":{"m":53,"g":94},"c54bda30":{"m":53,"g":94},"3c79ad35":{"m":53,"g":94},"983bfcf3":{"m":53,"g":94},"28bc60dc":{"m":53,"g":94},"7301a39b":{"m":53,"g":94},"47eb139f":{"m":53,"g":94},"5c18a037":{"m":53,"g":94},"5c91a315":{"m":53,"g":94},"3dbd73d3":{"m":53,"g":94},"e9a6203d":{"m":53,"g":94},"62c516ac":{"m":53,"g":94},"fc78640e":{"m":53,"g":94},"906d795f":{"m":53,"g":94},"118b6af3":{"m":53,"g":94},"9449a954":{"m":53,"g":94},"5f12f0e7":{"m":53,"g":94},"d5b95cbb":{"m":53,"g":94},"0303ca91":{"m":53,"g":94},"00181098":{"m":53,"g":94},"4936be8a":{"m":53,"g":94},"1bfa511b":{"m":53,"g":94},"f5b5f2bf":{"m":53,"g":94},"7e4c6dd8":{"m":53,"g":94},"d622851d":{"m":53,"g":94},"883c9554":{"m":53,"g":94},"0d6a49bd":{"m":53,"g":94},"ccaf1f99":{"m":53,"g":94},"7d1485d3":{"m":53,"g":94},"7d5d1d3d":{"m":53,"g":94},"b53d6cbd":{"m":53,"g":94},"01017d4c":{"m":53,"g":94},"94e167ea":{"m":53,"g":94},"262e370f":{"m":53,"g":94},"419a57e7":{"m":53,"g":94},"e5f227c0":{"m":54,"g":94},"0e7409ad":{"m":54,"g":94},"3cde5eb6":{"m":54,"g":94},"f5b2a3aa":{"m":54,"g":94},"f6817596":{"m":54,"g":94},"67b65794":{"m":54,"g":94},"37ee906f":{"m":54,"g":94},"34b364e0":{"m":54,"g":94},"84d96b3a":{"m":54,"g":94},"3d32e4a3":{"m":54,"g":94},"64fceab8":{"m":54,"g":94},"71e2a277":{"m":54,"g":94},"4a63c181":{"m":54,"g":94},"2b0fc594":{"m":54,"g":94},"9cc733b3":{"m":54,"g":94},"d693ec04":{"m":54,"g":94},"18ea841f":{"m":54,"g":94},"786be44d":{"m":54,"g":94},"2db44698":{"m":54,"g":94},"ed45e509":{"m":54,"g":94},"ec52464d":{"m":54,"g":94},"eb0c1f53":{"m":54,"g":94},"b2986d7a":{"m":54,"g":94},"8f4d04e5":{"m":55,"g":94},"feb2b768":{"m":55,"g":94},"d95a5f5b":{"m":55,"g":94},"4b83db24":{"m":55,"g":94},"64456cf0":{"m":55,"g":94},"bb4a9220":{"m":55,"g":94},"21e9e63a":{"m":55,"g":94},"1fc84cf6":{"m":55,"g":94},"361ea8d9":{"m":55,"g":94},"33c5ff28":{"m":55,"g":94},"5ce9daea":{"m":55,"g":94},"ce094a5d":{"m":55,"g":94},"e2102669":{"m":55,"g":94},"bd619616":{"m":55,"g":94},"56198b45":{"m":55,"g":94},"ba36b552":{"m":55,"g":94},"9cd9dc83":{"m":55,"g":94},"7a1aecb9":{"m":55,"g":94},"82699474":{"m":55,"g":94},"7154b4b1":{"m":55,"g":94},"b532a5fd":{"m":55,"g":94},"a0592c05":{"m":55,"g":94},"e8dbdf75":{"m":55,"g":94},"e04d3f28":{"m":55,"g":94},"5f2595be":{"m":55,"g":94},"0ba2c589":{"m":55,"g":94},"fccbfa37":{"m":55,"g":94},"2f9bd0fa":{"m":55,"g":94},"5282a473":{"m":55,"g":94},"f0ed9c35":{"m":55,"g":94},"e3b3acfa":{"m":55,"g":94},"2673fa29":{"m":55,"g":94},"dedaf8cd":{"m":55,"g":94},"32ed0160":{"m":55,"g":94},"6efa9e4a":{"m":55,"g":94},"7791fd99":{"m":55,"g":94},"2ac36b9a":{"m":55,"g":94},"2d60a5ee":{"m":55,"g":94},"2e4a5907":{"m":55,"g":94},"c0ee46fe":{"m":55,"g":94},"9208618b":{"m":55,"g":94},"864bf2ba":{"m":55,"g":94},"a4cca7fc":{"m":55,"g":94},"993956c6":{"m":55,"g":94},"f8548295":{"m":55,"g":94},"959735fc":{"m":55,"g":94},"f6772394":{"m":55,"g":94},"626a99ac":{"m":55,"g":94},"ece72491":{"m":55,"g":94},"0fb88aaa":{"m":55,"g":94},"d4de9a62":{"m":55,"g":94},"7310aede":{"m":55,"g":94},"5de9a58e":{"m":55,"g":94},"56fcd8e8":{"m":55,"g":94},"2b340adf":{"m":55,"g":94},"8586b72d":{"m":55,"g":94},"641b7d0a":{"m":55,"g":94},"0ce091a8":{"m":55,"g":94},"835f8afc":{"m":55,"g":94},"3844feb9":{"m":55,"g":94},"27f7bed7":{"m":55,"g":94},"6387098f":{"m":55,"g":94},"2a717c50":{"m":55,"g":94},"a1e697b2":{"m":55,"g":94},"a6ca736c":{"m":55,"g":94},"f62055b5":{"m":55,"g":94},"74bc9184":{"m":55,"g":94},"0f8eb153":{"m":55,"g":94},"67470bbb":{"m":55,"g":94},"cc858953":{"m":55,"g":94},"6128f7cf":{"m":55,"g":94},"a2486eb5":{"m":55,"g":94},"61dec545":{"m":55,"g":94},"96db0f66":{"m":55,"g":94},"7dc66fcb":{"m":55,"g":94},"1f09e84b":{"m":55,"g":94},"63dfab1b":{"m":55,"g":94},"ef995dae":{"m":55,"g":94},"75ae9689":{"m":55,"g":94},"95f93f49":{"m":55,"g":94},"aaac33fd":{"m":55,"g":94},"d332aa3b":{"m":55,"g":94},"c36736c8":{"m":55,"g":94},"1bf9e347":{"m":55,"g":94},"499c85f1":{"m":55,"g":94},"efc52f85":{"m":56,"g":94},"60e2fdcf":{"m":56,"g":94},"d7c0e872":{"m":56,"g":94},"31548116":{"m":56,"g":94},"53aed988":{"m":56,"g":94},"8a56b431":{"m":56,"g":94},"e835a500":{"m":56,"g":94},"23e5e50f":{"m":56,"g":94},"25e5d589":{"m":56,"g":94},"41b1db69":{"m":56,"g":94},"84967019":{"m":56,"g":94},"7d672d27":{"m":56,"g":94},"d4b17481":{"m":56,"g":94},"19ba2b0e":{"m":56,"g":94},"4e1e3cff":{"m":56,"g":94},"ef5b0ff9":{"m":57,"g":94},"6e530515":{"m":57,"g":94},"77d1210b":{"m":57,"g":94},"70dc2fbe":{"m":57,"g":94},"b438a2e5":{"m":57,"g":94},"7ca751ff":{"m":57,"g":94},"c75adfec":{"m":57,"g":94},"7722c11c":{"m":57,"g":94},"b2ed5c8e":{"m":57,"g":94},"f46f394f":{"m":57,"g":94},"2125898a":{"m":57,"g":94},"44f011d2":{"m":57,"g":94},"ed91e003":{"m":57,"g":94},"531d6ea9":{"m":57,"g":94},"dc3bee48":{"m":57,"g":94},"a74d1941":{"m":57,"g":94},"3169e66c":{"m":57,"g":94},"77395154":{"m":57,"g":94},"637de9e8":{"m":57,"g":94},"acb34072":{"m":57,"g":94},"08effbff":{"m":57,"g":94},"60bd3272":{"m":57,"g":94},"e7ebecf8":{"m":57,"g":94},"9a23c484":{"m":57,"g":94},"635a0426":{"m":57,"g":94},"2dccecf4":{"m":57,"g":94},"75ad0a14":{"m":57,"g":94},"3ccf566b":{"m":58,"g":94},"afa0341e":{"m":58,"g":94},"30828e71":{"m":58,"g":94},"e0e09fce":{"m":58,"g":94},"9c05c689":{"m":58,"g":94},"3464e57b":{"m":58,"g":94},"3815b23c":{"m":58,"g":94},"fd34f2da":{"m":58,"g":94},"8ee9a850":{"m":58,"g":94},"fd28640d":{"m":58,"g":94},"7863e436":{"m":58,"g":94},"333e3bfd":{"m":58,"g":94},"239c9d4d":{"m":58,"g":94},"855d0ba3":{"m":58,"g":94},"9254a33a":{"m":58,"g":94},"8a2681e2":{"m":58,"g":94},"5276a675":{"m":58,"g":94},"751e5ca2":{"m":58,"g":94},"7a7ac6be":{"m":58,"g":94},"d9e6ee38":{"m":58,"g":94},"03d5fbfd":{"m":59,"g":94},"1703d766":{"m":59,"g":94},"09e6e2aa":{"m":59,"g":94},"fad29f7f":{"m":59,"g":94},"35bdb485":{"m":59,"g":94},"b085e06b":{"m":59,"g":94},"763dd55d":{"m":59,"g":94},"2f0d3864":{"m":60,"g":94},"3900a94a":{"m":60,"g":94},"ded9fcd0":{"m":60,"g":94},"bc6ad367":{"m":60,"g":94},"3a22a303":{"m":60,"g":94},"bdb3929d":{"m":60,"g":94},"f5d0865b":{"m":60,"g":94},"afdee7b1":{"m":60,"g":94},"cb34d848":{"m":60,"g":94},"0f9cc6d8":{"m":60,"g":94},"c7ae474a":{"m":60,"g":94},"bdf946bf":{"m":60,"g":94},"8c8779cd":{"m":60,"g":94},"1775b963":{"m":60,"g":94},"dd2e2d27":{"m":60,"g":94},"a990daff":{"m":60,"g":94},"ba5112ff":{"m":60,"g":94},"815dce05":{"m":60,"g":94},"ad20b795":{"m":60,"g":94},"9183c23e":{"m":60,"g":94},"148254d4":{"m":60,"g":94},"a4d6d6f1":{"m":60,"g":94},"062c48d2":{"m":60,"g":94},"b6e0cfb5":{"m":60,"g":94},"0d8d97b8":{"m":60,"g":94},"0a765bbc":{"m":60,"g":94},"286cad3e":{"m":60,"g":94},"dc7eb01f":{"m":60,"g":94},"b0524c37":{"m":60,"g":94},"6c42fa22":{"m":60,"g":94},"d49b13c6":{"m":60,"g":94},"bedc4c7a":{"m":60,"g":94},"f44d1439":{"m":60,"g":94},"b6b57fc2":{"m":60,"g":94},"b4403985":{"m":60,"g":94},"339c69a2":{"m":60,"g":94},"f7074700":{"m":60,"g":94},"21ec66e5":{"m":60,"g":94},"c5210dfa":{"m":60,"g":94},"a29dd950":{"m":60,"g":94},"9c6ba248":{"m":60,"g":94},"b02da24a":{"m":60,"g":94},"bdd2827a":{"m":60,"g":94},"8c3b420e":{"m":60,"g":94},"e6f523b5":{"m":60,"g":94},"32318178":{"m":60,"g":94},"a11f8d5f":{"m":60,"g":94},"098d659c":{"m":60,"g":94},"76d14f8c":{"m":60,"g":94},"b08c308e":{"m":60,"g":94},"f624901c":{"m":61,"g":94},"f0e15dc6":{"m":61,"g":94},"f1769586":{"m":61,"g":94},"5d6e9467":{"m":61,"g":94},"a47bf391":{"m":61,"g":94},"b1706469":{"m":61,"g":94},"5413ec2b":{"m":61,"g":94},"f290bd43":{"m":61,"g":94},"8f157893":{"m":61,"g":94},"2db03a04":{"m":61,"g":94},"5cc11705":{"m":61,"g":94},"11fffbc9":{"m":61,"g":94},"4f077c01":{"m":61,"g":94},"679c3bca":{"m":61,"g":94},"656aed58":{"m":61,"g":94},"b5fb4ef5":{"m":61,"g":94},"2e6346fc":{"m":61,"g":94},"977f785d":{"m":61,"g":94},"8a690612":{"m":61,"g":94},"694e4192":{"m":61,"g":94},"b22f3f64":{"m":61,"g":94},"6fb57683":{"m":61,"g":94},"51caee74":{"m":61,"g":94},"58f9060e":{"m":61,"g":94},"bdc1acf6":{"m":61,"g":94},"6d08ce2a":{"m":61,"g":94},"380930a9":{"m":61,"g":94},"9dec582d":{"m":61,"g":94},"b01febdc":{"m":61,"g":94},"1acbaf1b":{"m":61,"g":94},"287427e2":{"m":61,"g":94},"b8574f69":{"m":61,"g":94},"2855caa4":{"m":61,"g":94},"2329e1dd":{"m":61,"g":94},"0f3eb1d2":{"m":61,"g":94},"06dd2eab":{"m":61,"g":94},"439f6580":{"m":61,"g":94},"b3e99dfb":{"m":62,"g":94},"f005758f":{"m":62,"g":94},"f5c6c667":{"m":62,"g":94},"cc0485be":{"m":62,"g":94},"b8cd09f2":{"m":62,"g":94},"c19d8482":{"m":62,"g":94},"80002562":{"m":62,"g":94},"46d44318":{"m":62,"g":94},"923f5183":{"m":62,"g":94},"d08c77c4":{"m":62,"g":94},"c1e097ca":{"m":62,"g":94},"6ec75e62":{"m":62,"g":94},"d855653b":{"m":62,"g":94},"336ff5b9":{"m":62,"g":94},"3b141e15":{"m":62,"g":94},"6249e4a1":{"m":62,"g":94},"f3516c28":{"m":62,"g":94},"17de02f9":{"m":62,"g":94},"51ab3ccf":{"m":62,"g":94},"67008f4b":{"m":62,"g":94},"4536d724":{"m":62,"g":94},"41d7e5b7":{"m":62,"g":94},"20a9f5df":{"m":62,"g":94},"42f39099":{"m":62,"g":94},"72c77763":{"m":62,"g":94},"4093aa46":{"m":62,"g":94},"e808c1df":{"m":62,"g":94},"a18ab81d":{"m":62,"g":94},"0bb0f763":{"m":62,"g":94},"85b2e057":{"m":62,"g":94},"a879c2fb":{"m":62,"g":94},"e2b16c47":{"m":62,"g":94},"c4f9707e":{"m":62,"g":94},"197cbf9b":{"m":62,"g":94},"e94fb7cb":{"m":63,"g":94},"b5caa22d":{"m":63,"g":94},"73401fd0":{"m":63,"g":94},"89cd9235":{"m":63,"g":94},"dc188132":{"m":63,"g":94},"10bfce71":{"m":63,"g":94},"583697cd":{"m":63,"g":94},"2584f6d9":{"m":63,"g":94},"51e87f6f":{"m":63,"g":94},"09bcbe01":{"m":63,"g":94},"03464890":{"m":63,"g":94},"44a96697":{"m":63,"g":94},"1a820e38":{"m":63,"g":94},"0ffcfdf4":{"m":63,"g":94},"cd493b5a":{"m":63,"g":94},"61f42b57":{"m":63,"g":94},"e403d237":{"m":63,"g":94},"3bcf5ece":{"m":63,"g":94},"2c05f81f":{"m":63,"g":94},"d77caa2b":{"m":63,"g":94},"8b6a4486":{"m":63,"g":94},"a69cb5cf":{"m":63,"g":94},"def5c318":{"m":63,"g":94},"3fc2b625":{"m":63,"g":94},"6ada05d0":{"m":63,"g":94},"24cafe31":{"m":63,"g":94},"5a176c92":{"m":63,"g":94},"4719c1d0":{"m":63,"g":94},"ef18b0ed":{"m":63,"g":94},"53cc91e5":{"m":63,"g":94},"d33cbb7e":{"m":63,"g":94},"23196d52":{"m":63,"g":94},"93b77c8e":{"m":63,"g":94},"7906d1d2":{"m":63,"g":94},"81d27c8e":{"m":63,"g":94},"4d4cdb3f":{"m":63,"g":94},"2bd18e2d":{"m":63,"g":94},"83452dbb":{"m":63,"g":94},"3d93f84a":{"m":63,"g":94},"c2f212d6":{"m":63,"g":94},"e2cdc8a5":{"m":63,"g":94},"2add697d":{"m":63,"g":94},"6f98c586":{"m":63,"g":94},"656dcc1a":{"m":63,"g":94},"8af7048d":{"m":63,"g":94},"d3024f4f":{"m":63,"g":94},"13387e6b":{"m":63,"g":94},"120c3634":{"m":63,"g":94},"78e5b22f":{"m":63,"g":94},"7a15e9ad":{"m":63,"g":94},"dc2ac0cb":{"m":63,"g":94},"d47c5101":{"m":63,"g":94},"033c715b":{"m":63,"g":94},"d06c1ab5":{"m":63,"g":94},"c5644cac":{"m":63,"g":94},"53e6552f":{"m":63,"g":94},"5dc54f1a":{"m":63,"g":94},"f3e9b489":{"m":63,"g":94},"6a7973ad":{"m":63,"g":94},"63051738":{"m":63,"g":94},"a8ccacc8":{"m":63,"g":94},"0427416b":{"m":63,"g":94},"bf3edc2c":{"m":63,"g":94},"78e974b2":{"m":63,"g":94},"bc6915e3":{"m":63,"g":94},"a883f079":{"m":63,"g":94},"8b6ce52e":{"m":63,"g":94},"58f3f2b8":{"m":63,"g":94},"93d69061":{"m":63,"g":94},"e00e5385":{"m":63,"g":94},"a2f602b5":{"m":63,"g":94},"8f2c522a":{"m":63,"g":94},"75964177":{"m":63,"g":94},"2dc957d4":{"m":63,"g":94},"bf8d07a6":{"m":63,"g":94},"ab317936":{"m":63,"g":94},"b7f3fec1":{"m":63,"g":94},"58f42b1d":{"m":63,"g":94},"767c9dec":{"m":63,"g":94},"a53454c5":{"m":63,"g":94},"6cb3974e":{"m":63,"g":94},"f65c13b5":{"m":63,"g":94},"b803b395":{"m":63,"g":94},"bfbda62c":{"m":63,"g":94},"4ab43cfb":{"m":64,"g":94},"2f79f588":{"m":64,"g":94},"8a96f749":{"m":64,"g":94},"827aa873":{"m":64,"g":94},"f8ca66fb":{"m":64,"g":94},"53cef815":{"m":64,"g":94},"351a72d4":{"m":64,"g":94},"514f37c3":{"m":64,"g":94},"52c03f16":{"m":64,"g":94},"741fccd7":{"m":64,"g":94},"1e3e5215":{"m":64,"g":94},"fb11a439":{"m":64,"g":94},"af02f99b":{"m":64,"g":94},"9472e699":{"m":64,"g":94},"1acc1f56":{"m":64,"g":94},"b045841b":{"m":64,"g":94},"f265d15b":{"m":64,"g":94},"02431b9a":{"m":64,"g":94},"1dda8c5e":{"m":64,"g":94},"7e097613":{"m":64,"g":94},"f4a92f4b":{"m":64,"g":94},"318260c0":{"m":64,"g":94},"4a612531":{"m":64,"g":94},"d1a08632":{"m":64,"g":94},"f8b28e46":{"m":64,"g":94},"82392da8":{"m":64,"g":94},"95f789ad":{"m":64,"g":94},"4f118a39":{"m":64,"g":94},"66283dbc":{"m":64,"g":94},"822bae8c":{"m":64,"g":94},"8e48ca8c":{"m":64,"g":94},"27acf63b":{"m":64,"g":94},"da6f8081":{"m":64,"g":94},"9286740e":{"m":64,"g":94},"896c0744":{"m":64,"g":94},"c23d5706":{"m":64,"g":94},"67ad4338":{"m":64,"g":94},"3cab5f71":{"m":64,"g":94},"14e754a8":{"m":64,"g":94},"98522149":{"m":64,"g":94},"5d9d15e7":{"m":64,"g":94},"665e5e85":{"m":64,"g":94},"a22f60a3":{"m":64,"g":94},"04f0b4cb":{"m":64,"g":94},"4505a436":{"m":64,"g":94},"685a5738":{"m":64,"g":94},"153b414e":{"m":64,"g":94},"6619f48e":{"m":64,"g":94},"3ed0a547":{"m":64,"g":94},"8d8ef849":{"m":64,"g":94},"9a0cc2e9":{"m":64,"g":94},"7bad7e75":{"m":64,"g":94},"1c4e0d24":{"m":64,"g":94},"54bac8af":{"m":64,"g":94},"5de4051b":{"m":64,"g":94},"e0cd65c2":{"m":64,"g":94},"f1b68618":{"m":64,"g":94},"0da0989a":{"m":64,"g":94},"07a22cbb":{"m":64,"g":94},"3d0bfa3e":{"m":64,"g":94},"1f6cf0d4":{"m":64,"g":94},"553f5a3f":{"m":64,"g":94},"ac2dc35d":{"m":64,"g":94},"3e032c07":{"m":64,"g":94},"44e12ce4":{"m":64,"g":94},"a547aad6":{"m":64,"g":94},"ea535dc5":{"m":64,"g":94},"862bcff8":{"m":64,"g":94},"8b84e69f":{"m":64,"g":94},"5de50653":{"m":64,"g":94},"c0bf9bf1":{"m":64,"g":94},"022614d2":{"m":64,"g":94},"b8ab989f":{"m":64,"g":94},"b3393e94":{"m":64,"g":94},"ddc2001f":{"m":64,"g":94},"806a3002":{"m":64,"g":94},"0d2148ef":{"m":64,"g":94},"bf669606":{"m":64,"g":94},"b2bd8f44":{"m":64,"g":94},"9d9b482a":{"m":64,"g":94},"7353fb9b":{"m":64,"g":94},"bcda0c9e":{"m":64,"g":94},"9f8f2c7f":{"m":64,"g":94},"6fc37bd8":{"m":64,"g":94},"3d8f1c9b":{"m":64,"g":94},"a42213db":{"m":64,"g":94},"0ac019f1":{"m":64,"g":94},"5a0d680a":{"m":64,"g":94},"a4331cd2":{"m":64,"g":94},"ec1c21cd":{"m":64,"g":94},"6c856b4f":{"m":64,"g":94},"287d07a6":{"m":64,"g":94},"d2571dd5":{"m":64,"g":94},"b730aa6b":{"m":64,"g":94},"60b2a44a":{"m":64,"g":94},"949b3fbf":{"m":64,"g":94},"da4e8b38":{"m":64,"g":94},"af6c5357":{"m":64,"g":94},"3ad4cd49":{"m":64,"g":94},"3a8428ec":{"m":64,"g":94},"0311ce8e":{"m":64,"g":94},"5dfcacfc":{"m":64,"g":94},"41a0ccd4":{"m":64,"g":94},"cf0f7eaf":{"m":65,"g":94},"b49d6d0f":{"m":65,"g":94},"c02e3139":{"m":65,"g":94},"734daedd":{"m":65,"g":94},"3ee62235":{"m":65,"g":94},"9829e77e":{"m":65,"g":94},"cde4bbd5":{"m":65,"g":94},"9602c2aa":{"m":65,"g":94},"e81d7f11":{"m":65,"g":94},"222ce6f1":{"m":65,"g":94},"468d23cf":{"m":65,"g":94},"c38b5fb4":{"m":65,"g":94},"20453cef":{"m":65,"g":94},"9f635ea5":{"m":65,"g":94},"76285fde":{"m":65,"g":94},"988d0a4b":{"m":65,"g":94},"81262c7b":{"m":65,"g":94},"27aeb4b7":{"m":65,"g":94},"7b9b4f44":{"m":65,"g":94},"08104b56":{"m":65,"g":94},"cf142b6e":{"m":65,"g":94},"7aad8d18":{"m":66,"g":94},"76fa2d15":{"m":66,"g":94},"7ab84948":{"m":66,"g":94},"4885b908":{"m":66,"g":94},"c2723a42":{"m":66,"g":94},"c7256ca8":{"m":66,"g":94},"6186a8f8":{"m":66,"g":94},"a07364cc":{"m":66,"g":94},"2c1a695f":{"m":66,"g":94},"d39899e8":{"m":66,"g":94},"70817a7e":{"m":66,"g":94},"7b5a3741":{"m":66,"g":94},"4b6f62e2":{"m":66,"g":94},"897e2e25":{"m":66,"g":94},"d54cee14":{"m":66,"g":94},"00fa7d04":{"m":66,"g":94},"013021b6":{"m":66,"g":94},"3c8ac78d":{"m":66,"g":94},"455bfe8d":{"m":66,"g":94},"28b0a62b":{"m":66,"g":94},"566d61d9":{"m":66,"g":94},"55f5fc68":{"m":66,"g":94},"c27c378a":{"m":66,"g":94},"d9eb9358":{"m":66,"g":94},"959dca4f":{"m":66,"g":94},"f2b3a318":{"m":66,"g":94},"ad674097":{"m":66,"g":94},"8db776f0":{"m":66,"g":94},"4eb4b401":{"m":66,"g":94},"17dbf976":{"m":66,"g":94},"53179026":{"m":66,"g":94},"d7c0b32f":{"m":66,"g":94},"7b020cca":{"m":66,"g":94},"7876279e":{"m":66,"g":94},"34e405e0":{"m":66,"g":94},"1ebe1d6d":{"m":66,"g":94},"7811bfda":{"m":66,"g":94},"656f7fc1":{"m":66,"g":94},"c1f5f99f":{"m":67,"g":94},"fa82dfcc":{"m":67,"g":94},"5da3d21c":{"m":67,"g":94},"f2870376":{"m":67,"g":94},"f9905d59":{"m":67,"g":94},"45c87e08":{"m":67,"g":94},"2b1808ce":{"m":67,"g":94},"e868d0b6":{"m":67,"g":94},"591e751e":{"m":67,"g":94},"40022d07":{"m":67,"g":94},"823148e7":{"m":67,"g":94},"76ca91df":{"m":67,"g":94},"cdae77b0":{"m":67,"g":94},"adeee152":{"m":67,"g":94},"6792411e":{"m":67,"g":94},"7348d962":{"m":67,"g":94},"25ed22b6":{"m":67,"g":94},"200d3b16":{"m":67,"g":94},"ad349985":{"m":67,"g":94},"32de54ed":{"m":67,"g":94},"2d9c3195":{"m":67,"g":94},"07e58a2d":{"m":67,"g":94},"04d8cd20":{"m":67,"g":94},"a322051e":{"m":67,"g":94},"de553334":{"m":67,"g":94},"cddb1cdf":{"m":68,"g":94},"fa1b40e0":{"m":68,"g":94},"c45cab1c":{"m":68,"g":94},"27c4c9cf":{"m":68,"g":94},"52a492a1":{"m":68,"g":94},"36f6fc50":{"m":68,"g":94},"d8727275":{"m":68,"g":94},"6239d0b2":{"m":68,"g":94},"4cfd3add":{"m":68,"g":94},"20cf910d":{"m":68,"g":94},"0af1d239":{"m":68,"g":94},"85986bb9":{"m":68,"g":94},"64c87135":{"m":68,"g":94},"1646149a":{"m":68,"g":94},"bc72e5bd":{"m":68,"g":94},"014cab4d":{"m":68,"g":94},"4d2dbeac":{"m":68,"g":94},"29daf498":{"m":68,"g":94},"6702592d":{"m":68,"g":94},"60abdb3e":{"m":68,"g":94},"7b4e61ff":{"m":68,"g":94},"6222e1c2":{"m":68,"g":94},"fad315cb":{"m":68,"g":94},"f90db8bc":{"m":68,"g":94},"d8ad5970":{"m":68,"g":94},"849f58d6":{"m":68,"g":94},"64480df4":{"m":68,"g":94},"4530136e":{"m":68,"g":94},"0a6f18f0":{"m":68,"g":94},"e0b9a423":{"m":69,"g":94},"e0821425":{"m":69,"g":94},"70f894b8":{"m":69,"g":94},"368de366":{"m":69,"g":94},"20de05a7":{"m":69,"g":94},"f076328b":{"m":69,"g":94},"bf2a7087":{"m":69,"g":94},"871a4aa1":{"m":69,"g":94},"98eecbda":{"m":69,"g":94},"4430c0a5":{"m":69,"g":94},"640363ad":{"m":69,"g":94},"8616357a":{"m":69,"g":94},"8adbc78b":{"m":69,"g":94},"45e3a7bc":{"m":69,"g":94},"b96e92e6":{"m":69,"g":94},"693c2600":{"m":69,"g":94},"ced68066":{"m":69,"g":94},"b8318aec":{"m":69,"g":94},"2f482210":{"m":69,"g":94},"d81ac443":{"m":69,"g":94},"2491cc92":{"m":69,"g":94},"67c5de92":{"m":69,"g":94},"1e2cf2b5":{"m":69,"g":94},"9490d157":{"m":69,"g":94},"eefcbdd3":{"m":69,"g":94},"7e6d5fc6":{"m":69,"g":94},"cadd5dbe":{"m":69,"g":94},"bb418ced":{"m":69,"g":94},"fdf04a14":{"m":69,"g":94},"5f0e7de3":{"m":69,"g":94},"2f47d710":{"m":69,"g":94},"4fe92bfc":{"m":69,"g":94},"d23cb9a0":{"m":69,"g":94},"2d611323":{"m":69,"g":94},"e782eb7e":{"m":70,"g":94},"e319153b":{"m":70,"g":94},"32b44d2f":{"m":70,"g":94},"5f1a485d":{"m":70,"g":94},"c9565e49":{"m":70,"g":94},"d03c4c25":{"m":70,"g":94},"8f13377d":{"m":70,"g":94},"3d4a8f9b":{"m":70,"g":94},"7474bed8":{"m":70,"g":94},"03caefeb":{"m":70,"g":94},"bcc213df":{"m":70,"g":94},"39416e39":{"m":70,"g":94},"231c40d8":{"m":70,"g":94},"bbc47c34":{"m":70,"g":94},"dfce9269":{"m":70,"g":94},"6718b109":{"m":70,"g":94},"7711ac6e":{"m":70,"g":94},"7443197a":{"m":70,"g":94},"862dd76c":{"m":70,"g":94},"fb4c9c3a":{"m":70,"g":94},"d973c78e":{"m":70,"g":94},"6ce6eabb":{"m":70,"g":94},"4e23c961":{"m":70,"g":94},"3efbdf68":{"m":70,"g":94},"6cc30955":{"m":70,"g":94},"31eec35b":{"m":70,"g":94},"ac963be2":{"m":70,"g":94},"a5375adc":{"m":71,"g":94},"75d171a9":{"m":71,"g":94},"714f3e63":{"m":71,"g":94},"c38f3aed":{"m":71,"g":94},"2e6be53e":{"m":71,"g":94},"fc671f66":{"m":72,"g":94},"197751e9":{"m":72,"g":94},"d2d0d061":{"m":72,"g":94},"25482edb":{"m":72,"g":94},"62b362b1":{"m":72,"g":94},"44d76463":{"m":72,"g":94},"cd85b78f":{"m":72,"g":94},"0aaccbbf":{"m":72,"g":94},"357671e2":{"m":72,"g":94},"e70fa279":{"m":72,"g":94},"abe74b7b":{"m":72,"g":94},"70b3c6ee":{"m":72,"g":94},"ef9d3b3c":{"m":72,"g":94},"fc91d08a":{"m":72,"g":94},"71ab0dab":{"m":72,"g":94},"d3d4d767":{"m":72,"g":94},"5be8f1ed":{"m":72,"g":94},"e5760bc4":{"m":72,"g":94},"56a724eb":{"m":72,"g":94},"583d6af7":{"m":72,"g":94},"e074d84e":{"m":72,"g":94},"4725e3f6":{"m":72,"g":94},"77a3954b":{"m":72,"g":94},"03b0364f":{"m":72,"g":94},"2dd7d0c5":{"m":72,"g":94},"0d4e3228":{"m":72,"g":94},"926f8efc":{"m":72,"g":94},"9545bfb2":{"m":72,"g":94},"37373ef2":{"m":72,"g":94},"61261b39":{"m":72,"g":94},"19120f71":{"m":72,"g":94},"2415ec38":{"m":72,"g":94},"87f671ab":{"m":72,"g":94},"51d25405":{"m":72,"g":94},"e0a2c963":{"m":72,"g":94},"12f2e6c3":{"m":72,"g":94},"95575aa7":{"m":72,"g":94},"11eea69e":{"m":72,"g":94},"1baa9e6c":{"m":72,"g":94},"911fcd09":{"m":72,"g":94},"9fafa62d":{"m":72,"g":94},"146ac8df":{"m":72,"g":94},"57a404fd":{"m":72,"g":94},"2796fbb5":{"m":72,"g":94},"935cda94":{"m":72,"g":94},"110e0066":{"m":72,"g":94},"6b45a21d":{"m":72,"g":94},"a7000a76":{"m":72,"g":94},"1a8f995c":{"m":72,"g":94},"a3ab768a":{"m":72,"g":94},"66301e12":{"m":72,"g":94},"ac238727":{"m":72,"g":94},"0194948f":{"m":72,"g":94},"b4d34cd3":{"m":72,"g":94},"728e175f":{"m":72,"g":94},"9e1014cf":{"m":72,"g":94},"fa561067":{"m":72,"g":94},"7fbab730":{"m":72,"g":94},"b7e274f2":{"m":72,"g":94},"9cf40772":{"m":72,"g":94},"d3fe9bae":{"m":72,"g":94},"00ce7e31":{"m":72,"g":94},"50f28f65":{"m":72,"g":94},"90a55e25":{"m":72,"g":94},"407e2b92":{"m":72,"g":94},"40782f05":{"m":72,"g":94},"18bb216c":{"m":72,"g":94},"6b859e7d":{"m":72,"g":94},"930da877":{"m":72,"g":94},"3f8a4414":{"m":72,"g":94},"aceb4201":{"m":72,"g":94},"90a4b7d9":{"m":72,"g":94},"f3b99f73":{"m":72,"g":94},"9e74ee91":{"m":72,"g":94},"77a6c9d2":{"m":72,"g":94},"e3e0bc50":{"m":72,"g":94},"bac414ab":{"m":72,"g":94},"eec3f6d1":{"m":72,"g":94},"90bc26a8":{"m":72,"g":94},"ec0a72c2":{"m":72,"g":94},"1c96fa86":{"m":72,"g":94},"bc20e93f":{"m":72,"g":94},"d3887852":{"m":72,"g":94},"564bdf29":{"m":72,"g":94},"5d860168":{"m":72,"g":94},"d2815879":{"m":72,"g":94},"b0df5d24":{"m":72,"g":94},"3e02526b":{"m":72,"g":94},"d8a98a2c":{"m":72,"g":94},"0519269d":{"m":72,"g":94},"d6898dd2":{"m":72,"g":94},"71ed0183":{"m":72,"g":94},"8b681d77":{"m":72,"g":94},"194eea17":{"m":72,"g":94},"acd1a159":{"m":72,"g":94},"7c1692aa":{"m":72,"g":94},"8f019c7d":{"m":72,"g":94},"7551498a":{"m":72,"g":94},"44a2c4bd":{"m":72,"g":94},"c9fc4a9d":{"m":72,"g":94},"21463e32":{"m":72,"g":94},"3dc9ff3c":{"m":72,"g":94},"06427dfa":{"m":72,"g":94},"60524920":{"m":72,"g":94},"10771026":{"m":72,"g":94},"4606e2a3":{"m":72,"g":94},"127998cc":{"m":72,"g":94},"c0bb9eb3":{"m":72,"g":94},"7036d6fc":{"m":72,"g":94},"6ce9dbe8":{"m":72,"g":94},"3758d209":{"m":72,"g":94},"faf29e0b":{"m":72,"g":94},"b0743ea0":{"m":72,"g":94},"60b771c8":{"m":72,"g":94},"d7934cde":{"m":72,"g":94},"62bbd343":{"m":72,"g":94},"f2388f6b":{"m":72,"g":94},"c9745ee0":{"m":72,"g":94},"1a6e9757":{"m":72,"g":94},"b1100846":{"m":72,"g":94},"27a46317":{"m":72,"g":94},"c9795808":{"m":72,"g":94},"6c7a152c":{"m":72,"g":94},"4d2a88bd":{"m":72,"g":94},"45360b2f":{"m":72,"g":94},"3f41b184":{"m":72,"g":94},"45205d88":{"m":72,"g":94},"90876940":{"m":72,"g":94},"a3339d8c":{"m":72,"g":94},"14d90617":{"m":72,"g":94},"d37f9551":{"m":72,"g":94},"c66b2c9c":{"m":72,"g":94},"20b765a2":{"m":72,"g":94},"e3107222":{"m":72,"g":94},"e074e76b":{"m":72,"g":94},"4592afc2":{"m":72,"g":94},"9af0e21e":{"m":72,"g":94},"c7c79b16":{"m":72,"g":94},"d8d75d25":{"m":72,"g":94},"1df6eabd":{"m":72,"g":94},"0c227ee3":{"m":72,"g":94},"5c54ef03":{"m":72,"g":94},"c6a48521":{"m":72,"g":94},"4f678c87":{"m":72,"g":94},"e79f7420":{"m":72,"g":94},"ac053100":{"m":72,"g":94},"d5d80ab4":{"m":72,"g":94},"ddcf9fe3":{"m":72,"g":94},"6252ade9":{"m":72,"g":94},"1eb8eade":{"m":72,"g":94},"3c7bfd7e":{"m":72,"g":94},"bb121214":{"m":72,"g":94},"55de40f7":{"m":72,"g":94},"6b0aeb58":{"m":72,"g":94},"bb3e5268":{"m":72,"g":94},"f93e9158":{"m":72,"g":94},"55a7ec38":{"m":72,"g":94},"fe0673f1":{"m":72,"g":94},"99c1b9d2":{"m":72,"g":94},"634a3561":{"m":72,"g":94},"424848d2":{"m":72,"g":94},"e5ce395a":{"m":72,"g":94},"f983213a":{"m":72,"g":94},"67fc595b":{"m":72,"g":94},"07ab4d4a":{"m":72,"g":94},"522e18ea":{"m":72,"g":94},"c51dc2cc":{"m":72,"g":94},"ddf39d3f":{"m":72,"g":94},"2eab1132":{"m":72,"g":94},"058d199d":{"m":72,"g":94},"9c58e68b":{"m":73,"g":94},"d03b3467":{"m":73,"g":94},"ab7fba0e":{"m":73,"g":94},"bc1534ff":{"m":73,"g":94},"3a391812":{"m":73,"g":94},"800bf018":{"m":73,"g":94},"b16af90b":{"m":73,"g":94},"98c73d71":{"m":73,"g":94},"fcc2e37f":{"m":73,"g":94},"0804dd11":{"m":73,"g":94},"55dc8e4d":{"m":73,"g":94},"02e9e9f1":{"m":73,"g":94},"8f0b6313":{"m":73,"g":94},"b9b3b098":{"m":73,"g":94},"aee30630":{"m":73,"g":94},"286e6540":{"m":73,"g":94},"718c391f":{"m":73,"g":94},"6aaeb848":{"m":74,"g":94},"3623b6a7":{"m":74,"g":94},"4ff12642":{"m":74,"g":94},"2a4cbad8":{"m":74,"g":94},"2937387a":{"m":74,"g":94},"cf721fde":{"m":74,"g":94},"45de8971":{"m":74,"g":94},"71046fcd":{"m":74,"g":94},"c76040e3":{"m":74,"g":94},"2f6bacee":{"m":74,"g":94},"40148041":{"m":74,"g":94},"ad46550d":{"m":74,"g":94},"14344caa":{"m":74,"g":94},"f7f88b70":{"m":74,"g":94},"18c27131":{"m":74,"g":94},"ccdd10c8":{"m":74,"g":94},"76f6c0eb":{"m":74,"g":94},"959a3143":{"m":74,"g":94},"6412c5e4":{"m":74,"g":94},"0c020860":{"m":74,"g":94},"85ef7f64":{"m":74,"g":94},"f1cf6eef":{"m":74,"g":94},"0a59a465":{"m":74,"g":94},"aff79f10":{"m":74,"g":94},"01603318":{"m":74,"g":94},"56c39a05":{"m":74,"g":94},"4068e012":{"m":74,"g":94},"817d4370":{"m":74,"g":94},"c550e52f":{"m":74,"g":94},"e35a93fa":{"m":74,"g":94},"2c3656f2":{"m":74,"g":94},"d40ee62b":{"m":74,"g":94},"91b19949":{"m":74,"g":94},"7c866711":{"m":74,"g":94},"10b544ae":{"m":74,"g":94},"01090e8a":{"m":74,"g":94},"6f43a9b9":{"m":74,"g":94},"0540fef7":{"m":74,"g":94},"481f608b":{"m":74,"g":94},"ed91561f":{"m":74,"g":94},"6e7239f9":{"m":74,"g":94},"0a3960f2":{"m":74,"g":94},"07f94463":{"m":74,"g":94},"e0917e6b":{"m":74,"g":94},"7130a7ce":{"m":74,"g":94},"8f1f614e":{"m":74,"g":94},"7140ba35":{"m":74,"g":94},"d1da58e2":{"m":74,"g":94},"1cf63485":{"m":74,"g":94},"ff2ce0b8":{"m":74,"g":94},"0f2a2e3c":{"m":74,"g":94},"690e1f23":{"m":74,"g":94},"00f42707":{"m":74,"g":94},"6a02b32d":{"m":74,"g":94},"3a08f546":{"m":74,"g":94},"dce303e2":{"m":74,"g":94},"4d27eb9a":{"m":74,"g":94},"d3ecd632":{"m":74,"g":94},"cd909455":{"m":74,"g":94},"bde24ab3":{"m":74,"g":94},"bf2eefc0":{"m":74,"g":94},"5524e7d0":{"m":74,"g":94},"e187a3d5":{"m":74,"g":94},"3dd4feae":{"m":74,"g":94},"2ac189ed":{"m":74,"g":94},"5a6400ee":{"m":74,"g":94},"cf0ccd40":{"m":74,"g":94},"3d56585a":{"m":74,"g":94},"00d25a7f":{"m":74,"g":94},"1a5023e0":{"m":74,"g":94},"23308a90":{"m":74,"g":94},"ac698850":{"m":74,"g":94},"aa957102":{"m":74,"g":94},"007f8b3d":{"m":74,"g":94},"4455b26e":{"m":74,"g":94},"c553e160":{"m":74,"g":94},"7c0541b3":{"m":74,"g":94},"e8a69e4d":{"m":74,"g":94},"fbd56002":{"m":74,"g":94},"730d084f":{"m":74,"g":94},"4a05bdfa":{"m":74,"g":94},"eb06dbcb":{"m":74,"g":94},"9dfafa74":{"m":74,"g":94},"f1d09a65":{"m":74,"g":94},"df84ab2a":{"m":74,"g":94},"34c88987":{"m":74,"g":94},"0dd6cda2":{"m":74,"g":94},"9fb48f95":{"m":74,"g":94},"89ccb533":{"m":74,"g":94},"dceb256f":{"m":74,"g":94},"0e90ae62":{"m":74,"g":94},"1361ab9e":{"m":74,"g":94},"5c7dd14b":{"m":74,"g":94},"8abf74e3":{"m":74,"g":94},"ee132a45":{"m":74,"g":94},"79a321af":{"m":74,"g":94},"6eec3cdc":{"m":74,"g":94},"48473684":{"m":74,"g":94},"b3251e9f":{"m":74,"g":94},"2cadd51d":{"m":74,"g":94},"4a893d14":{"m":74,"g":94},"8d323e95":{"m":74,"g":94},"0fe7c13b":{"m":74,"g":94},"08c4d764":{"m":74,"g":94},"96d0e37f":{"m":74,"g":94},"90bb2be2":{"m":74,"g":94},"b93ef5e5":{"m":74,"g":94},"d4017a6b":{"m":74,"g":94},"d052f4c8":{"m":74,"g":94},"e1aaa79a":{"m":74,"g":94},"20c81199":{"m":74,"g":94},"70866b6f":{"m":74,"g":94},"eb61f5c9":{"m":74,"g":94},"0beea450":{"m":74,"g":94},"c827c671":{"m":74,"g":94},"b55a621f":{"m":74,"g":94},"ffa1b3e3":{"m":74,"g":94},"7e3bb527":{"m":74,"g":94},"96263f27":{"m":74,"g":94},"9376ac36":{"m":74,"g":94},"94a2b9d3":{"m":74,"g":94},"3c3eb374":{"m":74,"g":94},"d557319a":{"m":74,"g":94},"95085d65":{"m":74,"g":94},"c7f25446":{"m":74,"g":94},"63ee26d1":{"m":74,"g":94},"ad55f171":{"m":74,"g":94},"361971b8":{"m":74,"g":94},"13bc39c5":{"m":74,"g":94},"9854a18a":{"m":74,"g":94},"ebddb65a":{"m":74,"g":94},"19fd57bc":{"m":74,"g":94},"ba80c102":{"m":75,"g":94},"fbdb5050":{"m":75,"g":94},"f0afaf52":{"m":75,"g":94},"85d2365d":{"m":75,"g":94},"5fe79605":{"m":75,"g":94},"c6d7f8d3":{"m":75,"g":94},"a5a892ff":{"m":75,"g":94},"8e66fbec":{"m":75,"g":94},"f141298a":{"m":75,"g":94},"4fea040c":{"m":75,"g":94},"1099f6c9":{"m":76,"g":94},"04e3ff69":{"m":76,"g":94},"45fdf1f7":{"m":76,"g":94},"d89c0e4b":{"m":76,"g":94},"fa3c9e06":{"m":76,"g":94},"0d658ac3":{"m":76,"g":94},"ced35a06":{"m":76,"g":94},"26f07294":{"m":76,"g":94},"34e07a65":{"m":76,"g":94},"15ddd843":{"m":76,"g":94},"52029bd1":{"m":76,"g":94},"eb934bdf":{"m":76,"g":94},"e45ae444":{"m":76,"g":94},"ac3fae84":{"m":76,"g":94},"2d1b83e5":{"m":76,"g":94},"199bb01d":{"m":76,"g":94},"6b7038ba":{"m":76,"g":94},"57eec0bf":{"m":76,"g":94},"f01b0925":{"m":76,"g":94},"14269198":{"m":76,"g":94},"9b7cf9ee":{"m":76,"g":94},"1e86457c":{"m":76,"g":94},"64129fa6":{"m":76,"g":94},"e9f8e423":{"m":76,"g":94},"22c3702e":{"m":76,"g":94},"4c584fc6":{"m":76,"g":94},"77cf771e":{"m":76,"g":94},"8154de5a":{"m":76,"g":94},"c11cfda0":{"m":76,"g":94},"64edeb79":{"m":76,"g":94},"65c24c28":{"m":76,"g":94},"3980ff1b":{"m":76,"g":94},"5d7edc8e":{"m":76,"g":94},"af6535e7":{"m":76,"g":94},"93cf7fc5":{"m":76,"g":94},"2a206b22":{"m":76,"g":94},"4d253057":{"m":76,"g":94},"11577ced":{"m":76,"g":94},"ca75741e":{"m":76,"g":94},"c6d549e7":{"m":76,"g":94},"3c09548d":{"m":76,"g":94},"8796cebb":{"m":76,"g":94},"c2bd094d":{"m":76,"g":94},"f8f9244a":{"m":76,"g":94},"ecbfe58b":{"m":76,"g":94},"8f163b16":{"m":76,"g":94},"e7a8610d":{"m":76,"g":94},"a2cc62a6":{"m":76,"g":94},"fb888603":{"m":76,"g":94},"321ab756":{"m":76,"g":94},"38f25e87":{"m":76,"g":94},"8cd42504":{"m":76,"g":94},"6a384d5c":{"m":76,"g":94},"f69e0696":{"m":76,"g":94},"f6ab4ca6":{"m":76,"g":94},"c7c7dbeb":{"m":76,"g":94},"417fc72f":{"m":76,"g":94},"c6ec7029":{"m":76,"g":94},"4c56e5db":{"m":76,"g":94},"7b5fc719":{"m":76,"g":94},"ad4e58bf":{"m":76,"g":94},"bfb03c61":{"m":76,"g":94},"b36ab493":{"m":76,"g":94},"9e93ef3f":{"m":76,"g":94},"fad86a68":{"m":76,"g":94},"df7014a8":{"m":76,"g":94},"49420741":{"m":76,"g":94},"ba52fd18":{"m":76,"g":94},"b6944f97":{"m":76,"g":94},"f44db16c":{"m":76,"g":94},"f9c53cbb":{"m":76,"g":94},"90532b76":{"m":76,"g":94},"c0e9a36c":{"m":76,"g":94},"588865f0":{"m":76,"g":94},"3196999f":{"m":76,"g":94},"9e0186f3":{"m":76,"g":94},"8baf9a0c":{"m":76,"g":94},"c7872985":{"m":76,"g":94},"45212ce1":{"m":76,"g":94},"c16b33cc":{"m":76,"g":94},"2d004512":{"m":76,"g":94},"804d250a":{"m":76,"g":94},"dd865bef":{"m":76,"g":94},"d373a48c":{"m":76,"g":94},"98be3bd3":{"m":76,"g":94},"a98290ae":{"m":76,"g":94},"9b81f9bd":{"m":76,"g":94},"f81a27f6":{"m":76,"g":94},"988ab646":{"m":76,"g":94},"3ded4b21":{"m":76,"g":94},"f4d7ab7a":{"m":76,"g":94},"c38ca4fc":{"m":76,"g":94},"82dec1f7":{"m":76,"g":94},"5f9b2c62":{"m":76,"g":94},"5493c334":{"m":76,"g":94},"f2ab37e5":{"m":76,"g":94},"91ba98fe":{"m":76,"g":94},"c614dbdf":{"m":76,"g":94},"927ca935":{"m":76,"g":94},"ef3c2dd0":{"m":76,"g":94},"75b65648":{"m":76,"g":94},"0f52fb55":{"m":76,"g":94},"d6d21640":{"m":76,"g":94},"0212d2e2":{"m":76,"g":94},"8cc300f5":{"m":76,"g":94},"452db508":{"m":76,"g":94},"d1112d85":{"m":76,"g":94},"48efec7b":{"m":76,"g":94},"9b8333d9":{"m":76,"g":94},"f5bbf603":{"m":76,"g":94},"5cbd709e":{"m":76,"g":94},"2e4a1e2d":{"m":76,"g":94},"9d02bb3e":{"m":76,"g":94},"402db5c5":{"m":76,"g":94},"754a0e82":{"m":76,"g":94},"799fb5f4":{"m":76,"g":94},"25e1816e":{"m":76,"g":94},"a53fe428":{"m":76,"g":94},"1b859295":{"m":76,"g":94},"9971dc22":{"m":76,"g":94},"3db35c1a":{"m":76,"g":94},"52a34d74":{"m":76,"g":94},"06d12b39":{"m":76,"g":94},"c30976fb":{"m":76,"g":94},"1a3fa75f":{"m":76,"g":94},"81f431ed":{"m":76,"g":94},"65b7c9b7":{"m":76,"g":94},"2c4f5cca":{"m":76,"g":94},"15843047":{"m":76,"g":94},"8ec2ce07":{"m":76,"g":94},"1fd0cf8a":{"m":76,"g":94},"bf63ee54":{"m":76,"g":94},"22c96f78":{"m":76,"g":94},"2892b9bb":{"m":76,"g":94},"470b4740":{"m":76,"g":94},"26c372c1":{"m":76,"g":94},"86d9baed":{"m":76,"g":94},"21d485f8":{"m":76,"g":94},"035ac2ab":{"m":76,"g":94},"e1a5e7e4":{"m":76,"g":94},"ad1ae7f7":{"m":76,"g":94},"e73167ad":{"m":76,"g":94},"862fe522":{"m":76,"g":94},"61e4433c":{"m":76,"g":94},"660305c3":{"m":76,"g":94},"642ab418":{"m":76,"g":94},"1ce4878d":{"m":76,"g":94},"977d7cd2":{"m":76,"g":94},"0e0ec702":{"m":76,"g":94},"bb378556":{"m":76,"g":94},"19e96e59":{"m":77,"g":94},"aa08aeac":{"m":77,"g":94},"d8a136a1":{"m":77,"g":94},"20c90be2":{"m":77,"g":94},"ec3ee028":{"m":77,"g":94},"92941ce7":{"m":77,"g":94},"2bb0e7cf":{"m":77,"g":94},"72549263":{"m":77,"g":94},"044c3159":{"m":77,"g":94},"4db29e82":{"m":77,"g":94},"c483377e":{"m":77,"g":94},"74e0ac1d":{"m":77,"g":94},"ef9a378a":{"m":77,"g":94},"6dea5c96":{"m":77,"g":94},"6ffb6bd4":{"m":77,"g":94},"47e6628a":{"m":77,"g":94},"7907f9eb":{"m":77,"g":94},"8c04f0f2":{"m":77,"g":94},"265e7564":{"m":77,"g":94},"d3f71f5e":{"m":77,"g":94},"5eae67cb":{"m":77,"g":94},"6dbf9998":{"m":77,"g":94},"e0166f8a":{"m":77,"g":94},"53a2c3b4":{"m":77,"g":94},"550586ef":{"m":77,"g":94},"cf29fe9e":{"m":77,"g":94},"26c0f131":{"m":77,"g":94},"f9970bd1":{"m":77,"g":94},"2e0f94ab":{"m":77,"g":94},"18317ddc":{"m":77,"g":94},"e2e2ab70":{"m":77,"g":94},"0d3e3072":{"m":77,"g":94},"62dd9587":{"m":77,"g":94},"72031173":{"m":77,"g":94},"9fdc6d6a":{"m":77,"g":94},"42a45df0":{"m":77,"g":94},"04eb6062":{"m":77,"g":94},"e84f4ba0":{"m":77,"g":94},"b149b393":{"m":77,"g":94},"31dfff7d":{"m":77,"g":94},"10a9ab7b":{"m":77,"g":94},"bb0fd749":{"m":77,"g":94},"7f19e083":{"m":77,"g":94},"98a2cfa9":{"m":77,"g":94},"2a882e8f":{"m":77,"g":94},"e6e4d022":{"m":77,"g":94},"188105a2":{"m":77,"g":94},"b3953258":{"m":77,"g":94},"5fa3058f":{"m":77,"g":94},"bbab97a6":{"m":77,"g":94},"0bc0bf57":{"m":77,"g":94},"f60f2931":{"m":77,"g":94},"17000d2b":{"m":77,"g":94},"668ecc6c":{"m":77,"g":94},"886fcbdd":{"m":77,"g":94},"8bf6d7f4":{"m":77,"g":94},"1b9175cb":{"m":77,"g":94},"92bb49a7":{"m":77,"g":94},"6f5cc5eb":{"m":77,"g":94},"c913ed40":{"m":77,"g":94},"1afe3d07":{"m":77,"g":94},"44f47d3e":{"m":77,"g":94},"ae25d36d":{"m":77,"g":94},"35e0856b":{"m":78,"g":94},"aba5ca15":{"m":78,"g":94},"496dde84":{"m":78,"g":94},"bcbbf519":{"m":78,"g":94},"0d99adb7":{"m":78,"g":94},"efbae697":{"m":78,"g":94},"ca8d02ab":{"m":78,"g":94},"3f287b85":{"m":78,"g":94},"7ed77d6b":{"m":78,"g":94},"4c54f442":{"m":78,"g":94},"924ca7c9":{"m":78,"g":94},"6ff9c6a5":{"m":78,"g":94},"77e929a1":{"m":78,"g":94},"febe21ce":{"m":78,"g":94},"a995a773":{"m":78,"g":94},"31035dda":{"m":78,"g":94},"913e38df":{"m":78,"g":94},"d95269f9":{"m":78,"g":94},"e53bf190":{"m":78,"g":94},"3289c120":{"m":78,"g":94},"69df9761":{"m":78,"g":94},"98f768d1":{"m":78,"g":94},"d7954b76":{"m":78,"g":94},"74885a84":{"m":78,"g":94},"b8b6008f":{"m":78,"g":94},"8e10fec9":{"m":78,"g":94},"e8999b13":{"m":78,"g":94},"772d2a19":{"m":78,"g":94},"9d0b36c4":{"m":78,"g":94},"7d8c0ce7":{"m":78,"g":94},"e41549c3":{"m":78,"g":94},"cccfc10e":{"m":78,"g":94},"a2aea59b":{"m":78,"g":94},"2c8fd993":{"m":78,"g":94},"31da75ab":{"m":78,"g":94},"e983e432":{"m":78,"g":94},"e9c6ce46":{"m":78,"g":94},"3fadc647":{"m":78,"g":94},"e119f042":{"m":78,"g":94},"9eb49e87":{"m":78,"g":94},"12047f5e":{"m":78,"g":94},"fda6bb78":{"m":78,"g":94},"23c764b1":{"m":78,"g":94},"87fafa01":{"m":78,"g":94},"1c63e797":{"m":78,"g":94},"ee47a6c1":{"m":78,"g":94},"6384d317":{"m":78,"g":94},"5cb552b1":{"m":78,"g":94},"c7457191":{"m":78,"g":94},"51ac297a":{"m":78,"g":94},"a169b9f8":{"m":78,"g":94},"4a63bc32":{"m":78,"g":94},"a303325f":{"m":78,"g":94},"42873eac":{"m":78,"g":94},"4814ecaf":{"m":78,"g":94},"e62d60fe":{"m":78,"g":94},"032f8faa":{"m":78,"g":94},"37c66ec8":{"m":78,"g":94},"9adf178c":{"m":78,"g":94},"f842853a":{"m":78,"g":94},"195a09f5":{"m":78,"g":94},"9fccda31":{"m":78,"g":94},"4ede6770":{"m":78,"g":94},"b26bc86b":{"m":78,"g":94},"5ec5eaf7":{"m":78,"g":94},"0d7fe866":{"m":78,"g":94},"54b9a2de":{"m":78,"g":94},"8e7b3154":{"m":78,"g":94},"45dcfc2e":{"m":78,"g":94},"ddf8981d":{"m":78,"g":94},"400ad660":{"m":78,"g":94},"05625b97":{"m":78,"g":94},"736502d4":{"m":78,"g":94},"8690c40b":{"m":78,"g":94},"b1cfb4e9":{"m":78,"g":94},"57f99608":{"m":79,"g":94},"81992474":{"m":79,"g":94},"f04c80dc":{"m":79,"g":94},"d1bb1711":{"m":79,"g":94},"5b5c7237":{"m":80,"g":94},"a42736bb":{"m":80,"g":94},"dd83e7e9":{"m":80,"g":94},"0769b14b":{"m":80,"g":94},"b64b88e7":{"m":80,"g":94},"bc24205b":{"m":80,"g":94},"3efc8e2d":{"m":80,"g":94},"27a009bb":{"m":80,"g":94},"8ec0bb7d":{"m":80,"g":94},"fa909dc3":{"m":80,"g":94},"e8f62b20":{"m":80,"g":94},"88defc4d":{"m":80,"g":94},"6f509d55":{"m":80,"g":94},"12ef7e3b":{"m":80,"g":94},"838fa0f2":{"m":80,"g":94},"f1b3b75f":{"m":80,"g":94},"33b16ad1":{"m":80,"g":94},"ffde65a0":{"m":80,"g":94},"471650de":{"m":80,"g":94},"d06a83fb":{"m":80,"g":94},"5d134401":{"m":80,"g":94},"f88f7e19":{"m":80,"g":94},"3dfc6023":{"m":80,"g":94},"15e91d72":{"m":80,"g":94},"8aab7fdb":{"m":80,"g":94},"e940dc4f":{"m":80,"g":94},"388e15c0":{"m":80,"g":94},"11421a3f":{"m":80,"g":94},"6c41fcf0":{"m":80,"g":94},"ee9d6ca6":{"m":80,"g":94},"2dd64894":{"m":80,"g":94},"61e7c4dd":{"m":80,"g":94},"dae79444":{"m":80,"g":94},"f6772f14":{"m":80,"g":94},"ac5b78ba":{"m":80,"g":94},"38076dea":{"m":80,"g":94},"5e0a9b09":{"m":80,"g":94},"bdde2375":{"m":80,"g":94},"e9fc2ac7":{"m":80,"g":94},"44afde82":{"m":80,"g":94},"072df753":{"m":80,"g":94},"defede50":{"m":80,"g":94},"fc728719":{"m":80,"g":94},"14e8bd88":{"m":80,"g":94},"adca585b":{"m":80,"g":94},"39d90449":{"m":80,"g":94},"39e41138":{"m":80,"g":94},"5fbafbb8":{"m":80,"g":94},"a9499885":{"m":80,"g":94},"f7655790":{"m":80,"g":94},"f58b929a":{"m":80,"g":94},"c1270aab":{"m":80,"g":94},"8311b07f":{"m":80,"g":94},"c1380257":{"m":80,"g":94},"b62e7e99":{"m":80,"g":94},"7d3b7c87":{"m":80,"g":94},"75015bb6":{"m":80,"g":94},"b371f7cd":{"m":80,"g":94},"812e82f3":{"m":80,"g":94},"4879e50c":{"m":80,"g":94},"bc92107b":{"m":80,"g":94},"3e4794aa":{"m":80,"g":94},"690ec205":{"m":80,"g":94},"2074a2e6":{"m":80,"g":94},"57de7c6b":{"m":80,"g":94},"115ae2e7":{"m":80,"g":94},"aea98512":{"m":80,"g":94},"e4155e96":{"m":80,"g":94},"1b1b47a9":{"m":80,"g":94},"3c9740d2":{"m":80,"g":94},"2eb55770":{"m":80,"g":94},"f65b8d5c":{"m":80,"g":94},"5ad05719":{"m":80,"g":94},"34ef6c81":{"m":80,"g":94},"61172091":{"m":80,"g":94},"4f288113":{"m":80,"g":94},"136b8e6a":{"m":80,"g":94},"034c5256":{"m":80,"g":94},"c1dd773c":{"m":80,"g":94},"6f859379":{"m":80,"g":94},"f774a0d2":{"m":80,"g":94},"60bcbf2a":{"m":80,"g":94},"a0a9f6d6":{"m":80,"g":94},"80aa8ca8":{"m":80,"g":94},"4aa6bab0":{"m":80,"g":94},"c35dcfdb":{"m":80,"g":94},"c163bf4f":{"m":80,"g":94},"55986343":{"m":80,"g":94},"b75275b6":{"m":80,"g":94},"7074e9ca":{"m":80,"g":94},"fc14cca0":{"m":80,"g":94},"e7beff8a":{"m":80,"g":94},"4d2e3051":{"m":80,"g":94},"e53a0b3d":{"m":80,"g":94},"038bc5d5":{"m":80,"g":94},"aee62d74":{"m":80,"g":94},"cd7e32e2":{"m":80,"g":94},"88799448":{"m":80,"g":94},"a879811c":{"m":80,"g":94},"a222945d":{"m":80,"g":94},"ed01b451":{"m":80,"g":94},"d050df36":{"m":80,"g":94},"76f44c2a":{"m":80,"g":94},"1078396f":{"m":80,"g":94},"7e4f72dd":{"m":80,"g":94},"4c31ae9f":{"m":80,"g":94},"f730362e":{"m":80,"g":94},"e3c4bd31":{"m":80,"g":94},"5db37c86":{"m":80,"g":94},"4cb53ecd":{"m":80,"g":94},"456b008b":{"m":80,"g":94},"ebf495f0":{"m":80,"g":94},"7f875f12":{"m":80,"g":94},"fbebcb7a":{"m":80,"g":94},"87eddedf":{"m":80,"g":94},"40652482":{"m":80,"g":94},"86a876d8":{"m":80,"g":94},"92823069":{"m":80,"g":94},"d2e507df":{"m":80,"g":94},"61970b08":{"m":80,"g":94},"76c48a09":{"m":80,"g":94},"90caf06c":{"m":80,"g":94},"6669d127":{"m":80,"g":94},"f2b70afd":{"m":80,"g":94},"bc3f6db2":{"m":80,"g":94},"aac531c5":{"m":80,"g":94},"39efad4f":{"m":80,"g":94},"466899e6":{"m":80,"g":94},"11d760d5":{"m":80,"g":94},"5039d547":{"m":80,"g":94},"d09a51f1":{"m":80,"g":94},"f8194b26":{"m":80,"g":94},"6d3b35fa":{"m":80,"g":94},"a73c4df4":{"m":80,"g":94},"89a55418":{"m":80,"g":94},"2695ab05":{"m":80,"g":94},"88d6fd9a":{"m":80,"g":94},"cc88d98a":{"m":80,"g":94},"3033c11a":{"m":80,"g":94},"fd5a55cf":{"m":80,"g":94},"804d9f2e":{"m":80,"g":94},"a7c3f74b":{"m":80,"g":94},"5a144a8a":{"m":80,"g":94},"27f8e6b9":{"m":80,"g":94},"afb752bc":{"m":80,"g":94},"9731eca7":{"m":80,"g":94},"7c5658c1":{"m":80,"g":94},"9798e72b":{"m":80,"g":94},"ade714a6":{"m":80,"g":94},"93470a14":{"m":80,"g":94},"db452760":{"m":80,"g":94},"fbdc94ba":{"m":81,"g":94},"b54b5a96":{"m":81,"g":94},"bca832c7":{"m":81,"g":94},"d9dd5298":{"m":81,"g":94},"0a0dd34e":{"m":81,"g":94},"80ac527d":{"m":81,"g":94},"99456bca":{"m":81,"g":94},"d07e797a":{"m":81,"g":94},"c555d794":{"m":81,"g":94},"e2574ee9":{"m":81,"g":94},"ab4b5606":{"m":81,"g":94},"20f1c8e3":{"m":81,"g":94},"613b197e":{"m":81,"g":94},"d58e3544":{"m":81,"g":94},"bf86c5e9":{"m":81,"g":94},"dca90f1d":{"m":81,"g":94},"0961feef":{"m":81,"g":94},"59dd090f":{"m":81,"g":94},"569b032c":{"m":81,"g":94},"f6a71139":{"m":81,"g":94},"1e0806f3":{"m":81,"g":94},"2c11f9c2":{"m":81,"g":94},"a6f892e5":{"m":81,"g":94},"08b518d5":{"m":81,"g":94},"4db463b1":{"m":81,"g":94},"bfa39224":{"m":81,"g":94},"e465b08d":{"m":81,"g":94},"bed05878":{"m":81,"g":94},"b2a189dd":{"m":81,"g":94},"f28d8299":{"m":81,"g":94},"8e09b370":{"m":81,"g":94},"53dcf388":{"m":81,"g":94},"1effba4c":{"m":81,"g":94},"a0fc5bc1":{"m":81,"g":94},"27e9538a":{"m":81,"g":94},"211c7b31":{"m":81,"g":94},"c08a717c":{"m":81,"g":94},"f13d65a7":{"m":81,"g":94},"06d0a3d9":{"m":81,"g":94},"22c2a79d":{"m":81,"g":94},"8beb356f":{"m":81,"g":94},"c776234b":{"m":81,"g":94},"3bface15":{"m":81,"g":94},"6fb29ffd":{"m":81,"g":94},"4fb05583":{"m":81,"g":94},"81c89111":{"m":81,"g":94},"92d1561b":{"m":81,"g":94},"8f783c19":{"m":81,"g":94},"90faf901":{"m":81,"g":94},"177320a5":{"m":81,"g":94},"d7bc19a4":{"m":81,"g":94},"85ec0440":{"m":81,"g":94},"06a1656e":{"m":81,"g":94},"6aca5834":{"m":81,"g":94},"b9c87e78":{"m":82,"g":94},"968ef515":{"m":82,"g":94},"13432002":{"m":82,"g":94},"c2942907":{"m":82,"g":94},"e69a2190":{"m":82,"g":94},"bf98d2e3":{"m":82,"g":94},"e65b9f21":{"m":82,"g":94},"4dce1cc6":{"m":82,"g":94},"deded17f":{"m":82,"g":94},"f29a718f":{"m":82,"g":94},"3f57b00a":{"m":82,"g":94},"453d412c":{"m":82,"g":94},"dc86f25a":{"m":82,"g":94},"08289eaa":{"m":82,"g":94},"3b6d539f":{"m":82,"g":94},"57131dd9":{"m":82,"g":94},"a7591ecf":{"m":82,"g":94},"c44f2869":{"m":82,"g":94},"685d8980":{"m":82,"g":94},"70645f4d":{"m":82,"g":94},"188f0955":{"m":82,"g":94},"eef9433b":{"m":82,"g":94},"97cb762b":{"m":82,"g":94},"11951820":{"m":82,"g":94},"5239d795":{"m":82,"g":94},"f0815419":{"m":82,"g":94},"2b3bdc93":{"m":82,"g":94},"5fc4b600":{"m":82,"g":94},"b868526d":{"m":82,"g":94},"502524e2":{"m":82,"g":94},"4c764007":{"m":82,"g":94},"9f3bd2ad":{"m":82,"g":94},"8de53da9":{"m":82,"g":94},"fac17acf":{"m":82,"g":94},"8b39274e":{"m":82,"g":94},"5156d5a4":{"m":82,"g":94},"c951d312":{"m":82,"g":94},"dcb82325":{"m":82,"g":94},"66c0ff9e":{"m":82,"g":94},"9a7e83e8":{"m":82,"g":94},"417b44eb":{"m":82,"g":94},"475e2e37":{"m":82,"g":94},"fba86b6b":{"m":82,"g":94},"072b4d03":{"m":82,"g":94},"9c434777":{"m":82,"g":94},"fa2f677e":{"m":82,"g":94},"463d4b74":{"m":82,"g":94},"9924bbe1":{"m":82,"g":94},"84022c0e":{"m":83,"g":94},"f9fb33ef":{"m":83,"g":94},"a38f6932":{"m":83,"g":94},"beb65c74":{"m":83,"g":94},"621e96bf":{"m":83,"g":94},"35ca04d2":{"m":83,"g":94},"3c4e0ee6":{"m":83,"g":94},"9c088829":{"m":83,"g":94},"005aad32":{"m":83,"g":94},"4d23ba08":{"m":83,"g":94},"6e313c1b":{"m":83,"g":94},"a45a4b23":{"m":83,"g":94},"981a2619":{"m":83,"g":94},"8ba31330":{"m":83,"g":94},"02102063":{"m":83,"g":94},"7e944246":{"m":83,"g":94},"a086a113":{"m":83,"g":94},"bdbe5f81":{"m":83,"g":94},"9ad28f63":{"m":83,"g":94},"d7b1ce65":{"m":83,"g":94},"f55933e1":{"m":83,"g":94},"408ba022":{"m":83,"g":94},"094891c0":{"m":83,"g":94},"a21ef363":{"m":83,"g":94},"3c4dc38a":{"m":83,"g":94},"d8fbc7c0":{"m":83,"g":94},"c5e1026f":{"m":83,"g":94},"799c4bb5":{"m":83,"g":94},"02723e1b":{"m":83,"g":94},"df2cf583":{"m":83,"g":94},"133ded03":{"m":83,"g":94},"f87a6ab3":{"m":83,"g":94},"eebfdb94":{"m":83,"g":94},"dfb32264":{"m":83,"g":94},"63c13a2c":{"m":83,"g":94},"4d1e52ab":{"m":83,"g":94},"155890e4":{"m":83,"g":94},"1f963d7f":{"m":83,"g":94},"04d0123f":{"m":83,"g":94},"feda9b11":{"m":83,"g":94},"c3948ba6":{"m":83,"g":94},"269c457e":{"m":83,"g":94},"18ce468d":{"m":83,"g":94},"21514ff5":{"m":83,"g":94},"5641a094":{"m":83,"g":94},"3dd3538c":{"m":83,"g":94},"93c6fb12":{"m":83,"g":94},"11e27d09":{"m":83,"g":94},"50eda839":{"m":83,"g":94},"c55550cb":{"m":83,"g":94},"43fb95c2":{"m":83,"g":94},"7d9679b7":{"m":83,"g":94},"b5be5694":{"m":83,"g":94},"d2b8d0b8":{"m":83,"g":94},"a14654dd":{"m":83,"g":94},"5d93a950":{"m":83,"g":94},"c998d04b":{"m":83,"g":94},"7d0edf3c":{"m":83,"g":94},"ce4ecba4":{"m":83,"g":94},"b1f6d89b":{"m":83,"g":94},"7c99103f":{"m":83,"g":94},"de071366":{"m":83,"g":94},"e0673969":{"m":83,"g":94},"127ff898":{"m":83,"g":94},"8777a1d2":{"m":83,"g":94},"711efe78":{"m":83,"g":94},"fbb5f229":{"m":83,"g":94},"15fabcc0":{"m":83,"g":94},"e62c4955":{"m":83,"g":94},"71d1785f":{"m":83,"g":94},"3f87f831":{"m":83,"g":94},"ce5412b6":{"m":83,"g":94},"7282ab74":{"m":83,"g":94},"b0feda09":{"m":83,"g":94},"6b6e7487":{"m":83,"g":94},"91732486":{"m":83,"g":94},"2ed96c7a":{"m":83,"g":94},"2aa3f5e2":{"m":83,"g":94},"76d17c7e":{"m":83,"g":94},"70d040f9":{"m":83,"g":94},"4418f599":{"m":83,"g":94},"04f2abcb":{"m":83,"g":94},"506be6b8":{"m":83,"g":94},"2343d8df":{"m":83,"g":94},"92bb64bc":{"m":83,"g":94},"11b23ae9":{"m":83,"g":94},"dcae1fb2":{"m":84,"g":94},"a0251a3f":{"m":84,"g":94},"663037a7":{"m":84,"g":94},"f4a9f60c":{"m":84,"g":94},"ee71ed8a":{"m":84,"g":94},"d364b9b0":{"m":84,"g":94},"849c83a0":{"m":84,"g":94},"d73ddeb1":{"m":84,"g":94},"f48b007c":{"m":84,"g":94},"74cb12a8":{"m":84,"g":94},"c6c62640":{"m":84,"g":94},"92ab0a20":{"m":84,"g":94},"e132cba2":{"m":84,"g":94},"0045f4b2":{"m":84,"g":94},"8601300b":{"m":84,"g":94},"6fa6f38e":{"m":84,"g":94},"693723d1":{"m":84,"g":94},"966eb908":{"m":84,"g":94},"644ed409":{"m":84,"g":94},"3029889c":{"m":84,"g":94},"ef15dcda":{"m":84,"g":94},"ad4df307":{"m":84,"g":94},"41ac0c6d":{"m":84,"g":94},"84810da4":{"m":84,"g":94},"40d9b8ac":{"m":84,"g":94},"f0365820":{"m":84,"g":94},"86317c09":{"m":84,"g":94},"daed453e":{"m":84,"g":94},"ded04b2e":{"m":84,"g":94},"9858113c":{"m":85,"g":94},"8441baad":{"m":85,"g":94},"256c4c25":{"m":85,"g":94},"9f21e754":{"m":85,"g":94},"7bcd8b1c":{"m":85,"g":94},"11383cec":{"m":85,"g":94},"e97e57e6":{"m":85,"g":94},"9a6ad891":{"m":85,"g":94},"d353d08b":{"m":85,"g":94},"08acdb5c":{"m":85,"g":94},"2afba1b1":{"m":85,"g":94},"e330f2b8":{"m":85,"g":94},"3ddf5b9d":{"m":85,"g":94},"3cff9633":{"m":85,"g":94},"d50e36a7":{"m":85,"g":94},"8fefdd32":{"m":85,"g":94},"403b855a":{"m":85,"g":94},"1698e94e":{"m":85,"g":94},"58195dd5":{"m":85,"g":94},"799789af":{"m":85,"g":94},"cc4a80ca":{"m":85,"g":94},"3c8a5231":{"m":85,"g":94},"a043f7f2":{"m":85,"g":94},"e3a53044":{"m":85,"g":94},"28b26dbf":{"m":85,"g":94},"2b06484b":{"m":85,"g":94},"e4b6133b":{"m":85,"g":94},"dd408ee4":{"m":85,"g":94},"9419e75d":{"m":85,"g":94},"2c7dbb7c":{"m":85,"g":94},"9a62191b":{"m":85,"g":94},"ae523675":{"m":85,"g":94},"5c08aa49":{"m":85,"g":94},"f4c191a7":{"m":85,"g":94},"771669cb":{"m":85,"g":94},"1468769b":{"m":85,"g":94},"91dda4cd":{"m":85,"g":94},"8e5a6d34":{"m":85,"g":94},"8465f035":{"m":85,"g":94},"8c0cfca8":{"m":85,"g":94},"2c3ea294":{"m":85,"g":94},"5bb0accb":{"m":85,"g":94},"8d463fe3":{"m":85,"g":94},"26fc32d1":{"m":85,"g":94},"1cc32603":{"m":85,"g":94},"05ee2192":{"m":85,"g":94},"678d8cc9":{"m":86,"g":94},"d2cb3024":{"m":86,"g":94},"1940cdec":{"m":86,"g":94},"63484f9f":{"m":86,"g":94},"dff0ab92":{"m":86,"g":94},"e30c273b":{"m":86,"g":94},"0ab3f437":{"m":86,"g":94},"cec98f10":{"m":86,"g":94},"8dc4efd0":{"m":86,"g":94},"6578cf27":{"m":86,"g":94},"087751a8":{"m":86,"g":94},"911f3ba6":{"m":86,"g":94},"f6f96b05":{"m":86,"g":94},"2a936a84":{"m":86,"g":94},"5e023301":{"m":86,"g":94},"fa7d7fd9":{"m":86,"g":94},"f1ff736d":{"m":86,"g":94},"acc816d8":{"m":86,"g":94},"a05bd83a":{"m":86,"g":94},"cef91b1e":{"m":86,"g":94},"6450c122":{"m":86,"g":94},"b6cf3532":{"m":86,"g":94},"3b2680a4":{"m":86,"g":94},"79961afa":{"m":86,"g":94},"cfca4e0e":{"m":86,"g":94},"e88dd482":{"m":86,"g":94},"73600673":{"m":86,"g":94},"8f508cc7":{"m":86,"g":94},"9bddf1c8":{"m":86,"g":94},"24c13ca9":{"m":86,"g":94},"b70957fc":{"m":86,"g":94},"e444c13f":{"m":86,"g":94},"fee37d9e":{"m":86,"g":94},"c68de479":{"m":86,"g":94},"4c7b4242":{"m":86,"g":94},"38053c33":{"m":86,"g":94},"00c2c1f0":{"m":86,"g":94},"cb691945":{"m":86,"g":94},"d25398cb":{"m":86,"g":94},"8a828666":{"m":86,"g":94},"aff584fa":{"m":86,"g":94},"6f566147":{"m":86,"g":94},"bdd17998":{"m":86,"g":94},"c9abd7be":{"m":86,"g":94},"a3e4e9bf":{"m":86,"g":94},"6d4d3bc8":{"m":86,"g":94},"5f300141":{"m":86,"g":94},"1c05425b":{"m":86,"g":94},"b26cb1c5":{"m":86,"g":94},"f8e46093":{"m":86,"g":94},"683707c3":{"m":86,"g":94},"a68ed766":{"m":86,"g":94},"82653f66":{"m":86,"g":94},"22da3d97":{"m":86,"g":94},"b8559764":{"m":86,"g":94},"56f6589e":{"m":86,"g":94},"1232f7e8":{"m":86,"g":94},"3008db9c":{"m":86,"g":94},"357fb2db":{"m":86,"g":94},"95c231e5":{"m":86,"g":94},"3042f1da":{"m":86,"g":94},"2b63798c":{"m":86,"g":94},"bf203cb7":{"m":86,"g":94},"8ebde73f":{"m":86,"g":94},"6b0fae79":{"m":86,"g":94},"141a4596":{"m":86,"g":94},"d8ab6011":{"m":86,"g":94},"6579cd7d":{"m":86,"g":94},"97ac42b6":{"m":86,"g":94},"1acca3a2":{"m":86,"g":94},"6ea1e6ac":{"m":86,"g":94},"3409aaab":{"m":86,"g":94},"73dcf2b3":{"m":86,"g":94},"170d1f21":{"m":86,"g":94},"73bc1d00":{"m":86,"g":94},"c5645e92":{"m":86,"g":94},"d33955d2":{"m":86,"g":94},"6fc17596":{"m":86,"g":94},"ad506a4e":{"m":86,"g":94},"ebaba856":{"m":86,"g":94},"de2faef9":{"m":86,"g":94},"67b7d5b1":{"m":86,"g":94},"4322c31e":{"m":86,"g":94},"16267d4f":{"m":87,"g":94},"0f5cb8ca":{"m":87,"g":94},"17299f08":{"m":87,"g":94},"5380cd7e":{"m":87,"g":94},"b2e95f62":{"m":87,"g":94},"1ab14c4c":{"m":87,"g":94},"3c32895c":{"m":87,"g":94},"ac2324c1":{"m":87,"g":94},"ef8ec07b":{"m":87,"g":94},"f24fc5b8":{"m":87,"g":94},"d18c6b33":{"m":87,"g":94},"f1c89600":{"m":87,"g":94},"983c663d":{"m":87,"g":94},"f94543d2":{"m":87,"g":94},"e8e18dcd":{"m":87,"g":94},"bad7c26f":{"m":87,"g":94},"12319a67":{"m":87,"g":94},"d738ab52":{"m":87,"g":94},"3ee40ff9":{"m":87,"g":94},"0f334945":{"m":87,"g":94},"fba8eccd":{"m":87,"g":94},"7d3a3d45":{"m":87,"g":94},"25c83fff":{"m":87,"g":94},"9f2c9568":{"m":87,"g":94},"3f2702ae":{"m":87,"g":94},"6ea05950":{"m":87,"g":94},"e7dd906c":{"m":87,"g":94},"6e2da515":{"m":87,"g":94},"e9a47f4c":{"m":87,"g":94},"03227c5f":{"m":87,"g":94},"01bdbf7f":{"m":87,"g":94},"94d42b67":{"m":87,"g":94},"69276f61":{"m":87,"g":94},"41a645f5":{"m":87,"g":94},"23010630":{"m":87,"g":94},"45b4dcf0":{"m":87,"g":94},"213e8c7d":{"m":87,"g":94},"41273fd7":{"m":87,"g":94},"e9bebafb":{"m":87,"g":94},"4d1c9db6":{"m":87,"g":94},"17c36c55":{"m":87,"g":94},"31d1f6e7":{"m":87,"g":94},"a823c6e8":{"m":87,"g":94},"2ce87935":{"m":87,"g":94},"de167cf5":{"m":87,"g":94},"4319978c":{"m":87,"g":94},"03dd785c":{"m":87,"g":94},"66fc63d6":{"m":87,"g":94},"921e4a81":{"m":87,"g":94},"9d8ec2e6":{"m":87,"g":94},"c178abda":{"m":87,"g":94},"b29a026e":{"m":87,"g":94},"7e257cd6":{"m":88,"g":94},"c4831e2f":{"m":88,"g":94},"2e37fa07":{"m":88,"g":94},"2d831c6e":{"m":88,"g":94},"ed0c3035":{"m":88,"g":94},"e6f11356":{"m":88,"g":94},"7b02c326":{"m":88,"g":94},"fefa19fe":{"m":88,"g":94},"9c574585":{"m":88,"g":94},"8233cc10":{"m":88,"g":94},"1b2e8f76":{"m":88,"g":94},"d2e0881a":{"m":88,"g":94},"2f427491":{"m":88,"g":94},"d8189660":{"m":88,"g":94},"3ded6235":{"m":88,"g":94},"4ba1eea8":{"m":88,"g":94},"4685fbb8":{"m":88,"g":94},"0a4fc73b":{"m":88,"g":94},"a6970a17":{"m":88,"g":94},"a6ae3af1":{"m":88,"g":94},"0b07c4a9":{"m":88,"g":94},"fc0e3b91":{"m":88,"g":94},"d71f3f0a":{"m":88,"g":94},"58f10679":{"m":88,"g":94},"7a80f565":{"m":88,"g":94},"9484eba4":{"m":88,"g":94},"e9feb488":{"m":88,"g":94},"fc992a09":{"m":88,"g":94},"121f92c5":{"m":88,"g":94},"3bde1010":{"m":88,"g":94},"75135580":{"m":88,"g":94},"4d643f6c":{"m":88,"g":94},"6ce0ed07":{"m":88,"g":94},"969660c7":{"m":88,"g":94},"16d4f680":{"m":88,"g":94},"ada268fd":{"m":88,"g":94},"cfe48c59":{"m":88,"g":94},"d4c038da":{"m":88,"g":94},"55f6005f":{"m":88,"g":94},"7222e1da":{"m":88,"g":94},"505eec4d":{"m":88,"g":94},"ccfe5c00":{"m":88,"g":94},"a071dc40":{"m":88,"g":94},"a40aecc5":{"m":88,"g":94},"d6e1d28c":{"m":88,"g":94},"7c347259":{"m":88,"g":94},"669caa0a":{"m":88,"g":94},"4024e1d2":{"m":88,"g":94},"5c0b38f3":{"m":88,"g":94},"30ca18f4":{"m":88,"g":94},"03886917":{"m":88,"g":94},"66324895":{"m":88,"g":94},"13feffd0":{"m":88,"g":94},"e98afbe0":{"m":88,"g":94},"69af3ec3":{"m":88,"g":94},"32cc66ef":{"m":88,"g":94},"83f2d9d4":{"m":88,"g":94},"6317c5c6":{"m":88,"g":94},"cba1cdbc":{"m":88,"g":94},"c471d39e":{"m":88,"g":94},"d0443275":{"m":88,"g":94},"17d080b7":{"m":88,"g":94},"1b19df4b":{"m":88,"g":94},"f0653886":{"m":88,"g":94},"b1465557":{"m":88,"g":94},"b06215da":{"m":88,"g":94},"7adf245b":{"m":88,"g":94},"299fd22f":{"m":88,"g":94},"506e5de8":{"m":88,"g":94},"844e2f22":{"m":88,"g":94},"4f39bcf7":{"m":88,"g":94},"31c9569b":{"m":88,"g":94},"1be6956d":{"m":88,"g":94},"626ccb7d":{"m":88,"g":94},"72bfb0ba":{"m":88,"g":94},"15521495":{"m":88,"g":94},"ebe58d54":{"m":88,"g":94},"066cf445":{"m":88,"g":94},"6dc6b306":{"m":88,"g":94},"1f30c05d":{"m":88,"g":94},"5dd62c3a":{"m":88,"g":94},"f11481b9":{"m":88,"g":94},"9d24c3ff":{"m":88,"g":94},"24161c59":{"m":88,"g":94},"eabcf82a":{"m":88,"g":94},"c47a51db":{"m":88,"g":94},"11553c1a":{"m":88,"g":94},"01dd39ba":{"m":88,"g":94},"b3f3d610":{"m":88,"g":94},"f07c6a00":{"m":88,"g":94},"4bb816d4":{"m":88,"g":94},"c250939e":{"m":88,"g":94},"b6909aa2":{"m":88,"g":94},"f8728357":{"m":88,"g":94},"73187152":{"m":88,"g":94},"40865665":{"m":88,"g":94},"fd08c048":{"m":88,"g":94},"26ebb849":{"m":88,"g":94},"02973cd9":{"m":88,"g":94},"6d95a35a":{"m":88,"g":94},"01d2838c":{"m":88,"g":94},"e3b8a722":{"m":88,"g":94},"3cf1473a":{"m":88,"g":94},"27168308":{"m":88,"g":94},"e3bed74a":{"m":88,"g":94},"e9ef39d2":{"m":88,"g":94},"205d5cb4":{"m":88,"g":94},"3d7f7a43":{"m":88,"g":94},"2df9d40a":{"m":88,"g":94},"8dc191f2":{"m":88,"g":94},"64825b83":{"m":88,"g":94},"69748d08":{"m":88,"g":94},"dcc0a456":{"m":88,"g":94},"c2b7ddca":{"m":88,"g":94},"abebd939":{"m":88,"g":94},"4bd2952a":{"m":88,"g":94},"6fc93575":{"m":88,"g":94},"839fb31e":{"m":88,"g":94},"f19a9204":{"m":88,"g":94},"c23a7072":{"m":88,"g":94},"e07a6977":{"m":88,"g":94},"cd8d4b9d":{"m":88,"g":94},"f194e14f":{"m":88,"g":94},"cfc9f9ab":{"m":88,"g":94},"fb4959b2":{"m":88,"g":94},"9a405274":{"m":88,"g":94},"2e4babdb":{"m":88,"g":94},"44a3783d":{"m":88,"g":94},"f3bf6110":{"m":88,"g":94},"198b9056":{"m":88,"g":94},"73eb67c0":{"m":88,"g":94},"9a91fa0e":{"m":88,"g":94},"cd7c8a8d":{"m":88,"g":94},"3e350a93":{"m":88,"g":94},"fb71725c":{"m":88,"g":94},"912788c0":{"m":88,"g":94},"0f75b907":{"m":88,"g":94},"4f723edd":{"m":89,"g":94},"fcde67b0":{"m":89,"g":94},"81372f3b":{"m":89,"g":94},"baa6624d":{"m":89,"g":94},"c2b16795":{"m":89,"g":94},"f6ebba53":{"m":89,"g":94},"6716b417":{"m":89,"g":94},"1c8b42c8":{"m":89,"g":94},"f20f7000":{"m":89,"g":94},"f40942ad":{"m":89,"g":94},"dc0705a5":{"m":89,"g":94},"a968c888":{"m":89,"g":94},"a979daac":{"m":89,"g":94},"f1569876":{"m":89,"g":94},"3465d7ae":{"m":89,"g":94},"e58423b2":{"m":89,"g":94},"7059ae16":{"m":89,"g":94},"51d9a597":{"m":89,"g":94},"56ccd3c2":{"m":89,"g":94},"98c00a2d":{"m":89,"g":94},"451ffe74":{"m":89,"g":94},"b1e5a33a":{"m":89,"g":94},"9d5fa68b":{"m":89,"g":94},"2c186425":{"m":89,"g":94},"18efb5e8":{"m":89,"g":94},"de1350ea":{"m":89,"g":94},"86fe943b":{"m":89,"g":94},"9ecb1856":{"m":89,"g":94},"cc74499d":{"m":89,"g":94},"0c1f03a2":{"m":89,"g":94},"3712abfa":{"m":89,"g":94},"971a0dfa":{"m":89,"g":94},"2fc12995":{"m":89,"g":94},"20d3ad3b":{"m":89,"g":94},"fa3592cf":{"m":89,"g":94},"608668e1":{"m":89,"g":94},"6c0a4828":{"m":89,"g":94},"47402883":{"m":89,"g":94},"1fb76ebb":{"m":89,"g":94},"c2c4f57f":{"m":89,"g":94},"23881fa6":{"m":89,"g":94},"8db3ac55":{"m":89,"g":94},"3e56f557":{"m":89,"g":94},"62fec60d":{"m":89,"g":94},"e7759778":{"m":89,"g":94},"77e928d0":{"m":89,"g":94},"515ef4fa":{"m":89,"g":94},"f5599ef1":{"m":89,"g":94},"c499591a":{"m":89,"g":94},"e1ce44cd":{"m":89,"g":94},"f1114e7f":{"m":89,"g":94},"bae4fdc7":{"m":89,"g":94},"6153f2ff":{"m":89,"g":94},"8b5f83ed":{"m":89,"g":94},"2a413829":{"m":89,"g":94},"d5c097a2":{"m":89,"g":94},"9736cd3b":{"m":89,"g":94},"2f715f51":{"m":89,"g":94},"d664ca18":{"m":89,"g":94},"22fe7878":{"m":89,"g":94},"c4ffbeca":{"m":89,"g":94},"f8eaaab8":{"m":89,"g":94},"697b0f71":{"m":89,"g":94},"132dad87":{"m":89,"g":94},"60fdad7c":{"m":89,"g":94},"61ce91ed":{"m":89,"g":94},"e6b7053b":{"m":89,"g":94},"5f91c825":{"m":89,"g":94},"b819381f":{"m":89,"g":94},"562f279a":{"m":89,"g":94},"8b247489":{"m":89,"g":94},"0df6765c":{"m":89,"g":94},"35b65cf0":{"m":89,"g":94},"dd1012fc":{"m":89,"g":94},"44aab7f9":{"m":89,"g":94},"43baba64":{"m":89,"g":94},"0166403c":{"m":89,"g":94},"bcf66ef3":{"m":89,"g":94},"0de5e7d4":{"m":89,"g":94},"72a110f6":{"m":89,"g":94},"5aff1e93":{"m":89,"g":94},"8e3797be":{"m":89,"g":94},"4474eaf5":{"m":89,"g":94},"499f5e62":{"m":89,"g":94},"81964328":{"m":89,"g":94},"f0f84975":{"m":89,"g":94},"3f1e4339":{"m":89,"g":94},"cf9815ba":{"m":89,"g":94},"bd75690f":{"m":89,"g":94},"180ff5ee":{"m":89,"g":94},"37f15475":{"m":89,"g":94},"8a548052":{"m":89,"g":94},"b6d0ce9f":{"m":89,"g":94},"0ea330ca":{"m":89,"g":94},"27e327b4":{"m":89,"g":94},"ff00895c":{"m":89,"g":94},"ff914748":{"m":89,"g":94},"eb38c7d1":{"m":89,"g":94},"df7f61ee":{"m":89,"g":94},"ef21729c":{"m":89,"g":94},"f5159315":{"m":89,"g":94},"6d7b6696":{"m":89,"g":94},"6376b632":{"m":89,"g":94},"e05e29d1":{"m":89,"g":94},"a2cb5913":{"m":89,"g":94},"55444ed6":{"m":89,"g":94},"20fd53b8":{"m":89,"g":94},"6a47b730":{"m":89,"g":94},"c429919d":{"m":89,"g":94},"1da8d230":{"m":89,"g":94},"2f7420bc":{"m":89,"g":94},"c6a0cacc":{"m":89,"g":94},"0a9bfc20":{"m":89,"g":94},"34c63731":{"m":89,"g":94},"2d72fc47":{"m":89,"g":94},"b520d028":{"m":89,"g":94},"7dc0e394":{"m":89,"g":94},"fb507b7b":{"m":89,"g":94},"f90945c4":{"m":89,"g":94},"094fbdac":{"m":89,"g":94},"888cb175":{"m":89,"g":94},"e39bca07":{"m":89,"g":94},"a2bb8565":{"m":89,"g":94},"ced3c07a":{"m":89,"g":94},"f18b068f":{"m":89,"g":94},"4fac524b":{"m":89,"g":94},"b581b225":{"m":89,"g":94},"69dd878b":{"m":89,"g":94},"22630ca2":{"m":89,"g":94},"d279d499":{"m":89,"g":94},"6cb00c63":{"m":89,"g":94},"62cac2c4":{"m":89,"g":94},"2c3b71d6":{"m":89,"g":94},"51cdd81f":{"m":89,"g":94},"73def253":{"m":89,"g":94},"d9d35def":{"m":89,"g":94},"6df81e8a":{"m":89,"g":94},"3ab7d9b5":{"m":89,"g":94},"7e5071c9":{"m":89,"g":94},"78689d33":{"m":89,"g":94},"1dc6864f":{"m":89,"g":94},"485a023b":{"m":89,"g":94},"7e412900":{"m":89,"g":94},"c673727e":{"m":89,"g":94},"f4d4f939":{"m":89,"g":94},"f2bd3515":{"m":89,"g":94},"c459536b":{"m":89,"g":94},"535c8386":{"m":89,"g":94},"2163586e":{"m":89,"g":94},"e06b0761":{"m":89,"g":94},"844a8f42":{"m":89,"g":94},"791b3bfa":{"m":89,"g":94},"31589e17":{"m":89,"g":94},"ae6a5b29":{"m":89,"g":94},"4839999b":{"m":89,"g":94},"541a985f":{"m":89,"g":94},"5170b010":{"m":89,"g":94},"d63e76f7":{"m":89,"g":94},"e9fd11c0":{"m":89,"g":94},"c7588d59":{"m":89,"g":94},"6b231325":{"m":89,"g":94},"b1c8d4e9":{"m":89,"g":94},"c25231c6":{"m":89,"g":94},"fba03b29":{"m":89,"g":94},"461a7302":{"m":89,"g":94},"07610353":{"m":89,"g":94},"c087ddd6":{"m":89,"g":94},"f4a8987f":{"m":89,"g":94},"41ba767f":{"m":89,"g":94},"f127355a":{"m":89,"g":94},"bdb962d7":{"m":89,"g":94},"0b9557fc":{"m":89,"g":94},"87068b5c":{"m":89,"g":94},"a564e001":{"m":89,"g":94},"2103b806":{"m":89,"g":94},"e806f708":{"m":89,"g":94},"fa6723f0":{"m":89,"g":94},"673ff668":{"m":89,"g":94},"447be242":{"m":89,"g":94},"183d9f96":{"m":89,"g":94},"63195028":{"m":89,"g":94},"a3d7f4b6":{"m":89,"g":94},"b18416fb":{"m":89,"g":94},"ce9d690e":{"m":89,"g":94},"bdaefbbf":{"m":89,"g":94},"45a31a82":{"m":89,"g":94},"1aa0fbf4":{"m":89,"g":94},"7a0bbe6a":{"m":89,"g":94},"ae335842":{"m":89,"g":94},"477a101c":{"m":89,"g":94},"1a8f5f68":{"m":89,"g":94},"32cd7070":{"m":89,"g":94},"ebd1ed49":{"m":89,"g":94},"f77da699":{"m":89,"g":94},"d6864ce6":{"m":89,"g":94},"755a3661":{"m":89,"g":94},"79a39ac0":{"m":89,"g":94},"3ce94f71":{"m":89,"g":94},"ca95556c":{"m":89,"g":94},"eb8f02dd":{"m":89,"g":94},"0ca3e568":{"m":89,"g":94},"5c7aa009":{"m":89,"g":94},"fe386aca":{"m":89,"g":94},"14d1075f":{"m":89,"g":94},"006ead9d":{"m":89,"g":94},"0d503090":{"m":89,"g":94},"501efc3d":{"m":89,"g":94},"f9bab3d5":{"m":89,"g":94},"16f69b1f":{"m":89,"g":94},"65f09131":{"m":89,"g":94},"fc419b62":{"m":89,"g":94},"7eb9d8e5":{"m":89,"g":94},"84147254":{"m":89,"g":94},"6bebef60":{"m":89,"g":94},"25be63d0":{"m":89,"g":94},"d502dae0":{"m":89,"g":94},"93e53f6e":{"m":89,"g":94},"a191a0e4":{"m":89,"g":94},"8c7279c2":{"m":89,"g":94},"0ca18117":{"m":89,"g":94},"2c3a6fe1":{"m":89,"g":94},"8b33d8df":{"m":89,"g":94},"e235be16":{"m":89,"g":94},"5ccf8fe1":{"m":89,"g":94},"3f23d8cd":{"m":89,"g":94},"1a399799":{"m":89,"g":94},"022012aa":{"m":89,"g":94},"681e7af3":{"m":89,"g":94},"681fdc26":{"m":89,"g":94},"0d477880":{"m":89,"g":94},"f4560373":{"m":89,"g":94},"b2388433":{"m":89,"g":94},"a38376fa":{"m":89,"g":94},"7a5e6ce1":{"m":89,"g":94},"24c035f2":{"m":89,"g":94},"f9dc9dd2":{"m":90,"g":94},"62a7aa2e":{"m":90,"g":94},"5ca07eed":{"m":90,"g":94},"e30ef368":{"m":90,"g":94},"91a066ec":{"m":90,"g":94},"c4943867":{"m":90,"g":94},"53a525bf":{"m":90,"g":94},"7ddf8e83":{"m":90,"g":94},"8321f8e4":{"m":90,"g":94},"cfceb83d":{"m":90,"g":94},"b1286a11":{"m":90,"g":94},"21615cc3":{"m":90,"g":94},"0ae1e9a7":{"m":90,"g":94},"e07d0647":{"m":90,"g":94},"3c2274fb":{"m":90,"g":94},"d2679f51":{"m":90,"g":94},"96be97bf":{"m":90,"g":94},"88f9c347":{"m":90,"g":94},"fff10809":{"m":90,"g":94},"5f1ab327":{"m":90,"g":94},"7df7c679":{"m":90,"g":94},"38af4f68":{"m":90,"g":94},"a6305c7d":{"m":90,"g":94},"a023856b":{"m":90,"g":94},"db0cc57e":{"m":90,"g":94},"349bb2c9":{"m":90,"g":94},"0b8939bc":{"m":90,"g":94},"ed89837c":{"m":90,"g":94},"55561e25":{"m":90,"g":94},"44733203":{"m":90,"g":94},"0bd67ba2":{"m":90,"g":94},"7d316991":{"m":90,"g":94},"ab1a4fa5":{"m":90,"g":94},"ed54bf9d":{"m":90,"g":94},"b57d87c2":{"m":90,"g":94},"98538822":{"m":90,"g":94},"f47a1b1d":{"m":90,"g":94},"93cec433":{"m":90,"g":94},"ba589b88":{"m":90,"g":94},"50876abc":{"m":90,"g":94},"b4c41f72":{"m":90,"g":94},"8b8f2e74":{"m":90,"g":94},"0fc3d992":{"m":90,"g":94},"be2d985d":{"m":90,"g":94},"5b1afa78":{"m":90,"g":94},"c49c1d92":{"m":90,"g":94},"0f1dfa1e":{"m":90,"g":94},"e3ec6bf4":{"m":90,"g":94},"b04df75a":{"m":90,"g":94},"bec3e484":{"m":90,"g":94},"8ab7d93c":{"m":90,"g":94},"5c66c442":{"m":90,"g":94},"aa46ed34":{"m":90,"g":94},"2f4ec752":{"m":90,"g":94},"da47621c":{"m":90,"g":94},"22a6b9fc":{"m":90,"g":94},"b02df20a":{"m":90,"g":94},"bd7cfbd2":{"m":90,"g":94},"4b9971e4":{"m":90,"g":94},"dcc79d32":{"m":90,"g":94},"7046e0fa":{"m":90,"g":94},"930746d9":{"m":90,"g":94},"84727a51":{"m":90,"g":94},"ef326774":{"m":90,"g":94},"021f76e4":{"m":90,"g":94},"777688b8":{"m":90,"g":94},"0ca594ed":{"m":90,"g":94},"31d6dee5":{"m":90,"g":94},"02543b54":{"m":90,"g":94},"25a6a9aa":{"m":90,"g":94},"83d87685":{"m":90,"g":94},"2a5f0100":{"m":90,"g":94},"dbdf76ca":{"m":90,"g":94},"f2a75a66":{"m":90,"g":94},"6b12d6a8":{"m":90,"g":94},"0f218731":{"m":90,"g":94},"14c18d25":{"m":90,"g":94},"90bd3e32":{"m":90,"g":94},"ca929118":{"m":90,"g":94},"344adb00":{"m":90,"g":94},"b56de8f9":{"m":90,"g":94},"ce5ee3bd":{"m":90,"g":94},"a0e4d4eb":{"m":90,"g":94},"2f584455":{"m":90,"g":94},"fe55947a":{"m":90,"g":94},"19995dd7":{"m":90,"g":94},"3b014bc1":{"m":90,"g":94},"d7c3e8e9":{"m":90,"g":94},"8ea7df61":{"m":90,"g":94},"4a102a2b":{"m":90,"g":94},"6406408a":{"m":90,"g":94},"019851d0":{"m":90,"g":94},"2dae104d":{"m":90,"g":94},"cef6655b":{"m":90,"g":94},"27196d41":{"m":90,"g":94},"bb185b0e":{"m":90,"g":94},"7c3a12c0":{"m":91,"g":94},"e846d95e":{"m":91,"g":94},"15f34013":{"m":91,"g":94},"d04163b3":{"m":91,"g":94},"7732bbe4":{"m":91,"g":94},"ed0a0b69":{"m":91,"g":94},"fa42e419":{"m":91,"g":94},"e5afb88b":{"m":91,"g":94},"e5ddeb04":{"m":91,"g":94},"bdbb8d00":{"m":91,"g":94},"34c3f9b2":{"m":91,"g":94},"76139bfb":{"m":91,"g":94},"f8d48fd3":{"m":91,"g":94},"34b6b842":{"m":91,"g":94},"25549433":{"m":91,"g":94},"d6dddc19":{"m":91,"g":94},"55e03b10":{"m":91,"g":94},"8aa68ed5":{"m":91,"g":94},"506c4928":{"m":91,"g":94},"30ceccc7":{"m":91,"g":94},"ac5010e0":{"m":91,"g":94},"3cee035e":{"m":91,"g":94},"30f2a44a":{"m":91,"g":94},"bd4f5818":{"m":91,"g":94},"50f1b6d6":{"m":91,"g":94},"5962e70d":{"m":91,"g":94},"edc21cc8":{"m":91,"g":94},"05c9bc89":{"m":91,"g":94},"b7a2df0a":{"m":91,"g":94},"1998ce40":{"m":91,"g":94},"72676cd6":{"m":91,"g":94},"02bf31ef":{"m":91,"g":94},"5ea5d221":{"m":91,"g":94},"fdfd5224":{"m":91,"g":94},"7f3ee861":{"m":91,"g":94},"bec58910":{"m":91,"g":94},"9edf6608":{"m":91,"g":94},"ab74f8f0":{"m":91,"g":94},"5e7fdc79":{"m":91,"g":94},"4d8d9b8e":{"m":91,"g":94},"5041df2d":{"m":91,"g":94},"256801e9":{"m":91,"g":94},"73b13e69":{"m":91,"g":94},"8609e637":{"m":91,"g":94},"dea2b84b":{"m":91,"g":94},"cfb2fb5a":{"m":91,"g":94},"22bfed75":{"m":91,"g":94},"e879d8b7":{"m":91,"g":94},"09988080":{"m":91,"g":94},"794be55a":{"m":91,"g":94},"187b85b7":{"m":91,"g":94},"ceba0ce4":{"m":91,"g":94},"1ab6be1b":{"m":91,"g":94},"4df5fc21":{"m":91,"g":94},"a06912ad":{"m":91,"g":94},"97011abc":{"m":91,"g":94},"1d6515ef":{"m":91,"g":94},"dea8aa7a":{"m":91,"g":94},"906dbc34":{"m":91,"g":94},"fadf18fd":{"m":91,"g":94},"f88e7085":{"m":91,"g":94},"4f838c09":{"m":91,"g":94},"d20a073b":{"m":91,"g":94},"47367b76":{"m":91,"g":94},"650127a1":{"m":91,"g":94},"3774f078":{"m":91,"g":94},"9179ea15":{"m":91,"g":94},"20a503c7":{"m":91,"g":94},"ffd1a26e":{"m":91,"g":94},"09ae5b20":{"m":91,"g":94},"712bf9ec":{"m":91,"g":94},"9c6a0656":{"m":91,"g":94},"2ae809c5":{"m":91,"g":94},"1de4db9b":{"m":91,"g":94},"31fccf5a":{"m":91,"g":94},"b783c1cb":{"m":91,"g":94},"094c116f":{"m":91,"g":94},"e56685ac":{"m":91,"g":94},"c26d7349":{"m":91,"g":94},"ceaa85c9":{"m":91,"g":94},"0650e517":{"m":91,"g":94},"fc554105":{"m":91,"g":94},"4f204db5":{"m":91,"g":94},"3eb4a800":{"m":91,"g":94},"e7261315":{"m":91,"g":94},"8c16da33":{"m":91,"g":94},"a39d9287":{"m":91,"g":94},"10d60cd4":{"m":91,"g":94},"8a10c4c3":{"m":91,"g":94},"405780bc":{"m":91,"g":94},"1dffee31":{"m":91,"g":94},"70c471a8":{"m":91,"g":94},"1a9c2c92":{"m":91,"g":94},"873ae12c":{"m":91,"g":94},"c64290dc":{"m":91,"g":94},"8e2363dc":{"m":91,"g":94},"69183f88":{"m":92,"g":94},"9b00990b":{"m":92,"g":94},"4d67025a":{"m":92,"g":94},"0e05fe8c":{"m":92,"g":94},"2390a2bc":{"m":92,"g":94},"16d76b9f":{"m":92,"g":94},"5c214257":{"m":92,"g":94},"b8df43ab":{"m":92,"g":94},"a1c1ebe9":{"m":92,"g":94},"fe2a0f96":{"m":92,"g":94},"20beb370":{"m":92,"g":94},"00fbd8a4":{"m":92,"g":94},"802815e4":{"m":92,"g":94},"4c6675c4":{"m":92,"g":94},"e21aa1df":{"m":92,"g":94},"f3cbd245":{"m":92,"g":94},"506a2d59":{"m":92,"g":94},"a07f8ae4":{"m":92,"g":94},"7eb47b0f":{"m":92,"g":94},"bc2e5645":{"m":92,"g":94},"3abc3036":{"m":92,"g":94},"afeed465":{"m":92,"g":94},"587b4c6e":{"m":92,"g":94},"7b9a174a":{"m":92,"g":94},"03c039c4":{"m":92,"g":94},"57ab7769":{"m":92,"g":94},"112b496a":{"m":92,"g":94},"3562256b":{"m":92,"g":94},"5f527834":{"m":92,"g":94},"9f1787fa":{"m":92,"g":94},"8ecad0b1":{"m":92,"g":94},"7151194b":{"m":92,"g":94},"2ed68d7a":{"m":92,"g":94},"e984d507":{"m":92,"g":94},"755f3147":{"m":92,"g":94},"ec5f9c62":{"m":93,"g":94},"62f5522f":{"m":93,"g":94},"01f98730":{"m":93,"g":94},"199d6218":{"m":93,"g":94},"f200af0d":{"m":93,"g":94},"5589b750":{"m":93,"g":94},"c04a8a82":{"m":93,"g":94},"6c903611":{"m":93,"g":94},"77cfea68":{"m":93,"g":94},"8fc910db":{"m":93,"g":94},"75354d9a":{"m":93,"g":94},"4fece12b":{"m":93,"g":94},"c7973222":{"m":93,"g":94},"ef8a29c4":{"m":93,"g":94},"8e9fb43d":{"m":93,"g":94},"83646089":{"m":93,"g":94},"da3890e8":{"m":93,"g":94},"cb432f17":{"m":93,"g":94},"1964c325":{"m":93,"g":94},"af564774":{"m":93,"g":94},"af46f299":{"m":93,"g":94},"16a6b1d8":{"m":93,"g":94},"14229ccf":{"m":93,"g":94},"975a5ec6":{"m":93,"g":94},"1e3e3add":{"m":93,"g":94},"8c298031":{"m":93,"g":94},"4de03953":{"m":93,"g":94},"8b1942c6":{"m":93,"g":94},"489934be":{"m":93,"g":94},"43f93f63":{"m":93,"g":94},"aca1101a":{"m":93,"g":94},"2998c4bd":{"m":93,"g":94},"6840a7bb":{"m":93,"g":94},"c01a1df5":{"m":93,"g":94},"00991723":{"m":93,"g":94},"264dc6e7":{"m":93,"g":94},"646cef2e":{"m":93,"g":94},"1dce6c48":{"m":93,"g":94},"9fcc9a80":{"m":93,"g":94},"ac49dac0":{"m":93,"g":94},"1e0e5497":{"m":93,"g":94},"b5822651":{"m":93,"g":94},"2c4feaf3":{"m":93,"g":94},"2ff572e2":{"m":93,"g":94},"84f2e4a0":{"m":93,"g":94},"8f844db6":{"m":93,"g":94},"36cc3ffd":{"m":93,"g":94},"1bebd315":{"m":93,"g":94},"d3c275b1":{"m":93,"g":94},"b044400d":{"m":93,"g":94},"40e5cb7a":{"m":93,"g":94},"8e64140e":{"m":93,"g":94},"82f021e2":{"m":93,"g":94},"0626f678":{"m":93,"g":94},"09e699bb":{"m":93,"g":94},"b116b21a":{"m":93,"g":94},"88f484ce":{"m":93,"g":94},"8e03b641":{"m":93,"g":94},"b3fa5dc3":{"m":93,"g":94},"00aec6ad":{"m":93,"g":94},"1a08358a":{"m":93,"g":94},"f18a8fdd":{"m":93,"g":94},"a7efbb27":{"m":93,"g":94},"93b6785d":{"m":93,"g":94},"f9eb04dd":{"m":93,"g":94},"3a911b85":{"m":93,"g":94},"886d3449":{"m":93,"g":94},"637bfee4":{"m":93,"g":94},"6005ecee":{"m":93,"g":94},"ff2e9c94":{"m":93,"g":94},"3e34e900":{"m":93,"g":94},"7349717e":{"m":93,"g":94},"392e441a":{"m":93,"g":94},"7248272c":{"m":93,"g":94},"22352d47":{"m":93,"g":94},"c5131f7a":{"m":93,"g":94},"78700893":{"m":93,"g":94},"663c04f7":{"m":93,"g":94},"3b3f1e3a":{"m":93,"g":94},"b691dcc4":{"m":93,"g":94},"0c9c6c75":{"m":93,"g":94},"e3f9b548":{"m":93,"g":94},"b3cff365":{"m":93,"g":94},"8f335b5b":{"m":93,"g":94},"b2264076":{"m":93,"g":94},"04b35190":{"m":93,"g":94},"071a1f51":{"m":93,"g":94},"7c0db3a6":{"m":93,"g":94},"c45e49d8":{"m":93,"g":94},"d8053929":{"m":93,"g":94},"00c7b1ad":{"m":93,"g":94},"82eccae4":{"m":93,"g":94},"a8c10aee":{"m":93,"g":94},"eb429b88":{"m":93,"g":94},"49538d11":{"m":93,"g":94},"cfe2edac":{"m":93,"g":94},"2373faa3":{"m":93,"g":94},"9efb2993":{"m":93,"g":94},"a5317b2f":{"m":93,"g":94},"eb6c2c16":{"m":93,"g":94},"357921aa":{"m":93,"g":94},"c071198c":{"m":93,"g":94},"d7374d74":{"m":93,"g":94},"ce3a3e87":{"m":93,"g":94},"41650b0d":{"m":93,"g":94},"1b951620":{"m":93,"g":94},"29bd4c81":{"m":93,"g":94},"031f64aa":{"m":93,"g":94},"3d7cdb2e":{"m":93,"g":94},"604efe07":{"m":93,"g":94},"1b8cf77b":{"m":93,"g":94},"bb9b608c":{"m":93,"g":94},"066f4ec9":{"m":95,"g":97},"b6b6268c":{"m":95,"g":97},"08702321":{"m":95,"g":97},"64c5907e":{"m":95,"g":97},"128f16a8":{"m":95,"g":97},"49861046":{"m":95,"g":97},"a37e1247":{"m":95,"g":97},"136c6e04":{"m":95,"g":97},"43e20c06":{"m":95,"g":97},"4bab50a6":{"m":95,"g":97},"2e7ab862":{"m":95,"g":97},"51ae4030":{"m":95,"g":97},"653b873b":{"m":95,"g":97},"d379bda4":{"m":95,"g":97},"2b0e1d1c":{"m":95,"g":97},"659907e3":{"m":95,"g":97},"cb9d91ea":{"m":95,"g":97},"6a6e0bb7":{"m":95,"g":97},"076313bd":{"m":95,"g":97},"9abe1163":{"m":95,"g":97},"3646f6bb":{"m":95,"g":94},"35724aa1":{"m":95,"g":94},"2fc824b8":{"m":95,"g":94},"253454de":{"m":95,"g":94},"ea3e7ffe":{"m":95,"g":94},"8d4a01cb":{"m":95,"g":94},"a3398d84":{"m":95,"g":94},"ba69c153":{"m":95,"g":94},"3589aa79":{"m":95,"g":94},"e00715eb":{"m":95,"g":94},"ea4bf122":{"m":95,"g":94},"a291439a":{"m":95,"g":94},"54411f6a":{"m":95,"g":94},"625018d2":{"m":95,"g":94},"5732d904":{"m":95,"g":94},"eb118d88":{"m":96,"g":97},"732fc8e4":{"m":96,"g":97},"f2d5c492":{"m":96,"g":97},"2a2d3478":{"m":96,"g":97},"aa205609":{"m":96,"g":97},"61bb2858":{"m":96,"g":97},"880221bd":{"m":96,"g":97},"8f3173d0":{"m":96,"g":97},"26118a13":{"m":96,"g":97},"475a249b":{"m":96,"g":97},"191d836f":{"m":96,"g":97},"86044712":{"m":96,"g":97},"61555307":{"m":96,"g":97},"49a5915f":{"m":96,"g":97},"766392c6":{"m":96,"g":97},"4a0d1919":{"m":96,"g":97},"57482415":{"m":96,"g":97},"2d54d4bb":{"m":96,"g":97},"b5e3d603":{"m":96,"g":97},"4ed57807":{"m":96,"g":97},"dd445a41":{"m":96,"g":97},"7590f522":{"m":96,"g":97},"f9df11ae":{"m":96,"g":97},"d389bedf":{"m":96,"g":97},"ac80f4da":{"m":96,"g":97},"d487555f":{"m":96,"g":97},"e5888edd":{"m":96,"g":97},"01c00004":{"m":98,"g":103},"0dfe2491":{"m":98,"g":103},"ff45ab7a":{"m":98,"g":103},"0f8b5386":{"m":98,"g":103},"c33499a6":{"m":98,"g":103},"e50109f2":{"m":98,"g":103},"69adc4f8":{"m":98,"g":103},"11483785":{"m":98,"g":103},"7b68d271":{"m":98,"g":103},"74f59ae5":{"m":98,"g":103},"6936be32":{"m":98,"g":103},"9b5de6cb":{"m":98,"g":97},"5c8365a0":{"m":98,"g":97},"8430bfe3":{"m":98,"g":97},"c9e8613c":{"m":98,"g":97},"429bb0ef":{"m":98,"g":97},"7eebd440":{"m":98,"g":97},"93d124ef":{"m":98,"g":97},"1fc455e8":{"m":98,"g":97},"465968b2":{"m":98,"g":97},"750838ad":{"m":98,"g":97},"99aefa03":{"m":98,"g":97},"bbcfbc1a":{"m":98,"g":97},"83c104b1":{"m":98,"g":97},"2db6719c":{"m":98,"g":97},"55381a46":{"m":98,"g":97},"a589a071":{"m":98,"g":97},"f62d75b6":{"m":98,"g":97},"0f9b11e3":{"m":98,"g":97},"877e35d7":{"m":98,"g":97},"cbdfb771":{"m":98,"g":97},"282eb59f":{"m":98,"g":97},"4540a466":{"m":98,"g":97},"abda2542":{"m":98,"g":97},"8cddfa56":{"m":98,"g":97},"4e3defe5":{"m":98,"g":97},"60468da4":{"m":98,"g":97},"41d33e47":{"m":98,"g":97},"bfdd226f":{"m":98,"g":97},"3de617a7":{"m":98,"g":97},"bb0e8a32":{"m":98,"g":97},"1b427dae":{"m":98,"g":97},"f3d97361":{"m":98,"g":97},"561dd7b2":{"m":98,"g":97},"f98e88b9":{"m":98,"g":97},"15ad6c90":{"m":98,"g":97},"cfab0ff6":{"m":98,"g":97},"b763cf7e":{"m":98,"g":97},"8fcc55cf":{"m":98,"g":97},"610381b7":{"m":98,"g":97},"1403ea56":{"m":98,"g":97},"b7e951a6":{"m":98,"g":97},"d918ab79":{"m":98,"g":97},"3964b352":{"m":98,"g":97},"9c7a4618":{"m":98,"g":97},"7750b91c":{"m":98,"g":97},"c8f31042":{"m":98,"g":97},"1f76fc87":{"m":98,"g":97},"6737671c":{"m":98,"g":97},"fd63b62e":{"m":98,"g":97},"719b29f2":{"m":98,"g":97},"d0510f08":{"m":98,"g":97},"9d33fcfb":{"m":98,"g":97},"7891bac1":{"m":98,"g":97},"48c1fa7b":{"m":98,"g":97},"8aa5ae6b":{"m":98,"g":97},"8a323557":{"m":98,"g":97},"6e92da8f":{"m":98,"g":97},"e1020dc5":{"m":98,"g":97},"3586b4ce":{"m":98,"g":97},"42960214":{"m":98,"g":97},"01857fab":{"m":98,"g":97},"519ff5c8":{"m":98,"g":97},"af1cc8fe":{"m":98,"g":97},"49b87774":{"m":98,"g":97},"02404a1e":{"m":98,"g":97},"5c08a36c":{"m":98,"g":97},"9069884b":{"m":98,"g":97},"8a7a7770":{"m":98,"g":97},"795668dc":{"m":98,"g":97},"4395c87a":{"m":98,"g":97},"c28ad199":{"m":98,"g":97},"570d3343":{"m":98,"g":97},"d9eb5efc":{"m":98,"g":97},"6dc4af49":{"m":98,"g":97},"b188a89a":{"m":98,"g":97},"497efe74":{"m":98,"g":97},"69f453e5":{"m":98,"g":97},"3bc43c68":{"m":98,"g":97},"7498522f":{"m":98,"g":97},"194841e3":{"m":98,"g":97},"ebff5fcb":{"m":98,"g":97},"f06bd210":{"m":98,"g":97},"14f1f151":{"m":98,"g":97},"38216cf0":{"m":98,"g":97},"4a883795":{"m":98,"g":97},"f1f1d1d4":{"m":98,"g":97},"9120e83d":{"m":98,"g":97},"6e923dbd":{"m":98,"g":97},"c268c11c":{"m":98,"g":97},"e6d59884":{"m":98,"g":97},"9b560c3e":{"m":98,"g":97},"5dc5866e":{"m":98,"g":97},"64e78bb3":{"m":98,"g":97},"7c39e8a1":{"m":98,"g":97},"d969504d":{"m":98,"g":97},"1ebec1a8":{"m":98,"g":97},"d4d0c7c3":{"m":98,"g":97},"8d2cf38c":{"m":98,"g":97},"2117f82d":{"m":98,"g":97},"c07f647c":{"m":98,"g":97},"07452cbe":{"m":98,"g":97},"a562c8a3":{"m":98,"g":97},"cb736df8":{"m":98,"g":97},"e2ed9d04":{"m":98,"g":97},"b5dd5e87":{"m":98,"g":97},"9379da77":{"m":98,"g":97},"0c55cbcf":{"m":98,"g":97},"c46e069d":{"m":98,"g":97},"42fc4410":{"m":98,"g":97},"5f6756b0":{"m":98,"g":97},"98aa836b":{"m":98,"g":97},"22bd857c":{"m":98,"g":97},"ccfa0841":{"m":98,"g":97},"bcc5ba94":{"m":98,"g":97},"cee9f329":{"m":98,"g":97},"2272c2a5":{"m":99,"g":103},"3ec0b212":{"m":99,"g":103},"58c468f4":{"m":99,"g":103},"f8ca2368":{"m":99,"g":103},"d8ee1564":{"m":99,"g":103},"7181ec8c":{"m":99,"g":103},"ed2e313e":{"m":99,"g":103},"f8260f25":{"m":99,"g":103},"12cb760a":{"m":99,"g":103},"1b9cea5a":{"m":99,"g":103},"9045cc1e":{"m":99,"g":103},"70e37b97":{"m":99,"g":103},"15d27591":{"m":99,"g":103},"af4b9bae":{"m":99,"g":103},"7ad6b766":{"m":99,"g":103},"c0fb25e9":{"m":99,"g":103},"28d4d472":{"m":99,"g":103},"f4674df6":{"m":99,"g":103},"d40846d4":{"m":99,"g":103},"145482f4":{"m":99,"g":103},"39fe1e88":{"m":99,"g":103},"33c4b4d0":{"m":99,"g":103},"8d1c5b94":{"m":99,"g":103},"a167fd0b":{"m":99,"g":103},"2f86f3ad":{"m":99,"g":103},"bfb118c0":{"m":99,"g":103},"f6e07f27":{"m":99,"g":103},"5dd0f870":{"m":99,"g":103},"f7e102d5":{"m":99,"g":103},"0e5fa677":{"m":99,"g":103},"624a3b8d":{"m":99,"g":103},"01079e17":{"m":99,"g":103},"0e7a5b26":{"m":99,"g":103},"4953f4ca":{"m":99,"g":103},"38000a5f":{"m":99,"g":103},"70251e93":{"m":99,"g":103},"c87d4fec":{"m":99,"g":103},"a99801e0":{"m":99,"g":103},"4c605235":{"m":99,"g":103},"6f8f4aee":{"m":99,"g":103},"0c8dab9e":{"m":99,"g":103},"f39037ff":{"m":99,"g":103},"ce86e201":{"m":99,"g":103},"b4326330":{"m":99,"g":103},"8abd3e77":{"m":99,"g":103},"e885bfdc":{"m":99,"g":103},"e2d66f60":{"m":99,"g":103},"45bc170b":{"m":100,"g":103},"22623699":{"m":100,"g":103},"fb4ce17d":{"m":100,"g":103},"25f73c6c":{"m":100,"g":103},"581e7dcb":{"m":100,"g":103},"484d0e02":{"m":100,"g":103},"5922c0cb":{"m":100,"g":103},"6d6a8bc2":{"m":100,"g":103},"2fd5c704":{"m":100,"g":103},"4ad97370":{"m":100,"g":103},"28103384":{"m":100,"g":103},"fe6a445d":{"m":100,"g":103},"dd487e55":{"m":100,"g":103},"bb81daef":{"m":100,"g":103},"58dd95fb":{"m":100,"g":103},"b47eda33":{"m":100,"g":103},"e983d666":{"m":100,"g":103},"b58c3c28":{"m":100,"g":103},"df906455":{"m":100,"g":103},"95217a9b":{"m":100,"g":103},"22e00eeb":{"m":100,"g":103},"b3eac168":{"m":100,"g":103},"10ee8955":{"m":100,"g":103},"bf3352c5":{"m":100,"g":103},"4d921f2b":{"m":100,"g":103},"44d600cd":{"m":100,"g":103},"5c9c275b":{"m":100,"g":103},"bf0f448f":{"m":100,"g":103},"36d6f0ba":{"m":100,"g":103},"2a1936de":{"m":100,"g":103},"2ab97023":{"m":100,"g":103},"0bcc195f":{"m":100,"g":103},"91e3d154":{"m":100,"g":103},"85486b6f":{"m":100,"g":103},"e34cf6ad":{"m":100,"g":103},"62222bd2":{"m":100,"g":103},"ed0fdbf3":{"m":100,"g":103},"b602f423":{"m":100,"g":103},"426b7493":{"m":100,"g":103},"528bd1ed":{"m":100,"g":103},"62a6b7c7":{"m":100,"g":103},"76154631":{"m":100,"g":103},"5c705b1d":{"m":100,"g":103},"b7094a5e":{"m":100,"g":103},"da0c0260":{"m":100,"g":103},"3212c2ad":{"m":100,"g":103},"53475674":{"m":100,"g":103},"ce32bc2b":{"m":100,"g":103},"e236d8fe":{"m":100,"g":103},"4fa44d63":{"m":100,"g":103},"e6312d27":{"m":100,"g":103},"8af145b7":{"m":100,"g":103},"6478831b":{"m":101,"g":103},"2e1d2d7e":{"m":101,"g":103},"fb16fbaf":{"m":101,"g":103},"0ce84c82":{"m":101,"g":103},"59d0bf01":{"m":101,"g":103},"7df2c0c2":{"m":101,"g":103},"69712e6f":{"m":101,"g":103},"001bffca":{"m":101,"g":103},"7c969717":{"m":101,"g":103},"8240a6b0":{"m":101,"g":103},"3a04aa4b":{"m":101,"g":103},"bd516949":{"m":101,"g":103},"74e7e457":{"m":101,"g":103},"1466c1b8":{"m":101,"g":103},"9c138a04":{"m":101,"g":103},"c8f549d9":{"m":101,"g":103},"134fa43e":{"m":101,"g":103},"ccfe52a0":{"m":101,"g":103},"747dd450":{"m":101,"g":103},"b5821592":{"m":101,"g":103},"a9dd3ec3":{"m":101,"g":103},"02328864":{"m":102,"g":103},"7a1f7fc5":{"m":102,"g":103},"51c38163":{"m":102,"g":103},"09f1a247":{"m":102,"g":103},"32fa1e9c":{"m":102,"g":103},"e7dc163f":{"m":102,"g":103},"e179e0b7":{"m":102,"g":103},"d9049592":{"m":102,"g":103},"26c8a310":{"m":102,"g":103},"5963e505":{"m":102,"g":103},"43118f5f":{"m":102,"g":103},"a5f5ab40":{"m":102,"g":103},"59aab76f":{"m":102,"g":103},"659bfd10":{"m":102,"g":103},"67e53b16":{"m":102,"g":103},"9b9e8253":{"m":102,"g":103},"66a398f4":{"m":102,"g":103},"29980334":{"m":102,"g":103},"a79a5d70":{"m":102,"g":103},"ec5f9442":{"m":102,"g":103},"3bdcdd13":{"m":102,"g":103},"a730ce81":{"m":102,"g":103},"55ecdc0a":{"m":102,"g":103},"e3f08c77":{"m":102,"g":103},"a9fd8033":{"m":102,"g":103},"2fbb754e":{"m":102,"g":103},"a85ebf50":{"m":102,"g":103},"9effeb5b":{"m":102,"g":103},"1992ef9b":{"m":102,"g":103},"c0fd77e8":{"m":102,"g":103},"a4c3b121":{"m":102,"g":103},"5973675b":{"m":102,"g":103},"4d16c88b":{"m":102,"g":103},"7a4309cc":{"m":102,"g":103},"81367066":{"m":102,"g":103},"263c9236":{"m":102,"g":103},"33f0de33":{"m":105,"g":107},"e7e5a305":{"m":105,"g":107},"dd7ca006":{"m":105,"g":107},"9305ea6c":{"m":105,"g":107},"aa4c66b5":{"m":105,"g":107},"39decec1":{"m":105,"g":104},"f6f46f46":{"m":105,"g":104},"2886e23d":{"m":105,"g":104},"99795d61":{"m":105,"g":104},"fe5086fd":{"m":105,"g":104},"04913430":{"m":105,"g":104},"0ad098b4":{"m":105,"g":104},"4a6e7a66":{"m":105,"g":104},"4b04998d":{"m":105,"g":104},"3dde8619":{"m":105,"g":104},"b7170cc8":{"m":105,"g":104},"5c14515f":{"m":105,"g":104},"2cd2e27f":{"m":105,"g":104},"743638bc":{"m":105,"g":104},"061c8959":{"m":105,"g":104},"4acf6902":{"m":105,"g":104},"aee0ef52":{"m":105,"g":103},"ae807774":{"m":105,"g":103},"8fbcfd07":{"m":105,"g":103},"3c307dc0":{"m":105,"g":103},"5d15fb8c":{"m":105,"g":103},"016fd251":{"m":105,"g":103},"8cd34458":{"m":106,"g":107},"0e0eef00":{"m":106,"g":107},"cb099d20":{"m":106,"g":107},"7a913301":{"m":106,"g":107},"5ce5093b":{"m":106,"g":107},"6f9baf10":{"m":106,"g":107},"a31b7a70":{"m":106,"g":107},"7ed8e51b":{"m":106,"g":107},"32f28154":{"m":106,"g":107},"f7b2853f":{"m":106,"g":107},"b0add2da":{"m":106,"g":107},"0305c505":{"m":106,"g":107},"8675bdf2":{"m":106,"g":107},"a437aa99":{"m":106,"g":107},"0e612dbf":{"m":106,"g":107},"9f47d686":{"m":106,"g":107},"d9def43d":{"m":106,"g":107},"e273aa6d":{"m":106,"g":107},"828a4fe9":{"m":106,"g":107},"8ada1ab6":{"m":106,"g":107},"e314b084":{"m":106,"g":107},"403566bc":{"m":106,"g":107},"0a56b721":{"m":106,"g":107},"603f5ce0":{"m":106,"g":107},"6d4fd882":{"m":106,"g":107},"f9f0138f":{"m":106,"g":107},"ac6962cc":{"m":106,"g":107},"4ca43b06":{"m":106,"g":107},"ea93079b":{"m":106,"g":107},"4bec99ec":{"m":106,"g":107},"89caf7a3":{"m":106,"g":107},"b27b1191":{"m":106,"g":107},"f642524f":{"m":106,"g":107},"82e6c3a6":{"m":106,"g":107},"b89d37cb":{"m":106,"g":107},"5deab128":{"m":106,"g":107},"d1c4d51c":{"m":106,"g":107},"1fe691a4":{"m":106,"g":107},"e2521926":{"m":106,"g":107},"07e46eca":{"m":106,"g":107},"ab9b893e":{"m":106,"g":107},"6a7528e6":{"m":106,"g":107},"2ae95d17":{"m":106,"g":107},"2d401bd9":{"m":106,"g":107},"b17c5b01":{"m":106,"g":107},"db7343c9":{"m":106,"g":107},"533cb5b2":{"m":106,"g":107},"6bdd2786":{"m":106,"g":107},"46e9d1c7":{"m":106,"g":107},"6c88f6c8":{"m":106,"g":107},"c8d3a402":{"m":106,"g":107},"7e831efe":{"m":106,"g":107},"20b5563e":{"m":106,"g":107},"97a38ee8":{"m":108,"g":115},"86d10d22":{"m":108,"g":115},"83871aa1":{"m":108,"g":115},"b1b3f0b3":{"m":108,"g":115},"34e5e11f":{"m":108,"g":115},"2600fc0d":{"m":108,"g":115},"ccd3fb94":{"m":108,"g":115},"c9dd70fb":{"m":108,"g":115},"6b2b8bf0":{"m":108,"g":115},"4edbe0d5":{"m":108,"g":115},"0374304a":{"m":108,"g":115},"127d4b0d":{"m":108,"g":115},"7e880286":{"m":108,"g":115},"446c8e4c":{"m":108,"g":115},"5ef545e6":{"m":108,"g":115},"c4500233":{"m":108,"g":115},"f445a1d9":{"m":108,"g":115},"e5638573":{"m":108,"g":115},"f556ac8b":{"m":108,"g":115},"110a6598":{"m":108,"g":115},"49f9d025":{"m":108,"g":115},"0f587e80":{"m":108,"g":115},"6078d5fc":{"m":108,"g":115},"70cf4abc":{"m":108,"g":115},"cebf4599":{"m":108,"g":115},"9c0c1e30":{"m":108,"g":115},"a1f011d0":{"m":108,"g":115},"9ec314c6":{"m":108,"g":115},"fedfe91c":{"m":108,"g":115},"988accbc":{"m":108,"g":115},"b6b2287e":{"m":108,"g":115},"243e745d":{"m":108,"g":115},"61a0e600":{"m":108,"g":115},"0f8cee8c":{"m":108,"g":115},"816c4c85":{"m":108,"g":115},"13ec8d42":{"m":108,"g":115},"05bd7897":{"m":108,"g":115},"5fd311d3":{"m":108,"g":115},"53e2cd46":{"m":108,"g":115},"9708d353":{"m":108,"g":115},"704ced1b":{"m":108,"g":115},"3cc3d9b9":{"m":108,"g":115},"0b3a5b11":{"m":108,"g":115},"6c855db8":{"m":108,"g":115},"0f9318f7":{"m":108,"g":115},"849957bc":{"m":108,"g":115},"cded039b":{"m":108,"g":115},"275f9df3":{"m":108,"g":115},"e8449ab5":{"m":108,"g":115},"4746aaea":{"m":108,"g":115},"10d34f74":{"m":108,"g":115},"9ba72530":{"m":108,"g":115},"9c8e4f69":{"m":108,"g":115},"78ae1758":{"m":108,"g":115},"dae9a80f":{"m":108,"g":115},"e85cb1ce":{"m":108,"g":115},"55d336cb":{"m":108,"g":115},"de4990a5":{"m":108,"g":115},"029e0af3":{"m":108,"g":115},"64574ef8":{"m":108,"g":115},"18da2c96":{"m":108,"g":115},"9b5f0f64":{"m":108,"g":115},"70bb066e":{"m":108,"g":115},"2c4b4b78":{"m":108,"g":115},"7cd2ee06":{"m":108,"g":115},"eb19ccad":{"m":108,"g":115},"25ef53f0":{"m":108,"g":115},"c674bf9c":{"m":108,"g":115},"af1973b8":{"m":108,"g":115},"5cfbb4c1":{"m":108,"g":115},"e6523102":{"m":108,"g":115},"3828db43":{"m":108,"g":115},"88fbc31b":{"m":108,"g":115},"8f5b9910":{"m":108,"g":115},"ef3004d9":{"m":108,"g":115},"84719b52":{"m":108,"g":115},"e99729c9":{"m":108,"g":115},"c10b8e6a":{"m":108,"g":115},"d4bce297":{"m":108,"g":115},"b0980af8":{"m":108,"g":115},"24eaebeb":{"m":108,"g":115},"a91e90d9":{"m":108,"g":115},"f96413c4":{"m":108,"g":115},"08ebdf79":{"m":108,"g":115},"42c87045":{"m":108,"g":115},"c9bf3877":{"m":108,"g":115},"de2dd738":{"m":108,"g":115},"1ec97697":{"m":108,"g":115},"d8ed60f2":{"m":108,"g":115},"f1b0eda5":{"m":108,"g":115},"f20b6a3f":{"m":108,"g":115},"3680d6f8":{"m":108,"g":115},"f5154495":{"m":108,"g":115},"e0ce171d":{"m":108,"g":115},"fe43e889":{"m":108,"g":115},"5ae5ecaa":{"m":108,"g":115},"5fbad308":{"m":108,"g":115},"7638f5e4":{"m":108,"g":115},"b45f753c":{"m":108,"g":115},"c5057262":{"m":108,"g":115},"46fe8b8c":{"m":108,"g":115},"0b95a01a":{"m":108,"g":115},"a3b810eb":{"m":108,"g":115},"94959237":{"m":108,"g":115},"f4fafacc":{"m":108,"g":115},"01d47a27":{"m":108,"g":115},"ecc9f3e4":{"m":108,"g":115},"7e8187e0":{"m":108,"g":115},"e483ab6d":{"m":108,"g":115},"720cd308":{"m":108,"g":115},"ce67b2d5":{"m":108,"g":115},"3c2c9f6c":{"m":108,"g":115},"a31ea448":{"m":108,"g":115},"439df454":{"m":108,"g":115},"5626e20b":{"m":108,"g":115},"c6c379ab":{"m":108,"g":115},"c2fbf60f":{"m":108,"g":115},"98b44e9e":{"m":108,"g":115},"6805f6da":{"m":108,"g":115},"ca533580":{"m":108,"g":115},"886454e8":{"m":108,"g":115},"0cf3fbeb":{"m":108,"g":115},"2256d62d":{"m":108,"g":115},"6cdcbcc6":{"m":108,"g":115},"c480a3f6":{"m":108,"g":115},"6e316588":{"m":108,"g":115},"24247b41":{"m":108,"g":115},"4c0bb411":{"m":108,"g":115},"968e1818":{"m":108,"g":115},"d08663ee":{"m":108,"g":115},"716e6827":{"m":108,"g":115},"84b30d9e":{"m":108,"g":115},"ff0cf51c":{"m":108,"g":115},"a1c7f742":{"m":108,"g":115},"ebbb75e9":{"m":108,"g":115},"b341b7db":{"m":108,"g":115},"b498cd21":{"m":108,"g":115},"0fc54b97":{"m":108,"g":115},"b3c1f2e4":{"m":108,"g":115},"be1a3cd9":{"m":108,"g":115},"4b74c3fc":{"m":108,"g":115},"ce3ca9b0":{"m":108,"g":115},"4d98e486":{"m":108,"g":115},"3d77a318":{"m":108,"g":115},"845d12a9":{"m":108,"g":115},"e47800e1":{"m":108,"g":115},"bb10e3a1":{"m":108,"g":115},"fda762a2":{"m":108,"g":115},"1df84ff4":{"m":108,"g":115},"66d6be08":{"m":108,"g":115},"1c1f8a11":{"m":108,"g":115},"384f8ab5":{"m":108,"g":115},"6a9d6ca3":{"m":108,"g":115},"94371dbb":{"m":108,"g":115},"740f0630":{"m":108,"g":115},"81da16f6":{"m":108,"g":115},"bc938ea1":{"m":108,"g":115},"eff4eb3f":{"m":108,"g":115},"87dab548":{"m":108,"g":115},"5121af46":{"m":108,"g":115},"983aa496":{"m":108,"g":115},"9c3e95d9":{"m":108,"g":115},"e52c3866":{"m":108,"g":115},"da53e13c":{"m":108,"g":115},"d7e38b2f":{"m":108,"g":115},"21b88460":{"m":108,"g":115},"0c8594e6":{"m":108,"g":115},"c186feed":{"m":108,"g":115},"84b006b2":{"m":108,"g":115},"8ca07bd9":{"m":108,"g":115},"4fc09e0d":{"m":108,"g":115},"a3d99d6d":{"m":108,"g":115},"189af908":{"m":108,"g":115},"f8644a56":{"m":108,"g":115},"e3e75a78":{"m":108,"g":115},"d4db9b02":{"m":108,"g":115},"f7dd651d":{"m":108,"g":115},"9d54c6e6":{"m":108,"g":115},"1f9d65f5":{"m":108,"g":115},"29589512":{"m":108,"g":115},"584e1ab2":{"m":108,"g":115},"392de007":{"m":108,"g":115},"004f7f19":{"m":108,"g":115},"d2fbf2de":{"m":108,"g":115},"fab0f6e7":{"m":108,"g":115},"27985c27":{"m":108,"g":115},"ac474869":{"m":108,"g":115},"0b1e04f0":{"m":108,"g":115},"c1c7dc45":{"m":108,"g":115},"2cc9eeab":{"m":108,"g":115},"63d82a77":{"m":108,"g":115},"53dcc750":{"m":108,"g":115},"432f2053":{"m":108,"g":115},"1fea998a":{"m":108,"g":115},"5aa1ebd2":{"m":108,"g":115},"4dbf4360":{"m":108,"g":115},"3d6be1fb":{"m":108,"g":115},"4063234c":{"m":108,"g":115},"83feef5b":{"m":108,"g":115},"2871eacc":{"m":108,"g":115},"ac15bdc1":{"m":108,"g":115},"d6451c3f":{"m":108,"g":115},"841810f2":{"m":108,"g":115},"733446dd":{"m":108,"g":115},"4c22897a":{"m":108,"g":115},"1bc183c6":{"m":108,"g":115},"b87aacb5":{"m":108,"g":115},"b3363cc1":{"m":108,"g":115},"98457c04":{"m":108,"g":115},"0fc8bf2c":{"m":108,"g":115},"a669bc2f":{"m":108,"g":115},"6b7c2471":{"m":108,"g":115},"a027a9b4":{"m":108,"g":115},"9e426466":{"m":108,"g":115},"2f20f430":{"m":108,"g":115},"65736dc5":{"m":108,"g":115},"7b56e494":{"m":108,"g":115},"0ff6d1fc":{"m":108,"g":115},"4a16a71c":{"m":108,"g":115},"a16923ef":{"m":108,"g":115},"6337d905":{"m":108,"g":115},"71fb8c95":{"m":108,"g":115},"94f44b88":{"m":108,"g":115},"3b3b3baf":{"m":108,"g":115},"35e6bc92":{"m":108,"g":115},"9394ed63":{"m":108,"g":115},"930fe467":{"m":108,"g":115},"13c48dcf":{"m":108,"g":115},"8723b4f1":{"m":108,"g":115},"62f99e08":{"m":108,"g":115},"86a0be65":{"m":108,"g":115},"0edda320":{"m":108,"g":115},"924827c3":{"m":108,"g":115},"c81daf83":{"m":108,"g":115},"25caa7a8":{"m":108,"g":115},"03d11449":{"m":108,"g":115},"83123f48":{"m":108,"g":115},"48afa8f1":{"m":108,"g":115},"2ecbd8b8":{"m":108,"g":115},"305b27c1":{"m":108,"g":115},"1ce30dd1":{"m":108,"g":115},"c9ee7385":{"m":108,"g":115},"1f9ec653":{"m":108,"g":115},"ad359d1c":{"m":108,"g":115},"5f5b3b24":{"m":108,"g":115},"4caca4f6":{"m":108,"g":115},"f2a5de28":{"m":108,"g":115},"445f9dca":{"m":108,"g":115},"3a9afe2a":{"m":108,"g":115},"9aea2555":{"m":108,"g":115},"fcc11e5e":{"m":108,"g":115},"5190ba7f":{"m":108,"g":115},"5438886c":{"m":108,"g":115},"9c83d74d":{"m":108,"g":115},"b4ac2b9c":{"m":108,"g":115},"83262dcb":{"m":108,"g":115},"c46c75f8":{"m":108,"g":115},"2aaf22c4":{"m":108,"g":115},"29a610b4":{"m":108,"g":115},"5ded39ca":{"m":108,"g":115},"4093d460":{"m":108,"g":115},"9d68bdb2":{"m":108,"g":115},"a2184901":{"m":108,"g":115},"0eec4cb6":{"m":108,"g":115},"ff1f6825":{"m":108,"g":115},"9f78f391":{"m":108,"g":115},"f508cd3c":{"m":108,"g":115},"44e86480":{"m":108,"g":115},"8c07fabd":{"m":108,"g":115},"90f44b74":{"m":108,"g":115},"38907fe6":{"m":108,"g":115},"f9afa7dc":{"m":108,"g":115},"0d9e89ec":{"m":108,"g":115},"3d64fda3":{"m":108,"g":115},"3bffe112":{"m":108,"g":115},"44426e54":{"m":108,"g":115},"9f24dfef":{"m":108,"g":115},"89f1d4f5":{"m":108,"g":115},"75e6a7cd":{"m":108,"g":115},"6f81a710":{"m":108,"g":115},"a6452b71":{"m":108,"g":115},"f4ae50e9":{"m":108,"g":115},"84cb449e":{"m":108,"g":115},"f003cd35":{"m":108,"g":115},"9d834fdc":{"m":108,"g":115},"b3279251":{"m":108,"g":115},"067068f2":{"m":108,"g":115},"6beeff41":{"m":108,"g":115},"2e8e7e35":{"m":108,"g":115},"2449a0af":{"m":108,"g":115},"0f229c07":{"m":108,"g":115},"dd001a54":{"m":108,"g":115},"4ea9d74a":{"m":108,"g":115},"dd949ace":{"m":108,"g":115},"f2887498":{"m":108,"g":115},"8ecf6b9d":{"m":108,"g":115},"0418b9d4":{"m":108,"g":115},"e322a94d":{"m":108,"g":115},"2c7f01bc":{"m":108,"g":115},"b58ae7a2":{"m":108,"g":115},"6345069f":{"m":108,"g":115},"ce9cf353":{"m":108,"g":115},"f8a173bb":{"m":108,"g":115},"6b847a9a":{"m":108,"g":115},"473400e4":{"m":108,"g":115},"dd665f96":{"m":108,"g":115},"3817a37d":{"m":108,"g":115},"7ba5ad57":{"m":108,"g":115},"19bc77f0":{"m":108,"g":115},"86497d99":{"m":108,"g":115},"5c31b35d":{"m":108,"g":115},"ef48d554":{"m":108,"g":115},"a886564a":{"m":108,"g":115},"9a44b643":{"m":108,"g":115},"41d71ca4":{"m":108,"g":115},"20cfc5a2":{"m":108,"g":115},"48b8b4c1":{"m":108,"g":115},"323bc2f5":{"m":108,"g":115},"137e75da":{"m":108,"g":115},"52e1f52f":{"m":108,"g":115},"50188092":{"m":108,"g":115},"326a901d":{"m":108,"g":115},"6e0b6468":{"m":108,"g":115},"4a9f3eef":{"m":108,"g":115},"1b7afad0":{"m":108,"g":115},"f29aba8c":{"m":108,"g":115},"faa25df1":{"m":108,"g":115},"7b81f956":{"m":108,"g":115},"d3e67deb":{"m":108,"g":115},"442534aa":{"m":108,"g":115},"de8b8b6e":{"m":108,"g":115},"3f2e315f":{"m":108,"g":115},"6e215118":{"m":108,"g":115},"a47baff1":{"m":108,"g":115},"fd7e15b7":{"m":108,"g":115},"fc42ff7b":{"m":108,"g":115},"7c0db868":{"m":108,"g":115},"706bd69c":{"m":108,"g":115},"23f2afb2":{"m":108,"g":115},"a60f88b5":{"m":108,"g":115},"591c232f":{"m":108,"g":115},"f352b793":{"m":108,"g":115},"6642e3a2":{"m":108,"g":115},"67a7d1f6":{"m":108,"g":115},"92cbef59":{"m":108,"g":115},"b3359dc9":{"m":108,"g":115},"7b7e5615":{"m":108,"g":115},"1a8706c8":{"m":108,"g":115},"7d3af603":{"m":108,"g":115},"4e7f0252":{"m":108,"g":115},"36bfddec":{"m":108,"g":115},"91e2f902":{"m":108,"g":115},"a59cbea9":{"m":108,"g":115},"53f7874a":{"m":108,"g":115},"61a46804":{"m":108,"g":115},"9020f7fc":{"m":108,"g":115},"dd650e0e":{"m":108,"g":115},"a9471542":{"m":108,"g":115},"41357e51":{"m":108,"g":115},"e2fd2b9c":{"m":108,"g":115},"7490e3f6":{"m":108,"g":115},"6ee6619b":{"m":108,"g":115},"54ea57f2":{"m":108,"g":115},"b4c9f38a":{"m":108,"g":115},"11325474":{"m":108,"g":115},"1d24db83":{"m":108,"g":115},"44401358":{"m":108,"g":115},"9c7e3924":{"m":108,"g":115},"08fab2b0":{"m":108,"g":115},"0d1e27a0":{"m":108,"g":115},"774b47f3":{"m":108,"g":115},"76915d68":{"m":108,"g":115},"39fd1788":{"m":108,"g":115},"ed0a3dd5":{"m":108,"g":115},"2e901e89":{"m":108,"g":115},"d3be9710":{"m":108,"g":115},"3e7ff1ab":{"m":108,"g":115},"aaf0ad8c":{"m":108,"g":115},"361379b5":{"m":108,"g":115},"1ac16add":{"m":108,"g":115},"c3a5fb3b":{"m":108,"g":115},"4bf6e5a6":{"m":108,"g":115},"3ae33fcd":{"m":108,"g":115},"500b15c9":{"m":108,"g":107},"16a4c66d":{"m":108,"g":107},"89e6521c":{"m":108,"g":107},"fd05b567":{"m":108,"g":107},"482c3db2":{"m":108,"g":107},"47824c14":{"m":108,"g":107},"c36a6693":{"m":108,"g":107},"62f8eb48":{"m":108,"g":107},"b7cd7430":{"m":108,"g":107},"a69b6370":{"m":108,"g":107},"2d120f8b":{"m":108,"g":107},"4f2e1490":{"m":108,"g":107},"3fa3c6cd":{"m":108,"g":107},"6210e2c4":{"m":108,"g":107},"6ad6c8c9":{"m":108,"g":107},"5b6acc14":{"m":108,"g":107},"4373df55":{"m":108,"g":107},"c0e84297":{"m":108,"g":107},"92cc32d9":{"m":108,"g":107},"cbbd685a":{"m":108,"g":107},"78aad910":{"m":108,"g":107},"288ae41f":{"m":108,"g":107},"01c99a99":{"m":108,"g":107},"b114a810":{"m":108,"g":107},"0475448e":{"m":108,"g":107},"399e7ec8":{"m":108,"g":107},"1bd53168":{"m":108,"g":107},"aeac900c":{"m":108,"g":107},"4fc5f2f9":{"m":108,"g":107},"168033d5":{"m":108,"g":107},"cbbb7383":{"m":108,"g":107},"89588179":{"m":108,"g":107},"8c7bb39d":{"m":108,"g":107},"ca47e24f":{"m":108,"g":107},"d26ca84f":{"m":108,"g":107},"8128e08d":{"m":108,"g":107},"5d62b56f":{"m":108,"g":107},"3ae8e3ea":{"m":108,"g":107},"c1d2061f":{"m":108,"g":107},"556e4143":{"m":108,"g":107},"4ef47839":{"m":108,"g":107},"32d9e39a":{"m":108,"g":107},"4f4e0e41":{"m":108,"g":107},"901ab758":{"m":108,"g":107},"8e8545ca":{"m":108,"g":107},"a4b0d5c9":{"m":108,"g":107},"40e3b2be":{"m":108,"g":107},"75df31b6":{"m":108,"g":107},"194561f2":{"m":108,"g":107},"5e91fed1":{"m":108,"g":107},"873f384a":{"m":108,"g":107},"b01eeb80":{"m":108,"g":107},"1ea94d3b":{"m":108,"g":107},"354ac435":{"m":108,"g":107},"d98a4913":{"m":108,"g":107},"08f8f490":{"m":108,"g":107},"d4bf5a85":{"m":108,"g":107},"7cb20754":{"m":108,"g":107},"6d0646da":{"m":108,"g":107},"02bc1c7d":{"m":108,"g":107},"fc8c8e50":{"m":108,"g":107},"9bd4872a":{"m":108,"g":107},"2fa0462c":{"m":108,"g":107},"915140fd":{"m":108,"g":107},"36fc9260":{"m":108,"g":107},"fee0ab0f":{"m":108,"g":107},"f57d2dc1":{"m":108,"g":107},"f2d68ded":{"m":108,"g":107},"3b87a9e8":{"m":108,"g":107},"f024795e":{"m":108,"g":107},"b102353f":{"m":108,"g":107},"7a27e798":{"m":108,"g":107},"76ba5bbe":{"m":108,"g":107},"ed6f7597":{"m":108,"g":107},"e67276ec":{"m":108,"g":107},"0242bb9c":{"m":108,"g":107},"760286e3":{"m":108,"g":107},"3435a24e":{"m":108,"g":107},"00da9065":{"m":108,"g":107},"e0ab167d":{"m":109,"g":115},"c807cd7c":{"m":109,"g":115},"327f7b7c":{"m":109,"g":115},"80425e59":{"m":109,"g":115},"af9d4eb0":{"m":109,"g":115},"fb107cfd":{"m":109,"g":115},"e3e97a12":{"m":110,"g":115},"05106867":{"m":110,"g":115},"9dcdf5da":{"m":110,"g":115},"f8b757bc":{"m":110,"g":115},"ebd9dbe7":{"m":110,"g":115},"938e986e":{"m":110,"g":115},"17d5eda8":{"m":110,"g":115},"71a7f1d8":{"m":110,"g":115},"433266c1":{"m":110,"g":115},"fda47926":{"m":110,"g":115},"a0b22f2f":{"m":110,"g":115},"b5c6529e":{"m":110,"g":115},"ca4b86c5":{"m":110,"g":115},"dd6ec029":{"m":110,"g":115},"bf863e3b":{"m":110,"g":115},"9e169ea8":{"m":110,"g":115},"bc80dc4c":{"m":111,"g":115},"b962a296":{"m":111,"g":115},"aa3eba8e":{"m":111,"g":115},"07ee0ab7":{"m":111,"g":115},"5c06dcb7":{"m":111,"g":115},"6f6beca4":{"m":111,"g":115},"68a54e06":{"m":111,"g":115},"fd18995c":{"m":111,"g":115},"db0831e0":{"m":111,"g":115},"6e4e1c8c":{"m":111,"g":115},"9768c50d":{"m":111,"g":115},"fd71b11b":{"m":111,"g":115},"ae7428a8":{"m":111,"g":115},"a3aee7c3":{"m":111,"g":115},"79e6a8a6":{"m":111,"g":115},"8f7b1c31":{"m":111,"g":115},"b9683be6":{"m":111,"g":115},"a85363c1":{"m":111,"g":115},"b21fdd53":{"m":111,"g":115},"c04c17ed":{"m":111,"g":115},"16a6d21b":{"m":111,"g":115},"a530b3ff":{"m":111,"g":115},"603b3446":{"m":111,"g":115},"b6c14ec0":{"m":111,"g":115},"43de1d73":{"m":111,"g":115},"79ce3688":{"m":111,"g":115},"44ffe2cb":{"m":111,"g":115},"1a0896e9":{"m":111,"g":115},"90313fb0":{"m":111,"g":115},"3578eb1e":{"m":111,"g":115},"0936c766":{"m":111,"g":115},"0ef583b7":{"m":111,"g":115},"f7881a27":{"m":111,"g":115},"fdff3167":{"m":111,"g":115},"cbc0e4d7":{"m":111,"g":115},"4cd08dc5":{"m":111,"g":115},"f92b729d":{"m":111,"g":115},"e2e378ca":{"m":111,"g":115},"dc1decc6":{"m":111,"g":115},"03680f33":{"m":111,"g":115},"d4c5e534":{"m":111,"g":115},"817c62a0":{"m":111,"g":115},"0ff72419":{"m":111,"g":115},"80dc76e1":{"m":111,"g":115},"9b08d975":{"m":111,"g":115},"a0a77d93":{"m":111,"g":115},"24a8cee6":{"m":111,"g":115},"3affa9dc":{"m":111,"g":115},"ea0696b9":{"m":111,"g":115},"3aec3d4f":{"m":111,"g":115},"b0d25e72":{"m":112,"g":115},"a2424068":{"m":112,"g":115},"c5d2b01c":{"m":112,"g":115},"46ccbed2":{"m":112,"g":115},"fe68c148":{"m":112,"g":115},"70c0c1f9":{"m":112,"g":115},"760b788a":{"m":112,"g":115},"1ee11df8":{"m":112,"g":115},"dee197e1":{"m":112,"g":115},"ab795ae8":{"m":112,"g":115},"480d1b8b":{"m":112,"g":115},"6c18ab46":{"m":112,"g":115},"4a0e0be2":{"m":112,"g":115},"64f296f8":{"m":112,"g":115},"956d805d":{"m":112,"g":115},"30c6e1f5":{"m":112,"g":115},"bfe01a5e":{"m":112,"g":115},"3dd6420a":{"m":112,"g":115},"532f998b":{"m":112,"g":115},"de15d140":{"m":112,"g":115},"37367da6":{"m":112,"g":115},"ef959d7b":{"m":112,"g":115},"4aa1e69b":{"m":112,"g":115},"dc491b39":{"m":112,"g":115},"5b64f006":{"m":112,"g":115},"5b7448de":{"m":112,"g":115},"6d55f60e":{"m":112,"g":115},"033b75f5":{"m":112,"g":115},"f3b5db6e":{"m":112,"g":115},"2286e85e":{"m":112,"g":115},"91b3555d":{"m":112,"g":115},"9e2f7252":{"m":112,"g":115},"21176b00":{"m":112,"g":115},"94100294":{"m":112,"g":115},"cda7e47c":{"m":112,"g":115},"e903f695":{"m":112,"g":115},"27760fc1":{"m":112,"g":115},"0ac809de":{"m":112,"g":115},"4efe2c57":{"m":112,"g":115},"5be8c2f7":{"m":112,"g":115},"737d73ed":{"m":112,"g":115},"ebd0e1c1":{"m":112,"g":115},"a1d03892":{"m":112,"g":115},"dccf52f9":{"m":112,"g":115},"676a7b51":{"m":112,"g":115},"15f99347":{"m":112,"g":115},"bcf1955f":{"m":112,"g":115},"a06bf664":{"m":112,"g":115},"bf72b801":{"m":112,"g":115},"8cbe1538":{"m":112,"g":115},"8471e5e6":{"m":112,"g":115},"4582931a":{"m":112,"g":115},"d352c29a":{"m":112,"g":115},"d3ee7098":{"m":112,"g":115},"71fc7b7f":{"m":112,"g":115},"9ab72f98":{"m":112,"g":115},"f3817cb0":{"m":112,"g":115},"71133a04":{"m":112,"g":115},"2cd94dd0":{"m":112,"g":115},"f5f6b3b4":{"m":112,"g":115},"94fb4e9e":{"m":112,"g":115},"d1d4074c":{"m":112,"g":115},"718f25ae":{"m":112,"g":115},"948b01a0":{"m":112,"g":115},"cdc56ef6":{"m":112,"g":115},"16ff3d4b":{"m":112,"g":115},"83d55ac5":{"m":112,"g":115},"2fe17735":{"m":112,"g":115},"97fff98c":{"m":112,"g":115},"ba066ca0":{"m":112,"g":115},"96784a65":{"m":112,"g":115},"df5407fb":{"m":112,"g":115},"8ad700f7":{"m":112,"g":115},"148022fc":{"m":112,"g":115},"7a40e4f4":{"m":112,"g":115},"19d64f2b":{"m":112,"g":115},"a02071a1":{"m":112,"g":115},"45b3a6a2":{"m":112,"g":115},"9a18aa54":{"m":112,"g":115},"91f0fd95":{"m":112,"g":115},"8085aca7":{"m":112,"g":115},"0096798e":{"m":112,"g":115},"2c2b19b1":{"m":112,"g":115},"72f9fc5f":{"m":112,"g":115},"ec99668a":{"m":112,"g":115},"78f13981":{"m":112,"g":115},"bfd7a18d":{"m":112,"g":115},"5dd8c644":{"m":112,"g":115},"ee21817c":{"m":112,"g":115},"b7d1f17b":{"m":112,"g":115},"c8295d23":{"m":112,"g":115},"b67c277f":{"m":112,"g":115},"8116804e":{"m":112,"g":115},"8c5930f0":{"m":112,"g":115},"3b99f23c":{"m":112,"g":115},"ee0b3c5b":{"m":112,"g":115},"6049ca20":{"m":112,"g":115},"7577f0e4":{"m":112,"g":115},"8cda5a62":{"m":112,"g":115},"400d3b97":{"m":112,"g":115},"37d83c6e":{"m":112,"g":115},"7802586c":{"m":112,"g":115},"bc5fc332":{"m":112,"g":115},"f3440adc":{"m":112,"g":115},"5a7e10fe":{"m":112,"g":115},"33467c05":{"m":112,"g":115},"b0fcbb74":{"m":112,"g":115},"76a2c86b":{"m":112,"g":115},"e719bb0e":{"m":112,"g":115},"06724683":{"m":112,"g":115},"617aa2b2":{"m":112,"g":115},"111b1379":{"m":112,"g":115},"41628dc1":{"m":112,"g":115},"a12061df":{"m":112,"g":115},"85ed8e0a":{"m":112,"g":115},"dd1e2689":{"m":112,"g":115},"9a7ced4e":{"m":112,"g":115},"cb3918a0":{"m":112,"g":115},"f3b67602":{"m":112,"g":115},"9eb50ecc":{"m":112,"g":115},"b3e7a2ce":{"m":112,"g":115},"00974e4f":{"m":112,"g":115},"5f1eb204":{"m":112,"g":115},"039cef76":{"m":112,"g":115},"4c22ebe2":{"m":112,"g":115},"a5a03209":{"m":112,"g":115},"21af5c04":{"m":112,"g":115},"012584ec":{"m":112,"g":115},"90dfe3de":{"m":112,"g":115},"9a719b7a":{"m":112,"g":115},"3fa62da7":{"m":112,"g":115},"dbb1235d":{"m":112,"g":115},"ad26f298":{"m":112,"g":115},"8d114f25":{"m":112,"g":115},"0e78c63c":{"m":112,"g":115},"1a3d6f31":{"m":112,"g":115},"0b8c5721":{"m":112,"g":115},"beac202b":{"m":112,"g":115},"21b9a4b4":{"m":112,"g":115},"db37422c":{"m":112,"g":115},"ab62b135":{"m":112,"g":115},"273b2834":{"m":112,"g":115},"f84db115":{"m":112,"g":115},"efb0de2c":{"m":112,"g":115},"0f6ac5e2":{"m":112,"g":115},"29850900":{"m":112,"g":115},"e678cc71":{"m":112,"g":115},"4efe844a":{"m":112,"g":115},"bde73ee4":{"m":112,"g":115},"4f0e28d7":{"m":112,"g":115},"045ab92d":{"m":112,"g":115},"bd7f8821":{"m":112,"g":115},"5e5c30d9":{"m":112,"g":115},"9f00ec44":{"m":112,"g":115},"8e85ee88":{"m":112,"g":115},"adf73175":{"m":112,"g":115},"13705dae":{"m":112,"g":115},"df97b31f":{"m":112,"g":115},"339f8eef":{"m":112,"g":115},"afd9f2f5":{"m":112,"g":115},"f40038fb":{"m":112,"g":115},"bebd0576":{"m":112,"g":115},"f9836660":{"m":112,"g":115},"8b3b995a":{"m":112,"g":115},"6e95f5e5":{"m":112,"g":115},"0e9387a9":{"m":112,"g":115},"fa9c82d3":{"m":112,"g":115},"918e3d4c":{"m":112,"g":115},"e9697374":{"m":112,"g":115},"93088b69":{"m":112,"g":115},"453511ac":{"m":112,"g":115},"d0730487":{"m":112,"g":115},"b32ab070":{"m":112,"g":115},"75ee0011":{"m":112,"g":115},"ec15c836":{"m":112,"g":115},"106c2b31":{"m":112,"g":115},"c6756949":{"m":112,"g":115},"27e8ffed":{"m":112,"g":115},"4dbb34fe":{"m":112,"g":115},"1e18a341":{"m":112,"g":115},"2c562fd2":{"m":112,"g":115},"b648d862":{"m":112,"g":115},"bbf261ae":{"m":112,"g":115},"4f8a982d":{"m":112,"g":115},"d966b902":{"m":112,"g":115},"de921733":{"m":112,"g":115},"397448eb":{"m":112,"g":115},"66d5d042":{"m":112,"g":115},"73179b76":{"m":112,"g":115},"8cbf71dc":{"m":112,"g":115},"56eb5d0a":{"m":112,"g":115},"4ed9053e":{"m":112,"g":115},"5e19b159":{"m":112,"g":115},"788b19a5":{"m":112,"g":115},"f78b7fd1":{"m":112,"g":115},"b1fb7e45":{"m":112,"g":115},"1b2ff4fb":{"m":112,"g":115},"2c7ca33a":{"m":112,"g":115},"df397a72":{"m":112,"g":115},"5dfcd6c2":{"m":112,"g":115},"0dfd54d1":{"m":112,"g":115},"bcbeed71":{"m":112,"g":115},"cc9a31c6":{"m":112,"g":115},"d631290e":{"m":112,"g":115},"37565b7f":{"m":112,"g":115},"6243c367":{"m":112,"g":115},"60e37f80":{"m":112,"g":115},"369b1433":{"m":112,"g":115},"03dbf1aa":{"m":112,"g":115},"11dcabc5":{"m":112,"g":115},"4d89389c":{"m":112,"g":115},"9491d6e5":{"m":112,"g":115},"f64b8e3e":{"m":112,"g":115},"53976fce":{"m":112,"g":115},"18f91eb6":{"m":112,"g":115},"8766b3ac":{"m":112,"g":115},"1db649ac":{"m":112,"g":115},"a1e5d781":{"m":112,"g":115},"b7361cc4":{"m":112,"g":115},"a96c5b5c":{"m":112,"g":115},"b9eb0d9c":{"m":112,"g":115},"1fbfdebe":{"m":112,"g":115},"a25e8e42":{"m":112,"g":115},"d4a93841":{"m":112,"g":115},"21e1bc47":{"m":112,"g":115},"9a0cac1b":{"m":112,"g":115},"b5245064":{"m":112,"g":115},"9d9fa9a5":{"m":112,"g":115},"58d06fdc":{"m":112,"g":115},"cb9e0e41":{"m":112,"g":115},"9db80253":{"m":112,"g":115},"598c0bc1":{"m":112,"g":115},"b361750a":{"m":112,"g":115},"16e56ea6":{"m":112,"g":115},"349b491c":{"m":112,"g":115},"5f77e129":{"m":112,"g":115},"4750cddf":{"m":112,"g":115},"065e523d":{"m":112,"g":115},"7de2ce45":{"m":112,"g":115},"8c2ffaaf":{"m":112,"g":115},"20445327":{"m":112,"g":115},"6d3c20cf":{"m":112,"g":115},"8b6966d0":{"m":112,"g":115},"a391f73a":{"m":112,"g":115},"25c73959":{"m":112,"g":115},"f05c6873":{"m":112,"g":115},"9a0d0b75":{"m":112,"g":115},"ba861293":{"m":112,"g":115},"c112bcc4":{"m":112,"g":115},"5e194b21":{"m":112,"g":115},"fd5ce576":{"m":112,"g":115},"92d79646":{"m":112,"g":115},"f9076a5a":{"m":112,"g":115},"646076b7":{"m":112,"g":115},"0d040089":{"m":112,"g":115},"05e47872":{"m":112,"g":115},"1e61b496":{"m":112,"g":115},"300676af":{"m":112,"g":115},"7fe89f7c":{"m":112,"g":115},"9970e3bf":{"m":112,"g":115},"70eedb58":{"m":112,"g":115},"9c99949e":{"m":112,"g":115},"c5082f0f":{"m":112,"g":115},"836873b9":{"m":112,"g":115},"8abe8dea":{"m":112,"g":115},"1e85589d":{"m":112,"g":115},"c2a26e72":{"m":112,"g":115},"591e6c59":{"m":112,"g":115},"42f34437":{"m":112,"g":115},"5c34b4f1":{"m":112,"g":115},"ff9b5618":{"m":112,"g":115},"fcd72bd1":{"m":112,"g":115},"3d8fc434":{"m":112,"g":115},"87a0f7d2":{"m":112,"g":115},"839c93bd":{"m":112,"g":115},"f1e9bbaf":{"m":112,"g":115},"3fd1431d":{"m":112,"g":115},"161e9dc5":{"m":112,"g":115},"54e872d3":{"m":112,"g":115},"e5b29bf1":{"m":112,"g":115},"9a7c8842":{"m":112,"g":115},"7a16db9b":{"m":112,"g":115},"09a1df22":{"m":112,"g":115},"4b7034dd":{"m":112,"g":115},"a23c3020":{"m":112,"g":115},"a7d825fc":{"m":112,"g":115},"38cd5fb1":{"m":112,"g":115},"001f5194":{"m":112,"g":115},"5ad296bd":{"m":112,"g":115},"9f81d741":{"m":112,"g":115},"a38c1497":{"m":112,"g":115},"74dd4249":{"m":112,"g":115},"dc20c22f":{"m":112,"g":115},"711390a9":{"m":112,"g":115},"53430588":{"m":112,"g":115},"fce7ae33":{"m":112,"g":115},"6b39f9cf":{"m":112,"g":115},"07c9d8fb":{"m":112,"g":115},"4a4772ae":{"m":112,"g":115},"c3779233":{"m":112,"g":115},"f84b57c8":{"m":112,"g":115},"aee094e4":{"m":112,"g":115},"55349e36":{"m":112,"g":115},"e1f7cf57":{"m":112,"g":115},"2bb9d454":{"m":112,"g":115},"d0934a51":{"m":112,"g":115},"3f2d0cef":{"m":112,"g":115},"8b30bec2":{"m":112,"g":115},"4aeba40d":{"m":112,"g":115},"28684f90":{"m":112,"g":115},"a4a3d823":{"m":113,"g":115},"0b13cbb7":{"m":113,"g":115},"efbc687c":{"m":113,"g":115},"292a867a":{"m":113,"g":115},"8fd41eae":{"m":113,"g":115},"0cd1996e":{"m":113,"g":115},"b6b4b563":{"m":113,"g":115},"f8924ad7":{"m":113,"g":115},"2f80bd9f":{"m":113,"g":115},"366a603e":{"m":113,"g":115},"baee0860":{"m":113,"g":115},"c7a104c1":{"m":113,"g":115},"97d966a7":{"m":113,"g":115},"8e66d87f":{"m":113,"g":115},"a20fc7b7":{"m":113,"g":115},"6b30e097":{"m":113,"g":115},"d645ae90":{"m":113,"g":115},"41763ba0":{"m":113,"g":115},"652c24a6":{"m":113,"g":115},"5e142484":{"m":113,"g":115},"c560410d":{"m":113,"g":115},"590f2da0":{"m":113,"g":115},"148d8d48":{"m":113,"g":115},"1a599509":{"m":113,"g":115},"36a6b8db":{"m":113,"g":115},"e0b2d3ee":{"m":113,"g":115},"4cb5a523":{"m":113,"g":115},"85c1f793":{"m":113,"g":115},"48e9e719":{"m":113,"g":115},"31b49c0b":{"m":113,"g":115},"d736e0b6":{"m":113,"g":115},"ffd03a9b":{"m":113,"g":115},"666da3d5":{"m":113,"g":115},"d01b9214":{"m":113,"g":115},"c70e58e8":{"m":113,"g":115},"c61b9a1d":{"m":113,"g":115},"3c3d6255":{"m":113,"g":115},"546914fa":{"m":113,"g":115},"4726c919":{"m":113,"g":115},"a0010bf4":{"m":113,"g":115},"307fc060":{"m":113,"g":115},"586e81a2":{"m":113,"g":115},"fad7ca73":{"m":113,"g":115},"08af8ffb":{"m":113,"g":115},"2c7f4ca2":{"m":113,"g":115},"03def5e3":{"m":113,"g":115},"6ae3f05b":{"m":113,"g":115},"fdc4e1e5":{"m":113,"g":115},"04b86b3c":{"m":113,"g":115},"d6777a70":{"m":113,"g":115},"8c574902":{"m":113,"g":115},"34151f17":{"m":113,"g":115},"6794d210":{"m":113,"g":115},"1a31229c":{"m":113,"g":115},"de89ef49":{"m":113,"g":115},"b00a0c78":{"m":113,"g":115},"a2faf894":{"m":113,"g":115},"7e61737d":{"m":113,"g":115},"3c699772":{"m":113,"g":115},"e8100774":{"m":113,"g":115},"963175d5":{"m":113,"g":115},"0618ad6d":{"m":113,"g":115},"6a261aac":{"m":113,"g":115},"7ff740a6":{"m":113,"g":115},"bfcd9b24":{"m":113,"g":115},"458611de":{"m":113,"g":115},"3511b370":{"m":113,"g":115},"afcd3e10":{"m":113,"g":115},"12d68183":{"m":113,"g":115},"b65db028":{"m":113,"g":115},"948278f1":{"m":113,"g":115},"7d004799":{"m":113,"g":115},"083629c2":{"m":113,"g":115},"b658be6f":{"m":113,"g":115},"5e786cca":{"m":113,"g":115},"0b9dfba7":{"m":113,"g":115},"6a290034":{"m":113,"g":115},"2ac453b0":{"m":113,"g":115},"f35def86":{"m":113,"g":115},"d61615fe":{"m":113,"g":115},"b1ccaf01":{"m":113,"g":115},"097725bb":{"m":113,"g":115},"44b1fbe2":{"m":113,"g":115},"c0dbbdd1":{"m":113,"g":115},"25e7dbe8":{"m":113,"g":115},"0b2aa8a7":{"m":113,"g":115},"609f65ba":{"m":113,"g":115},"2d62af6b":{"m":113,"g":115},"a28b394f":{"m":113,"g":115},"96fe2d0f":{"m":113,"g":115},"bfa27438":{"m":113,"g":115},"86cb4db0":{"m":113,"g":115},"2e130b76":{"m":113,"g":115},"ac1f2928":{"m":113,"g":115},"195a59fe":{"m":113,"g":115},"47488cc3":{"m":113,"g":115},"61305291":{"m":113,"g":115},"a9ce2bcb":{"m":113,"g":115},"5dddb331":{"m":113,"g":115},"01a26544":{"m":113,"g":115},"73d4a5f8":{"m":113,"g":115},"7fb551a7":{"m":113,"g":115},"1193f131":{"m":113,"g":115},"84a9f5d6":{"m":113,"g":115},"8ce830a8":{"m":113,"g":115},"fb367acf":{"m":113,"g":115},"a6cc86df":{"m":113,"g":115},"229d2b95":{"m":113,"g":115},"9710f718":{"m":113,"g":115},"91847e38":{"m":113,"g":115},"5a290a56":{"m":113,"g":115},"580051c5":{"m":113,"g":115},"1237aa19":{"m":113,"g":115},"59911195":{"m":113,"g":115},"424591d5":{"m":113,"g":115},"d1676cd4":{"m":113,"g":115},"33b3c0f8":{"m":113,"g":115},"e5281f84":{"m":113,"g":115},"d17986f8":{"m":113,"g":115},"8831c55c":{"m":113,"g":115},"2bc61dd1":{"m":113,"g":115},"6535fda1":{"m":113,"g":115},"3713eb61":{"m":113,"g":115},"5937a56d":{"m":113,"g":115},"f065e5be":{"m":113,"g":115},"9de1320b":{"m":113,"g":115},"dda34c2f":{"m":113,"g":115},"4eeaff74":{"m":113,"g":115},"a17e70f5":{"m":113,"g":115},"816b3a43":{"m":113,"g":115},"3a641d90":{"m":113,"g":115},"6f16bf9d":{"m":113,"g":115},"5942fdb4":{"m":113,"g":115},"af4ab656":{"m":113,"g":115},"11965b0d":{"m":113,"g":115},"71959545":{"m":113,"g":115},"24f7cb1e":{"m":113,"g":115},"e05555fa":{"m":113,"g":115},"43fa9f22":{"m":113,"g":115},"e98d9346":{"m":113,"g":115},"0c917410":{"m":113,"g":115},"25728863":{"m":113,"g":115},"dba751a8":{"m":113,"g":115},"2e763398":{"m":113,"g":115},"336e9a60":{"m":113,"g":115},"abb67815":{"m":113,"g":115},"07440f5f":{"m":113,"g":115},"9816989b":{"m":113,"g":115},"42245551":{"m":113,"g":115},"2a9d995c":{"m":113,"g":115},"a9050b5c":{"m":113,"g":115},"66face35":{"m":113,"g":115},"5519766a":{"m":113,"g":115},"72392f29":{"m":113,"g":115},"c1c8dd1d":{"m":113,"g":115},"f6bc3f52":{"m":113,"g":115},"8cc27fdc":{"m":113,"g":115},"9c339d6b":{"m":113,"g":115},"e23e280e":{"m":113,"g":115},"51f7c6bd":{"m":113,"g":115},"62e2e99d":{"m":113,"g":115},"8ebf72fe":{"m":113,"g":115},"82605747":{"m":113,"g":115},"37f3325b":{"m":113,"g":115},"bd95944c":{"m":113,"g":115},"c8a5d12a":{"m":113,"g":115},"2387c22b":{"m":113,"g":115},"592ddf37":{"m":113,"g":115},"0c3db889":{"m":113,"g":115},"2bdaf482":{"m":113,"g":115},"777eb538":{"m":113,"g":115},"05a35266":{"m":113,"g":115},"e56c64bf":{"m":113,"g":115},"fff7fbab":{"m":113,"g":115},"aae7ead2":{"m":113,"g":115},"a7fe6e10":{"m":113,"g":115},"be059b83":{"m":113,"g":115},"5d4fe1ce":{"m":113,"g":115},"1b011e68":{"m":113,"g":115},"5c0efa56":{"m":113,"g":115},"1e57b947":{"m":113,"g":115},"a5095d62":{"m":113,"g":115},"6c2c467d":{"m":113,"g":115},"c3d2ad4e":{"m":113,"g":115},"7ec5b4e8":{"m":113,"g":115},"60885482":{"m":113,"g":115},"172bcf01":{"m":113,"g":115},"37158f20":{"m":113,"g":115},"3e95aa1a":{"m":113,"g":115},"c4197e99":{"m":113,"g":115},"0ac61146":{"m":113,"g":115},"7dcd689b":{"m":113,"g":115},"f7bab41a":{"m":113,"g":115},"f68dd998":{"m":113,"g":115},"35ec2a45":{"m":113,"g":115},"0035f1ce":{"m":113,"g":115},"5e21d6ae":{"m":113,"g":115},"cd4da1f1":{"m":113,"g":115},"91678474":{"m":113,"g":115},"d511b2d9":{"m":113,"g":115},"77830a26":{"m":113,"g":115},"fce17048":{"m":113,"g":115},"3d40794f":{"m":113,"g":115},"c1f39013":{"m":113,"g":115},"3e43eb13":{"m":113,"g":115},"458c0219":{"m":113,"g":115},"a73eb8cd":{"m":113,"g":115},"e7387035":{"m":113,"g":115},"fe531d6f":{"m":113,"g":115},"c4e314f9":{"m":113,"g":115},"7a06ef98":{"m":113,"g":115},"4a87ba21":{"m":113,"g":115},"d7b20dd6":{"m":113,"g":115},"c3faf2d6":{"m":113,"g":115},"9209b209":{"m":113,"g":115},"adba172f":{"m":113,"g":115},"cd641a99":{"m":113,"g":115},"71f24ef8":{"m":113,"g":115},"b1f0fc1c":{"m":113,"g":115},"32d89373":{"m":113,"g":115},"f47a2c67":{"m":113,"g":115},"ee704e62":{"m":113,"g":115},"f4e3ebeb":{"m":113,"g":115},"312bfc4c":{"m":113,"g":115},"e290303e":{"m":113,"g":115},"aab35bcc":{"m":113,"g":115},"42aedb02":{"m":113,"g":115},"984730b7":{"m":113,"g":115},"23632d35":{"m":113,"g":115},"08b8c0c3":{"m":113,"g":115},"d42975c6":{"m":113,"g":115},"adc24a3a":{"m":113,"g":115},"7ff93e61":{"m":113,"g":115},"b24b2e7e":{"m":113,"g":115},"7135db5d":{"m":113,"g":115},"4b5ef300":{"m":113,"g":115},"4f564b9e":{"m":113,"g":115},"98c3b04f":{"m":113,"g":115},"ddab4fc7":{"m":113,"g":115},"d21c3522":{"m":113,"g":115},"4a762041":{"m":113,"g":115},"ea338676":{"m":113,"g":115},"b06db198":{"m":113,"g":115},"8c1ef0f9":{"m":113,"g":115},"f5a2faf2":{"m":113,"g":115},"1c82d9db":{"m":113,"g":115},"9241f4fd":{"m":113,"g":115},"063c3791":{"m":113,"g":115},"632b7d8c":{"m":113,"g":115},"16adf3dc":{"m":113,"g":115},"c3a1d775":{"m":113,"g":115},"89971c4c":{"m":113,"g":115},"113f8f65":{"m":113,"g":115},"e22f3a5e":{"m":113,"g":115},"095093ee":{"m":113,"g":115},"d27a6f70":{"m":113,"g":115},"0753ef83":{"m":113,"g":115},"662393f2":{"m":113,"g":115},"b1bb8e74":{"m":113,"g":115},"38c00ed7":{"m":113,"g":115},"d4041a5e":{"m":113,"g":115},"2f555c4c":{"m":113,"g":115},"e53df7c0":{"m":113,"g":115},"9c53dad8":{"m":113,"g":115},"7ca1bea6":{"m":113,"g":115},"97c38239":{"m":113,"g":115},"60dbbd08":{"m":113,"g":115},"aa1c5cf5":{"m":113,"g":115},"592caab6":{"m":113,"g":115},"2101d93b":{"m":113,"g":115},"70e4b218":{"m":113,"g":115},"944f1ea0":{"m":113,"g":115},"9d7e82a0":{"m":113,"g":115},"f0580551":{"m":113,"g":115},"635ccda6":{"m":113,"g":115},"1c3dbad8":{"m":113,"g":115},"e2ac7888":{"m":113,"g":115},"86527a47":{"m":113,"g":115},"134b4f7e":{"m":113,"g":115},"f67d1f45":{"m":113,"g":115},"0f04a5f4":{"m":113,"g":115},"2f18602f":{"m":113,"g":115},"56321e9f":{"m":113,"g":115},"12d6cf18":{"m":113,"g":115},"fc3e5420":{"m":113,"g":115},"08ecd0aa":{"m":113,"g":115},"720c1c8c":{"m":113,"g":115},"d403c143":{"m":113,"g":115},"cba0d8c3":{"m":113,"g":115},"f1d78923":{"m":113,"g":115},"7c876de7":{"m":113,"g":115},"ba94b829":{"m":113,"g":115},"2b7417bf":{"m":113,"g":115},"f1116495":{"m":113,"g":115},"bd7eb020":{"m":113,"g":115},"74cd6e39":{"m":113,"g":115},"b17e67df":{"m":113,"g":115},"8ecef73f":{"m":113,"g":115},"1d1ce624":{"m":113,"g":115},"60e2a7ce":{"m":113,"g":115},"d88ef4a3":{"m":113,"g":115},"6f993e8b":{"m":113,"g":115},"03ce92e5":{"m":113,"g":115},"00eb5eb7":{"m":113,"g":115},"dab4663b":{"m":113,"g":115},"610a6d6e":{"m":113,"g":115},"36efd5be":{"m":113,"g":115},"68cdc189":{"m":113,"g":115},"7f399e4b":{"m":113,"g":115},"873d858b":{"m":113,"g":115},"3fa3c22a":{"m":113,"g":115},"4f2055ad":{"m":113,"g":115},"616a3e20":{"m":113,"g":115},"ac2a723b":{"m":113,"g":115},"56b991b1":{"m":113,"g":115},"780d6a22":{"m":113,"g":115},"8b713c72":{"m":113,"g":115},"5bfafdfc":{"m":113,"g":115},"8c52de6f":{"m":113,"g":115},"c1815a99":{"m":113,"g":115},"4e6c4923":{"m":113,"g":115},"b91cb67e":{"m":113,"g":115},"e7bc6003":{"m":113,"g":115},"2a2ff9a8":{"m":113,"g":115},"5291f32d":{"m":113,"g":115},"67073dde":{"m":113,"g":115},"9a5c42f9":{"m":113,"g":115},"388c05d5":{"m":113,"g":115},"fc809665":{"m":113,"g":115},"6fd4816d":{"m":113,"g":115},"1344ebc8":{"m":113,"g":115},"e07b21ce":{"m":113,"g":115},"52f248cd":{"m":113,"g":115},"93f75778":{"m":113,"g":115},"4039c626":{"m":113,"g":115},"db71c38f":{"m":113,"g":115},"7a68b422":{"m":113,"g":115},"60fc5b51":{"m":113,"g":115},"a13dd1e4":{"m":113,"g":115},"d500eb91":{"m":113,"g":115},"1ccd59c7":{"m":113,"g":115},"c32fb7a2":{"m":113,"g":115},"1ba137e9":{"m":113,"g":115},"de28f8e7":{"m":113,"g":115},"56405076":{"m":113,"g":115},"b73ac629":{"m":113,"g":115},"77098aea":{"m":113,"g":115},"5ccf0b03":{"m":113,"g":115},"a77564e0":{"m":113,"g":115},"4f9e71df":{"m":113,"g":115},"541551ce":{"m":113,"g":115},"124097fc":{"m":113,"g":115},"e1d45bc2":{"m":113,"g":115},"14fdd527":{"m":113,"g":115},"f949ad57":{"m":113,"g":115},"c49484a6":{"m":113,"g":115},"a2f7218a":{"m":113,"g":115},"311de47b":{"m":113,"g":115},"373080ea":{"m":113,"g":115},"7f028b07":{"m":113,"g":115},"0abb41c7":{"m":113,"g":115},"925dbb32":{"m":113,"g":115},"8df7353a":{"m":113,"g":115},"ae4be601":{"m":113,"g":115},"9b876889":{"m":113,"g":115},"c0c6f543":{"m":113,"g":115},"edd6a07b":{"m":113,"g":115},"b6dd4bcb":{"m":113,"g":115},"b2435be6":{"m":113,"g":115},"5fe39e85":{"m":113,"g":115},"fa5d0bf6":{"m":113,"g":115},"16e93359":{"m":113,"g":115},"f1c692f6":{"m":113,"g":115},"80572c83":{"m":113,"g":115},"4bb08f6e":{"m":113,"g":115},"ec272dda":{"m":113,"g":115},"a220c14f":{"m":113,"g":115},"35ef3f29":{"m":113,"g":115},"31fb19a0":{"m":113,"g":115},"3f41b48c":{"m":113,"g":115},"2689f0bf":{"m":113,"g":115},"52074240":{"m":113,"g":115},"c3c26f76":{"m":113,"g":115},"2cf811a9":{"m":113,"g":115},"3b25dc12":{"m":113,"g":115},"5c08d7d2":{"m":113,"g":115},"a45d9a4e":{"m":113,"g":115},"28c79dc8":{"m":113,"g":115},"1fcccda4":{"m":113,"g":115},"79acec4f":{"m":113,"g":115},"b1721edb":{"m":113,"g":115},"57234d0c":{"m":113,"g":115},"b93acd70":{"m":113,"g":115},"86a32bb5":{"m":113,"g":115},"5afd0365":{"m":113,"g":115},"059c13de":{"m":113,"g":115},"50dc0c1e":{"m":113,"g":115},"76becc1d":{"m":113,"g":115},"2a37b24d":{"m":113,"g":115},"f73aae0b":{"m":113,"g":115},"69b35793":{"m":113,"g":115},"957482c8":{"m":113,"g":115},"3795b6a4":{"m":113,"g":115},"7eccbe99":{"m":113,"g":115},"0549f21c":{"m":113,"g":115},"b354e3c9":{"m":113,"g":115},"65e6f48c":{"m":113,"g":115},"0ec580a8":{"m":113,"g":115},"0b14159f":{"m":113,"g":115},"1489cd6c":{"m":113,"g":115},"fc2c3a3d":{"m":113,"g":115},"8f6a1758":{"m":113,"g":115},"01018138":{"m":113,"g":115},"4844fac9":{"m":113,"g":115},"b7d385e8":{"m":113,"g":115},"305c9e8c":{"m":113,"g":115},"ca63f075":{"m":113,"g":115},"f9ee6ae1":{"m":113,"g":115},"dcee42c2":{"m":113,"g":115},"258d02c8":{"m":113,"g":115},"60d7beda":{"m":113,"g":115},"2f8ba6fe":{"m":113,"g":115},"7ce6c10e":{"m":113,"g":115},"55025b92":{"m":113,"g":115},"4c21b090":{"m":113,"g":115},"165abeeb":{"m":113,"g":115},"21ca4c3a":{"m":113,"g":115},"e3cf812f":{"m":113,"g":115},"4da55336":{"m":113,"g":115},"ac964d2e":{"m":113,"g":115},"fa46e2bd":{"m":113,"g":115},"b047b553":{"m":113,"g":115},"a0f844ed":{"m":113,"g":115},"2df532ef":{"m":113,"g":115},"abea9250":{"m":113,"g":115},"b3c97762":{"m":113,"g":115},"b8347b40":{"m":113,"g":115},"72dfa96a":{"m":113,"g":115},"05b01ef4":{"m":113,"g":115},"55a6e644":{"m":113,"g":115},"6897e06b":{"m":113,"g":115},"a360511d":{"m":113,"g":115},"94d0f656":{"m":113,"g":115},"eca59f96":{"m":113,"g":115},"97528610":{"m":113,"g":115},"297d3745":{"m":113,"g":115},"31e9d3a5":{"m":113,"g":115},"6f4676ef":{"m":113,"g":115},"c9ec4cae":{"m":113,"g":115},"99757cc3":{"m":113,"g":115},"cdddab05":{"m":113,"g":115},"7c5a0a1b":{"m":113,"g":115},"49f169d5":{"m":113,"g":115},"7fce2fd9":{"m":113,"g":115},"16cd550c":{"m":113,"g":115},"d5e2a374":{"m":113,"g":115},"366043db":{"m":113,"g":115},"2f173ea0":{"m":113,"g":115},"321fecab":{"m":113,"g":115},"9d775b1a":{"m":113,"g":115},"78b7465c":{"m":113,"g":115},"07bcad7f":{"m":113,"g":115},"98adac8e":{"m":113,"g":115},"cef11e9a":{"m":113,"g":115},"2269cf1e":{"m":113,"g":115},"151e287d":{"m":113,"g":115},"8c86595c":{"m":113,"g":115},"4634fd59":{"m":113,"g":115},"efedbe6c":{"m":113,"g":115},"3a77c80b":{"m":113,"g":115},"36acd2ff":{"m":113,"g":115},"fe6cdf89":{"m":113,"g":115},"30d20ce8":{"m":113,"g":115},"1b1701f1":{"m":113,"g":115},"6d403089":{"m":113,"g":115},"24dc2bee":{"m":113,"g":115},"fac07c9b":{"m":113,"g":115},"b3839a7f":{"m":113,"g":115},"4aa39d72":{"m":113,"g":115},"b4c2c421":{"m":113,"g":115},"53ca1552":{"m":113,"g":115},"a23bdeaf":{"m":113,"g":115},"27778010":{"m":113,"g":115},"46d8fb1c":{"m":113,"g":115},"c7e85f53":{"m":113,"g":115},"3df05f4d":{"m":113,"g":115},"7b141f81":{"m":113,"g":115},"7bc5fb0d":{"m":113,"g":115},"144ee5f3":{"m":113,"g":115},"758b887a":{"m":114,"g":115},"eb7d9261":{"m":114,"g":115},"44cb0607":{"m":114,"g":115},"88bb627d":{"m":114,"g":115},"b520958e":{"m":114,"g":115},"fa7e2c30":{"m":114,"g":115},"8f2cd177":{"m":114,"g":115},"ab926dd6":{"m":114,"g":115},"a4b424c6":{"m":114,"g":115},"a0557642":{"m":114,"g":115},"84768d10":{"m":114,"g":115},"368fd206":{"m":114,"g":115},"53bd00d9":{"m":114,"g":115},"e22b13c5":{"m":114,"g":115},"a3c2ea44":{"m":114,"g":115},"fccac7d1":{"m":114,"g":115},"7ac6b900":{"m":114,"g":115},"a1080b72":{"m":114,"g":115},"a65ca739":{"m":114,"g":115},"677aa0e2":{"m":114,"g":115},"01c9ee1a":{"m":114,"g":115},"d6837aea":{"m":114,"g":115},"c882b5ae":{"m":114,"g":115},"e3bb7f5a":{"m":114,"g":115},"92473e2e":{"m":114,"g":115},"6c0bb327":{"m":114,"g":115},"0a7c4bde":{"m":114,"g":115},"edefab0c":{"m":114,"g":115},"97cd38e5":{"m":114,"g":115},"3c06b673":{"m":114,"g":115},"7c3f07db":{"m":114,"g":115},"edd86b88":{"m":114,"g":115},"4b4dc132":{"m":114,"g":115},"5a9170d9":{"m":114,"g":115},"c4d77774":{"m":114,"g":115},"832c84fb":{"m":114,"g":115},"64d1505c":{"m":114,"g":115},"f3764c26":{"m":114,"g":115},"7ba3de0e":{"m":114,"g":115},"fde9b963":{"m":114,"g":115},"f094e0a4":{"m":114,"g":115},"4ed67c27":{"m":114,"g":115},"cd4b39a9":{"m":114,"g":115},"420c99ac":{"m":114,"g":115},"e3c7f091":{"m":114,"g":115},"6f1e03a4":{"m":114,"g":115},"f4affd4d":{"m":114,"g":115},"df08bf9b":{"m":114,"g":115},"69efdd27":{"m":114,"g":115},"64582caa":{"m":114,"g":115},"2fcd56ea":{"m":114,"g":115},"0958a397":{"m":114,"g":115},"4f42c8cd":{"m":114,"g":115},"3ddd7dc9":{"m":114,"g":115},"501dfa6b":{"m":114,"g":115},"79d34951":{"m":114,"g":115},"1519a89c":{"m":114,"g":115},"24bc3fb0":{"m":114,"g":115},"8a8a608a":{"m":114,"g":115},"533e58a1":{"m":114,"g":115},"9b4c4497":{"m":114,"g":115},"a578d300":{"m":114,"g":115},"8c967037":{"m":114,"g":115},"fb27d383":{"m":114,"g":115},"fd8a0b29":{"m":114,"g":115},"afc35ccc":{"m":114,"g":115},"a57f0e3d":{"m":114,"g":115},"708f4ff4":{"m":114,"g":115},"e2daeb35":{"m":114,"g":115},"0e7b3530":{"m":114,"g":115},"b07c9c76":{"m":114,"g":115},"748f86f3":{"m":114,"g":115},"73ea484a":{"m":114,"g":115},"4aeb193f":{"m":114,"g":115},"466992b2":{"m":114,"g":115},"155cbb51":{"m":114,"g":115},"eb30b888":{"m":114,"g":115},"5ee777c9":{"m":114,"g":115},"baf277a9":{"m":116,"g":118},"f5d30dae":{"m":116,"g":118},"2479b894":{"m":116,"g":118},"54644572":{"m":116,"g":118},"6c01844f":{"m":116,"g":118},"f226d3da":{"m":116,"g":118},"d2478cd4":{"m":116,"g":118},"30ea4c46":{"m":116,"g":118},"6d036468":{"m":116,"g":118},"8221f9ae":{"m":116,"g":118},"ab9187a2":{"m":116,"g":118},"6b143d62":{"m":116,"g":118},"6bc503af":{"m":116,"g":118},"b2c85669":{"m":116,"g":118},"32803fb2":{"m":116,"g":118},"91fc5bb5":{"m":116,"g":118},"780fbf2f":{"m":116,"g":118},"825432fc":{"m":116,"g":118},"a40229f6":{"m":116,"g":118},"74737b28":{"m":116,"g":115},"40e0082d":{"m":116,"g":115},"e9e120ac":{"m":116,"g":115},"e0c2af2a":{"m":116,"g":115},"1d7f7835":{"m":116,"g":115},"32595146":{"m":116,"g":115},"86373b9e":{"m":116,"g":115},"d314bf60":{"m":116,"g":115},"e28c9e52":{"m":116,"g":115},"b98cf398":{"m":116,"g":115},"27d71045":{"m":116,"g":115},"c224a4c6":{"m":116,"g":115},"49345a68":{"m":116,"g":115},"94d26d85":{"m":116,"g":115},"9e8a15a7":{"m":116,"g":115},"3962e39d":{"m":116,"g":115},"eb8cac6f":{"m":116,"g":115},"5ea96ac7":{"m":116,"g":115},"56222658":{"m":116,"g":115},"dc965db0":{"m":116,"g":115},"817e46f4":{"m":116,"g":115},"5a33c3aa":{"m":116,"g":115},"9767a1e4":{"m":116,"g":115},"1d086539":{"m":116,"g":115},"a04efc49":{"m":116,"g":115},"642fa966":{"m":116,"g":115},"da7fac1b":{"m":116,"g":115},"28ad2297":{"m":116,"g":115},"f7f9f8ec":{"m":116,"g":115},"4b62af92":{"m":116,"g":115},"0b9915c1":{"m":116,"g":115},"27ef1459":{"m":116,"g":115},"e4358a45":{"m":116,"g":115},"ba2ce28f":{"m":116,"g":115},"98923880":{"m":116,"g":115},"f792e3c5":{"m":116,"g":115},"28f80b12":{"m":116,"g":115},"88a6f9da":{"m":116,"g":115},"cb8ed2c0":{"m":116,"g":115},"38473363":{"m":116,"g":115},"aaf7af1b":{"m":116,"g":115},"932e2637":{"m":116,"g":115},"43f80884":{"m":116,"g":115},"60b05032":{"m":116,"g":115},"dc48c4c0":{"m":116,"g":115},"6dc9ca8c":{"m":116,"g":115},"887c2b45":{"m":116,"g":115},"065ce815":{"m":116,"g":115},"8e51049f":{"m":116,"g":115},"cb8f3d90":{"m":116,"g":115},"4b694e7d":{"m":116,"g":115},"9f1f699a":{"m":116,"g":115},"c9cff2b9":{"m":116,"g":115},"b6fb5d76":{"m":116,"g":115},"f4aa7880":{"m":116,"g":115},"5e3f7e7f":{"m":116,"g":115},"728af887":{"m":116,"g":115},"7b59b0b8":{"m":116,"g":115},"acc2327b":{"m":116,"g":115},"bfadb5ea":{"m":116,"g":115},"9cc1e065":{"m":116,"g":115},"b8c430f1":{"m":116,"g":115},"f35f120d":{"m":116,"g":115},"54a46a26":{"m":116,"g":115},"7c94eaee":{"m":116,"g":115},"13d596c9":{"m":116,"g":115},"c7867b67":{"m":116,"g":115},"516738b0":{"m":116,"g":115},"0b6f535f":{"m":116,"g":115},"c5fe3c0b":{"m":116,"g":115},"318424e2":{"m":116,"g":115},"6806c4e6":{"m":116,"g":115},"0c0779d6":{"m":116,"g":115},"a55cf530":{"m":116,"g":115},"19ba16aa":{"m":116,"g":115},"a2b3d9b9":{"m":116,"g":115},"9a30914e":{"m":116,"g":115},"8e776c78":{"m":116,"g":115},"63e84352":{"m":116,"g":115},"a20e7df8":{"m":116,"g":115},"1bdd0102":{"m":116,"g":115},"6cd29694":{"m":116,"g":115},"2ac46e94":{"m":116,"g":115},"0aa65f94":{"m":116,"g":115},"0ecb4261":{"m":116,"g":115},"05f015f6":{"m":116,"g":115},"1083e7e3":{"m":116,"g":115},"2157d12a":{"m":116,"g":115},"9f2b457c":{"m":116,"g":115},"f5b34a51":{"m":116,"g":115},"5a6ec8f9":{"m":116,"g":115},"6a653bb1":{"m":116,"g":115},"548a57b1":{"m":116,"g":115},"88e73ed0":{"m":116,"g":115},"4b15fa00":{"m":116,"g":115},"f4941906":{"m":116,"g":115},"01e59e82":{"m":116,"g":115},"99a0704a":{"m":116,"g":115},"ec1cd90a":{"m":116,"g":115},"1103dc62":{"m":116,"g":115},"a220536f":{"m":116,"g":115},"7b064f04":{"m":116,"g":115},"43190bec":{"m":116,"g":115},"be740acd":{"m":116,"g":115},"2db2cddd":{"m":116,"g":115},"9b5efe34":{"m":116,"g":115},"4ac8e09d":{"m":116,"g":115},"20a6c0a6":{"m":116,"g":115},"47c606d3":{"m":116,"g":115},"9fcf7306":{"m":116,"g":115},"0a304870":{"m":116,"g":115},"8fdcd98e":{"m":116,"g":115},"b5dcfd41":{"m":116,"g":115},"5061b8fd":{"m":116,"g":115},"c8452551":{"m":116,"g":115},"bf3e7149":{"m":116,"g":115},"f5754d12":{"m":116,"g":115},"739daa63":{"m":116,"g":115},"d957177a":{"m":116,"g":115},"21337b22":{"m":116,"g":115},"129d2992":{"m":116,"g":115},"8b85926a":{"m":116,"g":115},"451d15c4":{"m":116,"g":115},"c80a96da":{"m":116,"g":115},"eae9a9fb":{"m":116,"g":115},"2674c1d2":{"m":116,"g":115},"61055cb3":{"m":116,"g":115},"92777135":{"m":116,"g":115},"c4958331":{"m":116,"g":115},"2eeb2751":{"m":116,"g":115},"b36afed4":{"m":116,"g":115},"9aa4502d":{"m":116,"g":115},"a0835c3a":{"m":116,"g":115},"55b14656":{"m":116,"g":115},"b4408e60":{"m":116,"g":115},"52fcbbb8":{"m":116,"g":115},"af96ca11":{"m":116,"g":115},"9082a7d3":{"m":116,"g":115},"3b9d97f3":{"m":116,"g":115},"a1a20b4c":{"m":116,"g":115},"4299aebd":{"m":116,"g":115},"0babd487":{"m":116,"g":115},"f19613e6":{"m":116,"g":115},"8df49455":{"m":116,"g":115},"ee3bd8a1":{"m":116,"g":115},"d8467db7":{"m":116,"g":115},"b5044fbf":{"m":116,"g":115},"70fbb3ad":{"m":116,"g":115},"9a7e7a65":{"m":116,"g":115},"0fe87213":{"m":116,"g":115},"1f106ee3":{"m":116,"g":115},"9b8ebb27":{"m":116,"g":115},"85ebeecf":{"m":117,"g":118},"0dd6cf16":{"m":117,"g":118},"0975ba99":{"m":117,"g":118},"1de3924b":{"m":117,"g":118},"3cceaa38":{"m":117,"g":118},"b0d20cde":{"m":117,"g":118},"cbac4997":{"m":117,"g":118},"476c67d7":{"m":117,"g":118},"3289da5b":{"m":117,"g":118},"868403f6":{"m":117,"g":118},"97d857c0":{"m":117,"g":118},"52a54a26":{"m":117,"g":118},"cd7e1bd5":{"m":117,"g":118},"729b7edf":{"m":117,"g":118},"4c03dbaa":{"m":117,"g":118},"1053e1be":{"m":119,"g":121},"9a71500c":{"m":119,"g":121},"6d6e24bc":{"m":119,"g":121},"2c057fbf":{"m":119,"g":121},"dbd9435d":{"m":119,"g":121},"8ae9d4bb":{"m":119,"g":121},"1c304aa9":{"m":119,"g":121},"770529a7":{"m":119,"g":121},"39c237f0":{"m":119,"g":121},"28b8a406":{"m":119,"g":121},"8bd26dd4":{"m":119,"g":121},"ab07cd3e":{"m":119,"g":121},"a9849683":{"m":119,"g":121},"a4b637d8":{"m":119,"g":121},"96a5e4dd":{"m":119,"g":121},"b0b4f716":{"m":119,"g":121},"6c18addb":{"m":119,"g":121},"32852fe9":{"m":119,"g":121},"53c2934d":{"m":119,"g":121},"e321c971":{"m":119,"g":121},"d6fee73d":{"m":119,"g":121},"36a4cad7":{"m":119,"g":121},"65d376b4":{"m":119,"g":121},"c23eda85":{"m":119,"g":121},"138ff231":{"m":119,"g":121},"13fb8b54":{"m":119,"g":121},"81fd2b0e":{"m":119,"g":121},"007b849b":{"m":119,"g":121},"8612811d":{"m":119,"g":121},"e7aa4664":{"m":119,"g":121},"4d4feccb":{"m":119,"g":121},"99c92ff2":{"m":119,"g":121},"6ade6a02":{"m":119,"g":121},"983ef22c":{"m":119,"g":121},"164302c7":{"m":119,"g":121},"5dccf697":{"m":119,"g":121},"eec9e471":{"m":119,"g":121},"6d535b71":{"m":119,"g":121},"fdcb1d13":{"m":119,"g":121},"d7e834d6":{"m":119,"g":121},"200a3c0b":{"m":119,"g":121},"77258ce0":{"m":119,"g":121},"1d097aac":{"m":119,"g":121},"7fceeef5":{"m":119,"g":121},"88568c01":{"m":119,"g":121},"904655c5":{"m":119,"g":121},"e028af69":{"m":119,"g":121},"80b2b320":{"m":119,"g":121},"4b65ed42":{"m":119,"g":121},"23afdfd1":{"m":119,"g":121},"9d61205d":{"m":119,"g":121},"590bc4b7":{"m":119,"g":121},"63cfe1b0":{"m":119,"g":121},"70f6309c":{"m":119,"g":121},"70416001":{"m":119,"g":121},"87a92e45":{"m":119,"g":121},"c461e771":{"m":119,"g":121},"fde2decf":{"m":119,"g":121},"9792b9d7":{"m":119,"g":121},"ef4a8097":{"m":119,"g":121},"ebff4ee6":{"m":119,"g":121},"2b1da821":{"m":119,"g":121},"97710ccd":{"m":119,"g":121},"f3cd5d25":{"m":119,"g":121},"c61b0b29":{"m":119,"g":121},"e8640ee9":{"m":119,"g":121},"d0a64c7e":{"m":119,"g":121},"05d3667a":{"m":119,"g":121},"260fe755":{"m":119,"g":121},"dbb16bed":{"m":119,"g":121},"c1e16003":{"m":119,"g":121},"852c0578":{"m":119,"g":121},"7e6191c0":{"m":119,"g":121},"6f9b66bd":{"m":119,"g":121},"8a801ee3":{"m":119,"g":118},"d9a20fd2":{"m":119,"g":118},"b113c72e":{"m":119,"g":118},"fb6cc7b0":{"m":119,"g":118},"8374a96e":{"m":119,"g":118},"74de76c6":{"m":119,"g":118},"9c0b1eb5":{"m":119,"g":118},"01f14a7a":{"m":119,"g":118},"11110303":{"m":119,"g":118},"28ddfb37":{"m":119,"g":118},"e69094df":{"m":119,"g":118},"43ad0590":{"m":119,"g":118},"b4948512":{"m":119,"g":118},"ddcba74b":{"m":119,"g":118},"0917c5da":{"m":119,"g":118},"184a4df6":{"m":119,"g":118},"f7b1d8c5":{"m":119,"g":118},"bfc3b3f7":{"m":119,"g":118},"da5bde4d":{"m":119,"g":118},"276e7b3e":{"m":119,"g":118},"296f6892":{"m":119,"g":118},"9edb7b51":{"m":119,"g":118},"e53bf442":{"m":119,"g":118},"d383e661":{"m":119,"g":118},"984fbeb1":{"m":119,"g":118},"a2ba0bc3":{"m":119,"g":118},"6d2d0ce2":{"m":119,"g":118},"271d3d0d":{"m":119,"g":118},"c4e81e64":{"m":119,"g":118},"c726d44c":{"m":119,"g":118},"283c8ba0":{"m":119,"g":118},"cae39565":{"m":119,"g":118},"27a223ab":{"m":119,"g":118},"53529f46":{"m":119,"g":118},"24ed3f32":{"m":119,"g":118},"44f0ece9":{"m":119,"g":118},"be0058bc":{"m":119,"g":118},"9e3be1fa":{"m":119,"g":118},"a8ba3279":{"m":119,"g":118},"3b80232d":{"m":119,"g":118},"252dc4e1":{"m":119,"g":118},"cbb5fc2e":{"m":119,"g":118},"53fb229f":{"m":119,"g":118},"4fff1ec1":{"m":119,"g":118},"7a020e0f":{"m":119,"g":118},"48738af7":{"m":119,"g":118},"efa47334":{"m":119,"g":118},"d658f049":{"m":119,"g":118},"57e25de7":{"m":119,"g":118},"12eb02e9":{"m":119,"g":118},"002d0373":{"m":119,"g":118},"a27825ae":{"m":119,"g":118},"ce399e15":{"m":119,"g":118},"ea6275df":{"m":119,"g":118},"eb7318f1":{"m":119,"g":118},"6058fb52":{"m":119,"g":118},"80407b04":{"m":119,"g":118},"b288f4f4":{"m":119,"g":118},"6d6ea5af":{"m":119,"g":118},"1dacedd2":{"m":119,"g":118},"b5e14b2b":{"m":119,"g":118},"d513ee93":{"m":119,"g":118},"a7ae61ed":{"m":119,"g":118},"fda0cb2a":{"m":119,"g":118},"ebda73dc":{"m":119,"g":118},"f4f8a1b4":{"m":119,"g":118},"c44e985d":{"m":119,"g":118},"f9a7d9b3":{"m":119,"g":118},"a93f10a7":{"m":119,"g":118},"585e1223":{"m":119,"g":118},"a7043c6f":{"m":119,"g":118},"67e34c56":{"m":119,"g":118},"1d726528":{"m":119,"g":118},"f4488e9d":{"m":119,"g":118},"e68a2b5b":{"m":119,"g":118},"31b9f19e":{"m":119,"g":118},"547003bd":{"m":119,"g":118},"f7ab9554":{"m":119,"g":118},"dbbd4e18":{"m":119,"g":118},"ca240eef":{"m":119,"g":118},"6c7c92eb":{"m":119,"g":118},"5b214b50":{"m":119,"g":118},"13219e1e":{"m":119,"g":118},"33e9bbec":{"m":119,"g":118},"dcb8f090":{"m":119,"g":118},"9eefe2c0":{"m":119,"g":118},"69fe3c97":{"m":119,"g":118},"8af84912":{"m":119,"g":118},"505329ca":{"m":119,"g":118},"8a382fd3":{"m":119,"g":118},"62797440":{"m":119,"g":118},"2614adf9":{"m":119,"g":118},"fdd7c69d":{"m":119,"g":118},"b9a54e09":{"m":119,"g":118},"20b8d230":{"m":119,"g":118},"d1984e21":{"m":119,"g":118},"b79f75fd":{"m":119,"g":118},"8fcc69e7":{"m":119,"g":118},"f440baa1":{"m":119,"g":118},"2bc3fcd4":{"m":119,"g":118},"a5978a20":{"m":119,"g":118},"e483c1ea":{"m":119,"g":118},"da681f35":{"m":119,"g":118},"9b0f725b":{"m":119,"g":118},"cde5a6e3":{"m":119,"g":118},"3e4c7da2":{"m":119,"g":118},"d88ac9bc":{"m":119,"g":118},"ce11dd82":{"m":119,"g":118},"9e87b60f":{"m":119,"g":118},"7780230a":{"m":119,"g":118},"dc01313d":{"m":119,"g":118},"7a7f99be":{"m":119,"g":118},"fd389df9":{"m":119,"g":118},"b0d1d717":{"m":119,"g":118},"c7962868":{"m":119,"g":118},"4f24ab17":{"m":119,"g":118},"64affab4":{"m":119,"g":118},"4c9bcb9d":{"m":119,"g":118},"86b04d25":{"m":119,"g":118},"55d75e11":{"m":120,"g":121},"3f4cc0af":{"m":120,"g":121},"cadfae66":{"m":120,"g":121},"da1766e4":{"m":120,"g":121},"a124b517":{"m":120,"g":121},"d05a968b":{"m":120,"g":121},"94aad0de":{"m":120,"g":121},"7ebc28f5":{"m":120,"g":121},"b89111d6":{"m":120,"g":121},"0b3b3e9a":{"m":120,"g":121},"a1d5bc4c":{"m":120,"g":121},"a8023891":{"m":120,"g":121},"0103f374":{"m":120,"g":121},"96a5a949":{"m":120,"g":121},"ea385ae8":{"m":120,"g":121},"9e949e58":{"m":120,"g":121},"6dbb569b":{"m":120,"g":121},"5994e6c3":{"m":120,"g":121},"3e6281d0":{"m":120,"g":121},"6371f7af":{"m":120,"g":121},"8491c794":{"m":120,"g":121},"bda3758f":{"m":120,"g":121},"7b36c47b":{"m":120,"g":121},"773d89da":{"m":120,"g":121},"03e7d949":{"m":120,"g":121},"ff604064":{"m":120,"g":121},"212f5e48":{"m":120,"g":121},"fe527812":{"m":120,"g":121},"97828878":{"m":120,"g":121},"c001deba":{"m":120,"g":121},"b4d2da10":{"m":120,"g":121},"b72f9f08":{"m":120,"g":121},"8e70064c":{"m":120,"g":121},"d98b81e2":{"m":120,"g":121},"bcecf27e":{"m":120,"g":121},"4b0ac1d5":{"m":120,"g":121},"8e987fa2":{"m":120,"g":121},"9e656dd3":{"m":120,"g":121},"3862661c":{"m":120,"g":121},"c8492978":{"m":120,"g":121},"428710c2":{"m":120,"g":121},"d9b31011":{"m":120,"g":121},"d0cff78f":{"m":120,"g":121},"e8b71445":{"m":120,"g":121},"4caca1ba":{"m":120,"g":121},"ceb105a7":{"m":120,"g":121},"22cbc9c0":{"m":120,"g":121},"3865afc5":{"m":120,"g":121},"4ea42f7c":{"m":120,"g":121},"ea13cb14":{"m":120,"g":121},"a04212f1":{"m":120,"g":121},"ce869793":{"m":120,"g":121},"22f55e1b":{"m":120,"g":121},"89824189":{"m":120,"g":121},"433c622e":{"m":120,"g":121},"20bd2271":{"m":120,"g":121},"64994980":{"m":120,"g":121},"729b2429":{"m":120,"g":121},"d7056c52":{"m":120,"g":121},"13bf565d":{"m":120,"g":121},"e51046be":{"m":120,"g":121},"4eeeae1e":{"m":120,"g":121},"f4b78d13":{"m":120,"g":121},"4463e90d":{"m":120,"g":121},"229f236d":{"m":120,"g":121},"5983e5bd":{"m":120,"g":121},"4b046a72":{"m":120,"g":121},"770d6312":{"m":120,"g":121},"14203432":{"m":120,"g":121},"d7f0d88f":{"m":120,"g":121},"fc86b18b":{"m":120,"g":121},"0bfa394a":{"m":120,"g":121},"e04340bf":{"m":120,"g":121},"84701338":{"m":120,"g":121},"93ef9a09":{"m":120,"g":121},"b04cd3d4":{"m":120,"g":121},"7ef5d8af":{"m":120,"g":121},"71d41212":{"m":120,"g":121},"b9fb74f3":{"m":120,"g":121},"e15b63a1":{"m":120,"g":121},"4060ed37":{"m":120,"g":121},"2342605e":{"m":120,"g":121},"dbf17a83":{"m":120,"g":121},"0f0c430e":{"m":120,"g":121},"8e797a47":{"m":120,"g":121},"aa3003f1":{"m":120,"g":121},"4793ec7d":{"m":120,"g":121},"92009bd2":{"m":120,"g":121},"4ef981e2":{"m":120,"g":121},"69ed8b67":{"m":120,"g":121},"1801cd19":{"m":120,"g":121},"ffc722a6":{"m":120,"g":121},"49afb3d9":{"m":120,"g":121},"f80371ff":{"m":120,"g":121},"62eff37b":{"m":120,"g":121},"47e12e08":{"m":120,"g":121},"823b4429":{"m":120,"g":121},"14a4d80e":{"m":120,"g":121},"41c10e67":{"m":122,"g":127},"0bfe1d14":{"m":122,"g":127},"5f98b7fe":{"m":122,"g":127},"a4bf5c6a":{"m":122,"g":127},"30ad1070":{"m":122,"g":127},"a80bcb5a":{"m":122,"g":127},"f7f9e41b":{"m":122,"g":127},"263eab9f":{"m":122,"g":127},"25257d8e":{"m":122,"g":127},"cf0c2415":{"m":122,"g":127},"5538e05c":{"m":122,"g":127},"c30ebb93":{"m":122,"g":127},"41efcaeb":{"m":122,"g":127},"70562969":{"m":122,"g":127},"b57dc169":{"m":122,"g":127},"0095e018":{"m":122,"g":127},"68486481":{"m":122,"g":127},"410225b7":{"m":122,"g":127},"2c9aebea":{"m":122,"g":127},"bc741073":{"m":122,"g":127},"2f6af1a3":{"m":122,"g":127},"50b6842b":{"m":122,"g":127},"2d5605e8":{"m":122,"g":127},"300b4c21":{"m":122,"g":127},"c0652d90":{"m":122,"g":127},"2e48584b":{"m":122,"g":127},"57cc5385":{"m":122,"g":127},"5cc0d25a":{"m":122,"g":127},"a076ec1a":{"m":122,"g":127},"72b5f3d0":{"m":122,"g":127},"2f766f38":{"m":122,"g":127},"069e490b":{"m":122,"g":127},"ab95d35f":{"m":122,"g":127},"34c286b8":{"m":122,"g":127},"9416ee60":{"m":122,"g":127},"d4a09ec9":{"m":122,"g":127},"662725b9":{"m":122,"g":127},"82cfcd3b":{"m":122,"g":127},"6c1a3f0c":{"m":122,"g":127},"62377548":{"m":122,"g":121},"96ac24c0":{"m":122,"g":121},"c0d02cf4":{"m":122,"g":121},"7d121448":{"m":122,"g":121},"6a63a985":{"m":122,"g":121},"4d2f17bd":{"m":122,"g":121},"7cd716f7":{"m":122,"g":121},"b7fdde4b":{"m":122,"g":121},"69bf8011":{"m":122,"g":121},"d8fcbaa3":{"m":122,"g":121},"2cf3d0f8":{"m":122,"g":121},"1ed1abfd":{"m":122,"g":121},"ecb9fa14":{"m":122,"g":121},"700daa34":{"m":122,"g":121},"39cee0fe":{"m":122,"g":121},"04e5b6fa":{"m":122,"g":121},"ce6b17c0":{"m":122,"g":121},"cafebef1":{"m":122,"g":121},"73dfd2df":{"m":122,"g":121},"df5192cf":{"m":122,"g":121},"78c43d88":{"m":122,"g":121},"7e28c67d":{"m":122,"g":121},"3edba9bc":{"m":122,"g":121},"e5ec9764":{"m":122,"g":121},"621dfb88":{"m":122,"g":121},"fb52d35f":{"m":122,"g":121},"2b71531a":{"m":122,"g":121},"25c50498":{"m":122,"g":121},"8e2ac2e6":{"m":122,"g":121},"17a57fd8":{"m":122,"g":121},"32438eba":{"m":122,"g":121},"fed02a49":{"m":122,"g":121},"03b3e89a":{"m":122,"g":121},"9ff9fa7f":{"m":122,"g":121},"7ed8ba05":{"m":122,"g":121},"df08f346":{"m":122,"g":121},"db15148c":{"m":122,"g":121},"5259becd":{"m":122,"g":121},"ed1044ac":{"m":122,"g":121},"d717e73e":{"m":122,"g":121},"a1816187":{"m":122,"g":121},"e39628fd":{"m":122,"g":121},"bacb3825":{"m":122,"g":121},"b53d9e11":{"m":122,"g":121},"8a683821":{"m":122,"g":121},"52694b60":{"m":122,"g":121},"400bddf2":{"m":122,"g":121},"1e90fe2e":{"m":122,"g":121},"caa5d296":{"m":122,"g":121},"750940ae":{"m":122,"g":121},"42f8ea40":{"m":122,"g":121},"14cbe42f":{"m":122,"g":121},"685c0645":{"m":122,"g":121},"1357397a":{"m":122,"g":121},"42e1a72e":{"m":122,"g":121},"83a7c89c":{"m":122,"g":121},"0380ca82":{"m":122,"g":121},"ec92b0ce":{"m":122,"g":121},"e03b6bee":{"m":122,"g":121},"5e36a0b4":{"m":122,"g":121},"0297773a":{"m":122,"g":121},"587deb15":{"m":122,"g":121},"83087247":{"m":122,"g":121},"334543ff":{"m":122,"g":121},"c143f416":{"m":122,"g":121},"b48354c5":{"m":122,"g":121},"29195aaa":{"m":122,"g":121},"0ee831de":{"m":122,"g":121},"8d6ab1cb":{"m":122,"g":121},"84a9d0ea":{"m":122,"g":121},"737b58d6":{"m":122,"g":121},"77225d60":{"m":122,"g":121},"9c6e25d2":{"m":122,"g":121},"2a3763c3":{"m":122,"g":121},"fdd00295":{"m":122,"g":121},"25e73640":{"m":122,"g":121},"0da9845e":{"m":122,"g":121},"92885441":{"m":122,"g":121},"64cf868e":{"m":122,"g":121},"ea399527":{"m":122,"g":121},"41a11335":{"m":122,"g":121},"a1f2dc90":{"m":122,"g":121},"ea961060":{"m":122,"g":121},"b1e13e7c":{"m":122,"g":121},"cc7b04a2":{"m":122,"g":121},"d85d6dba":{"m":122,"g":121},"c5642a7a":{"m":122,"g":121},"691c8534":{"m":122,"g":121},"d2b8c412":{"m":122,"g":121},"bf8f7a94":{"m":122,"g":121},"81a632ac":{"m":122,"g":121},"83b22400":{"m":122,"g":121},"285a8e69":{"m":122,"g":121},"813bd6f8":{"m":122,"g":121},"729f612d":{"m":122,"g":121},"899453ac":{"m":122,"g":121},"ce832d70":{"m":122,"g":121},"88596739":{"m":122,"g":121},"a6ea3add":{"m":122,"g":121},"326c84c4":{"m":122,"g":121},"8da608cc":{"m":122,"g":121},"9fc3e8aa":{"m":122,"g":121},"c11b34d5":{"m":122,"g":121},"05ad28f2":{"m":122,"g":121},"0cae873f":{"m":122,"g":121},"a8b91f6b":{"m":122,"g":121},"959d1ab8":{"m":122,"g":121},"6c1c1933":{"m":122,"g":121},"3029d301":{"m":122,"g":121},"f389f017":{"m":122,"g":121},"caa4819b":{"m":122,"g":121},"a88b006e":{"m":122,"g":121},"ce112c07":{"m":122,"g":121},"f7dc2f33":{"m":122,"g":121},"cd784faf":{"m":122,"g":121},"75c09e1f":{"m":122,"g":121},"09af0a7b":{"m":122,"g":121},"c8d385ce":{"m":122,"g":121},"09938e1f":{"m":123,"g":127},"23407983":{"m":123,"g":127},"1357ab02":{"m":123,"g":127},"44da7377":{"m":123,"g":127},"fb9582c4":{"m":123,"g":127},"d22d0447":{"m":123,"g":127},"887742a1":{"m":123,"g":127},"34f7564d":{"m":123,"g":127},"1cfbbc42":{"m":123,"g":127},"55dfb539":{"m":123,"g":127},"42889acb":{"m":123,"g":127},"211f4070":{"m":123,"g":127},"befa41a1":{"m":123,"g":127},"30b26ee9":{"m":123,"g":127},"aa797d01":{"m":123,"g":127},"7cee07a0":{"m":123,"g":127},"bb517fe3":{"m":123,"g":127},"0e82fd3d":{"m":123,"g":127},"b7d70411":{"m":123,"g":127},"ff0b64e1":{"m":123,"g":127},"d84790db":{"m":123,"g":127},"0678beaa":{"m":123,"g":127},"c2d4716d":{"m":123,"g":127},"c14cc47e":{"m":123,"g":127},"dbcf85b7":{"m":123,"g":127},"83804bc6":{"m":123,"g":127},"d5fa019c":{"m":123,"g":127},"fef3a6b6":{"m":123,"g":127},"173e0f70":{"m":123,"g":127},"f600866a":{"m":123,"g":127},"93be7e86":{"m":123,"g":127},"60b0754c":{"m":123,"g":127},"0b24af4d":{"m":123,"g":127},"a209fb05":{"m":123,"g":127},"48d6bea1":{"m":123,"g":127},"1689c0e3":{"m":123,"g":127},"193fbb0b":{"m":123,"g":127},"e607850f":{"m":123,"g":127},"15efbcb4":{"m":123,"g":127},"243c064d":{"m":123,"g":127},"0b41a293":{"m":123,"g":127},"d31d48b3":{"m":123,"g":127},"88342607":{"m":123,"g":127},"fd7a72d6":{"m":123,"g":127},"21a8fa16":{"m":123,"g":127},"7a21d8b2":{"m":123,"g":127},"d36639ee":{"m":123,"g":127},"6ef23b98":{"m":123,"g":127},"385599cb":{"m":123,"g":127},"952fbe47":{"m":123,"g":127},"edb25693":{"m":123,"g":127},"3529c061":{"m":123,"g":127},"ffb32a85":{"m":123,"g":127},"14d80648":{"m":123,"g":127},"ab8b83f7":{"m":123,"g":127},"de0b10cf":{"m":123,"g":127},"6e29446e":{"m":123,"g":127},"0c3543d7":{"m":123,"g":127},"6a3b9fd0":{"m":123,"g":127},"65f1d065":{"m":123,"g":127},"9434a0e5":{"m":123,"g":127},"20315697":{"m":123,"g":127},"c9db7911":{"m":123,"g":127},"15ed27d7":{"m":123,"g":127},"66fb9b13":{"m":123,"g":127},"819fc591":{"m":123,"g":127},"7efd8b3d":{"m":123,"g":127},"a920b9da":{"m":123,"g":127},"76196b3c":{"m":123,"g":127},"95191ebd":{"m":123,"g":127},"9a512cf9":{"m":123,"g":127},"3451fc32":{"m":123,"g":127},"c550ab91":{"m":123,"g":127},"086f0b79":{"m":123,"g":127},"0afd6832":{"m":123,"g":127},"6f858930":{"m":123,"g":127},"229256c5":{"m":123,"g":127},"6b634493":{"m":123,"g":127},"756ad9ce":{"m":123,"g":127},"d2a8f71c":{"m":123,"g":127},"2b7bf11b":{"m":123,"g":127},"566ade03":{"m":123,"g":127},"69193f71":{"m":123,"g":127},"d5b6e50f":{"m":123,"g":127},"9632e48f":{"m":123,"g":127},"59cce594":{"m":123,"g":127},"795e98f8":{"m":123,"g":127},"358ae356":{"m":123,"g":127},"0c006b88":{"m":124,"g":127},"cd135bfe":{"m":124,"g":127},"fc84b073":{"m":124,"g":127},"8be0e1bc":{"m":124,"g":127},"8e1d6756":{"m":124,"g":127},"0da30dbc":{"m":124,"g":127},"58095cb0":{"m":124,"g":127},"fd3034da":{"m":124,"g":127},"fbbe16fa":{"m":124,"g":127},"6a1a64fa":{"m":124,"g":127},"e2715cf8":{"m":124,"g":127},"74630ba3":{"m":124,"g":127},"73e9a2ef":{"m":124,"g":127},"837b08eb":{"m":124,"g":127},"bb6a21cd":{"m":124,"g":127},"32ec68fa":{"m":124,"g":127},"3c0a6df8":{"m":124,"g":127},"2104d20e":{"m":124,"g":127},"f235498e":{"m":124,"g":127},"149dc9aa":{"m":124,"g":127},"9a954982":{"m":124,"g":127},"97be66c3":{"m":124,"g":127},"74243dff":{"m":124,"g":127},"4ea4c48b":{"m":124,"g":127},"cf5d27e3":{"m":124,"g":127},"9ec6031d":{"m":124,"g":127},"a5affb0c":{"m":124,"g":127},"5925d3d7":{"m":124,"g":127},"7ef1964a":{"m":124,"g":127},"b0476a06":{"m":124,"g":127},"ffba61a1":{"m":124,"g":127},"3c219eb0":{"m":124,"g":127},"1ffdcdc4":{"m":124,"g":127},"c7d57d5b":{"m":124,"g":127},"80802c4c":{"m":124,"g":127},"83b104ee":{"m":124,"g":127},"14127804":{"m":124,"g":127},"82f39dc1":{"m":124,"g":127},"627bac64":{"m":124,"g":127},"3651cfbf":{"m":124,"g":127},"c8547ecd":{"m":124,"g":127},"7bc1dae0":{"m":124,"g":127},"4fe53e58":{"m":124,"g":127},"fb2e816e":{"m":124,"g":127},"7c45b8b4":{"m":124,"g":127},"ba5b6823":{"m":124,"g":127},"508d2f7a":{"m":124,"g":127},"a889c854":{"m":124,"g":127},"4d84f886":{"m":124,"g":127},"dc4f5418":{"m":124,"g":127},"0648eb48":{"m":124,"g":127},"b88fab31":{"m":124,"g":127},"36942660":{"m":124,"g":127},"9f5e7018":{"m":124,"g":127},"cbf23dbb":{"m":124,"g":127},"6dade6c3":{"m":124,"g":127},"b419e20c":{"m":124,"g":127},"48641435":{"m":124,"g":127},"44b1b394":{"m":124,"g":127},"0711d150":{"m":124,"g":127},"303cc957":{"m":125,"g":127},"661c1c97":{"m":125,"g":127},"c022107f":{"m":125,"g":127},"56c83e0f":{"m":125,"g":127},"b51d46d0":{"m":125,"g":127},"10864731":{"m":125,"g":127},"665416f6":{"m":125,"g":127},"838bcb0d":{"m":125,"g":127},"f1f4c451":{"m":125,"g":127},"b0ee99dd":{"m":125,"g":127},"ddfcb7c8":{"m":125,"g":127},"58b12ccb":{"m":125,"g":127},"547de8c7":{"m":125,"g":127},"37c40a87":{"m":125,"g":127},"1240ac13":{"m":125,"g":127},"5639145f":{"m":125,"g":127},"afee2843":{"m":125,"g":127},"6f084880":{"m":125,"g":127},"611a4fd0":{"m":125,"g":127},"9ea2c686":{"m":125,"g":127},"e2a784ec":{"m":125,"g":127},"05559a4a":{"m":125,"g":127},"7bffc5dc":{"m":125,"g":127},"a5e5088d":{"m":125,"g":127},"ac19ce7e":{"m":125,"g":127},"95876d75":{"m":125,"g":127},"a30f1907":{"m":125,"g":127},"dc8a5a1c":{"m":125,"g":127},"e123648b":{"m":125,"g":127},"90401cf7":{"m":125,"g":127},"9cfe78dd":{"m":125,"g":127},"307e7a61":{"m":125,"g":127},"ddd1440d":{"m":125,"g":127},"d1be60c3":{"m":125,"g":127},"583bb180":{"m":125,"g":127},"1f2a6c69":{"m":125,"g":127},"61c7fe7a":{"m":125,"g":127},"83f89cc6":{"m":125,"g":127},"db24d346":{"m":125,"g":127},"885cfca2":{"m":125,"g":127},"4e916f98":{"m":125,"g":127},"4f65a646":{"m":125,"g":127},"f5b3ccd9":{"m":125,"g":127},"bb00e24f":{"m":125,"g":127},"210a9cab":{"m":125,"g":127},"b8ac4fcb":{"m":125,"g":127},"877cb528":{"m":125,"g":127},"3633f8b0":{"m":125,"g":127},"93cf60fc":{"m":125,"g":127},"b5e04173":{"m":125,"g":127},"8a821af7":{"m":125,"g":127},"4b1d163b":{"m":125,"g":127},"c21a3ec2":{"m":125,"g":127},"b142831a":{"m":125,"g":127},"d1340963":{"m":125,"g":127},"f290e801":{"m":125,"g":127},"9299a62f":{"m":125,"g":127},"49543be9":{"m":125,"g":127},"52362903":{"m":125,"g":127},"b2b26d43":{"m":125,"g":127},"d3a03aee":{"m":125,"g":127},"5f02b918":{"m":125,"g":127},"49653c88":{"m":125,"g":127},"44f594d8":{"m":125,"g":127},"2b6c4257":{"m":125,"g":127},"243ea585":{"m":125,"g":127},"6fee2c53":{"m":125,"g":127},"f1a9c72d":{"m":125,"g":127},"190002c6":{"m":125,"g":127},"0296f1cd":{"m":125,"g":127},"e039ff38":{"m":125,"g":127},"b8ddc296":{"m":125,"g":127},"0b88d520":{"m":125,"g":127},"d3d7f960":{"m":125,"g":127},"e4341872":{"m":125,"g":127},"fe19a580":{"m":125,"g":127},"55e8e399":{"m":125,"g":127},"32f79828":{"m":125,"g":127},"0f76976c":{"m":125,"g":127},"ae622790":{"m":125,"g":127},"5c9273c0":{"m":125,"g":127},"e316bcac":{"m":125,"g":127},"0fe9c1f7":{"m":125,"g":127},"61bfd9fa":{"m":125,"g":127},"c67fce16":{"m":125,"g":127},"bef37d6d":{"m":125,"g":127},"bc25ea67":{"m":125,"g":127},"1fa788ec":{"m":125,"g":127},"125f76ea":{"m":125,"g":127},"d8736c75":{"m":125,"g":127},"3b1cc466":{"m":125,"g":127},"0ee5ab5a":{"m":125,"g":127},"ed5e905c":{"m":125,"g":127},"d9c812d8":{"m":125,"g":127},"7257525c":{"m":125,"g":127},"34ba10ef":{"m":125,"g":127},"a119363f":{"m":125,"g":127},"fb314d7b":{"m":125,"g":127},"3a64844a":{"m":125,"g":127},"585c417f":{"m":125,"g":127},"b0d1c21d":{"m":125,"g":127},"b07c5e40":{"m":125,"g":127},"1772671b":{"m":125,"g":127},"6e6009fb":{"m":125,"g":127},"88a2a340":{"m":125,"g":127},"78c58621":{"m":125,"g":127},"c3bb348d":{"m":125,"g":127},"4e234b4c":{"m":125,"g":127},"4cc725ac":{"m":125,"g":127},"2cb42dc1":{"m":125,"g":127},"ebaf86d4":{"m":126,"g":127},"8359f185":{"m":126,"g":127},"5324f37a":{"m":126,"g":127},"2864c49f":{"m":126,"g":127},"d26ec39f":{"m":126,"g":127},"9c546bfd":{"m":126,"g":127},"c9b58164":{"m":126,"g":127},"e5e65e3d":{"m":126,"g":127},"ffeb28ba":{"m":126,"g":127},"b40f605f":{"m":126,"g":127},"3cdec20c":{"m":126,"g":127},"d28caaf6":{"m":126,"g":127},"ad8d24c3":{"m":126,"g":127},"018123b5":{"m":126,"g":127},"4983b7e7":{"m":126,"g":127},"f825137f":{"m":126,"g":127},"ae68158f":{"m":126,"g":127},"a7cc02e3":{"m":126,"g":127},"8ece99a9":{"m":126,"g":127},"44e391b6":{"m":126,"g":127},"1a5c313f":{"m":126,"g":127},"7ea5b42d":{"m":126,"g":127},"5ded5e27":{"m":126,"g":127},"33d1aeb0":{"m":126,"g":127},"dd909a51":{"m":126,"g":127},"60cb7167":{"m":126,"g":127},"151e1368":{"m":126,"g":127},"2f9952cd":{"m":126,"g":127},"3e7cc273":{"m":126,"g":127},"8f01a12d":{"m":126,"g":127},"28b8c579":{"m":126,"g":127},"7b877ab8":{"m":126,"g":127},"0d4a4184":{"m":126,"g":127},"2ca25a8a":{"m":126,"g":127},"cc2e36c3":{"m":126,"g":127},"d8f7816a":{"m":126,"g":127},"99e25805":{"m":126,"g":127},"4a2768a8":{"m":126,"g":127},"9b247f73":{"m":126,"g":127},"36d14712":{"m":126,"g":127},"e0e6a6ef":{"m":126,"g":127},"e8114102":{"m":126,"g":127},"14a339fc":{"m":126,"g":127},"5f662e78":{"m":126,"g":127},"7f5055ed":{"m":126,"g":127},"63728b11":{"m":126,"g":127},"5de25f78":{"m":126,"g":127},"d52800db":{"m":126,"g":127},"38a704bc":{"m":126,"g":127},"a06c44f9":{"m":126,"g":127},"527b7d3f":{"m":126,"g":127},"f09eee03":{"m":126,"g":127},"e38994dd":{"m":126,"g":127},"4a78031a":{"m":126,"g":127},"ea10a9d1":{"m":126,"g":127},"71aea45c":{"m":126,"g":127},"e3b38d71":{"m":126,"g":127},"5c0cadd0":{"m":126,"g":127},"39b1d048":{"m":126,"g":127},"8db7fc41":{"m":126,"g":127},"fe92d4d8":{"m":126,"g":127},"fc8cda14":{"m":126,"g":127},"6a7322ff":{"m":126,"g":127},"c751cb38":{"m":126,"g":127},"3594815a":{"m":126,"g":127},"9caca6a4":{"m":126,"g":127},"08c805a8":{"m":126,"g":127},"f18ec927":{"m":126,"g":127},"aea88fa7":{"m":126,"g":127},"2fe4e69f":{"m":126,"g":127},"012bfc4f":{"m":126,"g":127},"0493775b":{"m":126,"g":127},"40b26b45":{"m":126,"g":127},"9840bf4f":{"m":126,"g":127},"7b2fb3d4":{"m":128,"g":131},"d64dd3e1":{"m":128,"g":131},"3ccd7fa6":{"m":128,"g":131},"254f62d8":{"m":128,"g":131},"2b8b9d84":{"m":128,"g":131},"e970892f":{"m":128,"g":131},"d5fa58c4":{"m":128,"g":131},"9f011f61":{"m":128,"g":131},"3b18fd4c":{"m":128,"g":131},"1869f25c":{"m":128,"g":131},"e019f233":{"m":128,"g":131},"b1c688fb":{"m":128,"g":131},"8e3663d4":{"m":128,"g":131},"9edb0e0d":{"m":128,"g":131},"95f43669":{"m":128,"g":131},"50691d7b":{"m":128,"g":131},"6afe3963":{"m":128,"g":131},"191f5c77":{"m":128,"g":131},"d7246708":{"m":128,"g":131},"efc5d8f5":{"m":128,"g":131},"ef32a252":{"m":128,"g":131},"9509c4cc":{"m":128,"g":131},"4e19c1d5":{"m":128,"g":131},"78a4b446":{"m":128,"g":131},"f9696641":{"m":128,"g":131},"f35f7f12":{"m":128,"g":131},"12c789eb":{"m":128,"g":131},"597d4160":{"m":128,"g":131},"1ca205f6":{"m":128,"g":131},"24a25ffa":{"m":128,"g":131},"db7299aa":{"m":128,"g":131},"13366843":{"m":128,"g":131},"be353ffd":{"m":128,"g":131},"20e59f95":{"m":128,"g":131},"0d116b9a":{"m":128,"g":131},"4a56fa5c":{"m":128,"g":131},"51f9b962":{"m":128,"g":131},"daf494b6":{"m":128,"g":131},"37e8724e":{"m":128,"g":131},"10592e9c":{"m":128,"g":131},"2aec8b6e":{"m":128,"g":131},"0d41ddfb":{"m":128,"g":131},"37c87615":{"m":128,"g":131},"3f400f25":{"m":128,"g":131},"d91b16eb":{"m":128,"g":131},"4a10e37b":{"m":128,"g":131},"b051d76d":{"m":128,"g":131},"d52d992a":{"m":128,"g":131},"d971f228":{"m":128,"g":131},"1d3d42bd":{"m":128,"g":131},"8e9f05ec":{"m":128,"g":131},"bc083521":{"m":128,"g":131},"33f08a98":{"m":128,"g":131},"8e6083bf":{"m":128,"g":131},"2fbc78a0":{"m":128,"g":131},"f0b5ccf5":{"m":128,"g":131},"b732ffa4":{"m":128,"g":131},"56fc4830":{"m":128,"g":131},"2a96e302":{"m":128,"g":131},"8a437340":{"m":128,"g":131},"f0021c0d":{"m":128,"g":131},"7ee3e364":{"m":128,"g":131},"6d5e16fb":{"m":128,"g":131},"67e6f143":{"m":128,"g":131},"34851471":{"m":128,"g":131},"c2083116":{"m":128,"g":131},"10285ec2":{"m":128,"g":131},"9b3fc186":{"m":128,"g":131},"172c71a2":{"m":128,"g":127},"af373636":{"m":128,"g":127},"a5be6ef9":{"m":128,"g":127},"8f4e18a2":{"m":128,"g":127},"e9681444":{"m":128,"g":127},"eae59b33":{"m":128,"g":127},"14dc0523":{"m":128,"g":127},"b2236691":{"m":128,"g":127},"dcc47a56":{"m":128,"g":127},"6448b4cd":{"m":128,"g":127},"5ae0ac42":{"m":128,"g":127},"22f641ab":{"m":128,"g":127},"0997c78d":{"m":128,"g":127},"fd3be107":{"m":128,"g":127},"665f43bd":{"m":128,"g":127},"a53f2d6c":{"m":128,"g":127},"a7002e61":{"m":128,"g":127},"84e151ac":{"m":128,"g":127},"875a25dd":{"m":128,"g":127},"fc55b45e":{"m":128,"g":127},"0050ff25":{"m":128,"g":127},"af9f71f9":{"m":128,"g":127},"15264232":{"m":128,"g":127},"f8d3d80f":{"m":128,"g":127},"5027739f":{"m":128,"g":127},"3701f34d":{"m":128,"g":127},"821fb060":{"m":128,"g":127},"ace27c0c":{"m":128,"g":127},"ed1d18d4":{"m":128,"g":127},"e7b57b0d":{"m":128,"g":127},"49141df9":{"m":128,"g":127},"7b79cc4f":{"m":128,"g":127},"385ff0e5":{"m":128,"g":127},"fc5da1e8":{"m":128,"g":127},"04848ba7":{"m":128,"g":127},"9bc6a9ad":{"m":128,"g":127},"7cdaedb8":{"m":128,"g":127},"1f134f85":{"m":128,"g":127},"5f72d36d":{"m":128,"g":127},"7a2254b2":{"m":128,"g":127},"b5904999":{"m":128,"g":127},"922525ee":{"m":128,"g":127},"ee3e337c":{"m":128,"g":127},"e523e216":{"m":128,"g":127},"2ce23777":{"m":128,"g":127},"19f6a33c":{"m":128,"g":127},"e9c0c558":{"m":128,"g":127},"9b41f31a":{"m":128,"g":127},"9db3add3":{"m":128,"g":127},"c9e5799b":{"m":128,"g":127},"2966367a":{"m":128,"g":127},"87791007":{"m":128,"g":127},"dd192a55":{"m":128,"g":127},"bfe638f7":{"m":128,"g":127},"4ac65e3c":{"m":128,"g":127},"0779c3d1":{"m":128,"g":127},"5c2d72ba":{"m":128,"g":127},"9bd511a5":{"m":128,"g":127},"85b8c5c4":{"m":128,"g":127},"c8b7516f":{"m":128,"g":127},"67e9d287":{"m":128,"g":127},"e7e89349":{"m":128,"g":127},"aead0ef5":{"m":128,"g":127},"66640835":{"m":128,"g":127},"c2d69e8b":{"m":128,"g":127},"4c1e909a":{"m":128,"g":127},"2bb0317e":{"m":128,"g":127},"86255f27":{"m":128,"g":127},"e4b29370":{"m":128,"g":127},"7a8524b4":{"m":128,"g":127},"909d0d38":{"m":128,"g":127},"e42df37d":{"m":128,"g":127},"6d21392b":{"m":128,"g":127},"a1cb717d":{"m":128,"g":127},"c9456491":{"m":128,"g":127},"c4b74c1d":{"m":128,"g":127},"7aa44390":{"m":128,"g":127},"4eda9969":{"m":128,"g":127},"03a7e6f4":{"m":128,"g":127},"2cdde3d4":{"m":128,"g":127},"401ed0c5":{"m":128,"g":127},"4ef43905":{"m":128,"g":127},"d646cf63":{"m":128,"g":127},"4edb2401":{"m":128,"g":127},"706502ff":{"m":128,"g":127},"c2e56dad":{"m":128,"g":127},"9c1c5c6d":{"m":128,"g":127},"2d531946":{"m":128,"g":127},"7ae368ef":{"m":129,"g":131},"c4e20cad":{"m":129,"g":131},"5dad1ff1":{"m":129,"g":131},"ca52ed42":{"m":129,"g":131},"5c03aa3e":{"m":129,"g":131},"253be18e":{"m":129,"g":131},"084b06e7":{"m":129,"g":131},"fc6fb550":{"m":129,"g":131},"7c38eca1":{"m":129,"g":131},"427b08e2":{"m":129,"g":131},"0141ca37":{"m":129,"g":131},"25a6be49":{"m":129,"g":131},"df1f3124":{"m":129,"g":131},"c5947ecd":{"m":129,"g":131},"9530b766":{"m":129,"g":131},"3067b3f0":{"m":129,"g":131},"e0ec42c7":{"m":129,"g":131},"9c9d7091":{"m":129,"g":131},"51a86ce6":{"m":129,"g":131},"64092c8b":{"m":129,"g":131},"63b9300f":{"m":129,"g":131},"21ec99be":{"m":129,"g":131},"383689e3":{"m":129,"g":131},"236a7c23":{"m":129,"g":131},"3dabd609":{"m":129,"g":131},"73df5253":{"m":129,"g":131},"e6420100":{"m":129,"g":131},"c9e20901":{"m":129,"g":131},"106df4ea":{"m":129,"g":131},"427a19b6":{"m":129,"g":131},"1f930cd2":{"m":129,"g":131},"11ce0516":{"m":129,"g":131},"cd4151ab":{"m":129,"g":131},"8fe8b635":{"m":129,"g":131},"8a7b1b83":{"m":129,"g":131},"26aebf83":{"m":129,"g":131},"3ab8ae68":{"m":129,"g":131},"03888b9d":{"m":129,"g":131},"796d82b1":{"m":129,"g":131},"1da59e83":{"m":129,"g":131},"1d66a14c":{"m":129,"g":131},"02af51e4":{"m":129,"g":131},"eb500884":{"m":129,"g":131},"079b1738":{"m":129,"g":131},"57f933fd":{"m":129,"g":131},"1f2b84d2":{"m":129,"g":131},"e7d6027e":{"m":129,"g":131},"07821352":{"m":129,"g":131},"edbeaf3b":{"m":129,"g":131},"d9dca282":{"m":129,"g":131},"9325f945":{"m":129,"g":131},"41b7aab8":{"m":129,"g":131},"491f4fe8":{"m":129,"g":131},"34035d8c":{"m":129,"g":131},"92ca6295":{"m":129,"g":131},"ec92d7f1":{"m":129,"g":131},"79b389da":{"m":129,"g":131},"3de09aad":{"m":129,"g":131},"2e8f54e6":{"m":129,"g":131},"e55731b6":{"m":129,"g":131},"45264554":{"m":129,"g":131},"c4293f59":{"m":129,"g":131},"a2423052":{"m":129,"g":131},"bc3d2a85":{"m":129,"g":131},"d815d002":{"m":129,"g":131},"fa9021b2":{"m":129,"g":131},"9c800728":{"m":129,"g":131},"630a6930":{"m":129,"g":131},"7ce8faae":{"m":129,"g":131},"de153cf7":{"m":129,"g":131},"f4a0c5c7":{"m":129,"g":131},"0f8e5394":{"m":129,"g":131},"e8ba5a66":{"m":129,"g":131},"a2960bdd":{"m":129,"g":131},"487c8d4d":{"m":129,"g":131},"f87b8eab":{"m":129,"g":131},"e8542db5":{"m":129,"g":131},"6df1e8d6":{"m":129,"g":131},"4addb602":{"m":129,"g":131},"bd0e6908":{"m":129,"g":131},"0825d7f4":{"m":129,"g":131},"0b9dbea5":{"m":129,"g":131},"982db4eb":{"m":129,"g":131},"f5f3a5d9":{"m":129,"g":131},"f138ae57":{"m":129,"g":131},"decb4896":{"m":129,"g":131},"c72f0756":{"m":129,"g":131},"f1115cf5":{"m":129,"g":131},"412160f4":{"m":129,"g":131},"7b03cc64":{"m":129,"g":131},"9872a677":{"m":129,"g":131},"c15c864b":{"m":129,"g":131},"dc7bdc73":{"m":129,"g":131},"0a9d6453":{"m":129,"g":131},"340c613a":{"m":129,"g":131},"36b729c2":{"m":129,"g":131},"67e6ef4b":{"m":129,"g":131},"65ba5ab8":{"m":129,"g":131},"990023e5":{"m":129,"g":131},"5ddd2f6b":{"m":129,"g":131},"0ae4b1ad":{"m":129,"g":131},"94cd64a7":{"m":129,"g":131},"b870271a":{"m":129,"g":131},"22ee9b01":{"m":129,"g":131},"9d0e5f1f":{"m":129,"g":131},"1d3d8b34":{"m":129,"g":131},"155a9e72":{"m":129,"g":131},"d7cb08c5":{"m":129,"g":131},"3339c810":{"m":129,"g":131},"d6c88d51":{"m":129,"g":131},"f03ea34a":{"m":129,"g":131},"4cafc835":{"m":129,"g":131},"c6a52f44":{"m":129,"g":131},"c6d34a06":{"m":129,"g":131},"848ee570":{"m":129,"g":131},"ce6b7dfc":{"m":129,"g":131},"0fe74af5":{"m":129,"g":131},"0a362d65":{"m":129,"g":131},"143b57b8":{"m":129,"g":131},"f446b51c":{"m":129,"g":131},"a102a050":{"m":129,"g":131},"6bad6a36":{"m":129,"g":131},"11b6217a":{"m":129,"g":131},"0b0b2607":{"m":129,"g":131},"841eb29d":{"m":129,"g":131},"45cf5758":{"m":129,"g":131},"0e8ce1e8":{"m":129,"g":131},"ea1e9f6b":{"m":129,"g":131},"f6e37d3e":{"m":129,"g":131},"ab9a46d4":{"m":129,"g":131},"621061f0":{"m":129,"g":131},"7daddcdb":{"m":129,"g":131},"91d249cd":{"m":129,"g":131},"95102896":{"m":129,"g":131},"3543a04a":{"m":129,"g":131},"e12c78aa":{"m":129,"g":131},"bce40fa2":{"m":129,"g":131},"051ad833":{"m":129,"g":131},"4c9f7c97":{"m":129,"g":131},"63b05621":{"m":129,"g":131},"21af8e73":{"m":129,"g":131},"7ab548ef":{"m":129,"g":131},"bab033b9":{"m":129,"g":131},"63500426":{"m":129,"g":131},"25758647":{"m":129,"g":131},"2bc8ee8b":{"m":129,"g":131},"ab843ced":{"m":129,"g":131},"6edffc63":{"m":129,"g":131},"077ca70e":{"m":129,"g":131},"7cb04dc0":{"m":129,"g":131},"5443db87":{"m":129,"g":131},"9f340ab1":{"m":129,"g":131},"70c6f951":{"m":129,"g":131},"d941a3be":{"m":129,"g":131},"b12c9e5c":{"m":129,"g":131},"e9e90460":{"m":129,"g":131},"6330d664":{"m":129,"g":131},"91e8dc37":{"m":129,"g":131},"231df4b0":{"m":129,"g":131},"b087ef8b":{"m":129,"g":131},"5155016b":{"m":129,"g":131},"082b54c6":{"m":129,"g":131},"a8ef4d18":{"m":129,"g":131},"15ff6982":{"m":129,"g":131},"9adef42c":{"m":129,"g":131},"685b9d82":{"m":129,"g":131},"a223402f":{"m":129,"g":131},"44d0a848":{"m":129,"g":131},"5b7da0f5":{"m":129,"g":131},"697a77bf":{"m":129,"g":131},"0a186924":{"m":129,"g":131},"b6312e62":{"m":129,"g":131},"779cbc6e":{"m":129,"g":131},"67c8c867":{"m":129,"g":131},"69a03bc3":{"m":129,"g":131},"66f242b9":{"m":129,"g":131},"8a9b8b84":{"m":129,"g":131},"7e964b51":{"m":129,"g":131},"a0d9f6cd":{"m":129,"g":131},"8308cd36":{"m":129,"g":131},"e0e8a996":{"m":129,"g":131},"5102d009":{"m":129,"g":131},"0dd759e0":{"m":129,"g":131},"5e70880e":{"m":129,"g":131},"9dab534b":{"m":129,"g":131},"262c3c1f":{"m":129,"g":131},"6c190cbd":{"m":129,"g":131},"eff6a07c":{"m":129,"g":131},"b704b0a9":{"m":129,"g":131},"15729dbc":{"m":129,"g":131},"21b0582d":{"m":129,"g":131},"5795da5e":{"m":129,"g":131},"540d6fee":{"m":129,"g":131},"5a8adca9":{"m":129,"g":131},"007c3e23":{"m":129,"g":131},"7130ad3a":{"m":129,"g":131},"35a4c21a":{"m":129,"g":131},"846ba3c6":{"m":129,"g":131},"18fb5158":{"m":129,"g":131},"ca5c8b16":{"m":129,"g":131},"f33e5d1e":{"m":129,"g":131},"13e5beea":{"m":129,"g":131},"c53e729d":{"m":129,"g":131},"03a26557":{"m":129,"g":131},"873382a9":{"m":129,"g":131},"391a863b":{"m":129,"g":131},"36b1bcd2":{"m":129,"g":131},"64a11303":{"m":129,"g":131},"1ab6ce0e":{"m":129,"g":131},"e99ca6ac":{"m":129,"g":131},"fcccaf90":{"m":129,"g":131},"215a97fa":{"m":129,"g":131},"5eed5fc0":{"m":129,"g":131},"808b6dfd":{"m":129,"g":131},"4852aa05":{"m":129,"g":131},"f922bfd5":{"m":129,"g":131},"dfd7ab96":{"m":129,"g":131},"46673b42":{"m":129,"g":131},"3421d049":{"m":129,"g":131},"d3d404d3":{"m":129,"g":131},"64225a8a":{"m":129,"g":131},"d64bf6c6":{"m":129,"g":131},"432ecf84":{"m":129,"g":131},"0b3f002d":{"m":129,"g":131},"6f094def":{"m":129,"g":131},"59464dbf":{"m":129,"g":131},"1f7fcc10":{"m":129,"g":131},"dbab5d50":{"m":129,"g":131},"760c20b3":{"m":129,"g":131},"407cb3ce":{"m":129,"g":131},"7cc43bd4":{"m":129,"g":131},"cce2d748":{"m":129,"g":131},"c1dd9a95":{"m":129,"g":131},"ed8786b0":{"m":129,"g":131},"f9fe0630":{"m":129,"g":131},"8ff3ef1f":{"m":129,"g":131},"da182e4b":{"m":129,"g":131},"83e72077":{"m":129,"g":131},"a2c388ba":{"m":129,"g":131},"9384fa27":{"m":129,"g":131},"173e73fa":{"m":129,"g":131},"a164259e":{"m":129,"g":131},"b0a26ba6":{"m":129,"g":131},"de430b67":{"m":129,"g":131},"4b45d556":{"m":129,"g":131},"db0ffc09":{"m":129,"g":131},"eb1d8854":{"m":129,"g":131},"bf108692":{"m":129,"g":131},"e83bd1fa":{"m":129,"g":131},"9dc15d85":{"m":129,"g":131},"fafaa2cc":{"m":129,"g":131},"9b4b3441":{"m":129,"g":131},"94216a9c":{"m":129,"g":131},"9535015d":{"m":129,"g":131},"a3b578fc":{"m":129,"g":131},"b60e769d":{"m":129,"g":131},"a95a3807":{"m":129,"g":131},"98b38de3":{"m":129,"g":131},"a146f833":{"m":129,"g":131},"1dd9a6ae":{"m":129,"g":131},"8ef11569":{"m":129,"g":131},"ecefc790":{"m":129,"g":131},"aeac6220":{"m":129,"g":131},"04b52fa8":{"m":129,"g":131},"e5c0f591":{"m":129,"g":131},"981ca831":{"m":129,"g":131},"414248e0":{"m":129,"g":131},"f56b9b42":{"m":129,"g":131},"b2f7b08c":{"m":129,"g":131},"75222bfe":{"m":129,"g":131},"9ea19533":{"m":129,"g":131},"dbf22152":{"m":129,"g":131},"d5e03468":{"m":129,"g":131},"a22104a6":{"m":129,"g":131},"4683e244":{"m":129,"g":131},"9054e844":{"m":129,"g":131},"18403f6b":{"m":129,"g":131},"2892265d":{"m":129,"g":131},"c9bd1aca":{"m":129,"g":131},"618ca238":{"m":129,"g":131},"5c291549":{"m":129,"g":131},"aaa40a9b":{"m":129,"g":131},"dd70cf99":{"m":129,"g":131},"d4593964":{"m":129,"g":131},"53fffefd":{"m":129,"g":131},"b964ce61":{"m":129,"g":131},"ac5505b0":{"m":129,"g":131},"a90435c0":{"m":129,"g":131},"5354d7b7":{"m":129,"g":131},"e0148677":{"m":129,"g":131},"04793508":{"m":129,"g":131},"cad78789":{"m":129,"g":131},"b29769f3":{"m":129,"g":131},"3990b84b":{"m":129,"g":131},"5a4394a3":{"m":129,"g":131},"dd303614":{"m":129,"g":131},"86312468":{"m":129,"g":131},"5625e32c":{"m":129,"g":131},"ca548d83":{"m":129,"g":131},"3397bcee":{"m":129,"g":131},"3e804bb0":{"m":129,"g":131},"a22de641":{"m":129,"g":131},"ac438226":{"m":129,"g":131},"a92afb00":{"m":129,"g":131},"0eea17e3":{"m":129,"g":131},"38052432":{"m":129,"g":131},"8bfce9b0":{"m":129,"g":131},"b41afa37":{"m":129,"g":131},"94ae816f":{"m":129,"g":131},"53620a1b":{"m":129,"g":131},"59b4d7f8":{"m":129,"g":131},"a56f7702":{"m":129,"g":131},"1b48e1b9":{"m":129,"g":131},"a24aefe5":{"m":129,"g":131},"45c572c5":{"m":129,"g":131},"681b9e64":{"m":129,"g":131},"dab06b50":{"m":129,"g":131},"85ffce30":{"m":129,"g":131},"e94ef9fc":{"m":129,"g":131},"964cdedc":{"m":129,"g":131},"aa6e2c8a":{"m":129,"g":131},"1776dce5":{"m":129,"g":131},"99e13d18":{"m":129,"g":131},"dc836909":{"m":129,"g":131},"323fed5c":{"m":129,"g":131},"eff7df6d":{"m":129,"g":131},"5e7f91d4":{"m":129,"g":131},"a34d3abb":{"m":129,"g":131},"6d0e0b9b":{"m":129,"g":131},"589d9ad5":{"m":129,"g":131},"a244c030":{"m":129,"g":131},"1bb063aa":{"m":129,"g":131},"b30f63c4":{"m":129,"g":131},"90a01335":{"m":129,"g":131},"43602790":{"m":129,"g":131},"b537ac0d":{"m":129,"g":131},"eda2f700":{"m":129,"g":131},"8c212a20":{"m":129,"g":131},"d754ce97":{"m":129,"g":131},"475962a1":{"m":129,"g":131},"bfcf15a1":{"m":129,"g":131},"fb04d434":{"m":129,"g":131},"6be65ae4":{"m":129,"g":131},"750084ae":{"m":129,"g":131},"64480ec7":{"m":129,"g":131},"db2d362d":{"m":129,"g":131},"81e86992":{"m":129,"g":131},"c4db77f8":{"m":129,"g":131},"c0a2513b":{"m":129,"g":131},"3ae664d7":{"m":129,"g":131},"c56fc424":{"m":129,"g":131},"3f1cfd87":{"m":129,"g":131},"b5344b31":{"m":129,"g":131},"6b262ac8":{"m":129,"g":131},"ada8ce1f":{"m":129,"g":131},"5a2c7039":{"m":129,"g":131},"42028af6":{"m":129,"g":131},"7291c72e":{"m":129,"g":131},"6bc30628":{"m":129,"g":131},"fa924410":{"m":129,"g":131},"fc9efdcb":{"m":129,"g":131},"2dec555d":{"m":129,"g":131},"acde21d8":{"m":129,"g":131},"4528cb7d":{"m":129,"g":131},"a352e833":{"m":129,"g":131},"852eb6ce":{"m":129,"g":131},"7af9b88c":{"m":129,"g":131},"2847e5c4":{"m":129,"g":131},"c8ede0e9":{"m":129,"g":131},"19729f72":{"m":129,"g":131},"b51f9bbe":{"m":129,"g":131},"4a8442af":{"m":129,"g":131},"7dcf910d":{"m":129,"g":131},"c7b37b70":{"m":129,"g":131},"10e0b83a":{"m":129,"g":131},"bc42c8c4":{"m":129,"g":131},"2e3a69ae":{"m":129,"g":131},"21370ef7":{"m":129,"g":131},"c3c4da71":{"m":129,"g":131},"dc694624":{"m":129,"g":131},"48ca9f75":{"m":129,"g":131},"127d59cd":{"m":129,"g":131},"af6bcadc":{"m":129,"g":131},"67fca6b2":{"m":129,"g":131},"f88b2aa6":{"m":129,"g":131},"17b24aca":{"m":129,"g":131},"bfaf0b86":{"m":129,"g":131},"83756a4b":{"m":129,"g":131},"a3557949":{"m":129,"g":131},"e72cf136":{"m":129,"g":131},"196b940a":{"m":129,"g":131},"a1e1e533":{"m":129,"g":131},"d4a4dcdf":{"m":129,"g":131},"97ba2c2d":{"m":129,"g":131},"e197bef5":{"m":129,"g":131},"8900f996":{"m":129,"g":131},"ba9102f9":{"m":129,"g":131},"b638abba":{"m":129,"g":131},"37980559":{"m":129,"g":131},"075ba74d":{"m":129,"g":131},"f7be98e1":{"m":129,"g":131},"9a1a9a42":{"m":129,"g":131},"6c2e5fcd":{"m":129,"g":131},"0d2d6878":{"m":129,"g":131},"9f59194f":{"m":129,"g":131},"cf1f0166":{"m":129,"g":131},"10969ae4":{"m":129,"g":131},"92ad2ff9":{"m":129,"g":131},"9b64f6f3":{"m":129,"g":131},"c0d1a338":{"m":129,"g":131},"a9d22b75":{"m":129,"g":131},"6b9459e8":{"m":129,"g":131},"3a6ec47b":{"m":129,"g":131},"b8e32e79":{"m":129,"g":131},"f5566acc":{"m":129,"g":131},"d79e1294":{"m":129,"g":131},"6e9b1549":{"m":129,"g":131},"109f27ba":{"m":129,"g":131},"c1a30aa7":{"m":129,"g":131},"2e1dbdb2":{"m":129,"g":131},"6d025fd3":{"m":129,"g":131},"518467be":{"m":129,"g":131},"63807079":{"m":129,"g":131},"f6cfe9f1":{"m":129,"g":131},"7bc99d41":{"m":129,"g":131},"e2d67468":{"m":129,"g":131},"6beb6e99":{"m":129,"g":131},"7e88b9c1":{"m":129,"g":131},"cfcf2758":{"m":129,"g":131},"ac81db66":{"m":129,"g":131},"33905005":{"m":129,"g":131},"820e13c9":{"m":129,"g":131},"595adf6d":{"m":129,"g":131},"a5ad0069":{"m":129,"g":131},"4e41edcb":{"m":129,"g":131},"67071f55":{"m":129,"g":131},"0c966779":{"m":129,"g":131},"f3386077":{"m":129,"g":131},"4ce8fb3c":{"m":129,"g":131},"4c3573e4":{"m":129,"g":131},"f1be8aa0":{"m":129,"g":131},"aa8ecbda":{"m":129,"g":131},"9188fecc":{"m":129,"g":131},"26ca0746":{"m":129,"g":131},"90c18a16":{"m":129,"g":131},"d7984f31":{"m":129,"g":131},"7119d188":{"m":129,"g":131},"fe3bbfb4":{"m":129,"g":131},"9846f8ed":{"m":129,"g":131},"85ae508e":{"m":129,"g":131},"d879e37f":{"m":129,"g":131},"e2c9a590":{"m":129,"g":131},"a1e37b02":{"m":129,"g":131},"e389f91d":{"m":129,"g":131},"aac07bf7":{"m":129,"g":131},"ea89a3a0":{"m":129,"g":131},"2bc7c5eb":{"m":129,"g":131},"a63f433b":{"m":129,"g":131},"58f8f4e4":{"m":129,"g":131},"25acbbc6":{"m":129,"g":131},"a8fcbf6f":{"m":129,"g":131},"e486308c":{"m":129,"g":131},"60420109":{"m":129,"g":131},"ff00b6ad":{"m":129,"g":131},"7b445260":{"m":129,"g":131},"c236d05f":{"m":129,"g":131},"df561392":{"m":129,"g":131},"15db5497":{"m":129,"g":131},"9ba3597d":{"m":129,"g":131},"80797c2a":{"m":129,"g":131},"7afff8fd":{"m":129,"g":131},"ac406d43":{"m":129,"g":131},"b436113f":{"m":129,"g":131},"8b5e2c53":{"m":129,"g":131},"b24235b8":{"m":129,"g":131},"ae7698fb":{"m":129,"g":131},"a3e4fe4b":{"m":129,"g":131},"f3e9336d":{"m":129,"g":131},"290fcd89":{"m":129,"g":131},"1dcde539":{"m":129,"g":131},"15bc1f5c":{"m":129,"g":131},"4d597616":{"m":129,"g":131},"ab63f3c5":{"m":129,"g":131},"147b7823":{"m":129,"g":131},"d368c745":{"m":129,"g":131},"7e626d12":{"m":129,"g":131},"2a577344":{"m":129,"g":131},"6abb8051":{"m":130,"g":131},"2e3946d8":{"m":130,"g":131},"32f8b606":{"m":130,"g":131},"b9bef31a":{"m":130,"g":131},"8550822d":{"m":130,"g":131},"8810152e":{"m":130,"g":131},"7bf16c63":{"m":130,"g":131},"39f9a9c2":{"m":130,"g":131},"d69ecc19":{"m":130,"g":131},"763888b5":{"m":130,"g":131},"9a327bdf":{"m":130,"g":131},"2de98010":{"m":130,"g":131},"8200fb56":{"m":130,"g":131},"cb4cdb43":{"m":130,"g":131},"80cfca50":{"m":130,"g":131},"7871593c":{"m":130,"g":131},"4a62a0e3":{"m":130,"g":131},"12a08efc":{"m":130,"g":131},"06836ad0":{"m":130,"g":131},"f72a7703":{"m":130,"g":131},"aeff0d38":{"m":130,"g":131},"cf0478d6":{"m":130,"g":131},"a2ca9bd4":{"m":130,"g":131},"36361adc":{"m":130,"g":131},"661e9775":{"m":130,"g":131},"2970f229":{"m":130,"g":131},"c08b780f":{"m":130,"g":131},"8fbf7dd5":{"m":130,"g":131},"1915a1f8":{"m":130,"g":131},"85d0ccfa":{"m":130,"g":131},"a4ffd665":{"m":130,"g":131},"559202b5":{"m":130,"g":131},"f57d4fe7":{"m":130,"g":131},"b7b7524e":{"m":130,"g":131},"6799847e":{"m":130,"g":131},"03b835e7":{"m":130,"g":131},"aff1238e":{"m":130,"g":131},"5e2cda61":{"m":130,"g":131},"b0bbc7f5":{"m":130,"g":131},"673c11ba":{"m":130,"g":131},"3b47973a":{"m":130,"g":131},"f6423b62":{"m":130,"g":131},"84efe54b":{"m":130,"g":131},"948b6ace":{"m":130,"g":131},"f124539a":{"m":130,"g":131},"c8683ae3":{"m":130,"g":131},"125e17ef":{"m":130,"g":131},"88c459c6":{"m":130,"g":131},"ae6a6630":{"m":130,"g":131},"26d95008":{"m":130,"g":131},"f2b5dcc9":{"m":130,"g":131},"9abcab3f":{"m":130,"g":131},"e5135b73":{"m":130,"g":131},"41d61faa":{"m":130,"g":131},"3c7886ec":{"m":130,"g":131},"0e4d8790":{"m":130,"g":131},"6d5d76ad":{"m":130,"g":131},"91c9c14c":{"m":130,"g":131},"32a32cf7":{"m":130,"g":131},"be4a3ec3":{"m":130,"g":131},"ff6e3ea9":{"m":130,"g":131},"dd91d38e":{"m":130,"g":131},"5f6f550a":{"m":130,"g":131},"5edbe351":{"m":130,"g":131},"d2b42477":{"m":130,"g":131},"9dfa01a4":{"m":130,"g":131},"e592ee65":{"m":130,"g":131},"cee93a6f":{"m":130,"g":131},"bc388471":{"m":130,"g":131},"3e40c636":{"m":130,"g":131},"80122e4f":{"m":130,"g":131},"e12c6b32":{"m":130,"g":131},"6d417918":{"m":130,"g":131},"35a9a073":{"m":130,"g":131},"ea177372":{"m":130,"g":131},"42fcf543":{"m":130,"g":131},"d257bf87":{"m":130,"g":131},"7b0c7ad1":{"m":130,"g":131},"d30d6b36":{"m":130,"g":131},"d881f314":{"m":130,"g":131},"2ac5b983":{"m":130,"g":131},"a0dde90a":{"m":130,"g":131},"b988c18e":{"m":130,"g":131},"e41664ba":{"m":130,"g":131},"3d1b591a":{"m":130,"g":131},"e11f795f":{"m":130,"g":131},"959a1746":{"m":130,"g":131},"b72f0268":{"m":130,"g":131},"09376fd7":{"m":130,"g":131},"aed835e3":{"m":130,"g":131},"49dfa1d8":{"m":130,"g":131},"1ea6b740":{"m":130,"g":131},"e73173b0":{"m":130,"g":131},"16e8463a":{"m":130,"g":131},"cf9a774c":{"m":130,"g":131},"ec7b2c16":{"m":130,"g":131},"1569fc7f":{"m":130,"g":131},"5a46fb15":{"m":130,"g":131},"38daa294":{"m":130,"g":131},"66984a8b":{"m":130,"g":131},"889b46ea":{"m":130,"g":131},"05284378":{"m":130,"g":131},"a8904560":{"m":130,"g":131},"66280987":{"m":130,"g":131},"205f041e":{"m":130,"g":131},"7235a7fb":{"m":130,"g":131},"8fce9e7b":{"m":130,"g":131},"53477322":{"m":130,"g":131},"2ce121a1":{"m":130,"g":131},"35ba6fe1":{"m":130,"g":131},"498ea41c":{"m":130,"g":131},"7c744d13":{"m":130,"g":131},"46b05ef5":{"m":130,"g":131},"beec8eed":{"m":130,"g":131},"b76e303e":{"m":130,"g":131},"80a575e4":{"m":130,"g":131},"4c5074eb":{"m":130,"g":131},"41429a8c":{"m":130,"g":131},"532037df":{"m":130,"g":131},"fa0ca976":{"m":130,"g":131},"b5d39985":{"m":130,"g":131},"2ecee757":{"m":130,"g":131},"6d37e708":{"m":130,"g":131},"c1006fd8":{"m":130,"g":131},"29c6c2ea":{"m":130,"g":131},"eb85fa6d":{"m":130,"g":131},"0e6441b4":{"m":130,"g":131},"88d1bab5":{"m":130,"g":131},"922756aa":{"m":130,"g":131},"d8faf2f3":{"m":130,"g":131},"7dfcc781":{"m":130,"g":131},"7f3308bc":{"m":130,"g":131},"fdc2ef58":{"m":130,"g":131},"1808df48":{"m":130,"g":131},"b01fc161":{"m":130,"g":131},"788628b5":{"m":130,"g":131},"11d33c0e":{"m":130,"g":131},"441420e1":{"m":130,"g":131},"29a2d4b5":{"m":130,"g":131},"079ac237":{"m":130,"g":131},"84280784":{"m":130,"g":131},"af35023e":{"m":130,"g":131},"cb8df87f":{"m":130,"g":131},"e3ab23c1":{"m":130,"g":131},"70d25873":{"m":130,"g":131},"894c0dc5":{"m":130,"g":131},"d6c49019":{"m":130,"g":131},"fa78c44a":{"m":130,"g":131},"654a78f9":{"m":130,"g":131},"f90b4004":{"m":130,"g":131},"78647e08":{"m":130,"g":131},"46f21a59":{"m":130,"g":131},"b2b09f5f":{"m":130,"g":131},"04df80a9":{"m":130,"g":131},"4f73e53d":{"m":130,"g":131},"16ff892c":{"m":130,"g":131},"df026bb1":{"m":130,"g":131},"d42c167b":{"m":130,"g":131},"38815105":{"m":130,"g":131},"9d823402":{"m":130,"g":131},"8ab5d8b4":{"m":130,"g":131},"03575ce3":{"m":130,"g":131},"80518bea":{"m":130,"g":131},"7e78825d":{"m":130,"g":131},"5bbd83a2":{"m":130,"g":131},"abf6272b":{"m":130,"g":131},"46d7b35e":{"m":130,"g":131},"20aad5b5":{"m":130,"g":131},"974c562a":{"m":130,"g":131},"aca0d01d":{"m":130,"g":131},"dc163502":{"m":130,"g":131},"24903b88":{"m":130,"g":131},"443d7bcd":{"m":130,"g":131},"16d8de22":{"m":130,"g":131},"d122e324":{"m":130,"g":131},"96cc1083":{"m":130,"g":131},"77512ae0":{"m":130,"g":131},"c233e9d7":{"m":130,"g":131},"58ac3f31":{"m":130,"g":131},"93452a82":{"m":130,"g":131},"65c8568c":{"m":130,"g":131},"4bcc5879":{"m":130,"g":131},"d5ea8c71":{"m":130,"g":131},"42271376":{"m":130,"g":131},"84e0abb7":{"m":130,"g":131},"043f1317":{"m":130,"g":131},"f764c691":{"m":130,"g":131},"92205407":{"m":130,"g":131},"7d1a130c":{"m":130,"g":131},"5c8bd8b5":{"m":132,"g":133},"b05b346a":{"m":132,"g":133},"5c961756":{"m":132,"g":133},"c5f1e861":{"m":132,"g":133},"2c4d376d":{"m":132,"g":133},"d0f756ae":{"m":132,"g":133},"6f99dc97":{"m":132,"g":133},"cd1c1fa5":{"m":132,"g":133},"5b0872d2":{"m":132,"g":133},"ba88f1ca":{"m":132,"g":133},"60560c07":{"m":132,"g":133},"ca114421":{"m":132,"g":133},"543d62d1":{"m":132,"g":133},"27032cec":{"m":132,"g":133},"5d804a37":{"m":132,"g":133},"388018a5":{"m":132,"g":133},"fca8e88f":{"m":132,"g":133},"45eeeb9a":{"m":132,"g":133},"a368df28":{"m":132,"g":133},"f85460fb":{"m":132,"g":133},"e52cf30e":{"m":132,"g":133},"a076d75e":{"m":132,"g":133},"8348725d":{"m":132,"g":133},"28566241":{"m":132,"g":133},"b62fe850":{"m":132,"g":133},"624725cb":{"m":132,"g":133},"1a96e664":{"m":132,"g":133},"32829b16":{"m":132,"g":133},"e54307f2":{"m":132,"g":133},"8642dbe4":{"m":132,"g":133},"7dcad45c":{"m":132,"g":133},"7c985331":{"m":132,"g":133},"bd7824b2":{"m":132,"g":133},"312df1d6":{"m":132,"g":133},"25e97380":{"m":132,"g":133},"b6523a4f":{"m":132,"g":133},"c51efb8b":{"m":132,"g":133},"bcc5483e":{"m":132,"g":133},"ccf26027":{"m":132,"g":133},"a4992873":{"m":132,"g":133},"c97ce391":{"m":132,"g":133},"c032b559":{"m":132,"g":133},"da9b801e":{"m":132,"g":133},"0e54a695":{"m":132,"g":133},"e99ee0c6":{"m":132,"g":133},"c1bd5ee8":{"m":132,"g":133},"ef1ab230":{"m":132,"g":133},"d6598737":{"m":132,"g":133},"6c5ebc0e":{"m":132,"g":133},"5b5571a8":{"m":132,"g":133},"1698c234":{"m":132,"g":133},"3d82c0f1":{"m":132,"g":133},"617e9b3b":{"m":132,"g":133},"83e35a7c":{"m":132,"g":133},"2543666c":{"m":132,"g":133},"f732f8ea":{"m":132,"g":133},"503880db":{"m":132,"g":133},"b8cfa02c":{"m":132,"g":133},"d85fecb5":{"m":132,"g":133},"6634f67b":{"m":132,"g":133},"5eccaf77":{"m":132,"g":133},"d7f6320b":{"m":132,"g":133},"766476f5":{"m":132,"g":133},"12b7a4fa":{"m":132,"g":133},"02f1e81e":{"m":132,"g":133},"908c7186":{"m":132,"g":133},"03836d85":{"m":132,"g":133},"87dbdddc":{"m":132,"g":133},"56e5c074":{"m":132,"g":133},"6c9c8da6":{"m":132,"g":133},"21028b55":{"m":132,"g":133},"b0a25d09":{"m":132,"g":133},"793c98af":{"m":132,"g":133},"b1cbfce6":{"m":132,"g":133},"b0f531ad":{"m":132,"g":133},"01835998":{"m":132,"g":133},"4285e99d":{"m":132,"g":133},"f0774368":{"m":132,"g":133},"5e8f544d":{"m":132,"g":133},"c8d74feb":{"m":132,"g":133},"cbc7dcda":{"m":132,"g":133},"a6dc7d29":{"m":132,"g":133},"390406c4":{"m":132,"g":131},"0c63fb94":{"m":132,"g":131},"9ad02b79":{"m":132,"g":131},"18bd8e8d":{"m":132,"g":131},"036e64da":{"m":132,"g":131},"7c6fb3aa":{"m":132,"g":131},"8b0b6a45":{"m":132,"g":131},"55504df2":{"m":132,"g":131},"73df7a4e":{"m":132,"g":131},"8b98bb76":{"m":132,"g":131},"15bc8cbd":{"m":132,"g":131},"9496f12d":{"m":132,"g":131},"ab004879":{"m":132,"g":131},"6ec77680":{"m":132,"g":131},"13680e55":{"m":132,"g":131},"98c430e1":{"m":132,"g":131},"fe7f91ef":{"m":132,"g":131},"cef5ba65":{"m":132,"g":131},"53d17088":{"m":132,"g":131},"f0e948a0":{"m":132,"g":131},"9a426fc5":{"m":132,"g":131},"66772aa2":{"m":132,"g":131},"b6263344":{"m":132,"g":131},"0f8bd55f":{"m":132,"g":131},"da3dc497":{"m":132,"g":131},"817daba0":{"m":132,"g":131},"af60cad0":{"m":132,"g":131},"ce4e836b":{"m":132,"g":131},"0e0b0c05":{"m":132,"g":131},"e6f0ddda":{"m":132,"g":131},"af20657c":{"m":132,"g":131},"08da4c26":{"m":132,"g":131},"ef3f8c97":{"m":132,"g":131},"e5201bda":{"m":132,"g":131},"60d36e7b":{"m":132,"g":131},"6f657070":{"m":132,"g":131},"c106b54b":{"m":132,"g":131},"119fd956":{"m":132,"g":131},"eac5b664":{"m":132,"g":131},"07404d76":{"m":132,"g":131},"93043f7b":{"m":132,"g":131},"edde5e5d":{"m":132,"g":131},"232982a0":"m134","9e88c0a2":"m134","b7e0d54e":"m134","5dde0a57":"m134","9e5ab903":"m134","98225be6":{"m":134,"g":135},"94bcc19b":{"m":134,"g":135},"db3821a9":{"m":134,"g":135},"8c5d91b8":{"m":134,"g":135},"6a3e7092":{"m":134,"g":135},"c2601f0d":{"m":134,"g":135},"1048803c":{"m":134,"g":135},"8a84b1e7":{"m":134,"g":135},"5e20e7a6":{"m":134,"g":135},"3946dad6":{"m":134,"g":135},"ac03ec08":{"m":134,"g":135},"94164646":{"m":134,"g":135},"5fb734f1":{"m":134,"g":135},"60f1ca69":{"m":134,"g":135},"9e263c21":{"m":134,"g":135},"0d003e34":{"m":134,"g":135},"f253f43c":{"m":134,"g":135},"1e453201":{"m":134,"g":135},"26e17f90":{"m":134,"g":135},"3de23274":{"m":134,"g":135},"f4ec6f8e":{"m":134,"g":135},"9c4eb460":{"m":134,"g":135},"c2e0913e":{"m":134,"g":135},"8c6f865a":{"m":134,"g":135},"269aa27b":{"m":134,"g":135},"f39382c6":{"m":134,"g":135},"2ff289e2":{"m":134,"g":135},"b2a3f055":{"m":134,"g":135},"684e148e":{"m":134,"g":135},"f44c4b37":{"m":134,"g":135},"7380ec9d":{"m":134,"g":135},"ac78f96e":{"m":134,"g":135},"278012ca":{"m":134,"g":135},"7f587998":{"m":134,"g":135},"162d1cf9":{"m":134,"g":135},"8e08207c":{"m":134,"g":135},"c31f6272":{"m":134,"g":135},"b5d9fc87":{"m":134,"g":135},"88f3de25":{"m":134,"g":135},"24616c52":{"m":134,"g":135},"d48723b7":{"m":134,"g":135},"f3d73b01":{"m":134,"g":135},"4ab66d95":{"m":134,"g":135},"de2799f3":{"m":134,"g":135},"f784cbfa":{"m":134,"g":135},"09733090":{"m":134,"g":135},"a44d0079":{"m":134,"g":135},"8305dc17":{"m":134,"g":135},"ec8c831d":{"m":134,"g":135},"f13949e5":{"m":134,"g":135},"c236a3fd":{"m":134,"g":135},"41a1d16b":{"m":134,"g":135},"9884c9fd":{"m":134,"g":135},"a435f55d":{"m":134,"g":135},"2ec6fa3c":{"m":134,"g":135},"c58a573a":{"m":134,"g":135},"b840d6aa":{"m":134,"g":135},"ef4b3c0e":{"m":134,"g":135},"6f9d0a89":{"m":134,"g":135},"d7a3336e":{"m":134,"g":135},"7d02c8e5":{"m":134,"g":135},"e6d5a213":{"m":134,"g":135},"9f8e2307":{"m":134,"g":135},"d90f9bfc":{"m":134,"g":135},"3881bc8d":{"m":134,"g":135},"208e6a9d":{"m":134,"g":135},"be3828a1":{"m":134,"g":135},"5969be2f":{"m":134,"g":135},"8fab4895":{"m":134,"g":135},"7ccaec64":{"m":134,"g":135},"c457aad5":{"m":134,"g":135},"c7e7bfa3":{"m":134,"g":135},"bf90ea9c":{"m":134,"g":135},"26c50912":{"m":134,"g":135},"325a4c19":{"m":134,"g":135},"0294844f":{"m":134,"g":135},"0e536600":{"m":134,"g":135},"d70c2655":{"m":134,"g":135},"656f4d69":{"m":134,"g":135},"8e43980e":{"m":134,"g":135},"474a4699":{"m":134,"g":135},"b4a00ed2":{"m":134,"g":135},"f55d608c":{"m":134,"g":135},"349ce2dd":{"m":134,"g":135},"183b6519":{"m":134,"g":135},"2af955e1":{"m":134,"g":135},"0cd2b719":{"m":134,"g":135},"39d56196":{"m":134,"g":135},"41addd2e":{"m":134,"g":135},"5c393e81":{"m":134,"g":135},"3645ed0f":{"m":134,"g":135},"ca740a41":{"m":134,"g":135},"0e25aa43":{"m":134,"g":135},"60a230b1":{"m":134,"g":135},"aa89c6a7":{"m":134,"g":135},"171912a9":{"m":134,"g":135},"faecd37e":{"m":134,"g":135},"9ad546d7":{"m":134,"g":135},"29ce7b36":{"m":134,"g":135},"a8380ded":{"m":134,"g":135},"4edee695":{"m":134,"g":135},"67caea6f":{"m":134,"g":135},"cd3289c7":{"m":134,"g":135},"acddb8e0":{"m":134,"g":135},"2ec57cef":{"m":134,"g":135},"988b14ca":{"m":134,"g":135},"93495dca":{"m":134,"g":135},"886e0383":{"m":134,"g":135},"01bd0d3e":{"m":134,"g":135},"43e1bbc0":{"m":134,"g":135},"59b12996":{"m":134,"g":135},"b7091496":{"m":134,"g":135},"51dbdb22":{"m":134,"g":135},"8dc6f0fc":{"m":134,"g":135},"cf34d0ab":{"m":134,"g":135},"3778c2fc":{"m":134,"g":135},"5d421db8":{"m":134,"g":135},"fe3d47fc":{"m":134,"g":135},"ef92b4eb":{"m":134,"g":135},"73c0c66f":{"m":134,"g":135},"a1e9b4ed":{"m":134,"g":135},"e75657c8":{"m":134,"g":135},"c28c536c":{"m":134,"g":135},"086813ae":{"m":134,"g":135},"3fd232ad":{"m":134,"g":135},"cb181295":{"m":134,"g":135},"a91e072f":{"m":134,"g":135},"0271fc34":{"m":134,"g":135},"68bece8c":{"m":134,"g":135},"7b7e357f":{"m":134,"g":135},"2f66b067":{"m":134,"g":135},"48051181":{"m":134,"g":135},"f2ccc442":{"m":134,"g":135},"caa95c7e":{"m":134,"g":135},"9d878c1f":{"m":134,"g":135},"8087ef12":{"m":134,"g":135},"6ef543f9":{"m":134,"g":135},"a3559119":{"m":134,"g":135},"f3ba7116":{"m":134,"g":135},"5c243ba5":{"m":134,"g":135},"b6702d72":{"m":134,"g":135},"c1256727":{"m":134,"g":135},"bb9e6cdf":{"m":134,"g":135},"de03b0cd":{"m":134,"g":135},"2a8a7856":{"m":134,"g":135},"f4e835af":{"m":134,"g":135},"e6ce16a4":{"m":134,"g":135},"de2f2880":{"m":134,"g":135},"a89e85e7":{"m":134,"g":135},"cbf9f134":{"m":134,"g":135},"eb3da9c1":{"m":134,"g":135},"72a980c6":{"m":134,"g":135},"ccf2330b":{"m":134,"g":135},"b9af8d2e":{"m":134,"g":135},"10a9573e":{"m":134,"g":135},"49ab72f8":{"m":134,"g":135},"8865424f":{"m":134,"g":135},"b311c43d":{"m":134,"g":135},"0c39730b":{"m":134,"g":135},"45adad37":{"m":134,"g":135},"1ba897f3":{"m":134,"g":135},"38dd4fbb":{"m":134,"g":135},"ecd2d09a":{"m":134,"g":135},"92ddc468":{"m":134,"g":135},"5454d2a7":{"m":134,"g":133},"17b38f88":{"m":134,"g":133},"ae434f78":{"m":134,"g":133},"643aeefe":{"m":134,"g":133},"186a56f6":{"m":134,"g":133},"17e65466":{"m":134,"g":133},"370bd27f":{"m":134,"g":133},"b27b5a83":{"m":134,"g":133},"2f7c6292":{"m":134,"g":133},"2fb31605":{"m":134,"g":133},"8bf7f240":{"m":134,"g":133},"2c5679f3":{"m":134,"g":133},"159b1283":{"m":134,"g":133},"9338f63f":{"m":134,"g":133},"8196998a":{"m":134,"g":133},"aa21c6e3":{"m":134,"g":133},"fd4a558e":{"m":134,"g":133},"b3b818fd":{"m":134,"g":133},"d5fbbfd9":{"m":134,"g":133},"e245cac0":{"m":134,"g":133},"c6a6ba43":{"m":134,"g":133},"d6108166":{"m":134,"g":133},"ddb3970e":{"m":134,"g":133},"f65fa047":{"m":134,"g":133},"7e027691":{"m":134,"g":133},"cb719c74":{"m":134,"g":133},"ff903a7e":{"m":134,"g":133},"eee3700d":{"m":134,"g":133},"e254cdf3":{"m":134,"g":133},"dfb53574":{"m":134,"g":133},"96655749":{"m":134,"g":133},"ac320a6f":{"m":134,"g":133},"6292c244":{"m":134,"g":133},"5f5a5677":{"m":134,"g":133},"3bf07c68":{"m":134,"g":133},"e7b09efc":{"m":134,"g":133},"99d3bcdf":{"m":134,"g":133},"4d64f150":{"m":134,"g":133},"aef7ca7c":{"m":134,"g":133},"fe712aa3":{"m":134,"g":133},"846953d9":{"m":134,"g":133},"5c64a20d":{"m":134,"g":133},"cf817376":{"m":134,"g":133},"aa6ac966":{"m":134,"g":133},"0d0367e9":{"m":134,"g":133},"bd572360":{"m":134,"g":133},"5f3a47d8":{"m":134,"g":133},"80ae2229":{"m":134,"g":133},"705287b2":{"m":134,"g":133},"76284653":{"m":134,"g":133},"dd620987":{"m":134,"g":133},"53f974b9":{"m":134,"g":133},"6a5764a7":{"m":134,"g":133},"291f11ae":{"m":134,"g":133},"d7301c89":{"m":134,"g":133},"758b9067":{"m":134,"g":133},"ffc23ef8":{"m":134,"g":133},"b3f83cc1":{"m":134,"g":133},"c15fa1c5":{"m":134,"g":133},"fa296698":{"m":134,"g":133},"f9dd90ac":{"m":134,"g":133},"66902e0f":{"m":134,"g":133},"e50f356f":{"m":134,"g":133},"ac42797c":{"m":134,"g":133},"883747ce":{"m":134,"g":133},"989d4b30":{"m":134,"g":133},"bc3ca300":{"m":134,"g":133},"061f41af":{"m":134,"g":133},"82f1d615":{"m":134,"g":133},"5e1a495c":{"m":134,"g":133},"34013d9d":{"m":134,"g":133},"77597167":{"m":134,"g":133},"3c882db3":{"m":134,"g":133},"b736a152":{"m":134,"g":133},"6984837d":{"m":134,"g":133},"2142881b":{"m":134,"g":133},"d77f3fcc":{"m":134,"g":133},"828dec1c":{"m":134,"g":133},"575a49dc":{"m":134,"g":133},"e62e1744":{"m":134,"g":133},"d5431ff8":{"m":134,"g":133},"454a2544":{"m":134,"g":133},"89619a99":{"m":134,"g":133},"cb30d056":{"m":134,"g":133},"677930c2":{"m":134,"g":133},"beae3f96":{"m":134,"g":133},"1167867e":{"m":134,"g":133},"ad7f35fb":{"m":134,"g":133},"f4100732":{"m":134,"g":133},"468931b5":{"m":134,"g":133},"796969ca":{"m":134,"g":133},"122c2503":{"m":134,"g":133},"a3a55223":{"m":134,"g":133},"0bf95e6d":{"m":134,"g":133},"a92de891":{"m":134,"g":133},"b9d78605":{"m":134,"g":133},"1354063a":{"m":134,"g":133},"254de6d2":{"m":134,"g":133},"350fbbf4":{"m":134,"g":133},"a3912667":{"m":134,"g":133},"e1dcd0df":{"m":134,"g":133},"393e2f9b":{"m":134,"g":133},"8766a1dd":{"m":134,"g":133},"1d9ba2ce":{"m":134,"g":133},"ef001fb8":{"m":134,"g":133},"c69c1c4f":{"m":134,"g":133},"bed301a5":{"m":134,"g":133},"8fe3e374":{"m":134,"g":133},"60143655":{"m":134,"g":133},"fc05acc2":{"m":134,"g":133},"1ed94668":{"m":134,"g":133},"d7fbe73b":{"m":134,"g":133},"42bff706":{"m":134,"g":133},"26704c23":{"m":134,"g":133},"43b7c174":{"m":134,"g":133},"96740d69":{"m":134,"g":133},"9a3bdf2c":{"m":134,"g":133},"4b351f6b":{"m":134,"g":133},"7fa4906f":{"m":134,"g":133},"050f108c":{"m":134,"g":133},"47cdb65a":{"m":134,"g":133},"1d90b194":{"m":134,"g":133},"537ef18d":{"m":134,"g":133},"69412ccb":{"m":134,"g":133},"d3885d4b":{"m":134,"g":133},"0a346d3b":{"m":134,"g":133},"bc18cb86":{"m":134,"g":133},"bee8ac5b":{"m":134,"g":133},"41bd76e1":{"m":134,"g":133},"c6ca1b3a":{"m":134,"g":133},"8999ce75":{"m":134,"g":133},"dce2ed44":{"m":134,"g":133},"019517a3":{"m":134,"g":133},"1f1f05a8":{"m":134,"g":133},"165f5c04":{"m":134,"g":133},"3e01f3a5":{"m":134,"g":133},"51e2eaa4":{"m":134,"g":133},"6468cb58":{"m":134,"g":133},"e220da17":{"m":134,"g":133},"b82c7a0a":{"m":134,"g":133},"c0f9b519":{"m":134,"g":133},"5529ab58":{"m":134,"g":133},"74a3349b":{"m":134,"g":133},"b9ebf0ed":{"m":134,"g":133},"3c116d5e":{"m":134,"g":133},"71a60288":{"m":134,"g":133},"61405b3d":{"m":134,"g":133},"0adfc42b":{"m":134,"g":133},"ba72e759":{"m":134,"g":133},"6afc5d49":{"m":134,"g":133},"2ee6c810":{"m":134,"g":133},"bd16244d":{"m":134,"g":133},"b5eb0214":{"m":134,"g":133},"d72e908b":{"m":134,"g":133},"50cad014":{"m":134,"g":133},"ef908aeb":{"m":134,"g":133},"9d0347b3":{"m":134,"g":133},"05eb0bcc":{"m":134,"g":133},"5dccd9bd":{"m":134,"g":133},"933cef16":{"m":134,"g":133},"241ae17b":{"m":134,"g":133},"2c5a4460":{"m":134,"g":133},"f3705b01":{"m":134,"g":133},"5a0ad731":{"m":134,"g":133},"5045aa34":{"m":134,"g":133},"ff1e2ce2":{"m":134,"g":133},"1e582488":{"m":134,"g":133},"46be74b4":{"m":134,"g":133},"1c658026":{"m":134,"g":133},"ba410808":{"m":134,"g":133},"89512029":{"m":134,"g":133},"92e6b3c3":{"m":134,"g":133},"6559e43f":{"m":134,"g":133},"af780c59":{"m":134,"g":133},"a21aa87e":{"m":134,"g":133},"fb178457":{"m":134,"g":133},"65c09859":{"m":134,"g":133},"4bf06635":{"m":134,"g":133},"f2d64e67":{"m":134,"g":133},"0e869f08":{"m":134,"g":133},"17394092":{"m":134,"g":133},"f228b662":{"m":134,"g":133},"a36142aa":{"m":134,"g":133},"160a06ca":{"m":134,"g":133},"a0985dd5":{"m":134,"g":133},"f6c9db4b":{"m":134,"g":133},"e88e75a9":{"m":134,"g":133},"4b4050e2":{"m":134,"g":133},"b2803ff2":{"m":134,"g":133},"9e0ef04e":{"m":134,"g":133},"216067c0":{"m":134,"g":133},"e72b02db":{"m":134,"g":133},"29e8f7f9":{"m":134,"g":133},"e0963a6c":{"m":134,"g":133},"e0026f7c":{"m":134,"g":133},"9749d3e3":{"m":134,"g":133},"2b0ddf89":{"m":134,"g":133},"17e81c75":{"m":134,"g":133},"88a405cc":{"m":134,"g":133},"602fe3b2":{"m":134,"g":133},"ad9616f1":{"m":134,"g":133},"c5f4e20f":{"m":134,"g":133},"2c196f95":{"m":134,"g":133},"9a7641d7":{"m":134,"g":133},"793c96c3":{"m":134,"g":133},"d1f00632":{"m":134,"g":133},"4792d1f4":{"m":134,"g":133},"fea2d521":{"m":134,"g":133},"56d12b4a":{"m":134,"g":133},"374ad4cc":{"m":134,"g":133},"8b0a68f1":{"m":134,"g":133},"70607e55":{"m":134,"g":133},"ee1ca51d":{"m":134,"g":133},"ef7c29ac":{"m":134,"g":133},"58c840db":{"m":134,"g":133},"3d42b7e7":{"m":134,"g":133},"9970ee34":{"m":134,"g":133},"9e7656be":{"m":134,"g":133},"9d4f066f":{"m":134,"g":133},"41683536":{"m":134,"g":133},"891ee822":{"m":134,"g":133},"8fa3dc36":{"m":134,"g":133},"d20699a3":{"m":134,"g":133},"169a75df":{"m":134,"g":133},"4128d4f5":{"m":134,"g":133},"011d8d89":{"m":134,"g":133},"5290cef9":{"m":134,"g":133},"726fe3e7":{"m":134,"g":133},"5d087891":{"m":134,"g":133},"8451e227":{"m":134,"g":133},"53e15194":{"m":134,"g":133},"d747147a":{"m":134,"g":133},"0c002207":{"m":134,"g":133},"eeb2b9b2":{"m":134,"g":133},"c4aed389":{"m":134,"g":133},"9d04b570":{"m":134,"g":133},"3e690cce":{"m":134,"g":133},"b12b40de":{"m":134,"g":133},"6c4bf8a0":{"m":134,"g":133},"533851fb":{"m":134,"g":133},"0071fe9c":{"m":134,"g":133},"ffa7e035":{"m":134,"g":133},"712f44ee":{"m":134,"g":133},"8c34e181":{"m":134,"g":133},"e9abb525":{"m":134,"g":133},"88859433":{"m":134,"g":133},"feb8e30b":{"m":134,"g":133},"45a959d3":{"m":134,"g":133},"cdce5163":{"m":134,"g":133},"79ab57bd":{"m":134,"g":133},"4b8901ac":{"m":134,"g":133},"435d1c83":{"m":134,"g":133},"2bdbaef1":{"m":134,"g":133},"31d48d7f":{"m":134,"g":133},"0129c911":{"m":134,"g":133},"03f9eb25":{"m":134,"g":133},"7ec678eb":{"m":134,"g":133},"9d64a7b2":{"m":134,"g":133},"46ad4b98":{"m":134,"g":133},"71cb9037":{"m":134,"g":133},"c8c64876":{"m":134,"g":133},"0861dca8":{"m":134,"g":133},"da58df6b":{"m":134,"g":133},"49237e26":{"m":134,"g":133},"d92c1f8c":{"m":134,"g":133},"93070586":{"m":134,"g":133},"ccc8f3b2":{"m":134,"g":133},"a4c76281":{"m":134,"g":133},"28a19e49":{"m":134,"g":133},"0261c4af":{"m":134,"g":133},"8ac350f3":{"m":134,"g":133},"99401e7b":{"m":134,"g":133},"66824751":{"m":134,"g":133},"f95729b0":{"m":134,"g":133},"9f4ed93d":{"m":134,"g":133},"ecb401ed":{"m":134,"g":133},"b399e3ac":{"m":134,"g":133},"e27635a0":{"m":134,"g":133},"272c5fe4":{"m":134,"g":133},"3c8dc448":{"m":134,"g":133},"5e96beb3":{"m":134,"g":133},"9327482b":{"m":134,"g":133},"36fcf71f":{"m":134,"g":133},"6292d971":{"m":134,"g":133},"c8434195":{"m":134,"g":133},"3e4d431a":{"m":134,"g":133},"538e733e":{"m":134,"g":133},"22587bc0":{"m":134,"g":133},"02d24244":{"m":134,"g":133},"1da5cd63":{"m":134,"g":133},"a9a2cdd8":{"m":134,"g":133},"4733fcff":{"m":134,"g":133},"3ffa2604":{"m":134,"g":133},"61f362c6":{"m":134,"g":133},"e7157c9b":{"m":134,"g":133},"30da2f05":{"m":134,"g":133},"49016931":{"m":134,"g":133},"3d484be5":{"m":134,"g":133},"c0d94440":{"m":134,"g":133},"1dedb638":{"m":134,"g":133},"7bc8b153":{"m":134,"g":133},"9003a436":{"m":134,"g":133},"3518b331":{"m":134,"g":133},"b098b1ae":{"m":134,"g":133},"abd3e048":{"m":134,"g":133},"92c29d43":{"m":134,"g":133},"bf643814":{"m":134,"g":133},"f03bfa4c":{"m":134,"g":133},"89ad3908":{"m":134,"g":133},"2ea844ec":{"m":134,"g":133},"1e2d7538":{"m":134,"g":133},"d16ff357":{"m":134,"g":133},"af49e302":{"m":134,"g":133},"01b955ac":{"m":134,"g":133},"16e6bc20":{"m":134,"g":133},"37250764":{"m":134,"g":133},"7b9156c7":{"m":134,"g":133},"21cfebac":{"m":134,"g":133},"702426b0":{"m":134,"g":133},"9e9a6169":{"m":134,"g":133},"bd9c3a47":{"m":134,"g":133},"1e641ee4":{"m":134,"g":133},"fb96669f":{"m":134,"g":133},"3912ee49":{"m":134,"g":133},"1ab9b8e0":{"m":134,"g":133},"e61dabf5":{"m":134,"g":133},"36e7c8c5":{"m":134,"g":133},"037c3982":{"m":134,"g":133},"62b3fdae":{"m":134,"g":133},"1cd0c3bf":{"m":134,"g":133},"2c899431":{"m":134,"g":133},"4513f549":{"m":134,"g":133},"c9690307":{"m":134,"g":133},"4449c170":{"m":134,"g":133},"5ca962ce":{"m":134,"g":133},"bab20a84":{"m":134,"g":133},"0e4108ba":{"m":134,"g":133},"99cb2ed9":{"m":134,"g":133},"0612175c":{"m":134,"g":133},"8c96fcda":{"m":134,"g":133},"ea7c69ce":{"m":134,"g":133},"8102e36b":{"m":134,"g":133},"3f048217":{"m":134,"g":133},"b11af135":{"m":134,"g":133},"f9bceea0":{"m":134,"g":133},"997ea57e":{"m":134,"g":133},"47633c19":{"m":134,"g":133},"64b5c3ab":{"m":134,"g":133},"d277a86d":{"m":134,"g":133},"9acb21ae":{"m":134,"g":133},"a9ce1623":{"m":134,"g":133},"6f0c77d7":{"m":134,"g":133},"e3f51e82":{"m":134,"g":133},"fdfabb7a":{"m":134,"g":133},"19c16748":{"m":134,"g":133},"5c75907e":{"m":134,"g":133},"4ea36422":{"m":134,"g":133},"f50af32d":{"m":134,"g":133},"72952919":{"m":134,"g":133},"2ae5bed1":{"m":134,"g":133},"54df514b":{"m":134,"g":133},"681c68cf":{"m":134,"g":133},"74ea45cc":{"m":134,"g":133},"0fa044ad":{"m":134,"g":133},"7d8e42c9":{"m":134,"g":133},"6abdf73f":{"m":134,"g":133},"20ce9938":{"m":134,"g":133},"168a31eb":{"m":134,"g":133},"69cfb17b":{"m":134,"g":133},"a7a4b175":{"m":134,"g":133},"fdc93b01":{"m":134,"g":133},"fd37cc5d":{"m":134,"g":133},"96705514":{"m":134,"g":133},"ab3ffd1c":{"m":134,"g":133},"2285afff":{"m":134,"g":133},"a81cc1b8":{"m":134,"g":133},"3134d2b2":{"m":134,"g":133},"06b58c5d":{"m":134,"g":133},"ea07a283":{"m":134,"g":133},"ea91a720":{"m":134,"g":133},"5d9c6bac":{"m":134,"g":133},"e048ee90":{"m":134,"g":133},"ed52d01b":{"m":134,"g":133},"90e7d4f7":{"m":134,"g":133},"c20d43d2":{"m":134,"g":133},"d977dd2e":{"m":134,"g":133},"0c23331e":{"m":134,"g":133},"993278b4":{"m":134,"g":133},"9e9d9107":{"m":134,"g":133},"3b8a824b":{"m":134,"g":133},"f1bbd26f":{"m":134,"g":133},"d36299ad":{"m":134,"g":133},"0e7d7969":{"m":134,"g":133},"80554598":{"m":134,"g":133},"b2e240bc":{"m":134,"g":133},"dcc5f5c0":{"m":134,"g":133},"4eda4194":{"m":134,"g":133},"875f84db":{"m":134,"g":133},"f6031adf":{"m":134,"g":133},"2a39cfe0":{"m":134,"g":133},"bf17e769":{"m":134,"g":133},"9a5d6a84":{"m":134,"g":133},"31c23e5f":{"m":134,"g":133},"06617a9e":{"m":134,"g":133},"e79ca959":{"m":134,"g":133},"9d3b411c":{"m":134,"g":133},"05325db3":{"m":134,"g":133},"01e3b3f3":{"m":134,"g":133},"86988674":{"m":134,"g":133},"29139654":{"m":134,"g":133},"665cb020":{"m":134,"g":133},"71602838":{"m":134,"g":133},"77873343":{"m":134,"g":133},"267170bf":{"m":134,"g":133},"313f59ad":{"m":134,"g":133},"487cf81a":{"m":134,"g":133},"df111bc0":{"m":134,"g":133},"6d2b3324":{"m":134,"g":133},"8cc77261":{"m":134,"g":133},"d143b020":{"m":134,"g":133},"9b9d2131":{"m":134,"g":133},"44fd7017":{"m":134,"g":133},"9a56273a":{"m":134,"g":133},"b737a125":{"m":134,"g":133},"1b5e9034":{"m":134,"g":133},"171b442a":{"m":134,"g":133},"4b7b5af3":{"m":134,"g":133},"ec242f51":{"m":134,"g":133},"b2431546":{"m":134,"g":133},"526fd008":{"m":134,"g":133},"56d0ad47":{"m":134,"g":133},"306e5b8d":{"m":134,"g":133},"10c68f62":{"m":134,"g":133},"c7c837cd":{"m":134,"g":133},"3e1e7157":{"m":134,"g":133},"8fa8d9d7":{"m":134,"g":133},"c8cf1caf":{"m":134,"g":133},"d71baa72":{"m":134,"g":133},"82e33170":{"m":134,"g":133},"94e12511":{"m":134,"g":133},"4dabfbc8":{"m":134,"g":133},"d7ed8a8c":{"m":134,"g":133},"c05d3afb":{"m":134,"g":133},"edb172e9":{"m":134,"g":133},"fe6d38d2":{"m":134,"g":133},"dab31e4c":{"m":134,"g":133},"a7fa31ff":{"m":134,"g":133},"bd91f882":{"m":134,"g":133},"b47adb80":{"m":134,"g":133},"b2b5bdb0":{"m":134,"g":133},"22fe5da1":{"m":134,"g":133},"1834401e":{"m":134,"g":133},"198c8ecf":{"m":134,"g":133},"c01b2ee0":{"m":134,"g":133},"8f5adac8":{"m":134,"g":133},"76743a98":{"m":134,"g":133},"8bf10e71":{"m":134,"g":133},"e4873d04":{"m":134,"g":133},"c660d8df":{"m":134,"g":133},"10146af0":{"m":134,"g":133},"b62e7e3b":{"m":134,"g":133},"6ce36b12":{"m":134,"g":133},"e9e7f15e":{"m":134,"g":133},"0aa3dec5":{"m":134,"g":133},"4885f8b9":{"m":134,"g":133},"f832994c":{"m":134,"g":133},"e59435c3":{"m":134,"g":133},"d6bd2d11":{"m":134,"g":133},"9975acf5":{"m":134,"g":133},"70758d45":{"m":134,"g":133},"fd1ebbb0":{"m":134,"g":133},"3d98bd5e":{"m":134,"g":133},"aa3716b2":{"m":134,"g":133},"6107268f":{"m":134,"g":133},"0189f41c":"m136","b6e4893a":"m136","3eb7da53":"m136","cb53ddc9":"m136","0c265321":"m136","6469c964":"m136","71705394":"m136","67589c16":"m136","a702c8f1":"m136","f2ae066a":"m136","0c2993ee":"m136","590969ee":"m136","e6ccb294":"m136","d6ea2c52":"m136","9be2a3a9":"m136","b74a57a8":"m136","95f59c13":"m136","85d9af51":"m136","858f317f":"m136","cf893516":"m136","1fdf5cac":"m136","cda43ffa":"m136","39089854":"m136","b827e9d3":"m136","d725487d":"m136","a95c9f5b":"m136","19089aa4":"m136","4f6f5d25":"m136","458fe5a3":"m136","2ff0880a":"m136","2c1b164a":"m136","bcc6d84f":"m136","a618202f":"m136","7520b929":"m136","e7224e96":"m136","e776239a":"m136","1b97fa76":"m136","236772c0":"m136","0d49b13f":"m136","0a7a2017":"m136","0a9099e1":"m136","0050c476":"m136","8251a74d":"m136","a54d75bf":"m136","3321eb4e":"m136","be5121b4":"m136","c3f9c30f":"m136","54a82179":"m136","aca354bc":"m136","aea57b33":"m136","823a046e":"m136","648aab0c":"m136","1e309030":"m136","60927215":"m136","38c233fd":"m136","20ed3822":"m136","4ecd9afd":"m136","eb38d644":"m136","6ea491e4":"m136","16802fb6":"m136","d97066d2":"m136","ce2d686e":"m136","76b06bee":"m136","612026ad":"m136","55c61642":"m136","91a4cd86":"m136","23d765d1":"m136","db2425a0":"m136","603f386c":"m136","f7a5e425":"m136","d50dcd9b":"m136","e6b7c049":"m136","a3addd62":"m136","6988a0f5":"m136","1b192cf1":"m136","c560e142":"m136","71cb9d03":"m136","8fb45523":"m136","84aef378":"m136","17c04b10":"m136","55c4288b":"m136","9f8b79f1":"m136","7dc3cbe7":"m136","79ddc34c":"m136","09a9d214":"m136","7e40d526":"m136","057b07fc":"m136","91d8c52d":"m136","e9a44ea6":"m136","c1282da2":"m136","71279e31":"m136","1a053a81":"m136","2ea02f06":"m136","20b0523e":"m136","ce8a6ac6":"m136","ebca5879":"m136","cc410a10":"m136","f374623f":"m136","5c022177":"m136","8916b9d0":"m136","a3d9a218":"m136","fb88fb67":"m136","2d72e168":"m136","64946679":"m136","5836324c":"m136","9fe56cd0":"m136","858a4d65":"m136","e619f531":"m136","fc4b932f":"m136","d2105d4a":"m136","84c83905":"m136","ea879c77":"m136","0227db89":"m136","ad1b4e47":"m136","51f147ad":"m136","d3eafc73":"m136","e00b4344":"m136","733de6be":"m136","93433726":"m136","330605cc":"m136","bb6055b4":"m136","4df74eb5":"m136","f3a7c7dc":"m136","2069050d":"m136","1fe0c82f":"m136","a45e0e5d":"m136","f78201f3":"m136","8fd33998":"m136","088758c1":"m136","6d29d8ab":"m136","e499258e":"m136","09491a9b":"m136","7edb0615":"m136","e486a4da":"m136","90399cbc":"m136","53609e5e":"m136","9c253064":"m136","d2c86387":"m136","737a1183":"m136","dc743fe4":"m136","dd99f818":"m136","8ce64aa1":"m136","eb768189":"m136","2cdd4370":"m136","a7b5f75d":"m136","305c1a57":"m136","c824ddd5":"m136","e18e0057":"m136","166396ca":"m136","43779f27":"m136","8b9e9357":"m136","d36f6f04":"m136","b0701f02":"m136","4229de3b":"m136","2e144079":"m136","d2ec128b":"m136","7f8353af":"m136","a7f5677a":"m136","3e968ab3":"m136","b4fce995":"m136","ec9b48ea":"m136","a0467589":"m136","82a1b645":"m136","6f10e17b":"m136","c771933d":"m136","9d8bbd42":"m136","daea5138":"m136","3355b6e2":"m136","a1dd3d48":"m136","d9ed80b9":"m136","7c39ea68":"m136","daa4841e":"m136","968c4f55":"m136","669d309a":"m136","21ee597e":"m136","6ee970a3":"m136","8ec160ed":"m136","2740ed1a":"m136","d44f09ad":"m136","e7dc85c5":"m136","c81bad1b":"m136","0e86de7c":"m136","e3a95077":"m136","146b5fcc":"m136","8b22deef":"m136","69822c72":"m136","8b99af9a":"m136","72e2f70e":"m136","3d72944f":"m136","7dde3438":"m136","77fc4c4a":"m136","655d2c7c":"m136","3f44268f":"m136","f7ec8174":"m136","cd23c2f0":"m136","d1110e1c":"m136","9227d9f6":"m136","4c59782e":"m136","dda35ccb":"m136","d11e2dc6":"m136","16831ab6":"m136","c9a45b7e":"m136","e7df8bdc":"m136","e9979950":"m136","6586f44a":"m136","43fe3a4d":"m136","98096b5e":"m136","68e8d0f6":"m136","000ad422":"m136","9d5f16d4":"m136","7f8a58ff":"m136","6b065298":"m136","c020d300":"m136","4346db5f":"m136","424a3800":"m136","f0918583":"m136","5b1215d9":"m136","aa2b4f76":"m136","b3a3f513":"m136","de94d793":"m136","0d904ef4":"m136","969faaa4":"m136","48c2aca9":"m136","5af84c8a":"m136","feae615b":"m136","e75299a1":"m136","72bacc88":"m136","ba625c2d":"m136","b025cff4":"m136","030496eb":"m136","c86ca128":"m136","cd336945":"m136","c5e363e8":"m136","9479eca7":"m136","a5348eac":"m136","95240402":"m136","2122fea3":"m136","e2c8a50b":"m136","a4825ed5":"m136","afe285f7":"m136","cf25852a":"m136","5938c3b0":"m136","b8806071":"m136","339915ce":"m136","075c5a57":"m136","a0b4ba90":"m136","2a7b67ad":"m136","1d811094":"m136","2ab3ed3e":"m136","250477d2":"m136","af1232b2":"m136","7a869045":"m136","888d7e54":"m136","3cb1fbae":"m136","ba9f6d8f":"m136","740d3c0b":"m136","87165898":"m136","ff3ddb9d":"m136","9d3018f4":"m136","a8348427":"m136","47d485f3":"m136","2b423099":"m136","ae0baefb":"m136","1f0e3d7f":"m136","d3c08fb0":"m136","c6a64e9f":"m136","e0ac559a":"m136","6620548f":"m136","6e158e55":"m136","ed729d22":"m136","fa51b854":"m136","559ff9ec":"m136","7b682de8":"m136","d0092dec":"m136","76f69b77":"m136","9a628744":"m136","53dca74f":"m136","2dadf635":"m136","aab640c9":"m136","2b3791ed":"m136","9f5cd80a":"m136","b1ee75ae":"m136","f44c63ee":"m136","c54c70ab":"m136","aab906a3":"m136","feb39f77":"m136","38b30c7b":"m136","c581b5ed":"m136","a1c48943":"m136","5b7bed7c":"m136","38a88479":"m136","503c3d95":"m136","934ae89a":"m136","cf1426a7":"m136","17cb3c8e":"m136","2f4a6add":"m136","f9fc50ac":"m136","3c16c586":"m136","7b089ae4":"m136","8b5d4263":"m136","b5493f65":"m136","09e2571e":"m136","c0248d6f":"m136","cc25f9df":"m136","cf14feba":"m136","7c25687c":"m136","ff978142":"m136","d112f6a2":"m136","a2c2c09d":"m136","2a9344d3":"m136","78c41758":"m136","206db66f":"m136","5c72be1e":"m136","76d48817":"m136","d1ec93e3":"m136","bdb76b34":"m136","dae6a409":"m136","a0899bdb":"m136","641830c1":"m136","3fd88ea9":"m136","145bd54f":"m136","2d088b85":"m136","3a8b44fe":"m136","aeb480c1":"m136","9fd2358c":"m136","3c358736":"m136","6327dff2":"m136","675acece":"m136","ad201273":"m136","7f393d95":"m136","4b14f622":"m136","94fc26aa":"m136","67b61a4e":"m136","d27f16f3":"m136","c89949bb":"m136","20abaee2":"m136","32a569fb":"m136","3ed3b7ef":"m136","1f9d4795":"m136","e6d40bff":"m136","fbc128a3":"m136","9c64a15a":"m136","e91a7176":"m136","1f0ea4f9":"m136","15da3061":"m136","6406a596":"m136","cec19b56":"m136","ef35d8fe":"m136","08636f72":"m136","a6c29d4c":"m136","84ab32a2":"m136","70667115":"m136","bd1afeb5":"m136","8ef5b905":"m136","76b3c698":"m136","5dcff947":"m136","8eeffbe9":"m136","71e9c31c":"m136","7656d267":"m136","dd24ba90":"m136","068abe7e":"m136","64a31d4b":"m136","2babf88f":"m136","d56d14e5":"m136","0c4e155a":"m136","d6d5c3fd":"m136","e46f7943":"m136","9d4d57db":"m136","41609b52":"m136","ccd0fb32":"m136","87ee6b5e":"m136","f7c1d24b":"m136","cceb5e6a":"m136","c1c13c84":"m136","fcec35dc":"m136","75da784d":"m136","77d35665":"m136","05dfef92":"m136","74602407":{"m":136,"g":135},"f7f5c389":{"m":136,"g":135},"9e3a032a":{"m":136,"g":135},"1bc7aa58":{"m":136,"g":135},"8726d30c":{"m":136,"g":135},"a1b243d7":{"m":136,"g":135},"a9799277":{"m":136,"g":135},"ee71e773":{"m":136,"g":135},"55a8dd00":{"m":136,"g":135},"cf242321":{"m":136,"g":135},"9d03af91":{"m":136,"g":135},"064ae341":{"m":136,"g":135},"49305fa1":{"m":136,"g":135},"4e999404":{"m":136,"g":135},"fbc24886":{"m":136,"g":135},"16880235":{"m":136,"g":135},"cda35611":{"m":136,"g":135},"8a45a9c6":{"m":136,"g":135},"aecd5f5f":{"m":136,"g":135},"05ab110e":{"m":136,"g":135},"c8dc4d2d":{"m":136,"g":135},"82a8d77b":{"m":136,"g":135},"294ff71d":{"m":136,"g":135},"f52ae586":{"m":136,"g":135},"2f8a3634":{"m":136,"g":135},"b6e8a0d8":{"m":136,"g":135},"fb7609f1":{"m":136,"g":135},"d2ea44f7":{"m":136,"g":135},"20ca2c6e":{"m":136,"g":135},"83abecd0":{"m":136,"g":135},"d54f0a10":{"m":136,"g":135},"fb04e7e3":{"m":136,"g":135},"1e5de05e":{"m":136,"g":135},"7dd679cb":{"m":136,"g":135},"3d51ae18":{"m":136,"g":135},"f9c04266":{"m":136,"g":135},"48b8dcd4":{"m":136,"g":135},"41b434a7":{"m":136,"g":135},"4935344f":{"m":136,"g":135},"63cc97f4":{"m":136,"g":135},"ab7d5829":{"m":136,"g":135},"261860e1":{"m":136,"g":135},"154740bd":{"m":136,"g":135},"1c09cbe3":{"m":136,"g":135},"e14f5ec8":{"m":136,"g":135},"8867d248":{"m":136,"g":135},"6b3f93c4":{"m":136,"g":135},"5a5cece5":{"m":136,"g":135},"d566739b":{"m":136,"g":135},"4c46ecde":{"m":136,"g":135},"12a0292b":{"m":136,"g":135},"a08dc5aa":{"m":136,"g":135},"eec7dbd3":{"m":136,"g":135},"109fe03a":{"m":136,"g":135},"bb798a1c":{"m":136,"g":135},"38dc5839":{"m":136,"g":135},"5e867f60":{"m":136,"g":135},"65bed838":{"m":136,"g":135},"156d97b2":{"m":136,"g":135},"24b30f77":{"m":136,"g":135},"3a4767da":{"m":136,"g":135},"6037267f":{"m":136,"g":135},"0241e046":{"m":136,"g":135},"0c474273":{"m":136,"g":135},"3e73e124":{"m":136,"g":135},"f4742558":{"m":136,"g":135},"7385834c":{"m":136,"g":135},"b5a94f8a":{"m":136,"g":135},"c356ed03":{"m":136,"g":135},"ee4d2287":{"m":136,"g":135},"153c69f6":{"m":136,"g":135},"55b79365":{"m":136,"g":135},"7fc12e0b":{"m":136,"g":135},"8729ad5e":{"m":136,"g":135},"e4320573":{"m":136,"g":135},"4d902c82":{"m":136,"g":135},"2ff87231":{"m":136,"g":135},"fd16c91c":{"m":136,"g":135},"32a6540a":{"m":136,"g":135},"62d0280f":{"m":136,"g":135},"d4b717c0":{"m":136,"g":135},"98a107d4":{"m":136,"g":135},"b86bbf84":{"m":136,"g":135},"48381c3b":{"m":136,"g":135},"8bce0853":{"m":136,"g":135},"6b8a9d70":{"m":136,"g":135},"973116e6":{"m":136,"g":135},"820e97d6":{"m":136,"g":135},"4c85f9d0":{"m":136,"g":135},"7d757d6f":{"m":136,"g":135},"5c04088b":{"m":136,"g":135},"f066036c":{"m":136,"g":135},"52de807d":{"m":136,"g":135},"70933f34":{"m":136,"g":135},"ce453fa4":{"m":136,"g":135},"3be1e734":{"m":136,"g":135},"38895a00":{"m":136,"g":135},"d8b81981":{"m":136,"g":135},"913b688f":{"m":136,"g":135},"951d16c8":{"m":136,"g":135},"53846746":{"m":136,"g":135},"534ac384":{"m":136,"g":135},"2a8d5493":{"m":136,"g":135},"90eac38a":{"m":136,"g":135},"badcd028":{"m":136,"g":135},"d874c8bb":{"m":136,"g":135},"9a21d89c":{"m":136,"g":135},"4c9ac856":{"m":136,"g":135},"fb5b71d0":{"m":136,"g":135},"05b54b6d":{"m":136,"g":135},"4f443f44":{"m":136,"g":135},"dce8b060":{"m":136,"g":135},"399d5283":{"m":136,"g":135},"2e0527dd":{"m":136,"g":135},"6beb50d6":{"m":136,"g":135},"18e2ef09":{"m":136,"g":135},"3271e0e7":{"m":136,"g":135},"d415d22d":{"m":136,"g":135},"a49b9a64":{"m":136,"g":135},"53497642":{"m":136,"g":135},"d57d8e7e":{"m":136,"g":135},"0cbd8f32":{"m":136,"g":135},"6e3fff13":{"m":136,"g":135},"2210155a":{"m":136,"g":135},"a3656cbb":{"m":136,"g":135},"21da2dc1":{"m":136,"g":135},"ed307a40":{"m":136,"g":135},"02722b91":{"m":136,"g":135},"f959250f":{"m":136,"g":135},"95934379":{"m":136,"g":135},"bc2f40be":{"m":136,"g":135},"2724b110":{"m":136,"g":135},"176266f3":{"m":136,"g":135},"5e5b1183":{"m":136,"g":135},"9bf76c11":{"m":136,"g":135},"1d7ad4af":{"m":136,"g":135},"fba785c4":{"m":136,"g":135},"5cfa901b":{"m":136,"g":135},"f27c6cdc":{"m":136,"g":135},"5097e1e8":{"m":136,"g":135},"861a35fb":{"m":136,"g":135},"6ffe1fc0":{"m":136,"g":135},"73398e22":{"m":136,"g":135},"17958c5f":{"m":136,"g":135},"3aa11ca7":{"m":136,"g":135},"7be1a8c7":{"m":136,"g":135},"84d13c54":{"m":136,"g":135},"c80c0e0f":{"m":136,"g":135},"c105a312":{"m":136,"g":135},"4cf2bbd0":{"m":136,"g":135},"d7b706be":{"m":136,"g":135},"4a9537a4":{"m":136,"g":135},"ca922d4b":{"m":136,"g":135},"402a0bd6":{"m":136,"g":135},"76c71d1d":{"m":136,"g":135},"2d02c150":{"m":136,"g":135},"b98bd9a5":{"m":136,"g":135},"ce694b2b":{"m":136,"g":135},"6c0fb189":{"m":136,"g":135},"9a9f996f":{"m":136,"g":135},"4221b7c5":{"m":136,"g":135},"c371df2f":{"m":136,"g":135},"1751c75b":{"m":136,"g":135},"23849eba":{"m":136,"g":135},"51541404":{"m":136,"g":135},"45ef8344":{"m":136,"g":135},"5a2b1ed4":{"m":136,"g":135},"454dc9e2":{"m":136,"g":135},"1e41069a":{"m":136,"g":135},"2b4d6d81":{"m":136,"g":135},"a3914e3b":{"m":136,"g":135},"130f60ee":{"m":136,"g":135},"4397cda7":{"m":136,"g":135},"d56fd10c":{"m":136,"g":135},"abb06be9":{"m":136,"g":135},"c35eb0fd":{"m":136,"g":135},"7f35c46e":{"m":136,"g":135},"da2f8cc3":{"m":136,"g":135},"4308c25b":{"m":136,"g":135},"4d737db8":{"m":136,"g":135},"9d6029fb":{"m":136,"g":135},"dcfb92dd":{"m":136,"g":135},"bebd625b":{"m":136,"g":135},"b12258bf":{"m":136,"g":135},"012dc586":{"m":136,"g":135},"7f6a678f":{"m":136,"g":135},"399ca037":{"m":136,"g":135},"d93f37a6":{"m":136,"g":135},"e6fe092d":{"m":136,"g":135},"f02d8221":{"m":136,"g":135},"10174e11":{"m":136,"g":135},"2138ff48":{"m":136,"g":135},"e53160bb":{"m":136,"g":135},"4ea6a11c":{"m":136,"g":135},"2181bc9e":{"m":136,"g":135},"520c048d":{"m":136,"g":135},"561a3e04":{"m":136,"g":135},"f84487af":{"m":136,"g":135},"07827047":{"m":136,"g":135},"c63e9cb2":{"m":136,"g":135},"12cde0df":{"m":136,"g":135},"a7fd8108":{"m":136,"g":135},"ca80c19b":{"m":136,"g":135},"1e7b3264":{"m":136,"g":135},"e267ca0b":{"m":136,"g":135},"9a8ba3c1":{"m":136,"g":135},"0fee6bc6":{"m":136,"g":135},"0ff3747c":{"m":136,"g":135},"f8411ded":{"m":136,"g":135},"249c3563":{"m":136,"g":135},"12df1660":{"m":136,"g":135},"55d112dc":{"m":136,"g":135},"a1ed247f":{"m":136,"g":135},"87699d48":{"m":136,"g":135},"52c60434":{"m":136,"g":135},"ff0f370f":{"m":136,"g":135},"26f9e207":{"m":136,"g":135},"828cd893":{"m":136,"g":135},"4436dc0f":{"m":136,"g":135},"cf6800f6":{"m":136,"g":135},"f16606d6":{"m":136,"g":135},"387fad2f":{"m":136,"g":135},"76bc07a3":{"m":136,"g":135},"b328cd20":{"m":136,"g":135},"bf32cd83":{"m":136,"g":135},"27a08305":{"m":136,"g":135},"53479e22":{"m":136,"g":135},"ff978e7d":{"m":136,"g":135},"16e00651":{"m":136,"g":135},"1b2b95d8":{"m":136,"g":135},"9cac3c86":{"m":136,"g":135},"8d58b3dc":{"m":136,"g":135},"5f3eb377":{"m":136,"g":135},"22993880":{"m":136,"g":135},"d7aa0ce7":{"m":136,"g":135},"e797f0c5":{"m":136,"g":135},"5d4b7c78":{"m":136,"g":135},"9bd64d73":{"m":136,"g":135},"24e116ef":{"m":136,"g":135},"8ca95970":{"m":136,"g":135},"216ea910":{"m":136,"g":135},"f4ab2ec5":{"m":136,"g":135},"25fa2ac2":{"m":136,"g":135},"ef5ac6f0":{"m":136,"g":135},"c88aaf22":{"m":136,"g":135},"e139d2aa":{"m":136,"g":135},"2337b1bb":{"m":136,"g":135},"7bc13c90":{"m":136,"g":135},"877c8e3a":{"m":136,"g":135},"66dfb8c1":{"m":136,"g":135},"dcacc492":{"m":136,"g":135},"87ef05e2":{"m":136,"g":135},"b65c9889":{"m":136,"g":135},"c7c0d97f":{"m":136,"g":135},"6bc5a52f":{"m":136,"g":135},"2c09de34":{"m":136,"g":135},"38d48de9":{"m":136,"g":135},"7f2fa216":{"m":136,"g":135},"d0fb24ee":{"m":136,"g":135},"65b0b5b2":{"m":136,"g":135},"9a414b16":{"m":136,"g":135},"5b4f7902":{"m":136,"g":135},"d8ac5eec":{"m":136,"g":135},"bdde9496":{"m":136,"g":135},"b23e7ed1":{"m":136,"g":135},"9821fae5":{"m":136,"g":135},"078d9621":{"m":136,"g":135},"8b111b20":{"m":136,"g":135},"74a166cb":{"m":136,"g":135},"888e126a":{"m":136,"g":135},"bb23a8fe":{"m":136,"g":135},"8b869e32":{"m":136,"g":135},"6256936d":{"m":136,"g":135},"62f73a8c":{"m":136,"g":135},"7c1b4b1c":{"m":136,"g":135},"31ed68e7":{"m":136,"g":135},"24c91001":{"m":136,"g":135},"c4edcac6":{"m":136,"g":135},"e9343389":{"m":136,"g":135},"a2d4f58a":{"m":136,"g":135},"f66b0916":{"m":136,"g":135},"2f623368":{"m":136,"g":135},"bd9a2ced":{"m":136,"g":135},"0ca417d9":{"m":136,"g":135},"30cfb687":{"m":136,"g":135},"b7c7e03d":{"m":136,"g":135},"f0195627":{"m":136,"g":135},"d401d238":{"m":136,"g":135},"17041f46":{"m":136,"g":135},"f07e76b2":{"m":136,"g":135},"1cfd2b2d":{"m":136,"g":135},"0d244116":{"m":136,"g":135},"0eae8317":{"m":136,"g":135},"c483a5f4":{"m":136,"g":135},"f26f6c2c":{"m":136,"g":135},"b0213323":{"m":136,"g":135},"5062537b":{"m":136,"g":135},"698629d1":{"m":136,"g":135},"dd93e445":{"m":136,"g":135},"6c8587b5":{"m":136,"g":135},"02704260":{"m":136,"g":135},"bd48ad5e":{"m":136,"g":135},"749736ba":{"m":136,"g":135},"72549863":{"m":136,"g":135},"00562ee1":{"m":136,"g":135},"d7a8257b":{"m":136,"g":135},"f6f7af40":{"m":136,"g":135},"a3b1e8ef":{"m":136,"g":135},"db499e18":{"m":136,"g":135},"6cf3a6dd":{"m":136,"g":135},"90e24f5c":{"m":136,"g":135},"21de3e14":{"m":136,"g":135},"e4c1e441":{"m":136,"g":135},"b5af283b":{"m":136,"g":135},"130c6911":{"m":136,"g":135},"e0e50848":{"m":136,"g":135},"70a769bc":{"m":136,"g":135},"3a42c5e3":{"m":136,"g":135},"12b89e51":{"m":136,"g":135},"85184557":{"m":136,"g":135},"57d2ba92":{"m":136,"g":135},"417e75a6":{"m":136,"g":135},"0500fea9":{"m":136,"g":135},"2b461c15":{"m":136,"g":135},"5595ae14":{"m":136,"g":135},"ace6f300":{"m":136,"g":135},"2da49eec":{"m":136,"g":135},"d65ae0ec":{"m":136,"g":135},"60d7279c":{"m":136,"g":135},"abdf65d4":{"m":136,"g":135},"c1dfbc77":{"m":136,"g":135},"3b3c5a05":{"m":136,"g":135},"2667c857":{"m":136,"g":135},"fc643ffb":{"m":136,"g":135},"4280a18a":{"m":136,"g":135},"386e5415":{"m":136,"g":135},"b6267de5":{"m":136,"g":135},"e47afa02":{"m":136,"g":135},"5ed384d0":{"m":136,"g":135},"b4ce7a6d":{"m":136,"g":135},"25b48564":{"m":136,"g":135},"1c360bf7":{"m":136,"g":135},"3619ec61":{"m":136,"g":135},"db6b51a8":{"m":136,"g":135},"8a9ca41f":{"m":136,"g":135},"ac11e6a7":{"m":136,"g":135},"47a660d5":{"m":136,"g":135},"c0fc7a89":{"m":136,"g":135},"5bf0d862":{"m":136,"g":135},"75b72eb8":{"m":136,"g":135},"bc8b526e":{"m":136,"g":135},"3dfff6ae":{"m":136,"g":135},"ad2c1ee3":{"m":136,"g":135},"9940c6f5":{"m":136,"g":135},"00e60711":{"m":136,"g":135},"4bc2f2e0":{"m":136,"g":135},"d17b9e63":{"m":136,"g":135},"ba67e006":{"m":136,"g":135},"45f3ad2f":{"m":136,"g":135},"f35b5da5":{"m":136,"g":135},"733a0c1a":{"m":136,"g":135},"b369aaa2":{"m":136,"g":135},"b9732025":{"m":136,"g":135},"cbff7ad9":{"m":136,"g":135},"4de59d83":{"m":136,"g":135},"39ca57cd":{"m":136,"g":135},"34498067":{"m":136,"g":135},"b3817fa9":{"m":136,"g":135},"059428bd":{"m":136,"g":135},"5d200dd8":{"m":136,"g":135},"7f9a3d06":{"m":136,"g":135},"664f611e":{"m":136,"g":135},"49adb37e":{"m":136,"g":135},"7518dc35":{"m":136,"g":135},"b6871ba7":{"m":136,"g":135},"c1f2241a":"m137","8da70e2a":"m137"},"g":"2026-02-12T19:54:15.483852"} diff --git a/sglang/docs/supported_models/index.rst b/sglang/docs/supported_models/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..f90c6fba104cc419a5d8ad851c5b0c7759902509 --- /dev/null +++ b/sglang/docs/supported_models/index.rst @@ -0,0 +1,13 @@ +Supported Models +================ + +SGLang supports a wide variety of model architectures for different use cases. +Browse by category below to find models suited for your needs. + +.. toctree:: + :maxdepth: 2 + + text_generation/index + retrieval_ranking/index + specialized/index + extending/index diff --git a/sglang/python/sglang/srt/__pycache__/server_args.cpython-311.pyc b/sglang/python/sglang/srt/__pycache__/server_args.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28cf796d1f014f6ff0d4a30a9c1c7901d859eedb --- /dev/null +++ b/sglang/python/sglang/srt/__pycache__/server_args.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c513cb4d6700524b36aecb98a67f745d0fcdc9cf354bfeac1d4b6c2fae09dbe2 +size 247374 diff --git a/sglang/python/sglang/srt/constrained/__pycache__/base_grammar_backend.cpython-311.pyc b/sglang/python/sglang/srt/constrained/__pycache__/base_grammar_backend.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50c4a9ba1bb7398c31e000ab3f09a8def64f4f94 Binary files /dev/null and b/sglang/python/sglang/srt/constrained/__pycache__/base_grammar_backend.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/constrained/__pycache__/grammar_manager.cpython-311.pyc b/sglang/python/sglang/srt/constrained/__pycache__/grammar_manager.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b82c05dde227366ce04e36aadeaca0fc2a405fe Binary files /dev/null and b/sglang/python/sglang/srt/constrained/__pycache__/grammar_manager.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/constrained/__pycache__/utils.cpython-311.pyc b/sglang/python/sglang/srt/constrained/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d1a903062a5a07f9b0d7cde07403495579a3d5b Binary files /dev/null and b/sglang/python/sglang/srt/constrained/__pycache__/utils.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/constrained/__pycache__/xgrammar_backend.cpython-311.pyc b/sglang/python/sglang/srt/constrained/__pycache__/xgrammar_backend.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..33eb8e6316055a9f5b4e11ced2675d093f297ac7 Binary files /dev/null and b/sglang/python/sglang/srt/constrained/__pycache__/xgrammar_backend.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/constrained/triton_ops/__pycache__/bitmask_ops.cpython-311.pyc b/sglang/python/sglang/srt/constrained/triton_ops/__pycache__/bitmask_ops.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4e64b1aceb59faf056dfeb062387d8a126e7fd08 Binary files /dev/null and b/sglang/python/sglang/srt/constrained/triton_ops/__pycache__/bitmask_ops.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/constrained/triton_ops/bitmask_ops.py b/sglang/python/sglang/srt/constrained/triton_ops/bitmask_ops.py new file mode 100644 index 0000000000000000000000000000000000000000..9a195c006b69788f6003a4d58813ba888ca5f55e --- /dev/null +++ b/sglang/python/sglang/srt/constrained/triton_ops/bitmask_ops.py @@ -0,0 +1,141 @@ +# Adapt from +# https://github.com/mlc-ai/xgrammar/blob/v0.1.17/python/xgrammar/kernels/apply_token_bitmask_inplace_triton.py + +from typing import List, Optional, Union + +import torch +import triton +import triton.language as tl + +from sglang.srt.utils import get_device_core_count + + +@triton.jit +def apply_token_bitmask_inplace_kernel( + logits_ptr, + bitmask_ptr, + indices_ptr, + num_rows, + vocab_size, + logits_strides, + bitmask_strides, + NUM_SMS: tl.constexpr, + BLOCK_SIZE: tl.constexpr, +): + """Apply a bitmask to logits in-place using Triton. The bitmask is a 01 bitwise compressed tensor, + where 0 means the token is masked and 1 means the token is not masked. After applying the bitmask, + the masked logits will be set to -inf. + + Parameters + ---------- + logits_ptr : tl.tensor + Pointer to the logits tensor to apply the bitmask to. + + bitmask_ptr : tl.tensor + Pointer to the bitmask tensor to apply. + + indices_ptr : Optional[tl.tensor] + Optional pointer to indices tensor specifying which rows to apply the mask to. + + num_rows : int + Number of rows to process. If indices_ptr is provided, this is the number of unique indices. + + vocab_size : int + Size of the vocabulary dimension. If the logits does not have a vocab padding, this is the + same as the logits's second dimension. Otherwise, this is the actual size of the vocabulary. + + logits_strides : int + Stride between rows in the logits tensor. + + bitmask_strides : int + Stride between rows in the bitmask tensor. + + NUM_SMS : int + Number of streaming multiprocessors to use. + + BLOCK_SIZE : int + Size of processing blocks. + """ + + pid = tl.program_id(0) + num_blocks = tl.cdiv(vocab_size, BLOCK_SIZE) + for work_id in tl.range(pid, num_rows * num_blocks, NUM_SMS): + row_id = work_id // num_blocks + block_offset = (work_id % num_blocks) * BLOCK_SIZE + batch_id = row_id if indices_ptr is None else tl.load(indices_ptr + row_id) + offsets = block_offset + tl.arange(0, BLOCK_SIZE) + bitmask_offsets = block_offset // 32 + tl.arange(0, BLOCK_SIZE // 32) + vocab_mask = offsets < vocab_size + packed_bitmask_mask = bitmask_offsets < bitmask_strides + packed_bitmask = tl.load( + bitmask_ptr + batch_id * bitmask_strides + bitmask_offsets, + packed_bitmask_mask, + ) + bitmask = ((packed_bitmask[:, None] >> (tl.arange(0, 32)[None, :])) & 1) == 0 + bitmask = bitmask.reshape(BLOCK_SIZE) + + tl.store( + logits_ptr + batch_id * logits_strides + offsets, + -float("inf"), + vocab_mask & bitmask, + ) + + +def apply_token_bitmask_inplace_triton( + logits: torch.Tensor, + bitmask: torch.Tensor, + indices: Optional[Union[List[int], torch.Tensor]] = None, +): + NUM_SMS = get_device_core_count() + BLOCK_SIZE = 4096 + BITS_PER_BLOCK = 32 + + # Check input dtype + assert bitmask.dtype == torch.int32, "bitmask must be of type int32" + + # Check input tensor shapes. + logits_shape = logits.shape + bitmask_shape = bitmask.shape + if logits.ndim == 1: + logits_shape = (1, logits_shape[0]) + if bitmask.ndim == 1: + bitmask_shape = (1, bitmask_shape[0]) + + required_bitmask_width = (logits_shape[1] + BITS_PER_BLOCK - 1) // BITS_PER_BLOCK + assert required_bitmask_width >= bitmask_shape[1], ( + f"Bitmask width too large: allow at most {required_bitmask_width} int32s for " + f"logits' width {logits_shape[1]}, but got {bitmask_shape[1]}" + ) + + vocab_size = min(logits_shape[1], bitmask_shape[1] * BITS_PER_BLOCK) + + num_rows = None + if isinstance(indices, list) or isinstance(indices, torch.Tensor): + indices = torch.tensor(indices, dtype=torch.int32, device=logits.device) + num_rows = indices.shape[0] + else: + assert ( + logits_shape[0] == bitmask_shape[0] + ), f"batch size mismatch: logits {logits_shape[0]} vs bitmask {bitmask_shape[0]}" + num_rows = logits_shape[0] + + if NUM_SMS > 0: + grid = (NUM_SMS,) + else: + num_blocks = triton.cdiv(vocab_size, BLOCK_SIZE) + grid = (num_rows * num_blocks,) + NUM_SMS = triton.next_power_of_2(grid[0]) + + apply_token_bitmask_inplace_kernel[grid]( + logits, + bitmask, + indices, + num_rows, + vocab_size, + logits_shape[1], + bitmask_shape[1], + NUM_SMS, + BLOCK_SIZE, + num_warps=BLOCK_SIZE // 32 // (16 // logits.element_size()), + num_stages=3, + ) diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/executor.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/executor.py new file mode 100644 index 0000000000000000000000000000000000000000..bf30dde8ba0a2614afab240ed377bc19b8aa60c5 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/executor.py @@ -0,0 +1,212 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import NamedTuple, Optional + +import torch + +from sglang.srt.debug_utils.comparator.aligner.axis_aligner import ( + execute_axis_aligner_plan, +) +from sglang.srt.debug_utils.comparator.aligner.entrypoint.traced_types import ( + TracedAlignerPlan, + TracedSidePlan, + TracedStepPlan, + TracedSubPlan, +) +from sglang.srt.debug_utils.comparator.aligner.entrypoint.types import ( + AlignerPerStepPlan, + AlignerPerStepSubPlan, + AlignerPlan, +) +from sglang.srt.debug_utils.comparator.aligner.reorderer.executor import ( + execute_reorderer_plan, +) +from sglang.srt.debug_utils.comparator.aligner.reorderer.types import ReordererPlan +from sglang.srt.debug_utils.comparator.aligner.token_aligner.concat_steps import ( + execute_token_aligner_concat_steps, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.executor import ( + execute_token_aligner, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.executor import ( + UnsharderResult, + execute_unsharder_plan, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.types import UnsharderPlan +from sglang.srt.debug_utils.comparator.output_types import ( + ReplicatedCheckResult, + ShapeSnapshot, +) +from sglang.srt.debug_utils.comparator.utils import Pair + + +class StepPlansResult(NamedTuple): + tensors: dict[int, torch.Tensor] + checks: list[ReplicatedCheckResult] + traced_side: TracedSidePlan + + +class SubPlansResult(NamedTuple): + tensor: Optional[torch.Tensor] + checks: list[ReplicatedCheckResult] + snapshots: list[ShapeSnapshot] + + +@dataclass(frozen=True) +class AlignerResult: + tensors: Optional[Pair[torch.Tensor]] + failed_side_xy: Optional[str] # "x" or "y"; None if success + replicated_checks: list[ReplicatedCheckResult] = field(default_factory=list) + traced_plan: Optional[TracedAlignerPlan] = None + + +def execute_aligner_plan( + *, + tensors_pair: Pair[list[torch.Tensor]], + plan: AlignerPlan, +) -> AlignerResult: + """Execute unified unshard/reorder + token-align.""" + all_checks: list[ReplicatedCheckResult] = [] + + # Per-side: unshard + reorder -> dict[step, tensor] + result_x: StepPlansResult = _execute_step_plans( + tensors=tensors_pair.x, step_plans=plan.per_step_plans.x + ) + all_checks.extend(result_x.checks) + + result_y: StepPlansResult = _execute_step_plans( + tensors=tensors_pair.y, step_plans=plan.per_step_plans.y + ) + all_checks.extend(result_y.checks) + + traced_plan: TracedAlignerPlan = TracedAlignerPlan( + plan=plan, + per_side=Pair(x=result_x.traced_side, y=result_y.traced_side), + ) + + if not result_x.tensors or not result_y.tensors: + failed_side_xy: str = "x" if not result_x.tensors else "y" + return AlignerResult( + tensors=None, + failed_side_xy=failed_side_xy, + replicated_checks=all_checks, + traced_plan=traced_plan, + ) + + # Cross-side: token alignment (or direct extraction for single-step) + step_pair: Pair[dict[int, torch.Tensor]] = Pair( + x=result_x.tensors, y=result_y.tensors + ) + combined: Pair[torch.Tensor] + if plan.token_aligner_mode == "concat_steps": + combined = execute_token_aligner_concat_steps(tensor_of_step_pair=step_pair) + elif plan.token_aligner_mode == "smart": + assert plan.token_aligner_plan is not None + combined = execute_token_aligner( + plan=plan.token_aligner_plan, + tensor_of_step_pair=step_pair, + ) + else: + assert len(result_x.tensors) == 1 and len(result_y.tensors) == 1 + combined = Pair( + x=list(result_x.tensors.values())[0], + y=list(result_y.tensors.values())[0], + ) + + # Cross-side: axis alignment (squeeze singletons + rearrange dim order) + if (aligner_plan := plan.axis_aligner_plan) is not None: + combined = Pair( + x=execute_axis_aligner_plan(tensor=combined.x, plan=aligner_plan, side="x"), + y=execute_axis_aligner_plan(tensor=combined.y, plan=aligner_plan, side="y"), + ) + + return AlignerResult( + tensors=combined, + failed_side_xy=None, + replicated_checks=all_checks, + traced_plan=traced_plan, + ) + + +def _execute_step_plans( + tensors: list[torch.Tensor], + step_plans: list[AlignerPerStepPlan], +) -> StepPlansResult: + result: dict[int, torch.Tensor] = {} + all_checks: list[ReplicatedCheckResult] = [] + traced_steps: list[TracedStepPlan] = [] + + for step_plan in step_plans: + step_tensors: list[torch.Tensor] = [ + tensors[i] for i in step_plan.input_object_indices + ] + sub_result: SubPlansResult = execute_sub_plans( + tensors=step_tensors, plans=step_plan.sub_plans + ) + all_checks.extend(sub_result.checks) + + traced_subs: list[TracedSubPlan] = [ + TracedSubPlan(plan=sub_plan, snapshot=snapshot) + for sub_plan, snapshot in zip(step_plan.sub_plans, sub_result.snapshots) + ] + traced_steps.append( + TracedStepPlan( + step=step_plan.step, + input_object_indices=step_plan.input_object_indices, + sub_plans=traced_subs, + ) + ) + + if sub_result.tensor is not None: + result[step_plan.step] = sub_result.tensor + + return StepPlansResult( + tensors=result, + checks=all_checks, + traced_side=TracedSidePlan(step_plans=traced_steps), + ) + + +def execute_sub_plans( + tensors: list[torch.Tensor], + plans: list[AlignerPerStepSubPlan], +) -> SubPlansResult: + if not tensors: + return SubPlansResult(tensor=None, checks=[], snapshots=[]) + + if not plans: + if len(tensors) != 1: + return SubPlansResult(tensor=None, checks=[], snapshots=[]) + return SubPlansResult(tensor=tensors[0], checks=[], snapshots=[]) + + current: list[torch.Tensor] = tensors + all_checks: list[ReplicatedCheckResult] = [] + all_snapshots: list[ShapeSnapshot] = [] + for plan in plans: + input_shapes: list[list[int]] = [list(t.shape) for t in current] + current, checks = execute_sub_plan(tensors=current, plan=plan) + output_shapes: list[list[int]] = [list(t.shape) for t in current] + all_checks.extend(checks) + all_snapshots.append( + ShapeSnapshot( + input_shapes=input_shapes, + output_shapes=output_shapes, + ) + ) + + assert len(current) == 1 + return SubPlansResult(tensor=current[0], checks=all_checks, snapshots=all_snapshots) + + +def execute_sub_plan( + tensors: list[torch.Tensor], + plan: AlignerPerStepSubPlan, +) -> tuple[list[torch.Tensor], list[ReplicatedCheckResult]]: + if isinstance(plan, UnsharderPlan): + unsharder_result: UnsharderResult = execute_unsharder_plan(plan, tensors) + return unsharder_result.tensors, unsharder_result.replicated_checks + elif isinstance(plan, ReordererPlan): + return execute_reorderer_plan(plan, tensors), [] + else: + raise NotImplementedError(f"Unknown {plan=}") diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/planner.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/planner.py new file mode 100644 index 0000000000000000000000000000000000000000..673701f9004ce1abadbd655902862e6e806cea49 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/planner.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from typing import Any, Optional + +from sglang.srt.debug_utils.comparator.aligner.axis_aligner import ( + AxisAlignerPlan, + compute_axis_aligner_plan, +) +from sglang.srt.debug_utils.comparator.aligner.entrypoint.types import ( + AlignerPerStepPlan, + AlignerPerStepSubPlan, + AlignerPlan, +) +from sglang.srt.debug_utils.comparator.aligner.reorderer.planner import ( + compute_reorderer_plans, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + TokenAlignerPlan, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.parallel_info import ( + normalize_parallel_info, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.planner import ( + compute_unsharder_plan, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + DimSpec, + DimsSpec, + ParallelAxis, + _SingletonDimUtil, + parse_dims, +) +from sglang.srt.debug_utils.comparator.utils import Pair + + +def compute_aligner_plan( + *, + metas_pair: Pair[list[dict[str, Any]]], + token_aligner_mode: Optional[str], + token_aligner_plan: Optional[TokenAlignerPlan], + thd_seq_lens_by_step_pair: Pair[Optional[dict[int, list[int]]]] = Pair( + x=None, y=None + ), +) -> AlignerPlan: + dims_str_pair: Pair[Optional[str]] = metas_pair.map( + lambda metas: metas[0].get("dims") if metas else None + ) + axis_aligner_plan: Optional[AxisAlignerPlan] = compute_axis_aligner_plan( + dims_str_pair=dims_str_pair + ) + + return AlignerPlan( + per_step_plans=Pair( + x=_compute_per_step_plans( + metas=metas_pair.x, + thd_seq_lens_by_step=thd_seq_lens_by_step_pair.x, + ), + y=_compute_per_step_plans( + metas=metas_pair.y, + thd_seq_lens_by_step=thd_seq_lens_by_step_pair.y, + ), + ), + token_aligner_mode=token_aligner_mode, + token_aligner_plan=token_aligner_plan, + axis_aligner_plan=axis_aligner_plan, + ) + + +def _compute_per_step_plans( + metas: list[dict[str, Any]], + *, + thd_seq_lens_by_step: Optional[dict[int, list[int]]] = None, +) -> list[AlignerPerStepPlan]: + step_to_input_indices: dict[int, list[int]] = {} + for i, meta in enumerate(metas): + step: int = int(meta["step"]) + step_to_input_indices.setdefault(step, []).append(i) + + result: list[AlignerPerStepPlan] = [] + for step in sorted(step_to_input_indices): + input_indices: list[int] = step_to_input_indices[step] + step_metas: list[dict[str, Any]] = [metas[idx] for idx in input_indices] + step_seq_lens: Optional[list[int]] = ( + thd_seq_lens_by_step.get(step) if thd_seq_lens_by_step is not None else None + ) + plans: list[AlignerPerStepSubPlan] = compute_per_step_sub_plans( + metas=step_metas, + thd_global_seq_lens=step_seq_lens, + ) + result.append( + AlignerPerStepPlan( + step=step, input_object_indices=input_indices, sub_plans=plans + ) + ) + + return result + + +def compute_per_step_sub_plans( + metas: list[dict[str, Any]], + *, + thd_global_seq_lens: Optional[list[int]] = None, +) -> list[AlignerPerStepSubPlan]: + if not metas or len(metas) == 1: + return [] + + dims_str = metas[0].get("dims") + if dims_str is None: + return [] + + dims_spec: DimsSpec = parse_dims(dims_str) + dim_specs: list[DimSpec] = _SingletonDimUtil.filter_out(dims_spec.dims) + replicated_axes: frozenset[ParallelAxis] = dims_spec.replicated_axes + parallel_infos = [normalize_parallel_info(meta) for meta in metas] + + unsharder_plans = compute_unsharder_plan( + dim_specs=dim_specs, + parallel_infos=parallel_infos, + explicit_replicated_axes=replicated_axes, + thd_global_seq_lens=thd_global_seq_lens, + ) + reorderer_plans = compute_reorderer_plans( + dim_specs=dim_specs, + parallel_infos=parallel_infos, + thd_global_seq_lens=thd_global_seq_lens, + ) + return [*unsharder_plans, *reorderer_plans] diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/types.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/types.py new file mode 100644 index 0000000000000000000000000000000000000000..e2e6d768395a385b46894c392aa8cc3c1d54337b --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/entrypoint/types.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from typing import Annotated, Optional, Union + +from pydantic import Discriminator + +from sglang.srt.debug_utils.comparator.aligner.axis_aligner import AxisAlignerPlan +from sglang.srt.debug_utils.comparator.aligner.reorderer.types import ReordererPlan +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + TokenAlignerPlan, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.types import UnsharderPlan +from sglang.srt.debug_utils.comparator.utils import Pair, _FrozenBase + +AlignerPerStepSubPlan = Annotated[ + Union[UnsharderPlan, ReordererPlan], + Discriminator("type"), +] + + +class AlignerPerStepPlan(_FrozenBase): + step: int + input_object_indices: list[int] + sub_plans: list[AlignerPerStepSubPlan] + + +class AlignerPlan(_FrozenBase): + per_step_plans: Pair[list[AlignerPerStepPlan]] + token_aligner_mode: Optional[str] = None # "concat_steps" | "smart" | None + token_aligner_plan: Optional[TokenAlignerPlan] = None + axis_aligner_plan: Optional[AxisAlignerPlan] = None diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/executor.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/executor.py new file mode 100644 index 0000000000000000000000000000000000000000..20b2338fe356d1ded1f10fc90732d9bb699112f2 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/executor.py @@ -0,0 +1,101 @@ +from typing import Optional + +import torch + +from sglang.srt.debug_utils.comparator.aligner.reorderer.types import ( + ReordererPlan, + ZigzagToNaturalParams, + ZigzagToNaturalThdParams, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + resolve_dim_by_name, + strip_dim_names, +) + + +def execute_reorderer_plan( + plan: ReordererPlan, + tensors: list[torch.Tensor], +) -> list[torch.Tensor]: + if isinstance(plan.params, ZigzagToNaturalThdParams): + thd_dim: int = resolve_dim_by_name(tensors[0], plan.params.dim_name) + return [ + _reorder_zigzag_to_natural_thd( + tensor, + dim=thd_dim, + cp_size=plan.params.cp_size, + seq_lens=plan.params.seq_lens, + ) + for tensor in tensors + ] + + if isinstance(plan.params, ZigzagToNaturalParams): + dim: int = resolve_dim_by_name(tensors[0], plan.params.dim_name) + return [ + _reorder_zigzag_to_natural(tensor, dim=dim, cp_size=plan.params.cp_size) + for tensor in tensors + ] + + raise ValueError(f"Unsupported reorderer params type: {type(plan.params).__name__}") + + +def _reorder_zigzag_to_natural_thd( + tensor: torch.Tensor, *, dim: int, cp_size: int, seq_lens: list[int] +) -> torch.Tensor: + """Undo CP zigzag interleaving for THD (packed-seq) format. + + Each seq in seq_lens is independently reordered from zigzag to natural order + along the given dim. + """ + stripped: torch.Tensor = strip_dim_names(tensor) + names: tuple[Optional[str], ...] = tensor.names + + split_sizes: list[int] = list(seq_lens) + remainder: int = stripped.shape[dim] - sum(split_sizes) + if remainder < 0: + raise ValueError( + f"sum(seq_lens)={sum(split_sizes)} exceeds tensor dim size " + f"{stripped.shape[dim]} along dim={dim}" + ) + if remainder > 0: + split_sizes.append(remainder) + + segments: list[torch.Tensor] = list(stripped.split(split_sizes, dim=dim)) + + reordered_segments: list[torch.Tensor] = [ + _reorder_zigzag_to_natural(seg, dim=dim, cp_size=cp_size) + for seg in segments[: len(seq_lens)] + ] + + # Tail padding — pass through unchanged + if remainder > 0: + reordered_segments.append(segments[-1]) + + result: torch.Tensor = torch.cat(reordered_segments, dim=dim) + + if names[0] is not None: + result = result.refine_names(*names) + return result + + +def _reorder_zigzag_to_natural( + tensor: torch.Tensor, *, dim: int, cp_size: int +) -> torch.Tensor: + """Undo CP zigzag interleaving, restoring natural chunk order. + + Generalized from Megatron-LM _undo_attention_load_balancing + (megatron/core/ssm/mamba_context_parallel.py:360-373). + """ + stripped: torch.Tensor = strip_dim_names(tensor) + names: tuple[Optional[str], ...] = tensor.names + + num_chunks: int = cp_size * 2 + chunks: tuple[torch.Tensor, ...] = stripped.chunk(num_chunks, dim=dim) + order: list[int] = [2 * i for i in range(cp_size)] + [ + num_chunks - 2 * i - 1 for i in range(cp_size) + ] + result: torch.Tensor = torch.cat([chunks[i] for i in order], dim=dim) + + if names[0] is not None: + result = result.refine_names(*names) + return result diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/planner.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/planner.py new file mode 100644 index 0000000000000000000000000000000000000000..bbede55f5b4223406eda8eb842c50d3b69222ad2 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/planner.py @@ -0,0 +1,67 @@ +from typing import Optional + +from sglang.srt.debug_utils.comparator.aligner.reorderer.types import ( + ReordererPlan, + ZigzagToNaturalParams, + ZigzagToNaturalThdParams, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.types import AxisInfo +from sglang.srt.debug_utils.comparator.dims_spec import ( + SEQ_DIM_NAME, + TOKEN_DIM_NAME, + DimSpec, + Ordering, + ParallelAxis, +) + +_ALLOWED_ZIGZAG_DIM_NAMES: set[str] = {SEQ_DIM_NAME, TOKEN_DIM_NAME} + + +def compute_reorderer_plans( + dim_specs: list[DimSpec], + parallel_infos: list[dict[ParallelAxis, AxisInfo]], + *, + thd_global_seq_lens: Optional[list[int]] = None, +) -> list[ReordererPlan]: + plans: list[ReordererPlan] = [] + + for spec in dim_specs: + for modifier in spec.parallel_modifiers: + if modifier.ordering is None or modifier.ordering == Ordering.NATURAL: + continue + + if spec.name not in _ALLOWED_ZIGZAG_DIM_NAMES: + raise ValueError( + f"Zigzag ordering is only supported on sequence dims " + f"(dim name must be one of " + f"{sorted(_ALLOWED_ZIGZAG_DIM_NAMES)}), " + f"but got dim name {spec.name!r} in {spec}" + ) + + if modifier.ordering != Ordering.ZIGZAG: + raise ValueError( + f"Unsupported ordering {modifier.ordering!r} for dim {spec.name!r}" + ) + axis_size: int = parallel_infos[0][modifier.axis].axis_size + + if spec.name == TOKEN_DIM_NAME: + if thd_global_seq_lens is None: + raise ValueError( + "thd_global_seq_lens is required for zigzag reorder on 't' dimension" + ) + params = ZigzagToNaturalThdParams( + dim_name=spec.name, + cp_size=axis_size, + seq_lens=thd_global_seq_lens, + ) + elif spec.name == SEQ_DIM_NAME: + params = ZigzagToNaturalParams(dim_name=spec.name, cp_size=axis_size) + else: + raise ValueError( + f"Unsupported zigzag dim name {spec.name!r}, " + f"expected one of {sorted(_ALLOWED_ZIGZAG_DIM_NAMES)}" + ) + + plans.append(ReordererPlan(params=params)) + + return plans diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/types.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/types.py new file mode 100644 index 0000000000000000000000000000000000000000..e430a202ba0736b7ccb62cab49bd5a35958a33c6 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/reorderer/types.py @@ -0,0 +1,29 @@ +from typing import Annotated, Literal, Union + +from pydantic import Field + +from sglang.srt.debug_utils.comparator.utils import _FrozenBase + + +class ZigzagToNaturalParams(_FrozenBase): + op: Literal["zigzag_to_natural"] = "zigzag_to_natural" + dim_name: str + cp_size: int + + +class ZigzagToNaturalThdParams(_FrozenBase): + op: Literal["zigzag_to_natural_thd"] = "zigzag_to_natural_thd" + dim_name: str + cp_size: int + seq_lens: list[int] # unshard-ed per-seq token counts, e.g. [100, 64, 92] + + +ReordererParams = Annotated[ + Union[ZigzagToNaturalParams, ZigzagToNaturalThdParams], + Field(discriminator="op"), +] + + +class ReordererPlan(_FrozenBase): + type: Literal["reorderer"] = "reorderer" + params: ReordererParams diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/__init__.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..598fefeda5fd96d86c8afe41359d2f05938341da --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/__init__.py @@ -0,0 +1,7 @@ +from sglang.srt.debug_utils.comparator.aligner.token_aligner.concat_steps.executor import ( + execute_token_aligner_concat_steps, +) + +__all__ = [ + "execute_token_aligner_concat_steps", +] diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/thd_seq_lens_loader.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/thd_seq_lens_loader.py new file mode 100644 index 0000000000000000000000000000000000000000..37d4f5f27473516a1619efc2ee3c9526c400059a --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/concat_steps/thd_seq_lens_loader.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Optional + +import polars as pl + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.aux_loader import ( + _detect_plugin, + _load_and_align_aux_tensor, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.aux_plugins import ( + _AuxFrameworkPlugin, +) + + +def load_thd_seq_lens_only( + dump_path: Path, df: pl.DataFrame +) -> Optional[dict[int, list[int]]]: + plugin: Optional[_AuxFrameworkPlugin] = _detect_plugin(df, dump_path=dump_path) + if plugin is None or not plugin.cp_sharded_names: + return None + + non_cp_tensor_names: set[str] = ( + set(df["name"].unique().to_list()) & plugin.tensor_names + ) - plugin.cp_sharded_names + steps: list[int] = sorted(df["step"].unique().to_list()) + + result: dict[int, list[int]] = {} + for step in steps: + step_data: dict[str, object] = {} + for name in non_cp_tensor_names: + tensor = _load_and_align_aux_tensor( + name=name, step=step, df=df, dump_path=dump_path, plugin=plugin + ) + if tensor is not None: + step_data[name] = tensor + + seq_lens: Optional[list[int]] = plugin.extract_global_seq_lens(step_data) + if seq_lens is not None: + result[step] = seq_lens + + return result or None diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/entrypoint.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/entrypoint.py new file mode 100644 index 0000000000000000000000000000000000000000..51a31d80d288b5a24bd507a7371dbf45f6a9fccf --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/entrypoint.py @@ -0,0 +1,132 @@ +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +from typing import Literal, Optional + +import polars as pl + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.concat_steps.thd_seq_lens_loader import ( + load_thd_seq_lens_only, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.aux_loader import ( + has_aux_tensors, + load_and_normalize_aux, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.planner import ( + compute_token_aligner_plan, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.seq_info_builder import ( + build_seqs_info, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + TokenAlignerGlobalAux, + TokenAlignerPlan, + TokenAlignerSeqsInfo, +) +from sglang.srt.debug_utils.comparator.log_sink import log_sink +from sglang.srt.debug_utils.comparator.output_types import InfoLog +from sglang.srt.debug_utils.comparator.utils import Pair + +_NONE_THD: Pair[Optional[dict[int, list[int]]]] = Pair(x=None, y=None) + + +TokenAlignerMode = Literal["concat_steps", "smart"] + + +@dataclass(frozen=True) +class TokenAlignerResult: + """Result of token aligner computation, bundling mode + plan with THD metadata.""" + + mode: Optional[TokenAlignerMode] + plan: Optional[TokenAlignerPlan] + thd_seq_lens_by_step_pair: Pair[Optional[dict[int, list[int]]]] + + +def compute_maybe_token_aligner_result( + *, + dir_pair: Pair[Path], + dfs: Pair[pl.DataFrame], + token_aligner_mode: Optional[TokenAlignerMode], +) -> TokenAlignerResult: + if token_aligner_mode is None: + return TokenAlignerResult( + mode=None, plan=None, thd_seq_lens_by_step_pair=_NONE_THD + ) + + if token_aligner_mode == "concat_steps": + thd_pair: Pair[Optional[dict[int, list[int]]]] = _load_thd_seq_lens_pair( + dir_pair=dir_pair, dfs=dfs + ) + return TokenAlignerResult( + mode="concat_steps", plan=None, thd_seq_lens_by_step_pair=thd_pair + ) + elif token_aligner_mode == "smart": + if not (has_aux_tensors(dfs.x) and has_aux_tensors(dfs.y)): + log_sink.add( + InfoLog( + category="aux_tensors_missing", + message="Aux tensors missing, skipping token alignment", + ) + ) + return TokenAlignerResult( + mode=None, plan=None, thd_seq_lens_by_step_pair=_NONE_THD + ) + + return _build_smart_result(dir_pair=dir_pair, dfs=dfs) + else: + raise NotImplementedError(f"Unknown {token_aligner_mode=}") + + +def _build_smart_result( + *, + dir_pair: Pair[Path], + dfs: Pair[pl.DataFrame], +) -> TokenAlignerResult: + """Load aux tensors, build token indices, and compute the alignment plan.""" + aux_pair: Pair[Optional[TokenAlignerGlobalAux]] = Pair( + x=load_and_normalize_aux(dump_path=dir_pair.x, df=dfs.x), + y=load_and_normalize_aux(dump_path=dir_pair.y, df=dfs.y), + ) + + thd_seq_lens_by_step_pair: Pair[Optional[dict[int, list[int]]]] = aux_pair.map( + lambda aux: aux.thd_seq_lens_by_step if aux is not None else None + ) + + if aux_pair.x is None or aux_pair.y is None: + log_sink.add( + InfoLog( + category="framework_detection_failed", + message="Framework detection failed, skipping token alignment", + ) + ) + return TokenAlignerResult( + mode=None, + plan=None, + thd_seq_lens_by_step_pair=thd_seq_lens_by_step_pair, + ) + + global_aux: Pair[TokenAlignerGlobalAux] = Pair(x=aux_pair.x, y=aux_pair.y) + + seqs_info: Pair[TokenAlignerSeqsInfo] = global_aux.map(build_seqs_info) + + plan: Optional[TokenAlignerPlan] = compute_token_aligner_plan( + seqs_info_pair=seqs_info + ) + return TokenAlignerResult( + mode="smart", + plan=plan, + thd_seq_lens_by_step_pair=thd_seq_lens_by_step_pair, + ) + + +def _load_thd_seq_lens_pair( + *, + dir_pair: Pair[Path], + dfs: Pair[pl.DataFrame], +) -> Pair[Optional[dict[int, list[int]]]]: + """Load only thd_seq_lens for each side (lightweight, no full aux loading).""" + return Pair( + x=load_thd_seq_lens_only(dump_path=dir_pair.x, df=dfs.x), + y=load_thd_seq_lens_only(dump_path=dir_pair.y, df=dfs.y), + ) diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/__init__.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_loader.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_loader.py new file mode 100644 index 0000000000000000000000000000000000000000..7ce7814e3d93e260758ea6faf43d3c0daec25947 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_loader.py @@ -0,0 +1,285 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Any, Optional + +import polars as pl +import torch + +from sglang.srt.debug_utils.comparator.aligner.entrypoint.executor import ( + execute_sub_plans, +) +from sglang.srt.debug_utils.comparator.aligner.entrypoint.planner import ( + compute_per_step_sub_plans, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.aux_plugins import ( + AUX_NAMES, + _AuxFrameworkPlugin, + _plugins, +) +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + TokenAlignerGlobalAux, + TokenAlignerStepAux, +) +from sglang.srt.debug_utils.comparator.aligner.unsharder.parallel_info import ( + normalize_parallel_info, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + ParallelAxis, + TokenLayout, + apply_dim_names, + resolve_dim_names, +) +from sglang.srt.debug_utils.comparator.dp_utils import filter_to_non_empty_dp_rank +from sglang.srt.debug_utils.comparator.log_sink import log_sink +from sglang.srt.debug_utils.comparator.output_types import ErrorLog, InfoLog +from sglang.srt.debug_utils.dump_loader import ValueWithMeta, filter_rows + +# re-export for existing callers +__all__ = [ + "AUX_NAMES", + "has_aux_tensors", + "load_and_normalize_aux", +] + + +def load_and_normalize_aux( + dump_path: Path, df: pl.DataFrame +) -> Optional[TokenAlignerGlobalAux]: + """Bootstrap: load, unshard, and normalize auxiliary tensors for one side.""" + plugin: Optional[_AuxFrameworkPlugin] = _detect_plugin(df, dump_path=dump_path) + if plugin is None: + return None + + available_names: set[str] = set(df["name"].unique().to_list()) & plugin.all_names + steps: list[int] = sorted(df["step"].unique().to_list()) + tensor_names: set[str] = available_names & plugin.tensor_names + non_tensor_names: set[str] = available_names & plugin.non_tensor_names + + steps_data: dict[int, dict[str, object]] = {} + thd_seq_lens_by_step: dict[int, list[int]] = {} + for step in steps: + step_data, thd_seq_lens = _load_step_data( + step=step, + tensor_names=tensor_names, + non_tensor_names=non_tensor_names, + df=df, + dump_path=dump_path, + plugin=plugin, + ) + if step_data: + steps_data[step] = step_data + if thd_seq_lens is not None: + thd_seq_lens_by_step[step] = thd_seq_lens + + layout: TokenLayout = plugin.detect_layout(steps_data) + + step_auxs: dict[int, TokenAlignerStepAux] = { + step: plugin.compute_step_aux(step_data, layout=layout, step=step) + for step, step_data in steps_data.items() + } + + return TokenAlignerGlobalAux( + step_auxs=step_auxs, + framework=plugin.name, + layout=layout, + thd_seq_lens_by_step=thd_seq_lens_by_step or None, + ) + + +def has_aux_tensors(df: pl.DataFrame) -> bool: + """Check if the DataFrame contains the minimum auxiliary tensors for alignment.""" + names: set[str] = set(df["name"].unique().to_list()) + return any(plugin.has_required_names(names) for plugin in _plugins) + + +def _detect_plugin(df: pl.DataFrame, dump_path: Path) -> Optional[_AuxFrameworkPlugin]: + names: set[str] = set(df["name"].unique().to_list()) + + for plugin in _plugins: + if names & plugin.discriminating_names: + return plugin + + first_row: dict = df.row(0, named=True) + value: ValueWithMeta = ValueWithMeta.load(dump_path / first_row["filename"]) + + for plugin in _plugins: + if f"{plugin.name}_parallel_info" in value.meta: + return plugin + + return None + + +def _load_step_data( + *, + step: int, + tensor_names: set[str], + non_tensor_names: set[str], + df: pl.DataFrame, + dump_path: Path, + plugin: _AuxFrameworkPlugin, +) -> tuple[dict[str, object], Optional[list[int]]]: + """Load all tensor and non-tensor aux values for a single step. + + Two-pass loading: non-CP-sharded tensors first (to obtain cu_seqlens_q + for seq_lens), then CP-sharded tensors with seq_lens for THD unshard/reorder. + + Returns (step_data, thd_global_seq_lens). + """ + result: dict[str, object] = {} + + # Pass 0: non-tensor values + for name in non_tensor_names: + value = _load_non_tensor_aux(name=name, step=step, df=df, dump_path=dump_path) + if value is not None: + result[name] = value + + # Pass 1: non-CP-sharded tensors (e.g. cu_seqlens_q, seq_lens) + non_cp_tensor_names: set[str] = tensor_names - plugin.cp_sharded_names + cp_tensor_names: set[str] = tensor_names & plugin.cp_sharded_names + + for name in non_cp_tensor_names: + tensor = _load_and_align_aux_tensor( + name=name, step=step, df=df, dump_path=dump_path, plugin=plugin + ) + if tensor is not None: + result[name] = tensor + + # Derive global seq_lens for THD unshard (framework-specific extraction) + thd_global_seq_lens: Optional[list[int]] = plugin.extract_global_seq_lens(result) + + # Pass 2: CP-sharded tensors (input_ids, position_ids, etc.) + for name in cp_tensor_names: + tensor = _load_and_align_aux_tensor( + name=name, + step=step, + df=df, + dump_path=dump_path, + plugin=plugin, + thd_global_seq_lens=thd_global_seq_lens, + ) + if tensor is not None: + result[name] = tensor + + return result, thd_global_seq_lens + + +def _load_non_tensor_aux( + *, name: str, step: int, df: pl.DataFrame, dump_path: Path +) -> Optional[object]: + """Load a non-tensor auxiliary value for a step, validating consistency across ranks.""" + rows = filter_rows(df, conditions={"name": name, "step": step}) + if not rows: + return None + + loaded: list[ValueWithMeta] = [ + ValueWithMeta.load(dump_path / r["filename"]) for r in rows + ] + loaded = filter_to_non_empty_dp_rank(loaded) + + if len(loaded) > 1: + first_value = loaded[0].value + for i, item in enumerate(loaded[1:], start=1): + if item.value != first_value: + log_sink.add( + ErrorLog( + category=f"{name}_mismatch", + message=( + f"{name} mismatch across ranks: rank 0 has {first_value}, " + f"rank {i} has {item.value}" + ), + ) + ) + break + + return loaded[0].value + + +def _load_and_align_aux_tensor( + *, + name: str, + step: int, + df: pl.DataFrame, + dump_path: Path, + plugin: _AuxFrameworkPlugin, + thd_global_seq_lens: Optional[list[int]] = None, +) -> Optional[torch.Tensor]: + """Load an auxiliary tensor for (name, step), align if needed.""" + rows = filter_rows(df, conditions={"name": name, "step": step}) + if not rows: + return None + + loaded: list[ValueWithMeta] = [ + ValueWithMeta.load(dump_path / r["filename"]) for r in rows + ] + loaded = filter_to_non_empty_dp_rank(loaded) + + tensors: list[torch.Tensor] = [ + item.value for item in loaded if isinstance(item.value, torch.Tensor) + ] + if not tensors: + return None + + if len(tensors) == 1: + return tensors[0] + + metas: list[dict[str, Any]] = [item.meta for item in loaded] + metas = _ensure_dims_in_metas( + name=name, plugin=plugin, metas=metas, ndim=tensors[0].ndim + ) + + sub_plans = compute_per_step_sub_plans( + metas=metas, + thd_global_seq_lens=( + thd_global_seq_lens if name in plugin.cp_sharded_names else None + ), + ) + if sub_plans: + dims_str: Optional[str] = metas[0].get("dims") + if dims_str is not None: + dim_names: list[str] = resolve_dim_names(dims_str) + tensors = [apply_dim_names(t, dim_names) for t in tensors] + + sub_result = execute_sub_plans(tensors=tensors, plans=sub_plans) + assert sub_result.tensor is not None + return sub_result.tensor.rename( + None + ) # strip named dims before returning to plugin + + log_sink.add( + InfoLog( + category="aux_no_dims", + message=( + f"aux tensor '{name}' has {len(tensors)} ranks " + f"but no dims metadata, using rank 0 only" + ), + ) + ) + return tensors[0] + + +def _ensure_dims_in_metas( + *, + name: str, + plugin: _AuxFrameworkPlugin, + metas: list[dict[str, Any]], + ndim: int, +) -> list[dict[str, Any]]: + """Inject inferred dims into metas if not already present. + + Returns metas unchanged if dims is already set, or a new list with dims + injected if inference succeeds for CP-sharded tensors. + """ + if metas[0].get("dims") is not None: + return metas + + parallel_infos = [normalize_parallel_info(m) for m in metas] + has_cp: bool = any(ParallelAxis.CP in info for info in parallel_infos) + if not has_cp: + return metas + + if name in plugin.cp_sharded_names: + inferred_dims: str = plugin.infer_cp_sharded_dims(name=name, ndim=ndim) + return [{**m, "dims": inferred_dims} for m in metas] + + return metas diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_plugins.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_plugins.py new file mode 100644 index 0000000000000000000000000000000000000000..8e497e9ecf6c36fd68ac0c1f667ce6cdfef33909 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/aux_plugins.py @@ -0,0 +1,292 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from typing import Optional + +import torch + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + PositionalSeqId, + SeqId, + SGLangSeqId, + TokenAlignerStepAux, +) +from sglang.srt.debug_utils.comparator.dims_spec import TokenLayout +from sglang.srt.debug_utils.comparator.log_sink import log_sink +from sglang.srt.debug_utils.comparator.output_types import InfoLog + +# ── plugin ABC ───────────────────────────────────────────────────── + + +class _AuxFrameworkPlugin(ABC): + @property + @abstractmethod + def name(self) -> str: ... + + @property + @abstractmethod + def tensor_names(self) -> frozenset[str]: ... + + @property + @abstractmethod + def non_tensor_names(self) -> frozenset[str]: ... + + @property + def cp_sharded_names(self) -> frozenset[str]: + return frozenset() + + @property + def discriminating_names(self) -> frozenset[str]: + """Field names unique to this framework (excluding shared names like input_ids).""" + return frozenset() + + @abstractmethod + def detect_layout(self, raw: dict[int, dict[str, object]]) -> TokenLayout: ... + + @abstractmethod + def compute_step_aux( + self, step_data: dict[str, object], *, layout: TokenLayout, step: int + ) -> TokenAlignerStepAux: ... + + @abstractmethod + def has_required_names(self, names: set[str]) -> bool: + """Whether the minimum set of aux names needed for alignment is present.""" + ... + + @property + def all_names(self) -> frozenset[str]: + return self.tensor_names | self.non_tensor_names + + def extract_global_seq_lens( + self, step_data: dict[str, object] + ) -> Optional[list[int]]: + """Extract per-seq token counts from loaded step data. + + Returns None if this framework doesn't support THD / no relevant data available. + """ + return None + + def infer_cp_sharded_dims(self, name: str, ndim: int) -> str: + """Infer dims string for a CP-sharded aux tensor based on its ndim.""" + raise NotImplementedError( + f"infer_cp_sharded_dims not implemented for {type(self).__name__}" + ) + + +# ── sglang plugin ───────────────────────────────────────────────── + + +class _SGLangPlugin(_AuxFrameworkPlugin): + @property + def name(self) -> str: + return "sglang" + + @property + def tensor_names(self) -> frozenset[str]: + return frozenset({"input_ids", "positions", "seq_lens", "req_pool_indices"}) + + @property + def non_tensor_names(self) -> frozenset[str]: + return frozenset({"rids"}) + + @property + def cp_sharded_names(self) -> frozenset[str]: + return frozenset({"input_ids", "positions"}) + + @property + def discriminating_names(self) -> frozenset[str]: + return frozenset({"seq_lens", "positions", "req_pool_indices", "rids"}) + + def has_required_names(self, names: set[str]) -> bool: + return "input_ids" in names and "seq_lens" in names + + def detect_layout(self, raw: dict[int, dict[str, object]]) -> TokenLayout: + return TokenLayout.T + + def extract_global_seq_lens( + self, step_data: dict[str, object] + ) -> Optional[list[int]]: + if not self.cp_sharded_names: + return None + + seq_lens = step_data.get("seq_lens") + if not isinstance(seq_lens, torch.Tensor): + return None + + return seq_lens.tolist() + + def infer_cp_sharded_dims(self, name: str, ndim: int) -> str: + """Infer dims for CP-sharded aux tensors. + + NOTE: assumes zigzag ordering — natural-order CP without explicit dims + will be mishandled. Callers should set dims explicitly for non-zigzag CP. + """ + if ndim == 1: + return "t[cp:zigzag]" + raise ValueError( + f"SGLang: cannot infer dims for CP-sharded '{name}' with ndim={ndim}" + ) + + def compute_step_aux( + self, step_data: dict[str, object], *, layout: TokenLayout, step: int + ) -> TokenAlignerStepAux: + input_ids = step_data["input_ids"] + positions = step_data["positions"] + seq_lens = step_data["seq_lens"] + rids_raw = step_data.get("rids") + + assert isinstance( + input_ids, torch.Tensor + ), f"input_ids: expected Tensor, got {type(input_ids)}" + assert isinstance( + positions, torch.Tensor + ), f"positions: expected Tensor, got {type(positions)}" + assert isinstance( + seq_lens, torch.Tensor + ), f"seq_lens: expected Tensor, got {type(seq_lens)}" + + seq_lens_list: list[int] = seq_lens.tolist() + num_seqs: int = len(seq_lens_list) + + seq_ids: list[SeqId] + if rids_raw is not None and isinstance(rids_raw, (list, tuple)): + seq_ids = [SGLangSeqId(rid=str(r)) for r in rids_raw] + else: + seq_ids = [PositionalSeqId(step=step, seq_index=i) for i in range(num_seqs)] + + return TokenAlignerStepAux( + input_ids=input_ids.tolist(), + positions=positions.tolist(), + seq_lens=seq_lens_list, + seq_ids=seq_ids, + ) + + +# ── megatron plugin ─────────────────────────────────────────────── + + +class _MegatronPlugin(_AuxFrameworkPlugin): + @property + def name(self) -> str: + return "megatron" + + @property + def tensor_names(self) -> frozenset[str]: + return frozenset({"input_ids", "position_ids", "cu_seqlens_q", "cu_seqlens_kv"}) + + @property + def non_tensor_names(self) -> frozenset[str]: + return frozenset({"qkv_format"}) + + @property + def cp_sharded_names(self) -> frozenset[str]: + return frozenset({"input_ids", "position_ids"}) + + @property + def discriminating_names(self) -> frozenset[str]: + return frozenset({"cu_seqlens_q", "cu_seqlens_kv", "qkv_format"}) + + def has_required_names(self, names: set[str]) -> bool: + return "input_ids" in names + + def extract_global_seq_lens( + self, step_data: dict[str, object] + ) -> Optional[list[int]]: + if not self.cp_sharded_names: + return None + + cu_seqlens_q = step_data.get("cu_seqlens_q") + if not isinstance(cu_seqlens_q, torch.Tensor): + return None + + return (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).tolist() + + def infer_cp_sharded_dims(self, name: str, ndim: int) -> str: + """Infer dims for CP-sharded aux tensors. + + NOTE: assumes zigzag ordering — natural-order CP without explicit dims + will be mishandled. Callers should set dims explicitly for non-zigzag CP. + """ + if ndim == 1: + return "t[cp:zigzag]" + if ndim == 2: + return "b s[cp:zigzag]" + raise ValueError( + f"Megatron: cannot infer dims for CP-sharded '{name}' with ndim={ndim}" + ) + + def detect_layout(self, raw: dict[int, dict[str, object]]) -> TokenLayout: + for step_data in raw.values(): + if (qkv_format := step_data.get("qkv_format")) is not None: + fmt = qkv_format if isinstance(qkv_format, str) else str(qkv_format) + if "bshd" in fmt.lower(): + return TokenLayout.BS + return TokenLayout.T + + input_ids = step_data.get("input_ids") + if isinstance(input_ids, torch.Tensor) and input_ids.ndim == 2: + return TokenLayout.BS + + log_sink.add( + InfoLog( + category="layout_detection_fallback", + message=( + "Megatron layout detection: no qkv_format or 2D input_ids found, " + "falling back to T" + ), + ) + ) + return TokenLayout.T + + def compute_step_aux( + self, step_data: dict[str, object], *, layout: TokenLayout, step: int + ) -> TokenAlignerStepAux: + input_ids: torch.Tensor = step_data["input_ids"] + is_bshd: bool = layout == TokenLayout.BS + + # BSHD [B, S] → flat [B*S]; THD [T] stays as-is + flat_ids: list[int] = input_ids.reshape(-1).tolist() + + if (cu_seqlens_q := step_data.get("cu_seqlens_q")) is not None: + seq_lens_list: list[int] = (cu_seqlens_q[1:] - cu_seqlens_q[:-1]).tolist() + elif is_bshd: + seq_lens_list = [input_ids.shape[1]] * input_ids.shape[0] + else: + seq_lens_list = [input_ids.shape[0]] + + if (position_ids := step_data.get("position_ids")) is not None: + flat_positions: list[int] = position_ids.reshape(-1).tolist() + elif is_bshd: + flat_positions = list(range(input_ids.shape[1])) * input_ids.shape[0] + else: + flat_positions = _infer_positions( + seq_lens=torch.tensor(seq_lens_list) + ).tolist() + + num_seqs: int = len(seq_lens_list) + seq_ids: list[SeqId] = [ + PositionalSeqId(step=step, seq_index=seq_index) + for seq_index in range(num_seqs) + ] + + return TokenAlignerStepAux( + input_ids=flat_ids, + positions=flat_positions, + seq_lens=seq_lens_list, + seq_ids=seq_ids, + ) + + +# ── plugin registry ─────────────────────────────────────────────── + +_plugins: list[_AuxFrameworkPlugin] = [_SGLangPlugin(), _MegatronPlugin()] + +AUX_NAMES: frozenset[str] = frozenset().union(*(p.all_names for p in _plugins)) + + +# ── helpers ──────────────────────────────────────────────────────── + + +def _infer_positions(*, seq_lens: torch.Tensor) -> torch.Tensor: + """Infer positions when position_ids is missing (THD only).""" + return torch.cat([torch.arange(int(slen.item())) for slen in seq_lens]) diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/executor.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/executor.py new file mode 100644 index 0000000000000000000000000000000000000000..98a4cca7d7ef40862fda1466f14cc7cc6738324c --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/executor.py @@ -0,0 +1,149 @@ +from __future__ import annotations + +import torch +from einops import rearrange + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + TokenAlignerPlan, + TokenLocator, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + BATCH_DIM_NAME, + SEQ_DIM_NAME, + TOKEN_DIM_NAME, + TokenLayout, + resolve_dim_by_name, + strip_dim_names, +) +from sglang.srt.debug_utils.comparator.utils import Pair + +_UNNAMED_TOKEN_DIM_FALLBACK: int = 0 + + +def execute_token_aligner( + plan: TokenAlignerPlan, + tensor_of_step_pair: Pair[dict[int, torch.Tensor]], +) -> Pair[torch.Tensor]: + flat_pair: Pair[dict[int, torch.Tensor]] = Pair( + x=_collapse_bs_to_t( + tensor_of_step=tensor_of_step_pair.x, layout=plan.layouts.x + ), + y=_collapse_bs_to_t( + tensor_of_step=tensor_of_step_pair.y, layout=plan.layouts.y + ), + ) + + if not plan.locators.x.steps: + return Pair( + x=_make_empty(tensor_of_step=flat_pair.x), + y=_make_empty(tensor_of_step=flat_pair.y), + ) + + return Pair( + x=_extract_and_stack_tokens( + tensor_of_step=flat_pair.x, locator=plan.locators.x + ), + y=_extract_and_stack_tokens( + tensor_of_step=flat_pair.y, locator=plan.locators.y + ), + ) + + +# ── BS → T preprocessing ───────────────────────────────────────── + + +def _collapse_bs_to_t( + *, + tensor_of_step: dict[int, torch.Tensor], + layout: TokenLayout, +) -> dict[int, torch.Tensor]: + """Collapse B and S dims into a single flat token dim (always batch-major). + + Handles both ``b s`` and ``s b`` orderings correctly via einops rearrange. + Returns the original tensors unchanged if layout is T. + """ + if layout != TokenLayout.BS: + return tensor_of_step + + some_tensor: torch.Tensor = next(iter(tensor_of_step.values())) + batch_dim: int = _resolve_dim_or_fallback(some_tensor, BATCH_DIM_NAME) + seq_dim: int = _resolve_dim_or_fallback(some_tensor, SEQ_DIM_NAME) + + if abs(batch_dim - seq_dim) != 1: + raise ValueError( + f"BS dims must be adjacent: " + f"{BATCH_DIM_NAME}={batch_dim}, " + f"{SEQ_DIM_NAME}={seq_dim}" + ) + + lhs_pattern, rhs_pattern, new_names = _build_bs_collapse_pattern( + names=list(some_tensor.names), + batch_dim=batch_dim, + seq_dim=seq_dim, + ) + + result: dict[int, torch.Tensor] = {} + for step, tensor in tensor_of_step.items(): + plain: torch.Tensor = strip_dim_names(tensor) + collapsed: torch.Tensor = rearrange(plain, f"{lhs_pattern} -> {rhs_pattern}") + result[step] = collapsed.refine_names(*new_names) + + return result + + +def _build_bs_collapse_pattern( + *, + names: list[str | None], + batch_dim: int, + seq_dim: int, +) -> tuple[str, str, list[str | None]]: + """Build einops lhs/rhs patterns and output dim names for BS→T collapse. + + Always produces batch-major order ``(b s)`` regardless of input ordering. + Uses the tensor's own dim names as einops axis names. + """ + lo: int = min(batch_dim, seq_dim) + hi: int = max(batch_dim, seq_dim) + + lhs: str = " ".join(names) # type: ignore[arg-type] + + rhs_names: list[str] = list(names[:lo]) + [f"({BATCH_DIM_NAME} {SEQ_DIM_NAME})"] + list(names[hi + 1 :]) # type: ignore[misc] + rhs: str = " ".join(rhs_names) + + new_names: list[str | None] = ( + list(names[:lo]) + [TOKEN_DIM_NAME] + list(names[hi + 1 :]) + ) + + return lhs, rhs, new_names + + +# ── core logic (T layout only) ─────────────────────────────────── + + +def _resolve_dim_or_fallback(tensor: torch.Tensor, name: str) -> int: + if tensor.names[0] is None: + return _UNNAMED_TOKEN_DIM_FALLBACK + return resolve_dim_by_name(tensor, name) + + +def _make_empty(*, tensor_of_step: dict[int, torch.Tensor]) -> torch.Tensor: + dummy: torch.Tensor = next(iter(tensor_of_step.values())) + token_dim: int = _resolve_dim_or_fallback(dummy, TOKEN_DIM_NAME) + shape: list[int] = list(dummy.shape) + shape[token_dim] = 0 + return torch.empty(shape, dtype=dummy.dtype) + + +def _extract_and_stack_tokens( + *, + tensor_of_step: dict[int, torch.Tensor], + locator: TokenLocator, +) -> torch.Tensor: + some_tensor: torch.Tensor = next(iter(tensor_of_step.values())) + token_dim: int = _resolve_dim_or_fallback(some_tensor, TOKEN_DIM_NAME) + + tokens: list[torch.Tensor] = [ + strip_dim_names(tensor_of_step[s]).select(dim=token_dim, index=i) + for s, i in zip(locator.steps, locator.token_index_in_step) + ] + return torch.stack(tokens, dim=token_dim) diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/planner.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/planner.py new file mode 100644 index 0000000000000000000000000000000000000000..c774f7d2a9d2d038af8b0e82118f26b997438d67 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/planner.py @@ -0,0 +1,135 @@ +from __future__ import annotations + +from collections import defaultdict +from typing import NamedTuple, Optional + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + SeqId, + TokenAlignerPlan, + TokenAlignerSeqInfo, + TokenAlignerSeqsInfo, + TokenLocator, +) +from sglang.srt.debug_utils.comparator.utils import Pair + + +def compute_token_aligner_plan( + seqs_info_pair: Pair[TokenAlignerSeqsInfo], +) -> TokenAlignerPlan: + """Compute a token alignment plan from two side token seqs_info_pair.""" + matched_pairs: list[tuple[SeqId, SeqId]] = _match_sequences( + seqs=Pair(x=seqs_info_pair.x.sequences, y=seqs_info_pair.y.sequences) + ) + + _empty = TokenLocator(steps=[], token_index_in_step=[]) + locator_x: TokenLocator = _empty + locator_y: TokenLocator = _empty + + for seq_id_x, seq_id_y in matched_pairs: + rec: Pair[TokenAlignerSeqInfo] = Pair( + x=seqs_info_pair.x.sequences[seq_id_x], + y=seqs_info_pair.y.sequences[seq_id_y], + ) + + # positions is validated to be [0, 1, ..., N-1], so position == index + # and the common range is simply [0, min(len_x, len_y)). + common_len: int = min(len(rec.x.positions), len(rec.y.positions)) + + x_ids = rec.x.input_ids[:common_len] + y_ids = rec.y.input_ids[:common_len] + assert x_ids == y_ids, f"{seq_id_x=} {seq_id_y=} {x_ids=} {y_ids=}" + + locator_x = locator_x + TokenLocator( + steps=rec.x.locator.steps[:common_len], + token_index_in_step=rec.x.locator.token_index_in_step[:common_len], + ) + locator_y = locator_y + TokenLocator( + steps=rec.y.locator.steps[:common_len], + token_index_in_step=rec.y.locator.token_index_in_step[:common_len], + ) + + return TokenAlignerPlan( + locators=Pair(x=locator_x, y=locator_y), + layouts=seqs_info_pair.map(lambda s: s.layout), + ) + + +# -------------------- Sequence matcher -------------------- + + +def _match_sequences( + seqs: Pair[dict[SeqId, TokenAlignerSeqInfo]], +) -> list[tuple[SeqId, SeqId]]: + """For each y (target) sequence, find a matching x (baseline) sequence. + + Two-pass: exact match first, then prefix match for remaining. + """ + x_lookup: dict[tuple[int, ...], list[SeqId]] = defaultdict(list) + for seq_id, rec in seqs.x.items(): + x_lookup[tuple(rec.input_ids)].append(seq_id) + + claimed_x_ids: set[SeqId] = set() + matched_seq_id_pairs: list[tuple[SeqId, SeqId]] = [] + + for seq_id_y in sorted(seqs.y.keys()): + seq_y: TokenAlignerSeqInfo = seqs.y[seq_id_y] + + matched_x: Optional[SeqId] = _find_matching_x_exact( + seq_y=seq_y, x_lookup=x_lookup, claimed_x_ids=claimed_x_ids + ) + if matched_x is None: + matched_x = _find_matching_x_prefix( + seq_y=seq_y, x_seqs=seqs.x, claimed_x_ids=claimed_x_ids + ) + + if matched_x is not None: + matched_seq_id_pairs.append((matched_x, seq_id_y)) + claimed_x_ids.add(matched_x) + + return matched_seq_id_pairs + + +def _find_matching_x_exact( + *, + seq_y: TokenAlignerSeqInfo, + x_lookup: dict[tuple[int, ...], list[SeqId]], + claimed_x_ids: set[SeqId], +) -> Optional[SeqId]: + """Find an x sequence with identical input_ids.""" + ids_y_key: tuple[int, ...] = tuple(seq_y.input_ids) + candidates: list[SeqId] = x_lookup.get(ids_y_key, []) + for candidate in candidates: + if candidate not in claimed_x_ids: + return candidate + return None + + +class _PrefixCandidate(NamedTuple): + seq_id_x: SeqId + overlap_len: int + + +def _find_matching_x_prefix( + *, + seq_y: TokenAlignerSeqInfo, + x_seqs: dict[SeqId, TokenAlignerSeqInfo], + claimed_x_ids: set[SeqId], +) -> Optional[SeqId]: + """Find the x sequence with the longest prefix relationship to y.""" + ids_y: list[int] = seq_y.input_ids + candidates: list[_PrefixCandidate] = [ + _PrefixCandidate( + seq_id_x=seq_id_x, overlap_len=min(len(seq_x.input_ids), len(ids_y)) + ) + for seq_id_x, seq_x in x_seqs.items() + if seq_id_x not in claimed_x_ids and _is_prefix_pair(seq_x.input_ids, ids_y) + ] + if not candidates: + return None + return max(candidates, key=lambda c: c.overlap_len).seq_id_x + + +def _is_prefix_pair(a: list[int], b: list[int]) -> bool: + """True if a is a prefix of b, or b is a prefix of a.""" + shorter_len: int = min(len(a), len(b)) + return a[:shorter_len] == b[:shorter_len] diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/seq_info_builder.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/seq_info_builder.py new file mode 100644 index 0000000000000000000000000000000000000000..7cbbfe3a5a67f5ee8f189d4e3b424a193609feae --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/seq_info_builder.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from sglang.srt.debug_utils.comparator.aligner.token_aligner.smart.types import ( + SeqId, + TokenAlignerGlobalAux, + TokenAlignerSeqInfo, + TokenAlignerSeqsInfo, + TokenAlignerStepAux, + TokenLocator, +) + + +@dataclass +class _SeqInfoAccumulator: + """Mutable accumulator for building TokenAlignerSeqInfo without per-step validation.""" + + input_ids: list[int] = field(default_factory=list) + positions: list[int] = field(default_factory=list) + steps: list[int] = field(default_factory=list) + token_index_in_step: list[int] = field(default_factory=list) + + def extend( + self, + *, + input_ids: list[int], + positions: list[int], + steps: list[int], + token_index_in_step: list[int], + ) -> None: + self.input_ids.extend(input_ids) + self.positions.extend(positions) + self.steps.extend(steps) + self.token_index_in_step.extend(token_index_in_step) + + def build(self) -> TokenAlignerSeqInfo: + return TokenAlignerSeqInfo( + input_ids=self.input_ids, + positions=self.positions, + locator=TokenLocator( + steps=self.steps, + token_index_in_step=self.token_index_in_step, + ), + ) + + +def build_seqs_info(global_aux: TokenAlignerGlobalAux) -> TokenAlignerSeqsInfo: + """Build sequence info for one side from its auxiliary tensors.""" + return TokenAlignerSeqsInfo( + sequences=_build_token_aligner_seq_infos(global_aux), + layout=global_aux.layout, + ) + + +def _build_token_aligner_seq_infos( + global_aux: TokenAlignerGlobalAux, +) -> dict[SeqId, TokenAlignerSeqInfo]: + """Build token index for any framework/layout using seq_ids for identity tracking.""" + accum: dict[SeqId, _SeqInfoAccumulator] = {} + + for step in sorted(global_aux.step_auxs.keys()): + aux: TokenAlignerStepAux = global_aux.step_auxs[step] + + offset: int = 0 + for seq_index, seq_len in enumerate(aux.seq_lens): + seq_id: SeqId = aux.seq_ids[seq_index] + + if seq_id not in accum: + accum[seq_id] = _SeqInfoAccumulator() + + accum[seq_id].extend( + input_ids=aux.input_ids[offset : offset + seq_len], + positions=aux.positions[offset : offset + seq_len], + steps=[step] * seq_len, + token_index_in_step=list(range(offset, offset + seq_len)), + ) + + offset += seq_len + + return {seq_id: acc.build() for seq_id, acc in accum.items()} diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/types.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/types.py new file mode 100644 index 0000000000000000000000000000000000000000..116c411d59fb7d80ae9d062a1f0fe61f1af8df02 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/token_aligner/smart/types.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import NamedTuple, Optional, Union + +from pydantic import model_validator + +from sglang.srt.debug_utils.comparator.dims_spec import TokenLayout +from sglang.srt.debug_utils.comparator.utils import ( + Pair, + _check_equal_lengths, + _FrozenBase, +) + + +class SGLangSeqId(NamedTuple): + rid: str + + +class PositionalSeqId(NamedTuple): + step: int + seq_index: int + + +SeqId = Union[SGLangSeqId, PositionalSeqId] + + +@dataclass(frozen=True) +class TokenAlignerStepAux: + """Normalized auxiliary tensors for a single step (framework-agnostic).""" + + input_ids: list[int] # [num_tokens] + positions: list[int] # [num_tokens] + seq_lens: list[int] # [num_seqs] + seq_ids: list[SeqId] # [num_seqs] — sequence identity + + def __post_init__(self) -> None: + _check_equal_lengths(input_ids=self.input_ids, positions=self.positions) + _check_equal_lengths(seq_lens=self.seq_lens, seq_ids=self.seq_ids) + + token_count: int = sum(self.seq_lens) + if token_count != len(self.input_ids): + raise ValueError( + f"sum(seq_lens)={token_count} != len(input_ids)={len(self.input_ids)}" + ) + + +@dataclass(frozen=True) +class TokenAlignerGlobalAux: + """Auxiliary tensors for one side across all steps + side-level metadata.""" + + step_auxs: dict[int, TokenAlignerStepAux] + framework: str # "sglang" | "megatron" + layout: TokenLayout + thd_seq_lens_by_step: Optional[dict[int, list[int]]] = field(default=None) + + +class TokenLocator(_FrozenBase): + """Locates tokens within a multi-step tensor store. + + token i is at tensor_of_step[steps[i]][token_index_in_step[i]]. + """ + + steps: list[int] + token_index_in_step: list[int] + + def __add__(self, other: TokenLocator) -> TokenLocator: + return TokenLocator( + steps=self.steps + other.steps, + token_index_in_step=self.token_index_in_step + other.token_index_in_step, + ) + + +class TokenAlignerSeqInfo(_FrozenBase): + """Information for a sequence, containing information to locate all the tokens inside the sequence.""" + + # All these fields are of shape (num_tokens_in_seq,) + input_ids: list[int] + positions: list[int] + locator: TokenLocator + + @model_validator(mode="after") + def _validate_fields(self) -> TokenAlignerSeqInfo: + n: int = len(self.input_ids) + _check_equal_lengths( + input_ids=self.input_ids, + positions=self.positions, + locator_steps=self.locator.steps, + locator_token_index_in_step=self.locator.token_index_in_step, + ) + + if self.positions != list(range(n)): + raise ValueError( + f"positions must be [0, 1, ..., {n - 1}], got {self.positions}" + ) + + return self + + def __add__(self, other: TokenAlignerSeqInfo) -> TokenAlignerSeqInfo: + return TokenAlignerSeqInfo( + input_ids=self.input_ids + other.input_ids, + positions=self.positions + other.positions, + locator=self.locator + other.locator, + ) + + +class TokenAlignerSeqsInfo(_FrozenBase): + """All sequences for one side across all steps.""" + + sequences: dict[SeqId, TokenAlignerSeqInfo] + layout: TokenLayout + + +class TokenAlignerPlan(_FrozenBase): + """Token alignment plan. locators.x[i] and locators.y[i] correspond to the same logical token.""" + + locators: Pair[TokenLocator] + layouts: Pair[TokenLayout] + + @model_validator(mode="after") + def _validate_fields(self) -> TokenAlignerPlan: + _check_equal_lengths( + locators_x_steps=self.locators.x.steps, + locators_x_token_index_in_step=self.locators.x.token_index_in_step, + locators_y_steps=self.locators.y.steps, + locators_y_token_index_in_step=self.locators.y.token_index_in_step, + ) + return self diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/__init__.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/executor.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/executor.py new file mode 100644 index 0000000000000000000000000000000000000000..788f365791b39da1015800bde6241198f55da7da --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/executor.py @@ -0,0 +1,183 @@ +from dataclasses import dataclass, field +from typing import Optional + +import torch + +from sglang.srt.debug_utils.comparator.aligner.unsharder.types import ( + ConcatParams, + CpThdConcatParams, + PickParams, + ReduceSumParams, + UnsharderParams, + UnsharderPlan, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + ParallelAxis, + resolve_dim_by_name, +) +from sglang.srt.debug_utils.comparator.output_types import ReplicatedCheckResult +from sglang.srt.debug_utils.comparator.tensor_comparator.comparator import compute_diff + +_REPLICATED_ATOL: float = 1e-6 + + +@dataclass(frozen=True) +class UnsharderResult: + tensors: list[torch.Tensor] + replicated_checks: list[ReplicatedCheckResult] = field(default_factory=list) + + +def execute_unsharder_plan( + plan: UnsharderPlan, + tensors: list[torch.Tensor], +) -> UnsharderResult: + result_tensors: list[torch.Tensor] = [] + all_checks: list[ReplicatedCheckResult] = [] + + for group_idx, group in enumerate(plan.groups): + group_tensors = [tensors[i] for i in group] + tensor, checks = _apply_unshard( + plan.params, + group_tensors, + axis=plan.axis, + group_index=group_idx, + ) + result_tensors.append(tensor) + all_checks.extend(checks) + + return UnsharderResult(tensors=result_tensors, replicated_checks=all_checks) + + +def _apply_unshard( + params: UnsharderParams, + ordered_tensors: list[torch.Tensor], + *, + axis: ParallelAxis, + group_index: int, +) -> tuple[torch.Tensor, list[ReplicatedCheckResult]]: + if isinstance(params, PickParams): + checks: list[ReplicatedCheckResult] = _verify_replicated_group( + ordered_tensors, + axis=axis, + group_index=group_index, + ) + return ordered_tensors[0], checks + + if isinstance(params, ConcatParams): + dim: int = resolve_dim_by_name(ordered_tensors[0], params.dim_name) + return torch.cat(ordered_tensors, dim=dim), [] + + if isinstance(params, CpThdConcatParams): + thd_dim: int = resolve_dim_by_name(ordered_tensors[0], params.dim_name) + return ( + _thd_concat( + ordered_tensors, + dim=thd_dim, + seq_lens_per_rank=params.seq_lens_per_rank, + ), + [], + ) + + if isinstance(params, ReduceSumParams): + stripped: list[torch.Tensor] = [t.rename(None) for t in ordered_tensors] + result: torch.Tensor = torch.stack(stripped).sum(dim=0) + names: tuple[Optional[str], ...] = ordered_tensors[0].names + if names[0] is not None: + result = result.refine_names(*names) + return result, [] + + raise ValueError(f"Unsupported unshard operation: {type(params).__name__}") + + +def _verify_replicated_group( + ordered_tensors: list[torch.Tensor], + *, + axis: ParallelAxis, + group_index: int, +) -> list[ReplicatedCheckResult]: + baseline: torch.Tensor = ordered_tensors[0].rename(None).float() + + return [ + _check_replicated_pair( + baseline=baseline, + other=ordered_tensors[i], + axis=axis, + group_index=group_index, + compared_index=i, + ) + for i in range(1, len(ordered_tensors)) + ] + + +def _check_replicated_pair( + *, + baseline: torch.Tensor, + other: torch.Tensor, + axis: ParallelAxis, + group_index: int, + compared_index: int, +) -> ReplicatedCheckResult: + other_float: torch.Tensor = other.rename(None).float() + + if baseline.shape != other_float.shape: + passed = False + diff_info = None + else: + diff_info = compute_diff( + x_baseline=baseline, + x_target=other_float, + diff_threshold=_REPLICATED_ATOL, + ) + passed = diff_info.max_abs_diff <= _REPLICATED_ATOL + + return ReplicatedCheckResult( + axis=axis.value, + group_index=group_index, + compared_index=compared_index, + baseline_index=0, + passed=passed, + atol=_REPLICATED_ATOL, + diff=diff_info, + ) + + +def _thd_concat( + ordered_tensors: list[torch.Tensor], + *, + dim: int, + seq_lens_per_rank: list[int], +) -> torch.Tensor: + """Per-seq concat across ranks for THD format. + + Each rank holds segments of each seq packed contiguously: + rank_data = [seq0_tokens | seq1_tokens | ... | pad_tokens] + + This function splits each rank by seq_lens, then interleaves across ranks + per-seq: [seqA_r0 + seqA_r1 + ... | seqB_r0 + seqB_r1 + ... | tail_pad]. + """ + names: tuple[Optional[str], ...] = ordered_tensors[0].names + stripped: list[torch.Tensor] = [t.rename(None) for t in ordered_tensors] + + # Split each rank into [seq0, seq1, ..., tail_remainder] + split_sizes: list[int] = list(seq_lens_per_rank) + remainder: int = stripped[0].shape[dim] - sum(split_sizes) + if remainder < 0: + raise ValueError( + f"sum(seq_lens_per_rank)={sum(split_sizes)} exceeds tensor dim size " + f"{stripped[0].shape[dim]} along dim={dim}" + ) + if remainder > 0: + split_sizes.append(remainder) + per_rank_splits: list[tuple[torch.Tensor, ...]] = [ + t.split(split_sizes, dim=dim) for t in stripped + ] + + # Per-seq concat across ranks, then concatenate all seqs + result: torch.Tensor = torch.cat( + [torch.cat(rank_parts, dim=dim) for rank_parts in zip(*per_rank_splits)], + dim=dim, + ) + + if names[0] is not None: + result = result.refine_names(*names) + return result diff --git a/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/planner.py b/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/planner.py new file mode 100644 index 0000000000000000000000000000000000000000..cde2a9a595d047fe44e5afed904e8bfcd1b9d143 --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/aligner/unsharder/planner.py @@ -0,0 +1,230 @@ +from collections import defaultdict +from typing import NamedTuple, Optional + +from sglang.srt.debug_utils.comparator.aligner.unsharder.types import ( + AxisInfo, + ConcatParams, + CpThdConcatParams, + PickParams, + ReduceSumParams, + UnsharderParams, + UnsharderPlan, +) +from sglang.srt.debug_utils.comparator.dims_spec import ( + TOKEN_DIM_NAME, + DimSpec, + ParallelAxis, + ParallelModifier, +) + +# _CoordsList[tensor_index][axis] = +# the axis_rank (shard position) of the tensor_index-th tensor along `axis` +# (e.g. coords[2] = {TP: 3} means tensor 2 is the 3rd shard in TP axis) +_CoordsList = list[dict[ParallelAxis, int]] + + +class _GroupResult(NamedTuple): + groups: list[list[int]] + projected_coords: _CoordsList + + +def compute_unsharder_plan( + dim_specs: list[DimSpec], + parallel_infos: list[dict[ParallelAxis, AxisInfo]], + *, + explicit_replicated_axes: frozenset[ParallelAxis] = frozenset(), + thd_global_seq_lens: Optional[list[int]] = None, +) -> list[UnsharderPlan]: + if not parallel_infos: + raise ValueError("parallel_infos must not be empty") + + # Within each dim spec, reverse modifier order: innermost shard (rightmost) unshards first. + reversed_sharded_modifiers: list[tuple[str, ParallelModifier]] = [ + (spec.sanitized_name, m) + for spec in dim_specs + for m in reversed(spec.parallel_modifiers) + ] + + sharded_axes_raw: set[ParallelAxis] = { + m.axis for _, m in reversed_sharded_modifiers + } + all_axes: set[ParallelAxis] = {axis for info in parallel_infos for axis in info} + + # axis annotated in dims but absent from all parallel_infos -> axis_size=1, skip + sharded_axes: set[ParallelAxis] = sharded_axes_raw & all_axes + reversed_sharded_modifiers = [ + (name, m) for name, m in reversed_sharded_modifiers if m.axis in sharded_axes + ] + + # RECOMPUTE_PSEUDO is always implicitly replicated (system-injected, not user-facing) + auto_replicated: frozenset[ParallelAxis] = frozenset( + {ParallelAxis.RECOMPUTE_PSEUDO} & all_axes + ) + effective_replicated: frozenset[ParallelAxis] = ( + explicit_replicated_axes | auto_replicated + ) + + _validate_explicit_replicated( + explicit_replicated_axes=effective_replicated, + sharded_axes=sharded_axes, + all_axes=all_axes, + ) + replicated_axes: frozenset[ParallelAxis] = effective_replicated + + if not sharded_axes and not replicated_axes: + return [] + + _validate( + axes_to_validate=sharded_axes | replicated_axes, + parallel_infos=parallel_infos, + ) + + current_coords: _CoordsList = [ + {axis: info[axis].axis_rank for axis in sharded_axes | replicated_axes} + for info in parallel_infos + ] + + axis_and_params: list[tuple[ParallelAxis, UnsharderParams]] = [ + (axis, PickParams()) for axis in sorted(replicated_axes, key=lambda a: a.value) + ] + [ + ( + modifier.axis, + _resolve_unshard_params( + modifier=modifier, + dim_name=dim_name, + parallel_infos=parallel_infos, + thd_global_seq_lens=thd_global_seq_lens, + ), + ) + for dim_name, modifier in reversed_sharded_modifiers + ] + + plans: list[UnsharderPlan] = [] + for axis, params in axis_and_params: + result = _group_and_project( + current_coords=current_coords, + target_axis=axis, + ) + plans.append(UnsharderPlan(axis=axis, params=params, groups=result.groups)) + current_coords = result.projected_coords + + return plans + + +def _validate_explicit_replicated( + *, + explicit_replicated_axes: frozenset[ParallelAxis], + sharded_axes: set[ParallelAxis], + all_axes: set[ParallelAxis], +) -> None: + """Validate explicit replicated declarations against sharded axes and parallel_infos.""" + invalid: frozenset[ParallelAxis] = explicit_replicated_axes - all_axes + if invalid: + invalid_names: str = ", ".join(sorted(a.value for a in invalid)) + raise ValueError( + f"Declared replicated axes {{{invalid_names}}} not found in parallel_infos " + f"(active axes: {{{', '.join(sorted(a.value for a in all_axes))}}})" + ) + + conflict: set[ParallelAxis] = explicit_replicated_axes & sharded_axes + if conflict: + conflict_names: str = ", ".join(sorted(a.value for a in conflict)) + raise ValueError( + f"Axes {{{conflict_names}}} declared as both sharded and replicated" + ) + + undeclared: set[ParallelAxis] = all_axes - sharded_axes - explicit_replicated_axes + if undeclared: + undeclared_names: str = ", ".join(sorted(a.value for a in undeclared)) + raise ValueError( + f"Axes {{{undeclared_names}}} are active (axis_size > 1) but not declared " + f"in dims. Annotate as sharded in dim spec or as '# axis:replicated'." + ) + + +def _validate( + *, + axes_to_validate: set[ParallelAxis], + parallel_infos: list[dict[ParallelAxis, AxisInfo]], +) -> None: + """Check that every rank has all axes, sizes are consistent, and ranks are complete.""" + axis_sizes: dict[ParallelAxis, int] = {} + + for world_rank, parallel_info in enumerate(parallel_infos): + for axis in axes_to_validate: + if axis not in parallel_info: + raise ValueError( + f"world_rank={world_rank} missing parallel_info for " + f"axis {axis.value!r}" + ) + + axis_info = parallel_info[axis] + if axis not in axis_sizes: + axis_sizes[axis] = axis_info.axis_size + elif axis_info.axis_size != axis_sizes[axis]: + raise ValueError( + f"Inconsistent axis_size for {axis.value}: " + f"expected {axis_sizes[axis]}, got {axis_info.axis_size} " + f"at world_rank={world_rank}" + ) + + for axis, expected_size in axis_sizes.items(): + seen_ranks = {info[axis].axis_rank for info in parallel_infos} + if seen_ranks != set(range(expected_size)): + raise ValueError( + f"axis_rank coverage for {axis.value} is incomplete: " + f"got {sorted(seen_ranks)}, expected 0..{expected_size - 1}" + ) + + +def _group_and_project( + *, + current_coords: _CoordsList, + target_axis: ParallelAxis, +) -> _GroupResult: + """Group tensors by other-axes coords, sort within group by target_axis rank.""" + # buckets[coords_excluding_target] = [(axis_rank, tensor_index), ...] + # e.g. when target_axis=CP: buckets[{(TP,0)}] = [(0, 1), (1, 3)] + # means tensor 1 (CP rank 0) and tensor 3 (CP rank 1) share TP rank 0 + buckets: dict[frozenset, list[tuple[int, int]]] = defaultdict(list) + + for idx, coords in enumerate(current_coords): + key = frozenset((k, v) for k, v in coords.items() if k != target_axis) + buckets[key].append((coords[target_axis], idx)) + + groups: list[list[int]] = [] + projected: _CoordsList = [] + for key in sorted(buckets, key=lambda k: sorted((a.value, v) for a, v in k)): + entries = sorted(buckets[key]) + groups.append([idx for _, idx in entries]) + projected.append(dict(key)) + + return _GroupResult(groups=groups, projected_coords=projected) + + +def _resolve_unshard_params( + *, + modifier: ParallelModifier, + dim_name: str, + parallel_infos: list[dict[ParallelAxis, AxisInfo]], + thd_global_seq_lens: Optional[list[int]] = None, +) -> UnsharderParams: + if modifier.reduction is not None: + return ReduceSumParams() + + if ( + dim_name == TOKEN_DIM_NAME + and modifier.axis == ParallelAxis.CP + and thd_global_seq_lens is not None + ): + axis_size: int = parallel_infos[0][modifier.axis].axis_size + for s in thd_global_seq_lens: + if s % axis_size != 0: + raise ValueError( + f"THD seq_len {s} is not divisible by cp_size {axis_size}. " + f"Sequences must be padded to a multiple of cp_size for CP zigzag." + ) + seq_lens_per_rank: list[int] = [s // axis_size for s in thd_global_seq_lens] + return CpThdConcatParams(dim_name=dim_name, seq_lens_per_rank=seq_lens_per_rank) + + return ConcatParams(dim_name=dim_name) diff --git a/sglang/python/sglang/srt/debug_utils/comparator/dims_spec/tensor_naming.py b/sglang/python/sglang/srt/debug_utils/comparator/dims_spec/tensor_naming.py new file mode 100644 index 0000000000000000000000000000000000000000..0f06ebadc4231b2e6529104f8f24203cdf44c81e --- /dev/null +++ b/sglang/python/sglang/srt/debug_utils/comparator/dims_spec/tensor_naming.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from typing import Optional + +import torch + +from sglang.srt.debug_utils.comparator.dims_spec.types import DimSpec + + +def find_dim_index(dim_specs: list[DimSpec], name: str) -> Optional[int]: + """Find index by name. Accepts both ``*``-form and ``___``-form for fused dims.""" + for i, spec in enumerate(dim_specs): + if spec.name == name or spec.sanitized_name == name: + return i + return None + + +def resolve_dim_by_name(tensor: torch.Tensor, name: str) -> int: + if tensor.names[0] is None: + raise ValueError(f"Tensor has no names, cannot resolve {name!r}") + + names: tuple[Optional[str], ...] = tensor.names + try: + return list(names).index(name) + except ValueError: + raise ValueError(f"Dim name {name!r} not in tensor names {names}") + + +def apply_dim_names(tensor: torch.Tensor, dim_names: list[str]) -> torch.Tensor: + if tensor.ndim != len(dim_names): + raise ValueError( + f"dims metadata mismatch: tensor has {tensor.ndim} dims (shape {list(tensor.shape)}) " + f"but dims string specifies {len(dim_names)} names {dim_names}. " + f"Please fix the dims string in the dumper.dump() call to match the actual tensor shape." + ) + return tensor.refine_names(*dim_names) + + +def strip_dim_names(tensor: torch.Tensor) -> torch.Tensor: + return tensor.rename(None) diff --git a/sglang/python/sglang/srt/disaggregation/fake/__init__.py b/sglang/python/sglang/srt/disaggregation/fake/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..137ecdef284c8357270cb1ebdc53f7806448221a --- /dev/null +++ b/sglang/python/sglang/srt/disaggregation/fake/__init__.py @@ -0,0 +1,5 @@ +from sglang.srt.disaggregation.fake.conn import ( + FakeKVManager, + FakeKVReceiver, + FakeKVSender, +) diff --git a/sglang/python/sglang/srt/disaggregation/fake/conn.py b/sglang/python/sglang/srt/disaggregation/fake/conn.py new file mode 100644 index 0000000000000000000000000000000000000000..4a3841e68208f296ee3d9189138ccc809fcc90b7 --- /dev/null +++ b/sglang/python/sglang/srt/disaggregation/fake/conn.py @@ -0,0 +1,110 @@ +import logging +from typing import List, Optional + +import numpy as np +import numpy.typing as npt + +from sglang.srt.disaggregation.base.conn import ( + BaseKVManager, + BaseKVReceiver, + BaseKVSender, + KVArgs, + KVPoll, +) +from sglang.srt.disaggregation.utils import DisaggregationMode +from sglang.srt.server_args import ServerArgs + +logger = logging.getLogger(__name__) + + +# For warmup reqs, we don't kv transfer, we use the fake manager, sender and receiver +class FakeKVManager(BaseKVManager): + def __init__( + self, + args: KVArgs, + disaggregation_mode: DisaggregationMode, + server_args: ServerArgs, + is_mla_backend: Optional[bool] = False, + ): + super().__init__(args, disaggregation_mode, server_args, is_mla_backend) + + def register_to_bootstrap(self): + pass + + +class FakeKVSender(BaseKVSender): + def __init__( + self, + mgr: BaseKVManager, + bootstrap_addr: str, + bootstrap_room: int, + dest_tp_ranks: List[int], + pp_rank: int, + ): + self.has_sent = False + + def poll(self) -> KVPoll: + if self.has_sent is False: + # Assume handshake completed instantly + return KVPoll.WaitingForInput + else: + # Assume transfer completed instantly + logger.debug("FakeKVSender poll success") + return KVPoll.Success + + def init( + self, + kv_indices: list[int], + aux_index: Optional[int] = None, + ): + logger.debug( + f"FakeKVSender init with kv_indices: {kv_indices}, aux_index: {aux_index}" + ) + pass + + def send( + self, + kv_indices: npt.NDArray[np.int32], + state_indices: Optional[List[int]] = None, + ): + self.has_sent = True + logger.debug( + f"FakeKVSender send with kv_indices: {kv_indices}, state_indices: {state_indices}" + ) + + def failure_exception(self): + raise Exception("Fake KVSender Exception") + + +class FakeKVReceiver(BaseKVReceiver): + def __init__( + self, + mgr: BaseKVManager, + bootstrap_addr: str, + bootstrap_room: Optional[int] = None, + prefill_dp_rank: Optional[int] = None, + ): + self.has_init = False + + def poll(self) -> KVPoll: + if self.has_init is False: + # Assume handshake completed instantly + return KVPoll.WaitingForInput + else: + # Assume transfer completed instantly + logger.debug("FakeKVReceiver poll success") + return KVPoll.Success + + def init( + self, + kv_indices: list[int], + aux_index: Optional[int] = None, + state_indices: Optional[List[int]] = None, + ): + self.has_init = True + logger.debug( + f"FakeKVReceiver init with kv_indices: {kv_indices}, aux_index: {aux_index}, state_indices: {state_indices}" + ) + + def failure_exception(self): + raise Exception("Fake KVReceiver Exception") diff --git a/sglang/python/sglang/srt/disaggregation/mooncake/utils.py b/sglang/python/sglang/srt/disaggregation/mooncake/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..63e7bd29de4e9732429621dd5cfb08cdc2b5b2d7 --- /dev/null +++ b/sglang/python/sglang/srt/disaggregation/mooncake/utils.py @@ -0,0 +1,112 @@ +# Copyright 2025 SGLang Team +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Mooncake-specific utilities for custom memory pool management.""" + +import logging +from typing import Any, Optional, Tuple + +import torch + +from sglang.srt.environ import envs + +logger = logging.getLogger(__name__) + +# Global constants for custom memory pool types +SUPPORTED_MOONCAKE_CUSTOM_MEM_POOL_TYPES = ["NVLINK", "BAREX", "INTRA_NVLINK"] + + +def init_mooncake_custom_mem_pool( + device: str, +) -> Tuple[bool, Optional[Any], Optional[str]]: + """ + Initialize custom memory pool based on environment variable. + + Args: + device: The device to allocate memory on + + Returns: + Tuple of (enable_custom_mem_pool, custom_mem_pool, custom_mem_pool_type) + """ + enable_custom_mem_pool, custom_mem_pool_type = ( + check_mooncake_custom_mem_pool_enabled() + ) + + custom_mem_pool = None + + if enable_custom_mem_pool: + try: + # TODO(shangming): abstract custom allocator class for more backends + if custom_mem_pool_type == "NVLINK": + from mooncake.allocator import NVLinkAllocator + + allocator = NVLinkAllocator.get_allocator(device) + elif custom_mem_pool_type == "BAREX": + from mooncake.allocator import BarexAllocator + + allocator = BarexAllocator.get_allocator(device) + elif custom_mem_pool_type == "INTRA_NODE_NVLINK": + return False, None, None + else: + # This should not happen due to the enable_custom_mem_pool check above + raise ValueError( + f"Unsupported custom mem pool type: {custom_mem_pool_type}" + ) + + custom_mem_pool = torch.cuda.MemPool(allocator.allocator()) + logger.debug( + f"Initialized custom memory pool: {custom_mem_pool_type} on device {device}" + ) + except ImportError as e: + logger.warning( + f"Failed to import mooncake allocator for {custom_mem_pool_type}: {e}. " + f"Falling back to default memory pool." + ) + enable_custom_mem_pool = False + custom_mem_pool = None + custom_mem_pool_type = None + except Exception as e: + logger.error( + f"Failed to initialize custom memory pool {custom_mem_pool_type}: {e}. " + f"Falling back to default memory pool." + ) + enable_custom_mem_pool = False + custom_mem_pool = None + custom_mem_pool_type = None + else: + return False, None, None + + return enable_custom_mem_pool, custom_mem_pool, custom_mem_pool_type + + +def check_mooncake_custom_mem_pool_enabled() -> Tuple[bool, Optional[str]]: + """ + Check if custom memory pool is enabled without importing allocators. + + Returns: + Tuple of (enable_custom_mem_pool, custom_mem_pool_type) + """ + custom_mem_pool_type = envs.SGLANG_MOONCAKE_CUSTOM_MEM_POOL.get() + + if custom_mem_pool_type is not None: + # Handle boolean True as NVLINK + if custom_mem_pool_type.lower() == "true": + custom_mem_pool_type = "NVLINK" + enable_custom_mem_pool = ( + custom_mem_pool_type in SUPPORTED_MOONCAKE_CUSTOM_MEM_POOL_TYPES + ) + else: + enable_custom_mem_pool = False + custom_mem_pool_type = None + + return enable_custom_mem_pool, custom_mem_pool_type diff --git a/sglang/python/sglang/srt/disaggregation/mori/__init__.py b/sglang/python/sglang/srt/disaggregation/mori/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..f537f00b4a30427479db4a99dd7895c675717f61 --- /dev/null +++ b/sglang/python/sglang/srt/disaggregation/mori/__init__.py @@ -0,0 +1,6 @@ +from sglang.srt.disaggregation.mori.conn import ( + MoriKVBootstrapServer, + MoriKVManager, + MoriKVReceiver, + MoriKVSender, +) diff --git a/sglang/python/sglang/srt/disaggregation/mori/conn.py b/sglang/python/sglang/srt/disaggregation/mori/conn.py new file mode 100644 index 0000000000000000000000000000000000000000..ff7d3a0561710af21953d157602d513c96d98c6d --- /dev/null +++ b/sglang/python/sglang/srt/disaggregation/mori/conn.py @@ -0,0 +1,1123 @@ +from __future__ import annotations + +import ctypes +import dataclasses +import logging +import os +import struct +import threading +import time +from typing import Dict, List, Optional, Tuple + +import msgspec +import numpy as np +import numpy.typing as npt +from mori.cpp import TransferStatus +from mori.io import ( + BackendType, + EngineDesc, + IOEngine, + IOEngineConfig, + MemoryDesc, + MemoryLocationType, + PollCqMode, + RdmaBackendConfig, +) + +from sglang.srt.disaggregation.base.conn import KVArgs, KVPoll +from sglang.srt.disaggregation.common.conn import ( + CommonKVBootstrapServer, + CommonKVManager, + CommonKVReceiver, + CommonKVSender, +) +from sglang.srt.disaggregation.common.utils import group_concurrent_contiguous +from sglang.srt.disaggregation.utils import ( + DisaggregationMode, + filter_kv_indices_for_cp_rank, +) +from sglang.srt.server_args import ServerArgs +from sglang.srt.utils.common import ( + format_tcp_address, + get_int_env_var, + get_local_ip_auto, + is_valid_ipv6_address, +) + +logger = logging.getLogger(__name__) +MORI_GUARD = b"MoriMsgGuard" + + +def _pack_mem_desc_list(mems: List[MemoryDesc]) -> bytes: + if not mems: + return b"" + packed_descs = [mem.pack() for mem in mems] + return msgspec.msgpack.encode(packed_descs) + + +def _unpack_mem_desc_list(blob: bytes) -> List[MemoryDesc]: + if not blob: + return [] + desc_blobs = msgspec.msgpack.decode(blob) + return [MemoryDesc.unpack(b) for b in desc_blobs] + + +@dataclasses.dataclass +class TransferInfo: + room: int + endpoint: str + dst_port: int + engine_key: str + dst_kv_indices: npt.NDArray[np.int32] + dst_aux_index: int + required_dst_info_num: int + is_dummy: bool + + @classmethod + def from_zmq(cls, payload: List[bytes]) -> TransferInfo: + room = int(payload[0].decode("ascii")) + endpoint = payload[1].decode("ascii") + dst_port = int(payload[2].decode("ascii")) + engine_key = payload[3].decode("ascii") + + if payload[4]: + dst_kv_indices = np.frombuffer(payload[4], dtype=np.int32) + else: + dst_kv_indices = np.array([], dtype=np.int32) + + if payload[5]: + dst_aux_index = int(payload[5].decode("ascii")) + else: + dst_aux_index = -1 + + required_dst_info_num = ( + int(payload[7].decode("ascii")) if len(payload) > 7 else 1 + ) + is_dummy = dst_kv_indices.size == 0 and dst_aux_index < 0 + return cls( + room=room, + endpoint=endpoint, + dst_port=dst_port, + engine_key=engine_key, + dst_kv_indices=dst_kv_indices, + dst_aux_index=dst_aux_index, + required_dst_info_num=required_dst_info_num, + is_dummy=is_dummy, + ) + + +@dataclasses.dataclass +class KVArgsRegisterInfo: + endpoint: str + dst_port: int + engine_desc: EngineDesc + dst_kv_mem_descs: List[MemoryDesc] + dst_aux_mem_descs: List[MemoryDesc] + dst_state_mem_descs: List[MemoryDesc] + gpu_id: int + decode_tp_size: int + decode_tp_rank: int + dst_kv_item_len: int + + @property + def engine_key(self) -> str: + return self.engine_desc.key + + @classmethod + def from_zmq(cls, payload: List[bytes]) -> KVArgsRegisterInfo: + endpoint = payload[1].decode("ascii") + dst_port = int(payload[2].decode("ascii")) + engine_desc = EngineDesc.unpack(payload[3]) + dst_kv_mem_descs = _unpack_mem_desc_list(payload[4]) + dst_aux_mem_descs = _unpack_mem_desc_list(payload[5]) + dst_state_mem_descs = _unpack_mem_desc_list(payload[6]) + gpu_id = int(payload[7].decode("ascii")) + decode_tp_size = int(payload[8].decode("ascii")) + decode_tp_rank = int(payload[9].decode("ascii")) + dst_kv_item_len = int(payload[10].decode("ascii")) + return cls( + endpoint=endpoint, + dst_port=dst_port, + engine_desc=engine_desc, + dst_kv_mem_descs=dst_kv_mem_descs, + dst_aux_mem_descs=dst_aux_mem_descs, + dst_state_mem_descs=dst_state_mem_descs, + gpu_id=gpu_id, + decode_tp_size=decode_tp_size, + decode_tp_rank=decode_tp_rank, + dst_kv_item_len=dst_kv_item_len, + ) + + +class AuxDataCodec: + @staticmethod + def serialize_data_from_buffer(src_addr, data_length): + buffer = (ctypes.c_byte * data_length).from_address(src_addr) + return bytes(buffer) + + @staticmethod + def deserialize_data_to_buffer(kv_args, buffer_index, aux_index, data): + dst_aux_ptr = kv_args.aux_data_ptrs[buffer_index] + item_len = kv_args.aux_item_lens[buffer_index] + dst_addr = dst_aux_ptr + item_len * aux_index + buffer = (ctypes.c_byte * len(data)).from_address(dst_addr) + buffer[:] = data + return + + +@dataclasses.dataclass +class TPSliceConfig: + page_size: int + src_item_len: int + dst_item_len: int + bytes_per_token_src: int + bytes_per_token_dst: int + src_head_slice_offset: int + dst_head_slice_offset: int + heads_bytes_per_token_to_send: int + + +class MoriKVManager(CommonKVManager): + AUX_DATA_HEADER = b"AUX_DATA" + + def __init__( + self, + args: KVArgs, + disaggregation_mode: DisaggregationMode, + server_args: ServerArgs, + is_mla_backend: Optional[bool] = False, + ): + super().__init__(args, disaggregation_mode, server_args, is_mla_backend) + self.engine = self._init_engine() + self.engine_desc = self.engine.get_engine_desc() + self.kv_mem_descs: List[MemoryDesc] = [] + self.aux_mem_descs: List[MemoryDesc] = [] + self.state_mem_descs: List[MemoryDesc] = [] + self.transfer_lock = threading.Lock() + self._register_local_buffers() + if self.disaggregation_mode == DisaggregationMode.PREFILL: + self._start_bootstrap_thread() + elif self.disaggregation_mode == DisaggregationMode.DECODE: + self.room_to_bootstrap_addr: Dict[int, str] = {} + self._start_decode_thread() + + def _init_engine(self) -> IOEngine: + if self.kv_args.ib_device: + os.environ["MORI_RDMA_DEVICES"] = self.kv_args.ib_device + + self.local_ip = get_local_ip_auto() + config = IOEngineConfig(host=self.local_ip, port=0) + + engine_key = ( + f"io-{self.disaggregation_mode.value}-" + f"dp{self.system_dp_rank}-tp{self.attn_tp_rank}-" + f"pid{os.getpid()}-{self.local_ip}" + ) + + engine = IOEngine(engine_key, config) + poll_mode = PollCqMode.POLLING + + # Number of RDMA Queue Pairs (QPs) used per transfer operation. + # Higher values can increase parallelism and bandwidth utilization. + # Default: 1 + qp_per_transfer = get_int_env_var("SGLANG_MORI_QP_PER_TRANSFER", 1) + + # Number of RDMA work requests posted in a single batch to each QP. + # Larger batch sizes reduce per-operation overhead and improve throughput + # at the cost of higher latency. Use -1 for automatic sizing based on + # the number of merged work requests and available endpoints. + # Default: -1 (automatic) + post_batch_size = get_int_env_var("SGLANG_MORI_POST_BATCH_SIZE", -1) + + # Number of worker threads in the RDMA executor thread pool. + # Each worker handles RDMA operations on a separate CPU core (with affinity). + # More workers can improve parallelism for large batch transfers across + # multiple QPs, but excessive threads may cause contention. + # Default: 1 + num_worker_threads = get_int_env_var("SGLANG_MORI_NUM_WORKERS", 1) + + rdma_cfg = RdmaBackendConfig( + qp_per_transfer, + post_batch_size, + num_worker_threads, + poll_mode, + False, + ) + engine.create_backend(BackendType.RDMA, rdma_cfg) + actual_port = engine.get_engine_desc().port + assert actual_port > 0, f"Failed to bind port for engine {engine_key}" + logger.debug( + "Initialized Mori IOEngine %s at %s:%s (qp_per_transfer=%s, workers=%s, poll_mode=%s)", + engine_key, + self.local_ip, + actual_port, + qp_per_transfer, + num_worker_threads, + poll_mode.name, + ) + return engine + + def _register_local_buffers(self) -> None: + for ptr, length in zip(self.kv_args.kv_data_ptrs, self.kv_args.kv_data_lens): + mem_desc = self.engine.register_memory( + ptr, + length, + self.kv_args.gpu_id, + MemoryLocationType.GPU, + ) + self.kv_mem_descs.append(mem_desc) + for ptr, length in zip(self.kv_args.aux_data_ptrs, self.kv_args.aux_data_lens): + desc = self.engine.register_memory( + ptr, + length, + -1, + MemoryLocationType.CPU, + ) + self.aux_mem_descs.append(desc) + for ptr, length in zip( + self.kv_args.state_data_ptrs, getattr(self.kv_args, "state_data_lens", []) + ): + desc = self.engine.register_memory( + ptr, + length, + self.kv_args.gpu_id, + MemoryLocationType.GPU, + ) + self.state_mem_descs.append(desc) + + def _handle_register_message(self, payload: List[bytes]) -> None: + try: + register_info = KVArgsRegisterInfo.from_zmq(payload) + self._add_remote_peer(register_info) + except Exception: + logger.exception("Failed to register remote peer") + + def _handle_transfer_message(self, payload: List[bytes]) -> None: + try: + transfer_info = TransferInfo.from_zmq(payload) + infos = self.transfer_infos.setdefault(transfer_info.room, {}) + infos[transfer_info.engine_key] = transfer_info + + if len(infos) >= transfer_info.required_dst_info_num: + logger.debug( + "Bootstrap room %s got enough transfer info (%s)", + transfer_info.room, + len(infos), + ) + self.update_status(transfer_info.room, KVPoll.WaitingForInput) + except Exception: + logger.exception("Failed to parse transfer info message") + + def _validate_message(self, msg: List[bytes]) -> Optional[List[bytes]]: + if not msg or msg[0] != MORI_GUARD: + logger.warning("Received malformed bootstrap message") + return None + payload = msg[1:] + if not payload: + return None + return payload + + def _start_bootstrap_thread(self) -> None: + def bootstrap_worker(): + while True: + try: + msg = self.server_socket.recv_multipart() + payload = self._validate_message(msg) + if payload is None: + continue + room = payload[0].decode("ascii") + + if room == "None": + self._handle_register_message(payload) + else: + self._handle_transfer_message(payload) + except Exception: + logger.exception("Bootstrap worker failed") + + threading.Thread(target=bootstrap_worker, daemon=True).start() + + def _cleanup_room_tracking(self, bootstrap_room: int) -> None: + bootstrap_addr = self.room_to_bootstrap_addr.pop(bootstrap_room, None) + if bootstrap_addr is not None: + rooms = self.addr_to_rooms_tracker.get(bootstrap_addr) + if rooms is not None: + rooms.discard(bootstrap_room) + if not rooms: + self.addr_to_rooms_tracker.pop(bootstrap_addr, None) + + def _start_decode_thread(self) -> None: + def decode_worker(): + while True: + try: + msg = self.server_socket.recv_multipart() + if msg and msg[0] == MoriKVManager.AUX_DATA_HEADER: + self._handle_aux_data(msg) + continue + + if not msg or msg[0] != MORI_GUARD: + logger.warning( + "Received malformed status message on decode worker" + ) + continue + payload = msg[1:] + if len(payload) < 3: + logger.warning("Incomplete status payload received") + continue + bootstrap_room = int(payload[0].decode("ascii")) + status_code = int(payload[1].decode("ascii")) + prefill_rank = int(payload[2].decode("ascii")) + failure_reason = ( + payload[3].decode("utf-8") + if len(payload) > 3 and payload[3] + else None + ) + + if status_code == KVPoll.Success: + tracker = self.prefill_response_tracker[bootstrap_room] + tracker.add(prefill_rank) + expected = self.required_prefill_response_num_table.get( + bootstrap_room, 1 + ) + if len(tracker) >= expected: + self.prefill_response_tracker.pop(bootstrap_room, None) + self.update_status(bootstrap_room, KVPoll.Success) + self._cleanup_room_tracking(bootstrap_room) + elif status_code == KVPoll.Failed: + if failure_reason: + self.record_failure(bootstrap_room, failure_reason) + self.prefill_response_tracker.pop(bootstrap_room, None) + self.update_status(bootstrap_room, KVPoll.Failed) + self._cleanup_room_tracking(bootstrap_room) + else: + logger.warning( + "Unknown status code %s received for room %s", + status_code, + bootstrap_room, + ) + except Exception: + logger.exception("Decode status worker failed") + + threading.Thread(target=decode_worker, daemon=True).start() + + def notify_decode_status( + self, + infos: List[TransferInfo], + bootstrap_room: int, + status: KVPoll, + failure_reason: Optional[str] = None, + ) -> None: + if not infos: + return + payload = [ + MORI_GUARD, + str(bootstrap_room).encode("ascii"), + str(int(status)).encode("ascii"), + str(self.attn_tp_rank * self.pp_size + self.pp_rank).encode("ascii"), + failure_reason.encode("utf-8") if failure_reason else b"", + ] + for info in infos: + try: + endpoint = format_tcp_address(info.endpoint, info.dst_port) + socket = self._connect( + endpoint, is_ipv6=is_valid_ipv6_address(info.endpoint) + ) + socket.send_multipart(payload) + except Exception: + logger.exception( + "Failed to sync status %s to decode endpoint %s:%s for room %s", + status, + info.endpoint, + info.dst_port, + bootstrap_room, + ) + + def _add_remote_peer(self, register_info: KVArgsRegisterInfo) -> None: + engine_key = register_info.engine_key + if engine_key in self.decode_kv_args_table: + logger.debug("Remote peer %s already registered. Skipping.", engine_key) + return + self.engine.register_remote_engine(register_info.engine_desc) + self.decode_kv_args_table[engine_key] = register_info + logger.debug( + "Registered decode peer %s (%s:%s)", + engine_key, + register_info.endpoint, + register_info.dst_port, + ) + + def _get_mha_mem_desc_slices( + self, dst_mem_descs: List[MemoryDesc] + ) -> tuple[ + List[MemoryDesc], List[MemoryDesc], List[MemoryDesc], List[MemoryDesc], int + ]: + src_descs = self.kv_mem_descs + if not src_descs: + raise RuntimeError("KV memory descriptors are empty on prefill side") + + num_local_layers = len(src_descs) // 2 + src_k_descs = src_descs[:num_local_layers] + src_v_descs = src_descs[num_local_layers:] + + start_layer = self.kv_args.prefill_start_layer + end_layer = start_layer + num_local_layers + dst_total_layers = len(dst_mem_descs) // 2 + if len(dst_mem_descs) < 2 or end_layer > dst_total_layers: + raise ValueError( + "Destination KV descriptors do not match prefill pp configuration" + ) + dst_k_descs = dst_mem_descs[start_layer:end_layer] + dst_v_descs = dst_mem_descs[ + dst_total_layers + start_layer : dst_total_layers + end_layer + ] + return src_k_descs, src_v_descs, dst_k_descs, dst_v_descs, num_local_layers + + def _get_mla_mem_desc_slices( + self, dst_mem_descs: List[MemoryDesc] + ) -> tuple[List[MemoryDesc], List[MemoryDesc], int]: + src_descs = self.kv_mem_descs + num_local_layers = len(src_descs) + start_layer = self.kv_args.prefill_start_layer + end_layer = start_layer + num_local_layers + if end_layer > len(dst_mem_descs): + raise ValueError( + "Destination MLA KV descriptors do not match prefill pp configuration" + ) + dst_slice = dst_mem_descs[start_layer:end_layer] + return src_descs, dst_slice, num_local_layers + + def _issue_layer_transfers( + self, + src_desc: MemoryDesc, + dst_desc: MemoryDesc, + kv_item_len: int, + src_groups: List[List[int]], + dst_groups: List[List[int]], + ) -> List[TransferStatus]: + if not src_groups: + return [] + local_offsets = [int(src_group[0]) * kv_item_len for src_group in src_groups] + remote_offsets = [int(dst_group[0]) * kv_item_len for dst_group in dst_groups] + sizes = [len(src_group) * kv_item_len for src_group in src_groups] + + transfer_uid = self.engine.allocate_transfer_uid() + + statuses = self.engine.batch_write( + [src_desc], + [local_offsets], + [dst_desc], + [remote_offsets], + [sizes], + [transfer_uid], + ) + return statuses + + def _build_tp_slice_config(self, peer_info: KVArgsRegisterInfo) -> TPSliceConfig: + page_size = self.kv_args.page_size + + src_item_len = self.kv_args.kv_item_lens[0] + dst_item_len = peer_info.dst_kv_item_len + + bytes_per_token_src = src_item_len // page_size + bytes_per_token_dst = dst_item_len // page_size + + prefill_tp_size = self.attn_tp_size + decode_tp_size = peer_info.decode_tp_size + + num_kv_heads = self.kv_args.kv_head_num + src_heads_per_rank = num_kv_heads + dst_heads_per_rank = num_kv_heads * prefill_tp_size // decode_tp_size + if dst_heads_per_rank == 0: + raise ValueError("Destination heads per rank evaluates to zero") + + bytes_per_head_slice = bytes_per_token_dst // dst_heads_per_rank + if bytes_per_head_slice == 0: + raise ValueError("Head slice size evaluates to zero") + + local_tp_rank = self.kv_args.engine_rank % prefill_tp_size + dst_tp_rank = peer_info.decode_tp_rank % decode_tp_size + + if prefill_tp_size > decode_tp_size: + src_head_start = 0 + num_heads_to_send = src_heads_per_rank + dst_head_start = local_tp_rank * src_heads_per_rank + else: + src_head_start = (dst_tp_rank * dst_heads_per_rank) % src_heads_per_rank + num_heads_to_send = dst_heads_per_rank + dst_head_start = 0 + + src_head_slice_offset = src_head_start * bytes_per_head_slice + dst_head_slice_offset = dst_head_start * bytes_per_head_slice + heads_bytes_per_token = num_heads_to_send * bytes_per_head_slice + + if heads_bytes_per_token > bytes_per_token_dst: + raise ValueError( + "Slice size exceeds destination token capacity for TP slice transfer" + ) + + return TPSliceConfig( + page_size=page_size, + src_item_len=src_item_len, + dst_item_len=dst_item_len, + bytes_per_token_src=bytes_per_token_src, + bytes_per_token_dst=bytes_per_token_dst, + src_head_slice_offset=src_head_slice_offset, + dst_head_slice_offset=dst_head_slice_offset, + heads_bytes_per_token_to_send=heads_bytes_per_token, + ) + + def _issue_tp_slice_transfers( + self, + src_desc: MemoryDesc, + dst_desc: MemoryDesc, + kv_indices: npt.NDArray[np.int32], + dst_indices: npt.NDArray[np.int32], + tp_cfg: TPSliceConfig, + ) -> List[TransferStatus]: + if kv_indices.size == 0 or dst_indices.size == 0: + return [] + + limit = min(kv_indices.size, dst_indices.size) + if not limit: + return [] + + src_pages = kv_indices[:limit].astype(np.int64) + dst_pages = dst_indices[:limit].astype(np.int64) + token_slots = np.arange(tp_cfg.page_size, dtype=np.int64) + + src_page_bases = src_pages * tp_cfg.src_item_len + dst_page_bases = dst_pages * tp_cfg.dst_item_len + + src_token_offsets = token_slots * tp_cfg.bytes_per_token_src + dst_token_offsets = token_slots * tp_cfg.bytes_per_token_dst + + local_offsets = ( + ( + src_page_bases[:, np.newaxis] + + src_token_offsets + + tp_cfg.src_head_slice_offset + ) + .flatten() + .tolist() + ) + remote_offsets = ( + ( + dst_page_bases[:, np.newaxis] + + dst_token_offsets + + tp_cfg.dst_head_slice_offset + ) + .flatten() + .tolist() + ) + + num_transfers = limit * tp_cfg.page_size + sizes = [tp_cfg.heads_bytes_per_token_to_send] * num_transfers + + if not local_offsets: + return [] + + transfer_uid = self.engine.allocate_transfer_uid() + statuses = self.engine.batch_write( + [src_desc], + [local_offsets], + [dst_desc], + [remote_offsets], + [sizes], + [transfer_uid], + ) + return statuses + + def send_kvcache( + self, + peer_info: KVArgsRegisterInfo, + prefill_kv_indices: npt.NDArray[np.int32], + dst_kv_indices: npt.NDArray[np.int32], + ) -> List[TransferStatus]: + src_groups, dst_groups = group_concurrent_contiguous( + prefill_kv_indices, dst_kv_indices + ) + statuses = [] + kv_item_len = self.kv_args.kv_item_lens[0] + if self.is_mla_backend: + ( + src_descs, + dst_descs, + layers_current_pp_stage, + ) = self._get_mla_mem_desc_slices(peer_info.dst_kv_mem_descs) + for layer_id in range(layers_current_pp_stage): + statuses.extend( + self._issue_layer_transfers( + src_descs[layer_id], + dst_descs[layer_id], + kv_item_len, + src_groups, + dst_groups, + ) + ) + else: + tp_mismatch = peer_info.decode_tp_size != self.attn_tp_size + ( + src_k_descs, + src_v_descs, + dst_k_descs, + dst_v_descs, + layers_current_pp_stage, + ) = self._get_mha_mem_desc_slices(peer_info.dst_kv_mem_descs) + + if tp_mismatch: + tp_cfg = self._build_tp_slice_config(peer_info) + for layer_id in range(layers_current_pp_stage): + statuses.extend( + self._issue_tp_slice_transfers( + src_k_descs[layer_id], + dst_k_descs[layer_id], + prefill_kv_indices, + dst_kv_indices, + tp_cfg, + ) + ) + statuses.extend( + self._issue_tp_slice_transfers( + src_v_descs[layer_id], + dst_v_descs[layer_id], + prefill_kv_indices, + dst_kv_indices, + tp_cfg, + ) + ) + else: + src_groups, dst_groups = group_concurrent_contiguous( + prefill_kv_indices, dst_kv_indices + ) + for layer_id in range(layers_current_pp_stage): + statuses.extend( + self._issue_layer_transfers( + src_k_descs[layer_id], + dst_k_descs[layer_id], + kv_item_len, + src_groups, + dst_groups, + ) + ) + statuses.extend( + self._issue_layer_transfers( + src_v_descs[layer_id], + dst_v_descs[layer_id], + kv_item_len, + src_groups, + dst_groups, + ) + ) + + return statuses + + def send_aux( + self, + peer_info: KVArgsRegisterInfo, + prefill_aux_index: int, + dst_aux_index: int, + room: int, + ) -> List[TransferStatus]: + return self.send_aux_tcp(peer_info, prefill_aux_index, dst_aux_index, room) + + def send_aux_tcp( + self, + peer_info: KVArgsRegisterInfo, + prefill_aux_index: int, + dst_aux_index: int, + room: int, + ) -> List[TransferStatus]: + prefill_aux_ptrs = self.kv_args.aux_data_ptrs + prefill_aux_item_lens = self.kv_args.aux_item_lens + + for i in range(len(prefill_aux_ptrs)): + length = prefill_aux_item_lens[i] + src_addr = prefill_aux_ptrs[i] + length * prefill_aux_index + data = AuxDataCodec.serialize_data_from_buffer(src_addr, length) + + self.send_aux_data_to_endpoint( + remote=peer_info.endpoint, + dst_port=peer_info.dst_port, + room=room, + buffer_index=i, + aux_index=dst_aux_index, + data=data, + ) + + return [] + + def send_aux_data_to_endpoint( + self, + remote: str, + dst_port: int, + room: int, + buffer_index: int, + aux_index: int, + data: bytes, + ): + socket = self._connect( + format_tcp_address(remote, dst_port), is_ipv6=is_valid_ipv6_address(remote) + ) + + socket.send_multipart( + [ + MoriKVManager.AUX_DATA_HEADER, + str(room).encode("ascii"), + str(buffer_index).encode("ascii"), + str(aux_index).encode("ascii"), + struct.pack(">I", len(data)), + data, + ] + ) + + def _handle_aux_data(self, msg: List[bytes]): + """Handle AUX_DATA messages received by the decode thread.""" + room = int(msg[1].decode("ascii")) + buffer_index = int(msg[2].decode("ascii")) + aux_index = int(msg[3].decode("ascii")) + data_length = struct.unpack(">I", msg[4])[0] + data = msg[5] + + if len(data) != data_length: + logger.error(f"AUX_DATA length mismatch for bootstrap_room {room}") + return + + AuxDataCodec.deserialize_data_to_buffer( + self.kv_args, buffer_index, aux_index, data + ) + + logger.debug( + f"Received AUX_DATA for bootstrap_room {room} with length:{len(data)}" + ) + + def add_transfer_request( + self, + bootstrap_room: int, + kv_indices: npt.NDArray[np.int32], + index_slice: slice, + is_last: bool, + aux_index: Optional[int] = None, + state_indices: Optional[npt.NDArray[np.int32]] = None, + ) -> Tuple[List[TransferStatus], Optional[List[TransferInfo]]]: + assert self.disaggregation_mode == DisaggregationMode.PREFILL + transfer_infos = self.transfer_infos.get(bootstrap_room) + if not transfer_infos: + raise RuntimeError( + f"No transfer info found for bootstrap_room={bootstrap_room}" + ) + result_statuses = [] + target_infos_snapshot: Optional[List[TransferInfo]] = None + with self.transfer_lock: + self.update_status(bootstrap_room, KVPoll.Transferring) + for info in transfer_infos.values(): + peer_info = self.decode_kv_args_table.get(info.engine_key) + if not peer_info: + self.record_failure( + bootstrap_room, + f"Peer info missing for engine {info.engine_key}", + ) + raise RuntimeError( + f"Missing decode peer info for {info.engine_key}" + ) + if not info.is_dummy: + dst_indices_chunk = info.dst_kv_indices[index_slice] + statuses = self.send_kvcache( + peer_info, kv_indices, dst_indices_chunk + ) + result_statuses.extend(statuses) + if ( + is_last + and aux_index is not None + and info.dst_aux_index >= 0 + and self.pp_group.is_last_rank + ): + result_statuses.extend( + self.send_aux( + peer_info, aux_index, info.dst_aux_index, bootstrap_room + ) + ) + if is_last: + self.update_status(bootstrap_room, KVPoll.Success) + target_infos_snapshot = list(transfer_infos.values()) + self.transfer_infos.pop(bootstrap_room, None) + return result_statuses, target_infos_snapshot + + +class MoriKVSender(CommonKVSender): + def __init__( + self, + mgr: MoriKVManager, + bootstrap_addr: str, + bootstrap_room: int, + dest_tp_ranks: List[int], + pp_rank: int, + ): + super().__init__(mgr, bootstrap_addr, bootstrap_room, dest_tp_ranks, pp_rank) + self.transfer_statuses: List[TransferStatus] = [] + self.pending_infos: Optional[List[TransferInfo]] = None + self.sent_last_chunk = False + self.conclude_state: Optional[KVPoll] = None + self.status_notified = False + self.init_time = time.time() + + def send( + self, + kv_indices: npt.NDArray[np.int32], + state_indices: Optional[List[int]] = None, + ): + index_slice = slice(self.curr_idx, self.curr_idx + len(kv_indices)) + self.curr_idx += len(kv_indices) + is_last = self.curr_idx == self.num_kv_indices + + # Special handling for cp + if self.kv_mgr.enable_all_cp_ranks_for_transfer: + kv_indices, index_slice = filter_kv_indices_for_cp_rank( + self.kv_mgr, + kv_indices, + index_slice, + ) + elif self.kv_mgr.is_dummy_cp_rank: + if not is_last: + return + else: + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Success) + return + statuses, infos = self.kv_mgr.add_transfer_request( + self.bootstrap_room, + kv_indices, + index_slice, + is_last, + aux_index=self.aux_index if is_last else None, + ) + self.transfer_statuses.extend(statuses) + if infos is not None: + self.pending_infos = infos + self.sent_last_chunk = True + + def poll(self) -> KVPoll: + if self.conclude_state is not None: + return self.conclude_state + + status = self.kv_mgr.check_status(self.bootstrap_room) + if status == KVPoll.Bootstrapping: + elapsed = time.time() - self.init_time + if elapsed >= self.kv_mgr.bootstrap_timeout: + reason = ( + f"Request {self.bootstrap_room} timed out after {elapsed:.1f}s " + "waiting for decode handshake" + ) + self.kv_mgr.record_failure(self.bootstrap_room, reason) + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Failed) + self._finalize_failure(reason) + return KVPoll.Failed + return status + + if status == KVPoll.Failed: + self._finalize_failure() + return KVPoll.Failed + + transfers_done = self._all_transfers_finished() + if transfers_done: + if self._has_transfer_error(): + reason = self._collect_failure_reason() + self.kv_mgr.record_failure(self.bootstrap_room, reason) + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Failed) + self._finalize_failure(reason) + return KVPoll.Failed + self._notify_decode(KVPoll.Success) + self.conclude_state = KVPoll.Success + return KVPoll.Success + return KVPoll.Transferring if status == KVPoll.Success else status + + def _all_transfers_finished(self) -> bool: + if not self.sent_last_chunk: + return False + if not self.transfer_statuses: + return True + return all(not status.InProgress() for status in self.transfer_statuses) + + def _has_transfer_error(self) -> bool: + return any(status.Failed() for status in self.transfer_statuses) + + def _collect_failure_reason(self) -> str: + for status in self.transfer_statuses: + if status.Failed(): + return f"KV transfer failed: {status.Message()}" + return "KV transfer failed due to unknown reason" + + def _notify_decode( + self, status: KVPoll, failure_reason: Optional[str] = None + ) -> None: + if self.status_notified: + return + if self.pending_infos: + self.kv_mgr.notify_decode_status( + self.pending_infos, self.bootstrap_room, status, failure_reason + ) + self.status_notified = True + + def _finalize_failure(self, failure_reason: Optional[str] = None) -> None: + if self.conclude_state == KVPoll.Failed: + return + if failure_reason is None: + failure_reason = self.kv_mgr.failure_records.get( + self.bootstrap_room, "KV transfer failed" + ) + self._notify_decode(KVPoll.Failed, failure_reason) + self.conclude_state = KVPoll.Failed + + def clear(self) -> None: + self.kv_mgr.request_status.pop(self.bootstrap_room, None) + + def failure_exception(self): + if self.conclude_state is None: + self._finalize_failure() + self.clear() + with self.kv_mgr.failure_lock: + failure_reason = self.kv_mgr.failure_records.pop( + self.bootstrap_room, "KV transfer failed" + ) + raise RuntimeError(failure_reason) + + def abort(self): + reason = "Aborted by AbortReq." + self.kv_mgr.record_failure(self.bootstrap_room, reason) + self._notify_decode(KVPoll.Failed, reason) + self.conclude_state = KVPoll.Failed + + +class MoriKVReceiver(CommonKVReceiver): + + def __init__( + self, + mgr: MoriKVManager, + bootstrap_addr: str, + bootstrap_room: Optional[int] = None, + prefill_dp_rank: Optional[int] = None, + ): + super().__init__(mgr, bootstrap_addr, bootstrap_room, prefill_dp_rank) + self.conclude_state: Optional[KVPoll] = None + self.init_time: Optional[float] = None + if self.bootstrap_room is None or self.bootstrap_infos is None: + return + self.kv_mgr.addr_to_rooms_tracker[self.bootstrap_addr].add(self.bootstrap_room) + self.kv_mgr.room_to_bootstrap_addr[self.bootstrap_room] = self.bootstrap_addr + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.WaitingForInput) + self._register_kv_args() + + def _register_kv_args(self): + if self.bootstrap_infos is None: + return + engine_desc_blob = self.kv_mgr.engine_desc.pack() + packed_kv_descs = _pack_mem_desc_list(self.kv_mgr.kv_mem_descs) + packed_aux_descs = _pack_mem_desc_list(self.kv_mgr.aux_mem_descs) + packed_state_descs = _pack_mem_desc_list(self.kv_mgr.state_mem_descs) + gpu_id = str(self.kv_mgr.kv_args.gpu_id).encode("ascii") + decode_tp_size = str(self.kv_mgr.attn_tp_size).encode("ascii") + decode_tp_rank = str(self.kv_mgr.kv_args.engine_rank).encode("ascii") + kv_item_len = str(self.kv_mgr.kv_args.kv_item_lens[0]).encode("ascii") + + for bootstrap_info in self.bootstrap_infos: + sock, lock = self._connect_to_bootstrap_server(bootstrap_info) + with lock: + sock.send_multipart( + [ + MORI_GUARD, + "None".encode("ascii"), + self.kv_mgr.local_ip.encode("ascii"), + str(self.kv_mgr.rank_port).encode("ascii"), + engine_desc_blob, + packed_kv_descs, + packed_aux_descs, + packed_state_descs, + gpu_id, + decode_tp_size, + decode_tp_rank, + kv_item_len, + ] + ) + + def init( + self, + kv_indices: npt.NDArray[np.int32], + aux_index: Optional[int] = None, + state_indices: Optional[List[int]] = None, + ): + if self.bootstrap_infos is None or self.bootstrap_room is None: + return + + kv_indices_bytes = ( + np.asarray(kv_indices, dtype=np.int32).tobytes() if kv_indices.size else b"" + ) + aux_bytes = str(aux_index).encode("ascii") if aux_index is not None else b"" + state_bytes = b"" + + for bootstrap_info in self.bootstrap_infos: + sock, lock = self._connect_to_bootstrap_server(bootstrap_info) + is_dummy = bootstrap_info.get("is_dummy", False) + with lock: + sock.send_multipart( + [ + MORI_GUARD, + str(self.bootstrap_room).encode("ascii"), + self.kv_mgr.local_ip.encode("ascii"), + str(self.kv_mgr.rank_port).encode("ascii"), + self.kv_mgr.engine_desc.key.encode("ascii"), + kv_indices_bytes if not is_dummy else b"", + aux_bytes if not is_dummy else b"", + state_bytes, + str(self.required_dst_info_num).encode("ascii"), + ] + ) + self.init_time = time.time() + + def poll(self) -> KVPoll: + if self.conclude_state is not None: + return self.conclude_state + + status = self.kv_mgr.check_status(self.bootstrap_room) + if status in (KVPoll.Success, KVPoll.Failed): + self.conclude_state = status + return status + + if status == KVPoll.WaitingForInput and self.init_time is not None: + elapsed = time.time() - self.init_time + if elapsed >= self.kv_mgr.waiting_timeout: + reason = f"Request {self.bootstrap_room} timed out after {elapsed:.1f}s waiting for KV transfer" + self.kv_mgr.record_failure(self.bootstrap_room, reason) + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Failed) + self.conclude_state = KVPoll.Failed + return KVPoll.Failed + + return status + + def clear(self) -> None: + if self.bootstrap_room is None: + return + self.kv_mgr.request_status.pop(self.bootstrap_room, None) + self.kv_mgr.required_prefill_response_num_table.pop(self.bootstrap_room, None) + self.kv_mgr.prefill_response_tracker.pop(self.bootstrap_room, None) + self.kv_mgr._cleanup_room_tracking(self.bootstrap_room) + + def failure_exception(self): + if self.conclude_state is None: + self.conclude_state = KVPoll.Failed + + self.clear() + with self.kv_mgr.failure_lock: + failure_reason = self.kv_mgr.failure_records.pop( + self.bootstrap_room, "KV transfer failed" + ) + raise RuntimeError(failure_reason) + + def abort(self): + if self.bootstrap_room is None: + return + reason = "Aborted by AbortReq." + self.kv_mgr.record_failure(self.bootstrap_room, reason) + self.kv_mgr.update_status(self.bootstrap_room, KVPoll.Failed) + self.conclude_state = KVPoll.Failed + self.clear() + + +class MoriKVBootstrapServer(CommonKVBootstrapServer): + pass diff --git a/sglang/python/sglang/srt/hardware_backend/npu/attention/mla_preprocess.py b/sglang/python/sglang/srt/hardware_backend/npu/attention/mla_preprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..51cf7421e9ca9410c64b215e5051b0dd9bb3d9aa --- /dev/null +++ b/sglang/python/sglang/srt/hardware_backend/npu/attention/mla_preprocess.py @@ -0,0 +1,489 @@ +import re +from functools import lru_cache +from typing import TYPE_CHECKING, Optional + +import torch +import torch.nn.functional as F + +from sglang.srt.hardware_backend.npu.utils import npu_format_cast +from sglang.srt.utils import get_bool_env_var + +if TYPE_CHECKING: + from sglang.srt.layers.quantization.base_config import QuantizationConfig + + +@lru_cache(maxsize=1) +def is_mla_preprocess_enabled() -> bool: + return get_bool_env_var("SGLANG_NPU_USE_MLAPO") + + +@lru_cache(maxsize=1) +def is_fia_nz() -> bool: + is_fia_nz_ = get_bool_env_var("SGLANG_USE_FIA_NZ") + if is_fia_nz_: + assert ( + is_mla_preprocess_enabled() + ), "SGLANG_USE_FIA_NZ must be enable with SGLANG_NPU_USE_MLAPO" + return is_fia_nz_ + + +def round_up(val: int, align: int) -> int: + if align == 0: + return 0 + return -(val // -align) * align + + +def transdata(nd_mat, block_size: tuple = (16, 16)): + r = round_up(nd_mat.shape[0], block_size[0]) + c = round_up(nd_mat.shape[1], block_size[1]) + r_pad = r - nd_mat.shape[0] + c_pad = c - nd_mat.shape[1] + nd_mat = F.pad(nd_mat, ((0, r_pad, 0, c_pad))) + nz_mat = torch.permute( + torch.reshape( + nd_mat, + (r // block_size[0], block_size[0], c // block_size[1], block_size[1]), + ), + [2, 0, 1, 3], + ) + nz_mat = torch.reshape( + nz_mat, (nz_mat.shape[0], nz_mat.shape[1] * nz_mat.shape[2], nz_mat.shape[3]) + ) + return nz_mat + + +def trans_rope_weight(weight, rope_dim): + weight_1 = weight[..., -rope_dim::2, :].contiguous() + weight_2 = weight[..., -rope_dim + 1 :: 2, :].contiguous() + weight[..., -rope_dim:, :] = torch.cat([weight_1, weight_2], dim=-2) + + return weight.contiguous() + + +class NPUFusedMLAPreprocess(torch.nn.Module): + def __init__( + self, + fused_qkv_a_proj_with_mqa, + q_a_layernorm, + kv_a_layernorm, + q_b_proj, + w_kc, + rotary_emb, + layer_id, + num_local_heads, + qk_nope_head_dim, + qk_rope_head_dim, + v_head_dim, + quant_config: Optional["QuantizationConfig"] = None, + ): + super().__init__() + self.qkv_a_proj = fused_qkv_a_proj_with_mqa + self.q_a_layernorm = q_a_layernorm + self.kv_a_layernorm = kv_a_layernorm + self.q_b_proj = q_b_proj + self.w_kc = w_kc.contiguous() + self.rotary_emb = rotary_emb + self.layer_id = layer_id + self.quant_config = quant_config + self.has_preprocess_weights = False + self.dtype = None + + self.q_lora_rank = self.q_b_proj.input_size # 1536 + self.kv_lora_rank = self.kv_a_layernorm.hidden_size # 512 + self.num_local_heads = num_local_heads # tp + self.qk_nope_head_dim = qk_nope_head_dim # 128 + self.qk_rope_head_dim = qk_rope_head_dim # 64 + self.qk_head_dim = qk_nope_head_dim + qk_rope_head_dim + self.v_head_dim = v_head_dim + self.q_b_proj_weight_scale = self.q_b_proj.weight_scale.view(1, -1).to( + torch.float + ) + + def preprocess_weights(self, hidden_states): + self.dummy = torch.zeros( + (hidden_states.shape[-1]), + dtype=hidden_states.dtype, + device=hidden_states.device, + ) + self.qkv_a_proj_input_offset = self.qkv_a_proj.input_offset.to(dtype=torch.int8) + self.q_b_proj_input_offset = self.q_b_proj.input_offset.to(dtype=torch.int8) + + # matmul_0 weight [7168, 2112] + fused_qkv_a_proj_with_mqa_weight_q = self.qkv_a_proj.weight.data[ + :, : self.q_lora_rank + ].clone() # [7168, 1536] + fused_qkv_a_proj_with_mqa_weight_kv = self.qkv_a_proj.weight.data[ + :, self.q_lora_rank : + ].clone() # [7168, 576] + # rope fit + fused_qkv_a_proj_with_mqa_weight_kv_t = ( + fused_qkv_a_proj_with_mqa_weight_kv.t().contiguous() + ) + fused_qkv_a_proj_with_mqa_weight_kv_t = trans_rope_weight( + fused_qkv_a_proj_with_mqa_weight_kv_t, self.qk_rope_head_dim + ) + fused_qkv_a_proj_with_mqa_weight_kv = ( + fused_qkv_a_proj_with_mqa_weight_kv_t.t().contiguous() + ) + # cat nz + fused_qkv_a_proj_with_mqa_weight_new = torch.cat( + (fused_qkv_a_proj_with_mqa_weight_kv, fused_qkv_a_proj_with_mqa_weight_q), + dim=-1, + ) + fused_qkv_a_proj_with_mqa_weight = ( + fused_qkv_a_proj_with_mqa_weight_new.t().contiguous() + ) + fused_qkv_a_proj_with_mqa_weight_nz = ( + transdata(fused_qkv_a_proj_with_mqa_weight, block_size=(16, 32)) + .unsqueeze(0) + .contiguous() + ) + self.qkv_a_proj_weight_nz = npu_format_cast(fused_qkv_a_proj_with_mqa_weight_nz) + + # matmul_0 deq_scale [2112] + fused_qkv_a_proj_with_mqa_deq_scale_q = self.qkv_a_proj.deq_scale.data[ + : self.q_lora_rank + ].clone() # [7168, 1536] + fused_qkv_a_proj_with_mqa_deq_scale_kv = self.qkv_a_proj.deq_scale.data[ + self.q_lora_rank : + ].clone() # [7168, 576] + # rope fit + fused_qkv_a_proj_with_mqa_deq_scale_kv = ( + fused_qkv_a_proj_with_mqa_deq_scale_kv.reshape( + self.kv_lora_rank + self.qk_rope_head_dim, -1 + ).contiguous() + ) + fused_qkv_a_proj_with_mqa_deq_scale_kv = trans_rope_weight( + fused_qkv_a_proj_with_mqa_deq_scale_kv, self.qk_rope_head_dim + ) + fused_qkv_a_proj_with_mqa_deq_scale_kv = ( + fused_qkv_a_proj_with_mqa_deq_scale_kv.view( + self.kv_lora_rank + self.qk_rope_head_dim + ).contiguous() + ) + self.qkv_a_proj_deq_scale_kvq = torch.cat( + ( + fused_qkv_a_proj_with_mqa_deq_scale_kv, + fused_qkv_a_proj_with_mqa_deq_scale_q, + ), + dim=-1, + ) + + # matmul_0 quant_bias [2112] + fused_qkv_a_proj_with_mqa_quant_bias_q = self.qkv_a_proj.quant_bias.data[ + : self.q_lora_rank + ].clone() # [7168, 1536] + fused_qkv_a_proj_with_mqa_quant_bias_kv = self.qkv_a_proj.quant_bias.data[ + self.q_lora_rank : + ].clone() # [7168, 576] + # rope fit + fused_qkv_a_proj_with_mqa_quant_bias_kv = ( + fused_qkv_a_proj_with_mqa_quant_bias_kv.reshape( + self.kv_lora_rank + self.qk_rope_head_dim, -1 + ).contiguous() + ) + fused_qkv_a_proj_with_mqa_quant_bias_kv = trans_rope_weight( + fused_qkv_a_proj_with_mqa_quant_bias_kv, self.qk_rope_head_dim + ) + fused_qkv_a_proj_with_mqa_quant_bias_kv = ( + fused_qkv_a_proj_with_mqa_quant_bias_kv.view( + self.kv_lora_rank + self.qk_rope_head_dim + ).contiguous() + ) + self.qkv_a_proj_quant_bias_kvq = torch.cat( + ( + fused_qkv_a_proj_with_mqa_quant_bias_kv, + fused_qkv_a_proj_with_mqa_quant_bias_q, + ), + dim=-1, + ) + + # matmul_1 weight [1536, num_head * 192] + q_b_proj_weight = self.q_b_proj.weight.data.clone() + q_b_proj_weight = q_b_proj_weight.t().reshape( + self.num_local_heads, self.qk_nope_head_dim + self.qk_rope_head_dim, -1 + ) + q_b_proj_weight = trans_rope_weight(q_b_proj_weight, self.qk_rope_head_dim) + q_b_proj_weight = q_b_proj_weight.reshape( + self.num_local_heads * (self.qk_nope_head_dim + self.qk_rope_head_dim), -1 + ) + q_b_proj_weight_nz = ( + transdata(q_b_proj_weight, block_size=(16, 32)).unsqueeze(0).contiguous() + ) + self.q_b_proj_weight_nz = npu_format_cast(q_b_proj_weight_nz) + + # matmul_1 deq_scale [num_head * 192] + q_b_proj_deq_scale = self.q_b_proj.deq_scale.data.clone() + q_b_proj_deq_scale = q_b_proj_deq_scale.reshape( + self.num_local_heads, self.qk_nope_head_dim + self.qk_rope_head_dim, -1 + ) + q_b_proj_deq_scale = trans_rope_weight( + q_b_proj_deq_scale, self.qk_rope_head_dim + ) + self.q_b_proj_deq_scale = q_b_proj_deq_scale.reshape( + self.num_local_heads * (self.qk_nope_head_dim + self.qk_rope_head_dim) + ) + + # matmul_1 quant_bias [num_head * 192] + q_b_proj_quant_bias = self.q_b_proj.quant_bias.data.clone() + q_b_proj_quant_bias = q_b_proj_quant_bias.reshape( + self.num_local_heads, self.qk_nope_head_dim + self.qk_rope_head_dim, -1 + ) + q_b_proj_quant_bias = trans_rope_weight( + q_b_proj_quant_bias, self.qk_rope_head_dim + ) + self.q_b_proj_quant_bias = q_b_proj_quant_bias.reshape( + self.num_local_heads * (self.qk_nope_head_dim + self.qk_rope_head_dim) + ) + + def mlaprolog_preprocess_weight(self): + self.qkv_a_proj.weight.data = self.qkv_a_proj.weight.data.transpose(0, 1) + qkv_a_proj_weight_q = self.qkv_a_proj.weight.data[:, : self.q_lora_rank].clone() + qkv_a_proj_weight_kv = self.qkv_a_proj.weight.data[ + :, self.q_lora_rank : + ].clone() + self.q_a_proj_weight = npu_format_cast(qkv_a_proj_weight_q) + self.kv_a_proj_weight = npu_format_cast(qkv_a_proj_weight_kv) + + def get_sin_cos(self, positions): + cos_sin = self.rotary_emb.cos_sin_cache[positions] + cos, sin = cos_sin.chunk(2, dim=-1) + cos = cos.repeat(1, 2) + sin = sin.repeat(1, 2) + return cos, sin + + def get_kv_cache_and_cache_idx(self, forward_batch): + k_cache, v_cache = forward_batch.token_to_kv_pool.get_kv_buffer(self.layer_id) + slot_mapping = forward_batch.out_cache_loc.to(dtype=torch.int32) + return k_cache, v_cache, slot_mapping + + def forward_absorb_prepare_npu_rms_norm_cache( + self, + positions: torch.Tensor, + hidden_states: torch.Tensor, + forward_batch, + zero_allocator, + ): + bsz, _ = hidden_states.view(-1, hidden_states.shape[-1]).shape + self.dtype = hidden_states.dtype + if self.layer_id == 0: + self.cos, self.sin = self.get_sin_cos(positions) + self.rotary_emb.cos_cached, self.rotary_emb.sin_cache = self.cos, self.sin + else: + self.cos, self.sin = self.rotary_emb.cos_cached, self.rotary_emb.sin_cache + + self.kvCache, self.kvCacheRope, self.slotmapping = ( + self.get_kv_cache_and_cache_idx(forward_batch) + ) + + if not self.has_preprocess_weights: + self.has_preprocess_weights = True + + cos, sin = self.cos, self.sin + + if self.q_lora_rank is not None: + fused_qkv_a_proj_out = self.qkv_a_proj(hidden_states)[0] + q_lowrank, latent_cache = fused_qkv_a_proj_out.split( + [self.q_lora_rank, self.kv_lora_rank + self.qk_rope_head_dim], dim=-1 + ) + q = self.q_a_layernorm(q_lowrank) + q = self.q_b_proj(q)[0].view(-1, self.num_local_heads, self.qk_head_dim) + else: + q = self.q_proj(hidden_states)[0].view( + -1, self.num_local_heads, self.qk_head_dim + ) + latent_cache = self.kv_a_proj_with_mqa(hidden_states)[0] + + q_nope, q_pe = torch.split( + q, [self.qk_nope_head_dim, self.qk_rope_head_dim], dim=-1 + ) # b*s,n,d + + q_nope = q_nope.view(-1, self.num_local_heads, self.qk_nope_head_dim) + q_nope = torch.matmul(q_nope.transpose(0, 1), self.w_kc).transpose(0, 1) + + q_pe = q_pe.view(-1, self.num_local_heads, 1, self.qk_rope_head_dim) + cos = cos.view(-1, 1, 1, self.qk_rope_head_dim) + sin = sin.view(-1, 1, 1, self.qk_rope_head_dim) + q_pe = torch.ops.npu.npu_interleave_rope(q_pe, cos, sin) # (B,N,S,D) + q_pe = q_pe.view(cos.shape[0], self.num_local_heads, self.qk_rope_head_dim) + + latent_cache = latent_cache.view( + -1, 1, 1, self.kv_lora_rank + self.qk_rope_head_dim + ) # (B*S,N,1,D) + + cache_mode = "PA_NZ" if is_fia_nz() else "PA_BNSD" + self.kvCache = self.kvCache.view( + -1, + forward_batch.attn_backend.page_size, + 1, + forward_batch.attn_backend.kv_lora_rank, + ) + self.kvCacheRope = self.kvCacheRope.view( + -1, + forward_batch.attn_backend.page_size, + 1, + forward_batch.attn_backend.qk_rope_head_dim, + ) + k_rope, k_nope, _, _ = torch.ops.npu.npu_kv_rmsnorm_rope_cache( + latent_cache, + self.kv_a_layernorm.weight, + cos, + sin, + self.slotmapping.to(torch.int64), + self.kvCacheRope, + self.kvCache, + epsilon=self.kv_a_layernorm.variance_epsilon, + cache_mode=cache_mode, + ) + + return (q_pe, k_rope, q_nope, k_nope, forward_batch, zero_allocator, positions) + + def forward_mlapo(self, positions, hidden_states, forward_batch, zero_allocator): + input_dtype = hidden_states.dtype + if not self.has_preprocess_weights: + self.preprocess_weights(hidden_states) + self.has_preprocess_weights = True + self.dtype = hidden_states.dtype + + if self.layer_id == 0: + cos, sin = self.get_sin_cos(positions) + self.rotary_emb.cos_cached, self.rotary_emb.sin_cache = cos, sin + else: + cos, sin = self.rotary_emb.cos_cached, self.rotary_emb.sin_cache + + k_cache, v_cache, slot_mapping = self.get_kv_cache_and_cache_idx(forward_batch) + + q_nope_out = torch.empty( + (hidden_states.shape[0], self.w_kc.shape[0], k_cache.shape[-1]), + dtype=input_dtype, + device=hidden_states.device, + ) + q_rope_out = torch.empty( + (hidden_states.shape[0], self.w_kc.shape[0], v_cache.shape[-1]), + dtype=input_dtype, + device=hidden_states.device, + ) + if is_fia_nz(): + kv_shape, kv_rope_shape = k_cache.shape, v_cache.shape + num_blocks, block_size, num_heads, _ = kv_shape + k_cache = k_cache.view( + num_blocks, num_heads * self.kv_lora_rank // 16, block_size, 16 + ) + v_cache = v_cache.view( + num_blocks, num_heads * self.qk_rope_head_dim // 16, block_size, 16 + ) + # TODO: dummy inputs to be removed + # https://github.com/sgl-project/sgl-kernel-npu/issues/78 + if hasattr(self.q_a_layernorm, "bias"): + q_a_layernorm_bias = self.q_a_layernorm.bias + else: + q_a_layernorm_bias = self.dummy + + torch.ops.npu.mla_preprocess( + hidden_states, + self.dummy, + self.dummy, + self.qkv_a_proj_weight_nz, + self.qkv_a_proj_deq_scale_kvq, + self.q_a_layernorm.weight, + q_a_layernorm_bias, + self.q_b_proj_weight_nz, + self.q_b_proj_deq_scale, + self.kv_a_layernorm.weight, + cos, + sin, + self.w_kc, + k_cache, + v_cache, + slot_mapping, + quant_scale0=self.qkv_a_proj.input_scale, + quant_offset0=self.qkv_a_proj_input_offset, + bias0=self.qkv_a_proj_quant_bias_kvq, + quant_scale1=self.q_b_proj.input_scale, + quant_offset1=self.q_b_proj_input_offset, + bias1=self.q_b_proj_quant_bias, + cache_mode="nzcache" if is_fia_nz() else "krope_ctkv", + quant_mode="per_tensor_quant_asymm", + q_out0=q_nope_out, + kv_cache_out0=k_cache, + q_out1=q_rope_out, + kv_cache_out1=v_cache, + ) + + if is_fia_nz(): + k_cache = k_cache.view(kv_shape) + v_cache = v_cache.view(kv_rope_shape) + + return ( + q_rope_out, + v_cache, + q_nope_out, + k_cache, + forward_batch, + zero_allocator, + positions, + ) + + def forward_mlaprolog(self, positions, hidden_states, forward_batch): + if not self.has_preprocess_weights: + self.mlaprolog_preprocess_weight() + self.has_preprocess_weights = True + self.cos, self.sin = self.get_sin_cos(positions) + k_cache, v_cache, slot_mapping = self.get_kv_cache_and_cache_idx(forward_batch) + mla_prolog_input_args = { + "token_x": hidden_states, + "weight_dq": self.q_a_proj_weight, + "weight_uq_qr": self.q_b_proj.weight, + "weight_uk": self.w_kc, + "weight_dkv_kr": self.kv_a_proj_weight, + "rmsnorm_gamma_cq": self.q_a_layernorm.weight, + "rmsnorm_gamma_ckv": self.kv_a_layernorm.weight, + "rope_sin": self.sin, + "rope_cos": self.cos, + "kv_cache": k_cache, + "kr_cache": v_cache, + "cache_index": slot_mapping.to(dtype=torch.int64), + "dequant_scale_w_uq_qr": self.q_b_proj_weight_scale, + "rmsnorm_epsilon_cq": self.q_a_layernorm.variance_epsilon, + "rmsnorm_epsilon_ckv": self.kv_a_layernorm.variance_epsilon, + "cache_mode": "PA_BSND", + "query_norm_flag": True, + "weight_quant_mode": 1, # 0:no quant; 1:uq_qr: quant; 2: weight_dq,weight_uq_qr,weight_dkv_kr: quant + } + q_nope, q_pe, dequant_scale_q_nope, qr, dequant_q_norm = ( + torch.ops.custom.npu_mla_prolog_v3(**mla_prolog_input_args) + ) + dequant_q_norm = dequant_q_norm.view(hidden_states.shape[0]) + return ( + q_pe, + v_cache, + q_nope, + k_cache, + qr, + forward_batch, + positions, + dequant_q_norm, + ) + + def forward(self, positions, hidden_states, forward_batch, zero_allocator): + # assert self.quant_config and self.quant_config.get_name() == "modelslim" + # route by `qkv_a_proj` quant type as MTP layers can be unquantized + _is_w8a8 = ( + hasattr(self.qkv_a_proj.quant_method, "quantization_config") + and self.qkv_a_proj.quant_method.quantization_config.get_name() + == "modelslim" + ) + # with the mlaprolog enabled, the kv_b_proj layers are unquantized + _is_mlaprolog = hasattr(self.quant_config, "ignore") and any( + re.fullmatch(r".*kv_b_proj", l) for l in self.quant_config.ignore + ) + if _is_w8a8: + return self.forward_mlapo( + positions, hidden_states, forward_batch, zero_allocator + ) + elif _is_mlaprolog: + return self.forward_mlaprolog(positions, hidden_states, forward_batch) + else: + return self.forward_absorb_prepare_npu_rms_norm_cache( + positions, hidden_states, forward_batch, zero_allocator + ) diff --git a/sglang/python/sglang/srt/hardware_backend/npu/graph_runner/__pycache__/npu_graph_runner.cpython-311.pyc b/sglang/python/sglang/srt/hardware_backend/npu/graph_runner/__pycache__/npu_graph_runner.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e157f6a29f1bc95668dbb8455d8f5e6c870eb361 Binary files /dev/null and b/sglang/python/sglang/srt/hardware_backend/npu/graph_runner/__pycache__/npu_graph_runner.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/hardware_backend/npu/quantization/__pycache__/fused_moe_method_npu.cpython-311.pyc b/sglang/python/sglang/srt/hardware_backend/npu/quantization/__pycache__/fused_moe_method_npu.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e330478ed9064be3a725d7d09fa8840725bbe7c Binary files /dev/null and b/sglang/python/sglang/srt/hardware_backend/npu/quantization/__pycache__/fused_moe_method_npu.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/eviction_policy.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/eviction_policy.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cd2ea39d9209810c9fef168f3782b5fed97dafa Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/eviction_policy.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/layers.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/layers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10b9fd2773d6584e922a743d85d898ec61503335 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/layers.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/lora.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/lora.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89aeac702627b8034f4d72b9eb88f4ec46db7dcb Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/lora.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/lora_config.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/lora_config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2c78183846e0c191cc013faed9d55594c4e2216 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/lora_config.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/lora_manager.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/lora_manager.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9313d22e259358f6d33a82451e5f46e826555400 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/lora_manager.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/lora_overlap_loader.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/lora_overlap_loader.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..401fb6bcf767cd7befe61b2a07f3963d04d76c52 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/lora_overlap_loader.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/lora_registry.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/lora_registry.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..332517b6c6b930e18c06f3a87330359969dc70de Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/lora_registry.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/mem_pool.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/mem_pool.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..61f146ed93077125b6fafdd10dafdb29766a8f66 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/mem_pool.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/__pycache__/utils.cpython-311.pyc b/sglang/python/sglang/srt/lora/__pycache__/utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..111757b5be1b7c44f548d2926990e9a0c723add2 Binary files /dev/null and b/sglang/python/sglang/srt/lora/__pycache__/utils.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/backend/__pycache__/base_backend.cpython-311.pyc b/sglang/python/sglang/srt/lora/backend/__pycache__/base_backend.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca1af765bfe9acbbce36df18eac1065445a1b8a9 Binary files /dev/null and b/sglang/python/sglang/srt/lora/backend/__pycache__/base_backend.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/backend/__pycache__/lora_registry.cpython-311.pyc b/sglang/python/sglang/srt/lora/backend/__pycache__/lora_registry.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1bce0bac917696a8fa09928cd115a26e25060b4 Binary files /dev/null and b/sglang/python/sglang/srt/lora/backend/__pycache__/lora_registry.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/lora/backend/ascend_backend.py b/sglang/python/sglang/srt/lora/backend/ascend_backend.py new file mode 100644 index 0000000000000000000000000000000000000000..2cffea1897301831902f52d3c9c674f926c562e8 --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/ascend_backend.py @@ -0,0 +1,303 @@ +import torch + +from sglang.srt.lora.backend.base_backend import BaseLoRABackend +from sglang.srt.lora.utils import LoRABatchInfo +from sglang.srt.model_executor.forward_batch_info import ForwardBatch +from sglang.srt.utils import is_npu + +if is_npu(): + import sgl_kernel_npu # noqa: F401 + import torch_npu # noqa: F401 + + +class AscendLoRABackend(BaseLoRABackend): + name = "ascend" + + def __init__( + self, + max_loras_per_batch: int, + device: torch.device, + **kwargs, + ): + super().__init__(max_loras_per_batch, device) + + def run_lora_a_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + + total_seq_len, _ = x.shape + _, weight_out_dim, _ = weights.shape + + output_tensor = torch.zeros( + (total_seq_len, weight_out_dim), dtype=x.dtype, device=x.device + ) + torch.ops.npu.sgmv_shrink( + x, + weights, + self.batch_info.weight_indices, + self.batch_info.seg_lens, + output_tensor, + 1.0, + ) + scaling = ( + self.batch_info.scalings.gather(0, self.batch_info.weight_indices) + .repeat_interleave(self.batch_info.seg_lens, output_size=total_seq_len) + .unsqueeze(-1) + ) + output_tensor *= scaling + + return output_tensor + + def run_lora_b_sgemm( + self, + x: torch.Tensor, + weights: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + total_seq_len, _ = x.shape + _, weight_out_dim, _ = weights.shape + + if base_output is None: + output_tensor = torch.zeros( + (total_seq_len, weight_out_dim), device=x.device, dtype=x.dtype + ) + else: + output_tensor = base_output + + torch.ops.npu.sgmv_expand( + x, + weights, + self.batch_info.weight_indices, + self.batch_info.seg_lens, + output_tensor, + 0, + weight_out_dim, + ) + + return output_tensor + + def run_qkv_lora( + self, + x: torch.Tensor, + qkv_lora_a: torch.Tensor, + qkv_lora_b: torch.Tensor, + output_offset: torch.Tensor, + output_offset_cpu: torch.Tensor, + max_qkv_out_dim: int, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + num_slices = 3 + assert isinstance(qkv_lora_b, torch.Tensor) + + total_seq_len, _ = x.shape + _, weight_intermediate_dim, _ = qkv_lora_a.shape + _, weight_out_dim, _ = qkv_lora_b.shape + max_rank = weight_intermediate_dim // num_slices + + if base_output is None: + output_tensor = torch.zeros( + (total_seq_len, weight_out_dim), device=x.device, dtype=x.dtype + ) + else: + output_tensor = base_output + + lora_a_output = torch.zeros( + total_seq_len, weight_intermediate_dim, dtype=x.dtype, device=x.device + ) + torch.ops.npu.sgmv_shrink( + x, + qkv_lora_a, + self.batch_info.weight_indices, + self.batch_info.seg_lens, + lora_a_output, + 1.0, + ) + + scaling = ( + self.batch_info.scalings.gather(0, self.batch_info.weight_indices) + .repeat_interleave(self.batch_info.seg_lens, output_size=total_seq_len) + .unsqueeze(-1) + ) + lora_a_output *= scaling + + for slice_id in range(num_slices): + slice_offset = output_offset_cpu[slice_id] + slice_offset_next = output_offset_cpu[slice_id + 1] + slice_size = slice_offset_next - slice_offset + torch.ops.npu.sgmv_expand( + lora_a_output[:, (max_rank * slice_id) : (max_rank * (slice_id + 1))], + qkv_lora_b[:, slice_offset:slice_offset_next], + self.batch_info.weight_indices, + self.batch_info.seg_lens, + output_tensor, + slice_offset, + slice_size, + ) + + return output_tensor + + def run_gate_up_lora( + self, + x: torch.Tensor, + gate_up_lora_a: torch.Tensor, + gate_up_lora_b: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + + num_slices = 2 + assert isinstance(gate_up_lora_b, torch.Tensor) + + total_seq_len, _ = x.shape + _, weight_intermediate_dim, _ = gate_up_lora_a.shape + _, weight_out_dim, _ = gate_up_lora_b.shape + slice_size = weight_out_dim // num_slices + max_rank = weight_intermediate_dim // num_slices + + if base_output is None: + output_tensor = torch.zeros( + (total_seq_len, weight_out_dim), device=x.device, dtype=x.dtype + ) + else: + output_tensor = base_output + + lora_a_output = torch.zeros( + total_seq_len, weight_intermediate_dim, dtype=x.dtype, device=x.device + ) + + torch.ops.npu.sgmv_shrink( + x, + gate_up_lora_a, + self.batch_info.weight_indices, + self.batch_info.seg_lens, + lora_a_output, + 1.0, + ) + + scaling = ( + self.batch_info.scalings.gather(0, self.batch_info.weight_indices) + .repeat_interleave(self.batch_info.seg_lens, output_size=total_seq_len) + .unsqueeze(-1) + ) + lora_a_output *= scaling + + slice_offset = 0 + for slice_id in range(num_slices): + torch.ops.npu.sgmv_expand( + lora_a_output[:, (max_rank * slice_id) : (max_rank * (slice_id + 1))], + gate_up_lora_b[:, slice_offset : slice_offset + slice_size], + self.batch_info.weight_indices, + self.batch_info.seg_lens, + output_tensor, + slice_offset, + slice_size, + ) + slice_offset += slice_size + + return output_tensor + + def init_cuda_graph_batch_info( + self, + max_bs_in_cuda_graph: int, + num_tokens_per_bs: int, + ): + with torch.device("npu"): + self.npu_graph_batch_info = LoRABatchInfo( + bs=max_bs_in_cuda_graph, + use_cuda_graph=True, + num_segments=None, + seg_lens=torch.full( + (max_bs_in_cuda_graph,), num_tokens_per_bs, dtype=torch.int32 + ), + seg_indptr=torch.empty(max_bs_in_cuda_graph + 1, dtype=torch.int32), + max_len=num_tokens_per_bs, + weight_indices=torch.zeros(max_bs_in_cuda_graph, dtype=torch.int32), + lora_ranks=torch.zeros(self.max_loras_per_batch, dtype=torch.int32), + scalings=torch.zeros(self.max_loras_per_batch, dtype=torch.float), + permutation=None, + ) + + # Initialize seg_indptr for NPU graph as they remain constant + # across batches. + torch.cumsum( + self.npu_graph_batch_info.seg_lens[:max_bs_in_cuda_graph], + dim=0, + out=self.npu_graph_batch_info.seg_indptr[1 : max_bs_in_cuda_graph + 1], + ) + + def prepare_lora_batch( + self, + forward_batch: ForwardBatch, + weight_indices: list[int], + lora_ranks: list[int], + scalings: list[float], + use_cuda_graph: bool, + ): + # Use pinned memory to avoid synchronizations during host-to-device transfer + weight_indices_tensor = torch.tensor( + weight_indices, dtype=torch.int32, pin_memory=True, device="cpu" + ) + lora_ranks_tensor = torch.tensor( + lora_ranks, dtype=torch.int32, pin_memory=True, device="cpu" + ) + scalings_tensor = torch.tensor( + scalings, dtype=torch.float, pin_memory=True, device="cpu" + ) + + bs = forward_batch.batch_size + + if use_cuda_graph: + assert ( + self.npu_graph_batch_info is not None + ), "NPU Graph batch info is not initialized." + batch_info = self.npu_graph_batch_info + batch_info.bs = forward_batch.batch_size + batch_info.num_segments = forward_batch.batch_size + else: + max_len = ( + # Calculate max_len from the CPU copy to avoid D2H transfer. + max(forward_batch.extend_seq_lens_cpu) + if forward_batch.forward_mode.is_extend() + else 1 + ) + seg_lens = ( + forward_batch.extend_seq_lens + if forward_batch.forward_mode.is_extend() + else torch.ones(bs, dtype=torch.int32, device=self.device) + ) + seg_indptr = torch.zeros((bs + 1,), dtype=torch.int32, device=self.device) + seg_indptr[1:] = torch.cumsum(seg_lens, dim=0) + + batch_info = LoRABatchInfo( + bs=forward_batch.batch_size, + num_segments=forward_batch.batch_size, + max_len=max_len, + use_cuda_graph=False, + seg_lens=seg_lens, + seg_indptr=seg_indptr, + weight_indices=torch.empty( + (bs,), dtype=torch.int32, device=self.device + ), + lora_ranks=torch.empty( + (self.max_loras_per_batch,), dtype=torch.int32, device=self.device + ), + scalings=torch.empty( + (self.max_loras_per_batch,), dtype=torch.float, device=self.device + ), + permutation=None, + ) + + # Copy to device asynchronously + batch_info.lora_ranks[: self.max_loras_per_batch].copy_( + lora_ranks_tensor, non_blocking=True + ) + batch_info.scalings[: self.max_loras_per_batch].copy_( + scalings_tensor, non_blocking=True + ) + batch_info.weight_indices[:bs].copy_(weight_indices_tensor, non_blocking=True) + self.batch_info = batch_info diff --git a/sglang/python/sglang/srt/lora/backend/base_backend.py b/sglang/python/sglang/srt/lora/backend/base_backend.py new file mode 100644 index 0000000000000000000000000000000000000000..06e4e8ba5a95bbd05f8eedfc48ad83834e2d0c70 --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/base_backend.py @@ -0,0 +1,180 @@ +from typing import Tuple, Union + +import torch + +from sglang.srt.model_executor.forward_batch_info import ForwardBatch + + +class BaseLoRABackend: + """Base class for different Lora backends. + Each backend has its own implementation of Lora kernels. + + Args: + max_loras_per_batch: maximum number of different lora weights + that can be applied in a single forward batch. + device: the device where the backend runs. + """ + + def __init__(self, max_loras_per_batch: int, device: torch.device): + self.max_loras_per_batch = max_loras_per_batch + self.device = device + + def run_lora_a_embedding( + self, + input_ids: torch.Tensor, + weights: torch.Tensor, + vocab_size: int, + extra_embeddings: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + """Run LoRA A embedding lookup with CUDA graph support. + + Args: + input_ids: token IDs with shape (s,), where s is the sum of all sequence lengths + weights: LoRA A embedding weights with shape (num_loras, rank, vocab_size) + vocab_size: base vocabulary size (tokens >= vocab_size are extra tokens) + extra_embeddings: extra token embeddings with shape (num_loras, num_extra_tokens, rank) + Only needed if there are added tokens beyond base vocabulary. + + Returns: + result with shape (s, rank) + """ + pass + + def run_extra_token_embedding( + self, + input_ids: torch.Tensor, + output: torch.Tensor, + extra_embeddings: torch.Tensor, + vocab_size: int, + *args, + **kwargs, + ) -> torch.Tensor: + """ + Apply extra token embeddings to output in-place. + + Args: + input_ids: (s,) token IDs + output: (s, embed_dim) output tensor to be modified + extra_embeddings: (num_loras, num_extra_tokens, embed_dim) extra embeddings + vocab_size: base vocabulary size + + Returns: + output: modified output tensor + """ + raise NotImplementedError + + def run_lora_a_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + """Run segment Gemm of lora a modules with current backend. + The definition of segment Gemm can be referred to https://docs.flashinfer.ai/api/gemm.html. + + Args: + x: input matrix with shape (s, input_dim), here s is the sum of all sequence lengths + weights: a set of lora weights with shape (num_lora, c * r, input_dim), + here r is lora rank, c is a multiplier for stacked modules (e.g., c=3 for qkv_proj, c=2 for gate_up_proj) + usually input_dim is much larger than r + Returns: + result with shape (s, c * r) + """ + pass + + def run_lora_b_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + """Run segment Gemm of lora b modules with current backend. + The definition of segment Gemm can be referred to https://docs.flashinfer.ai/api/gemm.html. + + Args: + x: input matrix with shape (s, r), here s is the sum of all sequence lengths, r is lora rank + weights: a set of lora weights with shape (num_lora, output_dim, r) + usually output_dim is much larger than r + Returns: + result with shape (s, output_dim) + """ + pass + + def run_qkv_lora( + self, + x: torch.Tensor, + qkv_lora_a: torch.Tensor, + qkv_lora_b: Union[torch.Tensor, Tuple[torch.Tensor]], + *args, + **kwargs, + ) -> torch.Tensor: + """Run the lora pass for QKV Layer. + + Args: + x: input matrix with shape (s, input_dim), here s is the sum of all sequence lengths + qkv_lora_a: lora_a module for qkv, with shape (num_lora, 3 * r, input_dim) + qkv_lora_b: lora_b module for qkv. + If passed in as a tensor, its shape should be (num_lora,output_dim_q + 2 * output_dim_kv, r) + If passed in as a tuple of two tensors, it should contain: + a lora_b module for q, with shape (1, num_lora, output_dim_q, r) + and a combined lora_b module for kv, with shape (2, num_lora, output_dim_kv, r) + Returns: + result with shape (s, output_dim_q + 2 * output_dim_kv) + """ + pass + + def run_gate_up_lora( + self, + x: torch.Tensor, + gate_up_lora_a: torch.Tensor, + gate_up_lora_b: Union[torch.Tensor, Tuple[torch.Tensor]], + *args, + **kwargs, + ) -> torch.Tensor: + """Run the lora pass for gate_up_proj, usually attached to MergedColumnParallelLayer. + + Args: + x: input matrix with shape (s, input_dim), here s is the sum of all sequence lengths + gate_up_lora_a: lora_a module for gate_up_proj, with shape (num_lora, 2 * r, input_dim) + gate_up_lora_b: lora_b module for qkv. + If passed in as a tensor, its shape should be (num_lora, 2 * output_dim, r) + If passed in as a tuple, it should contain two tensors with shape (num_lora, output_dim, r) + Returns: + result with shape (s, 2 * output_dim) + """ + pass + + def init_cuda_graph_batch_info( + self, + max_bs_in_cuda_graph: int, + num_tokens_per_bs: int, + ): + """Initialize the batch info for CUDA Graph mode. + + This method provides a hook for each backend to conduct its own initialization + logic for CUDA Graph mode. + + Args: + cuda_graph_batch_info: the LoRABatchInfo object created in LoraManager + max_bs_in_cuda_graph: maximum batch size for CUDA Graph mode + num_tokens_per_bs: number of tokens per sequence (1 for decoding, >1 for target_verify) + """ + pass + + def prepare_lora_batch( + self, + forward_batch: ForwardBatch, + weight_indices: list[int], + lora_ranks: list[int], + scalings: list[float], + use_cuda_graph: bool, + ): + """Prepare the lora weights and batch info for current forward batch. + + This method provides a hook for each backend to conduct its own preparation + logic for each forward batch. + + Args: + forward_batch: the ForwardBatch object for current forward pass + weight_indices: list of indices of lora weights to be applied for current batch + lora_ranks: list of lora ranks corresponding to weight_indices + scalings: list of scaling factors corresponding to weight_indices + use_cuda_graph: whether to use CUDA Graph for this batch + """ + pass diff --git a/sglang/python/sglang/srt/lora/backend/chunked_backend.py b/sglang/python/sglang/srt/lora/backend/chunked_backend.py new file mode 100644 index 0000000000000000000000000000000000000000..54b28a77192f52c83bdde0e14a0b4284b37e8082 --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/chunked_backend.py @@ -0,0 +1,362 @@ +import torch + +from sglang.srt.lora.backend.base_backend import BaseLoRABackend +from sglang.srt.lora.triton_ops import ( + chunked_sgmv_lora_expand_forward, + chunked_sgmv_lora_shrink_forward, +) +from sglang.srt.lora.utils import LoRABatchInfo, generate_sequence_lengths +from sglang.srt.model_executor.forward_batch_info import ForwardBatch +from sglang.srt.server_args import ServerArgs + +MIN_CHUNK_SIZE = 16 + + +class ChunkedSgmvLoRABackend(BaseLoRABackend): + """ + Chunked LoRA backend using segmented matrix-vector multiplication. + + This backend is largely based on the SGMV (Segmented Gather Matrix-Vector multiplication) algorithm + introduced in the Punica paper (https://arxiv.org/pdf/2310.18547). One main variation made here is to + segment the input sequences into fixed-size chunks, which reduces excessive kernel launches especially + when the LoRA distribution is skewed. + """ + + name = "csgmv" + + def __init__( + self, + max_loras_per_batch: int, + device: torch.device, + server_args: ServerArgs, + ): + super().__init__(max_loras_per_batch, device) + self.max_chunk_size = server_args.max_lora_chunk_size + + def run_lora_a_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + return chunked_sgmv_lora_shrink_forward( + x=x, + weights=weights, + batch_info=self.batch_info, + num_slices=1, + ) + + def run_lora_b_sgemm( + self, + x: torch.Tensor, + weights: torch.Tensor, + output_offset: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + # For simple lora B, we use slice offsets [0, output_dim] + output_dim = weights.shape[-2] + max_slice_size = output_dim + return chunked_sgmv_lora_expand_forward( + x=x, + weights=weights, + batch_info=self.batch_info, + slice_offsets=output_offset, + max_slice_size=max_slice_size, + base_output=base_output, + ) + + def run_qkv_lora( + self, + x: torch.Tensor, + qkv_lora_a: torch.Tensor, + qkv_lora_b: torch.Tensor, + output_offset: torch.Tensor, + max_qkv_out_dim: int, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + + # x: (s, input_dim) + # qkv_lora_a: (num_lora, 3 * r, input_dim) + # qkv_lora_b: (num_lora, output_dim_q + 2 * output_dim_kv, r) + assert isinstance(qkv_lora_b, torch.Tensor) + + lora_a_output = chunked_sgmv_lora_shrink_forward( + x=x, + weights=qkv_lora_a, + batch_info=self.batch_info, + num_slices=3, + ) + lora_output = chunked_sgmv_lora_expand_forward( + x=lora_a_output, + weights=qkv_lora_b, + batch_info=self.batch_info, + slice_offsets=output_offset, + max_slice_size=max_qkv_out_dim, + base_output=base_output, + ) + return lora_output + + def run_gate_up_lora( + self, + x: torch.Tensor, + gate_up_lora_a: torch.Tensor, + gate_up_lora_b: torch.Tensor, + output_offset: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + + # x: (s, input_dim) + # gate_up_lora_a: (num_lora, 2 * r, input_dim) + # gate_up_lora_b: (num_lora, 2 * output_dim, r) + assert isinstance(gate_up_lora_b, torch.Tensor) + output_dim = gate_up_lora_b.shape[-2] // 2 + + # lora_a_output: (s, 2 * r) + lora_a_output = chunked_sgmv_lora_shrink_forward( + x=x, + weights=gate_up_lora_a, + batch_info=self.batch_info, + num_slices=2, + ) + lora_output = chunked_sgmv_lora_expand_forward( + x=lora_a_output, + weights=gate_up_lora_b, + batch_info=self.batch_info, + slice_offsets=output_offset, + max_slice_size=output_dim, + base_output=base_output, + ) + return lora_output + + def _determine_chunk_size(self, forward_batch: ForwardBatch) -> int: + """ + Heuristically determine the chunk size based on token token number in a batch. + + Args: + forward_batch (ForwardBatch): The batch information containing sequence lengths. + + Returns: + The determined chunk size + """ + + if self.max_chunk_size <= MIN_CHUNK_SIZE: + return MIN_CHUNK_SIZE + + num_tokens = ( + forward_batch.extend_num_tokens + if forward_batch.forward_mode.is_extend() + else forward_batch.batch_size + ) + if num_tokens >= 256: + chunk_size = 128 + elif num_tokens >= 64: + chunk_size = 32 + else: # num_tokens < 64 + chunk_size = 16 + return min(self.max_chunk_size, chunk_size) + + def init_cuda_graph_batch_info( + self, + max_bs_in_cuda_graph: int, + num_tokens_per_bs: int, + ): + max_num_segments = ( + (num_tokens_per_bs + MIN_CHUNK_SIZE - 1) // MIN_CHUNK_SIZE + ) * max_bs_in_cuda_graph + max_num_tokens = max_bs_in_cuda_graph * num_tokens_per_bs + with torch.device("cuda"): + self.cuda_graph_batch_info = LoRABatchInfo( + bs=max_bs_in_cuda_graph, + use_cuda_graph=True, + seg_lens=torch.zeros(max_num_segments, dtype=torch.int32), + seg_indptr=torch.zeros(max_num_segments + 1, dtype=torch.int32), + weight_indices=torch.zeros(max_num_segments, dtype=torch.int32), + permutation=torch.zeros(max_num_tokens, dtype=torch.int32), + lora_ranks=torch.zeros(self.max_loras_per_batch, dtype=torch.int32), + scalings=torch.zeros(self.max_loras_per_batch, dtype=torch.float), + num_segments=None, # Set per batch + max_len=None, # Not used in CSGMV backend + ) + + def prepare_lora_batch( + self, + forward_batch: ForwardBatch, + weight_indices: list[int], + lora_ranks: list[int], + scalings: list[float], + use_cuda_graph: bool, + ): + chunk_size = self._determine_chunk_size(forward_batch) + + permutation, weight_indices_reordered = ChunkedSgmvLoRABackend._get_permutation( + seq_weight_indices=weight_indices, + forward_batch=forward_batch, + ) + + seg_weight_indices, seg_indptr = self._get_segments_info( + weights_reordered=weight_indices_reordered, + chunk_size=chunk_size, + ) + num_segments = len(seg_weight_indices) + + lora_ranks_tensor = torch.tensor( + lora_ranks, dtype=torch.int32, pin_memory=True, device="cpu" + ) + scalings_tensor = torch.tensor( + scalings, dtype=torch.float, pin_memory=True, device="cpu" + ) + + if not use_cuda_graph: + batch_info = LoRABatchInfo( + bs=forward_batch.batch_size, + num_segments=num_segments, + max_len=chunk_size, + use_cuda_graph=False, + seg_indptr=torch.empty( + (num_segments + 1,), dtype=torch.int32, device=self.device + ), + weight_indices=torch.empty( + (num_segments,), dtype=torch.int32, device=self.device + ), + lora_ranks=torch.empty( + (self.max_loras_per_batch,), dtype=torch.int32, device=self.device + ), + scalings=torch.empty( + (self.max_loras_per_batch,), dtype=torch.float, device=self.device + ), + permutation=torch.empty( + (len(permutation),), dtype=torch.int32, device=self.device + ), + # Not used in chunked kernels + seg_lens=None, + ) + else: + batch_info = self.cuda_graph_batch_info + batch_info.bs = forward_batch.batch_size + batch_info.num_segments = num_segments + batch_info.max_len = chunk_size + + # Copy to device asynchronously + batch_info.lora_ranks[: self.max_loras_per_batch].copy_( + lora_ranks_tensor, non_blocking=True + ) + batch_info.scalings[: self.max_loras_per_batch].copy_( + scalings_tensor, non_blocking=True + ) + batch_info.weight_indices[:num_segments].copy_( + seg_weight_indices, non_blocking=True + ) + batch_info.seg_indptr[: num_segments + 1].copy_(seg_indptr, non_blocking=True) + batch_info.permutation[: len(permutation)].copy_(permutation, non_blocking=True) + + self.batch_info = batch_info + + @staticmethod + def _get_permutation(seq_weight_indices, forward_batch: ForwardBatch): + """ + Computes permutation indices for reordering tokens by their LoRA adapter assignments. + + This function implements the "gather" step in Chunked Segmented Gather Matrix Vector + multiplication by creating a permutation that groups tokens by their LoRA adapter. + Tokens using the same LoRA adapter are placed together to enable efficient batched + computation. + + Example: + seq_weight_indices = [0, 1, 0] # 3 sequences using adapters [0, 1, 0] + extend_seq_lens = [2, 1, 3] # sequence lengths [2, 1, 3 tokens] + + # Creates row_weight_indices: [0, 0, 1, 0, 0, 0] (6 tokens total) + # Returns permutation: [0, 1, 3, 4, 5, 2] (groups adapter 0 tokens together) + # weights_reordered: [0, 0, 0, 0, 0, 1] (sorted by adapter) + + Args: + seq_weight_indices: List of LoRA adapter indices for each sequence + forward_batch (ForwardBatch): Batch information containing sequence lengths + + Returns: + tuple: (permutation, weights_reordered) where: + - permutation: Token reordering indices to group by adapter + - weights_reordered: Sorted adapter indices for each token + """ + with torch.device("cpu"): + seq_weight_indices = torch.tensor(seq_weight_indices, dtype=torch.int32) + seg_lens_cpu = generate_sequence_lengths(forward_batch) + + row_weight_indices = torch.repeat_interleave( + seq_weight_indices, seg_lens_cpu + ) + permutation = torch.empty( + (len(row_weight_indices),), dtype=torch.long, pin_memory=True + ) + torch.argsort(row_weight_indices, stable=True, out=permutation) + weights_reordered = row_weight_indices[permutation] + + return permutation, weights_reordered + + def _get_segments_info(self, weights_reordered: torch.Tensor, chunk_size: int): + """ + Computes segment information for chunked SGMV operations. + + This function takes the reordered weight indices and creates segments of fixed size + (self.segment_size) for efficient kernel execution. Each segment contains tokens + that use the same LoRA adapter, enabling vectorized computation. + + The segmentation is necessary because: + 1. GPU kernels work efficiently on fixed-size blocks + 2. Large groups of tokens using the same adapter are split into manageable chunks + 3. Each segment can be processed independently in parallel + + Example: + weights_reordered = [0, 0, 0, 0, 0, 1] # 5 tokens with adapter 0, 1 with adapter 1 + segment_size = 3 + + # Creates segments: + # Segment 0: tokens 0-2 (adapter 0), length=3 + # Segment 1: tokens 3-4 (adapter 0), length=2 + # Segment 2: token 5 (adapter 1), length=1 + + # Returns: + # weight_indices_list: [0, 0, 1] (adapter for each segment) + # seg_indptr: [0, 3, 5, 6] (cumulative segment boundaries) + + Args: + weights_reordered (torch.Tensor): Sorted adapter indices for each token + chunk_size (int): Fixed size for each segment + + Returns: + tuple: (weight_indices_list, seg_indptr) where: + - weight_indices_list: LoRA adapter index for each segment + - seg_indptr: Cumulative segment boundaries (CSR-style indptr) + """ + with torch.device("cpu"): + unique_weights, counts = torch.unique_consecutive( + weights_reordered, return_counts=True + ) + + weight_indices_list = [] + seg_lens_list = [] + + for weight_idx, group_len in zip(unique_weights, counts): + group_len = group_len.item() + num_segs = (group_len + chunk_size - 1) // chunk_size + + weight_indices_list.extend([weight_idx.item()] * num_segs) + seg_lens_list.extend([chunk_size] * (num_segs - 1)) + seg_lens_list.append(group_len - (num_segs - 1) * chunk_size) + + seg_lens = torch.tensor(seg_lens_list, dtype=torch.int32) + + weight_indices_list = torch.tensor( + weight_indices_list, dtype=torch.int32, pin_memory=True + ) + + seg_indptr = torch.empty( + (len(seg_lens) + 1,), dtype=torch.int32, pin_memory=True + ) + seg_indptr[0] = 0 + seg_indptr[1:] = torch.cumsum(seg_lens, dim=0) + + return weight_indices_list, seg_indptr diff --git a/sglang/python/sglang/srt/lora/backend/lora_registry.py b/sglang/python/sglang/srt/lora/backend/lora_registry.py new file mode 100644 index 0000000000000000000000000000000000000000..15b531ab32b7d5f022813a4a74dcfeb0d1462c46 --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/lora_registry.py @@ -0,0 +1,61 @@ +import logging +from typing import Type + +from sglang.srt.lora.backend.base_backend import BaseLoRABackend + +logger = logging.getLogger(__name__) + +LORA_SUPPORTED_BACKENDS = {} + + +def register_lora_backend(name): + def decorator(fn): + LORA_SUPPORTED_BACKENDS[name] = fn + return fn + + return decorator + + +@register_lora_backend("triton") +def create_triton_backend(): + from sglang.srt.lora.backend.triton_backend import TritonLoRABackend + + return TritonLoRABackend + + +@register_lora_backend("csgmv") +def create_triton_csgmv_backend(): + from sglang.srt.lora.backend.chunked_backend import ChunkedSgmvLoRABackend + + return ChunkedSgmvLoRABackend + + +@register_lora_backend("ascend") +def create_ascend_backend(): + from sglang.srt.lora.backend.ascend_backend import AscendLoRABackend + + return AscendLoRABackend + + +@register_lora_backend("torch_native") +def create_torch_native_backend(): + from sglang.srt.lora.backend.torch_backend import TorchNativeLoRABackend + + return TorchNativeLoRABackend + + +@register_lora_backend("flashinfer") +def create_flashinfer_backend(): + raise ValueError( + "FlashInfer LoRA backend has been deprecated, please use `triton` instead." + ) + + +def get_backend_from_name(name: str) -> Type[BaseLoRABackend]: + """ + Get corresponding backend class from backend's name + """ + if name not in LORA_SUPPORTED_BACKENDS: + raise ValueError(f"Invalid backend: {name}") + lora_backend = LORA_SUPPORTED_BACKENDS[name]() + return lora_backend diff --git a/sglang/python/sglang/srt/lora/backend/torch_backend.py b/sglang/python/sglang/srt/lora/backend/torch_backend.py new file mode 100644 index 0000000000000000000000000000000000000000..3605d29e986ce556fd8a510e548511438f09b353 --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/torch_backend.py @@ -0,0 +1,275 @@ +from dataclasses import dataclass +from typing import Optional + +import torch + +from sglang.srt.lora.backend.base_backend import BaseLoRABackend +from sglang.srt.lora.torch_ops import sgemm_lora_a_fwd, sgemm_lora_b_fwd +from sglang.srt.lora.utils import LoRABatchInfo, generate_sequence_lengths +from sglang.srt.model_executor.forward_batch_info import ForwardBatch + + +@dataclass +class TorchNativeLoRABatchInfo(LoRABatchInfo): + # ranks of each lora adapter, in shape (lora_num,) placed on cpu device + lora_ranks_cpu: Optional[torch.Tensor] = None + + # Indice pointers of each segment in shape (num_segments + 1, ) placed on cpu device + seg_indptr_cpu: Optional[torch.Tensor] = None + + # Lengths of each segments in shape (num_segments,) placed on cpu device + seg_lens_cpu: Optional[torch.Tensor] = None + + # The index of lora adapter used by each segment, in shape (num_segments,) placed on cpu device + weight_indices_cpu: Optional[torch.Tensor] = None + + +class TorchNativeLoRABackend(BaseLoRABackend): + name = "torch_native" + + def __init__( + self, + max_loras_per_batch: int, + device: torch.device, + **kwargs, + ): + super().__init__(max_loras_per_batch, device) + + def run_lora_a_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + output_tensor = sgemm_lora_a_fwd( + inputs=x, + weights=weights, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + scaling_tensor=self.batch_info.scalings, + num_slices=1, + ) + + return output_tensor + + def run_lora_b_sgemm( + self, + x: torch.Tensor, + weights: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + _, weight_out_dim, _ = weights.shape + output_offset = torch.tensor( + [0, weight_out_dim], dtype=torch.int32, device="cpu" + ) + output_tensor = sgemm_lora_b_fwd( + inputs=x, + weights=weights, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + slice_offsets=output_offset, + base_output=base_output, + ) + + return output_tensor + + def run_qkv_lora( + self, + x: torch.Tensor, + qkv_lora_a: torch.Tensor, + qkv_lora_b: torch.Tensor, + output_offset: torch.Tensor, + output_offset_cpu: torch.Tensor, + max_qkv_out_dim: int, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + num_slices = 3 + lora_a_output = sgemm_lora_a_fwd( + inputs=x, + weights=qkv_lora_a, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + scaling_tensor=self.batch_info.scalings, + num_slices=num_slices, + ) + + output_tensor = sgemm_lora_b_fwd( + inputs=lora_a_output, + weights=qkv_lora_b, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + slice_offsets=output_offset_cpu, + base_output=base_output, + ) + + return output_tensor + + def run_gate_up_lora( + self, + x: torch.Tensor, + gate_up_lora_a: torch.Tensor, + gate_up_lora_b: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + num_slices = 2 + _, weight_out_dim, _ = gate_up_lora_b.shape + slice_size = weight_out_dim // num_slices + output_offset = torch.tensor( + [0, slice_size, weight_out_dim], dtype=torch.int32, device="cpu" + ) + + lora_a_output = sgemm_lora_a_fwd( + inputs=x, + weights=gate_up_lora_a, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + scaling_tensor=self.batch_info.scalings, + num_slices=num_slices, + ) + + output_tensor = sgemm_lora_b_fwd( + inputs=lora_a_output, + weights=gate_up_lora_b, + weight_indices=self.batch_info.weight_indices_cpu, + seg_len_tensor=self.batch_info.seg_lens_cpu, + lora_ranks=self.batch_info.lora_ranks_cpu, + slice_offsets=output_offset, + base_output=base_output, + ) + + return output_tensor + + def init_cuda_graph_batch_info( + self, + max_bs_in_cuda_graph: int, + num_tokens_per_bs: int, + ): + with torch.device("cuda"): + self.cuda_graph_batch_info = TorchNativeLoRABatchInfo( + use_cuda_graph=True, + bs=max_bs_in_cuda_graph, + num_segments=self.max_loras_per_batch, + seg_lens=torch.full( + (max_bs_in_cuda_graph,), num_tokens_per_bs, dtype=torch.int32 + ), + seg_indptr=torch.zeros(max_bs_in_cuda_graph + 1, dtype=torch.int32), + weight_indices=torch.zeros(max_bs_in_cuda_graph, dtype=torch.int32), + lora_ranks=torch.zeros(self.max_loras_per_batch, dtype=torch.int32), + scalings=torch.zeros(self.max_loras_per_batch, dtype=torch.float), + permutation=None, + max_len=num_tokens_per_bs, + ) + + # Initialize seg_indptr for CUDA graph as they remain constant + # across batches. + torch.cumsum( + self.cuda_graph_batch_info.seg_lens[:max_bs_in_cuda_graph], + dim=0, + out=self.cuda_graph_batch_info.seg_indptr[1 : max_bs_in_cuda_graph + 1], + ) + + def prepare_lora_batch( + self, + forward_batch: ForwardBatch, + weight_indices: list[int], + lora_ranks: list[int], + scalings: list[float], + use_cuda_graph: bool, + ): + original_seq_lens_cpu = generate_sequence_lengths(forward_batch, device="cpu") + original_weight_indices_tensor = torch.tensor( + weight_indices, dtype=torch.int32, device="cpu" + ) + + unique_weight_indices_tensor, inverse_weight_indices_tensor = ( + torch.unique_consecutive( + original_weight_indices_tensor, return_inverse=True + ) + ) + + seg_lens_cpu = ( + torch.zeros_like( + unique_weight_indices_tensor, dtype=torch.int32, device="cpu" + ) + .scatter_add_( + 0, + inverse_weight_indices_tensor, + original_seq_lens_cpu, + ) + .pin_memory() + ) + + seg_indptr_cpu = torch.zeros( + (len(seg_lens_cpu) + 1,), dtype=torch.int32, pin_memory=True + ) + seg_indptr_cpu[1:] = torch.cumsum(seg_lens_cpu, dim=0) + + # Use pinned memory to avoid synchronizations during host-to-device transfer + weight_indices_tensor = unique_weight_indices_tensor.pin_memory() + lora_ranks_tensor = torch.tensor( + lora_ranks, dtype=torch.int32, pin_memory=True, device="cpu" + ) + scalings_tensor = torch.tensor( + scalings, dtype=torch.float, pin_memory=True, device="cpu" + ) + + bs = forward_batch.batch_size + + if use_cuda_graph: + assert ( + self.cuda_graph_batch_info is not None + ), "CUDA Graph batch info is not initialized." + batch_info = self.cuda_graph_batch_info + batch_info.bs = forward_batch.batch_size + batch_info.num_segments = forward_batch.batch_size + else: + max_len = max(seg_lens_cpu) + + batch_info = TorchNativeLoRABatchInfo( + bs=forward_batch.batch_size, + num_segments=forward_batch.batch_size, + max_len=max_len, + use_cuda_graph=False, + seg_lens=torch.empty((bs,), dtype=torch.int32, device=self.device), + seg_indptr=torch.empty( + (bs + 1,), dtype=torch.int32, device=self.device + ), + weight_indices=torch.empty( + (bs,), dtype=torch.int32, device=self.device + ), + lora_ranks=torch.empty( + (self.max_loras_per_batch,), dtype=torch.int32, device=self.device + ), + scalings=torch.empty( + (self.max_loras_per_batch,), dtype=torch.float, device=self.device + ), + permutation=None, + ) + + # Copy to device asynchronously + batch_info.lora_ranks[: self.max_loras_per_batch].copy_( + lora_ranks_tensor, non_blocking=True + ) + batch_info.scalings[: self.max_loras_per_batch].copy_( + scalings_tensor, non_blocking=True + ) + batch_info.weight_indices[:bs].copy_(weight_indices_tensor, non_blocking=True) + batch_info.seg_indptr[: len(seg_indptr_cpu)].copy_( + seg_indptr_cpu, non_blocking=True + ) + batch_info.seg_lens[: len(seg_lens_cpu)].copy_(seg_lens_cpu, non_blocking=True) + + batch_info.lora_ranks_cpu = lora_ranks_tensor + batch_info.seg_indptr_cpu = seg_indptr_cpu + batch_info.seg_lens_cpu = seg_lens_cpu + batch_info.weight_indices_cpu = weight_indices_tensor + + self.batch_info = batch_info diff --git a/sglang/python/sglang/srt/lora/backend/triton_backend.py b/sglang/python/sglang/srt/lora/backend/triton_backend.py new file mode 100644 index 0000000000000000000000000000000000000000..ad79199fd27b4b06a1bbe6f8f6768f0980ea017c --- /dev/null +++ b/sglang/python/sglang/srt/lora/backend/triton_backend.py @@ -0,0 +1,216 @@ +import torch + +from sglang.srt.lora.backend.base_backend import BaseLoRABackend +from sglang.srt.lora.triton_ops import ( + embedding_lora_a_fwd, + gate_up_lora_b_fwd, + qkv_lora_b_fwd, + sgemm_lora_a_fwd, + sgemm_lora_b_fwd, +) +from sglang.srt.lora.utils import LoRABatchInfo +from sglang.srt.model_executor.forward_batch_info import ForwardBatch + + +class TritonLoRABackend(BaseLoRABackend): + name = "triton" + + def __init__( + self, + max_loras_per_batch: int, + device: torch.device, + **kwargs, + ): + super().__init__(max_loras_per_batch, device) + + def run_lora_a_embedding( + self, + input_ids: torch.Tensor, + weights: torch.Tensor, + vocab_size: int, + extra_embeddings: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + """Run LoRA A embedding lookup using Triton kernel.""" + return embedding_lora_a_fwd( + input_ids=input_ids, + weights=weights, + batch_info=self.batch_info, + vocab_size=vocab_size, + extra_embeddings=extra_embeddings, + ) + + def run_lora_a_sgemm( + self, x: torch.Tensor, weights: torch.Tensor, *args, **kwargs + ) -> torch.Tensor: + return sgemm_lora_a_fwd(x, weights, self.batch_info) + + def run_lora_b_sgemm( + self, + x: torch.Tensor, + weights: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + return sgemm_lora_b_fwd(x, weights, self.batch_info, base_output) + + def run_qkv_lora( + self, + x: torch.Tensor, + qkv_lora_a: torch.Tensor, + qkv_lora_b: torch.Tensor, + output_offset: torch.Tensor, + max_qkv_out_dim: int, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + + # x: (s, input_dim) + # qkv_lora_a: (num_lora, 3 * r, input_dim) + # qkv_lora_b: (num_lora, output_dim_q + 2 * output_dim_kv, r) + assert isinstance(qkv_lora_b, torch.Tensor) + + lora_a_output = sgemm_lora_a_fwd(x, qkv_lora_a, self.batch_info, stack_num=3) + lora_output = qkv_lora_b_fwd( + lora_a_output, + qkv_lora_b, + self.batch_info, + output_offset, + max_qkv_out_dim, + base_output, + ) + return lora_output + + def run_gate_up_lora( + self, + x: torch.Tensor, + gate_up_lora_a: torch.Tensor, + gate_up_lora_b: torch.Tensor, + base_output: torch.Tensor = None, + *args, + **kwargs, + ) -> torch.Tensor: + + # x: (s, input_dim) + # gate_up_lora_a: (num_lora, 2 * r, input_dim) + # gate_up_lora_b: (num_lora, 2 * output_dim, r) + assert isinstance(gate_up_lora_b, torch.Tensor) + output_dim = gate_up_lora_b.shape[-2] // 2 + + # lora_a_output: (s, 2 * r) + lora_a_output = sgemm_lora_a_fwd( + x, gate_up_lora_a, self.batch_info, stack_num=2 + ) + lora_output = gate_up_lora_b_fwd( + lora_a_output, + gate_up_lora_b, + self.batch_info, + output_dim, + base_output, + ) + return lora_output + + def init_cuda_graph_batch_info( + self, + max_bs_in_cuda_graph: int, + num_tokens_per_bs: int, + ): + with torch.device("cuda"): + self.cuda_graph_batch_info = LoRABatchInfo( + bs=max_bs_in_cuda_graph, + use_cuda_graph=True, + num_segments=None, + seg_lens=torch.full( + (max_bs_in_cuda_graph,), num_tokens_per_bs, dtype=torch.int32 + ), + seg_indptr=torch.zeros(max_bs_in_cuda_graph + 1, dtype=torch.int32), + max_len=num_tokens_per_bs, + weight_indices=torch.zeros(max_bs_in_cuda_graph, dtype=torch.int32), + lora_ranks=torch.zeros(self.max_loras_per_batch, dtype=torch.int32), + scalings=torch.zeros(self.max_loras_per_batch, dtype=torch.float), + permutation=None, + ) + + # Initialize seg_indptr for CUDA graph as they remain constant + # across batches. + torch.cumsum( + self.cuda_graph_batch_info.seg_lens[:max_bs_in_cuda_graph], + dim=0, + out=self.cuda_graph_batch_info.seg_indptr[1 : max_bs_in_cuda_graph + 1], + ) + + def prepare_lora_batch( + self, + forward_batch: ForwardBatch, + weight_indices: list[int], + lora_ranks: list[int], + scalings: list[float], + use_cuda_graph: bool, + ): + # Use pinned memory to avoid synchronizations during host-to-device transfer + weight_indices_tensor = torch.tensor( + weight_indices, dtype=torch.int32, pin_memory=True, device="cpu" + ) + lora_ranks_tensor = torch.tensor( + lora_ranks, dtype=torch.int32, pin_memory=True, device="cpu" + ) + scalings_tensor = torch.tensor( + scalings, dtype=torch.float, pin_memory=True, device="cpu" + ) + + bs = forward_batch.batch_size + + if use_cuda_graph: + assert ( + self.cuda_graph_batch_info is not None + ), "CUDA Graph batch info is not initialized." + batch_info = self.cuda_graph_batch_info + batch_info.bs = forward_batch.batch_size + batch_info.num_segments = forward_batch.batch_size + else: + max_len = ( + # Calculate max_len from the CPU copy to avoid D2H transfer. + max(forward_batch.extend_seq_lens_cpu) + if forward_batch.forward_mode.is_extend() + else 1 + ) + seg_lens = ( + forward_batch.extend_seq_lens + if forward_batch.forward_mode.is_extend() + else torch.ones(bs, dtype=torch.int32, device=self.device) + ) + seg_indptr = torch.zeros((bs + 1,), dtype=torch.int32, device=self.device) + seg_indptr[1:] = torch.cumsum(seg_lens, dim=0) + + batch_info = LoRABatchInfo( + bs=forward_batch.batch_size, + num_segments=forward_batch.batch_size, + max_len=max_len, + use_cuda_graph=False, + seg_lens=seg_lens, + seg_indptr=seg_indptr, + weight_indices=torch.empty( + (bs,), dtype=torch.int32, device=self.device + ), + lora_ranks=torch.empty( + (self.max_loras_per_batch,), dtype=torch.int64, device=self.device + ), + scalings=torch.empty( + (self.max_loras_per_batch,), dtype=torch.float, device=self.device + ), + permutation=None, + ) + + # Copy to device asynchronously + batch_info.lora_ranks[: self.max_loras_per_batch].copy_( + lora_ranks_tensor, non_blocking=True + ) + batch_info.scalings[: self.max_loras_per_batch].copy_( + scalings_tensor, non_blocking=True + ) + batch_info.weight_indices[:bs].copy_(weight_indices_tensor, non_blocking=True) + + self.batch_info = batch_info diff --git a/sglang/python/sglang/srt/lora/torch_ops/__init__.py b/sglang/python/sglang/srt/lora/torch_ops/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bc3a5391d6480d168ac49d58190c476e5d041bcf --- /dev/null +++ b/sglang/python/sglang/srt/lora/torch_ops/__init__.py @@ -0,0 +1,6 @@ +from .lora_ops import sgemm_lora_a_fwd, sgemm_lora_b_fwd + +__all__ = [ + "sgemm_lora_a_fwd", + "sgemm_lora_b_fwd", +] diff --git a/sglang/python/sglang/srt/lora/torch_ops/lora_ops.py b/sglang/python/sglang/srt/lora/torch_ops/lora_ops.py new file mode 100644 index 0000000000000000000000000000000000000000..7e72b9d4fd4f35df283e142f359ca8b0aac12cbc --- /dev/null +++ b/sglang/python/sglang/srt/lora/torch_ops/lora_ops.py @@ -0,0 +1,109 @@ +from typing import Optional + +import torch + + +def sgemm_lora_a_fwd( + inputs: torch.Tensor, + weights: torch.Tensor, + weight_indices: torch.Tensor, + seg_len_tensor: torch.Tensor, + lora_ranks: torch.Tensor, + scaling_tensor: torch.Tensor, + num_slices: int = 1, +): + total_seq_len, input_dim = inputs.shape + if weights.numel() == 0: + return torch.zeros(total_seq_len, 0, dtype=inputs.dtype, device=inputs.device) + + num_loras, weight_out_dim, _ = weights.shape + max_rank = weight_out_dim // num_slices + + output = torch.zeros( + total_seq_len, num_slices * max_rank, dtype=inputs.dtype, device=inputs.device + ) + + token_offset = 0 + for lora_idx, seq_len, rank in zip( + weight_indices, seg_len_tensor, lora_ranks[weight_indices] + ): + if seq_len == 0: + continue + + if rank > 0: + + x_seq = inputs[token_offset : token_offset + seq_len, :] + w_seq = weights[lora_idx, : num_slices * rank, :] + + result = torch.einsum("si, oi -> so", x_seq, w_seq) + output[token_offset : token_offset + seq_len, : num_slices * rank] = ( + scaling_tensor[lora_idx] * result + ) + + token_offset += seq_len + + return output + + +def sgemm_lora_b_fwd( + inputs: torch.Tensor, + weights: torch.Tensor, + weight_indices: torch.Tensor, + seg_len_tensor: torch.Tensor, + lora_ranks: torch.Tensor, + slice_offsets: torch.Tensor, + base_output: Optional[torch.Tensor] = None, +): + total_seq_len, _ = inputs.shape + num_loras, weight_out_dim, _ = weights.shape + total_output_dim = slice_offsets[-1].item() if len(slice_offsets) > 0 else 0 + + if weights.numel() == 0: + return torch.zeros( + total_seq_len, total_output_dim, dtype=inputs.dtype, device=inputs.device + ) + + num_slices = len(slice_offsets) - 1 + + if base_output is not None: + output = base_output + else: + output = torch.zeros( + total_seq_len, total_output_dim, dtype=inputs.dtype, device=inputs.device + ) + + token_offset = 0 + for lora_idx, seq_len, rank in zip( + weight_indices, seg_len_tensor, lora_ranks[weight_indices] + ): + if seq_len == 0: + continue + + if rank == 0: + token_offset += seq_len + continue + + for slice_idx in range(num_slices): + slice_start_input = slice_idx * rank + slice_end_input = (slice_idx + 1) * rank + + slice_start_output = slice_offsets[slice_idx] + slice_end_output = slice_offsets[slice_idx + 1] + + x_slice = inputs[ + token_offset : token_offset + seq_len :, + slice_start_input:slice_end_input, + ] # (seq_len, rank) + w_slice = weights[ + lora_idx, slice_start_output:slice_end_output, :rank + ] # (slice_dim, rank) + + result = torch.einsum("si, oi -> so", x_slice, w_slice) + output[ + token_offset : token_offset + seq_len, + slice_start_output:slice_end_output, + ] += result + + token_offset += seq_len + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/__init__.py b/sglang/python/sglang/srt/lora/triton_ops/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..71eb1fea4837f896b13e3835150da2927d741744 --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/__init__.py @@ -0,0 +1,17 @@ +from .chunked_sgmv_expand import chunked_sgmv_lora_expand_forward +from .chunked_sgmv_shrink import chunked_sgmv_lora_shrink_forward +from .embedding_lora_a import embedding_lora_a_fwd +from .gate_up_lora_b import gate_up_lora_b_fwd +from .qkv_lora_b import qkv_lora_b_fwd +from .sgemm_lora_a import sgemm_lora_a_fwd +from .sgemm_lora_b import sgemm_lora_b_fwd + +__all__ = [ + "gate_up_lora_b_fwd", + "qkv_lora_b_fwd", + "sgemm_lora_a_fwd", + "sgemm_lora_b_fwd", + "chunked_sgmv_lora_shrink_forward", + "chunked_sgmv_lora_expand_forward", + "embedding_lora_a_fwd", +] diff --git a/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_expand.py b/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_expand.py new file mode 100644 index 0000000000000000000000000000000000000000..414f704a7149c3e4cb2fcba2ec7b18f2a414779d --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_expand.py @@ -0,0 +1,214 @@ +from typing import Optional + +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo +from sglang.srt.utils import cached_triton_kernel + + +@cached_triton_kernel(lambda _, kwargs: (kwargs["NUM_SLICES"], kwargs["BLOCK_M"])) +@triton.jit(do_not_specialize=["num_segs"]) +def _chunked_lora_expand_kernel( + # Pointers to matrices + x, + weights, + output, + # Information on sequence lengths and weight id + seg_indptr, + weight_indices, + lora_ranks, + permutation, + num_segs, + # For fused output scaling + scalings, + # Offsets of q/k/v slice on output dimension + slice_offsets, + # Meta parameters + NUM_SLICES: tl.constexpr, + OUTPUT_DIM: tl.constexpr, + MAX_RANK: tl.constexpr, # K = R + BLOCK_M: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, +): + """ + Computes a chunked SGMV for LoRA expand operations. + + When a sequence's rank is 0, the kernel is essentially a no-op, following + the convention in pytorch where the product of two matrices of shape (m, 0) + and (0, n) is an all-zero matrix of shape (m, n). + + Args: + x (Tensor): The input tensor, which is the result of the LoRA A projection. + Shape: (s, num_slices * K), where s is the sum of all sequence lengths in the + batch and K is the maximum LoRA rank. + weights (Tensor): The LoRA B weights for all adapters. + Shape: (num_lora, output_dim, K). + output (Tensor): The output tensor where the result is stored. + Shape: (s, output_dim). + """ + tl.static_assert(NUM_SLICES <= 3) + + x_stride_0: tl.constexpr = NUM_SLICES * MAX_RANK + x_stride_1: tl.constexpr = 1 + + w_stride_0: tl.constexpr = OUTPUT_DIM * MAX_RANK + w_stride_1: tl.constexpr = MAX_RANK + w_stride_2: tl.constexpr = 1 + + output_stride_0: tl.constexpr = OUTPUT_DIM + output_stride_1: tl.constexpr = 1 + + pid_s = tl.program_id(axis=2) + if pid_s >= num_segs: + return + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len. + # qkv_id decides which of q,k,v to compute (0: q, 1: k, 2: v) + w_index = tl.load(weight_indices + pid_s) + cur_rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel is a no-op. + if cur_rank == 0: + return + + seg_start = tl.load(seg_indptr + pid_s) + seg_end = tl.load(seg_indptr + pid_s + 1) + + slice_id = tl.program_id(axis=1) + slice_start = tl.load(slice_offsets + slice_id) + slice_end = tl.load(slice_offsets + slice_id + 1) + + scaling = tl.load(scalings + w_index) + # Adjust K (rank) according to the specific LoRA adapter + cur_rank = tl.minimum(MAX_RANK, cur_rank) + + # Map logical sequence index to physical index + s_offset_logical = tl.arange(0, BLOCK_M) + seg_start + s_offset_physical = tl.load( + permutation + s_offset_logical, mask=s_offset_logical < seg_end + ) + + # Create pointers for the first block of x and weights[batch_id][n_start: n_end][:] + # The pointers will be advanced as we move in the K direction + # and accumulate + pid_n = tl.program_id(axis=0) + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + slice_start + k_offset = tl.arange(0, BLOCK_K) + + x_ptrs = ( + x + + slice_id * cur_rank * x_stride_1 + + (s_offset_physical[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1) + ) + w_ptrs = (weights + w_index * w_stride_0) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(cur_rank, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset_logical[:, None] < seg_end) + & (k_offset[None, :] < cur_rank - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < cur_rank - k * BLOCK_K) + & (n_offset[None, :] < slice_end), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum *= scaling + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = output + ( + s_offset_physical[:, None] * output_stride_0 + + n_offset[None, :] * output_stride_1 + ) + output_mask = (s_offset_logical[:, None] < seg_end) & ( + n_offset[None, :] < slice_end + ) + partial_sum += tl.load(output_ptr, mask=output_mask, other=0.0) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def chunked_sgmv_lora_expand_forward( + x: torch.Tensor, + weights: torch.Tensor, + batch_info: LoRABatchInfo, + slice_offsets: torch.Tensor, + max_slice_size: int, + base_output: Optional[torch.Tensor], +) -> torch.Tensor: + + # x: (s, slice_num * r) + # weights: (num_lora, output_dim, r) + # slice_offsets: boundaries for different slices in the output dimension + # output: (s, output_dim) + + # Compute lora_output with shape (s, output_dim) as follows: + # For each slice i, accumulates: + # lora_output[:, slice_offsets[i]:slice_offsets[i+1]] += scaling * sgemm(x[:, i*cur_rank:(i+1)*cur_rank], weights[:, slice_offsets[i]:slice_offsets[i+1], :]) + + assert x.is_contiguous() + assert weights.is_contiguous() + assert len(x.shape) == 2 + assert len(weights.shape) == 3 + + # Get dims + M = x.shape[0] + input_dim = x.shape[1] + OUTPUT_DIM = weights.shape[1] + MAX_RANK = weights.shape[2] + num_slices = len(slice_offsets) - 1 + assert input_dim == num_slices * MAX_RANK + + # TODO (lifuhuang): fine-tune per operation + BLOCK_M = batch_info.max_len + BLOCK_K = 16 + BLOCK_N = 64 + + num_segments = batch_info.num_segments + + grid = ( + triton.cdiv(max_slice_size, BLOCK_N), + num_slices, # number of slices in the input/output + batch_info.bs if batch_info.use_cuda_graph else num_segments, + ) + + if base_output is None: + output = torch.zeros((M, OUTPUT_DIM), device=x.device, dtype=x.dtype) + else: + output = base_output + + _chunked_lora_expand_kernel[grid]( + x=x, + weights=weights, + output=output, + seg_indptr=batch_info.seg_indptr, + weight_indices=batch_info.weight_indices, + lora_ranks=batch_info.lora_ranks, + permutation=batch_info.permutation, + num_segs=num_segments, + scalings=batch_info.scalings, + slice_offsets=slice_offsets, + # constants + NUM_SLICES=num_slices, + OUTPUT_DIM=OUTPUT_DIM, + MAX_RANK=MAX_RANK, + BLOCK_M=BLOCK_M, + BLOCK_N=BLOCK_N, + BLOCK_K=BLOCK_K, + ) + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_shrink.py b/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_shrink.py new file mode 100644 index 0000000000000000000000000000000000000000..b0ffdb763a990a0362135063cb971edc2bd6bb8e --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/chunked_sgmv_shrink.py @@ -0,0 +1,176 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo +from sglang.srt.utils import cached_triton_kernel + + +@cached_triton_kernel( + lambda _, kwargs: (kwargs["K"], kwargs["NUM_SLICES"], kwargs["BLOCK_M"]) +) +@triton.jit(do_not_specialize=["num_segs"]) +def _chunked_lora_shrink_kernel( + # Pointers to matrices + x, + weights, + output, + # Information on sequence lengths,ranks and weight id + seg_indptr, + weight_indices, + lora_ranks, + permutation, + num_segs, + # Meta parameters + N: tl.constexpr, # num_slices * r + K: tl.constexpr, # input_dim + NUM_SLICES: tl.constexpr, + BLOCK_M: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, +): + """ + Computes a chunked SGMV for LoRA shrink operations. + + The kernel ensures that output[seg_start:seg_start + seg_len, :rank * num_slices] + stores the product of the input `x` and the LoRA weights for the corresponding + sequence. This implies that when rank is 0, the kernel is essentially a no-op, + as output[seg_start:seg_start + seg_len, :0] is trivially correct (empty). + + Args: + x (torch.Tensor): The input activations tensor of shape `(s, K)`, where `s` + is the sum of all sequence lengths in the batch. + weights (torch.Tensor): The LoRA A weights for all available adapters, + with shape `(num_lora, N, K)` where N = num_slices * r. + output (torch.Tensor): The output tensor of shape `(s, N)`. + """ + x_stride_1: tl.constexpr = 1 + x_stride_0: tl.constexpr = K + + w_stride_0: tl.constexpr = N * K + w_stride_1: tl.constexpr = K + w_stride_2: tl.constexpr = 1 + + output_stride_0: tl.constexpr = N + output_stride_1: tl.constexpr = 1 + + pid_s = tl.program_id(1) + if pid_s >= num_segs: + return + + pid_n = tl.program_id(0) + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len + w_index = tl.load(weight_indices + pid_s) + rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel becomes a no-op as the output is always trivially correct. + if rank == 0: + return + + seg_start = tl.load(seg_indptr + pid_s) + seg_end = tl.load(seg_indptr + pid_s + 1) + + # Adjust N dim according to the specific LoRA adapter + cur_n = tl.minimum(N, rank * NUM_SLICES) + + # Map logical sequence index to physical index + s_offset_logical = tl.arange(0, BLOCK_M) + seg_start + s_offset_physical = tl.load( + permutation + s_offset_logical, mask=s_offset_logical < seg_end + ) + + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + k_offset = tl.arange(0, BLOCK_K) + x_ptrs = x + ( + s_offset_physical[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1 + ) + w_ptrs = (weights + w_index * w_stride_0) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(K, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset_logical[:, None] < seg_end) + & (k_offset[None, :] < K - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < K - k * BLOCK_K) & (n_offset[None, :] < cur_n), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = output + ( + s_offset_physical[:, None] * output_stride_0 + + n_offset[None, :] * output_stride_1 + ) + output_mask = (s_offset_logical[:, None] < seg_end) & (n_offset[None, :] < cur_n) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def chunked_sgmv_lora_shrink_forward( + x: torch.Tensor, + weights: torch.Tensor, + batch_info: LoRABatchInfo, + num_slices: int, +) -> torch.Tensor: + # x: (s, input_dim) + # weights: (num_lora, num_slices * r, input_dim) + # output: (s, num_slices * r) + # num_slices: qkv=3, gate_up=2, others=1 + # when called with multiple slices, the weights.shape[-2] will be num_slices * r + # input_dim is much larger than r + + assert x.is_contiguous() + assert weights.is_contiguous() + assert len(x.shape) == 2 + assert len(weights.shape) == 3 + + # Block shapes + # TODO (lifuhuang): experiment with split-k + BLOCK_M = batch_info.max_len + BLOCK_N = 16 + BLOCK_K = 256 + + S = x.shape[0] + N = weights.shape[1] + K = weights.shape[2] + assert x.shape[-1] == K + + num_segments = batch_info.num_segments + grid = ( + triton.cdiv(N, BLOCK_N), + batch_info.bs if batch_info.use_cuda_graph else num_segments, + ) + + output = torch.empty((S, N), device=x.device, dtype=x.dtype) + _chunked_lora_shrink_kernel[grid]( + x=x, + weights=weights, + output=output, + seg_indptr=batch_info.seg_indptr, + weight_indices=batch_info.weight_indices, + lora_ranks=batch_info.lora_ranks, + permutation=batch_info.permutation, + num_segs=num_segments, + # constants + N=N, + K=K, + NUM_SLICES=num_slices, + BLOCK_M=BLOCK_M, + BLOCK_N=BLOCK_N, + BLOCK_K=BLOCK_K, + ) + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/embedding_lora_a.py b/sglang/python/sglang/srt/lora/triton_ops/embedding_lora_a.py new file mode 100644 index 0000000000000000000000000000000000000000..1e21be50fd796ded0233e0703eb1fd580f1490af --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/embedding_lora_a.py @@ -0,0 +1,186 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo + + +@triton.jit +def _embedding_lora_a_kernel( + # Pointers to tensors + input_ids, + weights, + output, + extra_embeddings, + # Dimensions + vocab_size, + rank, + num_loras, + # Strides + w_stride_0, # stride for lora index + w_stride_1, # stride for rank + w_stride_2, # stride for vocab + output_stride_0, + output_stride_1, + extra_emb_stride_0, # stride for lora index + extra_emb_stride_1, # stride for token + extra_emb_stride_2, # stride for hidden dim (= rank for extra embeddings) + # Batch info + seg_lens, + seg_indptr, + weight_indices, + lora_ranks, + # Meta-parameters + BLOCK_RANK: tl.constexpr, + HAS_EXTRA_EMBEDDINGS: tl.constexpr, +): + """ + Embedding lookup for LoRA A weights with support for extra tokens. + + Each program handles one token across a block of rank dimensions. + Grid: (cdiv(max_len, 1), bs) - one program per token in each batch + """ + batch_id = tl.program_id(axis=1) + token_idx = tl.program_id(axis=0) + + w_index = tl.load(weight_indices + batch_id) + rank_val = tl.load(lora_ranks + w_index) + + # If rank is 0, skip + if rank_val == 0: + return + + seg_start = tl.load(seg_indptr + batch_id) + seg_len = tl.load(seg_lens + batch_id) + + # Check if this token is within the segment + if token_idx >= seg_len: + return + + # Load the token ID + token_id = tl.load(input_ids + seg_start + token_idx) + + # Process in chunks of BLOCK_RANK dimensions + num_blocks = tl.cdiv(rank_val, BLOCK_RANK) + + for block_id in range(num_blocks): + rank_offset = tl.arange(0, BLOCK_RANK) + block_id * BLOCK_RANK + rank_mask = rank_offset < rank_val + + # Check if this is an extra token + is_extra_token = token_id >= vocab_size + + if HAS_EXTRA_EMBEDDINGS and is_extra_token: + # Use extra embeddings + extra_token_id = token_id - vocab_size + extra_emb_ptr = ( + extra_embeddings + + w_index * extra_emb_stride_0 + + extra_token_id * extra_emb_stride_1 + + rank_offset * extra_emb_stride_2 + ) + emb_values = tl.load(extra_emb_ptr, mask=rank_mask, other=0.0) + else: + # Use regular LoRA A weights + # weights shape: (num_loras, rank, vocab_size) + # We need to load weights[w_index, rank_offset, token_id] + token_id_clamped = tl.minimum(token_id, vocab_size - 1) + weight_ptr = ( + weights + + w_index * w_stride_0 + + rank_offset * w_stride_1 + + token_id_clamped * w_stride_2 + ) + emb_values = tl.load(weight_ptr, mask=rank_mask, other=0.0) + + # Write to output + output_ptr = ( + output + + (seg_start + token_idx) * output_stride_0 + + rank_offset * output_stride_1 + ) + tl.store(output_ptr, emb_values, mask=rank_mask) + + +def embedding_lora_a_fwd( + input_ids: torch.Tensor, + weights: torch.Tensor, + batch_info: LoRABatchInfo, + vocab_size: int, + extra_embeddings: torch.Tensor = None, +) -> torch.Tensor: + """ + Forward pass for LoRA A embedding lookup. + + Args: + input_ids: (s,) token IDs + weights: (num_loras, rank, vocab_size) LoRA A embedding weights + batch_info: LoRABatchInfo containing batch information + vocab_size: base vocabulary size + extra_embeddings: (num_loras, num_extra_tokens, rank) extra token embeddings + + Returns: + output: (s, rank) embedded features + """ + assert input_ids.is_contiguous() + assert weights.is_contiguous() + assert len(input_ids.shape) == 1 + assert len(weights.shape) == 3 + + S = input_ids.shape[0] + num_loras = weights.shape[0] + rank = weights.shape[1] + vocab_size_weights = weights.shape[2] + + # Block size for rank dimension + BLOCK_RANK = 128 + + has_extra_embeddings = extra_embeddings is not None + + if has_extra_embeddings: + assert extra_embeddings.is_contiguous() + extra_emb_stride = ( + extra_embeddings.stride(0), + extra_embeddings.stride(1), + extra_embeddings.stride(2), + ) + else: + # Create dummy tensor to satisfy Triton + extra_embeddings = torch.empty( + (1, 1, 1), device=input_ids.device, dtype=weights.dtype + ) + extra_emb_stride = (1, 1, 1) + + # Grid: one program per token in each batch segment + grid = ( + batch_info.max_len, + batch_info.bs, + ) + + output = torch.zeros((S, rank), device=input_ids.device, dtype=weights.dtype) + + _embedding_lora_a_kernel[grid]( + input_ids, + weights, + output, + extra_embeddings, + vocab_size, + rank, + num_loras, + weights.stride(0), + weights.stride(1), + weights.stride(2), + output.stride(0), + output.stride(1), + extra_emb_stride[0], + extra_emb_stride[1], + extra_emb_stride[2], + batch_info.seg_lens, + batch_info.seg_indptr, + batch_info.weight_indices, + batch_info.lora_ranks, + BLOCK_RANK, + has_extra_embeddings, + ) + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/gate_up_lora_b.py b/sglang/python/sglang/srt/lora/triton_ops/gate_up_lora_b.py new file mode 100644 index 0000000000000000000000000000000000000000..fc4574dd3b1efe87a291ed7bd835dbc9306b83c0 --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/gate_up_lora_b.py @@ -0,0 +1,187 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo + + +@triton.jit +def _gate_up_lora_b_kernel( + # Pointers to matrices + x, + weights, + output, + # Parameters of size + K, # K = R + output_dim, + # Strides + x_stride_0, + x_stride_1, + w_stride_0, + w_stride_1, + w_stride_2, + output_stride_0, + output_stride_1, + # Information on sequence lengths,ranks and weight id + seg_lens, + seg_indptr, + weight_indices, + lora_ranks, + # Meta parameters + BLOCK_S: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, + # For fused output scaling + scalings, +): + """ + This kernel packs 2 sgemms (gate/up) into a single kernel. The multiplication + results are accumulated into the output tensor. + + When a sequence's rank is 0, the kernel is essentially a no-op, following + the convention in pytorch where the product of two matrices of shape (m, 0) + and (0, n) is an all-zero matrix of shape (m, n). + + Args: + x (Tensor): The input tensor, which is the result of the LoRA A projection. + Shape: (s, 2 * K), where s is the sum of all sequence lengths in the + batch and K is the maximum LoRA rank. + weights (Tensor): The LoRA B weights for all adapters. + Shape: (num_lora, 2 * output_dim, K). + output (Tensor): The output tensor where the result is stored. + Shape: (s, 2 * output_dim). + """ + # output_dim >> K + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len. + # gate_up_id decides which of gate or up (0: gate, 1: up) + batch_id = tl.program_id(axis=2) + w_index = tl.load(weight_indices + batch_id) + rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel is a no-op. + if rank == 0: + return + + gate_up_id = tl.program_id(axis=1) + pid = tl.program_id(axis=0) + seg_len = tl.load(seg_lens + batch_id) + seg_start = tl.load(seg_indptr + batch_id) + n_start = gate_up_id * output_dim # offset on output dim + scaling = tl.load(scalings + w_index) + + # Adjust K (rank) according to the specific LoRA adapter + K = tl.minimum(K, rank) + + # The tile in output matrix will have (pid_s, pid_n) as id + num_pid_n = tl.cdiv(output_dim, BLOCK_N) + pid_s = pid // num_pid_n + pid_n = pid % num_pid_n + + # Create pointers for the first block of x and weights + # The pointers will be advanced as we move in the K direction + # and accumulate + s_offset = tl.arange(0, BLOCK_S) + pid_s * BLOCK_S + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + k_offset = tl.arange(0, BLOCK_K) + + x_ptrs = (x + seg_start * x_stride_0 + (gate_up_id * K) * x_stride_1) + ( + s_offset[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1 + ) + w_ptrs = (weights + w_index * w_stride_0 + n_start * w_stride_1) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_S, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(K, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset[:, None] < seg_len) & (k_offset[None, :] < K - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < K - k * BLOCK_K) + & (n_offset[None, :] < output_dim), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum *= scaling + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = (output + seg_start * output_stride_0 + n_start * output_stride_1) + ( + s_offset[:, None] * output_stride_0 + n_offset[None, :] * output_stride_1 + ) + output_mask = (s_offset[:, None] < seg_len) & (n_offset[None, :] < output_dim) + partial_sum += tl.load(output_ptr, mask=output_mask) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def gate_up_lora_b_fwd( + x: torch.Tensor, + gate_up_lora_b: torch.Tensor, + batch_info: LoRABatchInfo, + output_dim: int, + base_output: torch.Tensor = None, +) -> torch.Tensor: + + # x: (s, 2 * r) + # gate_up_lora_b: (num_lora, 2 * output_dim, r) + # output: (s, 2 * output_dim) + + # Compute lora_output with shape (s, output_dim) as follows: + # lora_output[:, :output_dim] = sgemm(x[:, :r], gate_up_lora_b[:, :output_dim, :]) + # lora_output[:, output_dim:] + # = sgemm(x[:, r:], gate_up_lora_b[:, output_dim:, :]) + + # Get dims + s = x.shape[0] + input_dim = x.shape[1] + r = gate_up_lora_b.shape[-1] + assert input_dim == 2 * r + + BLOCK_S = 16 + BLOCK_R = 16 + BLOCK_OUT = 64 + + grid_b = ( + triton.cdiv(batch_info.max_len, BLOCK_S) * triton.cdiv(output_dim, BLOCK_OUT), + 2, # this dimension decides current block computes on gate or up proj + batch_info.bs, + ) + + if base_output is None: + output = torch.zeros((s, 2 * output_dim), device=x.device, dtype=x.dtype) + else: + output = base_output + + _gate_up_lora_b_kernel[grid_b]( + x, + gate_up_lora_b, + output, + r, + output_dim, + x.stride(0), + x.stride(1), + gate_up_lora_b.stride(0), + gate_up_lora_b.stride(1), + gate_up_lora_b.stride(2), + output.stride(0), + output.stride(1), + batch_info.seg_lens, + batch_info.seg_indptr, + batch_info.weight_indices, + batch_info.lora_ranks, + BLOCK_S, + BLOCK_OUT, + BLOCK_R, + batch_info.scalings, + ) + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/qkv_lora_b.py b/sglang/python/sglang/srt/lora/triton_ops/qkv_lora_b.py new file mode 100644 index 0000000000000000000000000000000000000000..1d6663dbe0c0599d04f56e4937ab3582c46ce253 --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/qkv_lora_b.py @@ -0,0 +1,198 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo + + +@triton.jit +def _qkv_lora_b_kernel( + # Pointers to matrices + x, + weights, + output, + # Parameters of size + K, # K = R + max_qkv_out_dim, # max(output_q_dim, output_kv_dim) + # Strides + x_stride_0, + x_stride_1, + w_stride_0, + w_stride_1, + w_stride_2, + output_stride_0, + output_stride_1, + # Information on sequence lengths and weight id + seg_lens, + seg_indptr, + weight_indices, + lora_ranks, + # Offsets of q/k/v slice on output dimension + n_offs, + # Meta parameters + BLOCK_S: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, + # For fused output scaling + scalings, +): + """ + This kernel packs 3 sgemms (q/k/v) into a single kernel. The multiplication + results are accumulated into the output tensor. + + When a sequence's rank is 0, the kernel is essentially a no-op, following + the convention in pytorch where the product of two matrices of shape (m, 0) + and (0, n) is an all-zero matrix of shape (m, n). + + Args: + x (Tensor): The input tensor, which is the result of the LoRA A projection. + Shape: (s, 3 * K), where s is the sum of all sequence lengths in the + batch and K is the maximum LoRA rank. The second dimension is partitioned + for Q, K, and V. + weights (Tensor): The LoRA B weights for all adapters. + Shape: (num_lora, N_Q + 2 * N_KV, K). + output (Tensor): The output tensor where the result is stored. + Shape: (s, N_Q + 2 * N_KV). + """ + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len. + # qkv_id decides which of q,k,v to compute (0: q, 1: k, 2: v) + batch_id = tl.program_id(axis=2) + w_index = tl.load(weight_indices + batch_id) + rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel is a no-op. + if rank == 0: + return + + qkv_id = tl.program_id(axis=1) + pid = tl.program_id(axis=0) + seg_len = tl.load(seg_lens + batch_id) + seg_start = tl.load(seg_indptr + batch_id) + n_start = tl.load(n_offs + qkv_id) + n_size = tl.load(n_offs + qkv_id + 1) - n_start + scaling = tl.load(scalings + w_index) + # Adjust K (rank) according to the specific LoRA adapter + K = tl.minimum(K, rank) + + # The tile in output matrix will have (pid_s, pid_n) as id + num_pid_n = tl.cdiv(max_qkv_out_dim, BLOCK_N) + pid_s = pid // num_pid_n + pid_n = pid % num_pid_n + + # Create pointers for the first block of x and weights[batch_id][n_start: n_end][:] + # The pointers will be advanced as we move in the K direction + # and accumulate + s_offset = tl.arange(0, BLOCK_S) + pid_s * BLOCK_S + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + k_offset = tl.arange(0, BLOCK_K) + + x_ptrs = (x + seg_start * x_stride_0 + (qkv_id * K) * x_stride_1) + ( + s_offset[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1 + ) + w_ptrs = (weights + w_index * w_stride_0 + n_start * w_stride_1) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_S, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(K, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset[:, None] < seg_len) & (k_offset[None, :] < K - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < K - k * BLOCK_K) & (n_offset[None, :] < n_size), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum *= scaling + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = (output + seg_start * output_stride_0 + n_start * output_stride_1) + ( + s_offset[:, None] * output_stride_0 + n_offset[None, :] * output_stride_1 + ) + output_mask = (s_offset[:, None] < seg_len) & (n_offset[None, :] < n_size) + partial_sum += tl.load(output_ptr, mask=output_mask) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def qkv_lora_b_fwd( + x: torch.Tensor, + qkv_lora_b: torch.Tensor, + batch_info: LoRABatchInfo, + output_offset: torch.Tensor, + max_qkv_out_dim: int, + base_output: torch.Tensor = None, +) -> torch.Tensor: + + # x: (s, 3 * r) + # qkv_lora_b: (num_lora, output_dim_q + 2 * output_dim_kv, r) + # output_offset = [0, output_dim_q, output_dim_q + output_dim_kv, + # output_dim_q + 2 * output_dim_kv] + # max_qkv_out_dim = max(output_dim_q, output_dim_kv) + # output: (s, output_dim_q + 2 * output_dim_kv) + + # Compute lora_output with shape (s, output_dim) as follows: + # lora_output[:, :output_dim_q] = sgemm(x[:, :r], qkv_lora_b[:, :outptu_dim_q, :]) + # lora_output[:, output_dim_q: output_dim_q + output_dim_kv] + # = sgemm(x[:, r: 2 * r], qkv_lora_b[:, outptu_dim_q: output_dim_q + output_dim_kv, :]) + # lora_output[:, output_dim_q + output_dim_kv: ] + # = sgemm(x[:, 2 * r: , qkv_lora_b[:, output_dim_q + output_dim_kv: , :]) + + # Get dims + s = x.shape[0] + input_dim = x.shape[1] + r = qkv_lora_b.shape[-1] + output_dim = qkv_lora_b.shape[-2] + assert input_dim == 3 * r + assert output_offset.shape[0] == 4 + + BLOCK_S = 16 + BLOCK_R = 16 + BLOCK_OUT = 64 + + grid_b = ( + triton.cdiv(batch_info.max_len, BLOCK_S) + * triton.cdiv(max_qkv_out_dim, BLOCK_OUT), + 3, # this dimension decides current block computes on q, k or v + batch_info.bs, + ) + + if base_output is None: + output = torch.zeros((s, output_dim), device=x.device, dtype=x.dtype) + else: + output = base_output + + _qkv_lora_b_kernel[grid_b]( + x, + qkv_lora_b, + output, + r, + max_qkv_out_dim, + x.stride(0), + x.stride(1), + qkv_lora_b.stride(0), + qkv_lora_b.stride(1), + qkv_lora_b.stride(2), + output.stride(0), + output.stride(1), + batch_info.seg_lens, + batch_info.seg_indptr, + batch_info.weight_indices, + batch_info.lora_ranks, + output_offset, + BLOCK_S, + BLOCK_OUT, + BLOCK_R, + batch_info.scalings, + ) + + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_a.py b/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_a.py new file mode 100644 index 0000000000000000000000000000000000000000..dded64bcf079bf38603636d9ec5f32c3e6661b4c --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_a.py @@ -0,0 +1,170 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo + + +@triton.jit +def _sgemm_lora_a_kernel( + # Pointers to matrices + x, + weights, + output, + # Matrix dimensions + N, # stack_num * r + K, # input_dim + stack_num, + # Strides + x_stride_0, + x_stride_1, + w_stride_0, + w_stride_1, + w_stride_2, + output_stride_0, + output_stride_1, + # Information on sequence lengths,ranks and weight id + seg_lens, + seg_indptr, + weight_indices, + lora_ranks, + # Meta parameters + BLOCK_S: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, +): + """ + Computes a segmented batched matrix multiplication for the LoRA A matrix. + + The kernel ensures that output[seg_start:seg_start + seg_len, :rank * stack_num] + stores the product of the input `x` and the LoRA weights for the corresponding + sequence. This implies that when rank is 0, the kernel is essentially a no-op, + as output[seg_start:seg_start + seg_len, :0] is trivially correct (empty). + + Args: + x (torch.Tensor): The input activations tensor of shape `(s, K)`, where `s` + is the sum of all sequence lengths in the batch. + weights (torch.Tensor): The LoRA 'A' weights for all available adapters, + with shape `(num_lora, N, K)`. + output (torch.Tensor): The output tensor of shape `(s, N)`. + """ + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len + batch_id = tl.program_id(axis=1) + w_index = tl.load(weight_indices + batch_id) + rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel becomes a no-op as the output is always trivially correct. + if rank == 0: + return + + pid = tl.program_id(axis=0) + seg_start = tl.load(seg_indptr + batch_id) + seg_len = tl.load(seg_lens + batch_id) + + # Adjust N (stack_num * max_rank) according to the specific LoRA adapter + N = tl.minimum(N, rank * stack_num) + + # The tile in output matrix will have (pid_s, pid_n) as id + num_pid_n = tl.cdiv(N, BLOCK_N) + pid_s = pid // num_pid_n + pid_n = pid % num_pid_n + + # Create pointers for the first block of x and weights[batch_id] + # The pointers will be advanced as we move in the K direction + # and accumulate + s_offset = tl.arange(0, BLOCK_S) + pid_s * BLOCK_S + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + k_offset = tl.arange(0, BLOCK_K) + x_ptrs = (x + seg_start * x_stride_0) + ( + s_offset[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1 + ) + w_ptrs = (weights + w_index * w_stride_0) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_S, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(K, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset[:, None] < seg_len) & (k_offset[None, :] < K - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < K - k * BLOCK_K) & (n_offset[None, :] < N), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = (output + seg_start * output_stride_0) + ( + s_offset[:, None] * output_stride_0 + n_offset[None, :] * output_stride_1 + ) + output_mask = (s_offset[:, None] < seg_len) & (n_offset[None, :] < N) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def sgemm_lora_a_fwd( + x: torch.Tensor, + weights: torch.Tensor, + batch_info: LoRABatchInfo, + stack_num: int = 1, +) -> torch.Tensor: + # x: (s, input_dim) + # weights: (num_lora, stack_num * r, input_dim) + # output: (s, stack_num * r) + # stack_num: run_qkv_lora: 3, run_gate_up_lora: 2 + # when called by run_qkv_lora, the weights.shape[-2] will be 3 * r + # input_dim is much larger than r + + assert x.is_contiguous() + assert weights.is_contiguous() + assert len(x.shape) == 2 + assert len(weights.shape) == 3 + + S = x.shape[0] + R = weights.shape[-2] + K = weights.shape[-1] + assert x.shape[-1] == K + + # Block shapes + BLOCK_S = 16 + BLOCK_K = 256 + BLOCK_R = 16 + + grid = ( + triton.cdiv(batch_info.max_len, BLOCK_S) * triton.cdiv(R, BLOCK_R), + batch_info.bs, + ) + + output = torch.empty((S, R), device=x.device, dtype=x.dtype) + _sgemm_lora_a_kernel[grid]( + x, + weights, + output, + R, + K, + stack_num, + x.stride(0), + x.stride(1), + weights.stride(0), + weights.stride(1), + weights.stride(2), + output.stride(0), + output.stride(1), + batch_info.seg_lens, + batch_info.seg_indptr, + batch_info.weight_indices, + batch_info.lora_ranks, + BLOCK_S, + BLOCK_R, + BLOCK_K, + ) + return output diff --git a/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_b.py b/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_b.py new file mode 100644 index 0000000000000000000000000000000000000000..357d3280548cab582d96b69bdb3fd05e83b9a3f1 --- /dev/null +++ b/sglang/python/sglang/srt/lora/triton_ops/sgemm_lora_b.py @@ -0,0 +1,176 @@ +import torch +import triton +import triton.language as tl + +from sglang.srt.lora.utils import LoRABatchInfo + + +@triton.jit +def _sgemm_lora_b_kernel( + # Pointers to matrices + x, + weights, + output, + # Matrix dimensions + N, # output_dim + K, # r + # Strides + x_stride_0, + x_stride_1, + w_stride_0, + w_stride_1, + w_stride_2, + output_stride_0, + output_stride_1, + # Information on sequence lengths and weight id + seg_lens, + seg_indptr, + weight_indices, + lora_ranks, + # Meta parameters + BLOCK_S: tl.constexpr, + BLOCK_N: tl.constexpr, + BLOCK_K: tl.constexpr, + # For fused output scaling + scalings, +): + """ + Computes a segmented batched matrix multiplication for the LoRA B matrix + and adds the result to the output in-place. + + When a sequence's rank is 0, the kernel is essentially a no-op, following + the convention in pytorch where the product of two matrices of shape (m, 0) + and (0, n) is an all-zero matrix of shape (m, n). + + Args: + x (torch.Tensor): The intermediate tensor from the LoRA 'A' multiplication, + of shape `(s, K)`, where `s` is the total number of tokens. + weights (torch.Tensor): The LoRA 'B' weights for all available adapters, + with shape `(num_lora, N, K)`. + output (torch.Tensor): The output tensor of shape `(s, N)`. This can be + the base model's output for a fused add operation. + """ + + # Current block computes sequence with batch_id, + # which starts from row seg_start of x with length seg_len + batch_id = tl.program_id(axis=1) + w_index = tl.load(weight_indices + batch_id) + rank = tl.load(lora_ranks + w_index) + + # If rank is 0, this kernel is a no-op. + if rank == 0: + return + + pid = tl.program_id(axis=0) + seg_len = tl.load(seg_lens + batch_id) + seg_start = tl.load(seg_indptr + batch_id) + scaling = tl.load(scalings + w_index) + # Adjust K (rank) according to the specific LoRA adapter + K = tl.minimum(K, rank) + + # The tile in output matrix will have (pid_s, pid_n) as id + num_pid_n = tl.cdiv(N, BLOCK_N) + pid_s = pid // num_pid_n + pid_n = pid % num_pid_n + + # Create pointers for the first block of x and weights[batch_id] + # The pointers will be advanced as we move in the K direction + # and accumulate + s_offset = tl.arange(0, BLOCK_S) + pid_s * BLOCK_S + n_offset = tl.arange(0, BLOCK_N) + pid_n * BLOCK_N + k_offset = tl.arange(0, BLOCK_K) + x_ptrs = (x + seg_start * x_stride_0) + ( + s_offset[:, None] * x_stride_0 + k_offset[None, :] * x_stride_1 + ) + w_ptrs = (weights + w_index * w_stride_0) + ( + k_offset[:, None] * w_stride_2 + n_offset[None, :] * w_stride_1 + ) + + # Iterate to compute the block in output matrix + partial_sum = tl.zeros((BLOCK_S, BLOCK_N), dtype=tl.float32) + for k in range(0, tl.cdiv(K, BLOCK_K)): + x_tile = tl.load( + x_ptrs, + mask=(s_offset[:, None] < seg_len) & (k_offset[None, :] < K - k * BLOCK_K), + other=0.0, + ) + w_tile = tl.load( + w_ptrs, + mask=(k_offset[:, None] < K - k * BLOCK_K), + other=0.0, + ) + partial_sum += tl.dot(x_tile, w_tile) + + x_ptrs += BLOCK_K * x_stride_1 + w_ptrs += BLOCK_K * w_stride_2 + + # Store result to output matrix + partial_sum *= scaling + partial_sum = partial_sum.to(x.dtype.element_ty) + output_ptr = (output + seg_start * output_stride_0) + ( + s_offset[:, None] * output_stride_0 + n_offset[None, :] * output_stride_1 + ) + output_mask = s_offset[:, None] < seg_len + partial_sum += tl.load(output_ptr, mask=output_mask) + tl.store(output_ptr, partial_sum, mask=output_mask) + + +def sgemm_lora_b_fwd( + x: torch.Tensor, + weights: torch.Tensor, + batch_info: LoRABatchInfo, + base_output: torch.Tensor = None, +) -> torch.Tensor: + # x: (s, max_r) + # weights: (num_lora, output_dim, max_r) + # output: (s, output_dim) + # output_dim is much larger than max_r + + assert x.is_contiguous() + assert weights.is_contiguous() + assert len(x.shape) == 2 + assert len(weights.shape) == 3 + + S = x.shape[0] + N = weights.shape[-2] + R = weights.shape[-1] + assert x.shape[-1] == R + + # Block shapes + BLOCK_S = 16 + BLOCK_R = 16 + BLOCK_N = 256 + + grid = ( + triton.cdiv(batch_info.max_len, BLOCK_S) * triton.cdiv(N, BLOCK_N), + batch_info.bs, + ) + + if base_output is None: + output = torch.zeros((S, N), device=x.device, dtype=x.dtype) + else: + output = base_output + + _sgemm_lora_b_kernel[grid]( + x, + weights, + output, + N, + R, + x.stride(0), + x.stride(1), + weights.stride(0), + weights.stride(1), + weights.stride(2), + output.stride(0), + output.stride(1), + batch_info.seg_lens, + batch_info.seg_indptr, + batch_info.weight_indices, + batch_info.lora_ranks, + BLOCK_S, + BLOCK_N, + BLOCK_R, + batch_info.scalings, + ) + return output diff --git a/sglang/python/sglang/srt/managers/__pycache__/schedule_batch.cpython-311.pyc b/sglang/python/sglang/srt/managers/__pycache__/schedule_batch.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..703b794220532daa57c4658a47e56fea021eef01 --- /dev/null +++ b/sglang/python/sglang/srt/managers/__pycache__/schedule_batch.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e966ffb2b809b22a9134fafb97d73d0a542c2c19a951b7254bac1ee9abfd9fe4 +size 103041 diff --git a/sglang/python/sglang/srt/managers/__pycache__/scheduler.cpython-311.pyc b/sglang/python/sglang/srt/managers/__pycache__/scheduler.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..378fa582ec81abfd6d1b96bdeb5b05576bbc41a2 --- /dev/null +++ b/sglang/python/sglang/srt/managers/__pycache__/scheduler.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a7aebb3cb073b6f5713c18b23970c2c6c714a27a95ea71c24820bf7201fad133 +size 140115 diff --git a/sglang/python/sglang/srt/managers/__pycache__/tokenizer_manager.cpython-311.pyc b/sglang/python/sglang/srt/managers/__pycache__/tokenizer_manager.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eacbd4fa72f37cec4e5d31a5af85fea814465731 --- /dev/null +++ b/sglang/python/sglang/srt/managers/__pycache__/tokenizer_manager.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:53aa688fc1cdc2181dea6df6c0a8f2d7cd5d70ceabaad5112d247e4927761e48 +size 118287 diff --git a/sglang/python/sglang/srt/mem_cache/__pycache__/memory_pool.cpython-311.pyc b/sglang/python/sglang/srt/mem_cache/__pycache__/memory_pool.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6462cdd44e0a2b39a4578a66bfcd2f367a0f2c1 --- /dev/null +++ b/sglang/python/sglang/srt/mem_cache/__pycache__/memory_pool.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b83741b7a7a51ef5179a45a4a892c40dbe78dcf5f63374e357ad8c8cc7866af +size 100675 diff --git a/sglang/python/sglang/srt/model_executor/__pycache__/model_runner.cpython-311.pyc b/sglang/python/sglang/srt/model_executor/__pycache__/model_runner.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8588c1002cc541e5f5b2b02cfd8e02f6b98e3fb --- /dev/null +++ b/sglang/python/sglang/srt/model_executor/__pycache__/model_runner.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cd0b6b9d0617d0b5bbc07519a904c894ca099b3bbb534b6939041effdb85291f +size 122198 diff --git a/sglang/python/sglang/srt/model_loader/__pycache__/loader.cpython-311.pyc b/sglang/python/sglang/srt/model_loader/__pycache__/loader.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..959f3d909acd14027679fe8feaf9e8b0a66005d5 --- /dev/null +++ b/sglang/python/sglang/srt/model_loader/__pycache__/loader.cpython-311.pyc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6a9de37d8215bf224fd2ec3ab41766c4d47a928e2ee86bfc735346f4ad3b2704 +size 123524 diff --git a/sglang/python/sglang/srt/multimodal/__pycache__/customized_mm_processor_utils.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/__pycache__/customized_mm_processor_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..54a82333963c348e87d0d5aac01a6eecb279e27c Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/__pycache__/customized_mm_processor_utils.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/__pycache__/internvl_utils.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/__pycache__/internvl_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..84fe9c5c9c29f84b5f6968d38adf1559d3edb977 Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/__pycache__/internvl_utils.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/__pycache__/internvl_vit_cuda_graph_runner.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/__pycache__/internvl_vit_cuda_graph_runner.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be367dd3f76fbf24a6375828d2c6fd6f3145f9e2 Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/__pycache__/internvl_vit_cuda_graph_runner.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/__pycache__/mm_utils.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/__pycache__/mm_utils.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3732804b9866e8ea494855fc72cfc3535b88deda Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/__pycache__/mm_utils.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/evs/README.md b/sglang/python/sglang/srt/multimodal/evs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..3bbf879966b3decb56f7cff6de328829dbeacc08 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/evs/README.md @@ -0,0 +1,123 @@ +# Efficient Video Sampling (EVS) + +Implementation of [Efficient Video Sampling: Pruning Temporally Redundant Tokens for Faster VLM Inference](https://arxiv.org/abs/2510.14624). + +## Overview + +> NOTE: The current implementation in sglang is cannot work with VLMs that use positional embeddings [Such as Qwen2.5VL]. Further work is warranted. + +Video frames often contain redundant information, as consecutive frames may be nearly identical. EVS exploits this in the latent space [=embedding space] by computing similarity between adjacent frame token embeddings and pruning tokens that are highly similar to the previous frames. This reduces the token count while preserving informative content. + +Key properties: +- The first frame is always fully retained (provides complete initial context) +- Configurable via `video_pruning_rate` in model config.json (0 = disabled, 0.7 = ~70% reduction; ~30% retained.) + + +## Performance Characteristics VS. Accuracy - Example + +> NOTE: Actual retained accuracy post-EVS may depend on how dynamic the input videos are, how high the pruning rate is, whether or not the model was trained with EVS on or not, etc. +> To learn more, read the paper above. It is incumbent on the user to evaluate as per their use case and benchmarks. + +A cursory example of a performance boost due to EVS: + +```bash +export SGLANG_VLM_CACHE_SIZE_MB=0 +sglang serve --model-path nvidia/Nemotron-Nano-12B-v2-VL-BF16 --trust-remote-code --mem-fraction-static 0.8 --max-mamba-cache-size 128 --chunked-prefill-size 8192 +``` +Example Request: +```json +{ "model": "nvidia/Nemotron-Nano-12B-v2-VL-BF16", "stream": true, "temperature": 0.0, "max_completion_tokens": 3, "messages": [{ "role": "user", "content": [{ "type": "video_url", "video_url": { "url": "file:///tmp/01.mp4" } }]}]} +``` + +- `1XH100 95GiB` +- `BS=1` +- All 30 videos of `https://huggingface.co/datasets/lmms-lab/Video-MME/blob/main/videos_chunked_01.zip` +- Default [for this model] pruning rate of `--json-model-override-args '{"video_pruning_rate": 0.7}'` [i.e., 30% of tokens are preserved] VS. `--json-model-override-args '{"video_pruning_rate": 0.0}'` [EVS off] + +| Scenario\ Metric | Online TTFT (Seconds) stderr: ±0.38 | VideoMME Accuracy | +|--------------------------------- |------------------------------------- |------------------------- | +| EVS Off [q=0.0] | 11.96 [100%] | Between 0.665 and 0.668 | +| EVS Off [q=0.4] | 09.97 [ 83%] | | +| EVS On [q=0.7] (default value) | 08.79 [ 73%] | | +| EVS Off [q=0.9] | 08.39 [ 70%] | 0.644 | + + +## Architecture + +### Request Flow + +1. Prompt Construction (EVSProcessor) + * Calculates estimated tokens per frame based on pruning rate, so the emitted input_ids tensor's length will by definition match the final sequence length post pruning. This is necessary for 3. +2. Embedding Generation (EVS) + * Calls original model `get_video_feature()` for full embeddings + * Retains top-k dissimilar tokens + * Returns EVSEmbeddingResult in addition to pruned token counts *per frame* +3. Token Redistribution (mm_utils) + * Adjusts input_ids so each frame's placeholder tokens matches the pruned count from 2. + + +## Integration Guide + +### Step 1: Model [See `NemotronH_Nano_VL_V2`] + +Make your model inherit from `EVS` and implement `create_evs_config`: + +```python +from sglang.srt.multimodal.evs import EVSConfig, EVS + +class MyEVSVideoModel(EVS): + @staticmethod + def create_evs_config(config): + return EVSConfig( + video_pruning_rate=config.video_pruning_rate + ) + + def __init__(self, config, ...): + super().__init__(config) # EVS wraps get_video_feature + ... + + def get_video_feature(self, items): + # Your existing implementation + # Returns: (total_frames, tokens_per_frame, hidden_dim) + ... +``` + +### Step 2: Processor [See `NanoNemotronVLImageProcessor`] + +Create an `EVSProcessor` as a member of your VLImageProcessor: + +```python +from sglang.srt.multimodal.evs import EVSProcessor + +class MyProcessor: + models = [MyEVSVideoModel, MyNonEVSModel] # You may mix evs and non evs models in a processor + + def __init__(hf_config): + self.evs = EVSProcessor(hf_config, config_to_evs_model={MyEVSVideoModelConfig: MyEVSVideoModel}) + + def process_video(self, ...): + for video in videos: + tokens_per_frame = self.tokens_per_frame() + mm_items = create_data_items( + image=image_feature, + image_offsets=img_offsets, + video=video_feature, + video_offsets=video_offsets, + ) +``` + +### Step 3: Config [See `NemotronH_Nano_VL_V2_Config`] + +Add `video_pruning_rate` to your model config: + +```python +class MyModelConfig(PretrainedConfig): + def __init__(self, ..., video_pruning_rate=0.0, ...): + self.video_pruning_rate = video_pruning_rate +``` + +## Files + +- `evs_core.py`: Core algorithms (retention mask computation, token redistribution) +- `evs_module.py`: EVS, configs) +- `evs_processor.py`: EVSProcessor diff --git a/sglang/python/sglang/srt/multimodal/evs/__init__.py b/sglang/python/sglang/srt/multimodal/evs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bb6462bd1ff5f4aa5c72ba80a2df413f8ed9e8e3 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/evs/__init__.py @@ -0,0 +1,11 @@ +"""https://arxiv.org/abs/2510.14624: Efficient Video Sampling: Pruning Temporally Redundant Tokens for Faster VLM Inference""" + +from .evs_module import EVS, EVSConfig, EVSEmbeddingResult +from .evs_processor import EVSProcessor + +__all__ = [ + "EVS", + "EVSConfig", + "EVSEmbeddingResult", + "EVSProcessor", +] diff --git a/sglang/python/sglang/srt/multimodal/evs/__pycache__/__init__.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/evs/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4673d3e009715a0f2e21d85a456cbfd66c4e93e4 Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/evs/__pycache__/__init__.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/evs/__pycache__/evs_core.cpython-311.pyc b/sglang/python/sglang/srt/multimodal/evs/__pycache__/evs_core.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..93c21150e01ea04a5377d1c749249ef8eb49baaa Binary files /dev/null and b/sglang/python/sglang/srt/multimodal/evs/__pycache__/evs_core.cpython-311.pyc differ diff --git a/sglang/python/sglang/srt/multimodal/evs/evs_core.py b/sglang/python/sglang/srt/multimodal/evs/evs_core.py new file mode 100644 index 0000000000000000000000000000000000000000..6ab53362b623b2e97b14ca1840f417a926cd6914 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/evs/evs_core.py @@ -0,0 +1,176 @@ +# Copyright 2025 SGLang Team +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Adapted from https://github.com/vllm-project/vllm/blob/main/vllm/multimodal/evs.py + +import torch + + +def compute_retained_tokens_count( + tokens_per_frame: int, num_frames: int, q: float +) -> int: + """ + Compute the number of retained tokens for a given video. + Method ensures that we retain all the tokens from the first frame + regardless of the pruning rate. + + Args: + tokens_per_frame: The number of tokens per frame. + num_frames: The total number of frames. + q: The pruning rate. + + Returns: + The number of retained tokens. + """ + total_tokens = tokens_per_frame * num_frames + evs_num_tokens = int(total_tokens * (1 - q)) + min_num_tokens = tokens_per_frame + return max(min_num_tokens, evs_num_tokens) + + +def compute_retention_mask( + video_embeds: torch.Tensor, + video_size_thw: torch.LongTensor | tuple[int, int, int], + spatial_merge_size: int, + q: float, +) -> torch.Tensor: + """ + Computes the retention mask for input video embeddings. + + Args: + video_embeds (`torch.Tensor`): The input video embeddings + of shape `(T * H * W // spatial_merge_size ^ 2, hidden_size)` + video_size_thw (`torch.LongTensor` of shape `(3)`): + The temporal, height and width of video. + spatial_merge_size: Size reduction for rows & cols dimensions. + q: (`float`): Pruning rate factor [0,1) + + Returns: + `torch.Tensor`: The retention mask for the video embeddings of + `(T * H * W // spatial_merge_size ^ 2)` shape. + """ + T, H, W = map(int, video_size_thw) + + # Use reshape instead of einops to avoid graph breaks + video_embeds = video_embeds.reshape( + T, + H // spatial_merge_size, + W // spatial_merge_size, + video_embeds.size(-1), + ) + tokens_per_frame = (H // spatial_merge_size) * (W // spatial_merge_size) + # Core EVS + similarity = torch.nn.functional.cosine_similarity( + video_embeds[1:, ...], video_embeds[:-1, ...], dim=-1 + ) + dissimilarity = 1 - similarity + + # Always ensure we include all tokens from the first frame + dissimilarity = torch.cat( + [255 * torch.ones_like(video_embeds[:1, :, :, 0]), dissimilarity], dim=0 + ) + + dissimilarity_flat = dissimilarity.view(-1) + order = torch.argsort(dissimilarity_flat, dim=-1, descending=True, stable=True) + retain_num_tokens = compute_retained_tokens_count( + tokens_per_frame=tokens_per_frame, num_frames=T, q=q + ) + topk_indices = order[:retain_num_tokens] + + retention_mask = torch.zeros_like(dissimilarity_flat, dtype=torch.bool) + retention_mask[topk_indices] = True + retention_mask = retention_mask.reshape(dissimilarity.size()) + + mask = retention_mask.view(-1) # "T H W -> (T H W)" + return mask + + +# ▲ End of VLLM code + + +def tokens_per_frame( + *, + q: float, + num_frames: int, + frame_num_tokens: int, +) -> list[int]: + """ + Before EVS pruning, we want to pre-reduce input_ids to be the same length that will be retained of embeddings due to EVS pruning, so the forward batch metadata will be correct post EVS. + We don't know the exact number of tokens per frame after EVS pruning, but we know the *total* number of tokens that will be retained. + So, we create a bogus tokens_per_frame list that sums to the total number of tokens that will be retained, and use it for placeholder spans, later to replaced, see `replace_offsets_with_tokens_per_frame` below. + """ + retained = compute_retained_tokens_count( + tokens_per_frame=frame_num_tokens, num_frames=num_frames, q=q + ) + base = retained // num_frames + rem = retained % num_frames + tpf = [base] * (num_frames - 1) + [base + rem] + assert sum(tpf) == retained + return tpf + + +def replace_offsets_with_tokens_per_frame( + *, + pre_chunked_input_ids: list[int], + num_tokens_per_frame: list[int], + frame_offsets_inclusive: list[tuple[int, int]], + filler_token_id: int, +) -> list[int]: + """ + Given a single video, after EVS pruning of redundant tokens, we have a new `num_tokens_per_frame`, therefore the existing input_ids and offsets are stale. + We need to replace all stale offsets with new offsets that reflect the new `num_tokens_per_frame`, respectively. + + Returns: + Modified input_ids with offsets replaced with new offsets. + + Examples: + >>> assert replace_offsets_with_tokens_per_frame( + ... pre_chunked_input_ids=[1, 0, 0, 4, 5, 0, 0, 0, 9, 10, 0, 0, 12, 13], + ... frame_offsets_inclusive=[(1, 2), (5, 7), (10, 11)], + ... num_tokens_per_frame=[1, 4, 2], + ... filler_token_id=0, + ... ) == [1, 0, 4, 5, 0, 0, 0, 0, 9, 10, 0, 0, 12, 13] + + >>> assert replace_offsets_with_tokens_per_frame( + ... pre_chunked_input_ids=[1, 0, 0, 4, 5, 9, 10, 0, 0, 0], + ... frame_offsets_inclusive=[(1, 2), (7, 9)], + ... num_tokens_per_frame=[1, 4], + ... filler_token_id=0, + ... ) == [1, 0, 4, 5, 9, 10, 0, 0, 0, 0] + + >>> assert replace_offsets_with_tokens_per_frame( + ... pre_chunked_input_ids=[0, 0, 1, 4, 0, 0, 0, 5, 9, 10], + ... frame_offsets_inclusive=[(0, 1), (4, 6)], + ... num_tokens_per_frame=[1, 4], + ... filler_token_id=0, + ... ) == [0, 1, 4, 0, 0, 0, 0, 5, 9, 10] + """ + assert isinstance(pre_chunked_input_ids, list) + ids = pre_chunked_input_ids + + if len(frame_offsets_inclusive) == 1: + """There might be no frame separators, in which case there will be one contiguous span of tokens""" + final = ids[0 : frame_offsets_inclusive[0][0]] + frames = [filler_token_id] * sum(num_tokens_per_frame) + final.extend(frames) + else: + cursor = 0 + final = [] + for (start, end), num_tokens in zip( + frame_offsets_inclusive, num_tokens_per_frame, strict=True + ): + final.extend(ids[cursor:start]) + final.extend([filler_token_id] * num_tokens) + cursor = end + 1 + final.extend(ids[frame_offsets_inclusive[-1][1] + 1 :]) + return final diff --git a/sglang/python/sglang/srt/multimodal/evs/evs_processor.py b/sglang/python/sglang/srt/multimodal/evs/evs_processor.py new file mode 100644 index 0000000000000000000000000000000000000000..251f17bca63c894b6b4761a0531305e3a3b26f1e --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/evs/evs_processor.py @@ -0,0 +1,132 @@ +# Copyright 2025 SGLang Team +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + + +import torch +from transformers import PretrainedConfig + +from sglang.srt.managers.schedule_batch import Modality, MultimodalDataItem +from sglang.utils import logger + +from .evs_core import tokens_per_frame +from .evs_module import EVS, EVSConfig, EVSDataItem, VideoEVSDataItem + + +def _non_evs_data_items( + *, + image: torch.Tensor | None, + image_offsets: list[tuple[int, int]], + video: torch.Tensor | None, + video_offsets: list[tuple[int, int]], + input_ids_list: list[int], +): + items: list[MultimodalDataItem] = [] + if image is not None: + item = MultimodalDataItem( + modality=Modality.IMAGE, feature=image, offsets=image_offsets + ) + items.append(item) + if video is not None: + item = MultimodalDataItem( + modality=Modality.VIDEO, feature=video, offsets=video_offsets + ) + items.append(item) + return items + + +class EVSProcessor: + """ + This processor handles prompt construction with the correct number of + placeholder tokens per frame. When EVS is active, it allocates fewer + placeholders based on the pruning rate. When inactive, it uses the full + token count. + """ + + def __init__( + self, + hf_config: PretrainedConfig, + config_to_evs_model: dict[type[PretrainedConfig], type[EVS]], + ): + assert len(config_to_evs_model) > 0 + assert all(issubclass(model, EVS) for model in config_to_evs_model.values()) + + self.evs_config: EVSConfig | None = None + + config_name = hf_config.__class__.__name__ + evs_model = config_to_evs_model.get(hf_config.__class__) + if evs_model is None: + logger.info( + f"[EVS] no model matches {config_name} in {config_to_evs_model}" + ) + return + evs_config = evs_model.create_evs_config(hf_config) + logger.info( + f"""[EVS] {evs_config} {'enabled' if evs_config.video_pruning_rate > 0.0 else 'disabled'} for model={evs_model.__name__}; model_config={config_name}""" + ) + if evs_config.video_pruning_rate > 0.0: + self.evs_config = evs_config + + def static_size_data_items( + self, *, frames_per_video: list[int], num_images: int, rows: int, cols: int + ): + """helper function to create data items for models with static image and video tokens per frame""" + + frame_num_tokens = rows * cols + + if self.evs_config is None: + tpf = [[frame_num_tokens] * num_frames for num_frames in frames_per_video] + return _non_evs_data_items, tpf + + def create_evs_data_items( + *, + input_ids_list: list[int], + image: torch.Tensor | None, + image_offsets: list[tuple[int, int]], + video: torch.Tensor | None, + video_offsets: list[tuple[int, int]], + ) -> list[MultimodalDataItem]: + items = [] + if image is not None: + image_thw_grids = [(1, rows, cols)] * num_images + item = EVSDataItem( + modality=Modality.IMAGE, + feature=image, + offsets=image_offsets, + thw_grids=image_thw_grids, + ) + items.append(item) + if video is not None: + video_thw_grids = [ + (num_frames, rows, cols) for num_frames in frames_per_video + ] + item = VideoEVSDataItem( + modality=Modality.VIDEO, + feature=video, + offsets=video_offsets, + thw_grids=video_thw_grids, + pre_chunked_input_ids=input_ids_list, + ) + items.append(item) + return items + + tpf = [ + tokens_per_frame( + q=self.evs_config.video_pruning_rate, + num_frames=num_frames, + frame_num_tokens=frame_num_tokens, + ) + for num_frames in frames_per_video + ] + + return create_evs_data_items, tpf diff --git a/sglang/python/sglang/srt/multimodal/processors/base_processor.py b/sglang/python/sglang/srt/multimodal/processors/base_processor.py new file mode 100644 index 0000000000000000000000000000000000000000..22adf71e2946d7bfb91ba34150050517b02c256b --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/base_processor.py @@ -0,0 +1,1121 @@ +import concurrent +import concurrent.futures +import dataclasses +import multiprocessing as mp +import os +import re +from abc import ABC, abstractmethod +from typing import Any, Dict, Iterator, List, Optional, Tuple, Union + +import numpy as np +import torch +from PIL import Image +from transformers import BaseImageProcessorFast + +from sglang.srt.managers.schedule_batch import ( + Modality, + MultimodalDataItem, + MultimodalInputFormat, +) +from sglang.srt.server_args import get_global_server_args +from sglang.srt.utils import ( + envs, + is_cpu, + is_npu, + is_xpu, + load_audio, + load_image, + load_video, + logger, +) +from sglang.srt.utils.cuda_ipc_transport_utils import ( + MM_FEATURE_CACHE_SIZE, + MM_ITEM_MEMORY_POOL_RECYCLE_INTERVAL, + CudaIpcTensorTransportProxy, + MmItemMemoryPool, +) + +_is_cpu = is_cpu() +_is_npu = is_npu() +_is_xpu = is_xpu() + +SGL_USE_CUDA_IPC = envs.SGLANG_USE_CUDA_IPC_TRANSPORT.get() + + +@dataclasses.dataclass +class BaseMultiModalProcessorOutput: + # input_text with all multimodality placeholder token expanded + input_text: str + + # frames loaded from image, in given order + images: Optional[list[Union[Image.Image, dict]]] = dataclasses.field( + default_factory=list + ) + + # videos + videos: Optional[list[Union[torch.Tensor, dict]]] = dataclasses.field( + default_factory=list + ) + + # audios + audios: Optional[list[Union[np.ndarray, dict]]] = dataclasses.field( + default_factory=list + ) + + def organize_results(self) -> List[Tuple[Modality, Any]]: + """ + + :return: a list of results, with their corresponding modalities + """ + return ( + [(Modality.IMAGE, data) for data in self.images] + + [(Modality.VIDEO, data) for data in self.videos] + + [(Modality.AUDIO, data) for data in self.audios] + ) + + +@dataclasses.dataclass +class MultimodalSpecialTokens: + image_token: Optional[Union[str, List[str]]] = None + video_token: Optional[Union[str, List[str]]] = None + audio_token: Optional[Union[str, List[str]]] = None + + image_token_id: Optional[int] = None + video_token_id: Optional[int] = None + audio_token_id: Optional[int] = None + + image_token_regex: Optional[re.Pattern] = None + video_token_regex: Optional[re.Pattern] = None + audio_token_regex: Optional[re.Pattern] = None + + combined_regex: Optional[re.Pattern] = None + + def build(self, processor): + self.convert_to_strs(processor) + self.parse_regex() + self.get_combined_regex() + return self + + def convert_to_str(self, token: Union[str, int], processor) -> str: + if token is None: + return token + if isinstance(token, str): + return token + return processor.tokenizer.convert_ids_to_tokens([token])[0] + + def convert_to_strs(self, processor): + if not self.image_token: + self.image_token = self.convert_to_str(self.image_token_id, processor) + if not self.video_token: + self.video_token = self.convert_to_str(self.video_token_id, processor) + if not self.audio_token: + self.audio_token = self.convert_to_str(self.audio_token_id, processor) + + def get_modality_of_token(self, token: str) -> Optional[Modality]: + """ + :return: the modality associated with the given token, if the token is a special_token or matches with the multimodal token regex + """ + modality = { + self.image_token: Modality.IMAGE, + self.video_token: Modality.VIDEO, + self.audio_token: Modality.AUDIO, + }.get(token) + if modality: + return modality + + for regex, modality in [ + (self.image_token_regex, Modality.IMAGE), + (self.video_token_regex, Modality.VIDEO), + (self.audio_token_regex, Modality.AUDIO), + ]: + if regex and regex.match(token): + return modality + + return None + + def get_token_id_by_modality(self, modality: Modality) -> Optional[int]: + return { + Modality.IMAGE: self.image_token_id, + Modality.MULTI_IMAGES: self.image_token_id, + Modality.VIDEO: self.video_token_id, + Modality.AUDIO: self.audio_token_id, + }.get(modality) + + def parse_regex(self): + if self.image_token_regex is None and self.image_token is not None: + self.image_token_regex = re.compile(re.escape(self.image_token)) + if self.video_token_regex is None and self.video_token is not None: + self.video_token_regex = re.compile(re.escape(self.video_token)) + if self.audio_token_regex is None and self.audio_token is not None: + self.audio_token_regex = re.compile(re.escape(self.audio_token)) + + def get_combined_regex(self) -> re.Pattern: + """ + Builds and returns a regex, used to split input str into tokens (with mm special tokens) + """ + if self.combined_regex: + return self.combined_regex + tokens = [ + self.image_token_regex, + self.video_token_regex, + self.audio_token_regex, + ] + patterns = [] + flags = 0 + for t in tokens: + if t is not None: + patterns.append(t.pattern) + flags |= t.flags + combined = "(" + "|".join(f"(?:{p})" for p in patterns) + ")" + self.combined_regex = re.compile(combined, flags) + return self.combined_regex + + +class BaseMultimodalProcessor(ABC): + models = [] + + def __init__( + self, hf_config, server_args, _processor, transport_mode, *args, **kwargs + ): + self.hf_config = hf_config + self._processor = _processor + self.server_args = server_args + self.transport_mode = transport_mode + + # Resolve tokenizer: some processors (e.g. InternVL) pass a tokenizer + # directly as _processor rather than a processor that wraps a tokenizer. + if hasattr(self._processor, "tokenizer"): + self._tokenizer = self._processor.tokenizer + else: + self._tokenizer = self._processor + + # FIXME: not accurate, model and image specific + self.NUM_TOKEN_PER_FRAME = 330 + + self.io_executor = concurrent.futures.ThreadPoolExecutor( + max_workers=int(os.environ.get("SGLANG_IO_WORKERS", 4)) + ) + self.cpu_executor = concurrent.futures.ProcessPoolExecutor( + mp_context=mp.get_context("fork"), + max_workers=int(os.environ.get("SGLANG_CPU_WORKERS", os.cpu_count())), + ) + + # Mapping from attribute names to modality types + self.ATTR_NAME_TO_MODALITY = { + # Image-related attributes + "pixel_values": Modality.IMAGE, + "image_sizes": Modality.IMAGE, + "image_grid_thw": Modality.IMAGE, + "image_attention_mask": Modality.IMAGE, + "image_emb_mask": Modality.IMAGE, + "images_spatial_crop": Modality.IMAGE, + "images_crop": Modality.IMAGE, + "tgt_size": Modality.IMAGE, + "image_grid_hws": Modality.IMAGE, + "aspect_ratio_ids": Modality.IMAGE, + "aspect_ratio_mask": Modality.IMAGE, + "num_patches": Modality.IMAGE, + "patch_pixel_values": Modality.IMAGE, + "block_sizes": Modality.IMAGE, + "grid_thws": Modality.IMAGE, # for kimi k2.5 + # Audio-related attributes + "audio_features": Modality.AUDIO, + "audio_feature_lens": Modality.AUDIO, + "input_features": Modality.AUDIO, + "input_features_mask": Modality.AUDIO, + "audio_attention_mask": Modality.AUDIO, + "feature_attention_mask": Modality.AUDIO, + # Video-related attributes + "pixel_values_videos": Modality.VIDEO, + "second_per_grid_ts": Modality.VIDEO, + "video_grid_thw": Modality.VIDEO, + # Generic attributes that could apply to multiple modalities + # "precomputed_embeddings" - handled specially as it can be any modality + } + + # name of the feature filed + # TODO: pass from processors + self.FEATURE_NAMES = [ + "pixel_values", + "pixel_values_videos", + "audio_features", + "input_features", + ] + + skip_mm_pool = kwargs.get("skip_mm_pool", False) + + if SGL_USE_CUDA_IPC and not skip_mm_pool: + self.cudaipc_mmfeature_pool = MmItemMemoryPool( + MM_FEATURE_CACHE_SIZE, + MM_ITEM_MEMORY_POOL_RECYCLE_INTERVAL, + ) + + @property + def spatial_merge_size(self): + return self.hf_config.vision_config.spatial_merge_size + + def build_input_ids(self, prompt, img_grid_thw): + """ + Use prompt and img_grid_thw to build input_ids + """ + if not isinstance(prompt, list): + prompt = self._tokenizer.encode(prompt) + + img_token_id = self.IM_TOKEN_ID + spatial_merge_size = self.spatial_merge_size + + input_ids = [] + offsets = [] + + cur_idx = 0 + + # Use img_token_id instead of im_start_id, because a dummy im_start_id + # may be generated by the tokenizer. + img_start_indices = list( + filter(lambda i: prompt[i + 1] == img_token_id, range(len(prompt) - 1)) + ) + + for cur_img_idx, img_start_idx in enumerate(img_start_indices): + assert cur_idx <= img_start_idx + # include img_start_id + input_ids.extend(prompt[cur_idx : img_start_idx + 1]) + img_offset_start = len(input_ids) + img_token_num = img_grid_thw[cur_img_idx].prod() // (spatial_merge_size**2) + input_ids.extend([img_token_id] * img_token_num) + # jump to img_end_id + cur_idx = img_start_idx + 2 + offsets.append((img_offset_start, len(input_ids) - 1)) + else: + input_ids.extend(prompt[cur_idx:]) + + return input_ids, offsets + + def get_mm_data(self, prompt, embeddings, img_grid_thw): + input_ids, offsets = self.build_input_ids(prompt, img_grid_thw) + mm_items = [ + MultimodalDataItem( + modality=Modality.IMAGE, + offsets=offsets, + precomputed_embeddings=embeddings, + ) + ] + + return { + "input_ids": input_ids, + "mm_items": mm_items, + "im_start_id": self.IM_START_TOKEN_ID, + "im_end_id": self.IM_END_TOKEN_ID, + "im_token_id": self.IM_TOKEN_ID, + } + + def process_mm_data( + self, input_text, images=None, videos=None, audios=None, **kwargs + ) -> dict: + """ + process multimodal data with transformers AutoProcessor + """ + if images: + kwargs["images"] = images + if videos: + kwargs["videos"] = videos + if audios: + if self._processor.__class__.__name__ in { + "Gemma3nProcessor", + "GlmAsrProcessor", + "Qwen2AudioProcessor", + "Qwen3OmniMoeProcessor", + }: + # Note(Xinyuan): for gemma3n, ref: https://github.com/huggingface/transformers/blob/ccf2ca162e33f381e454cdb74bf4b41a51ab976d/src/transformers/models/gemma3n/processing_gemma3n.py#L107 + kwargs["audio"] = audios + kwargs["audio_kwargs"] = {} + kwargs["audio_kwargs"].setdefault("truncation", False) + else: + kwargs["audios"] = audios + + processor = self._processor + if ( + hasattr(processor, "image_processor") + and isinstance(processor.image_processor, BaseImageProcessorFast) + and not self.server_args.disable_fast_image_processor + ): + if _is_cpu or get_global_server_args().rl_on_policy_target is not None: + kwargs["device"] = "cpu" + elif _is_xpu: + kwargs["device"] = "xpu" + elif not _is_npu: + kwargs["device"] = "cuda" + elif processor.__class__.__name__ not in { + "Qwen2_5_VLProcessor", + "Qwen3VLProcessor", + }: + # Note: for qwen-vl, processor has some reshape issue because of dims restriction on Ascend. + kwargs["device"] = "npu" + + result = processor.__call__( + text=[input_text], + padding=True, + return_tensors="pt", + **kwargs, + ) + if not self.server_args.keep_mm_feature_on_device: + # move feature tensors to cpu + for feature_name in self.FEATURE_NAMES: + if SGL_USE_CUDA_IPC: + pass + else: + if feature_name in result and isinstance( + result[feature_name], torch.Tensor + ): + result[feature_name] = result[feature_name].to("cpu") + + return result + + @abstractmethod + async def process_mm_data_async( + self, + image_data, + audio_data, + input_text, + request_obj, + **kwargs, + ) -> Optional[Dict[str, Any]]: + pass + + def get_estimated_frames_list(self, image_data): + """ + estimate the total frame count from all visual input + """ + # Lazy import because decord is not available on some arm platforms. + from decord import VideoReader, cpu + + # Before processing inputs + if not image_data or len(image_data) == 0: + return [] + estimated_frames_list = [] + for image in image_data: + if isinstance(image, str) and image.startswith("video:"): + path = image[len("video:") :] + # Estimate frames for the video + vr = VideoReader(path, ctx=cpu(0)) + num_frames = len(vr) + else: + # For images, each contributes one frame + num_frames = 1 + estimated_frames_list.append(num_frames) + + return estimated_frames_list + + @staticmethod + def _load_single_item( + data, + modality: Modality, + frame_count_limit=None, + audio_sample_rate: Optional[int] = None, + discard_alpha_channel=True, + ): + """ + Load a single multimodal data. + + If data is processor_output or precomputed embedding, return directly. + + Static method that can be pickled for multiprocessing""" + if isinstance(data, dict): + data_format = data.get("format") + if data_format in ( + MultimodalInputFormat.PROCESSOR_OUTPUT.name, + MultimodalInputFormat.PRECOMPUTED_EMBEDDING.name, + "processor_output", + "precomputed_embedding", + ): + return data + try: + if modality == Modality.IMAGE: + img, _ = load_image(data) + if discard_alpha_channel and img.mode != "RGB": + img = img.convert("RGB") + return img + elif modality == Modality.VIDEO: + return load_video(data, frame_count_limit) + elif modality == Modality.AUDIO: + return load_audio(data, audio_sample_rate) + + except Exception as e: + raise RuntimeError(f"Error while loading data {data}: {e}") + + def _submit_mm_data_loading_tasks_simple( + self, + data_list: Optional[list], + modality: Modality, + audio_sample_rate: Optional[int], + discard_alpha_channel: bool, + ) -> List[Tuple[Modality, int, concurrent.futures.Future]]: + """ + Simple version: For one modal data submit IO load task. + Return: + List[(modality, index_in_that_modality, future)] + """ + futures: List[Tuple[Modality, int, concurrent.futures.Future]] = [] + + if not data_list: + logger.debug( + "[_submit_mm_data_loading_tasks_simple] no data for modality=%s", + modality.name, + ) + return futures + + for idx, data in enumerate(data_list): + logger.debug( + "[_submit_mm_data_loading_tasks_simple] submit load task: " + "modality=%s, index=%d, data_type=%s", + modality.name, + idx, + type(data), + ) + future = self.io_executor.submit( + BaseMultimodalProcessor._load_single_item, + data, + modality, + None, # frame_count_limit: no consider for fast path + audio_sample_rate, + discard_alpha_channel, + ) + futures.append((modality, idx, future)) + + return futures + + def submit_data_loading_tasks( + self, + text_parts: List[str], + multimodal_tokens: MultimodalSpecialTokens, + data_iterators: dict[Modality, Iterator[Any]], + discard_alpha_channel: bool = True, + image_estimated_frames_iter: Optional[iter] = None, + image_scaling_factor: float = 1.0, + max_image_frames: int = 30, + audio_sample_rate: Optional[int] = None, + ) -> Tuple[List, List]: + """ + load multimodal data parallelly using iterators. + """ + futures = [] + task_info = [] + + for text_part in text_parts: + modality = multimodal_tokens.get_modality_of_token(text_part) + if modality is not None: + data_iterator = data_iterators.get(modality) + if data_iterator is None: + raise ValueError(f"No data iterator found for token: {text_part}") + + try: + data = next(data_iterator) + except StopIteration: + logger.warning( + f"Mismatch: More '{modality.name}' tokens found than corresponding data provided." + ) + return futures, task_info + + frame_count_limit = None + if modality == Modality.IMAGE and image_estimated_frames_iter: + try: + estimated_frames = next(image_estimated_frames_iter) + # Use the pre-calculated scaling factor and max frames + frame_count_limit = max( + 1, int(estimated_frames * image_scaling_factor) + ) + # Ensure we don't exceed the absolute max (redundant if scaling_factor handles it) + # frame_count_limit = min(frame_count_limit, max_image_frames) + except StopIteration: + raise ValueError( + "Mismatch between image tokens and estimated frame counts." + ) + + futures.append( + self.io_executor.submit( + BaseMultimodalProcessor._load_single_item, + data, + modality, + frame_count_limit, + audio_sample_rate, + discard_alpha_channel, + ) + ) + task_info.append((modality, data, frame_count_limit)) + + for modality, iterator in data_iterators.items(): + try: + next(iterator) + logger.warning( + f"Warning: More {modality.name.lower()} data items provided than corresponding tokens found in the prompt." + ) + except StopIteration: + pass + except Exception: + pass + + return futures, task_info + + @staticmethod + def _validate_one_modality(modality: Modality, data_list: Optional[list]): + if data_list is None: + return + if not isinstance(data_list, list): + raise TypeError( + f"{modality.name} must be a list or None, got {type(data_list)}" + ) + + formatted_indices = [] + for idx, item in enumerate(data_list): + if isinstance(item, dict): + fmt = item.get("format") + if fmt in {"processor_output", "precomputed_embedding"}: + formatted_indices.append(idx) + + if formatted_indices: + if len(data_list) != 1: + raise ValueError( + f"For {modality}, when providing a 'processor_output' or " + f"'precomputed_embedding', you must pass exactly one item; " + f"received {len(data_list)} items (formatted at indices {formatted_indices})." + ) + + @staticmethod + def validate_mm_data( + image_data: Optional[list] = None, + video_data: Optional[list] = None, + audio_data: Optional[list] = None, + ): + """ + Validate multimodal input lists per modality. + + Rule per modality (image/video/audio): + - Either the list has exactly one item and that single item is a dict with + format in {"processor_output", "precomputed_embedding"}; + - Or, the list contains only "normal" items (i.e., does not include any + item whose format is one of the two above). + + Empty or None lists are considered valid. + """ + + BaseMultimodalProcessor._validate_one_modality(Modality.IMAGE, image_data) + BaseMultimodalProcessor._validate_one_modality(Modality.VIDEO, video_data) + BaseMultimodalProcessor._validate_one_modality(Modality.AUDIO, audio_data) + + def _process_loaded_mm_data(self, modality, raw_data, result): + images, videos, audios = [], [], [] + + is_precomputed = isinstance(raw_data, dict) and raw_data.get("format") in [ + MultimodalInputFormat.PROCESSOR_OUTPUT.name, + MultimodalInputFormat.PRECOMPUTED_EMBEDDING.name, + "processor_output", + "precomputed_embedding", + ] + + if modality == Modality.IMAGE: + if is_precomputed: + images.append(result) + else: + if isinstance(result, list): + images.extend(result) + else: + images.append(result) + elif modality == Modality.VIDEO: + videos.append(result) + elif modality == Modality.AUDIO: + audios.append(result) + + return is_precomputed, images, videos, audios + + def load_mm_data( + self, + prompt: str, + multimodal_tokens: MultimodalSpecialTokens, + image_data: Optional[list] = None, + video_data: Optional[list] = None, + audio_data: Optional[list] = None, + return_text: Optional[bool] = True, + discard_alpha_channel: bool = True, + audio_sample_rate: Optional[int] = None, + ) -> BaseMultiModalProcessorOutput: + + BaseMultimodalProcessor.validate_mm_data(image_data, video_data, audio_data) + + multimodal_tokens_pattern = multimodal_tokens.get_combined_regex() + if isinstance(prompt, list) and return_text: + assert len(prompt) and isinstance(prompt[0], int) + prompt = self._tokenizer.decode(prompt) + else: + prompt = prompt + + assert isinstance(prompt, str) + # split text into list of normal text and special tokens + text_parts = re.split(multimodal_tokens_pattern, prompt) + + cnt = {Modality.IMAGE: 0, Modality.VIDEO: 0, Modality.AUDIO: 0} + for text_part in text_parts: + modality = multimodal_tokens.get_modality_of_token(text_part) + if modality is not None: + cnt[modality] += 1 + + n_image = len(image_data) if image_data else 0 + n_video = len(video_data) if video_data else 0 + n_audio = len(audio_data) if audio_data else 0 + + # For MiniCPMO and MiniCPMV or multimodal_tokens not totally align, legacy show path + if ( + self.server_args.skip_tokenizer_init + or cnt[Modality.IMAGE] != n_image + or cnt[Modality.VIDEO] != n_video + or cnt[Modality.AUDIO] != n_audio + or getattr(self, "support_dynamic_frame_expansion", False) + ): + return self.legacy_load_mm_data( + prompt=prompt, + multimodal_tokens=multimodal_tokens, + image_data=image_data, + video_data=video_data, + audio_data=audio_data, + return_text=return_text, + discard_alpha_channel=discard_alpha_channel, + audio_sample_rate=audio_sample_rate, + ) + # For models other than MiniCPMO and MiniCPMV, + # totally align multimodal_tokens, fast path + return self.fast_load_mm_data( + prompt=prompt, + multimodal_tokens=multimodal_tokens, + image_data=image_data, + video_data=video_data, + audio_data=audio_data, + return_text=return_text, + discard_alpha_channel=discard_alpha_channel, + audio_sample_rate=audio_sample_rate, + ) + + def fast_load_mm_data( + self, + prompt: str, + multimodal_tokens: MultimodalSpecialTokens, + image_data: Optional[list] = None, + video_data: Optional[list] = None, + audio_data: Optional[list] = None, + return_text: Optional[bool] = True, + discard_alpha_channel: bool = True, + audio_sample_rate: Optional[int] = None, + ) -> BaseMultiModalProcessorOutput: + """ + A fast version of `load_mm_data` that loads multimodal data directly. + This version does not scan the prompt to recognize tokens. It assumes + that the caller has already aligned the tokens and data in a 1:1 manner. + The behavior is as follows: + 1. It runs `_load_single_item` for all input data concurrently. + 2. It returns the loaded images, videos, and audios in their original order. + 3. It returns the input prompt as a string. + """ + + # Convert prompt into str + if isinstance(prompt, list) and return_text: + assert len(prompt) and isinstance(prompt[0], int) + prompt_str = self._tokenizer.decode(prompt) + else: + assert isinstance(prompt, str) + prompt_str = prompt + + futures: List[Tuple[Modality, int, concurrent.futures.Future]] = [] + + modalities_data = [ + (image_data, Modality.IMAGE), + (video_data, Modality.VIDEO), + (audio_data, Modality.AUDIO), + ] + + for data_list, modality in modalities_data: + futures.extend( + self._submit_mm_data_loading_tasks_simple( + data_list, modality, audio_sample_rate, discard_alpha_channel + ) + ) + + logger.debug("[load_mm_data(simple)] total futures submitted: %d", len(futures)) + + images: List[Any] = [None] * len(image_data) if image_data else [] + videos: List[Any] = [None] * len(video_data) if video_data else [] + audios: List[Any] = [None] * len(audio_data) if audio_data else [] + + for modality, idx, future in futures: + try: + result = future.result() + except Exception as e: + logger.exception( + "[load_mm_data(simple)] error loading %s data at index=%d", + modality.name, + idx, + ) + raise RuntimeError( + f"An exception occurred while loading {modality.name} data at index {idx}: {e}" + ) + + if modality == Modality.IMAGE: + images[idx] = result + elif modality == Modality.VIDEO: + videos[idx] = result + elif modality == Modality.AUDIO: + audios[idx] = result + + logger.debug( + "[load_mm_data(simple)] loaded counts: images=%d, videos=%d, audios=%d", + len(images), + len(videos), + len(audios), + ) + + return BaseMultiModalProcessorOutput( + images=images, + audios=audios, + videos=videos, + input_text=prompt_str, + ) + + def legacy_load_mm_data( + self, + prompt: str, + multimodal_tokens: MultimodalSpecialTokens, + image_data: Optional[list] = None, + video_data: Optional[list] = None, + audio_data: Optional[list] = None, + return_text: Optional[bool] = True, + discard_alpha_channel: bool = True, + audio_sample_rate: Optional[int] = None, + ) -> BaseMultiModalProcessorOutput: + """ + Each frame of video/image will be replaced by a single image token + + Args: + multimodal_tokens (list[str]): list of special token which denoting a single multimodal data + e.g. image token or audio token + discard_alpha_channel: if True, discards the alpha channel in the returned images + + """ + + multimodal_tokens_pattern = multimodal_tokens.get_combined_regex() + if isinstance(prompt, list) and return_text: + assert len(prompt) and isinstance(prompt[0], int) + prompt = self._tokenizer.decode(prompt) + else: + prompt = prompt + + assert isinstance(prompt, str) + # split text into list of normal text and special tokens + text_parts = re.split(multimodal_tokens_pattern, prompt) + # collect all data + data_iterators = {} + if multimodal_tokens.image_token and image_data: + data_iterators[Modality.IMAGE] = iter(image_data) + if multimodal_tokens.video_token and video_data: + data_iterators[Modality.VIDEO] = iter(video_data) + if multimodal_tokens.audio_token and audio_data: + data_iterators[Modality.AUDIO] = iter(audio_data) + + # futures: the futures of loaded data + # task_info: modality, raw_data, and other metadata of each data + futures, task_info = self.submit_data_loading_tasks( + text_parts=text_parts, + multimodal_tokens=multimodal_tokens, + data_iterators=data_iterators, + discard_alpha_channel=discard_alpha_channel, + audio_sample_rate=audio_sample_rate, + ) + task_info_iter = iter(task_info) + futures_iter = iter(futures) + + # Process results + images, videos, audios = [], [], [] + new_text_parts = [] + has_precomputed_input = False + for text_part in text_parts: + try: + if multimodal_tokens_pattern.match(text_part): + modality, raw_data, frame_limit = next(task_info_iter) + result = next(futures_iter).result() + + is_precomputed, new_imgs, new_vids, new_auds = ( + self._process_loaded_mm_data(modality, raw_data, result) + ) + + has_precomputed_input |= is_precomputed + images.extend(new_imgs) + videos.extend(new_vids) + audios.extend(new_auds) + + if modality == Modality.IMAGE: + if is_precomputed: + new_text_parts += [text_part] + else: + count = len(new_imgs) + if count > 0: + new_text_parts += [ + multimodal_tokens.image_token + ] * count + elif modality == Modality.VIDEO: + # load as video + mm_tokens = ( + text_part + if is_precomputed + else multimodal_tokens.video_token + ) + new_text_parts += mm_tokens + elif modality == Modality.AUDIO: + # audio + mm_tokens = ( + text_part + if is_precomputed + else multimodal_tokens.audio_token + ) + new_text_parts += mm_tokens + else: + # normal text + new_text_parts += [text_part] + + except StopIteration as e: + # when precomputed_input is presented with multi-images, StopIteration is expected + if has_precomputed_input: + new_text_parts += [text_part] + continue + raise RuntimeError( + f"An exception occurred while loading multimodal data: {e}" + ) + except Exception as e: + raise RuntimeError( + f"An exception occurred while loading multimodal data: {e}" + ) + return BaseMultiModalProcessorOutput( + images=images, + audios=audios, + videos=videos, + input_text="".join(new_text_parts), + ) + + @staticmethod + def get_mm_items_offset( + input_ids: torch.Tensor, mm_token_id: int + ) -> List[Tuple[int, int]]: + """ + Get a set of range for mm_items from input_ids + Example: + input_ids = [1, 2, 3, 3, 3, 4, 3, 3] + mm_token_id = 3 + return result = [(2,4),(6,7)] + """ + mask = input_ids == mm_token_id + start_positions = (mask & ~torch.roll(mask, 1)).nonzero(as_tuple=True)[0] + end_positions = (mask & ~torch.roll(mask, -1)).nonzero(as_tuple=True)[0] + return list(zip(start_positions.tolist(), end_positions.tolist())) + + @staticmethod + def get_mm_items_offset_by_pair( + input_ids: torch.Tensor, mm_start_id: int, mm_end_id: int + ) -> List[Tuple[int, int]]: + indices_start = (input_ids == mm_start_id).nonzero(as_tuple=True)[0] + 1 + indices_end = (input_ids == mm_end_id).nonzero(as_tuple=True)[0] - 1 + + return list(zip(indices_start.tolist(), indices_end.tolist())) + + def collect_mm_items_from_processor_output( + self, data_dict: dict, modality: Modality = None + ) -> List[MultimodalDataItem]: + """ + Create mm_items directly from processor output, with one item for each modality + + Note that the data_dict can be passed via offline engine api + """ + + items: dict[Modality, MultimodalDataItem] = {} + for attr_name, value in data_dict.items(): + if attr_name == "input_ids": + continue + + # Get modality for this attribute + current_modality = modality or self.ATTR_NAME_TO_MODALITY.get(attr_name) + + if attr_name == "precomputed_embeddings": + modality_str = data_dict.get("modality") + current_modality = Modality.IMAGE + if modality_str: + try: + current_modality = Modality.from_str(modality_str) + except ValueError: + pass + + if current_modality: + # Create item if needed + if current_modality not in items: + items[current_modality] = MultimodalDataItem( + modality=current_modality + ) + + if attr_name in self.FEATURE_NAMES: + attr_name = "feature" + + items[current_modality].set(attr_name, value) + + return list(items.values()) + + def _process_and_collect_mm_items( + self, input_text: str, images=None, audios=None, videos=None, **kwargs + ) -> Tuple[List[MultimodalDataItem], torch.Tensor, dict]: + """ + Helper method to process multimodal data and create mm_items in one step. + + Returns: + Tuple of (created mm_items, input_ids) + """ + ret = self.process_mm_data( + input_text=input_text, images=images, audios=audios, videos=videos, **kwargs + ) + + input_ids = ret["input_ids"].flatten() + collected_items = self.collect_mm_items_from_processor_output(ret) + + return collected_items, input_ids, ret + + def process_and_combine_mm_data( + self, + base_output: BaseMultiModalProcessorOutput, + mm_tokens: MultimodalSpecialTokens, + **kwargs, + ) -> Tuple[List[MultimodalDataItem], torch.Tensor, dict]: + """ + Process multimodal data and return the combined multimodal items and input_ids. + Supports mixed modalities (images and audio in the same request). + + Returns: + Tuple of (list of mm_items, input_ids) + """ + # Collect all items and categorize them + all_loaded_data = base_output.organize_results() + # Handle text-only case + if not all_loaded_data: + input_ids = self._tokenizer( + base_output.input_text, + return_tensors="pt", + add_special_tokens=True, + ).input_ids.flatten() + return [], input_ids, {} + + dict_items, raw_images, raw_audios, raw_videos = [], [], [], [] + for modality, item in all_loaded_data: + if isinstance(item, dict): + dict_items.append((modality, item)) + elif modality == Modality.IMAGE: + raw_images.append(item) + elif modality == Modality.AUDIO: + raw_audios.append(item) + elif modality == Modality.VIDEO: + raw_videos.append(item) + else: + raise ValueError(f"Unknown multimodal item type: {type(item)}") + # Process items and get input_ids + all_collected_items: list[MultimodalDataItem] = [] + input_ids = None + # Handle raw items (need processing) + if raw_images or raw_audios or raw_videos: + collected_items, input_ids, ret = self._process_and_collect_mm_items( + input_text=base_output.input_text, + images=raw_images, + audios=raw_audios, + videos=raw_videos, + **kwargs, + ) + all_collected_items = collected_items + else: + ret = None + + # Handle dict items (processed or precomputed) + for modality, dict_item in dict_items: + input_format = dict_item.get("format", None) + if input_format == "processor_output": + items = self.collect_mm_items_from_processor_output(dict_item) + for item in items: + item.format = MultimodalInputFormat.PROCESSOR_OUTPUT + all_collected_items.extend(items) + elif input_format == "precomputed_embedding": + feature = dict_item["feature"] + del dict_item["feature"] + all_collected_items.append( + MultimodalDataItem( + modality=modality, + feature=feature, + format=MultimodalInputFormat.PRECOMPUTED_EMBEDDING, + model_specific_data=dict_item, + ) + ) + # Fallback tokenization if no raw items were processed + if input_ids is None: + input_ids = self._tokenizer( + base_output.input_text, + return_tensors="pt", + add_special_tokens=True, + ).input_ids.flatten() + + # Add offsets to all items + for mm_item in all_collected_items: + mm_token_id = mm_tokens.get_token_id_by_modality(mm_item.modality) + if mm_token_id is None: + raise ValueError(f"No token id found for modality: {mm_item.modality}") + mm_item.offsets = self.get_mm_items_offset( + input_ids=input_ids, + mm_token_id=mm_token_id, + ) + + """ + solution for cuda-ipc memory-leak: + 1. memory-pool: each time get a slice from memory-pool and use it as transport-data (with async lock guard) + 2. if can not get a slice , transport normal tensor + 3. copy tensor in scheduler and release it (use position mark) + 4. copy + """ + + if SGL_USE_CUDA_IPC: + # post-process + for item in all_collected_items: + if isinstance(item.feature, torch.Tensor) and item.feature.is_cuda: + sync_flag, available_slice = ( + self.cudaipc_mmfeature_pool.return_a_slice_tensor_with_flag( + item.feature + ) + ) + if isinstance(available_slice, torch.Tensor): + available_slice.copy_( + item.feature.view(torch.int8).view(-1), non_blocking=True + ) + item.feature = CudaIpcTensorTransportProxy( + data=available_slice, + info_data=item.feature, + sync_buffer_meta=sync_flag, + ) + elif not self.server_args.keep_mm_feature_on_device: + item.feature = item.feature.cpu() + elif ( + isinstance(item.precomputed_embeddings, torch.Tensor) + and item.precomputed_embeddings.is_cuda + ): + + sync_flag, available_slice = ( + self.cudaipc_mmfeature_pool.return_a_slice_tensor_with_flag( + item.precomputed_embeddings + ) + ) + if isinstance(available_slice, torch.Tensor): + available_slice.copy_( + item.precomputed_embeddings.view(torch.int8).view(-1), + non_blocking=True, + ) + item.precomputed_embeddings = CudaIpcTensorTransportProxy( + data=available_slice, + info_data=item.precomputed_embeddings, + sync_buffer_meta=sync_flag, + ) + elif not self.server_args.keep_mm_feature_on_device: + item.precomputed_embeddings = item.precomputed_embeddings.cpu() + + return all_collected_items, input_ids, ret diff --git a/sglang/python/sglang/srt/multimodal/processors/clip.py b/sglang/python/sglang/srt/multimodal/processors/clip.py new file mode 100644 index 0000000000000000000000000000000000000000..19ff71e784174130994741ef4718c6f22e6330d1 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/clip.py @@ -0,0 +1,35 @@ +from typing import List, Union + +from sglang.srt.models.clip import CLIPModel +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + MultimodalSpecialTokens, +) + + +class ClipImageProcessor(BaseMultimodalProcessor): + models = [CLIPModel] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.mm_tokens = MultimodalSpecialTokens(image_token="").build( + _processor + ) + + async def process_mm_data_async( + self, image_data: List[Union[str, bytes]], input_text, *args, **kwargs + ): + base_output = self.load_mm_data( + prompt=input_text, + multimodal_tokens=self.mm_tokens, + image_data=image_data, + ) + + mm_items, input_ids, _ = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + + return { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/deepseek_ocr.py b/sglang/python/sglang/srt/multimodal/processors/deepseek_ocr.py new file mode 100644 index 0000000000000000000000000000000000000000..9b9002d8d36a27a34172be5f3dbdc255572ce645 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/deepseek_ocr.py @@ -0,0 +1,45 @@ +from typing import List, Union + +from sglang.srt.models.deepseek_ocr import DeepseekOCRForCausalLM +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + MultimodalSpecialTokens, +) + + +class DeepseekOCRProcessor(BaseMultimodalProcessor): + models = [DeepseekOCRForCausalLM] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + _processor.image_size = 640 + _processor.ocr2_mode = ( + str( + getattr(getattr(hf_config, "vision_config", None), "model_name", "") + ).lower() + == "deepencoderv2" + or getattr(getattr(hf_config, "projector_config", None), "input_dim", None) + == 896 + ) + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.mm_tokens = MultimodalSpecialTokens( + image_token="", image_token_id=self._processor.image_token_id + ).build(_processor) + + async def process_mm_data_async( + self, image_data: List[Union[str, bytes]], input_text, *args, **kwargs + ): + base_output = self.load_mm_data( + prompt=input_text, + multimodal_tokens=self.mm_tokens, + image_data=image_data, + ) + + mm_items, input_ids, _ = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + + return { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + "im_token_id": self.mm_tokens.image_token_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/deepseek_vl_v2.py b/sglang/python/sglang/srt/multimodal/processors/deepseek_vl_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..26708e8dc01aa7109687357d14bde581a8d5e10b --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/deepseek_vl_v2.py @@ -0,0 +1,62 @@ +# Copyright (c) 2023-2024 DeepSeek. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +from typing import List, Union + +from sglang.srt.models.deepseek_vl2 import DeepseekVL2ForCausalLM +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + MultimodalSpecialTokens, +) + + +class DeepseekVL2ImageProcessor(BaseMultimodalProcessor): + models = [DeepseekVL2ForCausalLM] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.mm_tokens = MultimodalSpecialTokens( + image_token="", image_token_id=self._processor.image_token_id + ).build(_processor) + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes]], + input_text, + request_obj, + max_req_input_len, + *args, + **kwargs + ): + base_output = self.load_mm_data( + input_text, + image_data=image_data, + multimodal_tokens=self.mm_tokens, + ) + mm_items, input_ids, _ = self.process_and_combine_mm_data( + base_output, + self.mm_tokens, + max_req_input_len=max_req_input_len, + conversations=base_output.input_text, + ) + + return { + "mm_items": mm_items, + "input_ids": input_ids.tolist(), + "im_token_id": self._processor.image_token_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/dots_vlm.py b/sglang/python/sglang/srt/multimodal/processors/dots_vlm.py new file mode 100644 index 0000000000000000000000000000000000000000..8d6faf5e8748ac75f4d56d521188ea87c71f2967 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/dots_vlm.py @@ -0,0 +1,81 @@ +import re +from typing import Dict, List, Union + +from sglang.srt.models.dots_ocr import DotsOCRForCausalLM +from sglang.srt.models.dots_vlm import DotsVLMForCausalLM +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + MultimodalSpecialTokens, +) + + +class DotsVLMImageProcessor(BaseMultimodalProcessor): + models = [DotsVLMForCausalLM, DotsOCRForCausalLM] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + # The single, pre-expanded image token. + self.IMAGE_TOKEN = "<|img|><|imgpad|><|endofimg|>" + # The regex that matches expanded image tokens. + self.IMAGE_TOKEN_REGEX = re.compile(r"<\|img\|>(?:<\|imgpad\|>)+<\|endofimg\|>") + + assert len(_processor.tokenizer.encode("<|img|>")) == 1 + self.im_start_id = _processor.tokenizer.encode("<|img|>")[0] + self.im_end_id = _processor.tokenizer.encode("<|endofimg|>")[0] + self.image_token_id = _processor.tokenizer.encode("<|imgpad|>")[0] + self.IM_TOKEN_ID = self.image_token_id + self.IM_START_TOKEN_ID = self.im_start_id + self.IM_END_TOKEN_ID = self.im_end_id + + vision_config = hf_config.vision_config + patch_size = vision_config.patch_size + merge_size = vision_config.spatial_merge_size + + self.IMAGE_FACTOR = patch_size * merge_size + self.MIN_PIXELS = _processor.image_processor.min_pixels + self.MAX_PIXELS = _processor.image_processor.max_pixels + self.MAX_RATIO = 200 + self.mm_tokens = MultimodalSpecialTokens( + image_token=self.IMAGE_TOKEN, + image_token_id=self.image_token_id, + image_token_regex=self.IMAGE_TOKEN_REGEX, + ).build(_processor) + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes, Dict]], + input_text, + request_obj, + max_req_input_len, + *args, + **kwargs, + ): + if isinstance(image_data, str): + image_data = [image_data] + + if ( + isinstance(image_data, list) + and image_data + and isinstance(image_data[0], list) + ): + image_data = sum(image_data, []) + + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + multimodal_tokens=self.mm_tokens, + ) + + combined_mm_item, input_ids, _ = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + if combined_mm_item is None: + return None + + return { + "input_ids": input_ids.tolist(), + "mm_items": combined_mm_item, + "im_start_id": self.im_start_id, + "im_end_id": self.im_end_id, + "im_token_id": self.image_token_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/ernie45_vl.py b/sglang/python/sglang/srt/multimodal/processors/ernie45_vl.py new file mode 100644 index 0000000000000000000000000000000000000000..8b3633c59a5242cc90ddcbccb98ee70dc1ad1ef2 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/ernie45_vl.py @@ -0,0 +1,419 @@ +import math +import os +from typing import List, Union + +import numpy as np +import torch +import torchvision +from PIL import Image +from torchvision.transforms import InterpolationMode +from transformers import BaseImageProcessorFast + +from sglang.srt.environ import envs +from sglang.srt.layers.rotary_embedding import MRotaryEmbedding +from sglang.srt.models.ernie45_vl import Ernie4_5_VLMoeForConditionalGeneration +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor as SGLangBaseProcessor, +) +from sglang.srt.multimodal.processors.base_processor import ( + MultimodalSpecialTokens, +) +from sglang.srt.utils import get_bool_env_var, is_npu, logger + +_is_npu = is_npu() + +SGL_USE_CUDA_IPC = get_bool_env_var("SGLANG_USE_CUDA_IPC_TRANSPORT") + + +IMAGE_FACTOR = 28 +MIN_PIXELS = 4 * 28 * 28 +# MAX_PIXELS = envs.SGLANG_IMAGE_MAX_PIXELS.get() +MAX_PIXELS = 16384 * 28 * 28 +MAX_RATIO = 200 +RESIZE_RESAMPLE = getattr(Image, envs.SGLANG_RESIZE_RESAMPLE.get(), None) +if envs.SGLANG_RESIZE_RESAMPLE.is_set() and RESIZE_RESAMPLE is None: + logger.warning( + f"Invalid RESIZE_RESAMPLE value: '{envs.SGLANG_RESIZE_RESAMPLE.get()}'. " + f"Ignoring and using default." + ) +VIDEO_TOTAL_PIXELS = int( + float(os.environ.get("VIDEO_MAX_PIXELS", 128000 * 28 * 28 * 0.9)) +) + +VIDEO_MIN_PIXELS = 299 * 28 * 28 +VIDEO_MAX_PIXELS = 1196 * 28 * 28 +FRAME_FACTOR = 2 +FPS = 2.0 +FPS_MIN_FRAMES = 16 +FPS_MAX_FRAMES = 180 + + +def smart_resize( + height: int, + width: int, + factor: int = IMAGE_FACTOR, + min_pixels: int = MIN_PIXELS, + max_pixels: int = MAX_PIXELS, +): + if max(height, width) / min(height, width) > MAX_RATIO: + if height > width: + new_width = max(factor, round_by_factor(width, factor)) + new_height = floor_by_factor(new_width * MAX_RATIO, factor) + else: + new_height = max(factor, round_by_factor(height, factor)) + new_width = floor_by_factor(new_height * MAX_RATIO, factor) + + height = new_height + width = new_width + + h_bar = max(factor, round_by_factor(height, factor)) + w_bar = max(factor, round_by_factor(width, factor)) + if h_bar * w_bar > max_pixels: + beta = math.sqrt((height * width) / max_pixels) + h_bar = floor_by_factor(height / beta, factor) + w_bar = floor_by_factor(width / beta, factor) + elif h_bar * w_bar < min_pixels: + beta = math.sqrt(min_pixels / (height * width)) + h_bar = ceil_by_factor(height * beta, factor) + w_bar = ceil_by_factor(width * beta, factor) + + if min_pixels > h_bar * w_bar or h_bar * w_bar > max_pixels: + raise ValueError(f"encounter invalid h_bar: {h_bar}, w_bar: {w_bar}") + + return h_bar, w_bar + + +def resize_image( + image, + min_pixels: int = MIN_PIXELS, + max_pixels: int = MAX_PIXELS, + size_factor: int = IMAGE_FACTOR, +) -> Image.Image: + width, height = image.size + min_pixels = min_pixels + max_pixels = max_pixels + resized_height, resized_width = smart_resize( + height, + width, + factor=size_factor, + min_pixels=min_pixels, + max_pixels=max_pixels, + ) + image = image.resize((resized_width, resized_height), resample=RESIZE_RESAMPLE) + return image + + +def round_by_factor(number: int | float, factor: int) -> int: + return round(number / factor) * factor + + +def ceil_by_factor(number: int | float, factor: int) -> int: + return math.ceil(number / factor) * factor + + +def floor_by_factor(number: int | float, factor: int) -> int: + return math.floor(number / factor) * factor + + +async def resize_image_async( + image, + min_pixels: int = MIN_PIXELS, + max_pixels: int = MAX_PIXELS, + size_factor: int = IMAGE_FACTOR, +): + return resize_image(image, min_pixels, max_pixels, size_factor) + + +def smart_nframes( + ele: dict, + total_frames: int, + video_fps: int | float, +) -> int: + """calculate the number of frames for video used for model inputs. + + Args: + ele (dict): a dict contains the configuration of video. + support either `fps` or `nframes`: + - nframes: the number of frames to extract for model inputs. + - fps: the fps to extract frames for model inputs. + - min_frames: the minimum number of frames of the video, only used when fps is provided. + - max_frames: the maximum number of frames of the video, only used when fps is provided. + total_frames (int): the original total number of frames of the video. + video_fps (int | float): the original fps of the video. + + Raises: + ValueError: nframes should in interval [FRAME_FACTOR, total_frames]. + + Returns: + int: the number of frames for video used for model inputs. + """ + assert not ( + "fps" in ele and "nframes" in ele + ), "Only accept either `fps` or `nframes`" + if "nframes" in ele: + nframes = round_by_factor(ele["nframes"], FRAME_FACTOR) + else: + fps = ele.get("fps", FPS) + min_frames = ceil_by_factor(ele.get("min_frames", FPS_MIN_FRAMES), FRAME_FACTOR) + max_frames = floor_by_factor( + ele.get("max_frames", min(FPS_MAX_FRAMES, total_frames)), FRAME_FACTOR + ) + nframes = total_frames / video_fps * fps + if nframes > total_frames: + logger.warning( + f"smart_nframes: nframes[{nframes}] > total_frames[{total_frames}]" + ) + nframes = min(min(max(nframes, min_frames), max_frames), total_frames) + nframes = floor_by_factor(nframes, FRAME_FACTOR) + if not (FRAME_FACTOR <= nframes and nframes <= total_frames): + raise ValueError( + f"nframes should in interval [{FRAME_FACTOR}, {total_frames}], but got {nframes}." + ) + return nframes + + +# process video, qwen-specific +async def preprocess_video( + vr, + image_factor: int = IMAGE_FACTOR, +) -> torch.Tensor: + + total_frames, video_fps = len(vr), vr.get_avg_fps() + nframes = smart_nframes({}, total_frames=total_frames, video_fps=video_fps) + idx = np.linspace(0, total_frames - 1, num=nframes, dtype=np.int64) + idx = np.unique(idx) + video_np = vr.get_batch(idx).asnumpy() + video = torch.from_numpy(video_np).pin_memory() + video = video.permute(0, 3, 1, 2) # Convert to TCHW format + nframes, _, height, width = video.shape + min_pixels = VIDEO_MIN_PIXELS + total_pixels = VIDEO_TOTAL_PIXELS + max_pixels = max( + min(VIDEO_MAX_PIXELS, total_pixels / nframes * FRAME_FACTOR), + int(min_pixels * 1.05), + ) + + resized_height, resized_width = smart_resize( + height, + width, + factor=image_factor, + min_pixels=min_pixels, + max_pixels=max_pixels, + ) + video = torchvision.transforms.functional.resize( + video, + [resized_height, resized_width], + interpolation=InterpolationMode.BILINEAR, + ) + + video = video.permute(0, 2, 3, 1) + video = video.pin_memory() + video_metadata = { + "fps": video_fps, + "duration": total_frames / video_fps, + "total_num_frames": total_frames, + "frames_indices": idx, + "video_backend": "torchvision", + } + + return video, video_metadata + + +# Compatible with Ernie-VL Series +class Ernie4_5_VLImageProcessor(SGLangBaseProcessor): + models = [Ernie4_5_VLMoeForConditionalGeneration] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.hf_config = hf_config + self.model_type = hf_config.model_type + self.image_start_token_id = hf_config.image_start_token_id + self.image_end_token_id = hf_config.image_end_token_id + self.video_start_token_id = hf_config.video_start_token_id + self.video_end_token_id = hf_config.video_end_token_id + + self.IMAGE_FACTOR = 28 + self.MIN_PIXELS = 4 * 28 * 28 + self.MAX_PIXELS = 16384 * 28 * 28 + self.MAX_RATIO = 200 + self.mm_tokens = MultimodalSpecialTokens( + image_token="<|IMAGE_START|><|image@placeholder|><|IMAGE_END|>", + video_token="<|VIDEO_START|><|video@placeholder|><|VIDEO_END|>", + image_token_id=hf_config.im_patch_id, + video_token_id=hf_config.im_patch_id, # image and video use the same token_id + ).build(_processor) + + self.tokenizer = self._processor.tokenizer + self.image_processor = self._processor.image_processor + + def _pixel_values_norm( + self, + pixel_values: torch.Tensor, + mm_kwargs: object, + ) -> torch.Tensor: + hf_config = self.hf_config + vision_config = hf_config.vision_config + image_processor = self.image_processor + image_mean_tensor = torch.tensor( + image_processor.image_mean, dtype=torch.float32 + ).reshape([1, 3, 1, 1]) + image_std_tensor = torch.tensor( + image_processor.image_std, dtype=torch.float32 + ).reshape([1, 3, 1, 1]) + rescale_factor = torch.tensor( + image_processor.rescale_factor, dtype=torch.float32 + ) + patch_size_squared = vision_config.patch_size**2 + + image_mean_tensor = image_mean_tensor.squeeze([-2, -1]).repeat_interleave( + patch_size_squared, -1 + ) + image_std_tensor = image_std_tensor.squeeze([-2, -1]).repeat_interleave( + patch_size_squared, -1 + ) + + if not image_mean_tensor.is_contiguous(): + image_mean_tensor = image_mean_tensor.contiguous() + if not image_std_tensor.is_contiguous(): + image_std_tensor = image_std_tensor.contiguous() + + pixel_values = ( + rescale_factor * pixel_values.to(torch.float32) - image_mean_tensor + ) / image_std_tensor + pixel_values = pixel_values.to(hf_config.dtype) + return pixel_values + + def process_mm_data( + self, input_text, images=None, videos=None, audios=None, **kwargs + ) -> dict: + """ + process multimodal data with transformers AutoProcessor + """ + if images: + kwargs["images"] = images + if videos: + kwargs["videos"] = videos + + processor = self._processor + if ( + hasattr(processor, "image_processor") + and isinstance(processor.image_processor, BaseImageProcessorFast) + and not self.server_args.disable_fast_image_processor + ): + if not _is_npu: + kwargs["device"] = "cuda" + + result = processor.__call__( + text=[input_text], + padding=True, + return_tensors="pt", + **kwargs, + ) + + # Divide the processor_output into two modalities: image and video. + if result is not None: + pixel_values = result["images"] + if pixel_values is not None: + result["images"] = self._pixel_values_norm(pixel_values, kwargs) + for key in list(result.keys()): + if result[key] is None: + del result[key] + continue + if key == "grid_thw": + grid_thw = result["grid_thw"] + pixel_values_all = result["images"] + # Identify elements where the first + # dimension is greater than 1 and + # treat them as the video modality + mask = grid_thw[:, 0] > 1 + result["video_grid_thw"] = grid_thw[mask] + result["image_grid_thw"] = grid_thw[~mask] + image_patch_num = result["image_grid_thw"].prod(dim=1).sum() + result["pixel_values"] = pixel_values_all[:image_patch_num] + result["pixel_values_videos"] = pixel_values_all[image_patch_num:] + del result["images"] + del result["grid_thw"] + + # del empty result + if result["image_grid_thw"].numel() == 0: + del result["image_grid_thw"] + if result["pixel_values"].numel() == 0: + del result["pixel_values"] + if result["video_grid_thw"].numel() == 0: + del result["video_grid_thw"] + if result["pixel_values_videos"].numel() == 0: + del result["pixel_values_videos"] + + if not self.server_args.keep_mm_feature_on_device: + # move feature tensors to cpu + for feature_name in self.FEATURE_NAMES: + if SGL_USE_CUDA_IPC: + pass + else: + if feature_name in result and isinstance( + result[feature_name], torch.Tensor + ): + result[feature_name] = result[feature_name].to("cpu") + + return result + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes]], + input_text, + request_obj, + *args, + **kwargs, + ): + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + video_data=request_obj.video_data, + audio_data=request_obj.audio_data, + multimodal_tokens=self.mm_tokens, + ) + + # resize images if they are raw Image objects + resized_images = [] + if base_output.images and isinstance(base_output.images[0], Image.Image): + for image in base_output.images: + resized_image = resize_image(image) + resized_images.append(resized_image) + base_output.images = resized_images + + if base_output.videos: + videos_processed = [ + await preprocess_video(video) for video in base_output.videos + ] + base_output.videos, _ = map(list, zip(*videos_processed)) + + mm_items, input_ids, ret = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + + input_ids = input_ids.flatten() + + mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index_ernie45( + input_ids=input_ids.unsqueeze(0), + hf_config=self.hf_config, + image_grid_thw=getattr(ret, "image_grid_thw", None), + video_grid_thw=getattr(ret, "video_grid_thw", None), + ) + mrope_positions = mrope_positions.squeeze(1) + + assert ( + input_ids.shape[0] == mrope_positions.shape[-1] + ), "input_ids and mrope_positions should have the same length" + + mm_inputs = { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + "im_start_id": self.image_start_token_id, + "im_end_id": self.image_end_token_id, + "im_token_id": self.mm_tokens.image_token_id, + "video_token_id": self.mm_tokens.video_token_id, + "mrope_positions": mrope_positions, + "mrope_position_delta": mrope_position_delta, + } + + return mm_inputs diff --git a/sglang/python/sglang/srt/multimodal/processors/gemma3.py b/sglang/python/sglang/srt/multimodal/processors/gemma3.py new file mode 100644 index 0000000000000000000000000000000000000000..cbfb45e8404e240ce5567d9dc55d750c1a143ea7 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/gemma3.py @@ -0,0 +1,54 @@ +import re +from typing import Dict, List, Union + +from sglang.srt.managers.multimodal_processor import ( + BaseMultimodalProcessor as SGLangBaseProcessor, +) +from sglang.srt.models.gemma3_mm import Gemma3ForConditionalGeneration +from sglang.srt.multimodal.processors.base_processor import MultimodalSpecialTokens + +# Copied from: https://github.com/huggingface/transformers/blob/main/src/transformers/models/gemma3/image_processing_gemma3_fast.py +# will be removed in the future + + +class Gemma3SGLangImageProcessor(SGLangBaseProcessor): + models = [Gemma3ForConditionalGeneration] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.IM_START_TOKEN_ID = hf_config.boi_token_index + self.IM_END_TOKEN_ID = hf_config.eoi_token_index + self.mm_tokens = MultimodalSpecialTokens( + # The single, pre-expanded image token. + image_token="", + image_token_id=hf_config.image_token_index, + # The regex that matches expanded image tokens. + image_token_regex=re.compile( + r"(?:(?:)*)?" + ), + ).build(_processor) + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes, Dict]], + input_text, + request_obj, + *args, + **kwargs, + ): + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + multimodal_tokens=self.mm_tokens, + discard_alpha_channel=True, + ) + + mm_items, input_ids, _ = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + return { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + "im_start_id": self.IM_START_TOKEN_ID, + "im_end_id": self.IM_END_TOKEN_ID, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/gemma3n.py b/sglang/python/sglang/srt/multimodal/processors/gemma3n.py new file mode 100644 index 0000000000000000000000000000000000000000..9ea8b8be3662f3c7d7417b2823e94364470b1564 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/gemma3n.py @@ -0,0 +1,71 @@ +# Copyright 2025 SGLang Team +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from typing import Dict, List, Optional, Union + +from sglang.srt.managers.multimodal_processor import ( + BaseMultimodalProcessor as SGLangBaseProcessor, +) +from sglang.srt.models.gemma3n_mm import Gemma3nForConditionalGeneration +from sglang.srt.multimodal.processors.base_processor import MultimodalSpecialTokens + + +class Gemma3nSGLangProcessor(SGLangBaseProcessor): + """Multimodal processor for Gemma3n supporting image and audio inputs.""" + + models = [Gemma3nForConditionalGeneration] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + + self.IM_START_TOKEN_ID = hf_config.boi_token_id + self.IM_END_TOKEN_ID = hf_config.eoi_token_id + + self.AUDIO_START_TOKEN_ID = hf_config.boa_token_id + self.AUDIO_END_TOKEN_ID = hf_config.eoa_token_id + self.mm_tokens = MultimodalSpecialTokens( + image_token="", + image_token_id=hf_config.image_token_id, + audio_token="", + audio_token_id=hf_config.audio_token_id, + ).build(_processor) + + async def process_mm_data_async( + self, + image_data: Optional[List[Union[str, bytes, Dict]]] = None, + audio_data: Optional[List[Union[str, bytes, Dict]]] = None, + input_text: str = "", + request_obj=None, + *args, + **kwargs, + ): + """Process multimodal data including images and audio.""" + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + audio_data=audio_data, + multimodal_tokens=self.mm_tokens, + ) + + mm_items, input_ids, _ = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + + return { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + # TODO(mick): could we return MultimodalSpecialTokens directly? + "im_token_id": self.mm_tokens.image_token_id, + "audio_token_id": self.mm_tokens.audio_token_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/glm4v.py b/sglang/python/sglang/srt/multimodal/processors/glm4v.py new file mode 100644 index 0000000000000000000000000000000000000000..33cce6fe25675e7385ecba2775743bab6dd8b22d --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/glm4v.py @@ -0,0 +1,102 @@ +from typing import List, Union + +from sglang.srt.layers.rotary_embedding import MRotaryEmbedding +from sglang.srt.models.glm4v import Glm4vForConditionalGeneration +from sglang.srt.models.glm4v_moe import Glm4vMoeForConditionalGeneration +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor as SGLangBaseProcessor, +) +from sglang.srt.multimodal.processors.base_processor import ( + MultimodalSpecialTokens, +) + +try: + from sglang.srt.models.glm_ocr import GlmOcrForConditionalGeneration +except ImportError: + GlmOcrForConditionalGeneration = None + + +class Glm4vImageProcessor(SGLangBaseProcessor): + models = [ + m + for m in [ + Glm4vForConditionalGeneration, + Glm4vMoeForConditionalGeneration, + GlmOcrForConditionalGeneration, + ] + if m is not None + ] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + + # GLM-V specific tokens + self.IMAGE_TOKEN = "<|image|>" + self.VIDEO_TOKEN = "<|video|>" + self.IMAGE_START_TOKEN = "<|begin_of_image|>" + self.IMAGE_END_TOKEN = "<|end_of_image|>" + self.VIDEO_START_TOKEN = "<|begin_of_video|>" + self.VIDEO_END_TOKEN = "<|end_of_video|>" + + # Token IDs + self.IM_TOKEN_ID = hf_config.image_token_id + self.VIDEO_TOKEN_ID = hf_config.video_token_id + self.IMAGE_START_TOKEN_ID = hf_config.image_start_token_id + self.IMAGE_END_TOKEN_ID = hf_config.image_end_token_id + self.VIDEO_START_TOKEN_ID = hf_config.video_start_token_id + self.VIDEO_END_TOKEN_ID = hf_config.video_end_token_id + + # Vision config + self.IMAGE_FACTOR = 28 + self.MIN_PIXELS = 112 * 112 + self.MAX_PIXELS = 30000 * 28 * 28 * 2 + + self.mm_tokens = MultimodalSpecialTokens( + image_token=self.IMAGE_TOKEN, + image_token_id=self.IM_TOKEN_ID, + video_token=self.VIDEO_TOKEN, + # Note: For GLM4v videos, it uses the video token before tokenization but uses image token after tokenization + video_token_id=self.IM_TOKEN_ID, + ).build(_processor) + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes]], + input_text, + request_obj, + *args, + **kwargs, + ): + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + video_data=request_obj.video_data, + multimodal_tokens=self.mm_tokens, + ) + + if base_output.videos: + base_output.videos = request_obj.video_data + mm_items, input_ids, ret = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + + input_ids = input_ids.flatten() + mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index_glm4v( + input_ids=input_ids.unsqueeze(0), + hf_config=self.hf_config, + image_grid_thw=getattr(ret, "image_grid_thw", None), + video_grid_thw=getattr(ret, "video_grid_thw", None), + attention_mask=getattr(ret, "attention_mask", None), + ) + mrope_positions = mrope_positions.squeeze(1) + + mm_inputs = { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + "im_token_id": self.mm_tokens.image_token_id, + "video_token_id": self.mm_tokens.video_token_id, + "mrope_positions": mrope_positions, + "mrope_position_delta": mrope_position_delta, + } + + return mm_inputs diff --git a/sglang/python/sglang/srt/multimodal/processors/glmasr.py b/sglang/python/sglang/srt/multimodal/processors/glmasr.py new file mode 100644 index 0000000000000000000000000000000000000000..cebeb1f6a60210939b9a5260e7ab2b253a1cdead --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/glmasr.py @@ -0,0 +1,53 @@ +import re + +from sglang.srt.models.glmasr import GlmAsrForConditionalGeneration +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + MultimodalSpecialTokens, +) + + +class GlmAsrProcessor(BaseMultimodalProcessor): + models = [GlmAsrForConditionalGeneration] + + def __init__(self, hf_config, server_args, _processor, *args, **kwargs): + super().__init__(hf_config, server_args, _processor, *args, **kwargs) + self.AUDIO_TOKEN = "<|begin_of_audio|><|pad|><|end_of_audio|>" + self.AUDIO_TOKEN_REGEX = re.compile( + r"<\|begin_of_audio\|><\|pad\|><\|end_of_audio\|>" + ) + # Collect special token ids + tokenizer = self._processor.tokenizer + self.audio_start_id = tokenizer.convert_tokens_to_ids("<|begin_of_audio|>") + self.audio_token_id = tokenizer.convert_tokens_to_ids("<|pad|>") + self.audio_end_id = tokenizer.convert_tokens_to_ids("<|end_of_audio|>") + + self.mm_tokens = MultimodalSpecialTokens( + audio_token=self.AUDIO_TOKEN, + audio_token_regex=self.AUDIO_TOKEN_REGEX, + audio_token_id=self.audio_token_id, + ).build(_processor) + + async def process_mm_data_async( + self, + audio_data, + input_text, + **kwargs, + ): + base_output = self.load_mm_data( + prompt=input_text, + audio_data=audio_data, + multimodal_tokens=self.mm_tokens, + ) + if base_output is None: + return None + mm_items, input_ids, ret = self.process_and_combine_mm_data( + base_output, self.mm_tokens + ) + return { + "mm_items": mm_items, + "input_ids": input_ids.tolist(), + "audio_start_id": self.audio_start_id, + "audio_token_id": self.audio_token_id, + "audio_end_id": self.audio_end_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/interns1pro.py b/sglang/python/sglang/srt/multimodal/processors/interns1pro.py new file mode 100644 index 0000000000000000000000000000000000000000..d448dc1cb92ba8e266bcea867d93572e0fed5b74 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/interns1pro.py @@ -0,0 +1,118 @@ +import time +from typing import List, Union + +from sglang.srt.managers.schedule_batch import Modality, MultimodalDataItem +from sglang.srt.models.interns1pro import InternS1ProForConditionalGeneration +from sglang.srt.multimodal.processors.qwen_vl import ( + QwenVLImageProcessor, + preprocess_video, +) +from sglang.utils import logger + + +class InternS1_1ImageProcessor(QwenVLImageProcessor): + models = [ + InternS1ProForConditionalGeneration, + ] + + def get_mm_data(self, prompt, embeddings, img_grid_thw): + input_ids, offsets = self.build_input_ids(prompt, img_grid_thw) + + mm_items = [ + MultimodalDataItem( + modality=Modality.IMAGE, + offsets=offsets, + precomputed_embeddings=embeddings, + ) + ] + + return { + "input_ids": input_ids, + "mm_items": mm_items, + "im_start_id": self.IM_START_TOKEN_ID, + "im_end_id": self.IM_END_TOKEN_ID, + "im_token_id": self.mm_tokens.image_token_id, + "video_token_id": self.mm_tokens.video_token_id, + "audio_token_id": self.mm_tokens.audio_token_id, + } + + async def process_mm_data_async( + self, + image_data: List[Union[str, bytes]], + input_text, + request_obj, + *args, + **kwargs, + ): + entry_time = time.perf_counter() + base_output = self.load_mm_data( + prompt=input_text, + image_data=image_data, + video_data=request_obj.video_data, + audio_data=request_obj.audio_data, + multimodal_tokens=self.mm_tokens, + ) + load_time = time.perf_counter() + rid = getattr(request_obj, "rid", "anonymous_rid") + + video_metadata = None + if base_output.videos: + videos_processed = [ + await preprocess_video(video, video_config=self.video_config) + for video in base_output.videos + ] + base_output.videos, video_metadata = map(list, zip(*videos_processed)) + + preprocess_time = time.perf_counter() + + mm_items, input_ids, ret = self.process_and_combine_mm_data( + base_output, + self.mm_tokens, + video_metadata=video_metadata, + do_sample_frames=False, + ) + + second_per_grid_ts = getattr(ret, "second_per_grid_ts", None) + if second_per_grid_ts is None: + second_per_grid_ts = getattr(ret, "video_second_per_grid", None) + + process_time = time.perf_counter() + + input_ids = input_ids.flatten() + + image_grid_thw = None + if hasattr(ret, "image_grid_thw"): + image_grid_thw = ret.image_grid_thw + + if image_grid_thw is None and image_data and isinstance(image_data[0], dict): + image_grid_thw = image_data[0].get("image_grid_thw") + + video_grid_thw = None + if hasattr(ret, "video_grid_thw"): + video_grid_thw = ret.video_grid_thw + + if video_grid_thw is None and request_obj.video_data: + first_video = request_obj.video_data[0] + if isinstance(first_video, dict): + video_grid_thw = first_video.get("video_grid_thw") + + get_rope_index_time = time.perf_counter() + + logger.debug( + f"[QwenVLProcessor Perf] {rid=}, " + f"load_time: {(load_time - entry_time) * 1000:.2f} ms, " + f"preprocess_time: {(preprocess_time - load_time) * 1000:.2f} ms, " + f"process_time: {(process_time - preprocess_time) * 1000:.2f} ms, " + f"get_rope_index_time: {(get_rope_index_time - process_time) * 1000:.2f} ms, " + f"total_time: {(get_rope_index_time - entry_time) * 1000:.2f} ms" + ) + + return { + "input_ids": input_ids.tolist(), + "mm_items": mm_items, + "im_start_id": self.vision_start_token_id, + "im_end_id": self.vision_end_token_id, + "im_token_id": self.mm_tokens.image_token_id, + "video_token_id": self.mm_tokens.video_token_id, + "audio_token_id": self.mm_tokens.audio_token_id, + } diff --git a/sglang/python/sglang/srt/multimodal/processors/internvl.py b/sglang/python/sglang/srt/multimodal/processors/internvl.py new file mode 100644 index 0000000000000000000000000000000000000000..2c05608d938f10a2f8228c2b804f5f2fb0965332 --- /dev/null +++ b/sglang/python/sglang/srt/multimodal/processors/internvl.py @@ -0,0 +1,724 @@ +# Adapted from https://huggingface.co/OpenGVLab/InternVL2-4B/blob/main/modeling_intern_vit.py + +import logging +from functools import lru_cache +from typing import List + +import numpy as np +import torch +from decord import VideoReader, cpu, gpu +from PIL import Image + +from sglang.srt.managers.schedule_batch import ( + Modality, + MultimodalDataItem, +) +from sglang.srt.models.interns1 import InternS1ForConditionalGeneration +from sglang.srt.models.internvl import InternVLChatModel +from sglang.srt.multimodal.processors.base_processor import ( + BaseMultimodalProcessor, + BaseMultiModalProcessorOutput, + MultimodalSpecialTokens, +) + +logger = logging.getLogger(__name__) + + +class InternVLProcessor(BaseMultimodalProcessor): + models = [InternVLChatModel, InternS1ForConditionalGeneration] + + IMAGENET_MEAN = [0.485, 0.456, 0.406] + IMAGENET_STD = [0.229, 0.224, 0.225] + IMAGE_MAX_NUM = 12 + + DEFAULT_VIDEO_NUM_FRAMES = 32 + VIDEO_MAX_NUM = 1 + VIDEO_USE_THUMBNAIL = False + + CONTEXT_FALLBACK = 40960 + CONTEXT_RESERVED = 256 + + # OpenAI multimodal placeholder tokens + IMAGE_PLACEHOLDER_TOKEN = "" + VIDEO_PLACEHOLDER_TOKEN = "