昇腾社区首页
中文
注册

分离架构

针对分离架构,使用基础API进行矩阵乘法算子实现的编程范式和耦合架构一致,由于硬件架构不同,具体实现有一些差异,本节仅提供差异点说明。完整代码请参见Mmad样例

  • CopyIn阶段差异
    • 耦合架构

      在CopyIn阶段,即从GM->A1/B1(L1 Buffer)的阶段,耦合架构可以使用DataCopy接口直接将数据从GM搬入L1 Buffer,也可以将数据从GM搬入UB,再搬入L1 Buffer。若需要ND2NZ的格式转换,需要开发者自行完成;或使用DataCopy接口提供的随路格式转换功能,但该功能会使用UB临时空间。

      如下示例,直接使用了GM->A1/B1的数据搬运指令,自行完成ND2NZ的格式转换。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
          __aicore__ inline void CopyND2NZ(const AscendC::LocalTensor<half>& dst, const AscendC::GlobalTensor<half>& src,
              const uint16_t height, const uint16_t width)
          {
              for (int i = 0; i < width / 16; ++i) {
                  int srcOffset = i * 16;
                  int dstOffset = i * 16 * height;
                  AscendC::DataCopy(dst[dstOffset], src[srcOffset], { height, 1, uint16_t(width / 16 - 1), 0 });
              }
          }
          __aicore__ inline void CopyIn()
          {
              AscendC::LocalTensor<half> a1Local = inQueueA1.AllocTensor<half>();
              AscendC::LocalTensor<half> b1Local = inQueueB1.AllocTensor<half>();
      
              CopyND2NZ(a1Local, aGM, m, k);
              CopyND2NZ(b1Local, bGM, k, n);
      
              inQueueA1.EnQue(a1Local);
              inQueueB1.EnQue(b1Local);
          }
      
    • 分离架构

      分离架构中数据无法经过VECIN/VECCALC/VECOUT (UB) 直接搬运到A1/B1 (L1 Buffer) ,但是使用DataCopy接口提供的随路格式转换功能一条指令即可完成格式转换,无需UB作为临时空间。

      示例如下:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
          __aicore__ inline void CopyIn()
          {
              AscendC::LocalTensor<half> a1Local = inQueueA1.AllocTensor<half>();
              AscendC::LocalTensor<half> b1Local = inQueueB1.AllocTensor<half>();
      
              AscendC::Nd2NzParams nd2nzA1Params;
              nd2nzA1Params.ndNum = 1;
              nd2nzA1Params.nValue = m;
              nd2nzA1Params.dValue = k;
              nd2nzA1Params.srcNdMatrixStride = 0;
              nd2nzA1Params.srcDValue = k;
              nd2nzA1Params.dstNzC0Stride = CeilCubeBlock(m) * CUBE_BLOCK;
              nd2nzA1Params.dstNzNStride = 1;
              nd2nzA1Params.dstNzMatrixStride = 0;
              AscendC::DataCopy(a1Local, aGM, nd2nzA1Params);
      
              AscendC::Nd2NzParams nd2nzB1Params;
              nd2nzB1Params.ndNum = 1;
              nd2nzB1Params.nValue = k;
              nd2nzB1Params.dValue = n;
              nd2nzB1Params.srcNdMatrixStride = 0;
              nd2nzB1Params.srcDValue = n;
              nd2nzB1Params.dstNzC0Stride = CeilCubeBlock(k) * CUBE_BLOCK;
              nd2nzB1Params.dstNzNStride = 1;
              nd2nzB1Params.dstNzMatrixStride = 0;
              AscendC::DataCopy(b1Local, bGM, nd2nzB1Params);
      
              inQueueA1.EnQue(a1Local);
              inQueueB1.EnQue(b1Local);
          }
      
  • Aggregate及CopyOut阶段差异
    • 耦合架构

      耦合架构中,完成矩阵乘计算后之后数据存放于CO1(L0C Buffer),最终搬入GM需要通过CO2(UB),且NZ2ND的格式转换需要在CO1->CO2->GM阶段中手动完成。如下样例,在Aggregate阶段将NZ格式数据从CO1搬入CO2中,在CO2->GM的阶段使用for循环调用DataCopy完成了格式转换。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
           
          __aicore__ inline void Aggregate(const AscendC::LocalTensor<float>& c2Local, const int bSplitIdx)
          {
              AscendC::LocalTensor<float> c1Local = outQueueCO1.DeQue<float>();
      
              AscendC::DataCopyParams dataCopyParams;
              dataCopyParams.blockCount = 1;
              dataCopyParams.blockLen = 2;
              AscendC::DataCopyEnhancedParams enhancedParams;
              enhancedParams.blockMode = AscendC::BlockMode::BLOCK_MODE_MATRIX;
              AscendC::DataCopy(c2Local[bSplitIdx * cSize / 2], c1Local, dataCopyParams, enhancedParams);
      
              outQueueCO1.FreeTensor(c1Local);
          }
          __aicore__ inline void CopyOut()
          {
              AscendC::LocalTensor<float> c2Local = outQueueCO2.DeQue<float>();
      
              // transform nz to nd
              for (int i = 0; i < nBlocks; ++i) {
                  AscendC::DataCopy(cGM[i * 16], c2Local[i * m * 16], { m, 2, 0, uint16_t((nBlocks - 1) * 2) });
              }
      
              outQueueCO2.FreeTensor(c2Local);
          }
      
    • 分离架构

      分离架构中,矩阵乘的计算结果从CO1(L0C Buffer)可以通过Fixpipe通路直接写入GM,而且Fixpipe提供了随路NZ2ND的功能,方便用户做格式转换。样例如下,样例中省去了Aggregate阶段,直接CopyOut。

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
          __aicore__ inline void CopyOut()
          {
              AscendC::LocalTensor<float> c1Local = outQueueCO1.DeQue<float>();
              AscendC::FixpipeParamsV220 fixpipeParams;
              fixpipeParams.nSize = n;
              fixpipeParams.mSize = m;
              fixpipeParams.srcStride = m;
              fixpipeParams.dstStride = n;
      
              fixpipeParams.ndNum = 1;
              fixpipeParams.srcNdStride = 0;
              fixpipeParams.dstNdStride = 0;
              AscendC::Fixpipe(cGM, c1Local, fixpipeParams);
              outQueueCO1.FreeTensor(c1Local);
          }