<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>通信计算融合算子实现 on Echo的技术博客</title><link>https://cybersecurityerial.github.io/echo_blog/series/%E9%80%9A%E4%BF%A1%E8%AE%A1%E7%AE%97%E8%9E%8D%E5%90%88%E7%AE%97%E5%AD%90%E5%AE%9E%E7%8E%B0/</link><description>Recent content in 通信计算融合算子实现 on Echo的技术博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 17 Aug 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://cybersecurityerial.github.io/echo_blog/series/%E9%80%9A%E4%BF%A1%E8%AE%A1%E7%AE%97%E8%9E%8D%E5%90%88%E7%AE%97%E5%AD%90%E5%AE%9E%E7%8E%B0/index.xml" rel="self" type="application/rss+xml"/><item><title>LLM System: 通信计算融合算子实现 01 - sm80GEMM + ReduceScatter</title><link>https://cybersecurityerial.github.io/echo_blog/posts/llm-system-comm-comp-fusion-operators-01-ampere-gemm-rs/</link><pubDate>Sun, 05 Jul 2026 00:00:00 +0800</pubDate><guid>https://cybersecurityerial.github.io/echo_blog/posts/llm-system-comm-comp-fusion-operators-01-ampere-gemm-rs/</guid><description>&lt;h2 id="flux实现sm80-gemmrs"&gt;flux实现：sm80 gemm+rs&lt;/h2&gt;
&lt;p&gt;看flux的论文来说，原理并不难，修改的是ffn的第二个gemm的epi阶段，让epi阶段的写回操作变成写入reducescatter的通信buffer，相当于做了一次零拷贝。
几个关键的点：1. 如何用cutlass自定义epi阶段。2. 用了什么ptx。3. 清零？&lt;/p&gt;
&lt;h2 id="cutlass自定义epiloguesm80"&gt;cutlass自定义epilogue&amp;ndash;sm80&lt;/h2&gt;
&lt;p&gt;常规的epi，写回gmem，这里改成写在scatter-aware-memory（我自己起的名字）。cutlass封装自定义epi的逻辑抽象是：输出tile存到哪里，以及做什么运算，这分别是两个模版类：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; EVT_D &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;decltype&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;evt_d(kparams));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; StoreD &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;decltype&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;evt_store_d(kparams));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; EVT &lt;span style="color:#f92672"&gt;=&lt;/span&gt; cutlass&lt;span style="color:#f92672"&gt;::&lt;/span&gt;epilogue&lt;span style="color:#f92672"&gt;::&lt;/span&gt;threadblock&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Sm80EVT&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;StoreD, EVT_D&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;StoreD就是规定了怎么存，EVTD就是规定了怎么算。
EVT全称epilogue visitor tree就是定义了一个epi阶段的计算-访存操作流，用树状图的形式保存epi阶段的一堆操作（做成图应该是为了方便接入nvcc？不懂为啥非得在这强调是tree）一个树节点（操作）是一个visitor。&lt;/p&gt;
&lt;h3 id="custom_evt_d"&gt;custom_evt_d()&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EVT_Compute0 = alpha * accumulator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码里对应 VisitorCompute&amp;lt;cutlass::multiplies, &amp;hellip;&amp;gt;，两个输入是 VisitorScalarBroadcast&lt;!-- raw HTML omitted --&gt; 和 VisitorAccFetch。第一个负责广播 alpha，第二个v从 GEMM accumulator 里拿当前 tile 的结果，然后 multiply&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EVT_Compute1 = beta * C + EVT_Compute0 = beta * C + alpha * accumulator
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码里对应 VisitorAuxLoadGemmk 先把 C/bias 读进 epilogue，然后 VisitorCompute&amp;lt;cutlass::multiply_add, &amp;hellip;&amp;gt; 做 beta * C + alpha * acc。因为CUTLASS 2.x 没有 SM90 那种 SrcFetch 替代物，所以这里用 VisitorAuxLoadGemmk 来读 C。&lt;/p&gt;</description></item><item><title>gemm和alltoall通算融合</title><link>https://cybersecurityerial.github.io/echo_blog/posts/llm-system-comm-comp-fusion-operators-03-gemm-alltoall-fusion/</link><pubDate>Mon, 17 Aug 2026 00:00:00 +0800</pubDate><guid>https://cybersecurityerial.github.io/echo_blog/posts/llm-system-comm-comp-fusion-operators-03-gemm-alltoall-fusion/</guid><description>&lt;h2 id="1-总体思想"&gt;1. 总体思想&lt;/h2&gt;
&lt;p&gt;这次做的是单机八卡 H200、NVLink、Ulysses CP 下的 GEMM 和 AllToAll 融合。先把 forward 写清楚：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A2A → QKV projection → QK → PV → A2A
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要接起来的主边界有两个。输入侧是 &lt;code&gt;A2A→QKV projection&lt;/code&gt;，通信先把各个 peer 的输入 tile 搬到本地最终布局，GEMM 拿到一块就算一块。输出侧是 &lt;code&gt;batched PV→A2A&lt;/code&gt;，每个本地 head 都有一组独立的 &lt;code&gt;P×V&lt;/code&gt;，GEMM 算完一个 tile，通信 CTA 立刻把它送到目标 rank 的最终 Ulysses 布局。&lt;/p&gt;
&lt;p&gt;如果 GEMM 和 NCCL 顺序执行，端到端时间接近两段时间相加。这里把通信 CTA 和 GEMM CTA 放进同一个 cooperative persistent grid，两种 CTA 常驻在不同的 SM 上，用 tile 级 ready epoch 接力。&lt;code&gt;A2A→GEMM&lt;/code&gt; 由通信生产、GEMM 消费；&lt;code&gt;GEMM→A2A&lt;/code&gt; 交换生产消费关系。这样首批 tile 到达后就能启动计算，前面的 tile 也可以在后续 GEMM 还在跑时发出去。&lt;/p&gt;</description></item></channel></rss>