使用 pyasc 获取 GlobalTensor 元素个数:`get_size` 接口解析与实战指南
2026/9/19 11:50:14 网站建设 项目流程

使用 pyasc 获取 GlobalTensor 元素个数:get_size接口解析与实战指南

【免费下载链接】pyasc本项目为Python用户提供算子编程接口,支持在昇腾AI处理器上加速计算,接口与Ascend C一一对应并遵守Python原生语法。项目地址: https://gitcode.com/cann/pyasc

在 CANN pyasc 项目中,asc.language.core.GlobalTensor是面向 Python 开发者、用于承载昇腾 AI 处理器 Global Memory(全局存储)数据的核心 Tensor 类型,其全部成员函数与 Ascend C 的GlobalTensor接口一一对应。本篇指南以 GlobalTensor.get_size 文档为主线,系统讲解该接口的语义、底层实现、初始化前提、约束限制及实际算子中的典型用法。阅读完本文后,你将掌握如何在@asc.jit算子内核中正确获取全局 Tensor 的元素个数,并能区分get_sizeget_shape_infoset_global_buffer之间的关系,避免常见误用。

接口总览:GlobalTensor.get_size()的定位

函数签名与语义

get_sizeGlobalTensor的成员方法,用于获取 GlobalTensor 的元素个数(element count),而非字节数。其 Python 侧签名如下:

GlobalTensor.get_size() → int
  • 参数:无。
  • 返回值GlobalTensor的元素个数,类型为int(在内核编译期对应 64 位无符号整数uint64_t)。
  • 对应 Ascend C 函数原型
__aicore__ inline uint64_t GetSize() const

从 C++ 原型可以看出,该接口在设备侧(AI Core)以内联函数形式实现,返回uint64_t,与 Python 侧int语义一致。

在 pyasc 中,GlobalTensor位于 python/asc/language/core/tensor.py,与LocalTensor(Local Memory 数据)形成对照:GlobalTensor专门存放全局数据,类型T支持基础数据类型以及TensorTrait类型,但需遵循使用该GlobalTensor的指令(如data_copy、向量运算等)的数据类型支持情况。

LocalTensor.get_size的区别

pyasc 中LocalTensor同样提供get_size方法(见 LocalTensor.get_size 文档),但二者有本质区别:

对比项GlobalTensor.get_sizeLocalTensor.get_size
存储位置Global Memory(外部存储)Local Memory(AI Core 内部存储)
返回值语义元素个数当前 Size 大小,单位为元素
返回类型uint64_tuint32_t
对应 Ascend C 原型__aicore__ inline uint64_t GetSize() const__aicore__ inline uint32_t GetSize() const
初始化前提需先通过set_global_buffer传入全局数据地址通过 TQue / LocalMemAllocator 等方式获得

值得注意的是,二者返回的都是元素个数而非字节数;若需字节数,应结合元素个数与dtype的字节宽度自行换算,或参考get_phy_addr、shape 信息等辅助接口。

编译链路:从 Python API 到 Ascend C 代码生成

get_size的调用在 pyasc 中并不是简单的函数调用,而是经过一层 IR(中间表示)的建图与代码生成。从源码结构看,其完整链路如下:

  1. Python 侧 API 定义:在 python/asc/language/core/tensor.py 中,get_size@require_jit@set_tensor_docstring(tensor_name="GlobalTensor", api_name="get_size")装饰,表明它必须在 JIT 编译上下文中使用,且其 docstring 由文档生成机制统一注入:
@require_jit @set_tensor_docstring(tensor_name="GlobalTensor", api_name="get_size") def get_size(self) -> RuntimeInt: if self.shape is None: builder = global_builder.get_ir_builder() handle = builder.create_asc_GlobalTensorGetSizeOp(builder.get_ui64_type(), self.to_ir()) return PlainValue(handle) return math.prod(self.shape)
  1. IR 建图:当GlobalTensor未显式设置 shape 时(self.shape is None),调用builder.create_asc_GlobalTensorGetSizeOp创建asc.global_tensor.get_size算子节点,结果类型为ui64。这一 Op 在 TableGen 定义中声明为对 Ascend CGlobalTensor::GetSize方法的调用,见 include/ascir/Dialect/Asc/IR/Core/Tensor.td:
def AscendC_GlobalTensorGetSizeOp : APIOp<"global_tensor.get_size", "GetSize", [AscMemberFunc]> { let summary = "Call `AscendC::GlobalTensor::GetSize` method"; let arguments = (ins AscendC_GlobalTensor:$tensor); let results = (outs UI64:$value); }
  1. 代码生成:随后由代码发射器(Emit)将 IR 转换为最终的内核 C++ 代码(即文档中给出的__aicore__ inline uint64_t GetSize() const调用形式)。

一个值得注意的编译期优化:在 python/asc/language/core/tensor.py 的实现中,若GlobalTensor已经具备 shape 信息(self.shape非空),get_size会直接返回math.prod(self.shape)——即各维度之积,而不再生成任何 IR 节点。这意味着 shape 已知时,元素个数可以在编译期常量折叠,降低运行时开销。这也解释了为何get_shape_info文档中强调"Shape 信息没有默认值,只有通过SetShapeInfo设置过 Shape 信息后,才可以调用该接口获取正确的 ShapeInfo"(见 GlobalTensor.get_shape_info 文档)。

初始化前提:set_global_buffer与元素个数的来源

get_size返回的元素个数来源于初始化时通过set_global_buffer传入的buffer_sizeset_global_buffer的完整签名如下(见 GlobalTensor.set_global_buffer 文档):

GlobalTensor.set_global_buffer(buffer: GlobalAddress | None = None) → None GlobalTensor.set_global_buffer(buffer: GlobalAddress | None = None, buffer_size: int | None = None) → None
  • buffer:Host 侧传入的全局数据指针,即GlobalAddress,对应 Ascend C 的__gm__ PrimType* buffer
  • buffer_size:GlobalTensor 所包含的类型为PrimType的数据个数,需自行保证不会超出实际数据的长度,对应 Ascend C 的uint64_t bufferSize

set_global_buffer对应的两个 Ascend C 重载原型为:

__aicore__ inline void SetGlobalBuffer(__gm__ PrimType* buffer, uint64_t bufferSize) __aicore__ inline void SetGlobalBuffer(__gm__ PrimType* buffer)

在 Python 实现中(python/asc/language/core/tensor.py),若buffer为空或缺少数据类型会抛出ValueError;传入buffer_size时生成带尺寸的GlobalTensorSetGlobalBufferOp,否则生成不带尺寸的版本。从源码结构看,get_size返回的元素个数正是基于此buffer_size维护的运行时信息。

关键约束:仅传入指针时元素个数为 0

原文档明确给出的约束是:

使用仅传入全局数据指针的set_global_buffer接口对GlobalTensor进行初始化,通过本接口获取到的元素个数为 0。

即如果只调用set_global_buffer(x)(不带buffer_size),后续get_size()返回 0,因为此时并没有记录元素个数的信息。因此,凡是后续需要依赖元素个数(如作为data_copy的拷贝长度、循环边界等)的场景,必须使用带buffer_sizeset_global_buffer(x, size)形式完成初始化

实战示例:在内核中获取并利用全局元素个数

标准用法:显式传入 buffer_size

参考set_global_buffer文档中的调用示例,以及 python/test/unit/language/core/test_global_tensor.py 中的单元测试,标准写法如下:

import asc @asc.jit def kernel_get_size(x: asc.GlobalAddress) -> None: x_gm = asc.GlobalTensor() x_gm.set_global_buffer(x, 8192) # 显式声明元素个数 x_size = x_gm.get_size() # 返回 8192

get_size与数据搬运结合,即可安全地驱动全局到局部的拷贝:

data_size = 256 input_global = asc.GlobalTensor() input_global.set_global_buffer(src_gm, data_size) input_local = in_queue_x.alloc_tensor(asc.int32) asc.data_copy(input_local, input_global, data_size)

此处input_global.get_size()data_size语义一致(元素个数),可以作为data_copy长度的动态来源,从而避免硬编码。

完整的内核骨架

结合 pyasc 的 JIT 框架,一个可运行的内核骨架如下(示意结构,省略队列初始化细节):

import asc @asc.jit def add_kernel(x: asc.GlobalAddress, y: asc.GlobalAddress, z: asc.GlobalAddress, size: asc.int32) -> None: x_gm = asc.GlobalTensor() x_gm.set_global_buffer(x, size) y_gm = asc.GlobalTensor() y_gm.set_global_buffer(y, size) z_gm = asc.GlobalTensor() z_gm.set_global_buffer(z, size) # 使用 get_size 获取元素个数,驱动搬运与循环 total = x_gm.get_size() # 通过 TQue 申请 LocalTensor 并执行数据拷贝、向量计算 # (具体队列/内存管理方式请参考 examples/ 目录下的完整算子示例)

更多可直接运行的端到端示例可参考仓库 examples 目录下的算子实现,例如 01_add/add.py 演示了完整的@asc.jit内核、Host 侧数据准备与 launch 流程。

单元测试验证

仓库中已有针对get_size的单元测试(python/test/unit/language/core/test_global_tensor.py):

def test_get_size(mock_launcher_run): @asc.jit def kernel_get_size(x: asc.GlobalAddress) -> None: x_gm = asc.GlobalTensor() x_gm.set_global_buffer(x) x_size = x_gm.get_size() data = MockTensor(asc.float32) kernel_get_size1 assert mock_launcher_run.call_count == 1

该测试在config.set_platform(config.Backend.Model, check=False)的 Model 平台下运行,使用MockTensor模拟输入,验证内核可以正常编译、建图并 launch。注意此用例演示的是不带buffer_size的初始化路径(对应"元素个数为 0"的约束场景),用于验证接口可用性;实际业务代码中应根据上述约束显式传入尺寸。

常见误用与注意事项

  1. 误以为返回字节数get_size返回元素个数。若需字节数,需乘以dtype的字节宽度,例如asc.float32为 4 字节。
  2. 漏传buffer_size导致返回 0:仅调用set_global_buffer(x)时,get_size()返回 0,无法用于数据拷贝长度或循环边界;务必使用set_global_buffer(x, size)
  3. buffer_size超出实际数据长度:文档明确要求"需自行保证不会超出实际数据的长度",越界访问可能导致未定义行为,需在 Host 侧确保尺寸正确。
  4. get_shape_info混淆get_size返回元素个数(标量),get_shape_info返回ShapeInfo对象(维度、原始 shape、data_format 等结构信息)。且 shape 信息没有默认值,必须先set_shape_info才能获得正确结果;而get_size在 shape 已知时(self.shape非空)会直接做编译期常量折叠。
  5. 返回值类型差异:Python 侧统一表现为int,但生成的内核代码中GlobalTensoruint64_tLocalTensoruint32_t,在大数据量场景下注意语义差异。

相关接口与延伸阅读

GlobalTensor的完整成员方法列表见 core.md,get_size与以下接口协同使用:

  • GlobalTensor.set_global_buffer:初始化全局 Tensor 并声明元素个数(get_size数据来源)。
  • GlobalTensor.get_phy_addr:获取全局数据地址,支持偏移量。
  • GlobalTensor.get_shape_info:获取维度/原始 shape/数据格式等结构信息。
  • GlobalTensor.get_value:按偏移读取指定位置的值。
  • GlobalTensor.set_value:按偏移写入指定位置的值。
  • LocalTensor.get_size:Local Memory 侧的元素个数获取(对照阅读可加深理解)。

上述接口对应的 IR Op 定义集中在 include/ascir/Dialect/Asc/IR/Core/Tensor.td,Python 实现集中在 python/asc/language/core/tensor.py,单元测试见 python/test/unit/language/core/test_global_tensor.py,可作为深入研读的起点。

【免费下载链接】pyasc本项目为Python用户提供算子编程接口,支持在昇腾AI处理器上加速计算,接口与Ascend C一一对应并遵守Python原生语法。项目地址: https://gitcode.com/cann/pyasc

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询