CANN opbase 格式工具 GetPrimaryFormat:获取根 Format 的实现原理与调用指南
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
导读
GetPrimaryFormat是 CANN opbase 算子库(cann/opbase)中format_utils工具集的核心接口之一,用于从携带 C0 扩展信息的格式编码中提取"根格式",例如将FORMAT_FRACTAL_Z_C04归一化为FORMAT_FRACTAL_Z。在算子开发中,当需要基于张量实际存储格式做分支判断(如判断是否 fractal Z 数据)时,该接口可以屏蔽 C0 子格式差异,让判断逻辑更简洁可靠。读完本文你将掌握GetPrimaryFormat的两种重载形式、位域编码原理、实际调用场景,以及与format_utils家族其他接口(IsPrivateFormat、GetSubFormat、ToOpFormat等)的配合方式。
功能说明
GetPrimaryFormat获取张量数据的根 format,即去除关于 C0 的信息,只保留单纯的 format 信息。
在昇腾算子的数据布局体系中,部分格式会在基础格式之上叠加 C0 维度信息,形成"带子格式的扩展格式"。例如:
FORMAT_FRACTAL_Z_C04→FORMAT_FRACTAL_ZFORMAT_NC1HWC0_C04→FORMAT_NC1HWC0
这类 C0 扩展格式在语义上仍属于其根格式,因此在做格式判断、格式映射、日志打印等操作时,往往需要先剥离 C0 信息、还原根格式,这正是GetPrimaryFormat的职责所在。
函数原型
GetPrimaryFormat提供两个重载版本,分别面向底层整数编码与Format枚举类型:
int32_t GetPrimaryFormat(int32_t format)Format GetPrimaryFormat(Format format)其中Format即op::Format(等同于ge::Format),是算子侧使用的格式枚举类型;而int32_t版本适用于需要在整数层面直接处理格式编码的场景,例如在日志序列化、tiling 信息落盘等模块中传入原始整型格式值。
参数说明
| 参数 | 输入/输出 | 说明 |
|---|---|---|
| format | 输入 | 原始目标数据格式,可为int32_t格式编码或Format枚举值。 |
返回值说明
返回去除 C0 信息后的格式:
int32_t重载返回剥离 C0 信息后的整型格式编码;Format重载返回剥离 C0 信息后的Format枚举值。
传入的格式本身不携带 C0 信息时,返回值与传入值保持一致(对格式无副作用,可安全用于任意格式的归一化处理)。
约束说明
无。该接口为纯位运算实现,不依赖运行环境、不申请内存、不抛异常,可在算子 Shape 推导、tiling 计算、日志输出等任意阶段安全调用。
底层实现原理:Format 的位域编码
GetPrimaryFormat的实现位于 include/nnopbase/opdev/format_utils.h,是一个内联函数,核心逻辑只有一行位掩码运算:
inline int32_t GetPrimaryFormat(int32_t format) { return static_cast<int32_t>(static_cast<uint32_t>(format) & 0xffU); } inline Format GetPrimaryFormat(Format format) { return static_cast<Format>(static_cast<uint32_t>(format) & 0xffU); }从源码结构可以推断出Format枚举值是一个 32 位整数,其位域布局如下:
- 低 8 位(bit 0–7):根格式(primary format),即
GetPrimaryFormat通过& 0xffU保留的部分; - bit 8–23:子格式(sub format),由 GetSubFormat 通过
& 0xffff00U再右移 8 位提取; - bit 24–27:C0 格式(C0 format),由 GetC0Format / HasC0Format 通过
& 0xf000000U提取,用于标记 C0 通道数(如 C04 表示 C0=4)。
因此,当格式编码为FORMAT_FRACTAL_Z_C04时,其高 28 位携带了子格式/C0 信息,而低 8 位仍是FORMAT_FRACTAL_Z,GetPrimaryFormat通过按位与直接命中根格式,计算开销极小(单个位运算指令)。
与GetPrimaryFormat配套的还有位域反向组合接口:
inline Format GetFormatFromSub(int32_t primaryFormat, int32_t subFormat)GetFormatFromSub(include/nnopbase/opdev/format_utils.h)将根格式置于低 8 位、子格式左移 8 位后做按位或,完成与GetPrimaryFormat相反的操作,可用于构造带子格式的完整格式值。
调用示例
原文档给出的典型用法是:当输入张量的存储格式为 fractal Z 时提前返回,配合GetStorageFormat()读取存储格式:
// 判断当 input 的 storage format 是 fractal z 时,返回 void Func(const aclTensor *input) { if (GetPrimaryFormat(input->GetStorageFormat()) == FORMAT_FRACTAL_Z) { return; } }需要注意的是,示例中传入的是input->GetStorageFormat()的结果,存储格式可能是FORMAT_FRACTAL_Z_C04这类携带 C0 信息的扩展格式;若不调用GetPrimaryFormat归一化,直接用== FORMAT_FRACTAL_Z比较会漏掉 C04 等变体。这正是该接口的实战价值所在。
场景一:格式分支判断(算子执行路径选择)
在 src/nnopbase/composite_op/aclnn_engine/kernel_arg.h 中,GetPrimaryFormat被用于判断张量存储格式是否为 fractal Z,从而决定不同的 kernel 参数装配路径:
static_cast<ge::Format>(GetPrimaryFormat(tensor->GetStorageFormat())) == ge::FORMAT_FRACTAL_Z同一文件的 kernel_arg.cpp 中,也先通过GetPrimaryFormat(tensor->GetStorageFormat())取得根格式,再基于根格式做后续参数构造与地址计算,确保 C04 等变体格式能复用统一的 fractal Z 处理逻辑。
场景二:tiling 上下文序列化
在算子信息记录模块 src/nnopbase/common/op_info_record/tiling_context_to_json.cpp 中,tiling 信息导出 JSON 前会先调用ge::GetPrimaryFormat(cpTdInfo->GetStorageFormat())对存储格式做归一化,保证不同 C0 变体格式在序列化结果中呈现为统一的根格式,避免导出数据出现格式枚举不一致。
场景三:格式名打印与 ToString
在 src/nnopbase/common/utils/format_utils.cpp 的ToString实现中,先调用GetPrimaryFormat拿到根格式后去kFormatToStringMap查找格式名,再通过HasSubFormat(format)判断是否需要追加:子格式号后缀:
const auto it = kFormatToStringMap.find(static_cast<Format>(GetPrimaryFormat(static_cast<int32_t>(format)))); if (it != kFormatToStringMap.end()) { if (op::HasSubFormat(format)) { return ge::AscendString((it->second + ":" + std::to_string(op::GetSubFormat(format))).c_str()); } return ge::AscendString((it->second).c_str()); }可见GetPrimaryFormat是format_utils内部被ToString复用的基础能力,也是整个格式工具链的基石。
与 format_utils 家族其他接口的配合
GetPrimaryFormat隶属于op命名空间下的format_utils工具集,文档入口见 docs/zh/api/nnopbase/opdev/format_utils/format_utils.md(英文版见 docs/en/api/nnopbase/opdev/format_utils/format_utils.md),同族接口包括:
- IsPrivateFormat:判断格式是否为私有格式(如
FORMAT_NC1HWC0、FORMAT_FRACTAL_Z、FORMAT_FRACTAL_NZ及其 C0 变体等),实现在 src/nnopbase/common/utils/format_utils.cpp; - ToOpFormat:将
aclFormat转为op::Format; - ToAclFormat:将
op::Format转为aclFormat,仅支持白名单内的格式(见 include/nnopbase/opdev/format_utils.h),不支持时返回ACL_FORMAT_UNDEFINED; GetSubFormat/GetC0Format/HasSubFormat/HasC0Format:子格式与 C0 信息的提取与判定;ToFormat/ToString:格式字符串与枚举的双向转换,ToFormat维护了从"FRACTAL_Z_C04"、"FRACTAL_NZ_C0_16"等字符串到枚举的映射(src/nnopbase/common/utils/format_utils.cpp)。
实际开发中的常见组合模式是:先用IsPrivateFormat判断是否为私有格式,再用GetPrimaryFormat归一化后与根格式常量比较,最后用ToString输出可读的格式名用于日志。这些接口共同构成了算子侧格式处理的标准工具箱。
总结
GetPrimaryFormat是 CANN opbase 中处理格式归一化的基础工具接口:
- 职责单一:剥离 C0 信息、还原根格式,对不携带 C0 信息的格式原样返回;
- 实现极简:基于 32 位格式编码的位域设计,一条
& 0xffU位运算完成,零开销、无副作用; - 应用广泛:在格式分支判断(kernel_arg.h、kernel_arg.cpp)、tiling 序列化(tiling_context_to_json.cpp)、格式名打印(format_utils.cpp)等核心链路上均有实际调用。
在编写算子代码时,凡是涉及存储格式与根格式常量的比较、格式映射或格式日志输出,建议优先通过GetPrimaryFormat归一化,避免因 C0 子格式差异引入判断遗漏。
【免费下载链接】opbase本项目是CANN算子库的基础框架库,为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考