兼容性处理
CANN Runtime 遵循语义化版本规范,提供版本查询机制和废弃接口处理策略,帮助开发者构建前后向兼容的应用程序。
1. 版本查询机制
Runtime提供多层次的版本查询接口,帮助应用在运行时获取环境信息,实现兼容性适配。
1.1 Runtime版本查询
使用aclsysGetVersionNum接口查询Runtime版本号,传入包名"runtime":
char pkgName[] = "runtime";
int32_t versionNum;
aclsysGetVersionNum(pkgName, &versionNum);
printf("Runtime Version Num: %d\n", versionNum);
版本号计算规则
返回的versionNum是一个整数值,遵循语义化版本编码规则,便于版本比较。
| 版本部分 | 权重 | 说明 |
|---|---|---|
| major(主版本号) | 10000000 | 不兼容的API变更 |
| minor(次版本号) | 100000 | 向后兼容的功能新增 |
| patch(修订号) | 1000 | 向后兼容的问题修复 |
正式版本计算公式:
versionNum = major × 10000000 + minor × 100000 + patch × 1000
计算示例:
| 版本字符串 | 计算过程 | versionNum |
|---|---|---|
| 9.0.0 | 9×10000000 + 0×100000 + 0×1000 | 90000000 |
| 8.5.1 | 8×10000000 + 5×100000 + 1×1000 | 80501000 |
1.2 Driver版本查询
Runtime依赖驱动能力,部分特性功能需要同时判断驱动版本号以做兼容性处理,传入"driver"包名可查询驱动版本号。
char pkgName[] = "driver"; // 查询驱动版本,使用"driver"
int32_t versionNum;
aclsysGetVersionNum(pkgName, &versionNum);
printf("Package Version Num: %d\n", versionNum);
1.3 运行时特性查询
使用aclrtGetDevFeature查询设备支持的特性能力,实现功能特性的条件适配:
int32_t deviceId = 0;
aclrtSetDevice(deviceId);
// 查询是否支持某特性
int32_t isSupported = 0;
aclrtGetDevFeature(deviceId, ACL_FEATURE_XXX, &isSupported);
if (isSupported) {
// 使用新特性
} else {
// 使用兼容方案
}
2. 应用兼容性处理
应用开发时预留扩展能力便于前向兼容(适配新版本)或者新版本应用需在旧版本环境运行时做后向兼容(支持旧版本),可采用如下处理方式:
- 运行时版本检测:程序启动时获取版本信息,记录日志或进行适配判断。
// 版本条件执行
int32_t versionNum;
aclsysGetVersionNum("runtime", &versionNum);
int32_t major = 8;
int32_t minor = 5;
if (versionNum >= major * 10000000 + minor * 100000) {
// 使用新版本特性接口
aclrtQueryEventStatus(event, &status);
} else {
// 使用旧版本兼容接口
aclrtQueryEvent(event, &status);
}
- 特性能力探测:使用特性查询接口而非硬编码版本号判断。
// 查询特性支持情况
int32_t isSupported = 0;
aclrtGetDevFeature(deviceId, ACL_FEATURE_TSCPU_TASK_UPDATE_SUPPORT_AIC_AIV, &isSupported);
if (isSupported) {
// 使用新特性实现高效路径
useNewFeaturePath();
} else {
// 降级到兼容实现
useLegacyPath();
}
3. CANN Runtime兼容性策略
3.1 兼容原则
CANN Runtime遵循以下兼容性原则:
| 版本变更类型 | 兼容性保证 | 示例 |
|---|---|---|
| Patch版本升级 | 完全向后兼容 | Bug修复、性能优化 |
| Minor版本升级 | API向后兼容 | 新增接口、新增特性 |
| Major版本升级 | 不保证兼容 | 删除废弃接口、架构调整 |
3.2 废弃接口处理策略
Runtime使用ACL_DEPRECATED_MESSAGE宏标记废弃接口,在废弃周期内保持可用,同时提示替换接口(如有)。
废弃接口标记方式
// 废弃接口声明示例
ACL_DEPRECATED_MESSAGE("aclrtQueryEvent is deprecated, use aclrtQueryEventStatus instead")
ACL_FUNC_VISIBILITY aclError aclrtQueryEvent(aclrtEvent event, aclrtEventStatus *status);
编译时将产生警告信息:
warning: 'aclrtQueryEvent' is deprecated: aclrtQueryEvent is deprecated, use aclrtQueryEventStatus instead [-Wdeprecated-declarations]
废弃接口生命周期
| 阶段 | 状态 | 建议 |
|---|---|---|
| 发布废弃通知 | 接口可用,编译警告 | 开始迁移到替代接口 |
| 废弃过渡期 | 接口可用,持续警告 | 完成迁移 |
| 正式移除 | 接口不可用 | 必须使用替代接口 |
3.3 枚举/结构体成员废弃处理
枚举值和结构体成员也可能被废弃:
typedef enum aclrtLaunchKernelAttrId {
ACL_RT_LAUNCH_KERNEL_ATTR_LOCAL_MEMORY_SIZE
ACL_DEPRECATED_MESSAGE("Use ACL_RT_LAUNCH_KERNEL_ATTR_DYN_UBUF_SIZE instead") = 2,
ACL_RT_LAUNCH_KERNEL_ATTR_DYN_UBUF_SIZE = 2, // 替代值,同编号
...
} aclrtLaunchKernelAttrId;
typedef union aclrtLaunchKernelAttrValue {
ACL_DEPRECATED_MESSAGE("Use dynUbufSize instead")
uint32_t localMemorySize; // 废弃成员
uint32_t dynUBufSize; // 替代成员
...
} aclrtLaunchKernelAttrValue;
处理建议:
- 使用替代枚举值/成员名。
- 注意替代值可能与废弃值编号相同,保持兼容。
4. 迁移废弃接口
4.1 迁移流程
- 识别废弃接口:编译时查看废弃警告,确认替代接口。
- 评估迁移影响:分析接口参数、返回值、语义差异。
- 编写迁移代码:替换废弃接口调用,适配新接口参数。
- 测试验证:确保迁移后功能正确、性能符合预期。
4.2 迁移示例
aclrtQueryEvent -> aclrtQueryEventStatus
// 废弃接口(旧代码)
aclrtEventStatus status;
aclrtQueryEvent(event, &status);
if (status == ACL_EVENT_STATUS_COMPLETE) {
// ...
}
// 替代接口(新代码)
aclrtEventRecordedStatus status;
aclrtQueryEventStatus(event, &status);
if (status == ACL_EVENT_RECORDED_STATUS_COMPLETE) {
// ...
}
4.3 推荐做法
- 定期检查编译警告:及时处理废弃接口警告,避免积累。
- 优先使用新接口:新接口通常有更好的语义、性能或功能。
- 版本信息记录:应用启动时记录Runtime版本,便于问题定位。
- 特性探测优于版本判断:使用特性查询接口判断能力,而非硬编码版本号。
- 封装版本适配逻辑:将兼容性逻辑集中在适配层,便于维护。
4.4 避免的做法
- 不要忽略废弃警告:废弃接口可能在未来版本移除,导致编译失败。
- 不要硬编码版本判断:版本号判断缺乏灵活性,应使用特性探测。
- 不要混用新旧接口:同一功能模块统一使用新或旧接口,避免混乱。
- 不要假设接口语义不变:迁移时仔细阅读新接口文档,确认语义一致。