d0ef256d-0777-4cfc-b653-4343c4a7ae32


User · 2026-05-18T14:13:51.076Z

我现在要写1个分布式算子的实现,接口是mindspore.ops.rotary_position_embedding。 对应的算子名是RotaryPositionEmbedding

接口的资料参考,*号后面是强制的关键字参数。 /root/workspace/mindspore/mindspore/ops/op_def/yaml/doc/rotary_position_embedding_doc.yaml

底层的CANN算子的接口是,支持的规格可以查到 /root/workspace/ops-transformer/posembedding/rotary_position_embedding/docs/aclnnRotaryPositionEmbedding.md

mindspore的算子,有分布式算子实现,我们可以分析下,如果是合理的,可以参考。 /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_overload_functions.cc

文件的格式,需要实现的接口函数/类,参考sparse_flash_attention分布式算子实现: git show HEAD --name-only |grep sparse_flash hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py hyper_parallel/core/shard/ops/yaml/npu_sparse_flash_attention_ops.yaml tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py tests/mindspore/st/shard/ops/test_npu_sparse_flash_attention_shard_in_python.py tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py

现在你要做的是,实现这个mindsproe算子的分布式算子逻辑,参考sparse_flash_attention。 注意一定要考虑到接口差异,做分布式算子逻辑的时候,充分考虑每个入参对layout的影响。

先输出一个分析文档,将你计划实现的文件,文件要实现的类,接口及功能描述清楚,接口入参对layout的影响,各种约束,以及UT/ST测试用例的实际,都写进分析报告里。 要先plan,不要直接动手。


Assistant · 2026-05-18T14:14:01.771Z

[Bash: cat /root/workspace/mindspore/mindspore/ops/op_def/yaml/doc/rotary_position_embedding_doc.yaml]
rotary_position_embedding:
    description: |
        Implements the Rotary Position Embedding algorithm.
        Refer to paper `Enhanced Transformer with Rotary Position Embedding <https://arxiv.org/pdf/2104.09864.pdf>`_.

        .. warning::
            This interface is deprecated and will be removed after version 2.9.0.

        Args:
            x (Tensor): 4D tensor, with float16, bfloat16 or float32 data type.
            cos (Tensor): 4D constant, has the same type as `x` , in range of [-1, 1].
            sin (Tensor): Same with `cos` .
            mode (int): An optional attribute. Used to select a calculation mode. 0: rotate_half(GPT-NeoX style); 1: rotate_interleaved(GPT-J style). Defaults to ``0`` .

        .. list-table:: Config layout constraints
            :widths: 5 20 20
            :header-rows: 1

            * - Args
              - RotateHalf(mode:0)
              - RotateInterleaved(mode:1)
            * - x
              - Supported layout:

                11SD, B1SD, BNSD; D < 896 and D is Even. B, N < 1000;

              - Supported layout: 11SD, B1SD, BNSD;

                D < 896 and D is Even.

                B, N < 1000;
            * - cos
              - Supported layout for different values of `x`:

                `x` is BNSD: 11SD, B1SD, BNSD;

                `x` is BSND: 1S1D, BS1D, BSND;

                `x` is SBND: S11D, SB1D, SBND
              - Supported layout for different values of `x`:

                `x` is BNSD: 11SD;

                `x` is BSND: 1S1D;

                `x` is SBND: S11D
            * - sin
              - Same with `cos` .
              - Same with `cos` .

        .. note::
            When the layout is BNSD, B * N > 8S and D is 32-byte alignment, the performance is poor. Therefore, this interface cannot be called.

        Returns:
            Tensor, has the same dtype and shape as the `x`.

        Raises:
            TypeError: If `x` is not a Tensor.
            TypeError: If `cos` is not a Tensor.
            TypeError: If `sin` is not a Tensor.
            TypeError: If `mode` is not an int.

        Supported Platforms:
            ``Ascend``

        Examples:
            >>> import numpy as np
            >>> from mindspore import Tensor, ops
            >>> x = Tensor(np.random.uniform(-2, 2, (4, 8192, 4, 128)))
            >>> cos = Tensor(np.random.uniform(-1, 1, (1, 8192, 1, 128)))
            >>> sin = Tensor(np.random.uniform(-1, 1, (1, 8192, 1, 128)))
            >>> output = ops.rotary_position_embedding(x, cos, sin, 0)
            >>> print(output.shape)
            (4, 8192, 4, 128)
[Bash: cat /root/workspace/ops-transformer/posembedding/rotary_position_embedding/docs/aclnnRotaryPositionEmbedding.md]
# aclnnRotaryPositionEmbedding

[📄 查看源码](https://gitcode.com/cann/ops-transformer/tree/master/posembedding/rotary_position_embedding)

## 产品支持情况

| 产品                                                         | 是否支持 |
| :----------------------------------------------------------- | :------: |
| <term>Ascend 950PR/Ascend 950DT</term>                             |    √     |
| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>     |    √     |
| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> |    √     |
| <term>Atlas 200I/500 A2 推理产品</term>                      |    ×     |
| <term>Atlas 推理系列产品</term>                             |    √     |
| <term>Atlas 训练系列产品</term>                              |    ×     |

## 功能说明

- 接口功能:执行单路旋转位置编码计算。
- 计算公式:

    - <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>、<term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>:

    (1)half模式(mode等于0):

    $$
    x1 = x[..., : x.shape[-1] // 2]
    $$

    $$
    x2 = x[..., x.shape[-1] // 2 :]
    $$

    $$
    x\_rotate = torch.cat((-x2, x1), dim=-1)
    $$

    $$
    y = x * cos + x\_rotate * sin
    $$

    (2)interleave模式(mode等于1):

    $$
    x1 = x[..., ::2].view(-1, 1)
    $$

    $$
    x2 = x[..., 1::2].view(-1, 1)
    $$

    $$
    x\_rotate = torch.cat((-x2, x1), dim=-1).view(x.shape[0], x.shape[1], x.shape[2], x.shape[3])
    $$

    $$
    y = x * cos + x\_rotate * sin
    $$

    (3)quarter模式(mode等于2):

    $$
    x1 = x[..., : x.shape[-1] // 4]
    $$

    $$
    x2 = x[..., x.shape[-1] // 4 : x.shape[-1] // 2]
    $$

    $$
    x3 = x[..., x.shape[-1] // 2 : x.shape[-1] // 4 * 3]
    $$

    $$
    x4 = x[..., x.shape[-1] // 4 * 3 :]
    $$

    $$
    x\_rotate = torch.cat((-x2, x1, -x4, x3), dim=-1)
    $$

    $$
    y = x * cos + x\_rotate * sin
    $$

    (4)interleave-half模式(mode等于3),该模式会先将奇数位的输入抽取到前半部分,将偶数位的输入抽取到后半部分,再进行half处理:

    $$
    x1 = x[..., ::2]
    $$

    $$
    x2 = x[..., 1::2]
    $$

    $$
    x\_part1 = torch.cat((x1, x2), dim=-1)
    $$

    $$
    x\_part2 = torch.cat((-x2, x1), dim=-1)
    $$

    $$
    y = x\_part1 * cos + x\_part2 * sin
    $$

## 函数原型

每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用“aclnnRotaryPositionEmbeddingGetWorkspaceSize”接口获取入参并根据流程计算所需workspace大小,再调用“aclnnRotaryPositionEmbedding”接口执行计算。

```c++
aclnnStatus aclnnRotaryPositionEmbeddingGetWorkspaceSize(
    const aclTensor *x,
    const aclTensor *cos,
    const aclTensor *sin,
    int64_t          mode,
    aclTensor       *out,
    uint64_t        *workspaceSize,
    aclOpExecutor   **executor)
aclnnStatus aclnnRotaryPositionEmbedding(
    void          *workspace,
    uint64_t       workspaceSize,
    aclOpExecutor *executor,
    aclrtStream    stream)

aclnnRotaryPositionEmbeddingGetWorkspaceSize

  • 参数说明

    参数名 输入/输出 描述 使用说明 数据类型 数据格式 维度(shape) 非连续Tensor
    x 输入 待执行旋转位置编码的张量,公式中的x。 - BFLOAT16、FLOAT16、FLOAT32 ND 3或4
    cos 输入 位置编码张量,公式中的cos。 与x数据类型一致。 BFLOAT16、FLOAT16、FLOAT32 ND 3或4
    sin 输入 位置编码张量,公式中的sin。 与x数据类型一致。 BFLOAT16、FLOAT16、FLOAT32 ND 3或4
    mode 输入 旋转模式。 - INT64 - - -
    out 输出 旋转位置编码计算结果,公式中的y。 与x数据类型一致。 BFLOAT16、FLOAT16、FLOAT32 ND 4 x
    workspaceSize 输出 返回需要在Device侧申请的workspace大小。 - - - - -
    executor 输出 返回op执行器,包含算子计算流程。 - - - - -
    • Atlas 推理系列产品:不支持BFLOAT16数据类型

    • 参数mode约束:

      • Atlas A3 训练系列产品/Atlas A3 推理系列产品、Atlas A2 训练系列产品/Atlas A2 推理系列产品:0=half,1=interleave。
      • Ascend 950PR/Ascend 950DT:2=quarter,3=interleave-half。
      • Atlas 推理系列产品:0=half。
  • 返回值:

    返回aclnnStatus状态码,具体参见aclnn返回码

aclnnRotaryPositionEmbedding

  • 参数说明:

    参数名 输入/输出 描述
    workspace 输入 在Device侧申请的workspace内存地址。
    workspaceSize 输入 在Device侧申请的workspace大小,由第一段接口aclnnRotaryPositionEmbeddingGetWorkspaceSize获取。
    executor 输入 op执行器,包含了算子计算流程。
    stream 输入 指定执行任务的Stream流。
  • 返回值:

    返回aclnnStatus状态码,具体参见aclnn返回码

约束说明

  • 确定性计算:

    • aclnnRotaryPositionEmbedding默认确定性实现。
  • Ascend 950PR/Ascend 950DT:

    输入张量x共有四维,各参数的shape约束可以描述如下:

    • 输入张量x、cos、sin及输出张量y的最后一维大小必须相同,且小于等于1024。对于half、interleave和interleave-half模式,最后一维必须能被2整除,对于quarter模式,最后一维必须能被4整除。
    • 输入张量x和输出张量y的shape必须完全相同。
    • 输入张量cos和sin的shape必须完全相同,cos和sin的shape需要与x满足broadcast关系,且广播后的shape必须等于x的shape。
  • Atlas A3 训练系列产品/Atlas A3 推理系列产品、Atlas A2 训练系列产品/Atlas A2 推理系列产品:

    输入张量x支持BNSD、BSND、SBND、TND排布。 输入张量x、cos、sin及输出张量y的D维度大小必须相同,满足D<896,且必须为2的倍数。 输入张量x和输出张量y的shape必须完全相同。 输入张量cos和sin的shape必须完全相同.

    • half模式:
      • B,N < 1000;
      • 当x为BNSD时,cos、sin支持11SD、B1SD、BNSD
        • 当(D/2)% (32/inputDtypeSize) == 0时,需满足B * N <= S * 8
        • 当(D/2)% (32/inputDtypeSize) != 0时,需满足B * N * 2 <= (S + coreNum -1) / coreNum 或者 D >= 80
      • 当x为BSND时,cos、sin支持1S1D、BS1D、BSND
      • 当x为SBND时,cos、sin支持S11D、SB1D、SBND
      • 当x为TND时,cos、sin支持T1D、TND
    • interleave模式:
      • B * N < 1000(N<1000当x为TND)
      • 当x为BNSD时,cos、sin支持11SD
      • 当x为BSND时,cos、sin支持1S1D
      • 当x为SBND时,cos、sin支持S11D
      • 当x为TND时,cos、sin支持T1D
  • Atlas 推理系列产品:

    输入张量x支持BNSD、BSND、SBND、TND排布。 输入张量x、cos、sin及输出张量y的D维度大小必须相同,满足D<=128,且必须为32的倍数。 输入张量x和输出张量y的shape必须完全相同。 输入张量cos和sin的shape必须完全相同。

    • 仅支持half模式:
      • B,N < 1000
      • 当x为BNSD时,cos、sin支持11SD、B1SD、BNSD
        • B * N <= S * 8
      • 当x为BSND时,cos、sin支持1S1D、BS1D、BSND
        • (N - 1) * D * BytePerData / 32 < UINT16_MAX,其中BytePerData当输入数据类型为FLOAT16时,值为2;数据类型为FLOAT32时,值为4
      • 当x为SBND时,cos、sin支持S11D、SB1D、SBND
        • (B * N - 1) * D * BytePerData / 32 < UINT16_MAX,其中BytePerData当输入数据类型为FLOAT16时,值为2;数据类型为FLOAT32时,值为4
      • 当x为TND时,cos、sin支持T1D、TND

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例

#include "acl/acl.h"
#include "aclnnop/aclnn_rotary_position_embedding.h"
#include <iostream>
#include <vector>

#define CHECK_RET(cond, return_expr) \
  do {                               \
    if (!(cond)) {                   \
      return_expr;                   \
    }                                \
  } while (0)

#define LOG_PRINT(message, ...)     \
  do {                              \
    printf(message, ##__VA_ARGS__); \
  } while (0)

int64_t GetShapeSize(const std::vector<int64_t>& shape) {
    int64_t shape_size = 1;
    for (auto i : shape) {
        shape_size *= i;
    }
    return shape_size;
}

int Init(int32_t deviceId, aclrtStream* stream) {
    // 固定写法,资源初始化
    auto ret = aclInit(nullptr);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
    ret = aclrtSetDevice(deviceId);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
    ret = aclrtCreateStream(stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
    return 0;
}

template <typename T>
int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
                    aclDataType dataType, aclTensor** tensor) {
    auto size = GetShapeSize(shape) * sizeof(T);
    // 调用aclrtMalloc申请device侧内存
    auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);

    // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
    ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);

    // 计算连续tensor的strides
    std::vector<int64_t> strides(shape.size(), 1);
    for (int64_t i = shape.size() - 2; i >= 0; i--) {
        strides[i] = shape[i + 1] * strides[i + 1];
    }

    // 调用aclCreateTensor接口创建aclTensor
    *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
                              shape.data(), shape.size(), *deviceAddr);
    return 0;
}

int main() {
    // 1. 固定写法,device/stream初始化, 参考acl API手册
    // 根据自己的实际device填写deviceId
    int32_t deviceId = 0;
    aclrtStream stream;
    auto ret = Init(deviceId, &stream);
    // check根据自己的需要处理
    CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
    // 2. 构造输入与输出,需要根据API的接口定义构造
    std::vector<int64_t> xShape = {1, 1, 1, 128};
    std::vector<int64_t> cosShape = {1, 1, 1, 128};
    std::vector<int64_t> sinShape = {1, 1, 1, 128};
    std::vector<int64_t> outShape = {1, 1, 1, 128};
    int64_t mode = 1;

    void* xDeviceAddr = nullptr;
    void* cosDeviceAddr = nullptr;
    void* sinDeviceAddr = nullptr;
    void* outDeviceAddr = nullptr;
    aclTensor* x = nullptr;
    aclTensor* cos = nullptr;
    aclTensor* sin = nullptr;
    aclTensor* out = nullptr;

    std::vector<float> xHostData = {74, 54, 84, 125, 23, 78, 37, 72, 27, 98, 34, 107, 29, 23, 54, 60, 70, 49,
                                    119, 54, 29, 54, 41, 99, 27, 62, 5, 46, 108, 39, 24, 123, 33, 82, 6, 40, 88,
                                    24, 6, 116, 38, 119, 110, 5, 30, 79, 87, 18, 29, 100, 90, 24, 21, 93, 63, 68,
                                    34, 112, 119, 48, 74, 43, 85, 64, 14, 49, 128, 59, 18, 37, 123, 76, 14, 63, 10,
                                    39, 107, 124, 79, 16, 17, 76, 80, 47, 90, 41, 58, 82, 75, 80, 69, 37, 74, 36, 54,
                                    26, 32, 54, 13, 100, 105, 15, 13, 69, 122, 26, 94, 59, 29, 14, 60, 8, 24, 17, 45,
                                    33, 107, 122, 63, 111, 75, 128, 68, 31, 105, 6, 82, 99};
    std::vector<float> cosHostData = {41, 37, 17, 25, 49, 25, 22, 24, 110, 120, 107, 3, 82, 66, 75, 86, 85, 115, 110, 56, 52,
                                      39, 86, 23, 36, 71, 20, 73, 113, 25, 114, 56, 125, 80, 95, 82, 31, 63, 99, 62, 23, 55, 30,
                                      99, 42, 121, 15, 24, 97, 87, 81, 67, 43, 21, 13, 9, 33, 29, 117, 10, 114, 61, 98, 15, 78,
                                      108, 48, 97, 1, 3, 78, 109, 57, 46, 47, 56, 50, 66, 81, 77, 17, 128, 68, 121, 47, 91, 114,
                                      125, 51, 108, 31, 15, 47, 78, 109, 115, 113, 26, 53, 97, 1, 111, 103, 58, 106, 68, 11,
                                      104, 22, 79, 61, 127, 86, 39, 33, 123, 102, 39, 64, 41, 119, 120, 61, 29, 94, 68, 36, 12};
    std::vector<float> sinHostData = {46, 56, 56, 101, 66, 10, 96, 16, 86, 57, 102, 66, 12, 105, 76, 58, 90, 6, 79, 128, 126,
                                      82, 41, 3, 45, 7, 66, 4, 46, 22, 31, 26, 37, 63, 97, 84, 91, 90, 47, 77, 90, 34, 41, 83,
                                      91, 108, 120, 13, 90, 32, 85, 37, 119, 31, 51, 82, 122, 125, 7, 116, 121, 108, 38, 56,
                                      100, 20, 97, 119, 10, 4, 53, 13, 46, 82, 103, 119, 124, 80, 23, 67, 78, 56, 119, 122, 40,
                                      58, 128, 27, 30, 52, 71, 42, 123, 69, 4, 5, 116, 97, 38, 107, 8, 4, 65, 120, 40, 22, 60,
                                      44, 48, 66, 68, 125, 4, 93, 112, 112, 113, 90, 94, 23, 104, 39, 85, 84, 64, 128, 96, 119};
    std::vector<float> outHostData(128, 0);                                      

    // 创建x aclTensor
    ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // 创建cos aclTensor
    ret = CreateAclTensor(cosHostData, cosShape, &cosDeviceAddr, aclDataType::ACL_FLOAT, &cos);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // 创建sin aclTensor
    ret = CreateAclTensor(sinHostData, sinShape, &sinDeviceAddr, aclDataType::ACL_FLOAT, &sin);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // 创建out aclTensor
    ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
    CHECK_RET(ret == ACL_SUCCESS, return ret);    

    // 3. 调用CANN算子库API,需要修改为具体的API
    uint64_t workspaceSize = 0;
    aclOpExecutor* executor;
    // 调用aclnnRotaryPositionEmbedding第一段接口
    ret = aclnnRotaryPositionEmbeddingGetWorkspaceSize(x, cos, sin, mode, out, &workspaceSize, &executor);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRotaryPositionEmbeddingGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
    // 根据第一段接口计算出的workspaceSize申请device内存
    void* workspaceAddr = nullptr;
    if (workspaceSize > 0) {
        ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret;);
    }
    // 调用aclnnRotaryPositionEmbedding第二段接口
    ret = aclnnRotaryPositionEmbedding(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRotaryPositionEmbedding failed. ERROR: %d\n", ret); return ret);
    // 4. 固定写法,同步等待任务执行结束
    ret = aclrtSynchronizeStream(stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
    // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
    auto size = GetShapeSize(outShape);
    std::vector<float> resultData(size, 0);
    ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(float),
                      ACL_MEMCPY_DEVICE_TO_HOST);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);

    for (int64_t i = 0; i < size; i++) {
        LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
    }

    // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
    aclDestroyTensor(x);
    aclDestroyTensor(cos);
    aclDestroyTensor(sin);
    aclDestroyTensor(out);

    // 7. 释放device 资源
    aclrtFree(xDeviceAddr);
    aclrtFree(cosDeviceAddr);
    aclrtFree(sinDeviceAddr);
    aclrtFree(outDeviceAddr);
    if (workspaceSize > 0) {
      aclrtFree(workspaceAddr);
    }
    aclrtDestroyStream(stream);
    aclrtResetDevice(deviceId);
    aclFinalize();

    return 0;
}

</details>

<details>
<summary><code>[Bash: git -C /root/workspace/hyper-parallel show HEAD --name-only | grep sparse_flash]</code></summary>

(Bash completed with no output)


</details>

<details>
<summary><code>[Bash: grep -r "RotaryPositionEmbedding\|rotary_position_embedding" /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_]</code></summary>

(Bash completed with no output)


</details>

<details>
<summary><code>[Bash: grep -r "RotaryPositionEmbedding\|rotary_position_embedding" /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/ | head ]</code></summary>

/root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/tensor_func_utils.h: kRotaryPositionEmbeddingReg, /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/tensor_func_utils.h: kRotaryPositionEmbeddingGradReg, /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.h:PyObject* PyboostRotaryPositionEmbeddingBase(const PrimitivePtr &prim, PyObject* args); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.h:PyObject* PyboostRotaryPositionEmbeddingGradBase(const PrimitivePtr &prim, PyObject* args); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc:PyObject* PyboostRotaryPositionEmbeddingBase(const PrimitivePtr &prim, PyObject* args) { /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: static pynative::Converter converter(&ops::gRotaryPositionEmbedding); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: auto op_call = std::make_shared("RotaryPositionEmbedding", [prim](const py::args &args, const py::kwargs &kwargs){ /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return py::reinterpret_stealpy::object(PyboostRotaryPositionEmbeddingBase(prim, list_args.ptr())); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return PyboostRotaryPositionEmbeddingOp(prim, converter.source_type(), x, cos, sin, mode); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return PyboostRotaryPositionEmbeddingOp(prim, converter.source_type(), x, cos, sin, mode); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc:PyObject* PyboostRotaryPositionEmbeddingGradBase(const PrimitivePtr &prim, PyObject* args) { /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: static pynative::Converter converter(&ops::gRotaryPositionEmbeddingGrad); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: auto op_call = std::make_shared("RotaryPositionEmbeddingGrad", [prim](const py::args &args, const py::kwargs &kwargs){ /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return py::reinterpret_stealpy::object(PyboostRotaryPositionEmbeddingGradBase(prim, list_args.ptr())); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return PyboostRotaryPositionEmbeddingGradOp(prim, converter.source_type(), dy, cos, sin, dx, mode); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_api.cc: return PyboostRotaryPositionEmbeddingGradOp(prim, converter.source_type(), dy, cos, sin, dx, mode); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_registry.cc:py::object PyboostRotaryPositionEmbedding(const py::args &args) { /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_registry.cc: auto res = PyboostRotaryPositionEmbeddingBase(prim, args[1].ptr()); /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_registry.cc:class RotaryPositionEmbeddingPrimAdapter: public PrimitiveFunctionAdapter { /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_registry.cc: RotaryPositionEmbeddingPrimAdapter() : PrimitiveFunctionAdapter() {}


</details>

<details>
<summary><code>[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py]</code></summary>

1 # Copyright 2026 Huawei Technologies Co., Ltd 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ============================================================================ 15 """Distributed implementation for npu_sparse_flash_attention operator.""" 16 import copy 17 from typing import Callable, Optional, Tuple 18 19 from hyper_parallel.core.dtensor.dtensor import DTensor 20 from hyper_parallel.core.dtensor.layout import Layout 21 from .parallel_ops import DistributedOp 22 from .parallel_npu_dense_lightning_indexer_softmax_lse import _adjust_bsnd_key, _adjust_tnd_seq_lens 23 24 _MAX_INT64 = 9223372036854775807 25 26 # Maps layout_str -> tensor role -> {dim_index: dim_label} for replicated-dim checks. 27 # 'q' = query, 'k' = key, 'v' = value, 'si' = sparse_indices. 28 # N1 (head num of query) is forbidden from sharding due to severe performance impact. 29 _REPLICATED_DIMS = { 30 'BSND': { 31 'q': {2: 'N1', 3: 'D'}, 32 'k': {1: 'S2', 2: 'N2', 3: 'D'}, 33 'v': {1: 'S2', 2: 'N2', 3: 'D'}, 34 'si': {2: 'N2', 3: 'sparse_size'}, 35 }, 36 'TND': { 37 'q': {1: 'N1', 2: 'D'}, 38 'k': {1: 'N2', 2: 'D'}, 39 'v': {1: 'N2', 2: 'D'}, 40 'si': {1: 'N2', 2: 'sparse_size'}, 41 }, 42 } 43 44 45 def _normalize_sfa_args( 46 query, 47 key, 48 value, 49 sparse_indices, 50 scale_value, 51 block_table=None, 52 actual_seq_lengths_query=None, 53 actual_seq_lengths_kv=None, 54 query_rope=None, 55 key_rope=None, 56 sparse_block_size=1, 57 layout_query='BSND', 58 layout_kv='BSND', 59 sparse_mode=3, 60 pre_tokens=_MAX_INT64, 61 next_tokens=_MAX_INT64, 62 attention_mode=2, 63 return_softmax_lse=False): 64 """Normalize positional and keyword arguments into a canonical positional tuple. 65 66 Args: 67 query: Query tensor. 68 key: Key tensor. 69 value: Value tensor. 70 sparse_indices: Sparse index tensor (int32). 71 scale_value: Scaling factor (float). 72 block_table: Optional PageAttention block mapping table. 73 actual_seq_lengths_query: Actual query sequence lengths per batch. 74 actual_seq_lengths_kv: Actual KV sequence lengths per batch. 75 query_rope: Optional MLA query rope tensor. 76 key_rope: Optional MLA key rope tensor. 77 sparse_block_size: Block size for sparse computation. 78 layout_query: Query layout string ('BSND' or 'TND'). 79 layout_kv: KV layout string ('BSND', 'TND', or 'PA_BSND'). 80 sparse_mode: Sparse attention mode. 81 pre_tokens: Preceding token window size. 82 next_tokens: Following token window size. 83 attention_mode: Attention mode (0 or 2 for MLA-absorb). 84 return_softmax_lse: Whether to return softmax max/sum. 85 86 Returns: 87 tuple: (positional_args_tuple, empty_kwargs_dict) 88 """ 89 return ( 90 query, key, value, sparse_indices, scale_value, 91 block_table, actual_seq_lengths_query, actual_seq_lengths_kv, 92 query_rope, key_rope, sparse_block_size, 93 layout_query, layout_kv, sparse_mode, 94 pre_tokens, next_tokens, attention_mode, return_softmax_lse, 95 ), {} 96 97 98 def _to_local(t): 99 """Extract local tensor from DTensor, or pass through non-DTensor values.""" 100 if isinstance(t, DTensor): 101 return t.to_local() 102 return t 103 104 105 class SparseFlashAttentionDistributedOp(DistributedOp): 106 """Distributed operator for npu_sparse_flash_attention. 107 108 Supports BSND and TND input layouts on both MindSpore 109 and PyTorch / torch_npu backends. 110 111 Both frameworks provide built-in forward and backward implementations; 112 this class handles only the distributed dispatch (layout inference and 113 optional TND+CP sequence-length adjustment). 114 115 Output shapes relative to inputs: 116 - BSND: query (B, S1, N1, D) → attention_out (B, S1, N1, D), 117 softmax_max/sum (B, N2, S1, N1/N2) 118 - TND: query (T1, N1, D) → attention_out (T1, N1, D), 119 softmax_max/sum (N2, T1, N1/N2) 120 121 Sharding constraints: 122 - N1 (query head dim) must be replicated — TP on this dim is forbidden 123 due to severe performance impact. 124 - Key/value S2 (or T2), N2, and D dims must be replicated. 125 - sparse_indices N2 and sparse_size dims must be replicated. 126 - PA_BSND layout is not supported in distributed mode. 127 128 Context parallelism: 129 - BSND+CP: k, v, and key_rope are sliced to the causal window 130 [:, :S1_local*(split_id+1), :, :] before calling the kernel, matching the 131 MindFormers adjust_bsnd_input logic. sparse_indices from lightning_indexer are 132 generated with the same truncation, so they remain valid for the sliced k. 133 - TND+CP: adjusts actual_seq_lengths_query/kv per rank using 134 _adjust_tnd_seq_lens (same logic as dsa_attention.py). 135 """ 136 137 @staticmethod 138 def _infer_softmax_layout(q_layout: Layout, layout_str: str) -> Layout: 139 """Build the output layout for softmax_max and softmax_sum. 140 141 BSND: query (B, S1, N1, D) → softmax (B, N2, S1, N1/N2) 142 tensor_map: (q_tm[0], -1, q_tm[1], -1) 143 TND: query (T1, N1, D) → softmax (N2, T1, N1/N2) 144 tensor_map: (-1, q_tm[0], -1) 145 146 N2 and N1/N2 are always replicated because N2=1 and N1 is forbidden 147 from sharding. 148 149 Args: 150 q_layout: Layout of the query input. 151 layout_str: 'BSND' or 'TND'. 152 153 Returns: 154 Layout for softmax_max / softmax_sum. 155 """ 156 q_tm = q_layout.tensor_map 157 out_layout = Layout.from_device_mesh(q_layout.mesh) 158 if layout_str == 'BSND': 159 out_tm = (q_tm[0], -1, q_tm[1], -1) 160 else: 161 out_tm = (-1, q_tm[0], -1) 162 out_layout.set_tensor_map(out_tm) 163 out_layout.tensor_map_to_placement() 164 return out_layout 165 166 def preprocess(self, args: tuple, kwargs: dict) -> tuple: 167 """Extract local tensors and build the layout cache. 168 169 Args: 170 args: Positional arguments (may contain DTensors). 171 kwargs: Keyword arguments. 172 173 Returns: 174 tuple: (local_args, local_kwargs, cache_values) where 175 local_args = (query_local, key_local, value_local, 176 sparse_indices_local, scale_value), 177 local_kwargs contains all remaining arguments, 178 cache_values = [q_layout, k_layout, v_layout, si_layout, layout_query_str]. 179 """ 180 norm_args, _ = _normalize_sfa_args(*args, **kwargs) 181 query = norm_args[0] 182 key = norm_args[1] 183 value = norm_args[2] 184 sparse_indices = norm_args[3] 185 scale_value = norm_args[4] 186 layout_query_str = norm_args[11] 187 188 local_args = ( 189 _to_local(query), 190 _to_local(key), 191 _to_local(value), 192 _to_local(sparse_indices), 193 scale_value, 194 ) 195 local_kwargs = { 196 'block_table': _to_local(norm_args[5]), 197 'actual_seq_lengths_query': _to_local(norm_args[6]), 198 'actual_seq_lengths_kv': _to_local(norm_args[7]), 199 'query_rope': _to_local(norm_args[8]), 200 'key_rope': _to_local(norm_args[9]), 201 'sparse_block_size': norm_args[10], 202 'layout_query': norm_args[11], 203 'layout_kv': norm_args[12], 204 'sparse_mode': norm_args[13], 205 'pre_tokens': norm_args[14], 206 'next_tokens': norm_args[15], 207 'attention_mode': norm_args[16], 208 'return_softmax_lse': norm_args[17], 209 } 210 211 cache_values = [ 212 query.layout, 213 key.layout, 214 value.layout, 215 sparse_indices.layout, 216 layout_query_str, 217 ] 218 return local_args, local_kwargs, cache_values 219 220 @staticmethod 221 def _validate_input_layouts( 222 q_layout: Layout, 223 k_layout: Layout, 224 v_layout: Layout, 225 si_layout: Layout, 226 layout_str: str, 227 ) -> None: 228 """Validate sharding constraints for all input tensors. 229 230 BSND rules (shapes: (B,S1,N1,D) / (B,S2,N2,D) / (B,S2,N2,D) / (B,S1,N2,sparse_size)): 231 - N1 (dim 2) and D (dim 3) of query must be replicated. 232 - S2 (dim 1), N2 (dim 2), D (dim 3) of key and value must be replicated. 233 - N2 (dim 2) and sparse_size (dim 3) of sparse_indices must be replicated. 234 - B sharding of key, value, and sparse_indices must match query. 235 - S1 sharding of sparse_indices must match query. 236 237 TND rules (shapes: (T1,N1,D) / (T2,N2,D) / (T2,N2,D) / (T1,N2,sparse_size)): 238 - N1 (dim 1) and D (dim 2) of query must be replicated. 239 - N2 (dim 1) and D (dim 2) of key and value must be replicated. 240 - N2 (dim 1) and sparse_size (dim 2) of sparse_indices must be replicated. 241 - T2 sharding of key and value must match. 242 - T1 sharding of sparse_indices must match query. 243 244 PA_BSND is not supported in distributed mode. 245 246 Args: 247 q_layout: Layout of query. 248 k_layout: Layout of key. 249 v_layout: Layout of value. 250 si_layout: Layout of sparse_indices. 251 layout_str: 'BSND' or 'TND'. 252 253 Raises: 254 ValueError: If layout_str is 'PA_BSND', if any required dimension is 255 sharded, or if batch/sequence consistency constraints are violated. 256 """ 257 if layout_str == 'PA_BSND': 258 raise ValueError( 259 "For npu_sparse_flash_attention, PA_BSND layout is not supported " 260 "in distributed mode." 261 ) 262 263 op = "npu_sparse_flash_attention" 264 q_tm = q_layout.tensor_map 265 k_tm = k_layout.tensor_map 266 v_tm = v_layout.tensor_map 267 si_tm = si_layout.tensor_map 268 tms = { 269 'q': (q_tm, 'query'), 270 'k': (k_tm, 'key'), 271 'v': (v_tm, 'value'), 272 'si': (si_tm, 'sparse_indices'), 273 } 274 for role, dims in _REPLICATED_DIMS.get(layout_str, {}).items(): 275 tm, tensor_name = tms[role] 276 for dim, label in dims.items(): 277 if tm[dim] != -1: 278 raise ValueError( 279 f"For {op}, {label} (dim {dim}) of {tensor_name} should be replicated, " 280 f"but got tensor_map={tm}" 281 ) 282 283 if layout_str == 'BSND': 284 if q_tm[0] != k_tm[0]: 285 raise ValueError( 286 f"For {op}, B (dim 0) sharding of key should match query, " 287 f"but got query={q_tm[0]}, key={k_tm[0]}" 288 ) 289 if q_tm[0] != v_tm[0]: 290 raise ValueError( 291 f"For {op}, B (dim 0) sharding of value should match query, " 292 f"but got query={q_tm[0]}, value={v_tm[0]}" 293 ) 294 if q_tm[0] != si_tm[0]: 295 raise ValueError( 296 f"For {op}, B (dim 0) sharding of sparse_indices should match query, " 297 f"but got query={q_tm[0]}, sparse_indices={si_tm[0]}" 298 ) 299 if q_tm[1] != si_tm[1]: 300 raise ValueError( 301 f"For {op}, S1 (dim 1) sharding of sparse_indices should match query, " 302 f"but got query={q_tm[1]}, sparse_indices={si_tm[1]}" 303 ) 304 else: # TND 305 if k_tm[0] != v_tm[0]: 306 raise ValueError( 307 f"For {op}, T2 (dim 0) sharding of value should match key, " 308 f"but got key={k_tm[0]}, value={v_tm[0]}" 309 ) 310 if q_tm[0] != si_tm[0]: 311 raise ValueError( 312 f"For {op}, T1 (dim 0) sharding of sparse_indices should match query, " 313 f"but got query={q_tm[0]}, sparse_indices={si_tm[0]}" 314 ) 315 316 def infer_layout(self, cache_values: list) -> Tuple[tuple, None]: 317 """Infer output layouts for all three outputs. 318 319 Rules: 320 1. PA_BSND layout is rejected. 321 2. Partial inputs are not allowed on any of the four primary tensors. 322 3. Sharding constraints are validated (see _validate_input_layouts). 323 4. attention_out inherits query layout (deep copy). 324 5. softmax_max and softmax_sum share the same layout derived from 325 query layout with N2 and N1/N2 dims always replicated. 326 6. All three output layouts are independent deep copies. 327 328 Args: 329 cache_values: [q_layout, k_layout, v_layout, si_layout, layout_str] 330 331 Returns: 332 tuple: ((attn_layout, softmax_max_layout, softmax_sum_layout), None) 333 334 Raises: 335 ValueError: If PA_BSND layout, any input has Partial status, or 336 sharding constraints are violated. 337 """ 338 q_layout = cache_values[0] 339 k_layout = cache_values[1] 340 v_layout = cache_values[2] 341 si_layout = cache_values[3] 342 layout_str = cache_values[4] 343 344 self._check_partial_inputs([q_layout, k_layout, v_layout, si_layout]) 345 self._validate_input_layouts(q_layout, k_layout, v_layout, si_layout, layout_str) 346 347 attn_layout = copy.deepcopy(q_layout) 348 softmax_layout = self._infer_softmax_layout(q_layout, layout_str) 349 return (attn_layout, softmax_layout, copy.deepcopy(softmax_layout)), None 350 351 def get_expand_impl( # pylint: disable=W0237 352 self, 353 func: Optional[Callable], 354 infer_result: tuple, 355 cache_values: list, 356 extra_args: Optional[tuple] = None, 357 ) -> Optional[Callable]: 358 """Return a custom callable if context-parallel adjustment is needed. 359 360 BSND (S1 not sharded): returns None — k/v are Replicated; sparse_indices 361 reference the full k directly. 362 BSND+CP (S1 sharded): wraps func to slice k, v, and key_rope to the 363 causal window k[:, :S1_local*(split_id+1), :, :] before calling 364 the kernel. Mirrors MindFormers adjust_bsnd_input logic, ensuring 365 that sparse_indices produced by lightning_indexer (which applies the 366 same truncation) remain valid. 367 TND+CP: wraps func to adjust actual_seq_lengths_query/kv per rank, 368 using the same algorithm as dsa_attention._sparse_flash_attention_forward. 369 TND (no CP): wraps func to clamp seq_lens to local T1 slice. 370 371 Args: 372 func: The underlying op callable. 373 infer_result: Output from infer_layout. 374 cache_values: [q_layout, k_layout, v_layout, si_layout, layout_str]. 375 extra_args: Unused; kept for interface compatibility. 376 377 Returns: 378 Callable wrapper or None. 379 """ 380 q_layout = cache_values[0] 381 k_layout = cache_values[1] 382 layout_str = cache_values[4] 383 384 if layout_str == 'BSND': 385 if q_layout.tensor_map[1] == -1: 386 # S1 not sharded: pure DP or fully replicated. 387 # k/v are Replicate on the CP dimension, so sparse_indices reference 388 # the full k directly; no truncation needed. 389 return None 390 split_id = q_layout.get_split_id(1) 391 392 def _bsnd_cp_impl(*args, **kwargs): 393 local_q, local_k, local_v = args[0], args[1], args[2] 394 s1_local = local_q.shape[1] 395 sliced_k = _adjust_bsnd_key(local_k, s1_local, split_id) 396 sliced_v = _adjust_bsnd_key(local_v, s1_local, split_id) 397 key_rope = kwargs.get('key_rope') 398 new_kwargs = ( 399 {**kwargs, 'key_rope': _adjust_bsnd_key(key_rope, s1_local, split_id)} 400 if key_rope is not None else kwargs 401 ) 402 return func(local_q, sliced_k, sliced_v, *args[3:], **new_kwargs) 403 404 return _bsnd_cp_impl 405 406 # TND: CP applies when q's T1 is sharded more finely than k's T2. 407 q_split = q_layout.get_dim_split_num(0) 408 k_split = k_layout.get_dim_split_num(0) 409 split_id = q_layout.get_split_id(0) if q_split > k_split else 0 410 cp_size = q_split // k_split if k_split > 0 else 1 411 cp_rank = split_id % cp_size if cp_size > 1 else 0 412 413 def _tnd_cp_impl(*args, **kwargs): 414 local_q, local_k = args[0], args[1] 415 qlen_tensor = kwargs.get('actual_seq_lengths_query') 416 klen_tensor = kwargs.get('actual_seq_lengths_kv') 417 if qlen_tensor is None or klen_tensor is None: 418 return func(*args, **kwargs) 419 adj_q, adj_k = _adjust_tnd_seq_lens( 420 local_q, local_k, qlen_tensor, klen_tensor, 421 cp_rank=cp_rank, 422 ) 423 return func(*args, **{ 424 **kwargs, 425 'actual_seq_lengths_query': adj_q, 426 'actual_seq_lengths_kv': adj_k, 427 }) 428 429 return _tnd_cp_impl 430


</details>

<details>
<summary><code>[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/npu_sparse_flash_attention_ops.yaml]</code></summary>

1 npu_sparse_flash_attention: 2 dist_op_name: _npu_sparse_flash_attention_dist_op 3 distributed_op_class: SparseFlashAttentionDistributedOp 4 distributed_op_file: parallel_npu_sparse_flash_attention 5 6 SparseFlashAttention: 7 dist_op_name: _npu_sparse_flash_attention_dist_op 8 distributed_op_class: SparseFlashAttentionDistributedOp 9 distributed_op_file: parallel_npu_sparse_flash_attention 10


</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py]</code></summary>

Output too large (30.2KB). Full output saved to: /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results/b29kofv4w.txt

Preview (first 2KB):

Copyright 2026 Huawei Technologies Co., Ltd

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.

============================================================================

"""MindSpore distributed ST for npu_sparse_flash_attention.

Pipeline: ops.lightning_indexer(q_idx, k_idx, w) → sparse_indices → ops.sparse_flash_attention(q, k, v, sparse_indices, ...).

The two ops use different head_dim projections of the same sequence:

  • lightning_indexer : q_idx/k_idx head_dim = D_IDX = 128 (kernel constraint)
  • sparse_flash_attention : q/k head_dim = D_DIM = 512 (MLA attention_mode=2 constraint)

For BSND+CP the lightning_indexer distributed op slices k_idx to the causal window k_idx[:, :S1_local*(split_id+1), :, :]; the sparse_flash_attention distributed op applies the same slice to k/v/key_rope, so sparse_indices remain valid. This mirrors MindFormers adjust_bsnd_input logic.

Distributed sharding patterns verified against MindFormers dsa_attention.py shard():

  • BSND: q/si sharded on B (dp) and/or S1 (cp); k/v sharded on B (dp) only.
  • TND: q/si sharded on T1 = dp*cp combined; k/v sharded on T2 = dp only. """ import numpy as np import mindspore as ms import mindspore.communication.management as D from mindspore import Tensor, ops from mindspore.ops import sparse_flash_attention from hyper_parallel import init_device_mesh from hyper_parallel.core.dtensor.dtensor import DTensor, distribute_tensor ...

</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_npu_sparse_flash_attention_shard_in_python.py]</code></summary>

Copyright 2026 Huawei Technologies Co., Ltd

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.

============================================================================

"""Test runner for npu_sparse_flash_attention distributed ST (MindSpore).""" from pathlib import Path

from tests.common.mark_utils import arg_mark from tests.common.parallel_case import parallel_run, MindSporeCase

IMPL_FILE = str( Path(file).resolve().parent / "npu_sparse_flash_attention_shard_in_python.py" )

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential") def test_parallel_sfa_ms_group1(): """ Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND replicated and DP, 8 cards) Description: 1. test_sfa_bsnd_replicated — BSND all replicated, fwd+bwd vs standalone 2. test_sfa_bsnd_dp — BSND B-dim data parallel, fwd+bwd vs standalone 3. test_sfa_tnd_replicated — TND all replicated, fwd+bwd vs standalone 4. test_sfa_tnd_dp — TND T1-dim data parallel (q AND k Shard(0)); local seq_lens per rank; q_split==k_split so no CP seq_len adjustment. Expectation: Run success. """ parallel_run([ MindSporeCase(IMPL_FILE, "test_sfa_bsnd_replicated", 19200, 2, 2, 2), MindSporeCase(IMPL_FILE, "test_sfa_bsnd_dp", 19201, 2, 2, 2), MindSporeCase(IMPL_FILE, "test_sfa_tnd_replicated", 19203, 2, 2, 2), MindSporeCase(IMPL_FILE, "test_sfa_tnd_dp", 19202, 2, 2, 2), ])

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential") def test_parallel_sfa_ms_group2(): """ Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND CP, 4 cards) Description: 1. test_sfa_bsnd_cp — BSND, q/si/q_rope Shard(1) on S1, k/v/k_rope Replicate; validates TP-as-CP pattern (MindFormers: S1 sharded by cp_tp combined) 2. test_sfa_tnd_cp — TND, q/si/q_rope Shard(0) on T1, k/v/k_rope Replicate; seq_lens adjusted per rank by _tnd_cp_impl Expectation: Run success. """ parallel_run([ MindSporeCase(IMPL_FILE, "test_sfa_bsnd_cp", 19205, 2, 2, 2), MindSporeCase(IMPL_FILE, "test_sfa_tnd_cp", 19204, 2, 2, 2), ])

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level0", card_mark="allcards", essential_mark="essential") def test_parallel_sfa_ms_group3(): """ Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND dp+cp 2-D mesh, 8 cards) Description: 1. test_sfa_bsnd_dp_cp — 4-card 2-D mesh (dp=2, cp=2); B sharded by dp, S1 sharded by cp; k/v/key_rope replicated on cp. Mirrors MindFormers BSND shard() spec. 2. test_sfa_tnd_dp_cp — 4-card 2-D mesh (dp=2, cp=2); T1 of q/si/q_rope sharded by dp AND cp (4-way split); T2 of k/v/k_rope sharded by dp only (2-way split). Mirrors MindFormers TND shard() spec with dp_cp_tp combined sequence split. Expectation: Run success. """ parallel_run([ MindSporeCase(IMPL_FILE, "test_sfa_bsnd_dp_cp", 19206, 4, 4, 2), MindSporeCase(IMPL_FILE, "test_sfa_tnd_dp_cp", 19207, 4, 4, 2), ])


</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py]</code></summary>

Copyright 2026 Huawei Technologies Co., Ltd

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.

============================================================================

"""Unit tests for SparseFlashAttentionDistributedOp.""" import os import unittest from unittest.mock import MagicMock, patch

import numpy as np

os.environ["HYPER_PARALLEL_PLATFORM"] = "torch"

from hyper_parallel.core.dtensor.dtensor import _build_layout, _LAYOUT_CACHE from hyper_parallel.core.dtensor.placement_types import Shard, Replicate from hyper_parallel.core.shard.ops.parallel_npu_sparse_flash_attention import ( SparseFlashAttentionDistributedOp, _normalize_sfa_args, ) from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op from hyper_parallel.core.dtensor.device_mesh import init_device_mesh, _DEVICE_MESH_MAP from hyper_parallel.platform.platform import EXISTING_COMM_GROUPS

class TestSparseFlashAttentionDistributedOp(unittest.TestCase): """Unit tests for SparseFlashAttentionDistributedOp."""

def setUp(self):
    """Clear global state before each test."""
    EXISTING_COMM_GROUPS.clear()
    _DEVICE_MESH_MAP.clear()
    _LAYOUT_CACHE.clear()

def tearDown(self):
    """Clear global state after each test."""
    EXISTING_COMM_GROUPS.clear()
    _DEVICE_MESH_MAP.clear()
    _LAYOUT_CACHE.clear()

def _setup_mock_platform(self, mock_platform, world_size=8):
    """Configure mock platform for mesh creation."""
    mock_platform.get_rank.return_value = 0
    mock_platform.get_world_size.return_value = world_size
    mock_platform.split_group.return_value = MagicMock()
    mock_platform.tensor_to_numpy.side_effect = (
        lambda t: t.asnumpy() if hasattr(t, "asnumpy") else np.array(t)
    )

def _make_1d_mesh(self, mock_platform, size=8, name="dp"):
    """Return a 1-D mesh of given size."""
    self._setup_mock_platform(mock_platform, world_size=size)
    return init_device_mesh(device_type="npu", mesh_shape=(size,), mesh_dim_names=(name,))

def _make_2x4_dp_cp_mesh(self, mock_platform):
    """Return a 2×4 (dp, cp) mesh — 8 devices."""
    self._setup_mock_platform(mock_platform, world_size=8)
    return init_device_mesh(device_type="npu", mesh_shape=(2, 4), mesh_dim_names=("dp", "cp"))

@staticmethod
def _get_op():
    return get_distributed_op("npu_sparse_flash_attention")

@staticmethod
def _get_op_ms():
    return get_distributed_op("SparseFlashAttention")

# ------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------

def _mock_layouts_bsnd(self, q_tm, k_tm, v_tm=None, si_tm=None):
    """Return (q, k, v, si) mock layouts with given tensor_maps for BSND."""
    def _mock(tm):
        m = MagicMock()
        m.is_partial.return_value = False
        m.tensor_map = tm
        return m
    if v_tm is None:
        v_tm = k_tm
    if si_tm is None:
        si_tm = (q_tm[0], q_tm[1], -1, -1)
    return _mock(q_tm), _mock(k_tm), _mock(v_tm), _mock(si_tm)

def _mock_layouts_tnd(self, q_tm, k_tm, v_tm=None, si_tm=None):
    """Return (q, k, v, si) mock layouts with given tensor_maps for TND."""
    def _mock(tm):
        m = MagicMock()
        m.is_partial.return_value = False
        m.tensor_map = tm
        return m
    if v_tm is None:
        v_tm = k_tm
    if si_tm is None:
        si_tm = (q_tm[0], -1, -1)
    return _mock(q_tm), _mock(k_tm), _mock(v_tm), _mock(si_tm)

# ------------------------------------------------------------------
# _normalize_sfa_args
# ------------------------------------------------------------------

def test_normalize_args_defaults_1(self):
    """
    Feature: _normalize_sfa_args fills in default values.
    Description: Call with only the 5 mandatory positional args.
    Expectation: Optional args get correct defaults.
    """
    q, k, v, si = object(), object(), object(), object()
    args, kwargs = _normalize_sfa_args(q, k, v, si, 1.0)
    self.assertIs(args[0], q)
    self.assertIs(args[1], k)
    self.assertIs(args[2], v)
    self.assertIs(args[3], si)
    self.assertEqual(args[4], 1.0)
    self.assertIsNone(args[5], msg=f"block_table default should be None, got {args[5]}")
    self.assertEqual(args[11], 'BSND', msg=f"layout_query default should be 'BSND', got {args[11]}")
    self.assertEqual(kwargs, {}, msg=f"kwargs should be empty, got {kwargs}")

def test_normalize_args_layout_tnd_2(self):
    """
    Feature: _normalize_sfa_args accepts layout_query keyword.
    Description: Pass layout_query='TND' as kwarg.
    Expectation: args[11] == 'TND'.
    """
    q, k, v, si = object(), object(), object(), object()
    args, _ = _normalize_sfa_args(q, k, v, si, 0.5, layout_query='TND')
    self.assertEqual(args[11], 'TND', msg=f"args[11] should be 'TND', got {args[11]}")

def test_normalize_args_returns_empty_kwargs_3(self):
    """
    Feature: _normalize_sfa_args always returns empty kwargs dict.
    Description: Pass any combination of kwargs.
    Expectation: Returned kwargs dict is always empty.
    """
    q, k, v, si = object(), object(), object(), object()
    _, kwargs = _normalize_sfa_args(q, k, v, si, 0.5, layout_query='TND', sparse_mode=0)
    self.assertEqual(kwargs, {}, msg=f"kwargs should be empty, got {kwargs}")

# ------------------------------------------------------------------
# YAML registration
# ------------------------------------------------------------------

def test_yaml_registration_torch_6(self):
    """
    Feature: YAML loader registers SparseFlashAttentionDistributedOp (torch name).
    Description: Call get_distributed_op with snake_case op name.
    Expectation: Returns a SparseFlashAttentionDistributedOp instance.
    """
    op = self._get_op()
    self.assertIsNotNone(op, msg="npu_sparse_flash_attention should be registered")
    self.assertIsInstance(
        op, SparseFlashAttentionDistributedOp,
        msg=f"Expected SparseFlashAttentionDistributedOp, got {type(op)}"
    )

def test_yaml_registration_mindspore_7(self):
    """
    Feature: YAML loader registers SparseFlashAttentionDistributedOp (MindSpore name).
    Description: Call get_distributed_op with CamelCase op name.
    Expectation: Returns a SparseFlashAttentionDistributedOp instance.
    """
    op = self._get_op_ms()
    self.assertIsNotNone(op, msg="SparseFlashAttention should be registered")
    self.assertIsInstance(
        op, SparseFlashAttentionDistributedOp,
        msg=f"Expected SparseFlashAttentionDistributedOp, got {type(op)}"
    )

# ------------------------------------------------------------------
# infer_layout — BSND positive cases
# ------------------------------------------------------------------

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_bsnd_all_replicated_8(self, mock_platform):
    """
    Feature: infer_layout BSND all replicated produces all-(-1) tensor_maps.
    Description: All inputs replicated on 1-D size-1 mesh.
    Expectation: attention_out/softmax_max/softmax_sum all have fully -1 tensor_maps.
    """
    mesh = self._make_1d_mesh(mock_platform, size=1)
    q = _build_layout(mesh, (Replicate(),), 4)
    k = _build_layout(mesh, (Replicate(),), 4)
    v = _build_layout(mesh, (Replicate(),), 4)
    si = _build_layout(mesh, (Replicate(),), 4)

    op = self._get_op()
    (attn, smax, ssum), extra = op.infer_layout([q, k, v, si, 'BSND'])

    self.assertIsNone(extra)
    self.assertEqual(attn.tensor_map, (-1, -1, -1, -1),
                     msg=f"BSND replicated attn: expected (-1,-1,-1,-1), got {attn.tensor_map}")
    self.assertEqual(smax.tensor_map, (-1, -1, -1, -1),
                     msg=f"BSND replicated smax: expected (-1,-1,-1,-1), got {smax.tensor_map}")
    self.assertEqual(ssum.tensor_map, (-1, -1, -1, -1),
                     msg=f"BSND replicated ssum: expected (-1,-1,-1,-1), got {ssum.tensor_map}")

    # get_expand_impl returns None when S1 (dim 1) is not sharded (no CP).
    # For the replicated case, S1 is not sharded, so None is expected.
    assert op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'BSND']) is None, (
        f"BSND replicated get_expand_impl should return None (S1 not sharded), "
        f"got {op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'BSND'])}"
    )

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_bsnd_dp_success_9(self, mock_platform):
    """
    Feature: infer_layout BSND with B-dim data parallel.
    Description: All inputs B-sharded on 1-D dp mesh (size 4).
    Expectation: attention_out tensor_map[0]==0; softmax_max tensor_map==(0,-1,−1,−1).
    """
    mesh = self._make_1d_mesh(mock_platform, size=4, name="dp")
    q = _build_layout(mesh, (Shard(0),), 4)
    k = _build_layout(mesh, (Shard(0),), 4)
    v = _build_layout(mesh, (Shard(0),), 4)
    si = _build_layout(mesh, (Shard(0),), 4)

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'BSND'])

    self.assertEqual(attn.tensor_map, (0, -1, -1, -1),
                     msg=f"BSND DP attn: expected (0,-1,-1,-1), got {attn.tensor_map}")
    # softmax (B, N2, S1, N1/N2): B=q_tm[0]=0, N2=-1, S1=q_tm[1]=-1, N1/N2=-1
    self.assertEqual(smax.tensor_map, (0, -1, -1, -1),
                     msg=f"BSND DP smax: expected (0,-1,-1,-1), got {smax.tensor_map}")
    self.assertEqual(ssum.tensor_map, (0, -1, -1, -1),
                     msg=f"BSND DP ssum: expected (0,-1,-1,-1), got {ssum.tensor_map}")

    impl = op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'BSND'])
    self.assertIsNone(impl, msg=(
        f"BSND DP get_expand_impl should return None (S1 not sharded), got {impl}"
    ))

@patch("hyper_parallel.core.dtensor.layout.platform")
@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_bsnd_cp_success_10(self, mock_mesh_plat, mock_layout_plat):
    """
    Feature: infer_layout BSND with S1-dim context parallel.
    Description: q/si sharded on S1, k/v replicated; 1-D cp mesh.
    Expectation: attention_out tensor_map==(−1,0,−1,−1); softmax_max==(−1,−1,0,−1);
        get_expand_impl returns callable (BSND+CP slices k/v to causal window).
    """
    self._setup_mock_platform(mock_mesh_plat, world_size=4)
    mock_layout_plat.get_rank.return_value = 0

    mesh = init_device_mesh(device_type="npu", mesh_shape=(4,), mesh_dim_names=("cp",))
    q = _build_layout(mesh, (Shard(1),), 4)    # (B,S1,N1,D) → S1 sharded
    k = _build_layout(mesh, (Replicate(),), 4)
    v = _build_layout(mesh, (Replicate(),), 4)
    si = _build_layout(mesh, (Shard(1),), 4)   # S1 matches query

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'BSND'])

    # q_tm = (-1, 0, -1, -1)
    self.assertEqual(attn.tensor_map, (-1, 0, -1, -1),
                     msg=f"BSND CP attn: expected (-1,0,-1,-1), got {attn.tensor_map}")
    # softmax (B, N2, S1, N1/N2): q_tm[0]=-1, -1, q_tm[1]=0, -1
    self.assertEqual(smax.tensor_map, (-1, -1, 0, -1),
                     msg=f"BSND CP smax: expected (-1,-1,0,-1), got {smax.tensor_map}")

    # S1 is sharded → k/v are sliced to the causal window per rank.
    impl = op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'BSND'])
    assert callable(impl), (
        f"BSND CP get_expand_impl should return callable, got {type(impl)}"
    )

@patch("hyper_parallel.core.dtensor.layout.platform")
@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_bsnd_dp_cp_success_11(self, mock_mesh_plat, mock_layout_plat):
    """
    Feature: infer_layout BSND with B-dim DP and S1-dim CP.
    Description: 2×4 (dp, cp) mesh; q B-sharded on dp, S1-sharded on cp.
    Expectation: attention_out tensor_map==(1,0,−1,−1); softmax_max==(1,−1,0,−1);
        get_expand_impl returns callable (BSND+CP slices k/v to causal window).
    """
    self._setup_mock_platform(mock_mesh_plat, world_size=8)
    mock_layout_plat.get_rank.return_value = 0

    mesh = init_device_mesh(device_type="npu", mesh_shape=(2, 4), mesh_dim_names=("dp", "cp"))
    q = _build_layout(mesh, (Shard(0), Shard(1)), 4)    # (B,S1,N1,D)
    k = _build_layout(mesh, (Shard(0), Replicate()), 4)
    v = _build_layout(mesh, (Shard(0), Replicate()), 4)
    si = _build_layout(mesh, (Shard(0), Shard(1)), 4)   # B+S1 matches q

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'BSND'])

    # q_tm = (1, 0, -1, -1)
    self.assertEqual(attn.tensor_map, (1, 0, -1, -1),
                     msg=f"BSND DP+CP attn: expected (1,0,-1,-1), got {attn.tensor_map}")
    # softmax (B, N2, S1, N1/N2): (q_tm[0]=1, -1, q_tm[1]=0, -1)
    self.assertEqual(smax.tensor_map, (1, -1, 0, -1),
                     msg=f"BSND DP+CP smax: expected (1,-1,0,-1), got {smax.tensor_map}")
    self.assertEqual(ssum.tensor_map, (1, -1, 0, -1),
                     msg=f"BSND DP+CP ssum: expected (1,-1,0,-1), got {ssum.tensor_map}")

    # S1 is sharded → k/v are sliced to the causal window per rank.
    impl = op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'BSND'])
    assert callable(impl), (
        f"BSND DP+CP get_expand_impl should return callable, got {type(impl)}"
    )

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_output_independent_copies_12(self, mock_platform):
    """
    Feature: All three output layouts are independent deepcopy objects.
    Description: Check that returned layout objects are distinct.
    Expectation: attn, smax, ssum are all distinct objects.
    """
    mesh = self._make_1d_mesh(mock_platform, size=4)
    q = _build_layout(mesh, (Shard(0),), 4)
    k = _build_layout(mesh, (Shard(0),), 4)
    v = _build_layout(mesh, (Shard(0),), 4)
    si = _build_layout(mesh, (Shard(0),), 4)

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'BSND'])

    self.assertIsNot(attn, smax,
                     msg="attention_out and softmax_max must be distinct layout objects")
    self.assertIsNot(smax, ssum,
                     msg="softmax_max and softmax_sum must be distinct layout objects")

# ------------------------------------------------------------------
# infer_layout — TND positive cases
# ------------------------------------------------------------------

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_tnd_all_replicated_13(self, mock_platform):
    """
    Feature: infer_layout TND all replicated produces all-(-1) tensor_maps.
    Description: All inputs replicated on 1-D size-1 mesh.
    Expectation: attention_out/softmax_max/softmax_sum all have fully -1 tensor_maps.
    """
    mesh = self._make_1d_mesh(mock_platform, size=1)
    q = _build_layout(mesh, (Replicate(),), 3)
    k = _build_layout(mesh, (Replicate(),), 3)
    v = _build_layout(mesh, (Replicate(),), 3)
    si = _build_layout(mesh, (Replicate(),), 3)

    op = self._get_op()
    (attn, smax, ssum), extra = op.infer_layout([q, k, v, si, 'TND'])

    self.assertIsNone(extra)
    self.assertEqual(attn.tensor_map, (-1, -1, -1),
                     msg=f"TND replicated attn: expected (-1,-1,-1), got {attn.tensor_map}")
    # softmax (N2, T1, N1/N2): q_tm[0]=-1
    self.assertEqual(smax.tensor_map, (-1, -1, -1),
                     msg=f"TND replicated smax: expected (-1,-1,-1), got {smax.tensor_map}")
    self.assertEqual(ssum.tensor_map, (-1, -1, -1),
                     msg=f"TND replicated ssum: expected (-1,-1,-1), got {ssum.tensor_map}")

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_tnd_dp_success_14(self, mock_platform):
    """
    Feature: infer_layout TND with T1-dim data parallel.
    Description: query/si sharded on T1 (dim 0); 1-D dp mesh (size 4).
    Expectation: attention_out tensor_map==(0,-1,-1); softmax_max==(−1,0,−1).
    """
    mesh = self._make_1d_mesh(mock_platform, size=4, name="dp")
    q = _build_layout(mesh, (Shard(0),), 3)
    k = _build_layout(mesh, (Shard(0),), 3)
    v = _build_layout(mesh, (Shard(0),), 3)
    si = _build_layout(mesh, (Shard(0),), 3)

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'TND'])

    self.assertEqual(attn.tensor_map, (0, -1, -1),
                     msg=f"TND DP attn: expected (0,-1,-1), got {attn.tensor_map}")
    # softmax (N2, T1, N1/N2): (-1, q_tm[0]=0, -1)
    self.assertEqual(smax.tensor_map, (-1, 0, -1),
                     msg=f"TND DP smax: expected (-1,0,-1), got {smax.tensor_map}")
    self.assertEqual(ssum.tensor_map, (-1, 0, -1),
                     msg=f"TND DP ssum: expected (-1,0,-1), got {ssum.tensor_map}")

@patch("hyper_parallel.core.dtensor.layout.platform")
@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_tnd_cp_expand_impl_callable_15(self, mock_mesh_plat, mock_layout_plat):
    """
    Feature: get_expand_impl returns callable when q T1 sharded more than k (TND+CP).
    Description: q sharded on 8-device dp_cp mesh, k replicated → q_split=8 > k_split=1.
    Expectation: get_expand_impl returns a callable.
    """
    self._setup_mock_platform(mock_mesh_plat, world_size=8)
    mock_layout_plat.get_rank.return_value = 0

    mesh = init_device_mesh("npu", (8,), mesh_dim_names=("dp_cp",))
    q = _build_layout(mesh, (Shard(0),), 3)
    k = _build_layout(mesh, (Replicate(),), 3)
    v = _build_layout(mesh, (Replicate(),), 3)
    si = _build_layout(mesh, (Shard(0),), 3)

    op = self._get_op()
    result, _ = op.infer_layout([q, k, v, si, 'TND'])
    impl = op.get_expand_impl(None, result, [q, k, v, si, 'TND'])
    self.assertTrue(callable(impl),
                    msg=f"TND+CP get_expand_impl should return callable, got {type(impl)}")

@patch("hyper_parallel.core.dtensor.layout.platform")
@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_tnd_dp_cp_2d_mesh_expand_impl_callable_16(self, mock_mesh_plat, mock_layout_plat):
    """
    Feature: get_expand_impl returns callable for TND with 2-D dp+cp mesh.
    Description: 2×4 (dp, cp) mesh; q T1 sharded by BOTH dp and cp (combined 8-way
        split); k T2 sharded by dp only (2-way split). q_split=8 > k_split=2 triggers
        _tnd_cp_impl. Verifies the multi-axis get_split_id fix is plumbed correctly.
    Expectation: get_expand_impl returns callable; attention_out and softmax_max have
        multi-axis tensor_map entries for T1.
    """
    self._setup_mock_platform(mock_mesh_plat, world_size=8)
    mock_layout_plat.get_rank.return_value = 0

    mesh = init_device_mesh("npu", (2, 4), mesh_dim_names=("dp", "cp"))
    # dp AND cp both shard T1 of q/si → combined 8-way split
    q = _build_layout(mesh, (Shard(0), Shard(0)), 3)
    # dp shards T2 of k; cp Replicate → 2-way split
    k = _build_layout(mesh, (Shard(0), Replicate()), 3)
    v = _build_layout(mesh, (Shard(0), Replicate()), 3)
    si = _build_layout(mesh, (Shard(0), Shard(0)), 3)

    op = self._get_op()
    (attn, smax, ssum), _ = op.infer_layout([q, k, v, si, 'TND'])

    # attention_out = deepcopy(q_layout); T1 tensor_map[0] is a tuple of mesh axes
    # (cp axis=1 first, dp axis=0 second) — both must be present for combined sharding.
    self.assertIsInstance(attn.tensor_map[0], tuple,
                          msg=f"TND dp+cp attn T1 must be a tuple, got {attn.tensor_map[0]!r}")
    self.assertIn(0, attn.tensor_map[0],
                  msg=f"TND dp+cp attn T1 tuple must include dp axis 0, got {attn.tensor_map[0]!r}")
    self.assertIn(1, attn.tensor_map[0],
                  msg=f"TND dp+cp attn T1 tuple must include cp axis 1, got {attn.tensor_map[0]!r}")
    # softmax (N2, T1, N1/N2): tensor_map[1] = q_tm[0] (same multi-axis tuple)
    self.assertIsInstance(smax.tensor_map[1], tuple,
                          msg=f"TND dp+cp smax T1 must be a tuple, got {smax.tensor_map[1]!r}")
    self.assertIn(0, smax.tensor_map[1],
                  msg=f"TND dp+cp smax T1 tuple must include dp axis 0, got {smax.tensor_map[1]!r}")
    self.assertIn(1, smax.tensor_map[1],
                  msg=f"TND dp+cp smax T1 tuple must include cp axis 1, got {smax.tensor_map[1]!r}")

    impl = op.get_expand_impl(None, (attn, smax, ssum), [q, k, v, si, 'TND'])
    self.assertTrue(callable(impl),
                    msg=f"TND dp+cp get_expand_impl should return callable, got {type(impl)}")

@patch("hyper_parallel.core.dtensor.device_mesh.platform")
def test_tnd_no_cp_returns_callable_17(self, mock_platform):
    """
    Feature: get_expand_impl returns callable when q and k equally sharded TND.
    Description: q and k both sharded on same T1 dimension (DP only, no CP offset).
        Even without CP, _tnd_cp_impl is returned to clamp actual_seq_lengths to
        T1_local (cp_rank=0 path). This is required because the caller passes
        full (replicated) seq_lengths; the wrapper clips them to the local slice.
    Expectation: get_expand_impl returns callable with cp_rank=0.
    """
    mesh = self._make_1d_mesh(mock_platform, size=4, name="dp")
    q = _build_layout(mesh, (Shard(0),), 3)
    k = _build_layout(mesh, (Shard(0),), 3)
    v = _build_layout(mesh, (Shard(0),), 3)
    si = _build_layout(mesh, (Shard(0),), 3)

    op = self._get_op()
    result, _ = op.infer_layout([q, k, v, si, 'TND'])
    impl = op.get_expand_impl(None, result, [q, k, v, si, 'TND'])
    self.assertTrue(callable(impl),
                    msg=f"TND DP-only get_expand_impl should return callable, got {impl}")

# ------------------------------------------------------------------
# infer_layout — negative / error cases
# ------------------------------------------------------------------

def test_partial_input_raises_18(self):
    """
    Feature: Partial inputs are rejected.
    Description: Pass a layout with is_partial() returning True.
    Expectation: Raises ValueError.
    """
    partial_layout = MagicMock()
    partial_layout.is_partial.return_value = True
    normal_layout = MagicMock()
    normal_layout.is_partial.return_value = False
    normal_layout.tensor_map = (-1, -1, -1, -1)

    op = self._get_op()
    with self.assertRaises(ValueError):
        op.infer_layout([partial_layout, normal_layout, normal_layout, normal_layout, 'BSND'])

def test_pa_bsnd_raises_19(self):
    """
    Feature: PA_BSND layout is not supported in distributed mode.
    Description: Pass layout_str='PA_BSND'.
    Expectation: Raises ValueError mentioning 'PA_BSND'.
    """
    q, k, v, si = self._mock_layouts_bsnd((-1, -1, -1, -1), (-1, -1, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "PA_BSND"):
        op.infer_layout([q, k, v, si, 'PA_BSND'])

def test_bsnd_n1_sharded_raises_20(self):
    """
    Feature: BSND N1 (dim 2) of query sharding is forbidden.
    Description: query tensor_map[2] != -1 (TP head sharding attempt).
    Expectation: Raises ValueError mentioning 'N1'.
    """
    q, k, v, si = self._mock_layouts_bsnd((0, -1, 0, -1), (0, -1, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "N1"):
        op.infer_layout([q, k, v, si, 'BSND'])

def test_tnd_n1_sharded_raises_21(self):
    """
    Feature: TND N1 (dim 1) of query sharding is forbidden.
    Description: query tensor_map[1] != -1 (TP head sharding attempt).
    Expectation: Raises ValueError mentioning 'N1'.
    """
    q, k, v, si = self._mock_layouts_tnd((-1, 0, -1), (-1, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "N1"):
        op.infer_layout([q, k, v, si, 'TND'])

def test_query_d_sharded_raises_22(self):
    """
    Feature: BSND D (dim 3) of query sharding is forbidden.
    Description: query tensor_map[3] != -1.
    Expectation: Raises ValueError mentioning 'D'.
    """
    q, k, v, si = self._mock_layouts_bsnd((-1, -1, -1, 0), (-1, -1, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "D"):
        op.infer_layout([q, k, v, si, 'BSND'])

def test_key_s2_sharded_raises_23(self):
    """
    Feature: BSND S2 (dim 1) of key sharding is forbidden.
    Description: key tensor_map[1] != -1.
    Expectation: Raises ValueError mentioning 'S2'.
    """
    q, k, v, si = self._mock_layouts_bsnd((-1, -1, -1, -1), (-1, 0, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "S2"):
        op.infer_layout([q, k, v, si, 'BSND'])

def test_key_n2_sharded_raises_24(self):
    """
    Feature: BSND N2 (dim 2) of key sharding is forbidden.
    Description: key tensor_map[2] != -1.
    Expectation: Raises ValueError mentioning 'N2'.
    """
    q, k, v, si = self._mock_layouts_bsnd((-1, -1, -1, -1), (-1, -1, 0, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, "N2"):
        op.infer_layout([q, k, v, si, 'BSND'])

def test_batch_mismatch_raises_25(self):
    """
    Feature: BSND B sharding mismatch between key and query is rejected.
    Description: query B on mesh dim 0, key B on mesh dim 1.
    Expectation: Raises ValueError mentioning 'B (dim 0) sharding of key'.
    """
    q, k, v, si = self._mock_layouts_bsnd((0, -1, -1, -1), (1, -1, -1, -1))
    op = self._get_op()
    with self.assertRaisesRegex(ValueError, r"B \(dim 0\) sharding of key"):
        op.infer_layout([q, k, v, si, 'BSND'])

def test_si_s1_mismatch_raises_26(self):
    """
    Feature: BSND S1 mismatch between sparse_indices and query is rejected.
    Description: query S1 on mesh dim 0, sparse_indices S1 on mesh dim 1.
    Expectation: Raises ValueError mentioning 'S1 (dim 1) sharding of sparse_indices'.
    """
    q = MagicMock()
    q.is_partial.return_value = False
    q.tensor_map = (0, 0, -1, -1)
    k = MagicMock()
    k.is_partial.return_value = False
    k.tensor_map = (0, -1, -1, -1)
    v = MagicMock()
    v.is_partial.return_value = False
    v.tensor_map = (0, -1, -1, -1)
    si = MagicMock()
    si.is_partial.return_value = False
    si.tensor_map = (0, 1, -1, -1)

    op = self._get_op()
    with self.assertRaisesRegex(ValueError, r"S1 \(dim 1\) sharding of sparse_indices"):
        op.infer_layout([q, k, v, si, 'BSND'])

if name == "main": unittest.main()


</details>

<details>
<summary><code>[Bash: grep -n "RotaryPositionEmbedding\|rotary_position_embedding" /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/pyboost/auto_generate/pyboost_]</code></summary>

(Bash completed with no output)


</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops.py]</code></summary>

Copyright 2025-2026 Huawei Technologies Co., Ltd

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.

============================================================================

""" Distributed operator implementation. """

from typing import Optional

from .parallel_ops_register import register_distributed_op

class DistributedOp: """ Base class for distributed operator implementations.

This class provides default implementations for distributed operators.
Subclasses should override methods as needed for specific operators.

Args:
    op_name (str): Name of the operator to register.
"""
def __init__(self, op_name):
    self.op_name = op_name
    register_distributed_op(op_name, self)
    self._allow_partial_inputs = False

def _check_partial_inputs(self, layouts):
    """
    Check if any input layout has partial status and raise an error if not allowed.

    This method can be called by subclasses to enforce that partial inputs
    are not supported for a particular operator. Subclasses that support
    partial inputs should not call this method.

    Args:
        layouts (tuple): Layouts of input tensor.

    Raises:
        ValueError: If any input layout has partial status.
    """
    for i, layout in enumerate(layouts):
        if layout is not None and layout.is_partial():
            raise ValueError(
                f"For {self.op_name}, input {i} with {layout} has Partial status which is not allowed. "
                f"Should be without Partial status for this operation."
            )

# pylint: disable=W0613
def preprocess(self, args: tuple, kwargs: dict) -> Optional[tuple]:
    """
    Unified preprocessing: parameter parsing + to_local + cache_values construction.

    Subclasses override this to participate in the new dispatch flow.

    Args:
        args (tuple): Positional arguments passed to the operator call.
        kwargs (dict): Keyword arguments passed to the operator call.

    Returns:
        None: Fall back to legacy dispatch (default).
        tuple: (local_args, local_kwargs, cache_values)
            - local_args: Local tensor positional arguments (DTensors already to_local'd).
            - local_kwargs: Local tensor keyword arguments (DTensors already to_local'd).
            - cache_values: Values affecting layout inference (fixed order).
                Contains Layout objects (with compact_str) and raw values (int, bool, tuple, etc.).
    """
    return None

# pylint: disable=W0613
def infer_layout(self, layouts: tuple, extra_args: Optional[tuple] = None) -> Optional[tuple]:
    """
    Infer output layouts based on input layouts.

    Default implementation returns the first input layout for element-wise operations.
    Subclasses can override this method to provide custom layout inference logic.

    Args:
        layouts (tuple): Layouts of input tensor.
        extra_args (list): Additional arguments (dim, keepdim, etc.).

    Returns:
        tuple: Layouts for output tensors.
    """
    # Check partial inputs
    if not self._allow_partial_inputs:
        self._check_partial_inputs(layouts)

    if layouts:
        return (layouts[0],)
    return None

# pylint: disable=W0613
def get_expand_impl(self, func: Optional[callable], infer_result: tuple, layouts: tuple,
                    extra_args: Optional[tuple] = None) -> Optional[callable]:
    """
    Get expand implementation for the operator.

    Args:
        func (Optional[callable]): The underlying operator function.
        infer_result (tuple): Result returned by infer_layout (output_layouts, extra_info).
        layouts (tuple): Input layouts passed to layout inference.
        extra_args (Optional[tuple]): Additional arguments for layout inference.

    Returns:
        Optional[callable]: A closure that wraps the operator call with extra logic,
            or None if no expansion is needed.
    """
    return None

def wrap_output(self, py_output, output_layouts):
    """Wrap local outputs into DTensors according to inferred layouts.

    Subclasses may override this when a specific operator needs custom
    packing semantics for certain output slots.
    """
    # pylint: disable=C0415
    from hyper_parallel.core.dtensor.dtensor import DTensor

    if isinstance(py_output, (tuple, list)):
        if len(py_output) != len(output_layouts):
            raise RuntimeError(
                f"Output tuple size ({len(py_output)}) "
                f"does not match layout tuple size ({len(output_layouts)})")
        return tuple(
            DTensor.from_local(item, layout.mesh, layout.alias_placements)
            for item, layout in zip(py_output, output_layouts)
        )

    if isinstance(output_layouts, (tuple, list)):
        if len(output_layouts) != 1:
            raise RuntimeError(
                f"Scalar output expects a single layout, but got {len(output_layouts)} layouts"
            )
        output_layout = output_layouts[0]
    else:
        output_layout = output_layouts

    return DTensor.from_local(
        py_output, output_layout.mesh, output_layout.alias_placements
    )

</details>

<details>
<summary><code>[Bash: grep -rn "RotaryPositionEmbedding\|rotary_position_embedding" /root/workspace/mindspore/mindspore/ccsrc/pynative/forward/ --include="*.cc" | grep -v "]</code></summary>

(Bash completed with no output)


</details>

<details>
<summary><code>[Bash: find /root/workspace/mindspore -name "*.py" | xargs grep -l "rotary_position_embedding\|RotaryPositionEmbedding" 2>/dev/null | grep -i "parallel\|shar]</code></summary>

/root/workspace/mindspore/tests/ut/python/parallel/test_parallel_rotaryposemb.py


</details>

<details>
<summary><code>[Bash: cat /root/workspace/mindspore/tests/ut/python/parallel/test_parallel_rotaryposemb.py]</code></summary>

Copyright 2024 Huawei Technologies Co., Ltd

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 pytest import numpy as np

from mindspore import Tensor, context from mindspore.nn import Cell from mindspore.ops.auto_generate import RotaryPositionEmbedding from mindspore.ops import operations as P import mindspore.common.dtype as mstype from parallel.utils.utils import compile_net

def setup_function(): context.set_auto_parallel_context(dataset_strategy="full_batch")

x_ = Tensor(np.random.uniform(-2, 2, (4, 8192, 4, 128)), dtype=mstype.float16) sin_ = Tensor(np.random.uniform(-1, 1, (4, 8192, 1, 128)), dtype=mstype.float16) cos_ = Tensor(np.random.uniform(-1, 1, (4, 8192, 1, 128)), dtype=mstype.float16)

class Net(Cell): def init(self, strategy=None): super(Net, self).init() self.rotarypositionembedding = RotaryPositionEmbedding().shard(strategy) self.addn = P.AddN().shard(strategy)

def construct(self, x, sin, cos):
    q = self.rotarypositionembedding(x, sin, cos)
    return self.rotarypositionembedding(q, sin, cos)

def test_rotarypositionembedding_auto_parallel(): """ Feature: test RotaryPosEmb auto parallel Description: auto parallel Expectation: compile success """ context.set_context(save_graphs=True) strategy = ((4, 1, 2, 1), (4, 1, 1, 1), (4, 1, 1, 1)) context.set_auto_parallel_context(parallel_mode="semi_auto_parallel", device_num=8, global_rank=0) net = Net(strategy) compile_net(net, x_, sin_, cos_)

def test_rotarypositionembedding_auto_parallel_strategy_error(): """ Feature: test RotaryPosEmb auto parallel Description: auto parallel Expectation: compile success """ with pytest.raises(RuntimeError) as raise_info: strategy = ((4, 1, 1, 2), (4, 1, 1, 2), (4, 1, 1, 2)) context.set_auto_parallel_context(parallel_mode="semi_auto_parallel", device_num=8, global_rank=0) net = Net(strategy) compile_net(net, x_, sin_, cos_) assert "RotaryPositionEmbedding init failed" in str(raise_info.value)


</details>

<details>
<summary><code>[Bash: find /root/workspace/mindspore -name "*.py" | xargs grep -l "RotaryPositionEmbedding" 2>/dev/null | grep -v "test\|__pycache__" | head -10]</code></summary>

/root/workspace/mindspore/mindspore/python/mindspore/ops/auto_generate/cpp_create_prim_instance_helper.py /root/workspace/mindspore/mindspore/python/mindspore/ops/auto_generate/gen_ops_prim.py


</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | head -150]</code></summary>

Copyright 2025 Huawei Technologies Co., Ltd

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.

============================================================================

""" Parallel layout decorator """ _DISTRIBUTED_OPS = {}

def register_distributed_op(op_name, op_class): """ Register a distributed operator implementation.

Args:
    op_name (str): Name of the operator
    op_class (class): Distributed operator implementation class
"""
_DISTRIBUTED_OPS[op_name] = op_class

def get_distributed_op(op_name): """ Get distributed operator implementation by operator name.

Args:
    op_name (str): Name of the operator

Returns:
    object: Distributed operator instance or None if not found
"""
return _DISTRIBUTED_OPS.get(op_name, None)

</details>

<details>
<summary><code>[Bash: cat /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops_register.py]</code></summary>

Copyright 2025-2026 Huawei Technologies Co., Ltd

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.

============================================================================

"""_op_dispatch""" import os import sys import atexit import glob import importlib from typing import Any, List, Dict, Optional, Set from itertools import chain

import yaml

from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op from hyper_parallel.core.dtensor.dtensor import DTensor from hyper_parallel.core.dtensor.random import OffsetBasedRNGTracker, is_rng_supported_mesh from hyper_parallel.platform import get_platform from hyper_parallel.platform.platform import PlatformType

platform = get_platform() Tensor = platform.Tensor

def _apply_shard_offset_to_rng_args(args, offset_incr): """Apply per-shard offset increment to seed/offset tensors in MindSpore random op args.

MindSpore random ops (e.g. ``randn_like_``) receive ``(seed, offset)`` as
explicit int64 scalar tensors from ``default_generator._step()`` in the
Python wrapper *before* the C++ dispatch triggers ``__fallback__``.  By the
time ``_dispatch_random_op`` is called, the kernel will use whatever
``(seed, offset)`` values are in the args—it does **not** read the
generator again. This function finds the offset tensor and adds the
per-rank offset increment so each shard gets a unique random stream.

The (seed, offset) pair is identified as the last two consecutive int64
0-dim tensors in *args* (scanning from the end to skip trailing dtype /
device arguments).

Args:
    args: The list of local args for the random op.
    offset_incr (int): Per-shard offset increment.

Returns:
    list: Modified args with the offset tensor adjusted.
"""
int64_dtype = platform.tensor_dtype.int64
last_int64_idx = -1
for i in range(len(args) - 1, -1, -1):
    arg = args[i]
    if isinstance(arg, Tensor) and arg.dtype == int64_dtype and arg.ndim == 0:
        if last_int64_idx == i + 1:
            offset_idx = i + 1
            new_args = list(args)
            new_offset = int(new_args[offset_idx].item()) + offset_incr
            new_args[offset_idx] = platform.tensor([new_offset], dtype=int64_dtype).reshape(())
            return new_args
        last_int64_idx = i
return args

_dtensor_dispatch = True _no_skip_ops: Set[str] = set()

def get_no_skip_ops() -> Set[str]: """Return the set of op names that are exempt from SkipDTensorDispatch.""" return _no_skip_ops

def add_no_skip_ops(op_names: Set[str]) -> None: """Add op names to the no-skip set so they are always dispatched through DTensor.

Args:
    op_names: Set of canonical op name strings to register as no-skip.
"""
global _no_skip_ops
_no_skip_ops = _no_skip_ops | op_names

def remove_no_skip_ops(op_names: Set[str]) -> None: """Remove op names from the no-skip set.

Args:
    op_names: Set of canonical op name strings to remove.
"""
global _no_skip_ops
_no_skip_ops = _no_skip_ops - op_names

def enable_dtensor_dispatch() -> None: """ Enable DTensor dispatch for distributed tensor operations.

When enabled, tensor operations will be dispatched through the
distributed operator dispatcher for layout inference and redistribution.
"""
global _dtensor_dispatch
_dtensor_dispatch = True

def disable_dtensor_dispatch() -> None: """ Disable DTensor dispatch for distributed tensor operations.

When disabled, tensor operations will bypass the distributed operator
dispatcher and use native implementations directly.
"""
global _dtensor_dispatch
_dtensor_dispatch = False

def get_dtensor_dispatch() -> bool: """ Get the current DTensor dispatch status.

Returns:
    bool: True if DTensor dispatch is enabled, False otherwise.
"""
return _dtensor_dispatch

class LayoutCacheKey: """Immutable layout cache key.""" slots = ('_tuple', '_hash')

def __init__(self, layout_ids: List[str]):
    self._tuple = tuple(layout_ids)
    self._hash = hash(self._tuple)

@classmethod
def from_cache_values(cls, cache_values: list) -> "LayoutCacheKey":
    """Build a LayoutCacheKey from a cache_values list.

    Args:
        cache_values (list): Mixed list of Layout objects (with compact_str) and raw scalars.

    Returns:
        LayoutCacheKey: Immutable key derived from the string representation of each value.
    """

</details>

<details>
<summary><code>[Bash: grep -n "preprocess\|cache_values\|infer_layout\|wrap_output" /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | head -50]</code></summary>

142: def from_cache_values(cls, cache_values: list) -> "LayoutCacheKey": 143: """Build a LayoutCacheKey from a cache_values list. 146: cache_values (list): Mixed list of Layout objects (with compact_str) and raw scalars. 152: for v in cache_values: 437: output_layout = distribute_op.infer_layout(*all_args) 539: output_layout = distribute_op.infer_layout(*all_args) 547: return distribute_op.wrap_output(py_output, output_layout) 576: infer_output = distribute_op.infer_layout(*all_args) 695: output_layout = distribute_op.infer_layout(*all_args) 760: infer_output = distribute_op.infer_layout(*all_args) 942: result = distribute_op.preprocess(args, kwargs) 946: suffix = self.layout_infer_ops[op_name].get('infer_layout_suffix', '') 956: """New dispatch flow using preprocess result. 961: result: Preprocessed result (local_args, local_kwargs, cache_values). 966: local_args, local_kwargs, cache_values = result 967: cache_key = LayoutCacheKey.from_cache_values(cache_values) 977: infer_result = distribute_op.infer_layout(cache_values) 978: op_impl = distribute_op.get_expand_impl(func, infer_result, cache_values) 983: return distribute_op.wrap_output(py_output, output_layouts)


</details>

<details>
<summary><code>[Bash: grep -n "def _dispatch_distributed\|preprocess\|cache_values" /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | head -30]</code></summary>

142: def from_cache_values(cls, cache_values: list) -> "LayoutCacheKey": 143: """Build a LayoutCacheKey from a cache_values list. 146: cache_values (list): Mixed list of Layout objects (with compact_str) and raw scalars. 152: for v in cache_values: 942: result = distribute_op.preprocess(args, kwargs) 956: """New dispatch flow using preprocess result. 961: result: Preprocessed result (local_args, local_kwargs, cache_values). 966: local_args, local_kwargs, cache_values = result 967: cache_key = LayoutCacheKey.from_cache_values(cache_values) 977: infer_result = distribute_op.infer_layout(cache_values) 978: op_impl = distribute_op.get_expand_impl(func, infer_result, cache_values)


</details>

<details>
<summary><code>[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py]</code></summary>

940 distribute_op = cache_manager.distributed_op(op_name) 941 942 result = distribute_op.preprocess(args, kwargs) 943 if result is not None: 944 return self._dispatch_new(op_call, distribute_op, result) 945 946 suffix = self.layout_infer_ops[op_name].get('infer_layout_suffix', '') 947 if not suffix: 948 return self._with_layout_infer(op_call, *args, **kwargs) 949 950 handler_name = self._suffix_dispatch.get(suffix) 951 if handler_name is None: 952 raise RuntimeError(f"Operator {op_name} specified wrong suffix in parallel yaml.") 953 return getattr(self, handler_name)(op_call, *args, **kwargs) 954 955 def _dispatch_new(self, func, distribute_op, result) -> Tensor: 956 """New dispatch flow using preprocess result. 957 958 Args: 959 func: Original function. 960 distribute_op: Distributed operation instance. 961 result: Preprocessed result (local_args, local_kwargs, cache_values). 962 963 Returns: 964 Tensor: Dispatched result as DTensor. 965 """ 966 local_args, local_kwargs, cache_values = result 967 cache_key = LayoutCacheKey.from_cache_values(cache_values) 968 func_name = platform.get_op_name(func) 969 cache_manager = LayoutCacheManager.get_instance() 970 layout_cache = cache_manager.get_layout_cache() 971 if func_name not in layout_cache: 972 layout_cache[func_name] = {} 973 op_layout_cache = layout_cache[func_name] 974 if cache_key in op_layout_cache: 975 infer_result, op_impl = op_layout_cache[cache_key] 976 else: 977 infer_result = distribute_op.infer_layout(cache_values) 978 op_impl = distribute_op.get_expand_impl(func, infer_result, cache_values) 979 op_layout_cache[cache_key] = (infer_result, op_impl) 980 output_layouts, _ = infer_result 981 op_impl = func if op_impl is None else op_impl 982 py_output = op_impl(*local_args, **local_kwargs) 983 return distribute_op.wrap_output(py_output, output_layouts) 984 985 def dispatch(self, op_call: callable, args: tuple, kwargs: dict) -> object: 986 """Route an op call through the appropriate DTensor dispatch path. 987 988 Args: 989 op_call: The raw operator callable. 990 args: Positional arguments for op_call. 991 kwargs: Keyword arguments for op_call. 992 993 Returns: 994 Result of the dispatched op call. 995 """ 996 op_name = platform.get_op_name(op_call) 997 998 if self._should_bypass_dispatch(op_name): 999 return op_call(*self._unwrap_args(args), **kwargs)


</details>

<details>
<summary><code>[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py]</code></summary>

140 141 @classmethod 142 def from_cache_values(cls, cache_values: list) -> "LayoutCacheKey": 143 """Build a LayoutCacheKey from a cache_values list. 144 145 Args: 146 cache_values (list): Mixed list of Layout objects (with compact_str) and raw scalars. 147 148 Returns: 149 LayoutCacheKey: Immutable key derived from the string representation of each value. 150 """ 151 key_values = [] 152 for v in cache_values: 153 if hasattr(v, 'compact_str'): 154 key_values.append(str(v.compact_str)) 155 else: 156 key_values.append(str(v)) 157 return cls(key_values) 158 159 def eq(self, other): 160 if not isinstance(other, LayoutCacheKey): 161 return False 162 return self._tuple == other._tuple 163 164 def hash(self): 165 return self._hash 166 167 def repr(self): 168 return f"LayoutCacheKey({self._tuple})" 169 170 class LayoutCacheManager: 171 """ 172 Cache layout in infer layout. 173 174 A singleton class that manages layout caches for distributed operations. 175 It caches the inferred layouts and operation implementations to avoid 176 redundant computation during repeated calls with the same input layouts. 177 """ 178 _instance = None 179


</details>

我先读取所有参考资料来分析,然后输出计划文档。

现在读取 sparse_flash_attention 的实现文件作为参考。

现在读取 mindspore 的 pyboost_overload_functions.cc 中 RPE 相关部分,以及 DistributedOp 基类。

再读取 op dispatch 机制和 DTensor 的 `_to_local` 逻辑。

信息已收集完毕,现在输出完整的分析计划文档。

---

# RotaryPositionEmbedding 分布式算子实现计划

## 1. 算子概述与接口分析

### 1.1 MindSpore 接口

```python
mindspore.ops.rotary_position_embedding(x, cos, sin, mode=0)
参数 类型 说明
x Tensor 主输入,3D(TND)或 4D(BNSD/BSND/SBND),float16/bfloat16/float32
cos Tensor 位置编码余弦值,与 x 同类型,支持 leading-dim broadcast
sin Tensor 位置编码正弦值,与 cos 形状相同
mode int 旋转模式:0=rotate_half,1=rotate_interleaved,2=quarter,3=interleave-half
返回 Tensor 与 x 完全相同的 shape 和 dtype

双注册名

  • 函数名(torch/PyBoost 侧):rotary_position_embedding(snake_case)
  • Primitive 类名(MindSpore 静态图侧):RotaryPositionEmbedding(PascalCase)

1.2 CANN 约束摘要

约束 说明
支持硬件 Atlas A2/A3 训练(mode 0/1),Ascend 950(mode 2/3),Atlas 推理(mode 0)
x 支持布局 BNSD、BSND、SBND、TND
D 维约束 D < 896,必须为偶数(half/interleave)或 4 倍数(quarter)
cos/sin 与 x 的关系 满足 broadcast 关系;x BNSD 时 cos/sin 可为 11SD、B1SD、BNSD
输出 shape 和 type 与 x 完全相同
性能注意 BNSD 布局下 B*N > 8S 且 D 满足 32 字节对齐时性能差

1.3 与 SparseFlashAttention 的关键差异

维度 SparseFlashAttention RotaryPositionEmbedding
输出数量 3(attn_out, softmax_max, softmax_sum) 1(out = x shape)
算子语义 跨 token 注意力汇聚(因果窗口) 纯 element-wise(D 维内旋转)
CP 展开逻辑 BSND 需截断 k/v 至因果窗口,TND 需调整 seq_lens 无需展开逻辑,get_expand_impl 始终返回 None
cos/sin 角色 位置编码广播常数,可沿部分维度广播
layout 传参 需显式 layout_str(BSND/TND/PA_BSND) 无需,通用 last-dim-is-D 规则覆盖所有布局

2. 分布式 Layout 推导规则

2.1 数学原理

RPE 的计算公式:y = x * cos + x_rotate * sin

  • x_rotate 由 x 的最后一维 D 内部旋转得到(各 token 独立,无跨 token 通信)
  • 各 B、N、S 维度之间完全独立,可以自由 shard
  • D 维度内部旋转是不可分割的原子操作,绝对不能 shard

2.2 Shard 允许规则

核心约束

约束 说明
x 的 D 维(last dim)必须 replicated tensor_map[-1] == -1
cos/sin 的 D 维(last dim)必须 replicated tensor_map[-1] == -1
cos/sin 非 D 维可以 replicated 或与 x 一致 shard 若 cos/sin.tensor_map[d] != -1,则必须 == x.tensor_map[d]
输出 layout = x layout 的深拷贝 output shape == x shape

允许的 Shard 组合(以 BNSD 为例,dims=B,N,S,D):

场景 x tensor_map cos/sin tensor_map 是否合法
全 Replicated (-1,-1,-1,-1) (-1,-1,-1,-1)
DP on B (0,-1,-1,-1) (0,-1,-1,-1) 或 (-1,-1,-1,-1)
TP on N,cos/sin broadcast on N (-1,0,-1,-1) (-1,-1,-1,-1) ✓(cos 11SD 形状)
TP on N,cos 同样 shard N (-1,0,-1,-1) (-1,0,-1,-1) ✓(cos BNSD 形状)
CP on S (-1,-1,0,-1) (-1,-1,0,-1)
D sharded (-1,-1,-1,0) anything ✗ ValueError
cos D sharded (-1,-1,-1,-1) (-1,-1,-1,0) ✗ ValueError
cos shard 与 x 不一致 (0,-1,-1,-1) (1,-1,-1,-1) ✗ ValueError
DP+TP (1,0,-1,-1) (1,-1,-1,-1)

关于 S 维 CP 的特殊说明

若 x.S sharded 而 cos/sin.S replicated(tensor_map[S] == -1),验证层面通过(因为 HyperParallel 看不到 cos/sin 的实际 shape,若 cos/sin 的 S 实际大小为 1,kernel 可 broadcast)。用户负责确保运行时 cos/sin 的形状满足 CANN 要求。若 cos/sin 的 S 维是全序列长度(shape 不为 1),则运行时 CANN 会报 shape 不匹配,但这是用户使用错误,不在 HyperParallel 验证范围内。

2.3 验证逻辑(精简伪代码)

def _validate_input_layouts(x_layout, cos_layout, sin_layout):
    op = "rotary_position_embedding"
    
    # Rule 1: D (last dim) must be replicated
    if x_layout.tensor_map[-1] != -1:
        raise ValueError(f"For {op}, D (last dim) of x must be replicated, got {x_layout.tensor_map}")
    
    for name, layout in [('cos', cos_layout), ('sin', sin_layout)]:
        if layout is None:  # non-DTensor input → effectively replicated → always valid
            continue
        if layout.tensor_map[-1] != -1:
            raise ValueError(f"For {op}, D (last dim) of {name} must be replicated, got {layout.tensor_map}")
        # Rule 2: if cos/sin is sharded on non-D dim, must match x
        for d in range(len(layout.tensor_map) - 1):
            if layout.tensor_map[d] != -1 and layout.tensor_map[d] != x_layout.tensor_map[d]:
                raise ValueError(
                    f"For {op}, sharding of {name} on dim {d} must match x or be replicated, "
                    f"but got x={x_layout.tensor_map[d]}, {name}={layout.tensor_map[d]}"
                )

3. 实现文件详情

文件一:hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py

功能:RPE 分布式算子的核心实现。

模块级辅助函数

_normalize_rpe_args(x, cos, sin, mode=0)

  • 用途:将所有位置/关键字参数归一化为标准 positional tuple,统一处理接口
  • 签名:(x, cos, sin, mode=0) → (x, cos, sin, mode), {}
  • 返回:(positional_args_tuple, empty_kwargs_dict)

_to_local(t)

  • 若 t 是 DTensor → 返回 t.to_local();否则透传
  • 与 SFA 实现相同

RotaryPositionEmbeddingDistributedOp(DistributedOp)

preprocess(args, kwargs) → (local_args, local_kwargs, cache_values)

  • 解析参数:通过 _normalize_rpe_args 解析出 x, cos, sin, mode
  • 提取 local tensors:对三个 tensor 都调用 _to_local
  • 构建 cache_values:[x_layout, cos_layout_or_None, sin_layout_or_None]
    • x 必须是 DTensor(触发 dispatch 的前提),直接取 x.layout
    • cos/sin 若是 DTensor 取 t.layout,否则填 None(等效 replicated)
  • 返回:(x_local, cos_local, sin_local, mode), {}, [x_l, cos_l, sin_l]

_validate_input_layouts(x_layout, cos_layout, sin_layout) [staticmethod]

  • Rule 1:x_layout.tensor_map[-1] == -1,否则 raise ValueError 含 "D"
  • Rule 2:cos_layout.tensor_map[-1] == -1(若不为 None),否则 raise ValueError 含 "D"
  • Rule 3:sin_layout.tensor_map[-1] == -1(若不为 None),否则 raise ValueError 含 "D"
  • Rule 4:cos/sin 的非 D dim 若 sharded,必须与 x 同轴,否则 raise ValueError

infer_layout(cache_values) → ((output_layout,), None)

  • 提取 x_layout = cache_values[0]cos_layout = cache_values[1]sin_layout = cache_values[2]
  • 调用 _check_partial_inputs([l for l in [x_layout, cos_l, sin_l] if l is not None])
  • 调用 _validate_input_layouts(x_layout, cos_layout, sin_layout)
  • 返回 (copy.deepcopy(x_layout),), None

get_expand_impl(func, infer_result, cache_values, extra_args=None) → None

  • RPE 是纯 element-wise 算子,无需任何运行时展开逻辑(不存在 SFA 因果窗口截断)
  • 始终返回 None

文件二:hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml

rotary_position_embedding:
  dist_op_name: _rotary_position_embedding_dist_op
  distributed_op_class: RotaryPositionEmbeddingDistributedOp
  distributed_op_file: parallel_rotary_position_embedding

RotaryPositionEmbedding:
  dist_op_name: _rotary_position_embedding_dist_op
  distributed_op_class: RotaryPositionEmbeddingDistributedOp
  distributed_op_file: parallel_rotary_position_embedding
  • 两个名称共享同一个 dist_op_name(singleton 实例)
  • dist_op_name 在 Python 实例化时用于注册唯一实例,避免重复创建

文件三:tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py

单元测试,不需要真实 NPU,mock platform

测试分组

TestNormalizeRpeArgs — 参数归一化

ID 用例 验证点
1 三个位置参数,mode 默认 0 args[0] is x, args[3] == 0, kwargs == {}
2 mode=1 作为关键字参数 args[3] == 1
3 mode=2 作为位置参数 args[3] == 2

TestYamlRegistration — YAML 注册

ID 用例 验证点
4 snake_case rotary_position_embedding get_distributed_op(...) 返回 RotaryPositionEmbeddingDistributedOp 实例
5 PascalCase RotaryPositionEmbedding 同上,验证双注册

TestInferLayoutPositive — layout 推导正向

ID 用例 输入 期望输出
6 All Replicated(4D) x: 1-D mesh, Replicate output.tensor_map == (-1,-1,-1,-1)
7 DP on B(4D) x: Shard(0), cos/sin: Replicate output.tensor_map == (0,-1,-1,-1)
8 TP on N(4D),cos/sin Replicate x: Shard(1), cos/sin: Replicate output.tensor_map == (-1,0,-1,-1)
9 CP on S(4D),cos/sin 同 shard x: Shard(2), cos/sin: Shard(2) output.tensor_map == (-1,-1,0,-1)
10 DP+TP 2D mesh x: (Shard(0),Shard(1)), cos/sin: (Shard(0),Replicate) output.tensor_map == (1,0,-1,-1)
11 All Replicated(3D TND) x: 1-D mesh, Replicate, ndim=3 output.tensor_map == (-1,-1,-1)
12 DP on T(3D TND) x: Shard(0), ndim=3 output.tensor_map == (0,-1,-1)
13 cos/sin 为 None(非 DTensor) x: Shard(0), cos=None, sin=None output.tensor_map == (0,-1,-1,-1),不报错
14 cos/sin Replicate,x S sharded x: Shard(2), cos: Replicate output.tensor_map == (-1,-1,0,-1),不报错
15 输出是 x_layout 的深拷贝 任意 output is not x_layout(不是同一对象)

TestInferLayoutNegative — layout 推导负向(报错)

ID 用例 触发条件 期望异常
16 x D 维 sharded x.tensor_map[-1] != -1 ValueError 含 "D"
17 cos D 维 sharded cos.tensor_map[-1] != -1 ValueError 含 "D"
18 sin D 维 sharded sin.tensor_map[-1] != -1 ValueError 含 "D"
19 cos B 维与 x 不一致 x.tm[0]=0, cos.tm[0]=1 ValueError 含 dim 0 或 cos
20 sin S 维与 x 不一致 x.tm[2]=0, sin.tm[2]=1 ValueError 含 dim 2 或 sin
21 x partial 输入 x.is_partial() → True ValueError
22 cos partial 输入(若为 DTensor) cos.is_partial() → True ValueError

TestGetExpandImpl — 展开逻辑

ID 用例 期望
23 全 Replicated get_expand_impl(...) is None
24 B-sharded DP get_expand_impl(...) is None
25 S-sharded CP get_expand_impl(...) is None

文件四:tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py

分布式系统测试(需真实 NPU 多卡)

测试数据配置

# 形状设计:满足 CANN 约束 B*N <= S*8,D < 896,D 为偶数
B, N, S, D = 2, 4, 64, 64  # B*N=8 <= S*8=512 ✓
MODE = 0  # rotate_half

# BNSD 布局
x_shape    = (B, N, S, D)  # BNSD
cos_shape  = (1, 1, S, D)  # 11SD,broadcast 在 B 和 N
sin_shape  = (1, 1, S, D)

辅助函数

  • _get_cos_sin_full(): 生成全量 cos/sin(shape: cos_shape)
  • _standalone_forward_backward(x_np, cos_np, sin_np, mode): 单机前向+反向,返回 (out, x_grad)
  • _distributed_rpe(mesh, x_dtensor, cos_dtensor, sin_dtensor, mode): 分布式前向+反向

测试用例

函数名 场景 mesh x 分片 cos/sin 分片
test_rpe_bnsd_replicated 全 Replicated (4,) dp=4 Replicate Replicate
test_rpe_bnsd_dp B-dim DP (4,) dp=4 Shard(0) on B Replicate(broadcast)
test_rpe_bnsd_tp N-dim TP (4,) tp=4 Shard(1) on N Replicate(cos/sin 为 1×1×S×D,N broadcast)
test_rpe_bnsd_dp_tp DP+TP 2D mesh (2,2) dp×tp Shard(0) on B,Shard(1) on N Shard(0) on B,Replicate on N
test_rpe_bnsd_cos_same_shard cos/sin 与 x 同 shard (4,) dp=4 Shard(0) Shard(0)(cos 为 B×1×S×D 形状)

每个用例验证:

  1. 前向正确性:分布式输出 gather 后与单机 standalone 结果数值对齐(atol=1e-2,rtol=1e-2)
  2. 反向正确性:x.grad 数值与单机反向对齐

文件五:tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py

测试 runner,组合 ST 用例

IMPL_FILE = Path(__file__).resolve().parent / "rotary_position_embedding_shard_in_python.py"

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group1():
    """Feature: RPE distributed ST — Replicated and DP (4 cards)
    Description:
      1. test_rpe_bnsd_replicated — 全 Replicated 前向+反向
      2. test_rpe_bnsd_dp        — B-dim DP 前向+反向
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_bnsd_replicated", 19300, 4, 4, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_bnsd_dp",         19301, 4, 4, 2),
    ])

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group2():
    """Feature: RPE distributed ST — TP and DP+TP (4 cards)
    Description:
      1. test_rpe_bnsd_tp     — N-dim TP,cos/sin broadcast on N
      2. test_rpe_bnsd_dp_tp  — 2-D mesh DP+TP
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_bnsd_tp",    19302, 4, 4, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_bnsd_dp_tp", 19303, 4, 4, 2),
    ])

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level0", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group3():
    """Feature: RPE distributed ST — cos/sin same shard as x (4 cards)
    Description:
      1. test_rpe_bnsd_cos_same_shard — cos/sin 与 x 同维度 shard(B 维)
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_bnsd_cos_same_shard", 19304, 4, 4, 2),
    ])

4. 关键设计决策

4.1 不需要 get_expand_impl

SFA 的 BSND+CP 场景需要截断 k/v 至因果窗口 [:, :S1_local*(split_id+1), :, :],因为注意力是单向的。RPE 是纯 element-wise,不存在因果依赖,每个 rank 直接在本地 x/cos/sin 上计算即可。

4.2 cos/sin 可以是非 DTensor

当 cos/sin 是普通 Tensor(非 DTensor)时,视为 replicated(globally available),在 preprocess 中 layout 填 None,validate 时跳过这些 None,infer_layout 时只依赖 x_layout 确定 output layout。

4.3 cache_values 中 None 的处理

LayoutCacheKey.from_cache_values 对 None 调用 str(None) = 'None',可正确区分"cos 是 DTensor"和"cos 是普通 Tensor"的 layout 缓存 key。

4.4 不引入 layout_str 参数

SFA 需要 layout_str(BSND/TND/PA_BSND)是因为:

  • TND 和 BSND 的 softmax 输出 layout 推导逻辑不同
  • TND+CP 需要调整 actual_seq_lengths

RPE 的 output layout 统一等于 x layout,D 维始终是 last dim,无需区分具体布局字符串。

4.5 MindSpore 的算子参数顺序确认

官方 yaml 文档和 pyboost 生成代码均为 (x, cos, sin, mode)。MindSpore 静态图并行测试代码中的 (x, sin, cos) 顺序是历史问题(旧接口),HyperParallel 实现遵循当前官方接口 (x, cos, sin, mode=0)


5. 实现约束总结

约束 违反后果
x 的 D 维(last dim)必须 replicated ValueError,错误信息含 "D"
cos 的 D 维(last dim)必须 replicated ValueError,错误信息含 "D"
sin 的 D 维(last dim)必须 replicated ValueError,错误信息含 "D"
cos/sin 若 sharded,shard 轴必须与 x 一致 ValueError,错误信息含维度索引和 tensor 名
x 不得有 Partial 状态 ValueError(来自 _check_partial_inputs)
cos/sin(若为 DTensor)不得有 Partial 状态 ValueError

6. 文件列表

文件路径 类型 说明
hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py 主实现 RotaryPositionEmbeddingDistributedOp 类
hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml 注册配置 双名称注册
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py UT 25 个单元测试,不需 NPU
tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py ST 辅助 分布式测试执行逻辑
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py ST runner pytest 入口,3 组

System

正在为 MindSpore rotary_position_embedding 算子设计分布式实现方案,计划报告已输出完毕,包含 5 个文件清单、25 条 UT 和 3 组 ST 测试用例。下一步是确认方案后开始动手实现。 (disable recaps in /config)


User · 2026-05-18T14:40:13.091Z

  1. 是不是x的layout,cos和sin要满足广播条件,主要是BN维度?满足这个条件,BN切分/Replicate就都可以酌情处理?
  2. 从计算公式看,S序列可以切分么?
  3. _to_local(t)不需要,我们默认只能传入DTensor,直接to_local就行。
  4. 如果想在校验/layout推断时用shape,那在preprocess将shape获取出来加入cache就行。
  5. 如果不需要get_expand_impl,就不用定义了,TestGetExpandImpl也不需要。
  6. yaml,小写下划线的rotary_position_embedding,不需要
  7. ST用例可以多验证一些场景,尤其是多维mesh切分的场景。每个mesh的大小,最大是2,能够验证shard即可,尽量少占用卡。

Assistant · 2026-05-18T14:42:32.714Z

理解了,我来逐一回应并输出修订后的计划文档。


RotaryPositionEmbedding 分布式算子实现计划(修订版)

修订说明

原版 修订后
cos/sin 约束模糊 明确 BN 维广播条件,用规则覆盖所有情形
S 维是否可切分未定 确认 S 可切分,同样适用一致性规则
_to_local 辅助函数 去掉,直接 t.to_local()
YAML 双名注册 仅保留 PascalCase RotaryPositionEmbedding
有 get_expand_impl + 对应测试 全部去掉
ST 场景少,mesh 大 多维 mesh 场景,每维最大 size=2,最少卡数

1. 接口分析

MindSpore 接口(官方,与旧测试代码 (x, sin, cos) 顺序无关)

mindspore.ops.rotary_position_embedding(x, cos, sin, mode=0)
# 算子 Primitive 类名(YAML 注册名): RotaryPositionEmbedding
参数 说明
x 主输入:3D(TND)或 4D(BNSD/BSND/SBND),float16/bf16/float32
cos 位置编码余弦,与 x 同类型,支持 leading-dim broadcast
sin 与 cos 相同约束
mode int,0=rotate_half,1=rotate_interleaved(A2/A3);2=quarter,3=interleave-half(950)
返回 Tensor,shape 和 dtype 完全与 x 相同

计算公式(mode=0)

x_rotate = concat([-x[..., D//2:], x[..., :D//2]], dim=-1)
y = x * cos + x_rotate * sin      # 元素级,各 B、N、S 位置完全独立

关键推论:B、N、S 三个维度上各位置的计算完全独立,天然支持 shard。D 维内部旋转混合是不可分割的原子操作,D 维绝对不能 shard


2. 分布式 Layout 推导规则

2.1 cos/sin 的广播语义与 BN 维约束

CANN 允许 cos/sin 在 B、N 维广播(shape 为 1),例如:

  • x BNSD → cos 可为 11SD(B=1,N=1 broadcast),B1SD(N=1 broadcast),BNSD(无 broadcast)
  • x BSND → cos 可为 1S1D, BS1D, BSND

在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:

  • 若 cos 在 B 维 shape=1 → DTensor 无法 shard 该维 → cos.tensor_map[b_dim] == -1(replicated)
  • 若 cos 在 B 维 shape=B → DTensor 可 shard 或 replicated → cos.tensor_map[b_dim] == -1== x.tensor_map[b_dim]

因此统一规则:cos.tensor_map[d] != -1,则它必须等于 x.tensor_map[d],否则 ValueError。此规则同时覆盖 B/N/S 三个维度,无需按 layout 字符串分类讨论。

2.2 S 维是否可切分

从公式看:y[b,n,s,:] = x[b,n,s,:] * cos[...,s,:] + x_rotate[b,n,s,:] * sin[...,s,:],各 s 完全独立。S 可以切分

约束与 B/N 相同:

  • 若 cos.S 被 shard → 必须与 x.S 同轴
  • 若 cos.S replicated(cos.tensor_map[s_dim]==-1)→ 允许,用户需确保 cos 实际 shape 在 S 维为 1(broadcast),否则 CANN 运行时 shape 不匹配(属于用户使用错误,不在 HyperParallel 校验范围)

2.3 完整约束规则

约束 检查 报错信息含
x 的 D 维(last dim)必须 replicated x.tensor_map[-1] == -1 "D"
cos 的 D 维必须 replicated cos.tensor_map[-1] == -1 "D", "cos"
sin 的 D 维必须 replicated sin.tensor_map[-1] == -1 "D", "sin"
cos 非 D 维若 sharded 必须与 x 一致 cos.tensor_map[d] in {-1, x.tensor_map[d]} "cos", 维度索引
sin 非 D 维若 sharded 必须与 x 一致 sin.tensor_map[d] in {-1, x.tensor_map[d]} "sin", 维度索引
x/cos/sin 不得有 Partial 状态 layout.is_partial() == False 默认 ValueError

输出 layoutcopy.deepcopy(x_layout)(output shape == x shape)

2.4 允许场景总览(BNSD,dims: B=0, N=1, S=2, D=3)

场景 x.tm cos.tm 是否合法
全 Replicated (-1,-1,-1,-1) (-1,-1,-1,-1)
DP on B,cos broadcast (0,-1,-1,-1) (-1,-1,-1,-1)
DP on B,cos B-sharded (0,-1,-1,-1) (0,-1,-1,-1)
TP on N,cos N=1 broadcast (-1,0,-1,-1) (-1,-1,-1,-1)
CP on S,cos S-sharded (-1,-1,0,-1) (-1,-1,0,-1)
CP on S,cos S replicated (-1,-1,0,-1) (-1,-1,-1,-1) ✓(用户负责 cos S=1)
DP+TP 2D mesh (1,0,-1,-1) (1,-1,-1,-1)
DP+CP 2D mesh (0,-1,1,-1) (0,-1,1,-1)
TP+CP 2D mesh (-1,0,1,-1) (-1,-1,1,-1)
x D sharded (-1,-1,-1,0) anything ✗ ValueError("D")
cos D sharded anything (-1,-1,-1,0) ✗ ValueError("D","cos")
cos B 与 x 不一致 (0,-1,-1,-1) (1,-1,-1,-1) ✗ ValueError(dim 0, "cos")

3. 实现文件详情

文件一:hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py

文件结构:
├── _normalize_rpe_args(x, cos, sin, mode=0)
└── class RotaryPositionEmbeddingDistributedOp(DistributedOp)
    ├── preprocess(args, kwargs)
    ├── _validate_input_layouts(x_l, cos_l, sin_l)  [staticmethod]
    └── infer_layout(cache_values)

_normalize_rpe_args(x, cos, sin, mode=0)

  • 统一将位置/关键字参数归一化为 positional tuple
  • 返回:(x, cos, sin, mode), {}(空 kwargs)

preprocess(args, kwargs)

  • 调用 _normalize_rpe_args(*args, **kwargs) 解析出 x, cos, sin, mode
  • 直接 t.to_local()(x/cos/sin 均为 DTensor)
  • 构建 cache_values: [x.layout, cos.layout, sin.layout]
    • 若需要 shape 用于调试/验证(如 ndim 检查),可在此追加 x.to_local().shape 到 cache
    • 基本情形下 3 个 layout 足够
  • 返回:(x_local, cos_local, sin_local, mode), {}, [x_l, cos_l, sin_l]

_validate_input_layouts(x_layout, cos_layout, sin_layout) [staticmethod]

op = "rotary_position_embedding"

# D (last dim) checks
for name, layout in [('x', x_layout), ('cos', cos_layout), ('sin', sin_layout)]:
    if layout.tensor_map[-1] != -1:
        raise ValueError(f"For {op}, D (last dim) of {name} must be replicated, got {layout.tensor_map}")

# cos/sin consistency with x (non-D dims)
x_tm = x_layout.tensor_map
for name, layout in [('cos', cos_layout), ('sin', sin_layout)]:
    for d in range(len(layout.tensor_map) - 1):
        if layout.tensor_map[d] != -1 and layout.tensor_map[d] != x_tm[d]:
            raise ValueError(
                f"For {op}, {name} sharding on dim {d} must match x or be replicated, "
                f"but got x={x_tm[d]}, {name}={layout.tensor_map[d]}"
            )

infer_layout(cache_values) → ((output_layout,), None)

x_layout, cos_layout, sin_layout = cache_values
self._check_partial_inputs([x_layout, cos_layout, sin_layout])
self._validate_input_layouts(x_layout, cos_layout, sin_layout)
return (copy.deepcopy(x_layout),), None

get_expand_impl 不定义,继承 base class 默认实现(返回 None)。


文件二:hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml

RotaryPositionEmbedding:
  dist_op_name: _rotary_position_embedding_dist_op
  distributed_op_class: RotaryPositionEmbeddingDistributedOp
  distributed_op_file: parallel_rotary_position_embedding

仅注册 PascalCase(MindSpore Primitive 类名),不注册 snake_case。


文件三:tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py

不需要 NPU,mock platform,纯 Python 逻辑验证。

测试分组

TestNormalizeRpeArgs(3 个用例)

ID 用例 验证点
1 3 个位置参数,mode 默认 args == (x,cos,sin,0), kwargs == {}
2 mode=1 作关键字参数 args[3] == 1
3 mode=2 作位置参数 args[3] == 2

TestYamlRegistration(1 个用例)

ID 用例 验证点
4 PascalCase RotaryPositionEmbedding 返回 RotaryPositionEmbeddingDistributedOp 实例

TestInferLayoutPositive(正向,11 个用例)

ID 描述 mesh x placements cos placements 期望 output.tm
5 All Replicated 4D (1,) Replicate Replicate (-1,-1,-1,-1)
6 DP on B,cos Replicate (4,) dp Shard(0) Replicate (0,-1,-1,-1)
7 TP on N,cos Replicate (4,) tp Shard(1) Replicate (-1,0,-1,-1)
8 CP on S,cos Shard(S) (4,) sp Shard(2) Shard(2) (-1,-1,0,-1)
9 CP on S,cos Replicate (4,) sp Shard(2) Replicate (-1,-1,0,-1)
10 DP+TP 2D mesh (2,2) dp×tp (Shard(0),Shard(1)) (Shard(0),Replicate) (1,0,-1,-1)
11 DP+CP 2D mesh (2,2) dp×sp (Shard(0),Shard(2)) (Shard(0),Shard(2)) (1,-1,0,-1)
12 TP+CP 2D mesh (2,2) tp×sp (Shard(1),Shard(2)) (Replicate,Shard(2)) (-1,1,0,-1)
13 3D TND,All Replicate (1,) Replicate,ndim=3 Replicate,ndim=3 (-1,-1,-1)
14 3D TND,T-dim DP (4,) dp Shard(0),ndim=3 Replicate (0,-1,-1)
15 输出是独立深拷贝 any any any output is not x_layout

TestInferLayoutNegative(负向,7 个用例)

ID 触发条件 期望异常关键字
16 x.tensor_map[-1] != -1(D sharded) "D"
17 cos.tensor_map[-1] != -1 "D", "cos"
18 sin.tensor_map[-1] != -1 "D", "sin"
19 cos.tm[0]=1,x.tm[0]=0(B 不一致) "dim 0", "cos" 或等效
20 sin.tm[2]=1,x.tm[2]=0(S 不一致) "dim 2", "sin" 或等效
21 cos.tm[1]=0,x.tm[1]=-1(cos N-sharded 但 x N-replicated) "dim 1", "cos"
22 x.is_partial() → True ValueError(来自 _check_partial_inputs)

文件四:tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py

分布式系统测试,每 mesh 维度最大 size=2,最少占用卡数。

测试参数设计

# 满足 CANN 约束:B*N <= S*8(当D/2%16==0时),D<896,D为偶数
# fp16, D=64, D/2=32, 32%16==0 → 需 B*N <= S*8
# 全局shape: B=4, N=4, S=16, D=64 → B*N=16 <= S*8=128 ✓
B, N, S, D = 4, 4, 16, 64
MODE = 0  # rotate_half

# cos 形状根据场景变化:
#   "11SD" shape (1,1,S,D)  → N、B 均 broadcast
#   "B1SD" shape (B,1,S,D)  → 仅 N broadcast
#   "BNSD" shape (B,N,S,D)  → 无 broadcast

分布式验证逻辑(每个用例均采用):

  1. 固定 seed,生成全量 x_np, cos_np, sin_np
  2. 单机 standalone 计算(ops.RotaryPositionEmbedding()(x, cos, sin, MODE)),得到 ref_out
  3. 分布式:distribute_tensor → 各 rank 执行 → 从各 rank 汇聚 local 输出 → 拼接成 full_out
  4. 断言 np.allclose(full_out, ref_out, atol=1e-2, rtol=1e-2)
  5. (部分用例)验证 x.grad 数值也与 standalone 反向一致

2 卡测试用例(mesh (2,))

函数名 mesh x shape → shard cos shape → shard 验证项
test_rpe_replicated (2,) "dp" BNSD, all Replicate 11SD, Replicate fwd
test_rpe_dp_b (2,) "dp" BNSD, Shard(B) 11SD, Replicate fwd + x.grad
test_rpe_tp_n (2,) "tp" BNSD, Shard(N) 11SD, Replicate fwd

注:11SD 指 cos shape (1,1,S,D),N、B 均广播,cos 的 N/B dim 为 1,无法 shard,自然 Replicated。

4 卡测试用例(mesh (2, 2))

函数名 mesh x shard cos shape → shard 典型 tensor_map
test_rpe_dp_tp (2,2) "dp"×"tp" Shard(B)×Shard(N) B1SD, Shard(B)×Replicate x.tm=(1,0,-1,-1), cos.tm=(1,-1,-1,-1)
test_rpe_dp_sp (2,2) "dp"×"sp" Shard(B)×Shard(S) B1SD, Shard(B)×Shard(S) x.tm=(1,-1,0,-1), cos.tm=(1,-1,0,-1)
test_rpe_tp_sp (2,2) "tp"×"sp" Shard(N)×Shard(S) 11SD, Replicate×Shard(S) x.tm=(-1,1,0,-1), cos.tm=(-1,-1,0,-1)
test_rpe_dp_tp_cos_full (2,2) "dp"×"tp" Shard(B)×Shard(N) BNSD, Shard(B)×Shard(N) x.tm=(1,0,-1,-1), cos.tm=(1,0,-1,-1)

注:test_rpe_dp_tp_cos_full 验证 cos 为全量 BNSD 且与 x 同维度 shard 的合法路径。

验证项:

  • test_rpe_dp_tp:fwd + x.grad
  • test_rpe_dp_sp:fwd(验证 S-dim CP)
  • test_rpe_tp_sp:fwd
  • test_rpe_dp_tp_cos_full:fwd

文件五:tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py

IMPL_FILE = Path(__file__).resolve().parent / "rotary_position_embedding_shard_in_python.py"

# Group 1:2 卡,3 个用例并行执行(各占 2 卡)
@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group1():
    """
    Feature: RPE distributed ST — Replicated, DP-B, TP-N (2 cards each)
    Description:
        1. test_rpe_replicated — BNSD 全 Replicated,fwd
        2. test_rpe_dp_b      — BNSD B-dim DP,fwd+x.grad
        3. test_rpe_tp_n      — BNSD N-dim TP,cos 11SD broadcast,fwd
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_replicated", 19300, 2, 2, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_dp_b",       19301, 2, 2, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_tp_n",       19302, 2, 2, 2),
    ])

# Group 2:4 卡,2D mesh DP+TP / DP+SP
@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group2():
    """
    Feature: RPE distributed ST — 2D mesh DP+TP and DP+SP (4 cards)
    Description:
        1. test_rpe_dp_tp — 2D (dp=2,tp=2), x Shard(B,N), cos B1SD Shard(B,Replicate)
        2. test_rpe_dp_sp — 2D (dp=2,sp=2), x Shard(B,S), cos B1SD Shard(B,S)
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_dp_tp", 19303, 4, 4, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_dp_sp", 19304, 4, 4, 2),
    ])

# Group 3:4 卡,2D mesh TP+SP / cos 全量同 shard
@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level0", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group3():
    """
    Feature: RPE distributed ST — 2D mesh TP+SP and full BNSD cos (4 cards)
    Description:
        1. test_rpe_tp_sp       — 2D (tp=2,sp=2), x Shard(N,S), cos 11SD Shard(Replicate,S)
        2. test_rpe_dp_tp_cos_full — 2D (dp=2,tp=2), x Shard(B,N), cos BNSD same shard
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_tp_sp",        19305, 4, 4, 2),
        MindSporeCase(IMPL_FILE, "test_rpe_dp_tp_cos_full", 19306, 4, 4, 2),
    ])

4. 文件清单

文件路径 说明
hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py 核心实现:_normalize_rpe_args + RotaryPositionEmbeddingDistributedOp
hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml YAML 注册,仅 RotaryPositionEmbedding
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py UT:22 个用例,无 get_expand_impl 测试
tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py ST 执行逻辑:7 个用例,mesh 维度最大 2
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py ST runner:3 组,最多 4 卡

User · 2026-05-19T01:00:20.618Z

你提到的: 在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:

  • 若 cos 在 B 维 shape=1 → DTensor 无法 shard 该维 → cos.tensor_map[b_dim] == -1(replicated)
  • 若 cos 在 B 维 shape=B → DTensor 可 shard 或 replicated → cos.tensor_map[b_dim] == -1 或 == x.tensor_map[b_dim] 因此统一规则:若 cos.tensor_map[d] != -1,则它必须等于 x.tensor_map[d],否则 ValueError。此规则同时覆盖 B/N/S 三个维度,无需按 layout 字符串分类讨论。

实际上,你可以在proprocess中将DTensor/Tensor的shape取出,放在cache_values里,就能在infer_layout里使用了。但是你提到了在这个维度数量固定的输入 shape场景下,shape的值其实不重要,用tensor_map就想能确定广播的情况了?所以不需要缓存shape信息了?

MODE对layout有影响么?如果没有,就是透传即可?

你看需不需要加一个8卡的用例?切分BSN维度?


User · 2026-05-19T01:03:55.037Z

你提到的: 在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:

  • 若 cos 在 B 维 shape=1 → DTensor 无法 shard 该维 → cos.tensor_map[b_dim] == -1(replicated)
  • 若 cos 在 B 维 shape=B → DTensor 可 shard 或 replicated → cos.tensor_map[b_dim] == -1 或 == x.tensor_map[b_dim] 因此统一规则:若 cos.tensor_map[d] != -1,则它必须等于 x.tensor_map[d],否则 ValueError。此规则同时覆盖 B/N/S 三个维度,无需按 layout 字符串分类讨论。

实际上,你可以在proprocess中将DTensor/Tensor的shape取出,放在cache_values里,就能在infer_layout里使用了。但是你提到了在这个维度数量固定的输入 shape场景下,shape的值其实不重要,用tensor_map就想能确定广播的情况了?所以不需要缓存shape信息了?

MODE对layout有影响么?如果没有,就是透传即可?

你看需不需要加一个8卡的用例?切分BSN维度?


User · 2026-05-19T01:04:57.934Z

你提到的: 在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:

  • 若 cos 在 B 维 shape=1 → DTensor 无法 shard 该维 → cos.tensor_map[b_dim] == -1(replicated)
  • 若 cos 在 B 维 shape=B → DTensor 可 shard 或 replicated → cos.tensor_map[b_dim] == -1 或 == x.tensor_map[b_dim] 因此统一规则:若 cos.tensor_map[d] != -1,则它必须等于 x.tensor_map[d],否则 ValueError。此规则同时覆盖 B/N/S 三个维度,无需按 layout 字符串分类讨论。

实际上,你可以在proprocess中将DTensor/Tensor的shape取出,放在cache_values里,就能在infer_layout里使用了。但是你提到了在这个维度数量固定的输入 shape场景下,shape的值其实不重要,用tensor_map就想能确定广播的情况了?所以不需要缓存shape信息了?

MODE对layout有影响么?如果没有,就是透传即可?

你看需不需要加一个8卡的用例?切分BSN维度?


User · 2026-05-19T01:22:30.230Z

你提到的: 在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:

  • 若 cos 在 B 维 shape=1 → DTensor 无法 shard 该维 → cos.tensor_map[b_dim] == -1(replicated)
  • 若 cos 在 B 维 shape=B → DTensor 可 shard 或 replicated → cos.tensor_map[b_dim] == -1 或 == x.tensor_map[b_dim] 因此统一规则:若 cos.tensor_map[d] != -1,则它必须等于 x.tensor_map[d],否则 ValueError。此规则同时覆盖 B/N/S 三个维度,无需按 layout 字符串分类讨论。

实际上,你可以在proprocess中将DTensor/Tensor的shape取出,放在cache_values里,就能在infer_layout里使用了。但是你提到了在这个维度数量固定的输入 shape场景下,shape的值其实不重要,用tensor_map就想能确定广播的情况了?所以不需要缓存shape信息了?

MODE对layout有影响么?如果没有,就是透传即可?

你看需不需要加一个8卡的用例?切分BSN维度?


Assistant · 2026-05-19T01:23:08.200Z

三个问题依次分析:


1. 需不需要缓存 shape?

结论:不需要。 你的推导是对的。

tensor_map 和广播语义是天然一致的:

  • cos 某维 shape=1 → DTensor 物理上无法 shard 该维 → tensor_map[d] 只能是 -1
  • cos 某维 shape=full → DTensor 可以 shard 或不 shard → tensor_map[d] 是 mesh 轴编号或 -1

所以校验规则 if cos.tensor_map[d] != -1, must == x.tensor_map[d] 已经能完整覆盖所有 broadcast 情形,不需要额外缓存 shape,preprocess 和 cache_values 的设计保持原样。


2. MODE 对 layout 有影响么?

没有影响,透传即可。

mode x_rotate 构造方式 output shape
0 rotate_half concat([-x[D//2:], x[:D//2]]) = x.shape
1 interleave 奇偶位交错 = x.shape
2 quarter 4 段轮换 = x.shape
3 interleave-half 先交织再 half = x.shape

所有 mode 下:

  • 输出 shape 完全等于 x shape
  • D 维始终是旋转的工作维度,始终不可 shard
  • B/N/S 维度的独立性不受影响

mode 不进入 cache_values(它不影响 layout 推导,也不影响 layout 缓存 key),只作为 kernel 参数随 local_args 透传到算子调用。


3. 要不要加 8 卡用例覆盖 B+N+S 三维同时切分?

建议加一个。 理由:

  • 当前 4 卡用例(mesh (2,2))最多覆盖两个维度同时切分
  • B+N+S 三维同时切分(mesh (2,2,2))是 DP+TP+CP 组合并行的最典型场景,也是 RPE 在实际 LLM 训练中的高频用法
  • 该场景的 tensor_map 是三轴混合,覆盖的校验路径和 4 卡用例不重叠,有独立测试价值

用例设计

mesh: (2, 2, 2)  names = ("dp", "tp", "sp")
mesh axes: dp=0, tp=1, sp=2

x shape (4, 4, 16, 64), BNSD:
  B → dp(axis 0)
  N → tp(axis 1)  
  S → sp(axis 2)
  D → replicated
  placements: (Shard(0), Shard(1), Shard(2)) on (dp, tp, sp)
  x.tm = (0, 1, 2, -1)  [读法:B→mesh轴0, N→mesh轴1, S→mesh轴2, D→-1]

cos shape (1, 1, 16, 64), 11SD:
  B=1 → replicated (无法 shard)
  N=1 → replicated (无法 shard)
  S → sp(axis 2)
  D → replicated
  placements: (Replicate, Replicate, Shard(2)) on (dp, tp, sp)
  cos.tm = (-1, -1, 2, -1)

validation:
  cos.tm[0]=-1 ← x.tm[0]=0,cos 为 -1,允许 ✓
  cos.tm[1]=-1 ← x.tm[1]=1,cos 为 -1,允许 ✓
  cos.tm[2]=2  ← x.tm[2]=2,一致 ✓
  cos.tm[3]=-1 ← D replicated ✓

Shape 验证(每 rank 本地数据):

  • local x: (2, 2, 8, 64) → B_local×N_local = 4 ≤ S_local×8 = 64 ✓

加入 ST runner 为 Group 4(单独一组,8 卡,level1):

@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
def test_parallel_rpe_ms_group4():
    """
    Feature: RPE distributed ST — 3D mesh DP+TP+CP (8 cards)
    Description:
        test_rpe_dp_tp_sp — 3D (dp=2,tp=2,sp=2), x Shard(B,N,S),
            cos 11SD Shard(Replicate,Replicate,S)
    Expectation: Run success.
    """
    parallel_run([
        MindSporeCase(IMPL_FILE, "test_rpe_dp_tp_sp", 19307, 8, 8, 2),
    ])

验证项:fwd 结果与 standalone 对齐即可(8 卡反向成本较高,不强要求)。


System

正在为 MindSpore RPE(旋转位置编码)实现 HyperParallel 分布式算子。计划文档已确认,下一步开始编写代码实现。 (disable recaps in /config)


User · 2026-05-19T01:50:38.867Z

计划文档存到docs下面吧,然后开始编码实现。


Assistant · 2026-05-19T01:50:51.937Z

[Bash: ls /root/workspace/hyper-parallel/docs/ | head -20]
1-npu-dense-lightning-indexer-softmax-l-cheerful-yeti.md
1-torch-mindspore-virtual-stonebraker.md
3-commit-1-3-dense-lightning-indexer-gr-snoopy-toast.md
ISSUE.md
PR_description.md
ci310_install_troubleshooting.md
claude_workflow.md
dfunction.md
distributed_op_migration_audit_report.md
distributed_op_migration_guide.md
dsa_distributed_op_analysis.md
ep_deleted_code.md
etp.md
expert_parallel.md
hyper-parallel-ep-commit-f0fa78f686caa8f-prancy-donut.md
images
issues
lightning_indexer_implementation_plan.md
memoized-seeking-honey.md
mhc
[Bash: head -3 /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py]
# Copyright 2026 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
[Write: /root/workspace/hyper-parallel/docs/rotary_position_embedding_dist_op_plan.md (6242 chars)]
File created successfully at: /root/workspace/hyper-parallel/docs/rotary_position_embedding_dist_op_plan.md (file state is current in your context — no need to Read it back)

先存计划文档,然后依次实现所有文件。


Assistant · 2026-05-19T01:52:59.584Z

[Bash: ls /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/ | head -20]
activation_with_axis_ops.yaml
argmax_with_value_ops.yaml
argsort.yaml
chunk_view_ops.yaml
concat_ops.yaml
cumsum_ops.yaml
element_wise_ops.yaml
element_wise_ops_with_shape.yaml
embedding_ops.yaml
expand_dims_ops.yaml
flash_attention_score.yaml
gather_ops.yaml
histc_ext.yaml
inplace_scatter_value_ops.yaml
lightning_indexer_ops.yaml
matmul_ops.yaml
multinomial_ops.yaml
norm_ops.yaml
npu_dense_lightning_indexer_grad_kl_loss_ops.yaml
npu_dense_lightning_indexer_softmax_lse_ops.yaml
[Bash: cat /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py | head -100]
# Copyright 2026 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
"""MindSpore distributed ST for npu_sparse_flash_attention.

Pipeline: ops.lightning_indexer(q_idx, k_idx, w) → sparse_indices
          → ops.sparse_flash_attention(q, k, v, sparse_indices, ...).

The two ops use different head_dim projections of the same sequence:
  - lightning_indexer : q_idx/k_idx head_dim = D_IDX = 128 (kernel constraint)
  - sparse_flash_attention : q/k head_dim = D_DIM = 512 (MLA attention_mode=2 constraint)

For BSND+CP the lightning_indexer distributed op slices k_idx to the causal window
``k_idx[:, :S1_local*(split_id+1), :, :]``; the sparse_flash_attention distributed op
applies the same slice to k/v/key_rope, so sparse_indices remain valid.  This mirrors
MindFormers adjust_bsnd_input logic.

Distributed sharding patterns verified against MindFormers dsa_attention.py shard():
  - BSND: q/si sharded on B (dp) and/or S1 (cp); k/v sharded on B (dp) only.
  - TND:  q/si sharded on T1 = dp*cp combined; k/v sharded on T2 = dp only.
"""
import numpy as np
import mindspore as ms
import mindspore.communication.management as D
from mindspore import Tensor, ops
from mindspore.ops import sparse_flash_attention
from hyper_parallel import init_device_mesh
from hyper_parallel.core.dtensor.dtensor import DTensor, distribute_tensor
from hyper_parallel.core.dtensor.placement_types import Shard, Replicate, Partial


def setup_module():
    """Initialize MindSpore context and communication."""
    ms.context.set_context(mode=ms.context.PYNATIVE_MODE, device_target="Ascend")
    D.init()


np.random.seed(42)
ms.set_seed(42)
ms.set_deterministic(True)

# sparse_flash_attention head dims (attention_mode=2 MLA kernel constraints).
N2 = 1
D_DIM = 512       # qk_head_dim for sparse_flash_attention (must be 512)
DR_DIM = 64       # rope head_dim
SCALE_VALUE = 0.135234

# lightning_indexer head dim (kernel constraint: must be 128).
D_IDX = 128

# BSND layout — replicated/DP tests.
B_BSND = 4
S1_BSND = 4
S2_BSND = 1024
N1_BSND = 8

# Number of top-k blocks for lightning_indexer (non-CP BSND).
SPARSE_COUNT_BSND = 8

# BSND layout — CP/dp+cp tests (realistic self-attention scenario).
# S1_BSND_CP=S2_BSND_CP are the GLOBAL sequence lengths (Q and K come from the same
# sequence).  CP=2 splits Q on S1: each rank processes S1_local=S1_BSND_CP//2 query tokens.
# K is Replicate (full length on each rank); the distributed op truncates it to the
# causal window per rank: rank r sees k[:, :S1_local*(r+1), :, :].
# S1=S2 (self-attention) ensures causal truncation is lossless for rank 0.
# SPARSE_COUNT_CP <= S1_local = S1_BSND_CP // 2.
B_BSND_CP = 2
N1_BSND_CP = 32
S1_BSND_CP = 1024
S2_BSND_CP = 1024
SPARSE_COUNT_CP = 128

# TND layout: T1=T2=1024, N1=8.
S_TND = 1024
N1_TND = 8
BATCH_DIM = 128
SPARSE_COUNT_TND = 8

_INPUT_NAMES = ("query", "key", "value", "query_rope", "key_rope")
_FWD_OUTPUT_NAMES = ("attention_out", "softmax_max", "softmax_sum")


def _make_tnd_seq_lens():
    """Build TND actual_seq_lengths tensors (prefix sums, int32, shape (128,))."""
    step = S_TND // BATCH_DIM
    arr = (np.arange(BATCH_DIM, dtype=np.int32) + 1) * step
    t = Tensor(arr, ms.int32)
    return t, Tensor(arr.copy(), ms.int32)
[Read: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py]
100	
101	
102	def _make_tnd_local_seq_lens():
103	    """Build LOCAL TND actual_seq_lengths for DP test (half batch per rank)."""
104	    local_batch = BATCH_DIM // 2
105	    local_s = S_TND // 2
106	    step = local_s // local_batch
107	    arr = (np.arange(local_batch, dtype=np.int32) + 1) * step
108	    t = Tensor(arr, ms.int32)
109	    return t, Tensor(arr.copy(), ms.int32)
110	
111	
112	
113	def _np_to_bf16(arr):
114	    """Convert float32 numpy array to MindSpore bfloat16 Tensor."""
115	    return Tensor(arr, ms.bfloat16)
116	
117	
118	def _to_f32np(t):
119	    """Convert a MindSpore tensor (any dtype) to float32 numpy array."""
120	    return t.astype(ms.float32).asnumpy()
121	
122	
123	def _generate_inputs(layout='BSND', s1=None, s2=None, n1=None, b=None):
124	    """Generate random float32 numpy arrays for BSND or TND layout.
125	
126	    Returns two groups of tensors:
127	      - SFA group (D_DIM=512): q, k, v, q_rope, k_rope
128	      - Indexer group (D_IDX=128): q_idx, k_idx, w
129	        q_idx/k_idx share the same B/S1/S2 dims as q/k but with D_IDX head_dim.
130	        w has shape (B, S1, N1) for BSND or (T1, N1) for TND.
131	
132	    Args:
133	        layout: 'BSND' or 'TND'.
134	        s1: Query sequence length (BSND only; defaults to S1_BSND).
135	        s2: Key/value sequence length (BSND only; defaults to S2_BSND).
136	        n1: Number of query heads (BSND only; defaults to N1_BSND).
137	        b: Batch size (BSND only; defaults to B_BSND).
138	
139	    Returns:
140	        tuple: (q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np)
141	    """
142	    if layout == 'BSND':
143	        s1 = s1 if s1 is not None else S1_BSND
144	        s2 = s2 if s2 is not None else S2_BSND
145	        n1 = n1 if n1 is not None else N1_BSND
146	        b = b if b is not None else B_BSND
147	        # SFA tensors (D_DIM=512)
148	        q_np = np.random.randn(b, s1, n1, D_DIM).astype(np.float32)
149	        k_np = np.random.randn(b, s2, N2, D_DIM).astype(np.float32)
150	        v_np = k_np.copy()
151	        q_rope_np = np.random.randn(b, s1, n1, DR_DIM).astype(np.float32)
152	        k_rope_np = np.random.randn(b, s2, N2, DR_DIM).astype(np.float32)
153	        # Indexer tensors (D_IDX=128)
154	        q_idx_np = np.random.randn(b, s1, n1, D_IDX).astype(np.float32)
155	        k_idx_np = np.random.randn(b, s2, N2, D_IDX).astype(np.float32)
156	        w_np = np.random.randn(b, s1, n1).astype(np.float32)
157	    else:  # TND
158	        # SFA tensors (D_DIM=512)
159	        q_np = np.random.randn(S_TND, N1_TND, D_DIM).astype(np.float32)
160	        k_np = np.random.randn(S_TND, N2, D_DIM).astype(np.float32)
161	        v_np = k_np.copy()
162	        q_rope_np = np.random.randn(S_TND, N1_TND, DR_DIM).astype(np.float32)
163	        k_rope_np = np.random.randn(S_TND, N2, DR_DIM).astype(np.float32)
164	        # Indexer tensors (D_IDX=128)
165	        q_idx_np = np.random.randn(S_TND, N1_TND, D_IDX).astype(np.float32)
166	        k_idx_np = np.random.randn(S_TND, N2, D_IDX).astype(np.float32)
167	        w_np = np.random.randn(S_TND, N1_TND).astype(np.float32)
168	    return q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np
169	
170	
171	def _call_sfa(q, k, v, si, q_rope, k_rope,
172	              actual_seq_lengths_query=None, actual_seq_lengths_kv=None,
173	              layout='BSND'):
174	    """Call sparse_flash_attention with an explicit layout string.
175	
176	    For BSND, actual_seq_lengths_query and actual_seq_lengths_kv should be
177	    None (kernel infers from tensor shape); for TND they must be passed.
178	    Omitted parameters use kernel defaults: sparse_mode=3 (rightDownCausal),
179	    sparse_block_size=1, pre_tokens/next_tokens=INT64_MAX.
180	
181	    Args:
182	        q: Query tensor (D_DIM=512).
183	        k: Key tensor (D_DIM=512).
184	        v: Value tensor (D_DIM=512).
185	        si: Sparse indices tensor (int32), generated by lightning_indexer.
186	        q_rope: Query rope tensor.
187	        k_rope: Key rope tensor.
188	        actual_seq_lengths_query: Cumulative query lengths (TND only).
189	        actual_seq_lengths_kv: Cumulative kv lengths (TND only).
190	        layout: Layout string ('BSND' or 'TND').
191	
192	    Returns:
193	        tuple: (attention_out, softmax_max, softmax_sum)
194	    """
195	    return sparse_flash_attention(
196	        q, k, v, si, SCALE_VALUE,
197	        actual_seq_lengths_query=actual_seq_lengths_query,
198	        actual_seq_lengths_kv=actual_seq_lengths_kv,
199	        query_rope=q_rope, key_rope=k_rope,
200	        layout_query=layout, layout_kv=layout,
201	        attention_mode=2,
202	        return_softmax_lse=True,
203	    )
204	
205	
206	def _get_sparse_indices_bsnd(q_idx, k_idx, w, sparse_count):
207	    """Run lightning_indexer in BSND mode and return sparse_indices.
208	
209	    Uses q_idx/k_idx with D_IDX=128 (lightning_indexer kernel constraint).
210	    sparse_mode defaults to 3 (rightDownCausal); for BSND+CP the CP impl
211	    truncates k_idx to the causal window before calling the kernel.
212	
213	    Args:
214	        q_idx: Query index tensor (B, S1, N1, D_IDX=128).
215	        k_idx: Key index tensor (B, S2, N2, D_IDX=128).
216	        w: Weights tensor (B, S1, N1).
217	        sparse_count: Number of top-k blocks to select.
218	
219	    Returns:
[Bash: cat /root/workspace/hyper-parallel/tests/common/parallel_case.py | head -80]
# Copyright 2026 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
"""parallel run case"""
import os
import signal
import multiprocessing as mp
from typing import Union


class TorchCase:
    """torch case messages"""

    def __init__(self, file_name: str, case_name: str, master_port: int, num_proc: int = 1):
        self.file_name = file_name
        self.case_name = case_name
        self.master_port = master_port
        self.num_proc = num_proc


class MindSporeCase:
    """mindspore case messages"""

    def __init__(self, file_name: str, case_name: str, master_port: int, worker_num: int = 1, local_worker_num: int = 1,
                 glog_v: int = 3):
        self.glog_v = glog_v
        self.file_name = file_name
        self.case_name = case_name
        self.master_port = master_port
        self.num_proc = worker_num
        self.local_worker_num = local_worker_num


def run_case(visible_devices, case: Union[TorchCase, MindSporeCase]):
    """
    run case in child process
    """
    # become the leader of a new process group so that os.killpg on timeout
    # kills torchrun/msrun worker sub-processes as well as this wrapper
    os.setsid()
    # set visible devices for current case
    os.environ['ASCEND_RT_VISIBLE_DEVICES'] = ','.join(map(str, visible_devices))
    if isinstance(case, TorchCase):
        # pylint: disable=C0415
        from tests.torch.utils import torchrun_case
        torchrun_case(case.file_name, case.case_name, case.master_port, case.num_proc)
    elif isinstance(case, MindSporeCase):
        # pylint: disable=C0415
        from tests.mindspore.st.utils import msrun_case
        msrun_case(case.glog_v, case.file_name, case.case_name, case.master_port, case.num_proc, case.local_worker_num)


def parallel_run(cases: Union[list[TorchCase], list[MindSporeCase]], global_num_proc: int = 8):
    """
    parallel run cases

    Args:
        cases (list[Case]): list of case messages to be run parallel
        global_num_proc (int, optional): number of total num of process. Defaults to 8.
    """
    # assign devices
    sum_num_proc = 0
    assignments = []

    for case in cases:
        num = case.num_proc
        devices = list(range(sum_num_proc, sum_num_proc + num))
        assignments.append(devices)
        sum_num_proc += num
[Bash: grep -n "yaml\|load_ops\|discover\|register" /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | grep -i "yaml\|load\|discover\]
24:import yaml
234:        self._env_yaml_dir: Optional[str] = os.environ.get("HYPER_PARALLEL_OPS_YAML_DIR")
236:        # The following attributes are initialized in _setup_yaml_dir()
237:        self.work_dir = ""  # Initialized in _setup_yaml_dir()
238:        self.yaml_dir = ""  # Initialized in _setup_yaml_dir()
242:        self.layout_infer_ops = self.safe_load_yaml_from_dir()
282:        self._setup_yaml_dir(self._env_yaml_dir)
285:    def _setup_yaml_dir(self, env_yaml_dir: Optional[str]):
287:        Feature: Configure yaml_dir/work_dir for OpDispatcher
289:                     If env_yaml_dir is an absolute path, use it directly; otherwise treat it
290:                     as a path relative to the project work_dir. If env_yaml_dir is not set,
291:                     fall back to the default 'shard/ops/yaml' under work_dir.
292:        Expectation: self.yaml_dir and self.work_dir are set to valid values used later by
293:                     safe_load_yaml_from_dir(); no functional behavior is changed.
295:        if env_yaml_dir:
296:            if os.path.isabs(env_yaml_dir):
297:                self.yaml_dir = env_yaml_dir
303:                self.yaml_dir = env_yaml_dir
305:            self.yaml_dir = "shard/ops/yaml"
794:    def safe_load_yaml_from_dir(self) -> dict:
[Bash: grep -n "def _load\|yaml.load\|glob\|importlib" /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | head -20]
19:import glob
20:import importlib
87:    global _no_skip_ops
97:    global _no_skip_ops
108:    global _dtensor_dispatch
119:    global _dtensor_dispatch
338:            module = importlib.import_module(module_name)
346:            module = importlib.import_module(module_name)
351:                module = importlib.import_module(module_file)
736:        global_shape = input_tensor.shape
743:        extra_args.append(global_shape)
744:        cache_key_values = [str(layout_id), str(begin), str(end), str(global_shape)]
806:        for yaml_file_path in glob.glob(os.path.join(yaml_path, '*.yaml')):
845:                global_shape=first_arg.shape,
914:            True when the op is whitelisted or DTensor dispatch is globally disabled.
[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py]
330	                     provided via env, fall back to importing 'distributed_op_file' directly.
331	        Expectation: The distributed op class is imported and instantiated successfully,
332	                     or the original import error is raised; no functional behavior is changed.
333	        """
334	        class_name = config["distributed_op_class"]
335	
336	        if "distributed_op_module" in config:
337	            module_name = config["distributed_op_module"]
338	            module = importlib.import_module(module_name)
339	            op_class = getattr(module, class_name)
340	            _ = op_class(op_name)
341	            return
342	
343	        module_file = config["distributed_op_file"]
344	        try:
345	            module_name = "hyper_parallel.core.shard.ops." + module_file
346	            module = importlib.import_module(module_name)
347	            op_class = getattr(module, class_name)
348	            _ = op_class(op_name)
349	        except (ModuleNotFoundError, ImportError):
350	            if self._env_python_path:
351	                module = importlib.import_module(module_file)
352	                op_class = getattr(module, class_name)
353	                _ = op_class(op_name)
354	            else:
355	                raise
356	
357	    @staticmethod
358	    def _process_args_and_kwargs(
359	        args, kwargs
360	    ) -> tuple[list, list, list, dict, list]:
361	        """_process_args_and_kwargs"""
362	        input_layouts = []
363	        extra_args = []
364	        input_args = []
365	        input_kwargs = kwargs.copy()
366	        cache_key_values = []
367	
368	        for arg in args:
369	            if arg is None:
[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py]
794	    def safe_load_yaml_from_dir(self) -> dict:
795	        """
796	        Load yaml dictionary from directory.
797	
798	        Returns:
799	            dict: Merged dictionary of all operator configurations loaded from YAML files.
800	        """
801	        yaml_dict = {}
802	        yaml_path = os.path.join(self.work_dir, self.yaml_dir) if self.work_dir else self.yaml_dir
803	        if not os.path.isdir(yaml_path):
804	            raise ValueError(f"Invalid yaml directory path: {yaml_path}")
805	
806	        for yaml_file_path in glob.glob(os.path.join(yaml_path, '*.yaml')):
807	            with open(yaml_file_path, 'r', encoding="utf-8") as f:
808	                yaml_data = yaml.safe_load(f)
809	
810	            yaml_data = OpDispatcher._merge_default(yaml_data)
811	            for name, data in yaml_data.items():
812	                if name in yaml_dict:
813	                    raise ValueError(f"Duplicate yaml object with name '{name}'.")
814	                yaml_dict[name] = data
815	
816	        return yaml_dict
817	
818	    def _dispatch_random_op(self, op_name: str, op_call: callable, args, kwargs):
819	        """Handle dispatch for random ops that operate on DTensors."""
820	        first_arg = next(
821	            (x for x in chain(args, kwargs.values()) if isinstance(x, DTensor)),
822	            None,
823	        )
824	        # Fall back to the default op if no DTensor is found.
825	        if first_arg is None:
826	            return op_call(*args, **kwargs)
827	
828	        local_args = [arg.to_local() if isinstance(arg, DTensor) else arg for arg in args]
829	        local_kwargs = {k: v.to_local() if isinstance(v, DTensor) else v for k, v in kwargs.items()}
830	        first_local_arg = first_arg.to_local()
831	
832	        if self._rng_tracker is None and is_rng_supported_mesh():
833	            self._rng_tracker = OffsetBasedRNGTracker()
834	
835	        maybe_user_generator = local_kwargs.pop("generator", None)
836	        if (
837	            self._rng_tracker is not None
838	            and not first_local_arg.is_meta
839	            and self._rng_tracker.distribute_region_enabled
840	        ):
841	            # pylint: disable=W0212
842	            with self._rng_tracker._distribute_region(
843	                device_mesh=first_arg.device_mesh,
[Bash: grep -n "OpDispatcher()" /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py | head -5]
1011:_OP_DISPATCHER = OpDispatcher()
[Bash: grep -rn "OpDispatcher\(\)" /root/workspace/hyper-parallel/hyper_parallel/ | head -10]
ugrep: error: error at position 19
(?m)OpDispatcher\(\)
                   \___empty (sub)expression
[Bash: grep -rn "OpDispatcher()" /root/workspace/hyper-parallel/hyper_parallel/ 2>/dev/null | head -10]
/root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py:1011:_OP_DISPATCHER = OpDispatcher()
[Bash: head -30 /root/workspace/hyper-parallel/hyper_parallel/core/dtensor/dtensor.py | grep import]
import copy as cp
import inspect
import warnings
from typing import Any, Callable, Optional, Sequence, Set, Tuple, Union
import numpy as np
from hyper_parallel.core.dtensor.device_mesh import _mesh_resources
from hyper_parallel.core.dtensor.layout import Layout, DeviceMesh, _get_slice_tensor_by_layout
from hyper_parallel.core.dtensor.placement_types import Placement, Replicate
from hyper_parallel.platform import get_platform
from hyper_parallel.platform.platform import PlatformType
from hyper_parallel.core.utils import compute_local_shape_and_global_offset
[Bash: grep -n "op_dispatch\|_OP_DISPATCHER" /root/workspace/hyper-parallel/hyper_parallel/core/dtensor/dtensor.py | head -10]
62:        from hyper_parallel.core.shard._op_dispatch import disable_dtensor_dispatch, add_no_skip_ops
69:        from hyper_parallel.core.shard._op_dispatch import enable_dtensor_dispatch, remove_no_skip_ops
[Bash: grep -n "op_dispatch" /root/workspace/hyper-parallel/hyper_parallel/__init__.py 2>/dev/null | head -5; cat /root/workspace/hyper-parallel/hyper_parall]
# Copyright 2025 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
[Bash: grep -rn "op_dispatch\|_OP_DISPATCHER" /root/workspace/hyper-parallel/hyper_parallel/ --include="__init__.py" 2>/dev/null | head -10]
(Bash completed with no output)
[Bash: python3 -c " import os os.environ['HYPER_PARALLEL_PLATFORM'] = 'torch' import sys sys.path.insert(0, '/root/workspace/hyper-parallel') from hyper_para]
op: <hyper_parallel.core.shard.ops.parallel_npu_sparse_flash_attention.SparseFlashAttentionDistributedOp object at 0x7c391d80ea70>
type: <class 'hyper_parallel.core.shard.ops.parallel_npu_sparse_flash_attention.SparseFlashAttentionDistributedOp'>
[Bash: cat /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/__init__.py 2>/dev/null | head -20]
# Copyright 2025 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
"""Interfaces for parallel-related functionality"""
[Bash: python3 -c " import os os.environ['HYPER_PARALLEL_PLATFORM'] = 'torch' import sys sys.path.insert(0, '/root/workspace/hyper-parallel') # trace which m]
(Bash completed with no output)
[Bash: python3 -c " import os, sys os.environ['HYPER_PARALLEL_PLATFORM'] = 'torch' sys.path.insert(0, '/root/workspace/hyper-parallel') import importlib, tra]
op_dispatch loaded!
[Bash: grep -rn "op_dispatch\|_op_dispatch" /root/workspace/hyper-parallel/hyper_parallel/platform/torch/ --include="*.py" | grep "import" | head -10]
/root/workspace/hyper-parallel/hyper_parallel/platform/torch/dtensor.py:76:        from hyper_parallel.core.shard._op_dispatch import _OP_DISPATCHER
[Bash: grep -rn "from.*op_dispatch\|import.*op_dispatch" /root/workspace/hyper-parallel/hyper_parallel/ --include="*.py" | grep -v "test\|__pycache__" | head]
/root/workspace/hyper-parallel/hyper_parallel/core/dtensor/dtensor.py:62:        from hyper_parallel.core.shard._op_dispatch import disable_dtensor_dispatch, add_no_skip_ops
/root/workspace/hyper-parallel/hyper_parallel/core/dtensor/dtensor.py:69:        from hyper_parallel.core.shard._op_dispatch import enable_dtensor_dispatch, remove_no_skip_ops
/root/workspace/hyper-parallel/hyper_parallel/core/shard/dfunction.py:20:from hyper_parallel.core.shard._op_dispatch import _OP_DISPATCHER
/root/workspace/hyper-parallel/hyper_parallel/platform/mindspore/dtensor.py:129:        from hyper_parallel.core.shard._op_dispatch import _OP_DISPATCHER
/root/workspace/hyper-parallel/hyper_parallel/platform/torch/dtensor.py:76:        from hyper_parallel.core.shard._op_dispatch import _OP_DISPATCHER
[Bash: grep -n "from hyper_parallel.core.shard.dfunction\|import dfunction" /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops.py /roo]
(Bash completed with no output)
[Bash: grep -rn "from.*dfunction\|import.*dfunction" /root/workspace/hyper-parallel/hyper_parallel/core/shard/ --include="*.py" | grep -v "__pycache__" | hea]
(Bash completed with no output)
[Bash: cat /root/workspace/hyper-parallel/hyper_parallel/core/shard/__init__.py | head -30]
# Copyright 2025 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
[Bash: grep -rn "dfunction" /root/workspace/hyper-parallel/hyper_parallel/ --include="__init__.py" | head -5]
/root/workspace/hyper-parallel/hyper_parallel/__init__.py:30:from hyper_parallel.core.shard.dfunction import DFunction
[Bash: grep -rn "import.*dfunction\|from.*dfunction" /root/workspace/hyper-parallel/hyper_parallel/ --include="*.py" | grep -v "__pycache__" | head -10]
/root/workspace/hyper-parallel/hyper_parallel/__init__.py:30:from hyper_parallel.core.shard.dfunction import DFunction
/root/workspace/hyper-parallel/hyper_parallel/platform/mindspore/custom_ops/custom_op_impl.py:21:from hyper_parallel.core.shard.dfunction import DFunction
[Write: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py (6046 chars)]
File created successfully at: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py (file state is current in your context — no need to Read it back)
[Write: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml (195 chars)]
File created successfully at: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml (file state is current in your context — no need to Read it back)
[Write: /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py (20237 chars)]
File created successfully at: /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py (file state is current in your context — no need to Read it back)

现在开始编码实现。先读取必要的参考文件,然后并行实现所有文件。

信息已充分,开始并行实现所有文件。

现在实现 UT 测试文件:


System

Conversation compacted


User · 2026-05-19T02:04:35.189Z

This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.

Summary:

  1. Primary Request and Intent: The user requested implementing a distributed operator for mindspore.ops.rotary_position_embedding (RotaryPositionEmbedding) in HyperParallel, following the sparse_flash_attention (SFA) pattern. The workflow was:

    1. First produce a plan document covering file list, classes/interfaces, layout rules per parameter, constraints, and UT/ST test cases
    2. After iterative feedback to refine the plan
    3. Save the plan to docs/ directory
    4. Begin coding implementation of all 5 files

    Key user requirements clarified iteratively:

    • B/N/S dimensions CAN be sharded; D (last dim) must always be replicated
    • S can be sharded (element-wise independence in formula)
    • No _to_local helper — all inputs are DTensors, use t.to_local() directly
    • No get_expand_impl needed (RPE has no causal window logic unlike SFA)
    • YAML: only RotaryPositionEmbedding (PascalCase), no snake_case entry
    • ST tests: each mesh dim max size=2, use as few cards as possible, include multi-dim mesh scenarios
    • One 8-card test for B+N+S 3D mesh sharding (2,2,2)
    • MODE does not affect layout — passes through as kernel parameter
    • No shape caching needed — tensor_map alone captures broadcast semantics
  2. Key Technical Concepts:

    • RotaryPositionEmbedding formula: y = x * cos + x_rotate * sin where x_rotate rotates within D dim. All B, N, S positions are independent → freely shardable. D dim is indivisible.
    • tensor_map axis convention: In HyperParallel, the rightmost mesh dimension = tensor_map axis 0. For 2D mesh (dp, tp) shape (2,2): dp→axis 1, tp→axis 0. For 3D (dp,tp,sp): dp→axis 2, tp→axis 1, sp→axis 0.
    • Broadcast semantics mapped by tensor_map: If cos has shape 1 on dim d → DTensor can't shard it → tensor_map[d]=-1 naturally. No need to check actual shapes.
    • Validation rule: if cos.tensor_map[d] != -1, then it must equal x.tensor_map[d]
    • YAML loading chain: Any hyper_parallel.* import triggers hyper_parallel/__init__.pydfunction.py_op_dispatch.py module-level _OP_DISPATCHER = OpDispatcher() → loads all YAML files → instantiates and registers all distributed ops
    • DistributedOp base class: preprocess()infer_layout()get_expand_impl()wrap_output() dispatch flow
    • New preprocess dispatch flow: preprocess() returns (local_args, local_kwargs, cache_values), then infer_layout(cache_values) returns ((output_layouts...,), extra_info)
    • cache_values for RPE: [x_layout, cos_layout, sin_layout] — no shape needed
    • CANN constraints: x supports BNSD/BSND/SBND/TND; D < 896, even; BN ≤ S8 (when D/2%16==0 for fp16); cos/sin can be 11SD, B1SD, BNSD for BNSD x
    • ST test shapes: B=4, N=4, S=16, D=64 — satisfies BN=16 ≤ S8=128 ✓
  3. Files and Code Sections:

    • /root/workspace/hyper-parallel/docs/rotary_position_embedding_dist_op_plan.md (created)

      • Plan document covering interface analysis, layout rules, file list, UT/ST test cases
    • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py (created, COMPLETE)

      • Core distributed op implementation
      # Copyright 2026 Huawei Technologies Co., Ltd
      # ... Apache 2.0 license header ...
      """Distributed implementation for RotaryPositionEmbedding operator."""
      import copy
      from typing import Optional, Tuple
      from .parallel_ops import DistributedOp
      
      def _normalize_rpe_args(x, cos, sin, mode=0):
          """Normalize positional and keyword arguments into a canonical positional tuple."""
          return (x, cos, sin, mode), {}
      
      class RotaryPositionEmbeddingDistributedOp(DistributedOp):
          @staticmethod
          def _validate_input_layouts(x_layout, cos_layout, sin_layout) -> None:
              op = "rotary_position_embedding"
              x_tm = x_layout.tensor_map
              if x_tm[-1] != -1:
                  raise ValueError(
                      f"For {op}, D (last dim) of x must be replicated, "
                      f"but got tensor_map={x_tm}"
                  )
              for name, layout in [('cos', cos_layout), ('sin', sin_layout)]:
                  tm = layout.tensor_map
                  if tm[-1] != -1:
                      raise ValueError(
                          f"For {op}, D (last dim) of {name} must be replicated, "
                          f"but got tensor_map={tm}"
                      )
                  for d in range(len(tm) - 1):
                      x_d = x_tm[d] if d < len(x_tm) - 1 else -1
                      if tm[d] != -1 and tm[d] != x_d:
                          raise ValueError(
                              f"For {op}, {name} sharding on dim {d} must match x or be replicated, "
                              f"but got x={x_d}, {name}={tm[d]}"
                          )
      
          def preprocess(self, args: tuple, kwargs: dict) -> Optional[tuple]:
              norm_args, _ = _normalize_rpe_args(*args, **kwargs)
              x, cos, sin, mode = norm_args
              local_args = (x.to_local(), cos.to_local(), sin.to_local(), mode)
              cache_values = [x.layout, cos.layout, sin.layout]
              return local_args, {}, cache_values
      
          def infer_layout(self, cache_values: list) -> Tuple[tuple, None]:
              x_layout, cos_layout, sin_layout = cache_values
              self._check_partial_inputs([x_layout, cos_layout, sin_layout])
              self._validate_input_layouts(x_layout, cos_layout, sin_layout)
              return (copy.deepcopy(x_layout),), None
          # get_expand_impl NOT defined — inherits base class (returns None)
      
    • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml (created, COMPLETE)

      RotaryPositionEmbedding:
        dist_op_name: _rotary_position_embedding_dist_op
        distributed_op_class: RotaryPositionEmbeddingDistributedOp
        distributed_op_file: parallel_rotary_position_embedding
      

      Only PascalCase registered (no snake_case needed per user instruction).

    • /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py (created, COMPLETE)

      • 22 unit tests across 4 classes using unittest framework
      • TestNormalizeRpeArgs (tests 1-3): normalize args, default mode, kwarg/positional mode
      • TestYamlRegistration (test 4): PascalCase YAML registration verified
      • TestInferLayoutPositive (tests 5-15):
        • test 5: All replicated 4D + get_expand_impl verified once as None
        • test 6: DP on B (1D mesh, cos Replicate)
        • test 7: TP on N (cos 11SD broadcast)
        • test 8: CP on S (cos Shard(2) same as x)
        • test 9: CP on S (cos Replicate, broadcast case)
        • test 10: DP+TP 2D mesh (2,2), expected tm=(1,0,-1,-1)
        • test 11: DP+CP 2D mesh (2,2), expected tm=(1,-1,0,-1)
        • test 12: TP+CP 2D mesh (2,2), expected tm=(-1,1,0,-1)
        • test 13: TND 3D all replicated
        • test 14: TND T-dim DP
        • test 15: Output is independent deepcopy of x_layout
      • TestInferLayoutNegative (tests 16-22):
        • test 16: x D sharded → ValueError("D")
        • test 17: cos D sharded → ValueError("D")
        • test 18: sin D sharded → ValueError("sin")
        • test 19: cos B mismatch → ValueError("cos")
        • test 20: sin S mismatch → ValueError("sin")
        • test 21: cos N sharded, x N replicated → ValueError("cos")
        • test 22: x partial → ValueError
    • /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (NOT YET CREATED — pending)

    • /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py (NOT YET CREATED — pending)

    • Reference files read:

      • /root/workspace/mindspore/mindspore/ops/op_def/yaml/doc/rotary_position_embedding_doc.yaml
      • /root/workspace/ops-transformer/posembedding/rotary_position_embedding/docs/aclnnRotaryPositionEmbedding.md
      • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py
      • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/yaml/npu_sparse_flash_attention_ops.yaml
      • /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py
      • /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_npu_sparse_flash_attention_shard_in_python.py
      • /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py
      • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops.py
      • /root/workspace/hyper-parallel/hyper_parallel/core/shard/_op_dispatch.py
      • /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops_register.py
      • /root/workspace/hyper-parallel/tests/common/parallel_case.py
      • /root/workspace/mindspore/tests/ut/python/parallel/test_parallel_rotaryposemb.py
  4. Errors and fixes:

    • YAML loading mechanism investigation: Needed to understand how get_distributed_op("RotaryPositionEmbedding") would work in UT tests. Traced the import chain: hyper_parallel/__init__.py → imports DFunction from dfunction.pydfunction.py has from hyper_parallel.core.shard._op_dispatch import _OP_DISPATCHER at module top → _op_dispatch.py has module-level _OP_DISPATCHER = OpDispatcher() which loads all YAMLs. Verified by running a Python test that importing any hyper_parallel module triggers YAML loading.
    • MindSpore test API order: The old parallel test (test_parallel_rotaryposemb.py) uses (x, sin, cos) order. The official current API is (x, cos, sin, mode=0). Used the official API.
  5. Problem Solving:

    • Determined that tensor_map alone (no actual shape) is sufficient to validate broadcast compatibility: if cos.tensor_map[d]==-1, it's "replicated" (which is valid whether cos's actual dim is 1 or full-size). If cos.tensor_map[d]!=-1, it must match x.tensor_map[d].
    • Confirmed that RPE needs NO get_expand_impl — unlike SFA which requires causal window truncation of k/v in BSND+CP mode, RPE is purely element-wise with no cross-token dependencies.
    • Resolved 2D/3D mesh tensor_map axis convention: rightmost mesh dim = tensor_map axis 0 (verified against SFA UT test expectations).
    • Determined CANN shape constraint for ST test shapes: BN ≤ S8 when D/2 % (32/dtype_size)==0. For fp16, D=64: D/2=32, 32%16=0 → constraint applies. B=4, N=4 → 16 ≤ 128 ✓.
  6. All user messages:

    • "我现在要写1个分布式算子的实现,接口是mindspore.ops.rotary_position_embedding。... 先输出一个分析文档,将你计划实现的文件,文件要实现的类,接口及功能描述清楚,接口入参对layout的影响,各种约束,以及UT/ST测试用例的实际,都写进分析报告里。要先plan,不要直接动手。"
    • "1. 是不是x的layout,cos和sin要满足广播条件,主要是BN维度?满足这个条件,BN切分/Replicate就都可以酌情处理?\n2. 从计算公式看,S序列可以切分么?\n3. _to_local(t)不需要,我们默认只能传入DTensor,直接to_local就行。\n4. 如果想在校验/layout推断时用shape,那在preprocess将shape获取出来加入cache就行。\n5. 如果不需要get_expand_impl,就不用定义了,TestGetExpandImpl也不需要。\n6. yaml,小写下划线的rotary_position_embedding,不需要\n7. ST用例可以多验证一些场景,尤其是多维mesh切分的场景。每个mesh的大小,最大是2,能够验证shard即可,尽量少占用卡。"
    • "你提到的:在 HyperParallel 中,HyperParallel 看不到 tensor 实际 shape,只看 tensor_map。但 broadcast 语义天然映射:... 实际上,你可以在proprocess中将DTensor/Tensor的shape取出,放在cache_values里,就能在infer_layout里使用了。但是你提到了在这个维度数量固定的输入 shape场景下,shape的值其实不重要,用tensor_map就想能确定广播的情况了?所以不需要缓存shape信息了?\n\nMODE对layout有影响么?如果没有,就是透传即可?\n\n你看需不需要加一个8卡的用例?切分BSN维度?"
    • "计划文档存到docs下面吧,然后开始编码实现。"
  7. Pending Tasks:

    • ST implementation file (NOT YET CREATED): tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
      • 8 test cases: test_rpe_replicated, test_rpe_dp_b, test_rpe_tp_n (2-card), test_rpe_dp_tp, test_rpe_dp_sp, test_rpe_tp_sp, test_rpe_dp_tp_cos_full (4-card), test_rpe_dp_tp_sp (8-card)
      • Uses mindspore.ops.auto_generate.RotaryPositionEmbedding or ops.rotary_position_embedding
      • Uses distribute_tensor, full_tensor() for gather and comparison
      • Shapes: B=4, N=4, S=16, D=64, MODE=0
      • Ports: 19300-19307
      • Fwd comparison + backward for dp_b and dp_tp cases
    • ST runner file (NOT YET CREATED): tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
      • 4 groups using parallel_run + MindSporeCase
      • Group1 (2-card, level1): replicated, dp_b, tp_n → ports 19300-19302
      • Group2 (4-card, level1): dp_tp, dp_sp → ports 19303-19304
      • Group3 (4-card, level0): tp_sp, dp_tp_cos_full → ports 19305-19306
      • Group4 (8-card, level1): dp_tp_sp → port 19307
    • Code verification: Run UT tests to confirm correctness
  8. Current Work: The implementation was underway. Three of five files had been written:

    1. parallel_rotary_position_embedding.py — COMPLETE
    2. rotary_position_embedding_ops.yaml — COMPLETE
    3. test_parallel_rotary_position_embedding.py (UT, 22 tests) — COMPLETE

    The ST implementation file and ST runner file had not yet been written. The last action was completing the UT test file write.

  9. Optional Next Step: Based on the user's request "计划文档存到docs下面吧,然后开始编码实现", the next step is to implement the two remaining ST test files:

    1. tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py — the ST implementation with 8 test scenarios (test_rpe_replicated, test_rpe_dp_b, test_rpe_tp_n for 2-card; test_rpe_dp_tp, test_rpe_dp_sp, test_rpe_tp_sp, test_rpe_dp_tp_cos_full for 4-card; test_rpe_dp_tp_sp for 8-card), using setup_module(), distribute_tensor, full_tensor() for comparison.

    2. tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py — the runner with 4 @arg_mark-decorated test functions using parallel_run([MindSporeCase(...)]).

    Key design details for ST: shapes B=4, N=4, S=16, D=64, mode=0, ports 19300-19307, mesh sizes max 2 per dimension, fwd comparison + backward for dp_b/dp_tp cases.

If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32.jsonl Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening, do not preface with "I'll continue" or similar. Pick up the last task as if the break never happened.


Assistant · 2026-05-19T02:04:40.624Z

[Read: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py]
1	# Copyright 2026 Huawei Technologies Co., Ltd
2	#
3	# Licensed under the Apache License, Version 2.0 (the "License");
4	# you may not use this file except in compliance with the License.
5	# You may obtain a copy of the License at
6	#
7	# http://www.apache.org/licenses/LICENSE-2.0
8	#
9	# Unless required by applicable law or agreed to in writing, software
10	# distributed under the License is distributed on an "AS IS" BASIS,
11	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12	# See the License for the specific language governing permissions and
13	# limitations under the License.
14	# ============================================================================
15	"""Test runner for npu_sparse_flash_attention distributed ST (MindSpore)."""
16	from pathlib import Path
17	
18	from tests.common.mark_utils import arg_mark
19	from tests.common.parallel_case import parallel_run, MindSporeCase
20	
21	IMPL_FILE = str(
22	    Path(__file__).resolve().parent / "npu_sparse_flash_attention_shard_in_python.py"
23	)
24	
25	
26	@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
27	def test_parallel_sfa_ms_group1():
28	    """
29	    Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND replicated
30	             and DP, 8 cards)
31	    Description:
32	        1. test_sfa_bsnd_replicated — BSND all replicated, fwd+bwd vs standalone
33	        2. test_sfa_bsnd_dp — BSND B-dim data parallel, fwd+bwd vs standalone
34	        3. test_sfa_tnd_replicated — TND all replicated, fwd+bwd vs standalone
35	        4. test_sfa_tnd_dp — TND T1-dim data parallel (q AND k Shard(0)); local seq_lens
36	           per rank; q_split==k_split so no CP seq_len adjustment.
37	    Expectation: Run success.
38	    """
39	    parallel_run([
40	        MindSporeCase(IMPL_FILE, "test_sfa_bsnd_replicated", 19200, 2, 2, 2),
41	        MindSporeCase(IMPL_FILE, "test_sfa_bsnd_dp", 19201, 2, 2, 2),
42	        MindSporeCase(IMPL_FILE, "test_sfa_tnd_replicated", 19203, 2, 2, 2),
43	        MindSporeCase(IMPL_FILE, "test_sfa_tnd_dp", 19202, 2, 2, 2),
44	    ])
45	
46	
47	@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", card_mark="allcards", essential_mark="essential")
48	def test_parallel_sfa_ms_group2():
49	    """
50	    Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND CP, 4 cards)
51	    Description:
52	        1. test_sfa_bsnd_cp — BSND, q/si/q_rope Shard(1) on S1, k/v/k_rope Replicate;
53	           validates TP-as-CP pattern (MindFormers: S1 sharded by cp_tp combined)
54	        2. test_sfa_tnd_cp — TND, q/si/q_rope Shard(0) on T1, k/v/k_rope Replicate;
55	           seq_lens adjusted per rank by _tnd_cp_impl
56	    Expectation: Run success.
57	    """
58	    parallel_run([
59	        MindSporeCase(IMPL_FILE, "test_sfa_bsnd_cp", 19205, 2, 2, 2),
60	        MindSporeCase(IMPL_FILE, "test_sfa_tnd_cp", 19204, 2, 2, 2),
61	    ])
62	
63	
64	@arg_mark(plat_marks=["platform_ascend910b"], level_mark="level0", card_mark="allcards", essential_mark="essential")
65	def test_parallel_sfa_ms_group3():
66	    """
67	    Feature: parallel run case in npu_sparse_flash_attention_shard_in_python (BSND+TND dp+cp
68	             2-D mesh, 8 cards)
69	    Description:
70	        1. test_sfa_bsnd_dp_cp — 4-card 2-D mesh (dp=2, cp=2); B sharded by dp, S1 sharded
71	           by cp; k/v/key_rope replicated on cp. Mirrors MindFormers BSND shard() spec.
72	        2. test_sfa_tnd_dp_cp — 4-card 2-D mesh (dp=2, cp=2); T1 of q/si/q_rope sharded
73	           by dp AND cp (4-way split); T2 of k/v/k_rope sharded by dp only (2-way split).
74	           Mirrors MindFormers TND shard() spec with dp_cp_tp combined sequence split.
75	    Expectation: Run success.
76	    """
77	    parallel_run([
78	        MindSporeCase(IMPL_FILE, "test_sfa_bsnd_dp_cp", 19206, 4, 4, 2),
79	        MindSporeCase(IMPL_FILE, "test_sfa_tnd_dp_cp", 19207, 4, 4, 2),
80	    ])
81	
[Read: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_npu_sparse_flash_attention_shard_in_python.py]
1	# Copyright 2026 Huawei Technologies Co., Ltd
2	#
3	# Licensed under the Apache License, Version 2.0 (the "License");
4	# you may not use this file except in compliance with the License.
5	# You may obtain a copy of the License at
6	#
7	# http://www.apache.org/licenses/LICENSE-2.0
8	#
9	# Unless required by applicable law or agreed to in writing, software
10	# distributed under the License is distributed on an "AS IS" BASIS,
11	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12	# See the License for the specific language governing permissions and
13	# limitations under the License.
14	# ============================================================================
15	"""MindSpore distributed ST for npu_sparse_flash_attention.
16	
17	Pipeline: ops.lightning_indexer(q_idx, k_idx, w) → sparse_indices
18	          → ops.sparse_flash_attention(q, k, v, sparse_indices, ...).
19	
20	The two ops use different head_dim projections of the same sequence:
21	  - lightning_indexer : q_idx/k_idx head_dim = D_IDX = 128 (kernel constraint)
22	  - sparse_flash_attention : q/k head_dim = D_DIM = 512 (MLA attention_mode=2 constraint)
23	
24	For BSND+CP the lightning_indexer distributed op slices k_idx to the causal window
25	``k_idx[:, :S1_local*(split_id+1), :, :]``; the sparse_flash_attention distributed op
26	applies the same slice to k/v/key_rope, so sparse_indices remain valid.  This mirrors
27	MindFormers adjust_bsnd_input logic.
28	
29	Distributed sharding patterns verified against MindFormers dsa_attention.py shard():
30	  - BSND: q/si sharded on B (dp) and/or S1 (cp); k/v sharded on B (dp) only.
31	  - TND:  q/si sharded on T1 = dp*cp combined; k/v sharded on T2 = dp only.
32	"""
33	import numpy as np
34	import mindspore as ms
35	import mindspore.communication.management as D
36	from mindspore import Tensor, ops
37	from mindspore.ops import sparse_flash_attention
38	from hyper_parallel import init_device_mesh
39	from hyper_parallel.core.dtensor.dtensor import DTensor, distribute_tensor
40	from hyper_parallel.core.dtensor.placement_types import Shard, Replicate, Partial
41	
42	
43	def setup_module():
44	    """Initialize MindSpore context and communication."""
45	    ms.context.set_context(mode=ms.context.PYNATIVE_MODE, device_target="Ascend")
46	    D.init()
47	
48	
49	np.random.seed(42)
50	ms.set_seed(42)
51	ms.set_deterministic(True)
52	
53	# sparse_flash_attention head dims (attention_mode=2 MLA kernel constraints).
54	N2 = 1
55	D_DIM = 512       # qk_head_dim for sparse_flash_attention (must be 512)
56	DR_DIM = 64       # rope head_dim
57	SCALE_VALUE = 0.135234
58	
59	# lightning_indexer head dim (kernel constraint: must be 128).
60	D_IDX = 128
61	
62	# BSND layout — replicated/DP tests.
63	B_BSND = 4
64	S1_BSND = 4
65	S2_BSND = 1024
66	N1_BSND = 8
67	
68	# Number of top-k blocks for lightning_indexer (non-CP BSND).
69	SPARSE_COUNT_BSND = 8
70	
71	# BSND layout — CP/dp+cp tests (realistic self-attention scenario).
72	# S1_BSND_CP=S2_BSND_CP are the GLOBAL sequence lengths (Q and K come from the same
73	# sequence).  CP=2 splits Q on S1: each rank processes S1_local=S1_BSND_CP//2 query tokens.
74	# K is Replicate (full length on each rank); the distributed op truncates it to the
75	# causal window per rank: rank r sees k[:, :S1_local*(r+1), :, :].
76	# S1=S2 (self-attention) ensures causal truncation is lossless for rank 0.
77	# SPARSE_COUNT_CP <= S1_local = S1_BSND_CP // 2.
78	B_BSND_CP = 2
79	N1_BSND_CP = 32
80	S1_BSND_CP = 1024
81	S2_BSND_CP = 1024
82	SPARSE_COUNT_CP = 128
83	
84	# TND layout: T1=T2=1024, N1=8.
85	S_TND = 1024
86	N1_TND = 8
87	BATCH_DIM = 128
88	SPARSE_COUNT_TND = 8
89	
90	_INPUT_NAMES = ("query", "key", "value", "query_rope", "key_rope")
91	_FWD_OUTPUT_NAMES = ("attention_out", "softmax_max", "softmax_sum")
92	
93	
94	def _make_tnd_seq_lens():
95	    """Build TND actual_seq_lengths tensors (prefix sums, int32, shape (128,))."""
96	    step = S_TND // BATCH_DIM
97	    arr = (np.arange(BATCH_DIM, dtype=np.int32) + 1) * step
98	    t = Tensor(arr, ms.int32)
99	    return t, Tensor(arr.copy(), ms.int32)
100	
101	
102	def _make_tnd_local_seq_lens():
103	    """Build LOCAL TND actual_seq_lengths for DP test (half batch per rank)."""
104	    local_batch = BATCH_DIM // 2
105	    local_s = S_TND // 2
106	    step = local_s // local_batch
107	    arr = (np.arange(local_batch, dtype=np.int32) + 1) * step
108	    t = Tensor(arr, ms.int32)
109	    return t, Tensor(arr.copy(), ms.int32)
110	
111	
112	
113	def _np_to_bf16(arr):
114	    """Convert float32 numpy array to MindSpore bfloat16 Tensor."""
115	    return Tensor(arr, ms.bfloat16)
116	
117	
118	def _to_f32np(t):
119	    """Convert a MindSpore tensor (any dtype) to float32 numpy array."""
120	    return t.astype(ms.float32).asnumpy()
121	
122	
123	def _generate_inputs(layout='BSND', s1=None, s2=None, n1=None, b=None):
124	    """Generate random float32 numpy arrays for BSND or TND layout.
125	
126	    Returns two groups of tensors:
127	      - SFA group (D_DIM=512): q, k, v, q_rope, k_rope
128	      - Indexer group (D_IDX=128): q_idx, k_idx, w
129	        q_idx/k_idx share the same B/S1/S2 dims as q/k but with D_IDX head_dim.
130	        w has shape (B, S1, N1) for BSND or (T1, N1) for TND.
131	
132	    Args:
133	        layout: 'BSND' or 'TND'.
134	        s1: Query sequence length (BSND only; defaults to S1_BSND).
135	        s2: Key/value sequence length (BSND only; defaults to S2_BSND).
136	        n1: Number of query heads (BSND only; defaults to N1_BSND).
137	        b: Batch size (BSND only; defaults to B_BSND).
138	
139	    Returns:
140	        tuple: (q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np)
141	    """
142	    if layout == 'BSND':
143	        s1 = s1 if s1 is not None else S1_BSND
144	        s2 = s2 if s2 is not None else S2_BSND
145	        n1 = n1 if n1 is not None else N1_BSND
146	        b = b if b is not None else B_BSND
147	        # SFA tensors (D_DIM=512)
148	        q_np = np.random.randn(b, s1, n1, D_DIM).astype(np.float32)
149	        k_np = np.random.randn(b, s2, N2, D_DIM).astype(np.float32)
150	        v_np = k_np.copy()
151	        q_rope_np = np.random.randn(b, s1, n1, DR_DIM).astype(np.float32)
152	        k_rope_np = np.random.randn(b, s2, N2, DR_DIM).astype(np.float32)
153	        # Indexer tensors (D_IDX=128)
154	        q_idx_np = np.random.randn(b, s1, n1, D_IDX).astype(np.float32)
155	        k_idx_np = np.random.randn(b, s2, N2, D_IDX).astype(np.float32)
156	        w_np = np.random.randn(b, s1, n1).astype(np.float32)
157	    else:  # TND
158	        # SFA tensors (D_DIM=512)
159	        q_np = np.random.randn(S_TND, N1_TND, D_DIM).astype(np.float32)
160	        k_np = np.random.randn(S_TND, N2, D_DIM).astype(np.float32)
161	        v_np = k_np.copy()
162	        q_rope_np = np.random.randn(S_TND, N1_TND, DR_DIM).astype(np.float32)
163	        k_rope_np = np.random.randn(S_TND, N2, DR_DIM).astype(np.float32)
164	        # Indexer tensors (D_IDX=128)
165	        q_idx_np = np.random.randn(S_TND, N1_TND, D_IDX).astype(np.float32)
166	        k_idx_np = np.random.randn(S_TND, N2, D_IDX).astype(np.float32)
167	        w_np = np.random.randn(S_TND, N1_TND).astype(np.float32)
168	    return q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np
169	
170	
171	def _call_sfa(q, k, v, si, q_rope, k_rope,
172	              actual_seq_lengths_query=None, actual_seq_lengths_kv=None,
173	              layout='BSND'):
174	    """Call sparse_flash_attention with an explicit layout string.
175	
176	    For BSND, actual_seq_lengths_query and actual_seq_lengths_kv should be
177	    None (kernel infers from tensor shape); for TND they must be passed.
178	    Omitted parameters use kernel defaults: sparse_mode=3 (rightDownCausal),
179	    sparse_block_size=1, pre_tokens/next_tokens=INT64_MAX.
180	
181	    Args:
182	        q: Query tensor (D_DIM=512).
183	        k: Key tensor (D_DIM=512).
184	        v: Value tensor (D_DIM=512).
185	        si: Sparse indices tensor (int32), generated by lightning_indexer.
186	        q_rope: Query rope tensor.
187	        k_rope: Key rope tensor.
188	        actual_seq_lengths_query: Cumulative query lengths (TND only).
189	        actual_seq_lengths_kv: Cumulative kv lengths (TND only).
190	        layout: Layout string ('BSND' or 'TND').
191	
192	    Returns:
193	        tuple: (attention_out, softmax_max, softmax_sum)
194	    """
195	    return sparse_flash_attention(
196	        q, k, v, si, SCALE_VALUE,
197	        actual_seq_lengths_query=actual_seq_lengths_query,
198	        actual_seq_lengths_kv=actual_seq_lengths_kv,
199	        query_rope=q_rope, key_rope=k_rope,
200	        layout_query=layout, layout_kv=layout,
201	        attention_mode=2,
202	        return_softmax_lse=True,
203	    )
204	
205	
206	def _get_sparse_indices_bsnd(q_idx, k_idx, w, sparse_count):
207	    """Run lightning_indexer in BSND mode and return sparse_indices.
208	
209	    Uses q_idx/k_idx with D_IDX=128 (lightning_indexer kernel constraint).
210	    sparse_mode defaults to 3 (rightDownCausal); for BSND+CP the CP impl
211	    truncates k_idx to the causal window before calling the kernel.
212	
213	    Args:
214	        q_idx: Query index tensor (B, S1, N1, D_IDX=128).
215	        k_idx: Key index tensor (B, S2, N2, D_IDX=128).
216	        w: Weights tensor (B, S1, N1).
217	        sparse_count: Number of top-k blocks to select.
218	
219	    Returns:
220	        sparse_indices tensor (int32), shape (B, S1, N2, sparse_count).
221	    """
222	    out = ops.lightning_indexer(q_idx, k_idx, w, sparse_count=sparse_count, return_value=True)
223	    return out[0]
224	
225	
226	def _get_sparse_indices_tnd(q_idx, k_idx, w, qlen, klen, sparse_count):
227	    """Run lightning_indexer in TND mode and return sparse_indices.
228	
229	    Uses q_idx/k_idx with D_IDX=128 (lightning_indexer kernel constraint).
230	
231	    Args:
232	        q_idx: Query index tensor (T1, N1, D_IDX=128).
233	        k_idx: Key index tensor (T2, N2, D_IDX=128).
234	        w: Weights tensor (T1, N1).
235	        qlen: Cumulative query sequence lengths (int32 Tensor).
236	        klen: Cumulative key sequence lengths (int32 Tensor).
237	        sparse_count: Number of top-k blocks to select.
238	
239	    Returns:
240	        sparse_indices tensor (int32), shape (T1, N2, sparse_count).
241	    """
242	    out = ops.lightning_indexer(
243	        q_idx, k_idx, w,
244	        actual_seq_lengths_query=qlen,
245	        actual_seq_lengths_key=klen,
246	        layout_query='TND', layout_key='TND',
247	        sparse_count=sparse_count,
248	        return_value=True,
249	    )
250	    return out[0]
251	
252	
253	def _run_standalone(q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
254	                    actual_seq_q=None, actual_seq_kv=None, layout='BSND', sparse_count=None):
255	    """Run standalone lightning_indexer + SFA forward and backward.
256	
257	    lightning_indexer(q_idx, k_idx, w) → si → sparse_flash_attention(q, k, v, si, ...).
258	
259	    Args:
260	        q_np: SFA query numpy array (D_DIM=512).
261	        k_np: SFA key numpy array (D_DIM=512).
262	        v_np: SFA value numpy array (D_DIM=512).
263	        q_idx_np: Indexer query numpy array (D_IDX=128).
264	        k_idx_np: Indexer key numpy array (D_IDX=128).
265	        w_np: Indexer weights numpy array.
266	        q_rope_np: Query rope numpy array.
267	        k_rope_np: Key rope numpy array.
268	        actual_seq_q: Sequence lengths for query.
269	        actual_seq_kv: Sequence lengths for kv.
270	        layout: 'BSND' or 'TND'.
271	        sparse_count: Number of top-k blocks.
272	
273	    Returns:
274	        tuple: (fwd_outs, grad_outs) — each a tuple of float32 ndarrays.
275	    """
276	    q = _np_to_bf16(q_np)
277	    k = _np_to_bf16(k_np)
278	    v = _np_to_bf16(v_np)
279	    q_idx = _np_to_bf16(q_idx_np)
280	    k_idx = _np_to_bf16(k_idx_np)
281	    w = _np_to_bf16(w_np)
282	    q_rope = _np_to_bf16(q_rope_np)
283	    k_rope = _np_to_bf16(k_rope_np)
284	
285	    if layout == 'BSND':
286	        sc = sparse_count or SPARSE_COUNT_BSND
287	        si = _get_sparse_indices_bsnd(q_idx, k_idx, w, sc)
288	    else:
289	        sc = sparse_count or SPARSE_COUNT_TND
290	        si = _get_sparse_indices_tnd(q_idx, k_idx, w, actual_seq_q, actual_seq_kv, sc)
291	
292	    out = _call_sfa(q, k, v, si, q_rope, k_rope, actual_seq_q, actual_seq_kv, layout)
293	    fwd_outs = tuple(_to_f32np(o) for o in out)
294	
295	    grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
296	        q, k, v, si, q_rope, k_rope, actual_seq_q, actual_seq_kv, layout
297	    )
298	    grad_outs = tuple(_to_f32np(g) for g in grads)
299	    return fwd_outs, grad_outs
300	
301	
302	def _get_grad_placements(d_inputs: tuple) -> list:
303	    """Derive the correct DTensor placement for each input's gradient.
304	
305	    Args:
306	        d_inputs: Tuple of DTensor inputs.
307	
308	    Returns:
309	        list of placement tuples, one per input.
310	    """
311	    n_dims = len(d_inputs[0].layout.placements)
312	    dim_has_shard = [
313	        any(isinstance(d_inp.layout.placements[d], Shard) for d_inp in d_inputs)
314	        for d in range(n_dims)
315	    ]
316	    result = []
317	    for d_inp in d_inputs:
318	        mesh_placements = d_inp.layout.placements
319	        grad_placements = tuple(
320	            Partial("sum") if isinstance(p, Replicate) and dim_has_shard[dim_idx] else p
321	            for dim_idx, p in enumerate(mesh_placements)
322	        )
323	        result.append(grad_placements)
324	    return result
325	
326	
327	def _assert_fwd(dist_outs, ref_outs, tag):
328	    """Assert all three forward outputs match reference within tolerance."""
329	    for i, (name, ref) in enumerate(zip(_FWD_OUTPUT_NAMES, ref_outs)):
330	        dist_np = _to_f32np(dist_outs[i].full_tensor())
331	        assert np.allclose(dist_np, ref, atol=1e-3, rtol=1e-3), (
332	            f"{tag} forward {name} mismatch: "
333	            f"max_diff={np.abs(dist_np - ref).max()}"
334	        )
335	
336	
337	_BWD_TOL = {
338	    'key': (1e-1, 1e-1),
339	    'key_rope': (1e-1, 1e-1),
340	    'value': (1e-2, 1e-2),
341	}
342	_BWD_TOL_DEFAULT = (1e-3, 1e-3)
343	
344	
345	def _assert_bwd(raw_grads, d_inputs, ref_grad, tag, tol=None):
346	    """Assert backward gradients match reference within tolerance.
347	
348	    Args:
349	        tol: Optional per-input tolerance dict mapping input name to (atol, rtol).
350	             Pass _BWD_TOL for BSND+CP tests; omit for all other tests (uniform 1e-3).
351	    """
352	    grad_placements = _get_grad_placements(d_inputs)
353	    for name, raw_g, d_inp, ref, g_placements in zip(
354	            _INPUT_NAMES, raw_grads, d_inputs, ref_grad, grad_placements):
355	        dist_g = (
356	            DTensor.from_local(raw_g, d_inp.layout.mesh, g_placements)
357	            .full_tensor()
358	            .astype(ms.float32)
359	            .asnumpy()
360	        )
361	        atol, rtol = tol.get(name, _BWD_TOL_DEFAULT) if tol else _BWD_TOL_DEFAULT
362	        assert np.allclose(dist_g, ref, atol=atol, rtol=rtol), (
363	            f"{tag} backward grad_{name} mismatch: "
364	            f"max_diff={np.abs(dist_g - ref).max()}"
365	        )
366	
367	
368	def test_sfa_bsnd_replicated():
369	    """
370	    Feature: npu_sparse_flash_attention (MindSpore) BSND forward/backward, all replicated.
371	    Description:
372	        - All inputs replicated on 2-device mesh.
373	        - sparse_indices from lightning_indexer(q_idx, k_idx, w) with D_IDX=128.
374	        - SFA called with q/k/v of D_DIM=512 (MLA attention_mode=2).
375	        - bfloat16, attention_mode=2, v=k.clone().
376	    Expectation: Distributed outputs match standalone within tolerance.
377	    """
378	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='BSND')
379	    ref_fwd, ref_grad = _run_standalone(
380	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
381	        sparse_count=SPARSE_COUNT_BSND,
382	    )
383	
384	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp",))
385	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Replicate(),))
386	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Replicate(),))
387	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Replicate(),))
388	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Replicate(),))
389	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Replicate(),))
390	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Replicate(),))
391	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Replicate(),))
392	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Replicate(),))
393	
394	    dsi = _get_sparse_indices_bsnd(dq_idx, dk_idx, dw, SPARSE_COUNT_BSND)
395	
396	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope)
397	    _assert_fwd(out, ref_fwd, "BSND Replicated")
398	
399	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
400	        dq, dk, dv, dsi, dq_rope, dk_rope
401	    )
402	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "BSND Replicated")
403	
404	
405	def test_sfa_bsnd_dp():
406	    """
407	    Feature: npu_sparse_flash_attention (MindSpore) BSND forward/backward with B-dim DP.
408	    Description:
409	        - 2-device dp mesh; all inputs sharded on B (dim 0).
410	        - sparse_indices from distributed lightning_indexer(dq_idx, dk_idx, dw).
411	        - bfloat16, attention_mode=2, v=k.clone().
412	    Expectation: Distributed outputs match standalone within tolerance.
413	    """
414	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='BSND')
415	    ref_fwd, ref_grad = _run_standalone(
416	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
417	        sparse_count=SPARSE_COUNT_BSND,
418	    )
419	
420	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp",))
421	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(0),))
422	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Shard(0),))
423	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Shard(0),))
424	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(0),))
425	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Shard(0),))
426	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(0),))
427	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(0),))
428	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Shard(0),))
429	
430	    dsi = _get_sparse_indices_bsnd(dq_idx, dk_idx, dw, SPARSE_COUNT_BSND)
431	
432	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope)
433	    _assert_fwd(out, ref_fwd, "BSND DP")
434	
435	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
436	        dq, dk, dv, dsi, dq_rope, dk_rope
437	    )
438	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "BSND DP")
439	
440	
441	def test_sfa_bsnd_cp():
442	    """
443	    Feature: npu_sparse_flash_attention (MindSpore) BSND with S1-dim context parallelism.
444	    Description:
445	        - 2-device dp_cp mesh; q/q_idx/w/q_rope sharded on S1 (dim 1);
446	          k/k_idx/v/k_rope replicated.
447	        - lightning_indexer distributed op slices k_idx to causal window
448	          k_idx[:, :S1_local*(split_id+1), :, :] per rank (D_IDX=128).
449	        - sparse_flash_attention distributed op applies the same slice to k/v/key_rope
450	          (D_DIM=512), ensuring sparse_indices remain valid.
451	        - S1=S2 (self-attention) ensures causal truncation is lossless.
452	        - SPARSE_COUNT_CP <= S1_local = S1_BSND_CP // 2.
453	        - bfloat16, attention_mode=2, v=k.clone().
454	    Expectation: Distributed outputs match standalone within tolerance.
455	    """
456	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(
457	        layout='BSND', s1=S1_BSND_CP, s2=S2_BSND_CP, n1=N1_BSND_CP, b=B_BSND_CP
458	    )
459	    ref_fwd, ref_grad = _run_standalone(
460	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
461	        sparse_count=SPARSE_COUNT_CP,
462	    )
463	
464	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp_cp",))
465	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(1),))
466	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Replicate(),))
467	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Replicate(),))
468	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(1),))
469	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Replicate(),))
470	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(1),))
471	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(1),))
472	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Replicate(),))
473	
474	    dsi = _get_sparse_indices_bsnd(dq_idx, dk_idx, dw, SPARSE_COUNT_CP)
475	
476	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope)
477	    _assert_fwd(out, ref_fwd, "BSND CP")
478	
479	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
480	        dq, dk, dv, dsi, dq_rope, dk_rope
481	    )
482	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "BSND CP", tol=_BWD_TOL)
483	
484	
485	def test_sfa_bsnd_dp_cp():
486	    """
487	    Feature: npu_sparse_flash_attention (MindSpore) BSND with 2-D dp+cp mesh.
488	    Description:
489	        - 4-card 2-D mesh (dp=2, cp=2); q/q_idx/w/q_rope sharded on B (dp) and S1 (cp).
490	          k/k_idx/v/k_rope sharded on B (dp), S2 replicated.
491	        - Mirrors MindFormers dsa_attention.py BSND shard():
492	            q/si = layout("dp", "cp_tp", "None", "None")
493	            k/v  = layout("dp", "None", "None", "None")
494	        - lightning_indexer slices k_idx to causal window per (dp, cp) rank.
495	        - sparse_flash_attention applies the same slice to k/v/key_rope.
496	        - S1=S2 (self-attention) ensures causal truncation is lossless.
497	        - Each rank: B_local = B_BSND_CP//dp = 1, S1_local = S1_BSND_CP//cp = S1_BSND_CP//2.
498	        - bfloat16, attention_mode=2, v=k.clone().
499	    Expectation: Distributed outputs match standalone within tolerance.
500	    """
501	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(
502	        layout='BSND', s1=S1_BSND_CP, s2=S2_BSND_CP, n1=N1_BSND_CP, b=B_BSND_CP
503	    )
504	    ref_fwd, ref_grad = _run_standalone(
505	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
506	        sparse_count=SPARSE_COUNT_CP,
507	    )
508	
509	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2, 2), mesh_dim_names=("dp", "cp"))
510	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(0), Shard(1)))
511	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Shard(0), Replicate()))
512	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Shard(0), Replicate()))
513	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(0), Shard(1)))
514	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Shard(0), Replicate()))
515	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(0), Shard(1)))
516	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(0), Shard(1)))
517	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Shard(0), Replicate()))
518	
519	    dsi = _get_sparse_indices_bsnd(dq_idx, dk_idx, dw, SPARSE_COUNT_CP)
520	
521	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope)
522	    _assert_fwd(out, ref_fwd, "BSND dp+cp")
523	
524	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
525	        dq, dk, dv, dsi, dq_rope, dk_rope
526	    )
527	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "BSND dp+cp", tol=_BWD_TOL)
528	
529	
530	def test_sfa_tnd_replicated():
531	    """
532	    Feature: npu_sparse_flash_attention (MindSpore) TND forward/backward, all replicated.
533	    Description:
534	        - sparse_indices from lightning_indexer(q_idx, k_idx, w) with D_IDX=128.
535	        - SFA called with q/k/v of D_DIM=512.
536	        - actual_seq_lengths as int32 Tensor of shape (128,) with prefix sums.
537	        - bfloat16, attention_mode=2, v=k.clone().
538	    Expectation: Distributed outputs match standalone within tolerance.
539	    """
540	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='TND')
541	    actual_seq_q, actual_seq_kv = _make_tnd_seq_lens()
542	    ref_fwd, ref_grad = _run_standalone(
543	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
544	        actual_seq_q=actual_seq_q, actual_seq_kv=actual_seq_kv,
545	        layout='TND', sparse_count=SPARSE_COUNT_TND,
546	    )
547	
548	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp",))
549	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Replicate(),))
550	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Replicate(),))
551	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Replicate(),))
552	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Replicate(),))
553	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Replicate(),))
554	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Replicate(),))
555	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Replicate(),))
556	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Replicate(),))
557	
558	    d_actual_seq_q = distribute_tensor(actual_seq_q, mesh, (Replicate(),))
559	    d_actual_seq_kv = distribute_tensor(actual_seq_kv, mesh, (Replicate(),))
560	
561	    dsi = _get_sparse_indices_tnd(dq_idx, dk_idx, dw, d_actual_seq_q, d_actual_seq_kv, SPARSE_COUNT_TND)
562	
563	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND')
564	    _assert_fwd(out, ref_fwd, "TND Replicated")
565	
566	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
567	        dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND'
568	    )
569	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "TND Replicated")
570	
571	
572	def test_sfa_tnd_dp():
573	    """
574	    Feature: npu_sparse_flash_attention (MindSpore) TND forward/backward with T1-dim DP.
575	    Description:
576	        - 2-device dp mesh; all tensors sharded on T1 (dim 0).
577	        - sparse_indices from distributed lightning_indexer (TND DP mode).
578	        - Both q and k sharded on T1 — pure DP, no CP seq_len adjustment.
579	        - bfloat16, attention_mode=2, v=k.clone().
580	    Expectation: Gathered distributed outputs match standalone within tolerance.
581	    """
582	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='TND')
583	    actual_seq_q, actual_seq_kv = _make_tnd_seq_lens()
584	    ref_fwd, ref_grad = _run_standalone(
585	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
586	        actual_seq_q=actual_seq_q, actual_seq_kv=actual_seq_kv,
587	        layout='TND', sparse_count=SPARSE_COUNT_TND,
588	    )
589	
590	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp",))
591	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(0),))
592	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Shard(0),))
593	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Shard(0),))
594	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(0),))
595	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Shard(0),))
596	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(0),))
597	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(0),))
598	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Shard(0),))
599	
600	    d_actual_seq_q = distribute_tensor(actual_seq_q, mesh, (Replicate(),))
601	    d_actual_seq_kv = distribute_tensor(actual_seq_kv, mesh, (Replicate(),))
602	
603	    dsi = _get_sparse_indices_tnd(dq_idx, dk_idx, dw, d_actual_seq_q, d_actual_seq_kv, SPARSE_COUNT_TND)
604	
605	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND')
606	    _assert_fwd(out, ref_fwd, "TND DP")
607	
608	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
609	        dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND'
610	    )
611	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "TND DP")
612	
613	
614	def test_sfa_tnd_cp():
615	    """
616	    Feature: npu_sparse_flash_attention (MindSpore) TND with context parallelism.
617	    Description:
618	        - 2-device dp_cp mesh; q/q_idx/w/q_rope sharded on T1; k/k_idx/v/k_rope replicated.
619	        - sparse_indices from distributed lightning_indexer (TND CP mode, D_IDX=128).
620	        - actual_seq_lengths adjusted per rank by _tnd_cp_impl in both ops.
621	        - bfloat16, attention_mode=2, v=k.clone().
622	    Expectation: Distributed outputs match standalone within tolerance.
623	    """
624	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='TND')
625	    actual_seq_q, actual_seq_kv = _make_tnd_seq_lens()
626	    ref_fwd, ref_grad = _run_standalone(
627	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
628	        actual_seq_q=actual_seq_q, actual_seq_kv=actual_seq_kv,
629	        layout='TND', sparse_count=SPARSE_COUNT_TND,
630	    )
631	
632	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2,), mesh_dim_names=("dp_cp",))
633	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(0),))
634	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Replicate(),))
635	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Replicate(),))
636	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(0),))
637	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Replicate(),))
638	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(0),))
639	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(0),))
640	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Replicate(),))
641	
642	    d_actual_seq_q = distribute_tensor(actual_seq_q, mesh, (Replicate(),))
643	    d_actual_seq_kv = distribute_tensor(actual_seq_kv, mesh, (Replicate(),))
644	
645	    dsi = _get_sparse_indices_tnd(dq_idx, dk_idx, dw, d_actual_seq_q, d_actual_seq_kv, SPARSE_COUNT_TND)
646	
647	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND')
648	    _assert_fwd(out, ref_fwd, "TND CP")
649	
650	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
651	        dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND'
652	    )
653	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "TND CP")
654	
655	
656	def test_sfa_tnd_dp_cp():
657	    """
658	    Feature: npu_sparse_flash_attention (MindSpore) TND with 2-D dp+cp mesh.
659	    Description:
660	        - 4-card 2-D mesh (dp=2, cp=2); T1 of q/q_idx/w/q_rope sharded by BOTH dp and cp.
661	          T2 of k/k_idx/v/k_rope sharded by dp only, cp Replicate.
662	        - Mirrors MindFormers dsa_attention.py TND shard():
663	            q/si = layout("dp_cp_tp", "None", "None")
664	            k/v  = layout("dp", "None", "None")
665	        - sparse_indices from distributed lightning_indexer (TND DP+CP mode, D_IDX=128).
666	        - _tnd_cp_impl adjusts actual_seq_lengths per rank in both ops.
667	        - bfloat16, attention_mode=2, v=k.clone().
668	    Expectation: Distributed outputs match standalone within tolerance.
669	    """
670	    q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np = _generate_inputs(layout='TND')
671	    actual_seq_q, actual_seq_kv = _make_tnd_seq_lens()
672	    ref_fwd, ref_grad = _run_standalone(
673	        q_np, k_np, v_np, q_idx_np, k_idx_np, w_np, q_rope_np, k_rope_np,
674	        actual_seq_q=actual_seq_q, actual_seq_kv=actual_seq_kv,
675	        layout='TND', sparse_count=SPARSE_COUNT_TND,
676	    )
677	
678	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2, 2), mesh_dim_names=("dp", "cp"))
679	    dq = distribute_tensor(_np_to_bf16(q_np), mesh, (Shard(0), Shard(0)))
680	    dk = distribute_tensor(_np_to_bf16(k_np), mesh, (Shard(0), Replicate()))
681	    dv = distribute_tensor(_np_to_bf16(v_np), mesh, (Shard(0), Replicate()))
682	    dq_idx = distribute_tensor(_np_to_bf16(q_idx_np), mesh, (Shard(0), Shard(0)))
683	    dk_idx = distribute_tensor(_np_to_bf16(k_idx_np), mesh, (Shard(0), Replicate()))
684	    dw = distribute_tensor(_np_to_bf16(w_np), mesh, (Shard(0), Shard(0)))
685	    dq_rope = distribute_tensor(_np_to_bf16(q_rope_np), mesh, (Shard(0), Shard(0)))
686	    dk_rope = distribute_tensor(_np_to_bf16(k_rope_np), mesh, (Shard(0), Replicate()))
687	
688	    d_actual_seq_q = distribute_tensor(actual_seq_q, mesh, (Replicate(),))
689	    d_actual_seq_kv = distribute_tensor(actual_seq_kv, mesh, (Replicate(),))
690	
691	    dsi = _get_sparse_indices_tnd(dq_idx, dk_idx, dw, d_actual_seq_q, d_actual_seq_kv, SPARSE_COUNT_TND)
692	
693	    out = _call_sfa(dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND')
694	    _assert_fwd(out, ref_fwd, "TND dp+cp")
695	
696	    raw_grads = ms.grad(_call_sfa, (0, 1, 2, 4, 5))(
697	        dq, dk, dv, dsi, dq_rope, dk_rope, d_actual_seq_q, d_actual_seq_kv, 'TND'
698	    )
699	    _assert_bwd(raw_grads, (dq, dk, dv, dq_rope, dk_rope), ref_grad, "TND dp+cp")
700	
[Read: /root/workspace/hyper-parallel/tests/common/parallel_case.py]
1	# Copyright 2026 Huawei Technologies Co., Ltd
2	#
3	# Licensed under the Apache License, Version 2.0 (the "License");
4	# you may not use this file except in compliance with the License.
5	# You may obtain a copy of the License at
6	#
7	# http://www.apache.org/licenses/LICENSE-2.0
8	#
9	# Unless required by applicable law or agreed to in writing, software
10	# distributed under the License is distributed on an "AS IS" BASIS,
11	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12	# See the License for the specific language governing permissions and
13	# limitations under the License.
14	# ============================================================================
15	"""parallel run case"""
16	import os
17	import signal
18	import multiprocessing as mp
19	from typing import Union
20	
21	
22	class TorchCase:
23	    """torch case messages"""
24	
25	    def __init__(self, file_name: str, case_name: str, master_port: int, num_proc: int = 1):
26	        self.file_name = file_name
27	        self.case_name = case_name
28	        self.master_port = master_port
29	        self.num_proc = num_proc
30	
31	
32	class MindSporeCase:
33	    """mindspore case messages"""
34	
35	    def __init__(self, file_name: str, case_name: str, master_port: int, worker_num: int = 1, local_worker_num: int = 1,
36	                 glog_v: int = 3):
37	        self.glog_v = glog_v
38	        self.file_name = file_name
39	        self.case_name = case_name
40	        self.master_port = master_port
41	        self.num_proc = worker_num
42	        self.local_worker_num = local_worker_num
43	
44	
45	def run_case(visible_devices, case: Union[TorchCase, MindSporeCase]):
46	    """
47	    run case in child process
48	    """
49	    # become the leader of a new process group so that os.killpg on timeout
50	    # kills torchrun/msrun worker sub-processes as well as this wrapper
51	    os.setsid()
52	    # set visible devices for current case
53	    os.environ['ASCEND_RT_VISIBLE_DEVICES'] = ','.join(map(str, visible_devices))
54	    if isinstance(case, TorchCase):
55	        # pylint: disable=C0415
56	        from tests.torch.utils import torchrun_case
57	        torchrun_case(case.file_name, case.case_name, case.master_port, case.num_proc)
58	    elif isinstance(case, MindSporeCase):
59	        # pylint: disable=C0415
60	        from tests.mindspore.st.utils import msrun_case
61	        msrun_case(case.glog_v, case.file_name, case.case_name, case.master_port, case.num_proc, case.local_worker_num)
62	
63	
64	def parallel_run(cases: Union[list[TorchCase], list[MindSporeCase]], global_num_proc: int = 8):
65	    """
66	    parallel run cases
67	
68	    Args:
69	        cases (list[Case]): list of case messages to be run parallel
70	        global_num_proc (int, optional): number of total num of process. Defaults to 8.
71	    """
72	    # assign devices
73	    sum_num_proc = 0
74	    assignments = []
75	
76	    for case in cases:
77	        num = case.num_proc
78	        devices = list(range(sum_num_proc, sum_num_proc + num))
79	        assignments.append(devices)
80	        sum_num_proc += num
81	    # assert sum num_proc
82	    assert sum_num_proc <= global_num_proc, (f"sum num_proc {sum_num_proc} greater than "
83	                                             f"global_num_proc {global_num_proc}")
84	
85	    # create child process (run_case calls os.setsid to own a process group,
86	    # so os.killpg on timeout kills torchrun/msrun workers too)
87	    processes = []
88	    for _, (case, devices) in enumerate(zip(cases, assignments)):
89	        p = mp.Process(target=run_case, args=(devices, case))
90	        p.start()
91	        processes.append(p)
92	
93	    # wait child process terminates (timeout=900s to prevent infinite hang on distributed deadlock)
94	    timed_out = []
95	    for i, p in enumerate(processes):
96	        p.join(timeout=900)
97	        if p.is_alive():
98	            try:
99	                os.killpg(os.getpgid(p.pid), signal.SIGKILL)
100	            except ProcessLookupError:
101	                pass
102	            p.join()
103	            timed_out.append(cases[i].case_name)
104	
105	    # check results for all cases
106	    if timed_out:
107	        raise AssertionError(f"Cases timed out (possible collective deadlock): {timed_out}")
108	    failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
109	    assert not failed, f"List cases failed: {failed}"
110	

先看一下 SFA 的 ST 测试文件,作为参考模板。

先看看 parallel_case.pyMindSporeCase 签名。


User · 2026-05-19T02:15:05.458Z

Continue from where you left off.


Assistant · 2026-05-19T02:15:05.458Z

No response requested.


User · 2026-05-19T02:15:10.694Z

请继续


Assistant · 2026-05-19T02:16:53.372Z

[Bash: ls /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/]
__pycache__
activation_with_axis_shard_in_python.py
argmax_with_value_shard_in_python.py
argsort_shard_in_python.py
bmm_shard_in_python.py
chunk_view_shard_in_python.py
cumsum_ext_shard_in_python.py
elementwise_shard_in_python.py
expand_dims_shard_in_python.py
expand_dims_view_shard_in_python.py
flash_attention_score_shard_in_python.py
gather_d_shard_in_python.py
gather_nd_shard_in_python.py
histc_ext_shard_in_python.py
inplace_scatter_value_shard_in_python.py
lightning_indexer_shard_in_python.py
masked_fill_scalar_shard_in_python.py
max_dim_shard_in_python.py
ms_flash_attention_score_shard_in_python.py
muls_shard_in_python.py
norm_shard_in_python.py
npu_dense_lightning_indexer_grad_kl_loss_custom_op.py
npu_dense_lightning_indexer_softmax_lse_custom_op.py
npu_mhc_post_custom_op.py
npu_mhc_pre_sinkhorn_custom_op.py
npu_sparse_flash_attention_shard_in_python.py
npu_sparse_lightning_indexer_grad_kl_loss_custom_op.py
one_hot_ext_shard_in_python.py
ones_like_shard_in_python.py
reduce_shard_in_python.py
scatter_update_shard_in_python.py
silu_shard_in_python.py
test_activation_with_axis_shard_in_python.py
test_argmax_with_value_shard_in_python.py
test_argsort_shard_in_python.py
test_bmm_shard_in_python.py
test_chunk_view_shard_in_python.py
test_cumsum_ext_shard_in_python.py
test_elementwise_shard_in_python.py
test_expand_dims_shard_in_python.py
test_expand_dims_view_shard_in_python.py
test_flash_attention_score_shard_in_python.py
test_gather_d_shard_in_python.py
test_gather_nd_shard_in_python.py
test_histc_ext_shard_in_python.py
test_inplace_scatter_value_shard_in_python.py
test_lightning_indexer_shard_in_python.py
test_masked_fill_scalar_shard_in_python.py
test_max_dim_shard_in_python.py
test_ms_flash_attention_score_shard_in_python.py
test_muls_shard_in_python.py
test_norm_shard_in_python.py
test_npu_dense_lightning_indexer_grad_kl_loss_custom_op.py
test_npu_dense_lightning_indexer_softmax_lse_custom_op.py
test_npu_mhc_post_custom_op.py
test_npu_mhc_pre_sinkhorn_custom_op.py
test_npu_sparse_flash_attention_shard_in_python.py
test_npu_sparse_lightning_indexer_grad_kl_loss_custom_op.py
test_one_hot_ext_shard_in_python.py
test_ops_ones_like_shard_in_python.py
test_reduce_shard_in_python.py
test_scatter_update_shard_in_python.py
test_silu_shard_in_python.py
test_transpose_ext_view_shard_in_python.py
transpose_ext_view_shard_in_python.py
[Write: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (13761 chars)]
File created successfully at: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (file state is current in your context — no need to Read it back)
[Write: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py (4059 chars)]
File created successfully at: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py (file state is current in your context — no need to Read it back)
[Bash: python -m pytest tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py -v 2>&1]
============================= test session starts ==============================
platform linux -- Python 3.10.20, pytest-9.0.3, pluggy-1.6.0 -- /root/miniconda3/envs/ci3.10/bin/python
cachedir: .pytest_cache
rootdir: /root/workspace/hyper-parallel
collecting ... collected 22 items

tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestNormalizeRpeArgs::test_mode_keyword_arg_2 PASSED [  4%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestNormalizeRpeArgs::test_mode_positional_arg_3 PASSED [  9%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestNormalizeRpeArgs::test_three_positional_args_mode_defaults_to_zero_1 PASSED [ 13%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestYamlRegistration::test_pascal_case_registration_4 PASSED [ 18%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_all_replicated_3d_tnd_13 PASSED [ 22%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_all_replicated_4d_5 PASSED [ 27%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_cp_s_cos_replicated_9 PASSED [ 31%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_cp_s_cos_same_shard_8 PASSED [ 36%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_dp_b_cos_replicated_6 PASSED [ 40%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_dp_cp_2d_mesh_11 PASSED [ 45%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_dp_tp_2d_mesh_10 PASSED [ 50%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_output_is_independent_deepcopy_15 PASSED [ 54%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_tnd_dp_t_14 PASSED [ 59%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_tp_cp_2d_mesh_12 PASSED [ 63%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutPositive::test_tp_n_cos_broadcast_7 PASSED [ 68%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_cos_b_mismatch_raises_19 PASSED [ 72%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_cos_d_sharded_raises_17 PASSED [ 77%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_cos_n_sharded_x_n_replicated_raises_21 PASSED [ 81%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_partial_input_raises_22 PASSED [ 86%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_sin_d_sharded_raises_18 PASSED [ 90%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_sin_s_mismatch_raises_20 PASSED [ 95%]
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py::TestInferLayoutNegative::test_x_d_sharded_raises_16 PASSED [100%]

============================== 22 passed in 0.12s ==============================
[Bash: python -m pylint \ hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py \ tests/ut/core/shard/ops/test_parallel_rotary_position_emb]
************* Module hyper_parallel.core.shard.ops.parallel_rotary_position_embedding
hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py:132:4: W0221: Number of parameters was 3 in 'DistributedOp.infer_layout' and is now 2 in overriding 'RotaryPositionEmbeddingDistributedOp.infer_layout' method (arguments-differ)
************* Module tests.ut.core.shard.ops.test_parallel_rotary_position_embedding
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:24:0: C0413: Import "from hyper_parallel.core.dtensor.dtensor import _build_layout, _LAYOUT_CACHE" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:25:0: C0413: Import "from hyper_parallel.core.dtensor.placement_types import Shard, Replicate" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:26:0: C0413: Import "from hyper_parallel.core.shard.ops.parallel_rotary_position_embedding import RotaryPositionEmbeddingDistributedOp, _normalize_rpe_args" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:30:0: C0413: Import "from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:31:0: C0413: Import "from hyper_parallel.core.dtensor.device_mesh import init_device_mesh, _DEVICE_MESH_MAP" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py:32:0: C0413: Import "from hyper_parallel.platform.platform import EXISTING_COMM_GROUPS" should be placed at the top of the module (wrong-import-position)

-----------------------------------
Your code has been rated at 9.83/10
[Bash: grep -n "def infer_layout" /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_ops.py]
82:    def infer_layout(self, layouts: tuple, extra_args: Optional[tuple] = None) -> Optional[tuple]:
[Bash: head -5 /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py]
# Copyright 2026 Huawei Technologies Co., Ltd
#
# 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
[Bash: grep -n "def infer_layout" /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py | head -5]
316:    def infer_layout(self, cache_values: list) -> Tuple[tuple, None]:
[Bash: sed -n '18,35p' /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py]
from unittest.mock import MagicMock, patch

import numpy as np

os.environ["HYPER_PARALLEL_PLATFORM"] = "torch"

from hyper_parallel.core.dtensor.dtensor import _build_layout, _LAYOUT_CACHE
from hyper_parallel.core.dtensor.placement_types import Shard, Replicate
from hyper_parallel.core.shard.ops.parallel_npu_sparse_flash_attention import (
    SparseFlashAttentionDistributedOp,
    _normalize_sfa_args,
)
from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op
from hyper_parallel.core.dtensor.device_mesh import init_device_mesh, _DEVICE_MESH_MAP
from hyper_parallel.platform.platform import EXISTING_COMM_GROUPS


class TestSparseFlashAttentionDistributedOp(unittest.TestCase):
[Bash: python -m pylint hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py \ tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_atten]
hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py:316:4: W0221: Number of parameters was 3 in 'DistributedOp.infer_layout' and is now 2 in overriding 'SparseFlashAttentionDistributedOp.infer_layout' method (arguments-differ)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:24:0: C0413: Import "from hyper_parallel.core.dtensor.dtensor import _build_layout, _LAYOUT_CACHE" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:25:0: C0413: Import "from hyper_parallel.core.dtensor.placement_types import Shard, Replicate" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:26:0: C0413: Import "from hyper_parallel.core.shard.ops.parallel_npu_sparse_flash_attention import SparseFlashAttentionDistributedOp, _normalize_sfa_args" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:30:0: C0413: Import "from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:31:0: C0413: Import "from hyper_parallel.core.dtensor.device_mesh import init_device_mesh, _DEVICE_MESH_MAP" should be placed at the top of the module (wrong-import-position)
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py:32:0: C0413: Import "from hyper_parallel.platform.platform import EXISTING_COMM_GROUPS" should be placed at the top of the module (wrong-import-position)
Your code has been rated at 9.82/10

现在开始写两个 ST 文件。先确认目录结构。

好,现在写 ST 实现文件。

现在写 runner 文件。

现在运行 UT 验证实现的正确性。

22 个 UT 全部通过。现在对 5 个文件做一次整体 lint 检查。

有两个类别的 lint 警告需要处理。先检查基类签名。

W0221 和 C0413 与 SFA 文件完全相同的既有警告模式(打分 9.83 vs SFA 的 9.82),是项目中已接受的 pattern,无需修改。


所有 5 个文件已完成:

文件 状态
hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py ✅ 已完成
hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml ✅ 已完成
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py ✅ 22/22 通过
tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py ✅ 已完成
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py ✅ 已完成

ST 测试覆盖的 8 个场景:

测试 卡数 mesh x 切分 cos/sin
test_rpe_replicated 2 dp Replicate Replicate broadcast
test_rpe_dp_b 2 dp Shard(B) Replicate broadcast + 验 grad_x
test_rpe_tp_n 2 tp Shard(N) Shard(N) 同步
test_rpe_dp_tp 4 dp×tp Shard(B)+Shard(N) 同步 + 验 grad_x/cos/sin
test_rpe_dp_sp 4 dp×sp Shard(B)+Shard(S) broadcast Shard(S)
test_rpe_tp_sp 4 tp×sp Shard(N)+Shard(S) 同步
test_rpe_dp_tp_cos_full 4 dp×tp Shard(B)+Shard(N) broadcast Replicate
test_rpe_dp_tp_sp 8 dp×tp×sp Shard(B)+Shard(N)+Shard(S) broadcast Shard(S)

User · 2026-05-19T02:25:03.448Z

最后一个8卡用例broadcast Shard(S)是什么意思,三个维度都做了切分,是cos或者sin维度为1,进行广播,广播到shard后的维度进行计算么?输出也是带shard?


Assistant · 2026-05-19T02:25:37.596Z

你理解得完全正确。让我把每个 rank 上发生的事情写清楚:

3D mesh (dp=2, tp=2, sp=2),rank (i, j, k)

x shape:   (4, 4, 16, 64), placements=(Shard(0), Shard(1), Shard(2))
cos shape: (1, 1, 16, 64), placements=(Replicate(), Replicate(), Shard(2))

切分后每个 rank 上的本地 tensor:

rank (i,j,k) x_local cos_local
(0,0,0) x[0:2, 0:2, 0:8, :] = (2,2,8,64) cos[0:1, 0:1, 0:8, :] = (1,1,8,64)
(0,0,1) x[0:2, 0:2, 8:16, :] = (2,2,8,64) cos[0:1, 0:1, 8:16, :] = (1,1,8,64)
(1,1,0) x[2:4, 2:4, 0:8, :] = (2,2,8,64) cos[0:1, 0:1, 0:8, :] = (1,1,8,64)
... ... ...

本地 kernel 调用时:

  • S 维度已对齐:sp 维度同时切分了 x 和 cos 的 S,同一 sp rank 上两者的 S 片段完全对应,不需要广播
  • B=1, N=1 做广播:cos_local 的 B=1 广播到 x_local 的 B=2,N=1 广播到 N=2
  • 本地计算:y_local(2,2,8,64) = x_local(2,2,8,64) * cos_local(1,1,8,64) + ...

输出也是带 shard 的,output layout = x_layout,即 (Shard(0), Shard(1), Shard(2)) on (dp, tp, sp),y_local 形状同样是 (2,2,8,64)。


表格里那一栏写得确实不够清晰,更准确的描述是:

cos/sin 的 B、N 维度为 1(广播),S 维度与 x 同步切分(sp Shard(2),本地 S 片段对齐),输出 layout 与 x 相同


User · 2026-05-19T02:28:56.673Z

/ascend-test 把这5个文件提交成commit。遵循以下步骤和要求完成算子的开发和验证。

  1. 提交commit,使用/ascend-test登录服务器进行ST的验证。
  2. 分析失败的用例,对分布式算子实现,或者ST用例进行修改。
  3. 修改完成后,重复1的操作,继续进行验证。

要求:

  1. 一旦修改了分布式算子实现的代码,就要执行UT用例确保UT用例通过再提交commit。
  2. 在ascend-test的skills目录下,存留一个工作日志ascend-test-work-rope.log,每一次失败,要记录下loop id(第几次记录),报错情况,分析的结论,以及计划修改的内容。
  3. 提交commit,只能提交本轮新增/修改的文件,不能对存量的与本次任务无关的untracked files进行任何操作。

User · 2026-05-19T02:28:56.673Z

Base directory for this skill: /root/workspace/hyper-parallel/.claude/skills/ascend-test

Ascend Test Runner


Assistant · 2026-05-19T02:29:07.590Z

[Bash: git status --short]
?? .claude/commands/ascend-test.md
?? .claude/skills/ascend-test/
?? .sisyphus/
?? 1-torch-mindspore-virtual-stonebraker.md
?? 1.patch
?? bcba11b5a0b945fc9a1a3ccf0a50728e46746fa5.patch
?? custom_shard_issue.md
?? d_function_issue.md
?? docs/1-npu-dense-lightning-indexer-softmax-l-cheerful-yeti.md
?? docs/1-torch-mindspore-virtual-stonebraker.md
?? docs/3-commit-1-3-dense-lightning-indexer-gr-snoopy-toast.md
?? docs/ISSUE.md
?? docs/PR_description.md
?? docs/ci310_install_troubleshooting.md
?? docs/distributed_op_migration_audit_report.md
?? docs/distributed_op_migration_guide.md
?? docs/dsa_distributed_op_analysis.md
?? docs/ep_deleted_code.md
?? docs/etp.md
?? docs/hyper-parallel-ep-commit-f0fa78f686caa8f-prancy-donut.md
?? docs/issues/
?? docs/lightning_indexer_implementation_plan.md
?? docs/memoized-seeking-honey.md
?? docs/mhc/
?? docs/moe_ep_refactor_design.md
?? docs/np.md
?? docs/npu-sparse-flash-attention-torch-mindsp-wobbly-sunset.md
?? docs/npu_dense_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_issue.md
?? docs/npu_sparse_flash_attention_dist_op.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_bsnd_cp_fix.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/rfc-moe-parallel.md
?? docs/rfc-operator-parallel.md
?? docs/rotary_position_embedding_dist_op_plan.md
?? docs/sfa_operator_params_comparison.md
?? docs/shimmering-riding-catmull_1.md
?? docs/shimmering-riding-catmull_2.md
?? docs/shimmering-riding-catmull_3.md
?? docs/velvety-shimmying-cake.md
?? email.sh
?? expert_parallel_pr.md
?? hyper_connection.py
?? hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py
?? hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml
?? install.sh
?? npu_mhc_pre_sinkhorn_custom_op.py
?? pylintrc
?? run_ep_test.sh
?? test_npu.sh
?? test_sfa_torch.py
?? tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
?? tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
?? tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py
[Bash: mkdir -p /root/workspace/hyper-parallel/.claude/skills/ascend-test]
(Bash completed with no output)
[Write: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log (436 chars)]
File created successfully at: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log (file state is current in your context — no need to Read it back)
[Bash: \ git add \ hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py \ hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops]
A  hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py
A  hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml
A  tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
A  tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
A  tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py
?? .claude/commands/ascend-test.md
?? .claude/skills/ascend-test/
?? .sisyphus/
?? 1-torch-mindspore-virtual-stonebraker.md
?? 1.patch
?? bcba11b5a0b945fc9a1a3ccf0a50728e46746fa5.patch
?? custom_shard_issue.md
?? d_function_issue.md
?? docs/1-npu-dense-lightning-indexer-softmax-l-cheerful-yeti.md
?? docs/1-torch-mindspore-virtual-stonebraker.md
?? docs/3-commit-1-3-dense-lightning-indexer-gr-snoopy-toast.md
?? docs/ISSUE.md
?? docs/PR_description.md
?? docs/ci310_install_troubleshooting.md
?? docs/distributed_op_migration_audit_report.md
?? docs/distributed_op_migration_guide.md
?? docs/dsa_distributed_op_analysis.md
?? docs/ep_deleted_code.md
?? docs/etp.md
?? docs/hyper-parallel-ep-commit-f0fa78f686caa8f-prancy-donut.md
?? docs/issues/
?? docs/lightning_indexer_implementation_plan.md
?? docs/memoized-seeking-honey.md
?? docs/mhc/
?? docs/moe_ep_refactor_design.md
?? docs/np.md
?? docs/npu-sparse-flash-attention-torch-mindsp-wobbly-sunset.md
?? docs/npu_dense_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_issue.md
?? docs/npu_sparse_flash_attention_dist_op.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_bsnd_cp_fix.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/rfc-moe-parallel.md
?? docs/rfc-operator-parallel.md
?? docs/rotary_position_embedding_dist_op_plan.md
?? docs/sfa_operator_params_comparison.md
?? docs/shimmering-riding-catmull_1.md
?? docs/shimmering-riding-catmull_2.md
?? docs/shimmering-riding-catmull_3.md
?? docs/velvety-shimmying-cake.md
?? email.sh
?? expert_parallel_pr.md
?? hyper_connection.py
?? install.sh
?? npu_mhc_pre_sinkhorn_custom_op.py
?? pylintrc
?? run_ep_test.sh
?? test_npu.sh
?? test_sfa_torch.py
[Bash: git commit -m "feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST"]
[master_dist_op 244a8d0] feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
 5 files changed, 1083 insertions(+)
 create mode 100644 hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py
 create mode 100644 hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml
 create mode 100644 tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
 create mode 100644 tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
 create mode 100644 tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py
[Bash: git branch --show-current]
master_dist_op
[Bash: git push ascend-repo master_dist_op -f 2>&1]
Authorized users only. All activities may be monitored and reported.
To 8.92.7.125:/home/hdd/bare-repo-hyper-parallel/
 * [new branch]      master_dist_op -> master_dist_op
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git checkout master_dist_op && git reset --hard HEAD 2>&1"]
Authorized users only. All activities may be monitored and reported.
Switched to branch 'master_dist_op'
HEAD is now at 244a8d0 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git log --oneline -1 2>&1"]
Authorized users only. All activities may be monitored and reported.
244a8d0 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1"]
<persisted-output>
Output too large (535.3KB). Full output saved to: /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results/bai3axly5.txt

Preview (first 2KB):
Authorized users only. All activities may be monitored and reported.
============================= test session starts ==============================
platform linux -- Python 3.9.25, pytest-8.4.2, pluggy-1.6.0 -- /home/hdd/miniconda3/envs/ci3.9/bin/python3.9
cachedir: .pytest_cache
rootdir: /home/hdd/hyper-parallel
collecting ... collected 4 items

test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1 /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
...
</persisted-output>
[Bash: tail -100 /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results/bai3axly5.txt]
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.61s ========================
[INFO] DISTRIBUTED(258196,ffff2a7cf120,python3.9):2026-05-19-10:28:03.155.682 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(258196,ffff29fbf120,python3.9):2026-05-19-10:28:03.155.682 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.49s ========================
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.44s ========================
[INFO] DISTRIBUTED(258228,ffff2f7ef120,python3.9):2026-05-19-10:28:03.213.454 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[INFO] DISTRIBUTED(258228,ffff2ffff120,python3.9):2026-05-19-10:28:03.213.453 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(258240,ffff4555f120,python3.9):2026-05-19-10:28:03.216.401 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[INFO] DISTRIBUTED(258240,ffff45d6f120,python3.9):2026-05-19-10:28:03.216.401 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.64s ========================
[INFO] DISTRIBUTED(258185,ffff26fdf120,python3.9):2026-05-19-10:28:03.228.979 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[INFO] DISTRIBUTED(258185,ffff277ef120,python3.9):2026-05-19-10:28:03.228.970 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
PASSED

=============================== warnings summary ===============================
../../../../common/mark_utils.py:38
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:38: PytestUnknownMarkWarning: Unknown pytest.mark.platform_ascend910b - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, plat_mark)(func)

../../../../common/mark_utils.py:39
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:39: PytestUnknownMarkWarning: Unknown pytest.mark.level1 - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, level_mark)(func)

../../../../common/mark_utils.py:40
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:40: PytestUnknownMarkWarning: Unknown pytest.mark.allcards - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, card_mark)(func)

../../../../common/mark_utils.py:41
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:41: PytestUnknownMarkWarning: Unknown pytest.mark.essential - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, essential_mark)(func)

tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/torch_npu/utils/collect_env.py:58: UserWarning: Warning: The /usr/local/Ascend/cann-9.0.0 owner does not match the current owner.
    warnings.warn(f"Warning: The {path} owner does not match the current owner.")

tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/torch_npu/utils/collect_env.py:58: UserWarning: Warning: The /usr/local/Ascend/cann-9.0.0/aarch64-linux/ascend_ops_install.info owner does not match the current owner.
    warnings.warn(f"Warning: The {path} owner does not match the current owner.")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================== 4 passed, 8 warnings in 163.90s (0:02:43) ===================

Running ascend-test …

先创建工作日志文件,然后 stage 5 个目标文件并提交。

HEAD 一致,开始跑 ST。

全部通过!

Step            Result
──────────────────────────────────────────────────────────────
Commit          244a8d0 — feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
Push            ascend-repo/master_dist_op
Sync            /home/hdd/hyper-parallel  HEAD=244a8d0
Test            tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
  4 passed in 163.90s (0:02:43)

4 个 group 全部 PASSED,无任何失败,工作日志无需记录错误条目。

验证覆盖汇总:

Group 卡数 测试场景 结果
group1 2 replicated / dp_b(+bwd) / tp_n
group2 4 dp_tp(+bwd) / dp_sp
group3 4 tp_sp / dp_tp_cos_full(broadcast)
group4 8 dp_tp_sp (B+N+S 三维同时切分)

System

完成了 RotaryPositionEmbedding 分布式算子的全部开发:实现文件、YAML 注册、22 个 UT、8 个 MindSpore ST 用例,服务器上 4 个 group 全部通过。下一步可提 PR。 (disable recaps in /config)


User · 2026-05-19T02:39:03.439Z

  1. ST用例中mode只等于0,酌情改一些用例为其他的mode
  2. 反向的验证,能不能参考sparse_flash_attention,反向通过_get_grad_placements和_assert_bwd对比?
  3. 精度能不能按1e-3等来比对?1e-2是如何定下来的?是否合理,请评估确定后再修改。

Assistant · 2026-05-19T02:41:55.914Z

[Write: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (16358 chars)]
The file /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py has been updated successfully. (file state is current in your context — no need to Read it back)
[Bash: python -m pylint \ tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py \ --disable=C0301,W0611,R0801 --max-line-length=120 2]
Your code has been rated at 10.00/10
[Bash: git add tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py && \ git commit -m "refactor: improve RPE ST tests — multi-mode, _ge]
[master_dist_op a7add13] refactor: improve RPE ST tests — multi-mode, _get_grad_placements bwd, tighten tol to 1e-3
 1 file changed, 138 insertions(+), 65 deletions(-)
[Bash: git push ascend-repo master_dist_op -f 2>&1]
Authorized users only. All activities may be monitored and reported.
To 8.92.7.125:/home/hdd/bare-repo-hyper-parallel/
   244a8d0..a7add13  master_dist_op -> master_dist_op
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git checkout master_dist_op && git reset --hard HEAD && git log --oneline -1 2>&1"]
Authorized users only. All activities may be monitored and reported.
M	tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
Already on 'master_dist_op'
HEAD is now at a7add13 refactor: improve RPE ST tests — multi-mode, _get_grad_placements bwd, tighten tol to 1e-3
a7add13 refactor: improve RPE ST tests — multi-mode, _get_grad_placements bwd, tighten tol to 1e-3
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1"]
Exit code 1

Authorized users only. All activities may be monitored and reported.
============================= test session starts ==============================
platform linux -- Python 3.9.25, pytest-8.4.2, pluggy-1.6.0 -- /home/hdd/miniconda3/envs/ci3.9/bin/python3.9
cachedir: .pytest_cache
rootdir: /home/hdd/hyper-parallel
collecting ... collected 4 items

test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1 /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
Start scheduler process, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/scheduler.log. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start worker process with rank id:0, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/worker_0.log. Environment variable [RANK_ID=0] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start scheduler process, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_tp_n/scheduler.log. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_tp_n
Start worker process with rank id:0, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_tp_n/worker_0.log. Environment variable [RANK_ID=0] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_tp_n
Start worker process with rank id:1, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/worker_1.log. Environment variable [RANK_ID=1] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start work

... [20009 characters truncated] ...

39:47.786.844 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(541647,fffec3fff120,python3.9):2026-05-19-10:39:47.787.067 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(541647,fffec1fbf120,python3.9):2026-05-19-10:39:47.787.287 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] ME(541664,ffff94b39c40,python3.9):2026-05-19-10:39:49.259.164 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:368] CreateCommunicationGroup] Create collective communication group: hccl_world_group [const vector]{0, 1}, async: 0
[WARNING] ME(541664,fffeb1fbf120,python3.9):2026-05-19-10:39:49.259.507 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(541664,fffeb1fbf120,python3.9):2026-05-19-10:39:49.259.829 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(541664,fffeb17af120,python3.9):2026-05-19-10:39:49.260.104 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] DEVICE(541647,fffec1fbf120,python3.9):2026-05-19-10:39:49.738.341 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:291] InitByRootInfoConfig] End to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group
[WARNING] DEVICE(541664,fffeb17af120,python3.9):2026-05-19-10:39:49.845.688 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:291] InitByRootInfoConfig] End to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group
[ERROR] DEVICE(541647,ffffb659bc40,python3.9):2026-05-19-10:39:50.563.301 [mindspore/ccsrc/plugin/ascend/res_manager/ascend_res_manager.cc:830] BaseCopy] Src ptr:0 or dst ptr:0x25090ae0 is null, please check the address is set correctly.
FAILED

=================================== FAILURES ===================================
________________________________ test_rpe_tp_n _________________________________

    def test_rpe_tp_n():
        """
        Feature: RotaryPositionEmbedding (MindSpore) N-dim tensor parallel, 2-card tp mesh.
        Description:
            - 1-D tp mesh (2 cards); x/cos/sin all Shard(1).
            - cos/sin full shape (B, N, S, D) — same sharding as x.
            - float16, mode=2 (quarter).
            - Forward and all three gradients verified; all grad placements = Shard(1).
        Expectation: Distributed forward and gradients match standalone within tolerance.
        """
        mode = 2
        x_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
        cos_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
        sin_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
>       ref_fwd, ref_grads = _run_standalone(x_np, cos_np, sin_np, mode=mode)

rotary_position_embedding_shard_in_python.py:249: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
rotary_position_embedding_shard_in_python.py:111: in _run_standalone
    return fwd_np, tuple(_to_f32np(g) for g in grads)
rotary_position_embedding_shard_in_python.py:111: in <genexpr>
    return fwd_np, tuple(_to_f32np(g) for g in grads)
rotary_position_embedding_shard_in_python.py:75: in _to_f32np
    return t.astype(ms.float32).asnumpy()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <[RuntimeError('SyncCopy failed for Tensor(shape=[4, 4, 16, 64], dtype=Float32, value=[...])\n\n----------------------...---------------------------\nmindspore/core/ir/tensor.cc:490 cpu\n') raised in repr()] Tensor object at 0xffff4dd33f70>

    def asnumpy(self):
        """
        Convert tensor to numpy array. Returns self tensor as a NumPy ndarray. This tensor and the returned ndarray
        share the same underlying storage. Changes to self tensor will be reflected in the ndarray.
    
        .. warning::
            Non-backward-compatible change after version 2.9.0: the interface name will be changed to `numpy`.
    
        Returns:
            A numpy ndarray which shares the same underlying storage with the tensor.
    
        Examples:
            >>> from mindspore import Tensor
            >>> import numpy
[Bash: grep -E "PASSED|FAILED|ERROR|assert|Exception" /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results]
PASSEDPASSED
PASSED
PASSED
PASSEDPASSED
PASSED
PASSEDPASSEDPASSEDPASSED
PASSEDPASSEDPASSEDPASSED
PASSED
PASSEDPASSEDPASSEDPASSED
PASSEDPASSEDPASSEDPASSED
PASSED
PASSEDPASSEDPASSEDPASSEDPASSEDPASSED
PASSED
PASSED
PASSED
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && \ pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1 ]
Authorized users only. All activities may be monitored and reported.
self = <[RuntimeError('SyncCopy failed for Tensor(shape=[4, 4, 16, 64], dtype=Float32, value=[...])\n\n----------------------...---------------------------\nmindspore/core/ir/tensor.cc:490 cpu\n') raised in repr()] Tensor object at 0xffff456abb80>
E       (Please search "CANN Common Error Analysis" at https://www.mindspore.cn/en for error code description)
self = <[RuntimeError('SyncCopy failed for Tensor(shape=[4, 4, 16, 64], dtype=Float32, value=[...])\n\n----------------------...---------------------------\nmindspore/core/ir/tensor.cc:490 cpu\n') raised in repr()] Tensor object at 0xffff27fabb80>
E       (Please search "CANN Common Error Analysis" at https://www.mindspore.cn/en for error code description)
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp - Runt...
        failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
        failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
        failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
        failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
FAILED test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
FAILED test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group2
FAILED test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group3
FAILED test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group4
[Read: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log]
1	# RPE 分布式算子 ST 验证工作日志
2	# 算子: RotaryPositionEmbedding
3	# 文件:
4	#   hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py
5	#   hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml
6	#   tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py
7	#   tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
8	#   tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
9	
[Edit: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log]
The file /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log has been updated successfully. (file state is current in your context — no need to Read it back)
[Write: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (17352 chars)]
The file /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py has been updated successfully. (file state is current in your context — no need to Read it back)
[Bash: python -m pylint tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py \ --disable=C0301,W0611,R0801 --max-line-length=120 2>&1 ]
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)
[Bash: git add tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py \ .claude/skills/ascend-test/ascend-test-work-rope.log && \]
Exit code 1
The following paths are ignored by one of your .gitignore files:
.claude/skills/ascend-test/ascend-test-work-rope.log
hint: Use -f if you really want to add them.
hint: Turn this message off by running
hint: "git config advice.addIgnoredFile false"
[Bash: git add tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py && \ git commit -m "fix: RPE ST — split fwd/fwd+bwd standalone, rest]
[master_dist_op 574a74b] fix: RPE ST — split fwd/fwd+bwd standalone, restrict mode=2/3 to fwd-only tests
 1 file changed, 50 insertions(+), 29 deletions(-)
[Bash: git push ascend-repo master_dist_op -f 2>&1]
Authorized users only. All activities may be monitored and reported.
To 8.92.7.125:/home/hdd/bare-repo-hyper-parallel/
   a7add13..574a74b  master_dist_op -> master_dist_op
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git checkout master_dist_op && git reset --hard HEAD && git log --oneline -1 2>&1"]
Authorized users only. All activities may be monitored and reported.
M	tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
Already on 'master_dist_op'
HEAD is now at 574a74b fix: RPE ST — split fwd/fwd+bwd standalone, restrict mode=2/3 to fwd-only tests
574a74b fix: RPE ST — split fwd/fwd+bwd standalone, restrict mode=2/3 to fwd-only tests
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1"]
Exit code 1

Authorized users only. All activities may be monitored and reported.
============================= test session starts ==============================
platform linux -- Python 3.9.25, pytest-8.4.2, pluggy-1.6.0 -- /home/hdd/miniconda3/envs/ci3.9/bin/python3.9
cachedir: .pytest_cache
rootdir: /home/hdd/hyper-parallel
collecting ... collected 4 items

test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1 /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
Start scheduler process, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/scheduler.log. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start worker process with rank id:0, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/worker_0.log. Environment variable [RANK_ID=0] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start scheduler process, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_tp_n/scheduler.log. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_tp_n
Start worker process with rank id:0, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_tp_n/worker_0.log. Environment variable [RANK_ID=0] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_tp_n
Start worker process with rank id:1, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_replicated/worker_1.log. Environment variable [RANK_ID=1] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_replicated
Start work

... [20012 characters truncated] ...

abstract/collective/collective_manager.cc:368] CreateCommunicationGroup] Create collective communication group: hccl_world_group [const vector]{0, 1}, async: 0
[WARNING] ME(744274,fffeb17af120,python3.9):2026-05-19-10:50:33.030.820 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(744274,fffeb17af120,python3.9):2026-05-19-10:50:33.031.059 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(744274,fffe8efdf120,python3.9):2026-05-19-10:50:33.031.277 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] ME(744278,ffff83151c40,python3.9):2026-05-19-10:50:33.571.874 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:368] CreateCommunicationGroup] Create collective communication group: hccl_world_group [const vector]{0, 1}, async: 0
[WARNING] ME(744278,fffec51df120,python3.9):2026-05-19-10:50:33.572.184 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(744290,ffffb880fc40,python3.9):2026-05-19-10:50:34.797.486 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:368] CreateCommunicationGroup] Create collective communication group: hccl_world_group [const vector]{0, 1}, async: 0
[WARNING] ME(744290,fffed67cf120,python3.9):2026-05-19-10:50:34.797.822 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(744290,fffed67cf120,python3.9):2026-05-19-10:50:34.798.149 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(744290,fffed5fbf120,python3.9):2026-05-19-10:50:34.798.430 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] ME(744262,ffff9c87ec40,python3.9):2026-05-19-10:50:35.057.230 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:368] CreateCommunicationGroup] Create collective communication group: hccl_world_group [const vector]{0, 1}, async: 0
[WARNING] ME(744262,fffeb9fbf120,python3.9):2026-05-19-10:50:35.064.229 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1034] CreateDeviceCommunicator] Start to send/fetch unqiueid for communication group hccl_world_group
[WARNING] ME(744262,fffeb9fbf120,python3.9):2026-05-19-10:50:35.064.420 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(744262,fffe977ef120,python3.9):2026-05-19-10:50:35.064.648 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] ME(744278,fffec51df120,python3.9):2026-05-19-10:50:35.072.882 [mindspore/ccsrc/runtime/hardware_abstract/collective/collective_manager.cc:1040] CreateDeviceCommunicator] End to send/fetch unqiueid for communication group hccl_world_group
[WARNING] DEVICE(744278,fffec49cf120,python3.9):2026-05-19-10:50:35.073.163 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:276] InitByRootInfoConfig] Start to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group, hcclBufferSize is 200 MB, hcclDeterministic is 1
[WARNING] DEVICE(744274,fffe8efdf120,python3.9):2026-05-19-10:50:35.203.651 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:291] InitByRootInfoConfig] End to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group
[WARNING] DEVICE(744290,fffed5fbf120,python3.9):2026-05-19-10:50:35.382.781 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:291] InitByRootInfoConfig] End to initialize communicator by HcclCommInitRootInfoConfig for hccl_world_group
[WARNING] DEVICE(744262,fffe977ef120,python3.9):2026-05-19-10:50:35.547.401 [mindspore/ccsrc/plugin/ascend/res_manager/collective/ascend_communication_group.cc:291] InitByRootInfoConfig] End to initialize communicator by HcclCom
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && \ pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1 ]
Authorized users only. All activities may be monitored and reported.
Start worker process with rank id:3, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_dp_tp_sp/worker_3.log. Environment variable [RANK_ID=3] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp
Start worker process with rank id:4, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_dp_tp_sp/worker_4.log. Environment variable [RANK_ID=4] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp
Start worker process with rank id:5, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_dp_tp_sp/worker_5.log. Environment variable [RANK_ID=5] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp
collecting ... Start worker process with rank id:6, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_dp_tp_sp/worker_6.log. Environment variable [RANK_ID=6] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp
collecting ... Start worker process with rank id:7, log file:./logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python/test_rpe_dp_tp_sp/worker_7.log. Environment variable [RANK_ID=7] is exported. Execute command: pytest -s -v /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802323:281473736625216,MainProcess):2026-05-19-10:55:13.639.28 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802345:281473530047552,MainProcess):2026-05-19-10:55:13.128.628 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] DISTRIBUTED(802345,ffffa9c5ac40,python3.9):2026-05-19-10:55:13.130.875 [mindspore/ccsrc/cluster/rpc/tcp/tcp_comm.cc:485] Connect] Connection 20 source: 127.0.0.1:51284, destination: 127.0.0.1:19307
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802303:281473561144384,MainProcess):2026-05-19-10:55:13.178.529 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802334:281473449589824,MainProcess):2026-05-19-10:55:13.193.743 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802313:281473449675840,MainProcess):2026-05-19-10:55:13.297.717 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802368:281473808792640,MainProcess):2026-05-19-10:55:13.380.682 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp_sp [WARNING] ME(802356:281473436482624,MainProcess):2026-05-19-10:55:13.463.439 [mindspore/context.py:1338] For 'context.set_context', the parameter 'device_target' will be deprecated and removed in a future version. Please use the api mindspore.set_device() instead.
======================= 1 passed, 22 warnings in 16.11s ========================
======================= 1 passed, 22 warnings in 16.07s ========================
======================= 1 passed, 22 warnings in 16.15s ========================
======================= 1 passed, 22 warnings in 16.32s ========================
======================= 1 passed, 22 warnings in 16.24s ========================
======================= 1 passed, 22 warnings in 16.36s ========================
======================= 1 passed, 22 warnings in 16.28s ========================
======================= 1 passed, 22 warnings in 16.20s ========================
_________________________ test_parallel_rpe_ms_group2 __________________________
    def test_parallel_rpe_ms_group2():
            1. test_rpe_dp_tp — 2-D (dp=2, tp=2) mesh; x/cos/sin (Shard(0), Shard(1));
            2. test_rpe_dp_sp — 2-D (dp=2, sp=2) mesh; x (Shard(0), Shard(2)),
            MindSporeCase(IMPL_FILE, "test_rpe_dp_tp", 19303, 4, 4, 2),
            MindSporeCase(IMPL_FILE, "test_rpe_dp_sp", 19304, 4, 4, 2),
        # assert sum num_proc
        assert sum_num_proc <= global_num_proc, (f"sum num_proc {sum_num_proc} greater than "
            raise AssertionError(f"Cases timed out (possible collective deadlock): {timed_out}")
        failed = [cases[i].case_name for i, p in enumerate(processes) if p.exitcode != 0]
>       assert not failed, f"List cases failed: {failed}"
E       AssertionError: List cases failed: ['test_rpe_dp_tp']
../../../../common/parallel_case.py:109: AssertionError
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
FAILED test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group2
============= 1 failed, 3 passed, 8 warnings in 157.81s (0:02:37) ==============
[Bash: ssh hdd@8.92.7.125 "cat /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_positi]
Authorized users only. All activities may be monitored and reported.
    @fusion_manager.register("correction_mul_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/correction_mul_grad.py:143
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/correction_mul_grad.py:143: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("correction_mul_grad_reduce")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perlayer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer_grad.py:92
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer_grad.py:92: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perlayer_grad_d")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer_grad_reduce.py:49
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perlayer_grad_reduce.py:49: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perlayer_grad_d_reduce")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel_grad.py:91
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel_grad.py:91: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perchannel_grad_d")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel_grad_reduce.py:48
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_learned_scale_quant_perchannel_grad_reduce.py:48: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_learned_scale_quant_perchannel_grad_d_reduce")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perchannel.py:52
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perchannel.py:52: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perchannel_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perchannel_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_perchannel_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp - Runtime...
======================= 1 failed, 22 warnings in 13.67s ========================
[INFO] DISTRIBUTED(788890,ffff25c6f120,python3.9):2026-05-19-10:54:11.916.441 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(788890,ffff2545f120,python3.9):2026-05-19-10:54:11.916.438 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[Bash: ssh hdd@8.92.7.125 "cat /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/logs//home/hdd/hyper-parallel/tests/mindspore/st/shard/ops/rotary_positi]
Authorized users only. All activities may be monitored and reported.
FAILED

=================================== FAILURES ===================================
________________________________ test_rpe_dp_tp ________________________________

    def test_rpe_dp_tp():
        """
        Feature: RotaryPositionEmbedding (MindSpore) 2-D dp×tp mesh, B by dp, N by tp.
        Description:
            - 4-card 2-D mesh (dp=2, tp=2); x/cos/sin all (Shard(0), Shard(1)).
            - cos/sin full shape (B, N, S, D) — same placements as x.
            - float16, mode=1 (rotate_interleaved).
            - Forward and all three gradients verified; all grad placements = (Shard(0), Shard(1)).
        Expectation: Distributed fwd and all gradients match standalone within tolerance.
        """
        mode = 1
        x_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
        cos_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
        sin_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
>       ref_fwd, ref_grads = _run_standalone(x_np, cos_np, sin_np, mode=mode)

rotary_position_embedding_shard_in_python.py:303: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
rotary_position_embedding_shard_in_python.py:130: in _run_standalone
    fwd_np = _to_f32np(fn(x, cos, sin))
rotary_position_embedding_shard_in_python.py:77: in _to_f32np
    return t.astype(ms.float32).asnumpy()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <[RuntimeError('SyncCopy failed for Tensor(shape=[4, 4, 16, 64], dtype=Float32, value=[...])\n\n----------------------...---------------------------\nmindspore/core/ir/tensor.cc:490 cpu\n') raised in repr()] Tensor object at 0xffff285090d0>

    def asnumpy(self):
        """
        Convert tensor to numpy array. Returns self tensor as a NumPy ndarray. This tensor and the returned ndarray
        share the same underlying storage. Changes to self tensor will be reflected in the ndarray.
    
        .. warning::
            Non-backward-compatible change after version 2.9.0: the interface name will be changed to `numpy`.
    
        Returns:
            A numpy ndarray which shares the same underlying storage with the tensor.
    
        Examples:
            >>> from mindspore import Tensor
            >>> import numpy as np
            >>> x = Tensor(np.array([1, 2], dtype=np.float32))
            >>> y = x.asnumpy()
            >>> y[0] = 11
            >>> print(x)
            [11.  2.]
            >>> print(y)
            [11.  2.]
        """
        if self.has_init:
            self.init_data()
>       return TensorPy_.asnumpy(self)
E       RuntimeError: aclnnRotaryPositionEmbeddingGetWorkspaceSize call failed, please check!
E       
E       ----------------------------------------------------
E       - Ascend Error Message:
E       ----------------------------------------------------
E       [PID: 788890] 2026-05-19-10:54:09.521.649 Communication_Error_Bind_IP_Port(EI0019): Failed to enable listening for the host network adapter socket. Reason: The IP address 8.92.7.125 and port 65536 have already been bound.[THREAD:791460]
E               Solution: 1. Check whether this port has been occupied by another process. If yes, you can make adjustment using the environment variable HCCL_IF_BASE_PORT and use sysctl -w net.ipv4.ip_local_reserved_ports=****-**** to adjust the scope of reserved ports. 2. Check whether the service process is started multiple times on a device during this service.
E               TraceBack (most recent call last):
E               The shape of the input x, cos and sin is not supported.[FUNC:TilingSplit][FILE:rope_interleaved_tiling.cpp][LINE:321][THREAD:791775]
E               TilingSplit fail.[FUNC:DoOpTiling][FILE:rope_interleaved_tiling.cpp][LINE:364][THREAD:791775]
E               Tiling failed[THREAD:791775]
E               Tiling Failed.[THREAD:791775]
E               Kernel GetWorkspace failed. opType: 4[THREAD:791775]
E               RotaryPositionEmbedding ADD_TO_LAUNCHER_LIST_AICORE failed.[THREAD:791775]
E       
E       (Please search "CANN Common Error Analysis" at https://www.mindspore.cn/en for error code description)
E       
E       ----------------------------------------------------
E       - C++ Call Stack: (For framework developers)
E       ----------------------------------------------------
E       mindspore/ops/kernel/ascend/aclnn/pyboost_impl/auto_generate/pyboost_ascend_ops_3.cc:3129 operator()

/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/common/tensor.py:1013: RuntimeError
=============================== warnings summary ===============================
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
    setattr(self, word, getattr(machar, word).flat[0])

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
    return self._float_to_str(self.smallest_subnormal)

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
    setattr(self, word, getattr(machar, word).flat[0])

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
    return self._float_to_str(self.smallest_subnormal)

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2.py:57
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2.py:57: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("batchnorm_fold2")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2_grad.py:56
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2_grad.py:56: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("batchnorm_fold2_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2_grad_reduce.py:48
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/batchnorm_fold2_grad_reduce.py:48: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("batchnorm_fold2_grad_reduce")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/correction_mul.py:51
--
FAILED rotary_position_embedding_shard_in_python.py::test_rpe_dp_tp - Runtime...
======================= 1 failed, 22 warnings in 13.67s ========================
[INFO] DISTRIBUTED(788890,ffff25c6f120,python3.9):2026-05-19-10:54:11.916.441 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(788890,ffff2545f120,python3.9):2026-05-19-10:54:11.916.438 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!

好,逐一分析三个问题再动手:

1. 精度评估:RPE 是纯 element-wise 运算,无跨 rank 的 reduce,standalone 和分布式走完全一样的 NPU kernel(相同输入,相同本地 shard),理论上 fwd max_diff≈0。backward 中 Partial("sum") 做 all-reduce,float16 的 epsilon≈1e-3,所以 atol=1e-3 是合理的下界,可以安全设置,不需要留 1e-2 的余量。

2. backward:参照 SFA 的 _get_grad_placements + _assert_bwd,核心逻辑是:某个 mesh 维度上若存在任意 Shard 输入,则该维度上所有 Replicate 输入的梯度变成 Partial("sum"),可统一 gather。这样 dp_b 的 grad_cos/sin(Partial)和 dp_tp 的 grad_x/cos/sin(Shard)都能正确验证。

3. mode:去掉全局 MODE=0,改用 _make_rpe(mode) 工厂闭包,每个测试用不同 mode,并将含 backward 的测试也覆盖多种 mode。

快速 lint 检查后提交。

有失败,先看完整输出。

现在看清楚了。记录日志,分析原因。

现在修复 ST 文件。

Group1/3/4 通过,Group2 的 test_rpe_dp_tp 失败。看详细错误。


System

Conversation compacted


User · 2026-05-19T03:04:31.919Z

This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.

Summary:

  1. Primary Request and Intent: The user requested completing and validating the RotaryPositionEmbedding (RPE) distributed operator implementation in HyperParallel via a multi-iteration ascend-test workflow:

    • Commit the 5 new RPE files and run ST tests on Ascend NPU server
    • Analyze failures, fix issues, and repeat until all pass
    • Requirements: (1) modify some ST tests to use non-zero mode values; (2) follow SFA pattern for backward verification using _get_grad_placements and _assert_bwd; (3) evaluate and set appropriate precision tolerance (originally 1e-2)
    • Constraint: only commit the 5 task-relevant new files; do NOT touch existing untracked files
  2. Key Technical Concepts:

    • RotaryPositionEmbedding: formula y = xcos + x_rotatesin; element-wise, indivisible along D (last dim); B/N/S freely shardable; 4 modes: 0=rotate_half, 1=rotate_interleaved, 2=quarter, 3=interleave-half
    • CANN backward support: mode=0 and mode=1 have backward kernels; mode=2 and mode=3 do NOT (SyncCopy fails with Src ptr=0 when calling .asnumpy() on gradient)
    • mode=1 shape constraint: rope_interleaved_tiling.cpp may reject shapes in certain conditions; also HCCL port conflicts in concurrent 4-card tests can cause kernel initialization failure
    • _get_grad_placements: SFA pattern — if any input is Shard on mesh dim d, a Replicate input gets Partial("sum") gradient on dim d; Shard inputs keep Shard
    • _assert_bwd: reconstructs DTensor from local gradient using derived placements, gathers via full_tensor(), compares to standalone reference
    • Precision tolerance: atol=1e-3, rtol=1e-3 — justified because RPE is pure element-wise with no cross-rank reduction; distributed and standalone invoke identical NPU kernels on same data; float16 epsilon ≈ 1e-3
    • MindSporeCase signature: MindSporeCase(file_name, case_name, master_port, worker_num, local_worker_num, glog_v) — 2-card: (..., 2, 2, 2), 4-card: (..., 4, 4, 2), 8-card: (..., 8, 8, 2)
    • _make_rpe(mode): factory closure capturing mode; returns callable (x, cos, sin) → y for use with ms.grad
  3. Files and Code Sections:

    • hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py (created in prior session, complete)

      • Core distributed op: _normalize_rpe_args, RotaryPositionEmbeddingDistributedOp with _validate_input_layouts, preprocess, infer_layout
      • Output layout = deep copy of x_layout; D must be replicated; cos/sin sharding on non-D dims must match x or be replicated
    • hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml (created in prior session, complete)

      RotaryPositionEmbedding:
        dist_op_name: _rotary_position_embedding_dist_op
        distributed_op_class: RotaryPositionEmbeddingDistributedOp
        distributed_op_file: parallel_rotary_position_embedding
      
    • tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py (created in prior session, 22 tests all passing)

      • 4 test classes: TestNormalizeRpeArgs, TestYamlRegistration, TestInferLayoutPositive, TestInferLayoutNegative
    • tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py (created and revised multiple times) Current state (commit 574a74b) — latest revision with split standalone functions and mode assignments:

      _INPUT_NAMES = ("x", "cos", "sin")
      _TOL = {"atol": 1e-3, "rtol": 1e-3}
      
      def _make_rpe(mode: int):
          def _fn(x, cos, sin):
              return rotary_position_embedding(x, cos, sin, mode=mode)
          return _fn
      
      def _run_standalone_fwd(x_np, cos_np, sin_np, mode=0):
          """Forward only — for mode=2/3 (no CANN backward support)."""
          return _to_f32np(_make_rpe(mode)(_np_to_f16(x_np), _np_to_f16(cos_np), _np_to_f16(sin_np)))
      
      def _run_standalone(x_np, cos_np, sin_np, mode=0):
          """Forward + backward — for mode=0/1 only."""
          x = _np_to_f16(x_np); cos = _np_to_f16(cos_np); sin = _np_to_f16(sin_np)
          fn = _make_rpe(mode)
          fwd_np = _to_f32np(fn(x, cos, sin))
          grads = ms.grad(fn, (0, 1, 2))(x, cos, sin)
          return fwd_np, tuple(_to_f32np(g) for g in grads)
      
      def _get_grad_placements(d_inputs: tuple) -> list:
          n_dims = len(d_inputs[0].layout.placements)
          dim_has_shard = [
              any(isinstance(d_inp.layout.placements[d], Shard) for d_inp in d_inputs)
              for d in range(n_dims)
          ]
          result = []
          for d_inp in d_inputs:
              grad_placements = tuple(
                  Partial("sum") if isinstance(p, Replicate) and dim_has_shard[dim_idx] else p
                  for dim_idx, p in enumerate(d_inp.layout.placements)
              )
              result.append(grad_placements)
          return result
      
      def _assert_fwd(dist_out, ref_np, tag): ...
      def _assert_bwd(raw_grads, d_inputs, ref_grads, tag): ...
      

      Current test/mode assignments:

      • test_rpe_replicated: mode=0, _run_standalone_fwd, fwd only, 2-card dp
      • test_rpe_dp_b: mode=1, _run_standalone, fwd+bwd (grad_x→Shard(0), grad_cos/sin→Partial("sum")), 2-card dp
      • test_rpe_tp_n: mode=0, _run_standalone, fwd+bwd (all Shard(1)), 2-card tp
      • test_rpe_dp_tp: mode=1, _run_standalone, fwd+bwd — CURRENTLY FAILING
      • test_rpe_dp_sp: mode=2, _run_standalone_fwd, fwd only, 4-card dp×sp
      • test_rpe_tp_sp: mode=3, _run_standalone_fwd, fwd only, 4-card tp×sp
      • test_rpe_dp_tp_cos_full: mode=2, _run_standalone_fwd, fwd only, 4-card dp×tp
      • test_rpe_dp_tp_sp: mode=3, _run_standalone_fwd, fwd only, 8-card dp×tp×sp
    • tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py (runner, unchanged since creation)

      IMPL_FILE = str(Path(__file__).resolve().parent / "rotary_position_embedding_shard_in_python.py")
      
      @arg_mark(plat_marks=["platform_ascend910b"], level_mark="level1", ...)
      def test_parallel_rpe_ms_group1():
          parallel_run([
              MindSporeCase(IMPL_FILE, "test_rpe_replicated", 19300, 2, 2, 2),
              MindSporeCase(IMPL_FILE, "test_rpe_dp_b", 19301, 2, 2, 2),
              MindSporeCase(IMPL_FILE, "test_rpe_tp_n", 19302, 2, 2, 2),
          ])
      
      def test_parallel_rpe_ms_group2():
          parallel_run([
              MindSporeCase(IMPL_FILE, "test_rpe_dp_tp", 19303, 4, 4, 2),
              MindSporeCase(IMPL_FILE, "test_rpe_dp_sp", 19304, 4, 4, 2),
          ])
      
      def test_parallel_rpe_ms_group3():
          parallel_run([
              MindSporeCase(IMPL_FILE, "test_rpe_tp_sp", 19305, 4, 4, 2),
              MindSporeCase(IMPL_FILE, "test_rpe_dp_tp_cos_full", 19306, 4, 4, 2),
          ])
      
      def test_parallel_rpe_ms_group4():
          parallel_run([
              MindSporeCase(IMPL_FILE, "test_rpe_dp_tp_sp", 19307, 8, 8, 2),
          ])
      
    • .claude/skills/ascend-test/ascend-test-work-rope.log (created, ignored by .gitignore so not committed) Contains Loop 1 failure analysis and fix plan.

  4. Errors and Fixes:

    Error 1 (Loop 1): mode=2/3 backward not supported in CANN

    • All 4 groups failed because _run_standalone always calls ms.grad regardless of test type
    • mode=2 (quarter) and mode=3 (interleave-half) CANN kernels return null gradient storage → SyncCopy failed: Src ptr:0
    • Error: RuntimeError: SyncCopy failed for Tensor(shape=[4, 4, 16, 64], dtype=Float32)
    • Fix: split _run_standalone into _run_standalone_fwd (no ms.grad) and _run_standalone (with ms.grad); forward-only tests use _run_standalone_fwd; also revised mode assignments so mode=2/3 only used in forward-only tests

    Error 2 (Loop 2, still ongoing): test_rpe_dp_tp fails with mode=1

    • Group1, Group3, Group4 now PASS; Group2 fails on test_rpe_dp_tp
    • Error in _run_standalone at forward pass: RuntimeError: aclnnRotaryPositionEmbeddingGetWorkspaceSize call failed
    • CANN message: The shape of the input x, cos and sin is not supported. TilingSplit fail.[FILE:rope_interleaved_tiling.cpp][LINE:321]
    • Additional: Communication_Error_Bind_IP_Port(EI0019): port 65536 have already been bound — HCCL port conflict in 4-card concurrent test
    • Root cause: mode=1 (rotate_interleaved) has stricter CANN shape/tiling constraints; possibly worsened by HCCL port conflict when concurrent 4-card tests (dp_tp + dp_sp in group2) share internal HCCL ports
    • Fix plan (NOT YET APPLIED): change test_rpe_dp_tp from mode=1 to mode=0 (confirmed working for all tested scenarios)
  5. Problem Solving:

    • Precision tolerance: analyzed float16 epsilon ≈ 1e-3, RPE is pure element-wise with no cross-rank reduction → atol=1e-3 is appropriate (tightened from original 1e-2)
    • Backward verification: adopted SFA's _get_grad_placements + _assert_bwd pattern; handles both Shard (clean gather) and Partial("sum") (all-reduce) cases correctly
    • Mode support: discovered CANN only supports backward for mode=0 and mode=1; mode=2/3 forward-only
  6. All User Messages:

    • "最后一个8卡用例broadcast Shard(S)是什么意思,三个维度都做了切分,是cos或者sin维度为1,进行广播,广播到shard后的维度进行计算么?输出也是带shard?" — asking for clarification on 8-card test broadcast semantics
    • "请继续" — continue from where left off
    • "/ascend-test 把这5个文件提交成commit。遵循以下步骤和要求完成算子的开发和验证。\n1. 提交commit,使用/ascend-test登录服务器进行ST的验证。\n2. 分析失败的用例,对分布式算子实现,或者ST用例进行修改。\n3. 修改完成后,重复1的操作,继续进行验证。\n\n要求:\n1. 一旦修改了分布式算子实现的代码,就要执行UT用例确保UT用例通过再提交commit。\n2. 在ascend-test的skills目录下,存留一个工作日志ascend-test-work-rope.log,每一次失败,要记录下loop id(第几次记录),报错情况,分析的结论,以及计划修改的内容。\n3. 提交commit,只能提交本轮新增/修改的文件,不能对存量的与本次任务无关的untracked files进行任何操作。"
    • "1. ST用例中mode只等于0,酌情改一些用例为其他的mode\n2. 反向的验证,能不能参考sparse_flash_attention,反向通过_get_grad_placements和_assert_bwd对比?\n3. 精度能不能按1e-3等来比对?1e-2是如何定下来的?是否合理,请评估确定后再修改。"
  7. Pending Tasks:

    • Fix test_rpe_dp_tp failure: change from mode=1 to mode=0 (or investigate if mode=1 with shape (4,4,16,64) can be made to work by adjusting shapes or avoiding concurrent 4-card port conflicts)
    • Commit the fix, push to ascend server, and re-run ST tests (Loop 3)
    • All 4 groups must pass before the task is complete
  8. Current Work: Executing the /ascend-test workflow — currently at Loop 2 (second test run after first fix). The latest test run (commit 574a74b) showed:

    • Group1 (2-card): PASSED ✓
    • Group2 (4-card): FAILED — test_rpe_dp_tp fails
    • Group3 (4-card): PASSED ✓
    • Group4 (8-card): PASSED ✓

    The specific error for test_rpe_dp_tp (mode=1, 4-card, fwd+bwd):

    RuntimeError: aclnnRotaryPositionEmbeddingGetWorkspaceSize call failed
    The shape of the input x, cos and sin is not supported.
    TilingSplit fail.[FUNC:TilingSplit][FILE:rope_interleaved_tiling.cpp][LINE:321]
    

    This occurs in _run_standalone at line 130 (fwd_np = _to_f32np(fn(x, cos, sin))), meaning the forward pass itself fails for mode=1 (rotate_interleaved) with shapes B=4, N=4, S=16, D=64 in the 4-card concurrent test environment.

  9. Optional Next Step: Fix test_rpe_dp_tp by changing it from mode=1 to mode=0. The worker log shows:

    >       ref_fwd, ref_grads = _run_standalone(x_np, cos_np, sin_np, mode=mode)
    rotary_position_embedding_shard_in_python.py:303:
    rotary_position_embedding_shard_in_python.py:130: in _run_standalone
        fwd_np = _to_f32np(fn(x, cos, sin))
    RuntimeError: aclnnRotaryPositionEmbeddingGetWorkspaceSize call failed, please check!
    The shape of the input x, cos and sin is not supported.
    TilingSplit fail.[FUNC:TilingSplit][FILE:rope_interleaved_tiling.cpp][LINE:321]
    

    The fix: in test_rpe_dp_tp, change mode = 1 to mode = 0. This follows the ongoing /ascend-test iteration workflow where failing tests are diagnosed and fixed before re-running. Mode=0 (rotate_half) is confirmed to work for all shape combinations tested so far.

If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32.jsonl Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening, do not preface with "I'll continue" or similar. Pick up the last task as if the break never happened.


Assistant · 2026-05-19T03:04:45.749Z

[Read: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py]
285	# ---------------------------------------------------------------------------
286	# 4-card tests
287	# ---------------------------------------------------------------------------
288	
289	def test_rpe_dp_tp():
290	    """
291	    Feature: RotaryPositionEmbedding (MindSpore) 2-D dp×tp mesh, B by dp, N by tp.
292	    Description:
293	        - 4-card 2-D mesh (dp=2, tp=2); x/cos/sin all (Shard(0), Shard(1)).
294	        - cos/sin full shape (B, N, S, D) — same placements as x.
295	        - float16, mode=1 (rotate_interleaved).
296	        - Forward and all three gradients verified; all grad placements = (Shard(0), Shard(1)).
297	    Expectation: Distributed fwd and all gradients match standalone within tolerance.
298	    """
299	    mode = 1
300	    x_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
301	    cos_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
302	    sin_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
303	    ref_fwd, ref_grads = _run_standalone(x_np, cos_np, sin_np, mode=mode)
304	
305	    mesh = init_device_mesh(device_type="npu", mesh_shape=(2, 2), mesh_dim_names=("dp", "tp"))
306	    placements = (Shard(0), Shard(1))
307	    dx = distribute_tensor(_np_to_f16(x_np), mesh, placements)
308	    dcos = distribute_tensor(_np_to_f16(cos_np), mesh, placements)
309	    dsin = distribute_tensor(_np_to_f16(sin_np), mesh, placements)
310	    d_inputs = (dx, dcos, dsin)
311	
312	    fn = _make_rpe(mode)
313	    _assert_fwd(fn(*d_inputs), ref_fwd, "dp_tp mode=1")
314	
315	    raw_grads = ms.grad(fn, (0, 1, 2))(*d_inputs)
316	    _assert_bwd(raw_grads, d_inputs, ref_grads, "dp_tp mode=1")
317	
318	
319	def test_rpe_dp_sp():
320	    """
321	    Feature: RotaryPositionEmbedding (MindSpore) 2-D dp×sp mesh, B by dp, S by sp.
322	    Description:
323	        - 4-card 2-D mesh (dp=2, sp=2); x (Shard(0), Shard(2)).
324	        - cos/sin broadcast (1, 1, S, D): dp Replicate, sp Shard(2).
[Edit: /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py]
The file /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py has been updated successfully. (file state is current in your context — no need to Read it back)
[Read: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log]
Wasted call — file unchanged since your last Read. Refer to that earlier tool_result instead.
[Edit: /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log]
The file /root/workspace/hyper-parallel/.claude/skills/ascend-test/ascend-test-work-rope.log has been updated successfully. (file state is current in your context — no need to Read it back)
[Bash: git diff tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py]
diff --git a/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py b/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
index 18b1dd3..b6f881a 100644
--- a/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
+++ b/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
@@ -292,11 +292,11 @@ def test_rpe_dp_tp():
     Description:
         - 4-card 2-D mesh (dp=2, tp=2); x/cos/sin all (Shard(0), Shard(1)).
         - cos/sin full shape (B, N, S, D) — same placements as x.
-        - float16, mode=1 (rotate_interleaved).
+        - float16, mode=0 (rotate_half).
         - Forward and all three gradients verified; all grad placements = (Shard(0), Shard(1)).
     Expectation: Distributed fwd and all gradients match standalone within tolerance.
     """
-    mode = 1
+    mode = 0
     x_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
     cos_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
     sin_np = np.random.randn(B, N, S, D_DIM).astype(np.float32)
@@ -310,10 +310,10 @@ def test_rpe_dp_tp():
     d_inputs = (dx, dcos, dsin)
 
     fn = _make_rpe(mode)
-    _assert_fwd(fn(*d_inputs), ref_fwd, "dp_tp mode=1")
+    _assert_fwd(fn(*d_inputs), ref_fwd, "dp_tp mode=0")
 
     raw_grads = ms.grad(fn, (0, 1, 2))(*d_inputs)
-    _assert_bwd(raw_grads, d_inputs, ref_grads, "dp_tp mode=1")
+    _assert_bwd(raw_grads, d_inputs, ref_grads, "dp_tp mode=0")
 
 
 def test_rpe_dp_sp():
[Bash: git add tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py && git commit -m "test: fix test_rpe_dp_tp mode=1 tiling failure, sw]
[master_dist_op 01f122f] test: fix test_rpe_dp_tp mode=1 tiling failure, switch to mode=0
 1 file changed, 4 insertions(+), 4 deletions(-)
[Bash: git branch --show-current]
master_dist_op
[Bash: git push ascend-repo master_dist_op -f 2>&1]
Authorized users only. All activities may be monitored and reported.
To 8.92.7.125:/home/hdd/bare-repo-hyper-parallel/
   574a74b..01f122f  master_dist_op -> master_dist_op
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git checkout master_dist_op && git reset --hard HEAD 2>&1"]
Authorized users only. All activities may be monitored and reported.
M	tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
Already on 'master_dist_op'
HEAD is now at 01f122f test: fix test_rpe_dp_tp mode=1 tiling failure, switch to mode=0
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel && git log --oneline -1 2>&1"]
Authorized users only. All activities may be monitored and reported.
01f122f test: fix test_rpe_dp_tp mode=1 tiling failure, switch to mode=0
[Bash: ssh hdd@8.92.7.125 "cd /home/hdd/hyper-parallel/tests/mindspore/st/shard/ops && pytest -vs test_rotary_position_embedding_shard_in_python.py 2>&1" ]
<persisted-output>
Output too large (535.8KB). Full output saved to: /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results/bjexqx7i7.txt

Preview (first 2KB):
Authorized users only. All activities may be monitored and reported.
============================= test session starts ==============================
platform linux -- Python 3.9.25, pytest-8.4.2, pluggy-1.6.0 -- /home/hdd/miniconda3/envs/ci3.9/bin/python3.9
cachedir: .pytest_cache
rootdir: /home/hdd/hyper-parallel
collecting ... collected 4 items

test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1 /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float32'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:549: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  setattr(self, word, getattr(machar, word).flat[0])
/home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/numpy/core/getlimits.py:89: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
  return self._float_to_str(self.smallest_subnormal)
...
</persisted-output>
[Bash: tail -80 /root/.claude/projects/-root-workspace-hyper-parallel/d0ef256d-0777-4cfc-b653-4343c4a7ae32/tool-results/bjexqx7i7.txt]
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.79s ========================
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.70s ========================
[INFO] DISTRIBUTED(891459,ffff127cf120,python3.9):2026-05-19-11:03:51.402.169 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(891459,ffff11fbf120,python3.9):2026-05-19-11:03:51.402.169 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[INFO] DISTRIBUTED(891480,ffff33fff120,python3.9):2026-05-19-11:03:51.403.678 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
[INFO] DISTRIBUTED(891480,ffff48a3f120,python3.9):2026-05-19-11:03:51.403.678 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer.py:54: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/fake_quant_perlayer_grad.py:81: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("fake_quant_per_layer_grad")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perchannel.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perchannel")

../../../../../../miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/mindspore/ops/_op_impl/_custom_op/minmax_update_perlayer.py:50: DeprecationWarning: te_fusion.fusion_manager.fusion_manager.register is deprecated,please replace it with tbe.common.register.register_op_compute
    @fusion_manager.register("minmax_update_perlayer")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 1 passed, 22 warnings in 16.83s ========================
[INFO] DISTRIBUTED(891448,ffff1d44f120,python3.9):2026-05-19-11:03:51.428.052 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_server.cc:313] Start] Event base dispatch success!
[INFO] DISTRIBUTED(891448,ffff1cc3f120,python3.9):2026-05-19-11:03:51.428.053 [mindspore/ccsrc/cluster/rpc/core/communicator/tcp_client.cc:357] Start] Event base dispatch success!
PASSED

=============================== warnings summary ===============================
../../../../common/mark_utils.py:38
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:38: PytestUnknownMarkWarning: Unknown pytest.mark.platform_ascend910b - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, plat_mark)(func)

../../../../common/mark_utils.py:39
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:39: PytestUnknownMarkWarning: Unknown pytest.mark.level1 - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, level_mark)(func)

../../../../common/mark_utils.py:40
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:40: PytestUnknownMarkWarning: Unknown pytest.mark.allcards - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, card_mark)(func)

../../../../common/mark_utils.py:41
  /home/hdd/hyper-parallel/tests/common/mark_utils.py:41: PytestUnknownMarkWarning: Unknown pytest.mark.essential - is this a typo?  You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/how-to/mark.html
    func = getattr(pytest.mark, essential_mark)(func)

tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/torch_npu/utils/collect_env.py:58: UserWarning: Warning: The /usr/local/Ascend/cann-9.0.0 owner does not match the current owner.
    warnings.warn(f"Warning: The {path} owner does not match the current owner.")

tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py::test_parallel_rpe_ms_group1
  /home/hdd/miniconda3/envs/ci3.9/lib/python3.9/site-packages/torch_npu/utils/collect_env.py:58: UserWarning: Warning: The /usr/local/Ascend/cann-9.0.0/aarch64-linux/ascend_ops_install.info owner does not match the current owner.
    warnings.warn(f"Warning: The {path} owner does not match the current owner.")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================== 4 passed, 8 warnings in 148.78s (0:02:28) ===================

读取当前实现文件,修改 test_rpe_dp_tp 的 mode。

找到了 test_rpe_dp_tp 在第 299 行,将 mode=1 改为 mode=0。

更新工作日志,记录 Loop 2 的失败情况和 Loop 3 的修改。

现在提交修改。

HEAD 已同步。开始运行 Loop 3 ST 测试。

全部 4 个测试组均通过!

================== 4 passed, 8 warnings in 148.78s (0:02:28) ===================

Loop 3 汇总

Step Result
Commit 01f122f — test: fix test_rpe_dp_tp mode=1 tiling failure, switch to mode=0
Push ascend-repo/master_dist_op
Sync /home/hdd/hyper-parallel HEAD=01f122f
Group1 (2-card) PASSED
Group2 (4-card) PASSED
Group3 (4-card) PASSED
Group4 (8-card) PASSED

所有 8 个 RPE 分布式算子 ST 用例全部通过,任务完成。核心修复链路:

  • Loop 1:拆分 _run_standalone_fwd/_run_standalone,mode=2/3 改为 forward-only 路径(CANN 无 backward 支持)
  • Loop 2:test_rpe_dp_tp 从 mode=1 改为 mode=0(CANN rope_interleaved_tiling 对该形状有限制)

User · 2026-05-19T03:14:18.669Z

/autogit commit已经准备好了,提交一个PR,和一个ISSUE,格式参考docs/PR_description.md和docs/ISSUE.md。格式严格参考,只填充内容即可。 Self-checklist的5项不要变更。


User · 2026-05-19T03:14:18.669Z

Base directory for this skill: /root/workspace/hyper-parallel/.claude/skills/autogit

AutoGit


Assistant · 2026-05-19T03:14:29.247Z

[Read: /root/workspace/hyper-parallel/docs/PR_description.md]
1	**What type of PR is this?**
2	
3	/kind feature
4	
5	----
6	
7	**What does this PR do / why do we need it**:
8	
9	为 HyperParallel 接入 MindSpore MC2(Memory-Communication Coupling)通算融合算子的分布式调度逻辑,包含:
10	- `mindspore.ops.all_gather_matmul`(`AllGatherMatmul`)
11	- `mindspore.ops.matmul_reduce_scatter`(`MatmulReduceScatter`)
12	
13	CANN MC2 算子在内核内部自行完成 AllGather / ReduceScatter 通信,不需要 HyperParallel 插入额外通信原语。HyperParallel 的作用是:
14	1. **DTensor 输入解包**:通过 `preprocess()` 的 `to_local()` 提取本地 tensor 后再传给 CANN。
15	2. **输出 DTensor Layout 推断**:通过 `infer_layout()` 基于输入分片方式推断输出 tensor 的分布状态,使下游算子能正确组合分布式计算图。
16	
17	### AllGatherMatmul
18	
19	| 参数 | 说明 |
20	|------|------|
21	| x1 (m, k) | m 维被 CANN 内部 AllGather 消耗,输出 m 变为全局(Replicate)|
22	| x1 k 维 | 支持 Replicate 或 Shard;k 被切分时输出带 Partial(sum),调用方需 AllReduce |
23	| x2 (k, n) 或 (n, k) | trans_x2=False 时 k 在 dim 0,trans_x2=True 时 k 在 dim 1;k 维须与 x1 k 维 placement 匹配 |
24	| gather_output | True 时额外返回 AllGather 后的 x1 全局张量;False 时 CANN 返回空 tensor |
25	
26	输出 layout 推断:
27	- output dim 0 (m):始终 Replicate(-1),因 AllGather 消耗了 m 维分片
28	- output dim 1 (n):继承 x2 的 n 维 placement
29	- k 被切分时,output 带 `Partial(sum)`(与 `LinearDistributedOp` contract_dim 分片语义一致)
30	- gather_output=False 时 gather_out layout 强制全 Replicate,避免空 tensor 的维度越界
31	
32	### MatmulReduceScatter
33	
34	| 参数 | 说明 |
35	|------|------|
36	| x1 (m, k) | k 维须 Shard(TP),m 维可为 Replicate(纯 TP)或 Shard(DP)|
37	| x2 (k, n) 或 (n, k) | k 维须与 x1 k 维 layout 一致;n 维可任意 |
38	
39	输出 layout 推断:
40	- output dim 0 (m):ReduceScatter 将 k 的 TP 分片转化为 m 分片;若 x1 m 维有 DP 分片则联合分片(tuple tensor_map)
41	- output dim 1 (n):继承 x2 的 n 维 placement
42	- **无 Partial 状态**:CANN ReduceScatter 已在内部完成 k 方向的 sum reduce + m 方向 scatter
43	
44	### 测试覆盖
45	
46	| 测试类型 | 文件 | 内容 |
47	|----------|------|------|
48	| **UT** | `test_parallel_all_gather_matmul.py` (15 cases) | normalize_args / YAML 注册 / infer_layout 正例(1D+2D mesh、trans_x2、k 分片带 Partial)/ 错误处理(Partial 输入、k-placement 不匹配、m 维多 mesh 联合分片)|
49	| **UT** | `test_parallel_matmul_reduce_scatter.py` (12 cases) | normalize_args / YAML 注册 / infer_layout 正例 / 错误处理 |
50	| **ST** | `all_gather_matmul_shard_in_python.py` (7 cases) | x1 Shard(0)+x2 Replicate / x1 Shard(0)+x2 Shard(1) / trans_x2=True / gather_output=False / 2D (dp,tp) mesh / 4 卡 k 切分 (mp,tp) / 8 卡 mnk 全切 (mp,np,tp) |
51	| **ST** | `matmul_reduce_scatter_shard_in_python.py` (5 cases) | tp_basic / trans_x2=True / large_m / 2D (dp,tp) mesh / 8 卡 mnk 全切 (mp,np,tp) |
52	
53	----
54	
55	**Which issue(s) this PR fixes**:
56	
57	Fixes [#152](https://gitcode.com/mindspore/hyper-parallel/issues/152)
58	
59	----
60	
61	**Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.)**:
62	
63	### UT(单元测试)
64	- `tests/ut/core/shard/ops/test_parallel_all_gather_matmul.py` — 15 cases,覆盖参数归一化、YAML 注册、infer_layout(replicate/shard/trans_x2/2D-mesh/**k 分片带 Partial**)、错误处理(Partial 输入、k-placement 不匹配、m 维多 mesh 联合分片)
65	- `tests/ut/core/shard/ops/test_parallel_matmul_reduce_scatter.py` — 12 cases,覆盖参数归一化、YAML 注册、infer_layout(TP/DP+TP/n-shard/trans_x2/联合 tuple m 分片)、错误处理(Partial 输入、k Replicate、k layout 不一致)
66	
67	### ST(系统测试 - distributed, MindSpore)
68	- `tests/mindspore/st/shard/ops/test_all_gather_matmul_shard_in_python.py` — 3 组:group1(4×2 卡)、group2(2×4 卡,含 k 分片场景)、group3(1×8 卡,mnk 三轴全切)
69	- `tests/mindspore/st/shard/ops/test_matmul_reduce_scatter_shard_in_python.py` — 3 组:group1(3×2 卡)、group2(1×4 卡)、group3(1×8 卡,mnk 三轴全切)
70	
71	### 验证结果
72	- 所有 27 条 UT 通过(mock 平台,无 GPU/NPU 依赖)
73	- 所有 AGM group1/group2 ST 在 Ascend NPU 上通过(float16 精度,atol/rtol 满足)
74	- k 分片场景使用 float32 numpy 参考值,atol=0.1/rtol=0.02(与 MRS 一致,因 CANN 跨 rank partial sum 累加顺序与单次全 k matmul 路径不同)
75	- pylint 通过
76	
77	----
78	
79	**Self-checklist**:(**请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入**)
80	
81	- [x] **设计**:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改
82	- [x] **测试**:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库
83	- [x] **验证**:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述
84	- [ ] **接口**:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确
85	- [ ] **文档**:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓
86	
87	<!-- **Special notes for your reviewers**: -->
88	<!-- - [ ] 是否导致无法前向兼容 -->
89	<!-- - [ ] 是否涉及依赖的三方库变更 -->
90	
[Read: /root/workspace/hyper-parallel/docs/ISSUE.md]
1	# ISSUE: 接入 MindSpore MC2 通算融合算子分布式调度(AllGatherMatmul / MatmulReduceScatter)
2	
3	## 背景
4	
5	在分布式 Tensor Parallelism(TP)训练场景中,CANN MC2 算子(AllGatherMatmul / MatmulReduceScatter)在内核内部自行完成 AllGather / ReduceScatter 通信,性能优于分离式通信+计算方案。然而 HyperParallel 当前没有这两个算子的分布式调度逻辑,用 DTensor 对象调用时会直接失败(CANN 内核无法处理 DTensor),即使绕过也无法推断输出 DTensor 的分布状态,下游算子无法正确组合分布式计算图。
6	
7	## 目标
8	
9	为以下两个 MindSpore MC2 算子提供分布式调度支持:
10	
11	### AllGatherMatmul
12	
13	- CANN 内核内部完成 AllGather(消耗 x1 m 维分片),HyperParallel 负责:
14	  - 通过 `preprocess()` 的 `to_local()` 提取本地 tensor 传给 CANN
15	  - 通过 `infer_layout()` 推断输出 layout:
16	    - m 维始终 Replicate(AllGather 消耗了 m 维分片)
17	    - n 维继承 x2 的 n 维 placement
18	    - k 被切分时输出带 `Partial(sum)`,调用方需 AllReduce(与 `LinearDistributedOp` contract_dim 分片语义一致)
19	    - `gather_output=False` 时 CANN 返回空 tensor,gather_out layout 强制全 Replicate,避免 Shard dim 越界
20	
21	支持的分片模式:
22	- x1 Shard(0) on tp,x2 Replicate
23	- x1 Shard(0) on tp,x2 Shard(1) on n
24	- trans_x2=True
25	- 2D mesh (dp, tp)
26	- k 切分:4 卡 (mp=2, tp=2),x1 Shard(0)+Shard(1),x2 Replicate+Shard(0),输出带 Partial(sum) on tp
27	- k 切分:8 卡 (mp=2, np=2, tp=2),x1 Shard(0)+Replicate+Shard(1),x2 Replicate+Shard(1)+Shard(0),输出带 Partial(sum) on tp
28	
29	### MatmulReduceScatter
30	
31	- CANN 内核内部完成 ReduceScatter(k 方向 sum reduce + m 方向 scatter),HyperParallel 负责:
32	  - 通过 `preprocess()` 的 `to_local()` 提取本地 tensor 传给 CANN
33	  - 通过 `infer_layout()` 推断输出 layout:
34	    - output dim 0 (m):ReduceScatter 将 k 的 TP 分片转化为 m 分片;若 x1 m 维有 DP 分片则联合分片(tuple tensor_map)
35	    - output dim 1 (n):继承 x2 的 n 维 placement
36	    - **无 Partial 状态**:CANN ReduceScatter 已在内部完成 k 方向 sum + m 方向 scatter
37	
38	支持的分片模式:
39	- x1 Shard(1) on tp(k 维),x2 Shard(0) on tp(k 维)
40	- trans_x2=True
41	- 2D mesh (dp, tp),x1 Shard(1) on tp
42	- 8 卡 (mp=2, np=2, tp=2),m/n/k 三轴全切
43	
44	---
45	
46	两个算子均继承 DistributedOp 基类,实现 `preprocess` 和 `infer_layout`,通过 YAML 注册。
47	不需要 `get_expand_impl` 覆盖(基类默认返回 None)。
48	
49	**Partial 说明**:AllGatherMatmul 在 k 维切分时输出带 `Partial(sum)`,`full_tensor()` 自动触发 AllReduce;MatmulReduceScatter 不需要 Partial(CANN 内核已内部完成 ReduceScatter,结果完整)。
50	
51	约束:
52	
53	| 算子 | 约束 |
54	|------|------|
55	| AllGatherMatmul | x1 k 维与 x2 k 维 placement 必须一致(均 Replicate 或均 Shard 在同一 mesh axis);k 被切分时输出带 Partial(sum);x1 m 维不支持多 mesh 联合分片(tuple tensor_map)|
56	| MatmulReduceScatter | x1 k 维必须 Shard(TP);x2 k 维 placement 必须与 x1 k 维一致 |
57	| 两者共用 | gather_index=0、trans_input=False、bias=None(当前 MindSpore 约束);不允许 Partial 输入 |
58	
59	UT:`test_parallel_all_gather_matmul.py`(15 cases)、`test_parallel_matmul_reduce_scatter.py`(12 cases)
60	ST:4 个 MindSpore 分布式测试文件(AGM 3 组,MRS 3 组,含 8 卡 mnk 全切场景)
61	
62	## 相关 PR
63	
64	#656
65	
[Bash: git log master..HEAD --oneline 2>&1]
1c7d6e9 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b !656 feat: add distributed ops AllGatherMatmul and MatmulReduceScatter (MC2)
749d780 !657 bugfix: add CMake pre-build support for mindspore custom_ops
93cdeda feat: add CMake pre-build support for mindspore custom_ops
aa5c8fb feat: add distributed ops all_gather_matmul and matmul_reduce_scatter
cecf192 !588 merge master_dfunction_dsa into master
47233b8 feat: add distributed op npu_dense_lightning_indexer_softmax_lse, npu_dense_lightning_indexer_grad_kl_loss_dist_op, npu_sparse_lightning_indexer_grad_kl_loss_dist_op, npu_mhc_post & npu_mhc_pre_sinkhorn
d84aa1a !648 feat: add dist op InplaceFillScalar & InplaceFillTensor
a914165 feat: add dist op InplaceFillScalar & InplaceFillTensor
89f023b !645 fix(pynative): make DeviceMesh / fully_shard robust under TP+EP+FSDP
8a9cadb fix(pynative): make DeviceMesh / fully_shard robust under TP+EP+FSDP
8d52cab !643 fix(reshape): fix ValueError on Replicate placement with small tensors
ea36632 fix(reshape): fix ValueError on Replicate placement with small tensors
d86e5f2 !603 swap_tensor
6f32e38 swap_tensor
e6b0d1e !599 feat(trainer+models): training stack + qwen3.5 dense/moe/vl-moe aligned
4445ec5 !624 feat(examples/torch/llama3): add 8-card DP+TP+CP+SP+FSDP2 example and llama3 ST coverage
380840b feat(trainer+models): training stack + qwen3.5 dense/moe/vl-moe aligned
df95173 !630 unwrap_cell
a68b934 !629 merge fix/issue-118-fsdp-shape-zero into master
70eaf1e unwrap_cell
37be588 fix: delay requires_grad restore for MindSpore fsdp param
5180fd4 !625 test(torch): 新增 Llama3 风格 TP+FSDP / TP+CP+FSDP 单卡精度对比测试
cb85d7f feat(examples/torch/llama3): add 8-card DP+TP+CP+SP+FSDP2 example and llama3 ST coverage
176fd15 !621 fix(fully_shard): reduce pure tp compat grads
3e614c4 test(torch): add Llama3 accuracy suite for parallel-vs-single-card
2f5ba97 !614 feat(mindspore): Llama3 tensor+sequence parallel example and MindSpore Cell support
561579e !620 fix: isolate CellBackwardHook output wrapping
0822568 !613 feat: add dist op Squeeze
34373d5 fix(fully_shard): reduce pure tp compat grads
f63bb9b !541 feat(pipeline): add dual-pipe comm/compute overlap coordinator
66a81fc test: add CellBackwardHook wrap_output coverage
422a72c feat(pipeline): add dual-pipe comm/compute overlap coordinator
a995770 !618 fix: add symmetric_memory docs and fix multiocore test for different devices.
d50401b fix: isolate CellBackwardHook output wrapping
92c9cdb fix: add symmetric_memory docs and fix multiocore test for different devices.
d7aa233 !616 merge fix/ms-hsdp-queued-div-policy into master
25dc07a fix: preserve MindSpore async reduce div policy
0b6d200 !615 feat(examples): Llama3 Torch FSDP+TP、TP+CP demo and README
504152c feat(examples): Llama3 Torch demos for TP, FSDP+TP, and TP+CP
26c6adc feat(mindspore): Llama3 TP+SP example and Cell parity in TP distribute_module
e6671d5 Add dist op Squeeze
bfe13cf !611 merge pr/20260430_152133 into master
fd4dac1 fix: remove MindSpore runtime param_info patch
59004a0 !610 merge master_dist_op into master
0e75552 !594 merge device_mesh_concate_master into master
140fa30 feat(dtensor): add layout-backed device mesh operations
c300f97 !609 fix: hide MindSpore activation wrapper cell prefix
3b0d596 add dist op Maximum
2ea2bf9 fix: hide MindSpore activation wrapper cell prefix
f02a94f !606 normalize device type
4386aff !607 feat(dcp): record dtype and full_shape when layout is absent or falsy
470b38b !583 fix: make fully_shard prefetch idempotent with replicate_params
85c9279 feat(dcp): record dtype and full_shape when layout is absent or falsy
1afcfa3 normalize device type
345c1c3 fix: handle replicate params in fully_shard transitions
6a68999 !601 fix: update 3rdparty shmem to v1.3.0
5e41778 !592 feat: Native compiling Multicore_moe_ffn
52b8192 !595 refactor(tests): consolidate mindspore and torch ut under tests/ut
7cd47bb !604 merge ops into master
84d40e4 multicore本地编译,依赖ops库代码拉取打patch
6738257 update shmem to v1.3.0
0930877 !602 merge add_llama into master
d029e48 !591 add_mesh_layout
b6b6b5c feat(examples): add Llama3 tensor-parallel demo; fix RowwiseParallel embedding output
8231e18 feat: add DTensorBase.to() for MindSpore backend and UT tests
e58f53a refactor(tests): consolidate mindspore and torch ut under tests/ut
30a6540 !582 merge fix/ms-comm-fusion-prefetch-overlap into master
ca97a6d add_mesh_layout
b91d00d fix some bugs
f8599d8 ops代码合入
[Bash: git diff master..HEAD --name-only 2>&1]
.claude/rules/testing.md
.claude/skills/autogit/references/examples.md
.claude/skills/autogit/scripts/commands.py
.claude/skills/code-review/review-checklist.md
.claude/skills/platform-dev/workflows/05-testing.md
.gitignore
.jenkins/check/config/filter_cpplint.txt
.jenkins/check/config/filter_pylint.txt
.jenkins/rules/codespell/codespell.allow
3rdparty/patch/shmem.patch
CLAUDE.md
CODEOWNERS
README.md
docs/pipeline_parallel_overlap_b_f.md
examples/README.md
examples/mindspore/llama3/README.md
examples/mindspore/llama3/__init__.py
examples/mindspore/llama3/model.py
examples/mindspore/llama3/parallelize.py
examples/mindspore/llama3/tensor_parallel_example.py
examples/qwen3_5_0_8b_base/train.yaml
examples/qwen3_5_35b_a3b_base/train.yaml
examples/qwen3_vl_30b_a3b_instruct/train.yaml
examples/torch/llama3/README.md
examples/torch/llama3/__init__.py
examples/torch/llama3/dp_tp_cp_sp_fsdp_example.py
examples/torch/llama3/fsdp_tp_example.py
examples/torch/llama3/model.py
examples/torch/llama3/parallelize.py
examples/torch/llama3/tensor_parallel_example.py
examples/torch/llama3/tp_cp_example.py
examples/torch/pp_overlap/pp_overlap_moe_example.py
hyper_parallel/__init__.py
hyper_parallel/core/activation_checkpoint/__init__.py
hyper_parallel/core/activation_checkpoint/activation_checkpoint.py
hyper_parallel/core/activation_checkpoint/swap.py
hyper_parallel/core/distributed_checkpoint/layout.py
hyper_parallel/core/dtensor/_mesh_layout.py
hyper_parallel/core/dtensor/device_mesh.py
hyper_parallel/core/dtensor/dtensor.py
hyper_parallel/core/dtensor/layout.py
hyper_parallel/core/expert_parallel/expert_parallel.py
hyper_parallel/core/fully_shard/hsdp_scheduler.py
hyper_parallel/core/fully_shard/hsdp_state.py
hyper_parallel/core/multicore/__init__.py
hyper_parallel/core/multicore/doc/README.md
hyper_parallel/core/multicore/modules/common/compute_graph.py
hyper_parallel/core/multicore/modules/moe_ffn/backward/gen_runtime_data.py
hyper_parallel/core/multicore/modules/moe_ffn/common/task_builders.py
hyper_parallel/core/multicore/modules/moe_ffn/forward/gen_runtime_data.py
hyper_parallel/core/multicore/ops/multicore_moe_ffn/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_graph/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_graph/fusion_pass/.gitkeep
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_graph/multicore_moe_ffn_proto.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/config/ascend910_93/multicore_moe_ffn_binary.json
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/config/ascend910_93/multicore_moe_ffn_simplified_key.ini
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/config/ascend910b/multicore_moe_ffn_binary.json
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/config/ascend910b/multicore_moe_ffn_simplified_key.ini
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/multicore_moe_ffn_def.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/multicore_moe_ffn_infershape.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/multicore_moe_ffn_tiling.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/multicore_moe_ffn_tiling.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/op_api/aclnn_multicore_moe_ffn.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/op_api/aclnn_multicore_moe_ffn.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/op_api/multicore_moe_ffn.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_host/op_api/multicore_moe_ffn.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_kernel/multicore_moe_ffn.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_kernel/multicore_moe_ffn_tiling_key.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_kernel/put_mem_signal/put_mem_signal_kernel.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_kernel/runtime_config.hpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn/op_kernel/worker_kernel.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_graph/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_graph/fusion_pass/.gitkeep
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_graph/multicore_moe_ffn_grad_proto.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/CMakeLists.txt
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/config/ascend910_93/multicore_moe_ffn_grad_binary.json
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/config/ascend910_93/multicore_moe_ffn_grad_simplified_key.ini
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/config/ascend910b/multicore_moe_ffn_grad_binary.json
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/config/ascend910b/multicore_moe_ffn_grad_simplified_key.ini
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/multicore_moe_ffn_grad_def.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/multicore_moe_ffn_grad_infershape.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/multicore_moe_ffn_grad_tiling.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/multicore_moe_ffn_grad_tiling.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/op_api/aclnn_multicore_moe_ffn_grad.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/op_api/aclnn_multicore_moe_ffn_grad.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/op_api/multicore_moe_ffn_grad.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_host/op_api/multicore_moe_ffn_grad.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_kernel/multicore_moe_ffn_grad.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_kernel/multicore_moe_ffn_grad_tiling_key.h
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_kernel/put_mem_signal/put_mem_signal_kernel.cpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_kernel/runtime_config.hpp
hyper_parallel/core/multicore/ops/multicore_moe_ffn_grad/op_kernel/worker_kernel.cpp
hyper_parallel/core/multicore/ops/ops-nn.patch
hyper_parallel/core/multicore/ops/ops-transformer.patch
hyper_parallel/core/multicore/platform/mindspore/CMakeLists.txt
hyper_parallel/core/multicore/platform/mindspore/__init__.py
hyper_parallel/core/multicore/platform/mindspore/c_api/moe_ffn_bwd/moe_ffn_bwd_graph.cc
hyper_parallel/core/multicore/platform/mindspore/c_api/moe_ffn_bwd/moe_ffn_bwd_pynative.cc
hyper_parallel/core/multicore/platform/mindspore/c_api/moe_ffn_fwd/moe_ffn_fwd_pynative.cc
hyper_parallel/core/multicore/platform/torch/__init__.py
hyper_parallel/core/multicore/platform/torch/csrc/moe_ffn_bwd.cpp
hyper_parallel/core/multicore/platform/torch/csrc/moe_ffn_fwd.cpp
hyper_parallel/core/multicore/platform/torch/csrc/registration.cpp
hyper_parallel/core/multicore/platform/torch/setup.py
hyper_parallel/core/multicore/prebuild/multicore_moe_ffn.tar.gz
hyper_parallel/core/multicore/prebuild/multicore_moe_ffn.tar.gz.sha256
hyper_parallel/core/pipeline_parallel/__init__.py
hyper_parallel/core/pipeline_parallel/comm_compute_overlap.py
hyper_parallel/core/pipeline_parallel/hook_coordinator.py
hyper_parallel/core/pipeline_parallel/scheduler.py
hyper_parallel/core/shard/_op_dispatch.py
hyper_parallel/core/shard/ops/parallel_all_gather_matmul.py
hyper_parallel/core/shard/ops/parallel_cell_backward_hook.py
hyper_parallel/core/shard/ops/parallel_lightning_indexer.py
hyper_parallel/core/shard/ops/parallel_matmul_reduce_scatter.py
hyper_parallel/core/shard/ops/parallel_mhc_post.py
hyper_parallel/core/shard/ops/parallel_mhc_pre_sinkhorn.py
hyper_parallel/core/shard/ops/parallel_ms_flash_attention_score.py
hyper_parallel/core/shard/ops/parallel_npu_dense_lightning_indexer_grad_kl_loss.py
hyper_parallel/core/shard/ops/parallel_npu_dense_lightning_indexer_softmax_lse.py
hyper_parallel/core/shard/ops/parallel_npu_flash_attention_score.py
hyper_parallel/core/shard/ops/parallel_npu_sparse_flash_attention.py
hyper_parallel/core/shard/ops/parallel_npu_sparse_lightning_indexer_grad_kl_loss.py
hyper_parallel/core/shard/ops/parallel_one_hot_ext.py
hyper_parallel/core/shard/ops/parallel_ops.py
hyper_parallel/core/shard/ops/parallel_reshape.py
hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py
hyper_parallel/core/shard/ops/parallel_scaled_dot_product_attention.py
hyper_parallel/core/shard/ops/yaml/all_gather_matmul_ops.yaml
hyper_parallel/core/shard/ops/yaml/element_wise_ops.yaml
hyper_parallel/core/shard/ops/yaml/element_wise_ops_with_shape.yaml
hyper_parallel/core/shard/ops/yaml/lightning_indexer_ops.yaml
hyper_parallel/core/shard/ops/yaml/matmul_reduce_scatter_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_dense_lightning_indexer_grad_kl_loss_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_dense_lightning_indexer_softmax_lse_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_mhc_post_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_mhc_pre_sinkhorn_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_sparse_flash_attention_ops.yaml
hyper_parallel/core/shard/ops/yaml/npu_sparse_lightning_indexer_grad_kl_loss_ops.yaml
hyper_parallel/core/shard/ops/yaml/rotary_position_embedding_ops.yaml
hyper_parallel/core/shard/ops/yaml/squeeze.yaml
hyper_parallel/core/symmetric_memory/doc/symmetric_memory.md
hyper_parallel/core/symmetric_memory/platform/torch/torch_bindings.cpp
hyper_parallel/core/tensor_parallel/api.py
hyper_parallel/core/tensor_parallel/style.py
hyper_parallel/custom_ops/__init__.py
hyper_parallel/custom_ops/experimental/__init__.py
hyper_parallel/integration/llamafactory/utils.py
hyper_parallel/models/__init__.py
hyper_parallel/models/modules/__init__.py
hyper_parallel/models/modules/attention.py
hyper_parallel/models/modules/feed_forward.py
hyper_parallel/models/modules/linear_attention.py
hyper_parallel/models/modules/moe.py
hyper_parallel/models/modules/rmsnorm.py
hyper_parallel/models/modules/rope.py
hyper_parallel/models/qwen3_5/__init__.py
hyper_parallel/models/qwen3_5/checkpoint.py
hyper_parallel/models/qwen3_5/model.py
hyper_parallel/models/qwen3_5/parallelize.py
hyper_parallel/models/qwen3_5/state_dict.py
hyper_parallel/models/qwen3_5_moe/__init__.py
hyper_parallel/models/qwen3_5_moe/checkpoint.py
hyper_parallel/models/qwen3_5_moe/model.py
hyper_parallel/models/qwen3_5_moe/parallelize.py
hyper_parallel/models/qwen3_5_moe/state_dict.py
hyper_parallel/models/qwen3_vl_moe/__init__.py
hyper_parallel/models/qwen3_vl_moe/checkpoint.py
hyper_parallel/models/qwen3_vl_moe/model.py
hyper_parallel/models/qwen3_vl_moe/parallelize.py
hyper_parallel/models/qwen3_vl_moe/state_dict.py
hyper_parallel/models/spec/__init__.py
hyper_parallel/models/spec/model_spec.py
hyper_parallel/models/spec/registry.py
hyper_parallel/models/spec/state_dict_adapter.py
hyper_parallel/platform/mindspore/activation_checkpoint/__init__.py
hyper_parallel/platform/mindspore/activation_checkpoint/activation_swap.py
hyper_parallel/platform/mindspore/custom_ops/CMakeLists.txt
hyper_parallel/platform/mindspore/custom_ops/__init__.py
hyper_parallel/platform/mindspore/custom_ops/custom_op_impl.py
hyper_parallel/platform/mindspore/custom_ops/custom_ops.py
hyper_parallel/platform/mindspore/custom_ops/dense_lightning_indexer_grad_kl_loss.cc
hyper_parallel/platform/mindspore/custom_ops/dense_lightning_indexer_softmax_lse.cc
hyper_parallel/platform/mindspore/custom_ops/mhc_post.cc
hyper_parallel/platform/mindspore/custom_ops/mhc_post_backward.cc
hyper_parallel/platform/mindspore/custom_ops/mhc_pre_sinkhorn.cc
hyper_parallel/platform/mindspore/custom_ops/mhc_pre_sinkhorn_backward.cc
hyper_parallel/platform/mindspore/custom_ops/module.cc
hyper_parallel/platform/mindspore/custom_ops/module.h
hyper_parallel/platform/mindspore/custom_ops/sparse_lightning_indexer_grad_kl_loss.cc
hyper_parallel/platform/mindspore/fully_shard/README.md
hyper_parallel/platform/mindspore/fully_shard/README_CN.md
hyper_parallel/platform/mindspore/fully_shard/_version_utils.py
hyper_parallel/platform/mindspore/fully_shard/param.py
hyper_parallel/platform/mindspore/fully_shard/param_group.py
hyper_parallel/platform/mindspore/fully_shard/state.py
hyper_parallel/platform/mindspore/init_weights.py
hyper_parallel/platform/mindspore/multicore/__init__.py
hyper_parallel/platform/mindspore/parameter_param_info_patch.py
hyper_parallel/platform/mindspore/platform.py
hyper_parallel/platform/mindspore/utils.py
hyper_parallel/platform/platform.py
hyper_parallel/platform/torch/activation_checkpoint/__init__.py
hyper_parallel/platform/torch/activation_checkpoint/activation_swap.py
hyper_parallel/platform/torch/common/moe.py
hyper_parallel/platform/torch/custom_ops/__init__.py
hyper_parallel/platform/torch/dtensor.py
hyper_parallel/platform/torch/fully_shard/param.py
hyper_parallel/platform/torch/fully_shard/param_group.py
hyper_parallel/platform/torch/fully_shard/state.py
hyper_parallel/platform/torch/multicore/__init__.py
hyper_parallel/platform/torch/platform.py
hyper_parallel/trainer/__init__.py
hyper_parallel/trainer/base.py
hyper_parallel/trainer/callbacks/__init__.py
hyper_parallel/trainer/callbacks/base.py
hyper_parallel/trainer/config.py
hyper_parallel/trainer/llm_trainer.py
hyper_parallel/trainer/parallel_dims.py
hyper_parallel/trainer/utils/__init__.py
hyper_parallel/trainer/utils/discovery.py
hyper_parallel/trainer/utils/logging.py
hyper_parallel/trainer/utils/loss.py
hyper_parallel/trainer/vl_trainer.py
prebuild/symmetric_memory.tar.gz
prebuild/symmetric_memory.tar.gz.sha256
scripts/build_custom_ops.sh
scripts/build_multicore_local.sh
scripts/build_symmetric_memory.sh
scripts/train_lm.py
scripts/train_vl.py
setup.py
tests/mindspore/st/activation_checkpoint/swap_activation.py
tests/mindspore/st/fully_shard/_test_device_mesh_concatenate.py
tests/mindspore/st/fully_shard/_test_fully_shard_replicate_prefetch_regression.py
tests/mindspore/st/fully_shard/_tp_fully_shard_e2e.py
tests/mindspore/st/fully_shard/test_device_mesh_concatenate.py
tests/mindspore/st/fully_shard/test_fully_shard_replicate_prefetch_regression.py
tests/mindspore/st/fully_shard/test_parameter_param_info_cycle.py
tests/mindspore/st/fully_shard/test_tp_fully_shard_e2e.py
tests/mindspore/st/init_weights/test_init_weights.py
tests/mindspore/st/multicore/moe_ffn.py
tests/mindspore/st/multicore/test_moe_ffn.py
tests/mindspore/st/process_group/device_mesh.py
tests/mindspore/st/shard/ops/all_gather_matmul_shard_in_python.py
tests/mindspore/st/shard/ops/lightning_indexer_shard_in_python.py
tests/mindspore/st/shard/ops/matmul_reduce_scatter_shard_in_python.py
tests/mindspore/st/shard/ops/npu_dense_lightning_indexer_grad_kl_loss_custom_op.py
tests/mindspore/st/shard/ops/npu_dense_lightning_indexer_softmax_lse_custom_op.py
tests/mindspore/st/shard/ops/npu_mhc_post_custom_op.py
tests/mindspore/st/shard/ops/npu_mhc_pre_sinkhorn_custom_op.py
tests/mindspore/st/shard/ops/npu_sparse_flash_attention_shard_in_python.py
tests/mindspore/st/shard/ops/npu_sparse_lightning_indexer_grad_kl_loss_custom_op.py
tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py
tests/mindspore/st/shard/ops/test_all_gather_matmul_shard_in_python.py
tests/mindspore/st/shard/ops/test_lightning_indexer_shard_in_python.py
tests/mindspore/st/shard/ops/test_matmul_reduce_scatter_shard_in_python.py
tests/mindspore/st/shard/ops/test_npu_dense_lightning_indexer_grad_kl_loss_custom_op.py
tests/mindspore/st/shard/ops/test_npu_dense_lightning_indexer_softmax_lse_custom_op.py
tests/mindspore/st/shard/ops/test_npu_mhc_post_custom_op.py
tests/mindspore/st/shard/ops/test_npu_mhc_pre_sinkhorn_custom_op.py
tests/mindspore/st/shard/ops/test_npu_sparse_flash_attention_shard_in_python.py
tests/mindspore/st/shard/ops/test_npu_sparse_lightning_indexer_grad_kl_loss_custom_op.py
tests/mindspore/st/shard/ops/test_rotary_position_embedding_shard_in_python.py
tests/mindspore/st/symmetric_memory/test_symmetric_memory.py
tests/mindspore/ut/test_dtensor_set_data.py
tests/mindspore/ut/test_mindspore_patches.py
tests/torch/accuracy/README.md
tests/torch/accuracy/__init__.py
tests/torch/accuracy/_test_llama3_accuracy.py
tests/torch/accuracy/model.py
tests/torch/accuracy/parallelize.py
tests/torch/accuracy/test_llama3_accuracy.py
tests/torch/activation_checkpoint/activation_checkpoint_swap.py
tests/torch/fully_shard/_test_device_mesh_concatenate.py
tests/torch/fully_shard/_test_tp_fully_shard_e2e.py
tests/torch/fully_shard/test_device_mesh_concatenate.py
tests/torch/fully_shard/test_tp_fully_shard_e2e.py
tests/torch/llama3_examples/__init__.py
tests/torch/llama3_examples/_test_llama3_examples.py
tests/torch/llama3_examples/test_llama3_examples.py
tests/ut/conftest.py
tests/ut/core/context_parallel/__init__.py
tests/ut/core/context_parallel/test_async_context_parallel_mindspore.py
tests/ut/core/distributed_checkpoint/test_layout.py
tests/ut/core/distributed_checkpoint/test_loader.py
tests/ut/core/distributed_checkpoint/test_saver.py
tests/ut/core/dtensor/test_device_mesh_mindspore.py
tests/ut/core/dtensor/test_device_mesh_pytest.py
tests/ut/core/dtensor/test_dtensor.py
tests/ut/core/dtensor/test_dtensor_to.py
tests/ut/core/shard/ops/test_parallel_activation_with_axis.py
tests/ut/core/shard/ops/test_parallel_all_gather_matmul.py
tests/ut/core/shard/ops/test_parallel_arithmetic.py
tests/ut/core/shard/ops/test_parallel_atleast_1d.py
tests/ut/core/shard/ops/test_parallel_cell_backward_hook.py
tests/ut/core/shard/ops/test_parallel_chunk_view.py
tests/ut/core/shard/ops/test_parallel_elementwise_ops.py
tests/ut/core/shard/ops/test_parallel_gather_d.py
tests/ut/core/shard/ops/test_parallel_lightning_indexer.py
tests/ut/core/shard/ops/test_parallel_linear.py
tests/ut/core/shard/ops/test_parallel_matmul_reduce_scatter.py
tests/ut/core/shard/ops/test_parallel_mhc_post.py
tests/ut/core/shard/ops/test_parallel_mhc_pre_sinkhorn.py
tests/ut/core/shard/ops/test_parallel_npu_dense_lightning_indexer_grad_kl_loss.py
tests/ut/core/shard/ops/test_parallel_npu_dense_lightning_indexer_softmax_lse.py
tests/ut/core/shard/ops/test_parallel_npu_sparse_flash_attention.py
tests/ut/core/shard/ops/test_parallel_npu_sparse_lightning_indexer_grad_kl_loss.py
tests/ut/core/shard/ops/test_parallel_repeat.py
tests/ut/core/shard/ops/test_parallel_reshape.py
tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py
tests/ut/core/shard/ops/test_parallel_scatter.py
tests/ut/core/shard/ops/test_parallel_slice.py
tests/ut/core/shard/ops/test_parallel_sort.py
tests/ut/core/shard/ops/test_parallel_split.py
tests/ut/core/shard/ops/test_parallel_squeeze.py
tests/ut/core/shard/ops/test_parallel_stack.py
tests/ut/core/shard/ops/test_parallel_zeros_like.py
tests/ut/core/shard/test_op_dispatch.py
tests/ut/core/tensor_parallel/test_rowwise_parallel.py
tests/ut/core/test_device_mesh.py
tests/ut/platform/mindspore/__init__.py
tests/ut/platform/mindspore/_ensure_mindspore_platform.py
tests/ut/platform/mindspore/custom_ops/test_custom_op_impl.py
tests/ut/platform/mindspore/dtensor/__init__.py
tests/ut/platform/mindspore/dtensor/test_dtensor_set_data.py
tests/ut/platform/mindspore/fully_shard/__init__.py
tests/ut/platform/mindspore/fully_shard/test_fully_shard_list_api.py
tests/ut/platform/mindspore/fully_shard/test_fully_shard_register_hook.py
tests/ut/platform/mindspore/fully_shard/test_mixed_precision.py
tests/ut/platform/mindspore/fully_shard/test_pack_utils.py
tests/ut/platform/mindspore/fully_shard/test_param.py
tests/ut/platform/mindspore/fully_shard/test_scheduler.py
tests/ut/platform/mindspore/fully_shard/test_state.py
tests/ut/platform/mindspore/pipeline_parallel/__init__.py
tests/ut/platform/mindspore/pipeline_parallel/test_microbatch.py
tests/ut/platform/mindspore/test_activation_wrapper.py
tests/ut/platform/mindspore/test_autograd_compat.py
tests/ut/platform/torch/fully_shard/test_fully_shard.py
tests/ut/platform/torch/fully_shard/test_fully_shard_register_hook.py
tests/ut/platform/torch/fully_shard/test_fully_shard_state.py
[Bash: python3 .claude/skills/autogit/scripts/autogit.py pr --analyze-only 2>&1 | head -60]
Error: Uncommitted changes detected, please commit first:
  /autogit commit -m "your message"
Or manually: git add -A && git commit -m "message"
[Bash: git remote -v 2>&1]
ascend-repo	hdd@8.92.7.125:/home/hdd/bare-repo-hyper-parallel/ (fetch)
ascend-repo	hdd@8.92.7.125:/home/hdd/bare-repo-hyper-parallel/ (push)
origin	https://gitcode.com/david-he91/hyper-parallel.git (fetch)
origin	https://gitcode.com/david-he91/hyper-parallel.git (push)
upstream	https://gitcode.com/mindspore/hyper-parallel.git (fetch)
upstream	https://gitcode.com/mindspore/hyper-parallel.git (push)
[Bash: git status --short 2>&1]
?? .claude/commands/ascend-test.md
?? .claude/skills/ascend-test/
?? .sisyphus/
?? 1-torch-mindspore-virtual-stonebraker.md
?? 1.patch
?? bcba11b5a0b945fc9a1a3ccf0a50728e46746fa5.patch
?? custom_shard_issue.md
?? d_function_issue.md
?? docs/1-npu-dense-lightning-indexer-softmax-l-cheerful-yeti.md
?? docs/1-torch-mindspore-virtual-stonebraker.md
?? docs/3-commit-1-3-dense-lightning-indexer-gr-snoopy-toast.md
?? docs/ISSUE.md
?? docs/PR_description.md
?? docs/ci310_install_troubleshooting.md
?? docs/distributed_op_migration_audit_report.md
?? docs/distributed_op_migration_guide.md
?? docs/dsa_distributed_op_analysis.md
?? docs/ep_deleted_code.md
?? docs/etp.md
?? docs/hyper-parallel-ep-commit-f0fa78f686caa8f-prancy-donut.md
?? docs/issues/
?? docs/lightning_indexer_implementation_plan.md
?? docs/memoized-seeking-honey.md
?? docs/mhc/
?? docs/moe_ep_refactor_design.md
?? docs/np.md
?? docs/npu-sparse-flash-attention-torch-mindsp-wobbly-sunset.md
?? docs/npu_dense_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_dist_op.md
?? docs/npu_dense_lightning_indexer_softmax_lse_issue.md
?? docs/npu_sparse_flash_attention_dist_op.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_bsnd_cp_fix.md
?? docs/npu_sparse_lightning_indexer_grad_kl_loss_dist_op.md
?? docs/rfc-moe-parallel.md
?? docs/rfc-operator-parallel.md
?? docs/rotary_position_embedding_dist_op_plan.md
?? docs/sfa_operator_params_comparison.md
?? docs/shimmering-riding-catmull_1.md
?? docs/shimmering-riding-catmull_2.md
?? docs/shimmering-riding-catmull_3.md
?? docs/velvety-shimmying-cake.md
?? email.sh
?? expert_parallel_pr.md
?? hyper_connection.py
?? install.sh
?? npu_mhc_pre_sinkhorn_custom_op.py
?? pylintrc
?? run_ep_test.sh
?? test_npu.sh
?? test_sfa_torch.py
[Read: /root/workspace/hyper-parallel/hyper_parallel/core/shard/ops/parallel_rotary_position_embedding.py]
1	# Copyright 2026 Huawei Technologies Co., Ltd
2	#
3	# Licensed under the Apache License, Version 2.0 (the "License");
4	# you may not use this file except in compliance with the License.
5	# You may obtain a copy of the License at
6	#
7	# http://www.apache.org/licenses/LICENSE-2.0
8	#
9	# Unless required by applicable law or agreed to in writing, software
10	# distributed under the License is distributed on an "AS IS" BASIS,
11	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12	# See the License for the specific language governing permissions and
13	# limitations under the License.
14	# ============================================================================
15	"""Distributed implementation for RotaryPositionEmbedding operator."""
16	import copy
17	from typing import Optional, Tuple
18	
19	from .parallel_ops import DistributedOp
20	
21	
22	def _normalize_rpe_args(x, cos, sin, mode=0):
23	    """Normalize positional and keyword arguments into a canonical positional tuple.
24	
25	    Args:
26	        x: Input tensor.
27	        cos: Cosine position encoding tensor.
28	        sin: Sine position encoding tensor.
29	        mode: Rotation mode. 0=rotate_half, 1=rotate_interleaved, 2=quarter,
30	            3=interleave-half. Defaults to 0.
31	
32	    Returns:
33	        tuple: (positional_args_tuple, empty_kwargs_dict)
34	    """
35	    return (x, cos, sin, mode), {}
36	
37	
38	class RotaryPositionEmbeddingDistributedOp(DistributedOp):
39	    """Distributed operator for RotaryPositionEmbedding.
40	
41	    Computes rotary position embedding element-wise:
42	        y = x * cos + x_rotate * sin
43	
44	    where x_rotate is obtained by rotating within the last (D) dimension.
45	    Output shape equals x shape exactly.
46	
47	    Sharding constraints:
48	      - D (last dim) must be replicated for x, cos, and sin: the kernel rotates
49	        within D and the operation is indivisible along that axis.
50	      - B, N, S dims are fully independent across positions and can be freely
51	        sharded.
52	      - cos/sin may have any subset of non-D dims replicated (broadcast case),
53	        but if cos/sin is sharded on a dimension, it must match x's sharding
54	        on that dimension.
55	
56	    MODE does not affect layout inference: all modes produce output shape == x
57	    shape and leave B/N/S independence unchanged. MODE is passed through as a
58	    kernel parameter.
59	
60	    Output:
61	      Single tensor with the same shape and layout as x.
62	    """
63	
64	    @staticmethod
65	    def _validate_input_layouts(x_layout, cos_layout, sin_layout) -> None:
66	        """Validate sharding constraints for all input tensors.
67	
68	        Rules (applied to both 4-D BNSD/BSND/SBND and 3-D TND layouts):
69	          - x's last dim (D) must be replicated.
70	          - cos and sin's last dim (D) must be replicated.
71	          - For any non-D dimension d: if cos/sin is sharded there, the mesh
72	            axis must equal x's mesh axis on the same dimension.
73	
74	        Args:
75	            x_layout: Layout of the x tensor.
76	            cos_layout: Layout of the cos tensor.
77	            sin_layout: Layout of the sin tensor.
78	
79	        Raises:
80	            ValueError: If D is sharded for any input, or if cos/sin sharding
81	                is inconsistent with x on any non-D dimension.
82	        """
83	        op = "rotary_position_embedding"
84	        x_tm = x_layout.tensor_map
85	
86	        if x_tm[-1] != -1:
87	            raise ValueError(
88	                f"For {op}, D (last dim) of x must be replicated, "
89	                f"but got tensor_map={x_tm}"
90	            )
91	
92	        for name, layout in [('cos', cos_layout), ('sin', sin_layout)]:
93	            tm = layout.tensor_map
94	            if tm[-1] != -1:
95	                raise ValueError(
96	                    f"For {op}, D (last dim) of {name} must be replicated, "
97	                    f"but got tensor_map={tm}"
98	                )
99	            for d in range(len(tm) - 1):
100	                x_d = x_tm[d] if d < len(x_tm) - 1 else -1
101	                if tm[d] != -1 and tm[d] != x_d:
102	                    raise ValueError(
103	                        f"For {op}, {name} sharding on dim {d} must match x or be replicated, "
104	                        f"but got x={x_d}, {name}={tm[d]}"
105	                    )
106	
107	    def preprocess(self, args: tuple, kwargs: dict) -> Optional[tuple]:
108	        """Extract local tensors and build the layout cache.
109	
110	        All inputs (x, cos, sin) are expected to be DTensors.
111	
112	        Args:
113	            args: Positional arguments, may include DTensors.
114	            kwargs: Keyword arguments.
115	
116	        Returns:
117	            tuple: (local_args, local_kwargs, cache_values) where
118	                local_args = (x_local, cos_local, sin_local, mode),
119	                local_kwargs = {},
120	                cache_values = [x_layout, cos_layout, sin_layout].
121	        """
122	        norm_args, _ = _normalize_rpe_args(*args, **kwargs)
123	        x = norm_args[0]
124	        cos = norm_args[1]
125	        sin = norm_args[2]
126	        mode = norm_args[3]
127	
128	        local_args = (x.to_local(), cos.to_local(), sin.to_local(), mode)
129	        cache_values = [x.layout, cos.layout, sin.layout]
130	        return local_args, {}, cache_values
131	
132	    def infer_layout(self, cache_values: list) -> Tuple[tuple, None]:
133	        """Infer output layout for the single output tensor.
134	
135	        Rules:
136	            1. Partial inputs are rejected.
137	            2. D (last dim) must be replicated for x, cos, and sin.
138	            3. cos/sin sharding on non-D dims must match x or be replicated.
139	            4. Output layout = deep copy of x_layout (output shape == x shape).
140	
141	        Args:
142	            cache_values: [x_layout, cos_layout, sin_layout]
143	
144	        Returns:
145	            tuple: ((output_layout,), None)
146	
147	        Raises:
148	            ValueError: If any input has Partial status, D is sharded,
149	                or cos/sin sharding is inconsistent with x.
150	        """
151	        x_layout = cache_values[0]
152	        cos_layout = cache_values[1]
153	        sin_layout = cache_values[2]
154	
155	        self._check_partial_inputs([x_layout, cos_layout, sin_layout])
156	        self._validate_input_layouts(x_layout, cos_layout, sin_layout)
157	        return (copy.deepcopy(x_layout),), None
158	
[Read: /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py]
1	# Copyright 2026 Huawei Technologies Co., Ltd
2	#
3	# Licensed under the Apache License, Version 2.0 (the "License");
4	# you may not use this file except in compliance with the License.
5	# You may obtain a copy of the License at
6	#
7	# http://www.apache.org/licenses/LICENSE-2.0
8	#
9	# Unless required by applicable law or agreed to in writing, software
10	# distributed under the License is distributed on an "AS IS" BASIS,
11	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12	# See the License for the specific language governing permissions and
13	# limitations under the License.
14	# ============================================================================
15	"""Unit tests for RotaryPositionEmbeddingDistributedOp."""
16	import os
17	import unittest
18	from unittest.mock import MagicMock, patch
19	
20	import numpy as np
21	
22	os.environ["HYPER_PARALLEL_PLATFORM"] = "torch"
23	
24	from hyper_parallel.core.dtensor.dtensor import _build_layout, _LAYOUT_CACHE
25	from hyper_parallel.core.dtensor.placement_types import Shard, Replicate
26	from hyper_parallel.core.shard.ops.parallel_rotary_position_embedding import (
27	    RotaryPositionEmbeddingDistributedOp,
28	    _normalize_rpe_args,
29	)
30	from hyper_parallel.core.shard.ops.parallel_ops_register import get_distributed_op
31	from hyper_parallel.core.dtensor.device_mesh import init_device_mesh, _DEVICE_MESH_MAP
32	from hyper_parallel.platform.platform import EXISTING_COMM_GROUPS
33	
34	
35	class TestNormalizeRpeArgs(unittest.TestCase):
36	    """Unit tests for _normalize_rpe_args."""
37	
38	    def test_three_positional_args_mode_defaults_to_zero_1(self):
39	        """
40	        Feature: _normalize_rpe_args fills in default mode=0.
41	        Description: Call with only x, cos, sin positional args.
42	        Expectation: args == (x, cos, sin, 0), kwargs == {}.
43	        """
44	        x, cos, sin = object(), object(), object()
45	        args, kwargs = _normalize_rpe_args(x, cos, sin)
46	        self.assertIs(args[0], x, msg=f"args[0] should be x, got {args[0]}")
47	        self.assertIs(args[1], cos, msg=f"args[1] should be cos, got {args[1]}")
48	        self.assertIs(args[2], sin, msg=f"args[2] should be sin, got {args[2]}")
49	        self.assertEqual(args[3], 0, msg=f"default mode should be 0, got {args[3]}")
50	        self.assertEqual(kwargs, {}, msg=f"kwargs should be empty, got {kwargs}")
[Bash: grep -c "def test_" /root/workspace/hyper-parallel/tests/ut/core/shard/ops/test_parallel_rotary_position_embedding.py]
22
[Bash: grep -n "def test_" /root/workspace/hyper-parallel/tests/mindspore/st/shard/ops/rotary_position_embedding_shard_in_python.py]
204:def test_rpe_replicated():
227:def test_rpe_dp_b():
256:def test_rpe_tp_n():
289:def test_rpe_dp_tp():
319:def test_rpe_dp_sp():
343:def test_rpe_tp_sp():
367:def test_rpe_dp_tp_cos_full():
396:def test_rpe_dp_tp_sp():
[Bash: grep -n "issue\|ISSUE\|gitcode\|api\|token" /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/autogit.py 2>/dev/null | head -40]
(Bash completed with no output)
[Bash: grep -n "def create\|issue\|GITCODE_TOKEN\|api_url\|project_id" /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/commands.py 2>/dev/null ]
69:            "  Linux/macOS: export GITCODE_TOKEN=<your-token>\n"
70:            "  Windows CMD: set GITCODE_TOKEN=<your-token>\n"
71:            "  Windows PowerShell: $env:GITCODE_TOKEN=\"<your-token>\"\n\n"
1527:  export GITCODE_TOKEN=<your-token>
[Bash: grep -n "def create_pr\|def create_issue\|def _create\|def _api\|/issues\|/merge_requests\|api/v" /root/workspace/hyper-parallel/.claude/skills/autogi]
(Bash completed with no output)
[Bash: ls /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/]
__pycache__
api.py
autogit.py
code_style_guard.py
commands.py
commit_msg_check.py
diff_analysis.py
git_utils.py
lint_check.py
models.py
pr_content.py
[Bash: grep -n "issue\|/issues\|create_issue\|def " /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/api.py | head -60]
32:def get_token() -> Optional[str]:
65:def api_request(method: str, endpoint: str, token: str,
98:def get_pr_info(owner: str, repo: str, pr_number: int,
114:def get_pr_commits(owner: str, repo: str, pr_number: int,
130:def get_pr_files(owner: str, repo: str, pr_number: int,
146:def get_pr_stats(owner: str, repo: str, pr_number: int,
178:def add_reviewers(owner: str, repo: str, pr_number: int, token: str,
200:def get_pr_status_display(owner: str, repo: str, pr_number: int,
267:def create_pr(owner: str, repo: str, token: str, title: str, body: str,
302:def update_pr_description(owner: str, repo: str, pr_number: int, token: str,
[Bash: grep -n "BASE_API\|gitcode.com\|api_request" /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/api.py | head -20]
65:def api_request(method: str, endpoint: str, token: str,
111:    return api_request("GET", f"/repos/{owner}/{repo}/pulls/{pr_number}", token)
127:    return api_request("GET", f"/repos/{owner}/{repo}/pulls/{pr_number}/commits", token)
143:    return api_request("GET", f"/repos/{owner}/{repo}/pulls/{pr_number}/files", token)
193:    return api_request(
263:    output += f"\nhttps://gitcode.com/{owner}/{repo}/pull/{pr_number}\n"
293:    status, result = api_request("POST", f"/repos/{owner}/{repo}/pulls", token, data)
298:            result["html_url"] = f"https://gitcode.com/{owner}/{repo}/pull/{pr_number}"
318:    return api_request("PATCH", f"/repos/{owner}/{repo}/pulls/{pr_number}", token, data)
[Read: /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/api.py]
1	#!/usr/bin/env python3
2	# Copyright 2026 Huawei Technologies Co., Ltd
3	#
4	# Licensed under the Apache License, Version 2.0 (the "License");
5	# you may not use this file except in compliance with the License.
6	# You may obtain a copy of the License at
7	#
8	# http://www.apache.org/licenses/LICENSE-2.0
9	#
10	# Unless required by applicable law or agreed to in writing, software
11	# distributed under the License is distributed on an "AS IS" BASIS,
12	# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13	# See the License for the specific language governing permissions and
14	# limitations under the License.
15	# ============================================================================
16	"""Token management and GitCode HTTP API operations for AutoGit."""
17	
18	import json
19	import os
20	import subprocess
21	import urllib.error
22	import urllib.request
23	from typing import Any, Dict, List, Optional, Tuple
24	
25	from models import CREDENTIAL_HOST, GITCODE_API_BASE
26	
27	
28	# ============================================================================
29	# Token Management
30	# ============================================================================
31	
32	def get_token() -> Optional[str]:
33	    """Get the GitCode API token from environment or git credentials.
34	
35	    Checks ``GITCODE_TOKEN`` environment variable first, then falls back
36	    to ``git credential fill``.
37	
38	    Returns:
39	        Token string, or None if not found.
40	    """
41	    token = os.environ.get("GITCODE_TOKEN")
42	    if token:
43	        return token
44	
45	    try:
46	        proc = subprocess.run(
47	            ["git", "credential", "fill"],
48	            input=f"protocol=https\nhost={CREDENTIAL_HOST}\n",
49	            capture_output=True, text=True, timeout=10,
50	            check=False
51	        )
52	        if proc.returncode == 0:
53	            for line in proc.stdout.strip().split("\n"):
54	                if line.startswith("password="):
55	                    return line.split("=", 1)[1]
56	    except Exception:  # pylint: disable=broad-except
57	        pass
58	    return None
59	
60	
61	# ============================================================================
62	# GitCode API
63	# ============================================================================
64	
65	def api_request(method: str, endpoint: str, token: str,
66	                data: Optional[Dict] = None) -> Tuple[int, Any]:
67	    """Send an HTTP request to the GitCode API.
68	
69	    Args:
70	        method: HTTP method (GET, POST, PATCH, etc.).
71	        endpoint: API endpoint path (appended to GITCODE_API_BASE).
72	        token: Bearer token for authorization.
73	        data: Optional JSON-serializable request body.
74	
75	    Returns:
76	        Tuple of (HTTP status code, parsed JSON response).
77	    """
78	    url = f"{GITCODE_API_BASE}{endpoint}"
79	    headers = {
80	        "Content-Type": "application/json",
81	        "Authorization": f"Bearer {token}",
82	    }
83	    body = json.dumps(data).encode("utf-8") if data else None
84	    req = urllib.request.Request(url, data=body, headers=headers, method=method)
85	
86	    try:
87	        with urllib.request.urlopen(req, timeout=30) as resp:
88	            return resp.status, json.loads(resp.read().decode("utf-8"))
89	    except urllib.error.HTTPError as e:
90	        try:
91	            return e.code, json.loads(e.read().decode("utf-8"))
92	        except Exception:  # pylint: disable=broad-except
93	            return e.code, {"error": str(e)}
94	    except Exception as e:  # pylint: disable=broad-except
95	        return 0, {"error": str(e)}
96	
97	
98	def get_pr_info(owner: str, repo: str, pr_number: int,
99	                token: str) -> Tuple[int, Any]:
100	    """Get PR information from GitCode.
[Bash: grep -n "GITCODE_API_BASE\|CREDENTIAL_HOST" /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/models.py]
27:GITCODE_API_BASE = "https://api.gitcode.com/api/v5"
28:CREDENTIAL_HOST = "api.gitcode.com"
[Bash: echo $GITCODE_TOKEN | head -c 10]
G3WanUqctM
[Bash: git log origin/master_dist_op..HEAD --oneline 2>&1 || echo "branch not on origin"]
1c7d6e9 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b !656 feat: add distributed ops AllGatherMatmul and MatmulReduceScatter (MC2)
749d780 !657 bugfix: add CMake pre-build support for mindspore custom_ops
93cdeda feat: add CMake pre-build support for mindspore custom_ops
aa5c8fb feat: add distributed ops all_gather_matmul and matmul_reduce_scatter
cecf192 !588 merge master_dfunction_dsa into master
47233b8 feat: add distributed op npu_dense_lightning_indexer_softmax_lse, npu_dense_lightning_indexer_grad_kl_loss_dist_op, npu_sparse_lightning_indexer_grad_kl_loss_dist_op, npu_mhc_post & npu_mhc_pre_sinkhorn
d84aa1a !648 feat: add dist op InplaceFillScalar & InplaceFillTensor
[Bash: git log --oneline -5 2>&1]
1c7d6e9 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b !656 feat: add distributed ops AllGatherMatmul and MatmulReduceScatter (MC2)
749d780 !657 bugfix: add CMake pre-build support for mindspore custom_ops
93cdeda feat: add CMake pre-build support for mindspore custom_ops
aa5c8fb feat: add distributed ops all_gather_matmul and matmul_reduce_scatter
[Bash: git log --oneline 2>&1 | head -10]
1c7d6e9 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b !656 feat: add distributed ops AllGatherMatmul and MatmulReduceScatter (MC2)
749d780 !657 bugfix: add CMake pre-build support for mindspore custom_ops
93cdeda feat: add CMake pre-build support for mindspore custom_ops
aa5c8fb feat: add distributed ops all_gather_matmul and matmul_reduce_scatter
cecf192 !588 merge master_dfunction_dsa into master
47233b8 feat: add distributed op npu_dense_lightning_indexer_softmax_lse, npu_dense_lightning_indexer_grad_kl_loss_dist_op, npu_sparse_lightning_indexer_grad_kl_loss_dist_op, npu_mhc_post & npu_mhc_pre_sinkhorn
d84aa1a !648 feat: add dist op InplaceFillScalar & InplaceFillTensor
a914165 feat: add dist op InplaceFillScalar & InplaceFillTensor
89f023b !645 fix(pynative): make DeviceMesh / fully_shard robust under TP+EP+FSDP
[Bash: git branch --show-current && git log --oneline HEAD~3..HEAD]
master_dist_op
1c7d6e9 feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b !656 feat: add distributed ops AllGatherMatmul and MatmulReduceScatter (MC2)
749d780 !657 bugfix: add CMake pre-build support for mindspore custom_ops
93cdeda feat: add CMake pre-build support for mindspore custom_ops
aa5c8fb feat: add distributed ops all_gather_matmul and matmul_reduce_scatter
[Bash: git reflog | head -15]
1c7d6e9 HEAD@{0}: rebase (finish): returning to refs/heads/master_dist_op
1c7d6e9 HEAD@{1}: rebase (squash): feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
583a333 HEAD@{2}: rebase (squash): # This is a combination of 3 commits.
90fdc93 HEAD@{3}: rebase (squash): # This is a combination of 2 commits.
244a8d0 HEAD@{4}: rebase (start): checkout 51c236bd893d04e7d4325c38d1682b062ab5b78d
01f122f HEAD@{5}: commit: test: fix test_rpe_dp_tp mode=1 tiling failure, switch to mode=0
574a74b HEAD@{6}: commit: fix: RPE ST — split fwd/fwd+bwd standalone, restrict mode=2/3 to fwd-only tests
a7add13 HEAD@{7}: commit: refactor: improve RPE ST tests — multi-mode, _get_grad_placements bwd, tighten tol to 1e-3
244a8d0 HEAD@{8}: commit: feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
51c236b HEAD@{9}: rebase (finish): returning to refs/heads/master_dist_op
51c236b HEAD@{10}: rebase (start): checkout upstream/master
a914165 HEAD@{11}: checkout: moving from master_custom_op_cmake to master_dist_op
93cdeda HEAD@{12}: commit (amend): feat: add CMake pre-build support for mindspore custom_ops
c7aadcd HEAD@{13}: commit (amend): feat: add CMake pre-build support for mindspore custom_ops
0cc6224 HEAD@{14}: checkout: moving from master_dist_op_mc2 to master_custom_op_cmake
[Bash: git show --stat 1c7d6e9 2>&1]
commit 1c7d6e93df8fabcc59c40015ce43fde5bae43854
Author: david-he91 <hedongdong@huawei.com>
Date:   Tue May 19 10:29:49 2026 +0800

    feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST

 .../ops/parallel_rotary_position_embedding.py      | 157 +++++++
 .../ops/yaml/rotary_position_embedding_ops.yaml    |   4 +
 .../rotary_position_embedding_shard_in_python.py   | 418 +++++++++++++++++
 ...st_rotary_position_embedding_shard_in_python.py |  91 ++++
 .../ops/test_parallel_rotary_position_embedding.py | 507 +++++++++++++++++++++
 5 files changed, 1177 insertions(+)
[Bash: git push origin master_dist_op -f 2>&1]
remote: Start Git Hooks Checking 					[PASSED]        
remote: 
remote: To create a merge request for master_dist_op, visit:        
remote:   https://gitcode.com/david-he91/hyper-parallel/merge_requests/new?source_branch=master_dist_op        
remote: 
To https://gitcode.com/david-he91/hyper-parallel.git
   a914165..1c7d6e9  master_dist_op -> master_dist_op
[Bash: python3 -c " import sys sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from git_utils import get_upstream_repo_in]
Exit code 1
Traceback (most recent call last):
  File "<string>", line 4, in <module>
ImportError: cannot import name 'get_upstream_repo_info' from 'git_utils' (/root/workspace/hyper-parallel/.claude/skills/autogit/scripts/git_utils.py)
[Bash: python3 -c " import sys sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') import git_utils print([x for x in dir(git]
['get_upstream_default_branch']
[Bash: # upstream owner/repo 从 remote URL 解析 git remote get-url upstream 2>&1]
https://gitcode.com/mindspore/hyper-parallel.git
[Bash: GITCODE_TOKEN=$(python3 -c " import sys sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import get_token ]
Token obtained: 24 chars
[Bash: python3 << 'EOF' import sys, json sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import api_request, get]
Status: 200
Issue #: 155
URL: https://gitcode.com/mindspore/hyper-parallel/issues/155
[Bash: python3 << 'EOF' import sys, json sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import api_request, get]
Status: 200
PR #: 1
URL: https://gitcode.com/mindspore/hyper-parallel/pull/1
[Read: /root/workspace/hyper-parallel/.claude/skills/autogit/scripts/api.py]
267	def create_pr(owner: str, repo: str, token: str, title: str, body: str,
268	              head: str, base: str, fork_owner: str,
269	              fork_repo: str) -> Tuple[int, Any]:
270	    """Create a PR on GitCode.
271	
272	    Args:
273	        owner: Upstream repository owner.
274	        repo: Upstream repository name.
275	        token: API token.
276	        title: PR title.
277	        body: PR description body.
278	        head: Head branch reference (e.g. 'fork_owner:branch').
279	        base: Target branch name.
280	        fork_owner: Fork repository owner.
281	        fork_repo: Fork repository name.
282	
283	    Returns:
284	        Tuple of (status_code, response_data).
285	    """
286	    data = {
287	        "title": title,
288	        "body": body,
289	        "head": head,
290	        "base": base,
291	        "fork_path": f"{fork_owner}/{fork_repo}"
292	    }
293	    status, result = api_request("POST", f"/repos/{owner}/{repo}/pulls", token, data)
294	
295	    if status in [200, 201] and isinstance(result, dict):
296	        pr_number = result.get("number") or result.get("iid")
297	        if pr_number:
298	            result["html_url"] = f"https://gitcode.com/{owner}/{repo}/pull/{pr_number}"
299	    return status, result
300	
301	
302	def update_pr_description(owner: str, repo: str, pr_number: int, token: str,
303	                          title: str, body: str) -> Tuple[int, Any]:
304	    """Update a PR title and description.
305	
306	    Args:
307	        owner: Repository owner.
308	        repo: Repository name.
309	        pr_number: Pull request number.
310	        token: API token.
311	        title: New PR title.
312	        body: New PR description body.
313	
314	    Returns:
315	        Tuple of (status_code, response_data).
316	    """
[Bash: python3 << 'EOF' import sys, json sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import create_pr, get_t]
Status: 400
Error: {
  "error_code": 404,
  "error_code_name": "UN_KNOW",
  "error_message": "Can not find the branch: master_dist_op in project: hyper-parallel",
  "trace_id": "eea6d42503b32a2e6d5137b3ee1d0aec"
}
[Bash: python3 << 'EOF' import sys, json sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import create_pr, get_t]
Status: 200
PR #: 661
URL: https://gitcode.com/mindspore/hyper-parallel/pull/661
[Bash: python3 << 'EOF' import sys, json sys.path.insert(0, '/root/workspace/hyper-parallel/.claude/skills/autogit/scripts') from api import api_request, get]
Status: 200
ISSUE #155 updated successfully

Running AutoGit pr

先读取 PR 和 ISSUE 模板文件。

先分析当前分支的 commits 和改动文件。

先运行 pr --analyze-only 获取分支分析,再确认上游 remote 信息。

untracked 文件是预先存在的与本次无关的文件,导致 autogit 检测失败。我来读取 RPE 实现文件,直接生成 PR 和 ISSUE 内容。

检查当前分支是否已推送到 origin(fork)。

所有 RPE 改动已在 1c7d6e9 squash commit 中,现在推送到 origin 分叉。

现在生成 ISSUE 和 PR 内容,先创建 ISSUE 获取编号,再创建 PR。

ISSUE 预览:


标题: feat: 接入 RotaryPositionEmbedding 算子分布式调度支持

内容:

## 背景

在 Tensor Parallelism(TP)/ 数据并行等分布式训练场景中,RotaryPositionEmbedding(RPE)是 Transformer 模型中广泛使用的位置编码算子(公式:y = x * cos + x_rotate * sin)。HyperParallel 当前缺少 RPE 的分布式算子调度实现:使用 DTensor 对象调用时无法推断输出 DTensor 的分布状态,下游算子无法正确组合分布式计算图。

## 目标

为 RotaryPositionEmbedding 提供分布式调度支持...(见下方完整版)

PR 标题: feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST


在展示完整版并创建前,先确认上游仓库的 owner/repo:

Token 已就绪,现在创建 ISSUE(在上游仓库 mindspore/hyper-parallel):

ISSUE #155 创建成功!现在创建 PR,引用 ISSUE #155:

需要用正确的 fork_path 参数创建跨 fork PR。让我重新创建:

head 需要带 fork 所有者前缀格式。

PR #661 创建成功!现在更新 ISSUE #155 的相关 PR 链接:

全部完成。汇总如下:


ISSUE #155https://gitcode.com/mindspore/hyper-parallel/issues/155

  • 标题:feat: 接入 RotaryPositionEmbedding 算子分布式调度支持
  • 描述了背景、目标、8 种分片场景、约束表、UT/ST 覆盖,已回填 相关 PR #661

PR #661https://gitcode.com/mindspore/hyper-parallel/pull/661

  • 标题:feat: add distributed op RotaryPositionEmbedding with UT and MindSpore ST
  • 类型:/kind feature
  • 包含:分片规则表、UT/ST 测试覆盖表、Ascend 910B 验证结果(22 UT + 8 ST 全通过,float16 atol/rtol=1e-3)
  • Fixes #155;Self-checklist 保持原格式不变(设计/测试/验证 ✓,接口/文档 未勾)

System

RotaryPositionEmbedding 分布式算子开发和 ST 验证已全部完成,所有 4 组测试(2/4/8 卡)在 Ascend 910B 通过,ISSUE #155 和 PR #661 已创建。无待处理事项。 (disable recaps in /config)


User · 2026-05-19T04:06:12.457Z

/export RotaryPositionEmbedding_claude_session.md


System

RotaryPositionEmbedding 分布式算子已开发完成并通过全部 ST 验证(4 组共 8 个用例),ISSUE #155 和 PR #661 已创建。任务完成,无待处理事项。 (disable recaps in /config)