news 2026/9/18 8:53:20

ATVOSS DefaultKernelSchedule:kernel 层默认调度策略的完整实现与使用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ATVOSS DefaultKernelSchedule:kernel 层默认调度策略的完整实现与使用指南

ATVOSS DefaultKernelSchedule:kernel 层默认调度策略的完整实现与使用指南

【免费下载链接】atvossATVOSS(Ascend C Templates for Vector Operator Subroutines)是一套基于Ascend C开发的Vector算子库,致力于为昇腾硬件上的Vector类融合算子提供极简、高效、高性能、高拓展的编程方式。项目地址: https://gitcode.com/cann/atvoss

导读

DefaultKernelSchedule是 ATVOSS(Ascend C Templates for Vector Operator Subroutines)中 kernel 层默认的 schedule 调度策略。它以完全继承BaseKernelSchedule能力的方式,依据DefaultKernelConfig中的切分参数,在昇腾 AI Core 上完成「多核任务划分 → 各核 GM 数据定位 → 下发 block 层执行」的完整调度逻辑。阅读本文后,你将掌握DefaultKernelSchedule的模板参数含义、tiling 配置字段的计算规则、kernel 层Run的执行链路,并能直接在KernelBuilder中正确装配该调度策略编写可运行的 Vector 融合算子。

一、功能定位:kernel 层调度策略在 ATVOSS 分层架构中的角色

ATVOSS 将算子实现划分为 device 层、kernel 层与 block 层。DefaultKernelSchedule属于 kernel 层的调度类(Schedule),其职责与分层协作关系如下:

  • kernel 层:负责根据总元素数量计算 tiling 信息(核数、每核基本块数、尾块元素数等),再依据当前核的blockIdx确定本核需要处理的 GM 数据区间,把数据交给 block 层计算;
  • block 层:kernel 层调度的"被包含对象"(BlockOp),在单核内完成 UB 缓冲管理、基本块循环与表达式求值;
  • device 层:通过 DeviceAdapter 完成 tiling 计算与 kernel 启动(LaunchKernelWithDataTuple)。

DefaultKernelScheduleBaseKernelSchedule的默认实现,二者在 include/elewise/kernel/schedule.h 中定义。从源码结构看,DefaultKernelSchedule是一个空继承类,未覆写任何成员,其全部调度能力(tiling 计算、参数准备、GM 偏移计算)均来自基类BaseKernelSchedule,这保证了默认策略与用户自定义策略拥有完全一致的接口契约。

二、类模板原型与参数说明

DefaultKernelSchedule的完整声明如下(位于 include/elewise/kernel/schedule.h#L214-L215):

template <typename BlockOp, const auto& Policy, typename ScheduleCfg> class DefaultKernelSchedule : public BaseKernelSchedule<BlockOp, Policy, ScheduleCfg> {};
参数名称参数类型输入/输出数据类型参数说明默认值
BlockOp模板参数输入NAblock 层对象类型,与 kernel 层是被包含关系NA
Policy模板参数输入NAkernel 层的用户静态策略类型NA
ScheduleCfg模板参数输入NAkernel 层调度配置类型NA

三个模板参数的取值通常为:

  • BlockOp:由Atvoss::Ele::BlockBuilder<Compute, ArchTag>生成的 block 层对象类型;
  • PolicyAtvoss::Ele::DefaultKernelPolicy类型(含segmentPolicy成员,目前仅支持UniformSegment均匀切分),定义于 include/elewise/kernel/builder.h#L24-L33;
  • ScheduleCfgAtvoss::Ele::DefaultKernelConfig类型,即 kernel 层 tiling 配置结构体。

返回值说明

返回值数据类型返回值说明
DefaultKernelSchedule返回默认的 kernel 层 schedule 调度策略对象

约束说明

原文档标注为 NA。结合源码实现可补充一条隐式约束:ScheduleCfg必须提供blockNum / unitNumPerCore / moreUnitCoreNum / tailNum / unitNum这些成员字段(即满足DefaultKernelConfig的字段布局),否则基类中的 tiling 计算与核内元素计数逻辑将无法编译通过。

三、调度配置的数据基础:DefaultKernelConfig 字段解析

DefaultKernelSchedule的调度逻辑围绕 DefaultKernelConfig 展开,该结构体定义于 include/elewise/kernel/builder.h#L16-L22:

struct DefaultKernelConfig { // Kernel layer tiling information uint32_t blockNum = 1; // Number of cores started uint64_t unitNumPerCore = 0; // Average number of unit processed per core uint64_t moreUnitCoreNum = 0; // Number of cores that need to process an additional full unit uint64_t tailNum = 0; // Number of tail elements to be processed by the last core uint64_t unitNum = 1; // Number of elements per unit block };

各字段含义与默认值如下:

成员名称成员类型成员说明默认值
blockNumuint32_t启用的核的数量1
unitNumPerCoreuint64_t平均每个核处理的基本块个数0
moreUnitCoreNumuint64_t核均分后,需要处理额外多出来的基本块的核的数量0
tailNumuint64_t最后一个核要处理的尾块元素数量0
unitNumuint64_t基本块的元素数量1

其中unitNum在调度执行时会被覆写为ACTUAL_N_ASSIGN(见下文),它代表单个基本块实际分配的元素数,是 tiling 计算的最小粒度。

四、调度原理深度解析:从源码看 tiling 计算与核内执行

4.1 编译期常量推导

BaseKernelSchedule在编译期根据 block 层的TileShape推导出一组调度常量(include/elewise/kernel/schedule.h#L35-L49):

static constexpr uint64_t TILE_SHAPE_SIZE = TileShape::size::value; static constexpr uint64_t BASIC_BLOCK = BlockOp::ScheduleClz::BASIC_BLOCK; static constexpr uint64_t ALIGN_TILE_SHAPE_SIZE = 2; static constexpr uint64_t ACTUAL_N_ASSIGN = TILE_SHAPE_SIZE == 1 ? 32 : TileShape::template get_type<TILE_SHAPE_SIZE - 1>::value; static constexpr uint64_t BASIC_CORE_ELE_NUM = (BASIC_BLOCK + ACTUAL_N_ASSIGN - 1) / ACTUAL_N_ASSIGN * ACTUAL_N_ASSIGN;
  • BASIC_BLOCK:block 层单个 Tile 的元素个数,由 block 层 policy 推导;
  • ACTUAL_N_ASSIGN:基本块实际分配元素数——一维 Tile 形状下取 32,多维取最后一维的元素数;
  • BASIC_CORE_ELE_NUM:单个核最少能处理的对齐后元素数,即BASIC_BLOCK向上对齐到ACTUAL_N_ASSIGN的整数倍。

4.2 MakeScheduleConfig:host 侧 tiling 计算

MakeScheduleConfig是 kernel 层 schedule 的 host 侧静态接口,输入用户参数列表,输出ScheduleCfg(即DefaultKernelConfig)配置(include/elewise/kernel/schedule.h#L57-L93)。计算流程:

  1. 提取形状并校验:从 arguments 的第一个输入中读取shape_vector(),累乘得到totalEleNum;若形状为空或总元素数为 0,打印[ERROR]: [Atvoss][Kernel] Shape info error并返回false
  2. 小数据量直接单核处理:若totalEleNum <= BASIC_CORE_ELE_NUM,则blockNum = 1tailNum = totalEleNum,其余字段置 0,直接返回true
  3. 多核均分
    • basicCoreUnitNum = BASIC_CORE_ELE_NUM / ACTUAL_N_ASSIGN:单核可处理的对齐基本块数;
    • totalUnitCnt = totalEleNum / ACTUAL_N_ASSIGN:总基本块数;
    • blockNum = ceil(totalUnitCnt / basicCoreUnitNum),且不超过ArchTag::CORE_NUM(由 common/arch.h 提供的架构核数上限);
    • unitNumPerCore = totalUnitCnt / blockNum(每核平均基本块数);
    • moreUnitCoreNum = totalUnitCnt % blockNum(多分到一个基本块的核数);
    • tailNum = totalEleNum % ACTUAL_N_ASSIGN(最后一个核负责的尾元素数)。

该接口在整个调用链中的位置可见于 device_adapter.h#L128-L140:CalcParam依次调用KernelOp::ScheduleClz::MakeScheduleConfig生成 kernel 层配置,再调用BlockOp::ScheduleClz::MakeScheduleConfig生成 block 层配置。

4.3 Run:device 侧核内调度执行

Run是 kernel 层在 AI Core 上执行的入口(include/elewise/kernel/schedule.h#L117-L130),完成三件事:

  1. 计算本核元素总数CalCurCoreEleCnt依据AscendC::GetBlockIdx()判断当前核归属——若blockIdx < moreUnitCoreNum则多分一个基本块;若blockIdx == blockNum - 1则追加tailNum尾元素;
  2. 准备参数PrepareParams根据编译期推导出的Params列表逐个构造参数,其中 Tensor 参数通过CalGMOffset计算本核在 GM 中的起始偏移(blockIdx * unitNumPerCore * unitNum + moreUnitCoreNum * unitNum的均匀划分公式),将 GM 地址指针按数据类型大小平移后传入;标量参数则直接透传或解引用;
  3. 下发 block 层:组装configBlock(含totalElemCnt)与参数元组,构造BlockOp并调用blockOp.Run(...),由 BaseBlockSchedule::Run 继续按BASIC_BLOCK切分wholeLooptileCnt循环求值。

值得注意,Run定义在#if !defined(__ATVOSS_HOST_ONLY__)分支内,即仅编译进 device 侧代码;host 侧仅暴露MakeScheduleConfig静态接口用于 tiling 计算,这正是 ATVOSS 将 host/device 代码通过宏隔离的典型模式。

五、在 KernelBuilder 中装配 DefaultKernelSchedule

DefaultKernelSchedule是 KernelBuilder 的第四个模板参数(调度类型)的默认值,定义于 include/elewise/kernel/builder.h#L39-L48:

template < typename BlockOp, const auto& Policy = defaultKernelPolicy, typename ScheduleCfg = DefaultKernelConfig, template <typename, const auto&, typename> class Schedule = DefaultKernelSchedule> class KernelBuilder { ... };

因此常规写法Atvoss::Ele::KernelBuilder<BlockOp, kernelPolicy>内部即隐式使用DefaultKernelSchedule+DefaultKernelConfig。当用户需要自定义调度时,可在第四个模板参数处替换为自己的 Schedule 类(同样须继承自BaseKernelSchedule)。

六、完整使用示例

以下示例实现out = in1 + in2 - in3(两个 Tensor 输入减一个标量输入),完整演示如何将DefaultKernelSchedule显式装配进KernelBuilder

template <typename InputDtype, typename OutputDtype> struct AddSubConfig { struct AddSubCompute { template <template <typename> class Tensor> __host_aicore__ constexpr auto Compute() const { auto in1 = Atvoss::PlaceHolder<1, Tensor<InputDtype>, Atvoss::ParamUsage::IN>(); auto in2 = Atvoss::PlaceHolder<2, Tensor<InputDtype>, Atvoss::ParamUsage::IN>(); auto in3 = Atvoss::PlaceHolder<3, InputDtype, Atvoss::ParamUsage::IN>(); auto out = Atvoss::PlaceHolder<4, Tensor<OutputDtype>, Atvoss::ParamUsage::OUT>(); return (out = in1 + in2 - in3); }; }; static constexpr Atvoss::Ele::DefaultKernelPolicy kernelPolicy{Atvoss::Ele::DefaultSegmentPolicy::UniformSegment}; using ArchTag = Atvoss::Arch::DAV_3510; using BlockOp = Atvoss::Ele::BlockBuilder<AddSubCompute, ArchTag>; using KernelOp = Atvoss::Ele::KernelBuilder< BlockOp, kernelPolicy, Atvoss::Ele::DefaultKernelConfig, // 🔥🔥🔥 使用示例 🔥🔥🔥 Atvoss::Ele::DefaultKernelSchedule // 🔥🔥🔥 使用示例 🔥🔥🔥 >; using DeviceOp = Atvoss::DeviceAdapter<KernelOp>; }; template <typename InputDtype, typename OutputDtype> static void Run() { /* ACL init and stream create */ ... Atvoss::Tensor<InputDtype> in1(deviceIn1, {{3, 4, 0, 0, 0, 0, 0, 0}}, 2); Atvoss::Tensor<InputDtype> in2(deviceIn2, {{3, 4, 0, 0, 0, 0, 0, 0}}, 2); InputDtype in3 = 5.0; Atvoss::Tensor<OutputDtype> out(deviceOut, {{3, 4, 0, 0, 0, 0, 0, 0}}, 2); auto arguments = Atvoss::ArgumentsBuilder{}.inputOutput(in1, in2, in3, out).attr("dim", 5).build(); using DeviceOp = typename AddSubConfig<InputDtype, OutputDtype>::DeviceOp; DeviceOp deviceOp; deviceOp.Run(arguments, stream); } int main(int argc, char const* argv[]) { Run<float, float>(); return 0; }

代码要点:

  • kernelPolicy采用DefaultSegmentPolicy::UniformSegment(均匀切分,当前唯一支持的切分方式);
  • BlockBuilder生成 block 层对象,KernelBuilderBlockOp + kernelPolicy + DefaultKernelConfig + DefaultKernelSchedule组装 kernel 层;
  • DeviceAdapter负责在 host 侧驱动MakeScheduleConfig生成 tiling,再以opParam.kernelParam.blockNum作为启动核数调用LaunchKernelWithDataTuple拉起 kernel;
  • 运行期每个核通过AscendC::GetBlockIdx()Run内确定自己的数据区间,实现多核并行。

该模式与仓库内 examples/muls/muls.cpp 等官方示例的编写方式一致,可作为实际算子开发的参照。

七、约束、局限与总结

  • 切分策略约束DefaultKernelPolicy目前仅支持UniformSegment均匀切分;若需按非均匀方式(如按 shape 维度特化切分)划分数据,需要自定义继承自BaseKernelSchedule的调度类;
  • 核数上限blockNumArchTag::CORE_NUM截断,超大 shape 下不会超过目标架构可用核数;
  • 调度粒度:kernel 层以「基本块(unit)」为最小调度单元,block 层再按BASIC_BLOCK细分循环,两级切分共同决定了数据在核间与核内的分布;
  • 接口契约:无论默认还是自定义调度,都必须实现 host 侧MakeScheduleConfig与 device 侧Run两个接口,且ScheduleCfg需与KernelBuilder传入的配置类型一致。

DefaultKernelSchedule以极小的代码量(单行继承声明)复用了BaseKernelSchedule完整的多核 tiling 与数据分发逻辑,是 ATVOSS「极简编程」理念在调度层的集中体现。理解它的 tiling 计算规则与核内执行链路,是进一步自定义 kernel 层调度、编写高性能 Vector 融合算子的基础。

相关文档导航

  • BaseKernelSchedule::MakeScheduleConfig:tiling 配置生成接口详解
  • BaseKernelSchedule::Run:核内调度执行接口详解
  • DefaultKernelConfig:调度配置结构体
  • DefaultKernelPolicy:kernel 层静态策略
  • KernelBuilder:kernel 层对象构建类
  • DefaultBlockSchedule:block 层默认调度策略
  • DeviceAdapter:device 层适配与 kernel 启动

【免费下载链接】atvossATVOSS(Ascend C Templates for Vector Operator Subroutines)是一套基于Ascend C开发的Vector算子库,致力于为昇腾硬件上的Vector类融合算子提供极简、高效、高性能、高拓展的编程方式。项目地址: https://gitcode.com/cann/atvoss

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 8:51:35

LiveTalking 数字人直播:5 分钟搭一套会说话的虚拟主播

LiveTalking 数字人直播&#xff1a;5 分钟搭一套会说话的虚拟主播 【免费下载链接】metahuman-stream Real time interactive streaming digital human 项目地址: https://gitcode.com/GitHub_Trending/me/metahuman-stream 开播前 10 分钟还在手动对口型&#xff1f;L…

作者头像 李华
网站建设 2026/9/18 8:51:27

Unity全景视频播放:投影、编码与流畅度优化实践

简介&#xff1a;面向Unity开发者和VR爱好者&#xff0c;资源聚焦Unity 2017环境下的全景视频播放实现&#xff0c;系统梳理了使用内置MovieTexture组件加载OGG/OVG视频、创建3D球体并放置主相机、通过Renderer映射纹理&#xff0c;以及利用AudioSource同步音轨的完整流程。文档…

作者头像 李华
网站建设 2026/9/18 8:51:13

急诊管理系统开发:SpringBoot+Vue实现高效医疗资源调度

1. 急诊管理系统开发背景与核心价值急诊科作为医院最前线的救治单元&#xff0c;每天需要处理大量突发性、紧急性病例。传统纸质登记人工调度的管理模式存在三大痛点&#xff1a;患者信息录入效率低下&#xff08;平均每位患者需要5-8分钟手工填表&#xff09;、医疗资源调配依…

作者头像 李华
网站建设 2026/9/18 8:50:39

Photoshop CS2 ACE题库拆解:色彩管理、图层蒙版与自动化全解析

简介&#xff1a;这是一份面向Photoshop认证考生的Adobe Photoshop CS2 ACE考试题库资源&#xff0c;整体采用docx文档格式&#xff0c;压缩包内仅一个文档&#xff0c;大小约394KB&#xff0c;方便下载与离线学习。题库内容紧扣考试大纲&#xff0c;覆盖透明度处理、变量与数据…

作者头像 李华