已合并
支持确定性计算与一致性开关动态生效 #631
ren-botao创建于 7月9日
支持确定性计算与一致性开关动态生效 #631
已合并
共 10 个文件变更+233-337
| @@ -1,12 +1,12 @@ | |||
| 1 | /** | 1 | /** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | + * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 3 | - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | - * CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | - * Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. |
| 6 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 7 | - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | 10 | ||
| 11 | #ifndef OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H | 11 | #ifndef OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H |
| 12 | #define OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H | 12 | #define OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H |
| @@ -19,18 +19,20 @@ struct OpConfigInfo { | |||
| 19 | OpConfigInfo() = default; | 19 | OpConfigInfo() = default; |
| 20 | OpConfigInfo(const OpConfigInfo& rhs) | 20 | OpConfigInfo(const OpConfigInfo& rhs) |
| 21 | { | 21 | { |
| 22 | - isDeterministicOn_ = rhs.isDeterministicOn_; | ||
| 23 | - isOpDumpEnable_ = rhs.isOpDumpEnable_; | ||
| 24 | aicNum_ = rhs.aicNum_; | 22 | aicNum_ = rhs.aicNum_; |
| 25 | aivNum_ = rhs.aivNum_; | 23 | aivNum_ = rhs.aivNum_; |
| 24 | + isDeterministicOn_ = rhs.isDeterministicOn_; | ||
| 25 | + isOpDumpEnable_ = rhs.isOpDumpEnable_; | ||
| 26 | + deterministicLevel_ = rhs.deterministicLevel_; | ||
| 26 | } | 27 | } |
| 27 | OpConfigInfo& operator=(const OpConfigInfo& rhs) | 28 | OpConfigInfo& operator=(const OpConfigInfo& rhs) |
| 28 | { | 29 | { |
| 29 | if (this != &rhs) { | 30 | if (this != &rhs) { |
| 30 | - isDeterministicOn_ = rhs.isDeterministicOn_; | ||
| 31 | - isOpDumpEnable_ = rhs.isOpDumpEnable_; | ||
| 32 | aicNum_ = rhs.aicNum_; | 31 | aicNum_ = rhs.aicNum_; |
| 33 | aivNum_ = rhs.aivNum_; | 32 | aivNum_ = rhs.aivNum_; |
| 33 | + isDeterministicOn_ = rhs.isDeterministicOn_; | ||
| 34 | + isOpDumpEnable_ = rhs.isOpDumpEnable_; | ||
| 35 | + deterministicLevel_ = rhs.deterministicLevel_; | ||
| 34 | } | 36 | } |
| 35 | return *this; | 37 | return *this; |
| 36 | } | 38 | } |
| @@ -39,9 +41,10 @@ struct OpConfigInfo { | |||
| 39 | uint32_t aivNum_{0}; | 41 | uint32_t aivNum_{0}; |
| 40 | bool isDeterministicOn_{false}; | 42 | bool isDeterministicOn_{false}; |
| 41 | bool isOpDumpEnable_{false}; | 43 | bool isOpDumpEnable_{false}; |
| 42 | - uint8_t reserved[6] = {0}; | 44 | + uint8_t deterministicLevel_{0}; |
| 45 | + uint8_t reserved[5] = {0}; | ||
| 43 | }; | 46 | }; |
| 44 | 47 | ||
| 45 | } // namespace op | 48 | } // namespace op |
| 46 | 49 | ||
| 47 | -#endif // OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H | 50 | +#endif // OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H |
| @@ -489,8 +489,8 @@ void AddOpConfigInfoToBuf() | |||
| 489 | tlsData->threadLocalContext.opConfigInfo_.aivNum_); | 489 | tlsData->threadLocalContext.opConfigInfo_.aivNum_); |
| 490 | *PtrCastTo<ThreadCoreNum>(tlsData->hashBuf + tlsData->hashOffset) = coreNum; | 490 | *PtrCastTo<ThreadCoreNum>(tlsData->hashBuf + tlsData->hashOffset) = coreNum; |
| 491 | tlsData->hashOffset += sizeof(ThreadCoreNum); | 491 | tlsData->hashOffset += sizeof(ThreadCoreNum); |
| 492 | - bool deterministic = tlsData->threadLocalContext.opConfigInfo_.isDeterministicOn_; | 492 | + uint8_t deterministicLevel = tlsData->threadLocalContext.opConfigInfo_.deterministicLevel_; |
| 493 | - OpCacheAdd1Byte(&deterministic, tlsData->hashBuf, tlsData->hashOffset); | 493 | + OpCacheAdd1Byte(&deterministicLevel, tlsData->hashBuf, tlsData->hashOffset); |
| 494 | } | 494 | } |
| 495 | } | 495 | } |
| 496 | 496 | ||
| @@ -735,7 +735,7 @@ void AddParamToBuf(char* c) | |||
| 735 | AddParamToBuf(constPtr); | 735 | AddParamToBuf(constPtr); |
| 736 | }; | 736 | }; |
| 737 | 737 | ||
| 738 | -void AddParamToBuf() {}; | 738 | +void AddParamToBuf(){}; |
| 739 | 739 | ||
| 740 | std::size_t OpCacheKeyHash::operator()(const OpCacheKey& key) const { return MurmurHash(key.buf, key.len); } | 740 | std::size_t OpCacheKeyHash::operator()(const OpCacheKey& key) const { return MurmurHash(key.buf, key.len); } |
| 741 | 741 | ||
| @@ -995,6 +995,36 @@ aclnnStatus CommonOpExecutorRun(void* workspace, uint64_t workspaceSize, aclOpEx | |||
| 995 | return res; | 995 | return res; |
| 996 | } | 996 | } |
| 997 | 997 | ||
| 998 | +namespace { | ||
| 999 | +// 从 ACL runtime 获取确定性计算 level | ||
| 1000 | +// ACL_OPT_DETERMINISTIC 取值含义: | ||
| 1001 | +// 0 = 关闭 | ||
| 1002 | +// 1 = 开启确定性计算 | ||
| 1003 | +// 2 = 开启强一致性(前向包含 1) | ||
| 1004 | +// 3 = 开启 batch 一致性(前向包含 2) | ||
| 1005 | +// 兼容老 runtime:当返回值为 1 时(老 runtime 仅返回 0/1),二次获取 | ||
| 1006 | +// ACL_OPT_STRONG_CONSISTENCY 确认是否实际应为 level 2 | ||
| 1007 | +int64_t GetDeterministicLevelFromRt() | ||
| 1008 | +{ | ||
| 1009 | + int64_t deterministicLevel = 0; | ||
| 1010 | + aclError aclRet = aclrtGetSysParamOpt(ACL_OPT_DETERMINISTIC, &deterministicLevel); | ||
| 1011 | + OP_CHECK_NO_RETURN(aclRet == ACL_SUCCESS, deterministicLevel = 0; | ||
| 1012 | + OP_LOGW("can not get system param deterministic, ret= %d.", aclRet)); | ||
| 1013 | + | ||
| 1014 | + if (deterministicLevel == 1) { | ||
| 1015 | + int64_t consistency = 0; | ||
| 1016 | + aclError consistencyRet = aclrtGetSysParamOpt(ACL_OPT_STRONG_CONSISTENCY, &consistency); | ||
| 1017 | + OP_CHECK_NO_RETURN(consistencyRet == ACL_SUCCESS, consistency = 0; | ||
| 1018 | + OP_LOGW("can not get system param strong consistency, ret= %d.", consistencyRet)); | ||
| 1019 | + if (consistency == 1) { | ||
| 1020 | + deterministicLevel = 2; | ||
| 1021 | + OP_LOGI("Upgrade deterministic level from 1 to 2, because strong consistency is on."); | ||
| 1022 | + } | ||
| 1023 | + } | ||
| 1024 | + return deterministicLevel; | ||
| 1025 | +} | ||
| 1026 | +} // namespace | ||
| 1027 | + | ||
| 998 | void InitL2Phase1Context(const char* l2Name, [[maybe_unused]] aclOpExecutor** executor) | 1028 | void InitL2Phase1Context(const char* l2Name, [[maybe_unused]] aclOpExecutor** executor) |
| 999 | { | 1029 | { |
| 1000 | auto& opTlsCtx = op::internal::GetThreadLocalContext(); | 1030 | auto& opTlsCtx = op::internal::GetThreadLocalContext(); |
| @@ -1009,14 +1039,12 @@ void InitL2Phase1Context(const char* l2Name, [[maybe_unused]] aclOpExecutor** ex | |||
| 1009 | opTlsCtx.opConfigInfo_.aivNum_ = controlCoreNum; | 1039 | opTlsCtx.opConfigInfo_.aivNum_ = controlCoreNum; |
| 1010 | opTlsCtx.opConfigInfo_.isOpDumpEnable_ = op::internal::IsDumpEnable(); | 1040 | opTlsCtx.opConfigInfo_.isOpDumpEnable_ = op::internal::IsDumpEnable(); |
| 1011 | 1041 | ||
| 1012 | - int64_t determinConfig = 0; | 1042 | + int64_t deterministicLevel = GetDeterministicLevelFromRt(); |
| 1013 | - aclError aclRet = aclrtGetSysParamOpt(ACL_OPT_DETERMINISTIC, &determinConfig); | 1043 | + opTlsCtx.opConfigInfo_.deterministicLevel_ = static_cast<uint8_t>(deterministicLevel); |
| 1014 | - OP_CHECK_NO_RETURN(aclRet == ACL_SUCCESS, determinConfig = 0; | 1044 | + opTlsCtx.opConfigInfo_.isDeterministicOn_ = (deterministicLevel >= 1); |
| 1015 | - OP_LOGW("can not get system param deterministic, ret= %d.", aclRet)); | 1045 | + OP_LOGI("aic num: %u, aiv num: %u, deterministic level: %d, is deterministic on: %d, is op dump enable: %d", |
| 1016 | - opTlsCtx.opConfigInfo_.isDeterministicOn_ = (determinConfig == 1); | 1046 | + opTlsCtx.opConfigInfo_.aicNum_, opTlsCtx.opConfigInfo_.aivNum_, opTlsCtx.opConfigInfo_.deterministicLevel_, |
| 1017 | - OP_LOGI("aic num: %u, aiv num: %u, is deterministic on: %d, is op dump enable: %d", opTlsCtx.opConfigInfo_.aicNum_, | 1047 | + opTlsCtx.opConfigInfo_.isDeterministicOn_, opTlsCtx.opConfigInfo_.isOpDumpEnable_); |
| 1018 | - opTlsCtx.opConfigInfo_.aivNum_, opTlsCtx.opConfigInfo_.isDeterministicOn_, | ||
| 1019 | - opTlsCtx.opConfigInfo_.isOpDumpEnable_); | ||
| 1020 | } | 1048 | } |
| 1021 | 1049 | ||
| 1022 | void InitL2Phase2Context([[maybe_unused]] const char* l2Name, aclOpExecutor* executor) | 1050 | void InitL2Phase2Context([[maybe_unused]] const char* l2Name, aclOpExecutor* executor) |
| @@ -49,15 +49,6 @@ using OpImplFunctions = gert::OpImplKernelRegistry::OpImplFunctions; | |||
| 49 | constexpr size_t K_DEFAULT_INPUT_SIZE = 3; | 49 | constexpr size_t K_DEFAULT_INPUT_SIZE = 3; |
| 50 | constexpr size_t K_DEFAULT_OUTPUT_SIZE = 1; | 50 | constexpr size_t K_DEFAULT_OUTPUT_SIZE = 1; |
| 51 | 51 | ||
| 52 | -// Deterministic level definitions | ||
| 53 | -// 0: deterministic:0, strong consistency:0 or 1 | ||
| 54 | -// 1: deterministic:1, strong consistency:0 | ||
| 55 | -// 2: deterministic:1, strong consistency:1 | ||
| 56 | -constexpr int32_t DETERMINISTIC_LEVEL_NONE = 0; | ||
| 57 | -constexpr int32_t DETERMINISTIC_LEVEL_NORMAL = 1; | ||
| 58 | -constexpr int32_t DETERMINISTIC_LEVEL_HIGH = 2; | ||
| 59 | -constexpr int32_t STRONG_CONSISTENCY_ON = 1; | ||
| 60 | - | ||
| 61 | uint32_t CalcMixCoreNum(uint32_t cubeCoreNum, uint32_t vectorCoreNum, const Json& opJson) | 52 | uint32_t CalcMixCoreNum(uint32_t cubeCoreNum, uint32_t vectorCoreNum, const Json& opJson) |
| 62 | { | 53 | { |
| 63 | if (!opJson.contains("taskRation")) { | 54 | if (!opJson.contains("taskRation")) { |
| @@ -228,33 +219,6 @@ aclnnStatus TilingParseCtxHolder::BuildTilingParseCtx(uint32_t opType, | |||
| 228 | tilingParseCtxValue_[kCompileInfoStruct].data.pointer = pStruct; | 219 | tilingParseCtxValue_[kCompileInfoStruct].data.pointer = pStruct; |
| 229 | tilingParseInfo_.compileInfoStruct_ = pStruct; | 220 | tilingParseInfo_.compileInfoStruct_ = pStruct; |
| 230 | 221 | ||
| 231 | - *PtrCastTo<int32_t>(Deterministic_.data.inplace) = GetThreadLocalContext().opConfigInfo_.isDeterministicOn_ ? 1 : 0; | ||
| 232 | - OP_LOGD("Deterministic status: %d", *PtrCastTo<int32_t>(Deterministic_.data.inplace)); | ||
| 233 | - | ||
| 234 | - // 一次性获取强一致性开关,后续直接从静态变量中获取 | ||
| 235 | - static int64_t consistency = 0; | ||
| 236 | - static std::once_flag consistencyFlag; | ||
| 237 | - std::call_once(consistencyFlag, [&]() { | ||
| 238 | - aclError retRts = aclrtGetSysParamOpt(ACL_OPT_STRONG_CONSISTENCY, &consistency); | ||
| 239 | - OP_CHECK_NO_RETURN(retRts == ACL_SUCCESS, OP_LOGD("Can not get system param consistency, ret = %d.", retRts)); | ||
| 240 | - }); | ||
| 241 | - | ||
| 242 | - /** | ||
| 243 | - * deterministic level: | ||
| 244 | - * 0: deterministic:0, strong consistency:0 | ||
| 245 | - * 0: deterministic:0, strong consistency:1 | ||
| 246 | - * 1: deterministic:1, strong consistency:0 | ||
| 247 | - * 2: deterministic:1, strong consistency:1 | ||
| 248 | - */ | ||
| 249 | - int32_t deterministicLevel = DETERMINISTIC_LEVEL_NONE; | ||
| 250 | - if (GetThreadLocalContext().opConfigInfo_.isDeterministicOn_) { | ||
| 251 | - deterministicLevel = (consistency == STRONG_CONSISTENCY_ON) ? DETERMINISTIC_LEVEL_HIGH : | ||
| 252 | - DETERMINISTIC_LEVEL_NORMAL; | ||
| 253 | - } | ||
| 254 | - int32_t* deterministicLevelDataInplace = reinterpret_cast<int32_t*>(DeterministicLevel_.data.inplace); | ||
| 255 | - *deterministicLevelDataInplace = deterministicLevel; | ||
| 256 | - OP_LOGD("Get deterministic level success, level = %d, strong consistency = %lld", deterministicLevel, consistency); | ||
| 257 | - | ||
| 258 | OP_CHECK(tilingFuncs->tiling_parse != nullptr, OP_LOGW("Op [%s] has no tiling parse function", opTypeStr_.c_str()), | 222 | OP_CHECK(tilingFuncs->tiling_parse != nullptr, OP_LOGW("Op [%s] has no tiling parse function", opTypeStr_.c_str()), |
| 259 | return ACLNN_SUCCESS); | 223 | return ACLNN_SUCCESS); |
| 260 | 224 | ||
| @@ -36,16 +36,6 @@ class TilingParseCtxHolder { | |||
| 36 | public: | 36 | public: |
| 37 | AsyncAnyValue* GetCompiledInfoStruct() const { return &tilingParseCtxValue_[kCompileInfoStruct]; } | 37 | AsyncAnyValue* GetCompiledInfoStruct() const { return &tilingParseCtxValue_[kCompileInfoStruct]; } |
| 38 | 38 | ||
| 39 | - AsyncAnyValue* GetDeterministic() const | ||
| 40 | - { | ||
| 41 | - *PtrCastTo<int32_t>(Deterministic_.data.inplace) = GetThreadLocalContext().opConfigInfo_.isDeterministicOn_ ? | ||
| 42 | - 1 : | ||
| 43 | - 0; | ||
| 44 | - return const_cast<AsyncAnyValue*>(&Deterministic_); | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - AsyncAnyValue* GetDeterministicLevel() const { return const_cast<AsyncAnyValue*>(&DeterministicLevel_); } | ||
| 48 | - | ||
| 49 | uint32_t GetCoreNum() const { return coreNum_; } | 39 | uint32_t GetCoreNum() const { return coreNum_; } |
| 50 | 40 | ||
| 51 | ~TilingParseCtxHolder(); | 41 | ~TilingParseCtxHolder(); |
| @@ -100,8 +90,6 @@ private: | |||
| 100 | static constexpr size_t MAX_COMPILE_INFO_STRUCT_SIZE = 32 * 1024; | 90 | static constexpr size_t MAX_COMPILE_INFO_STRUCT_SIZE = 32 * 1024; |
| 101 | aclnnOpInfoRecord::OpKernelInfo opKernelInfo_{"", 0}; | 91 | aclnnOpInfoRecord::OpKernelInfo opKernelInfo_{"", 0}; |
| 102 | uint32_t coreNum_{0}; | 92 | uint32_t coreNum_{0}; |
| 103 | - mutable AsyncAnyValue Deterministic_; | ||
| 104 | - AsyncAnyValue DeterministicLevel_; | ||
| 105 | }; | 93 | }; |
| 106 | 94 | ||
| 107 | } // namespace op::internal | 95 | } // namespace op::internal |
| @@ -1,5 +1,5 @@ | |||
| 1 | /** | 1 | /** |
| 2 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 2 | + * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 3 | * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 3 | * This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). | 4 | * CANN Open Software License Agreement Version 2.0 (the "License"). |
| 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. | 5 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| @@ -199,11 +199,17 @@ aclnnStatus TilingCtxHolder::UpdateTilingCtx(const KernelContextHolder* kernelCt | |||
| 199 | UpdateThradLocalPlatformInfo(platformInfo, coreNum, cubeCoreNum, vectorCoreNum); | 199 | UpdateThradLocalPlatformInfo(platformInfo, coreNum, cubeCoreNum, vectorCoreNum); |
| 200 | platformInfoValue_.data.pointer = platformInfo; | 200 | platformInfoValue_.data.pointer = platformInfo; |
| 201 | 201 | ||
| 202 | + *PtrCastTo<int32_t>(deterministicValue_.data.inplace) = GetThreadLocalContext().opConfigInfo_.isDeterministicOn_ ? | ||
| 203 | + 1 : | ||
| 204 | + 0; | ||
| 205 | + *PtrCastTo<int32_t>( | ||
| 206 | + deterministicLevelValue_.data.inplace) = GetThreadLocalContext().opConfigInfo_.deterministicLevel_; | ||
| 207 | + | ||
| 202 | tilingCtx_->values[tilingInputNum - TILING_INPUT_OTHER_NUM] = tilingParseCtx->GetCompiledInfoStruct(); | 208 | tilingCtx_->values[tilingInputNum - TILING_INPUT_OTHER_NUM] = tilingParseCtx->GetCompiledInfoStruct(); |
| 203 | tilingCtx_->values[tilingInputNum - TILING_PLATFORM_IDX] = &platformInfoValue_; | 209 | tilingCtx_->values[tilingInputNum - TILING_PLATFORM_IDX] = &platformInfoValue_; |
| 204 | tilingCtx_->values[tilingInputNum - TILING_FUNC_IDX] = nullptr; | 210 | tilingCtx_->values[tilingInputNum - TILING_FUNC_IDX] = nullptr; |
| 205 | - tilingCtx_->values[tilingInputNum - DETERMINISTIC_IDX] = tilingParseCtx->GetDeterministic(); | 211 | + tilingCtx_->values[tilingInputNum - DETERMINISTIC_IDX] = &deterministicValue_; |
| 206 | - tilingCtx_->values[tilingInputNum - 1] = tilingParseCtx->GetDeterministicLevel(); | 212 | + tilingCtx_->values[tilingInputNum - 1] = &deterministicLevelValue_; |
| 207 | FinalizeTilingCtx(tilingInputNum); | 213 | FinalizeTilingCtx(tilingInputNum); |
| 208 | 214 | ||
| 209 | OP_LOGI("Update op tiling ctx. input[%zu], output[%zu], compiled Info %p, deterministic %d, deterministicLevel %d, " | 215 | OP_LOGI("Update op tiling ctx. input[%zu], output[%zu], compiled Info %p, deterministic %d, deterministicLevel %d, " |
| @@ -191,7 +191,9 @@ private: | |||
| 191 | constexpr static size_t tilingOutputNum_ = kOutputNum; | 191 | constexpr static size_t tilingOutputNum_ = kOutputNum; |
| 192 | KernelRunContext* tilingCtx_{nullptr}; | 192 | KernelRunContext* tilingCtx_{nullptr}; |
| 193 | AsyncAnyValue* tilingCtxValue_{nullptr}; | 193 | AsyncAnyValue* tilingCtxValue_{nullptr}; |
| 194 | - AsyncAnyValue platformInfoValue_; | 194 | + AsyncAnyValue platformInfoValue_{}; |
| 195 | + AsyncAnyValue deterministicValue_{}; | ||
| 196 | + AsyncAnyValue deterministicLevelValue_{}; | ||
| 195 | std::unique_ptr<uint8_t[]> workspaceSizeVec_; | 197 | std::unique_ptr<uint8_t[]> workspaceSizeVec_; |
| 196 | 198 | ||
| 197 | // Dynamic capacity management | 199 | // Dynamic capacity management |
| @@ -261,12 +261,15 @@ aclError aclrtCacheLastTaskOpInfo(const void* const infoPtr, size_t infoSize) | |||
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | int64_t gDeterministicNew = 0; | 263 | int64_t gDeterministicNew = 0; |
| 264 | +int64_t gStrongConsistencyNew = 0; | ||
| 264 | 265 | ||
| 265 | EXTERN_C | 266 | EXTERN_C |
| 266 | aclError aclrtSetSysParamOpt(aclSysParamOpt opt, int64_t value) | 267 | aclError aclrtSetSysParamOpt(aclSysParamOpt opt, int64_t value) |
| 267 | { | 268 | { |
| 268 | if (opt == ACL_OPT_DETERMINISTIC) { | 269 | if (opt == ACL_OPT_DETERMINISTIC) { |
| 269 | gDeterministicNew = value; | 270 | gDeterministicNew = value; |
| 271 | + } else if (opt == ACL_OPT_STRONG_CONSISTENCY) { | ||
| 272 | + gStrongConsistencyNew = value; | ||
| 270 | } | 273 | } |
| 271 | return ACL_SUCCESS; | 274 | return ACL_SUCCESS; |
| 272 | } | 275 | } |
| @@ -276,6 +279,8 @@ aclError aclrtGetSysParamOpt(aclSysParamOpt opt, int64_t* value) | |||
| 276 | { | 279 | { |
| 277 | if (opt == ACL_OPT_DETERMINISTIC) { | 280 | if (opt == ACL_OPT_DETERMINISTIC) { |
| 278 | *value = gDeterministicNew; | 281 | *value = gDeterministicNew; |
| 282 | + } else if (opt == ACL_OPT_STRONG_CONSISTENCY) { | ||
| 283 | + *value = gStrongConsistencyNew; | ||
| 279 | } | 284 | } |
| 280 | return ACL_SUCCESS; | 285 | return ACL_SUCCESS; |
| 281 | } | 286 | } |
| @@ -438,48 +438,102 @@ TEST_F(OpExecutorTest, phase1ParamCheckTest) | |||
| 438 | delete ptr; | 438 | delete ptr; |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | -static void L2Phase2Func(const char* apiName, aclOpExecutor* executor, const int64_t configVal) | 441 | +static void L2Phase2Func(const char* apiName, aclOpExecutor* executor, int32_t expectedLevel) |
| 442 | { | 442 | { |
| 443 | std::cout << "phase2 thread id: " << std::this_thread::get_id() << std::endl; | 443 | std::cout << "phase2 thread id: " << std::this_thread::get_id() << std::endl; |
| 444 | InitL2Phase2Context(apiName, executor); | 444 | InitL2Phase2Context(apiName, executor); |
| 445 | - EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, (configVal == 1)); | 445 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, expectedLevel); |
| 446 | - EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, (configVal == 1)); | 446 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, expectedLevel); |
| 447 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, (expectedLevel >= 1)); | ||
| 448 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, (expectedLevel >= 1)); | ||
| 447 | } | 449 | } |
| 448 | 450 | ||
| 449 | TEST_F(OpExecutorTest, DeterministicTest) | 451 | TEST_F(OpExecutorTest, DeterministicTest) |
| 450 | { | 452 | { |
| 451 | - std::cout << "phase1 thread id: " << std::this_thread::get_id() << std::endl; | ||
| 452 | const char* apiName = "aclnnArgsort"; | 453 | const char* apiName = "aclnnArgsort"; |
| 453 | - int64_t deterministicValue = 0; | ||
| 454 | - aclrtGetSysParamOpt(ACL_OPT_DETERMINISTIC, &deterministicValue); | ||
| 455 | - std::cout << "deterministic value: " << deterministicValue << std::endl; | ||
| 456 | 454 | ||
| 457 | - aclOpExecutor* executor = nullptr; | 455 | + // 子用例 1:level=0(关闭) |
| 458 | - InitL2Phase1Context(apiName, &executor); | 456 | + { |
| 459 | - EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, (deterministicValue == 1)); | 457 | + aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, 0); |
| 460 | - auto uniqueExecutor = CREATE_EXECUTOR(); | 458 | + aclrtSetSysParamOpt(ACL_OPT_STRONG_CONSISTENCY, 0); |
| 461 | - uniqueExecutor.ReleaseTo(&executor); | 459 | + aclOpExecutor* executor = nullptr; |
| 462 | - EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, (deterministicValue == 1)); | 460 | + InitL2Phase1Context(apiName, &executor); |
| 461 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, 0); | ||
| 462 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, false); | ||
| 463 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 464 | + uniqueExecutor.ReleaseTo(&executor); | ||
| 465 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, 0); | ||
| 466 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, false); | ||
| 467 | + std::thread t(L2Phase2Func, apiName, executor, 0); | ||
| 468 | + t.join(); | ||
| 469 | + delete executor; | ||
| 470 | + } | ||
| 463 | 471 | ||
| 464 | - std::thread t(L2Phase2Func, apiName, executor, deterministicValue); | 472 | + // 子用例 2:level=1(仅确定性,consistency=0 不升级) |
| 465 | - t.join(); | 473 | + { |
| 466 | - delete executor; | 474 | + aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, 1); |
| 475 | + aclrtSetSysParamOpt(ACL_OPT_STRONG_CONSISTENCY, 0); | ||
| 476 | + aclOpExecutor* executor = nullptr; | ||
| 477 | + InitL2Phase1Context(apiName, &executor); | ||
| 478 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, 1); | ||
| 479 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, true); | ||
| 480 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 481 | + uniqueExecutor.ReleaseTo(&executor); | ||
| 482 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, 1); | ||
| 483 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, true); | ||
| 484 | + std::thread t(L2Phase2Func, apiName, executor, 1); | ||
| 485 | + t.join(); | ||
| 486 | + delete executor; | ||
| 487 | + } | ||
| 467 | 488 | ||
| 468 | - executor = nullptr; | 489 | + // 子用例 3:level=2(强一致性,新 runtime 直接返回) |
| 469 | - deterministicValue = (deterministicValue == 0) ? 1 : 0; | 490 | + { |
| 470 | - aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, deterministicValue); | 491 | + aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, 2); |
| 471 | - InitL2Phase1Context(apiName, &executor); | 492 | + aclOpExecutor* executor = nullptr; |
| 472 | - EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, (deterministicValue == 1)); | 493 | + InitL2Phase1Context(apiName, &executor); |
| 473 | - auto uniqueExecutor2 = CREATE_EXECUTOR(); | 494 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, 2); |
| 474 | - uniqueExecutor2.ReleaseTo(&executor); | 495 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, true); |
| 475 | - EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, (deterministicValue == 1)); | 496 | + auto uniqueExecutor = CREATE_EXECUTOR(); |
| 497 | + uniqueExecutor.ReleaseTo(&executor); | ||
| 498 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, 2); | ||
| 499 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, true); | ||
| 500 | + std::thread t(L2Phase2Func, apiName, executor, 2); | ||
| 501 | + t.join(); | ||
| 502 | + delete executor; | ||
| 503 | + } | ||
| 476 | 504 | ||
| 477 | - std::thread t2(L2Phase2Func, apiName, executor, deterministicValue); | 505 | + // 子用例 4:老 runtime 回退路径(deterministic=1 + consistency=1 → 升级为 2) |
| 478 | - t2.join(); | 506 | + { |
| 479 | - delete executor; | 507 | + aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, 1); |
| 508 | + aclrtSetSysParamOpt(ACL_OPT_STRONG_CONSISTENCY, 1); | ||
| 509 | + aclOpExecutor* executor = nullptr; | ||
| 510 | + InitL2Phase1Context(apiName, &executor); | ||
| 511 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, 2); | ||
| 512 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, true); | ||
| 513 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 514 | + uniqueExecutor.ReleaseTo(&executor); | ||
| 515 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, 2); | ||
| 516 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, true); | ||
| 517 | + std::thread t(L2Phase2Func, apiName, executor, 2); | ||
| 518 | + t.join(); | ||
| 519 | + delete executor; | ||
| 520 | + } | ||
| 480 | 521 | ||
| 481 | - deterministicValue = (deterministicValue == 0) ? 1 : 0; | 522 | + // 子用例 5:level=3(batch 一致性,新 runtime 路径) |
| 482 | - aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, deterministicValue); | 523 | + { |
| 524 | + aclrtSetSysParamOpt(ACL_OPT_DETERMINISTIC, 3); | ||
| 525 | + aclOpExecutor* executor = nullptr; | ||
| 526 | + InitL2Phase1Context(apiName, &executor); | ||
| 527 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_, 3); | ||
| 528 | + EXPECT_EQ(op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_, true); | ||
| 529 | + auto uniqueExecutor = CREATE_EXECUTOR(); | ||
| 530 | + uniqueExecutor.ReleaseTo(&executor); | ||
| 531 | + EXPECT_EQ(executor->GetOpConfigInfo().deterministicLevel_, 3); | ||
| 532 | + EXPECT_EQ(executor->GetOpConfigInfo().isDeterministicOn_, true); | ||
| 533 | + std::thread t(L2Phase2Func, apiName, executor, 3); | ||
| 534 | + t.join(); | ||
| 535 | + delete executor; | ||
| 536 | + } | ||
| 483 | } | 537 | } |
| 484 | 538 | ||
| 485 | // ============================================================================ | 539 | // ============================================================================ |
| @@ -38,10 +38,15 @@ | |||
| 38 | 38 | ||
| 39 | typedef std::function<void(void)> Functional; | 39 | typedef std::function<void(void)> Functional; |
| 40 | 40 | ||
| 41 | +extern inline uint32_t AxpyOpTypeId(); | ||
| 42 | +extern inline uint32_t SortOpTypeId(); | ||
| 43 | + | ||
| 41 | class TilingCtxBuildUT : public testing::Test { | 44 | class TilingCtxBuildUT : public testing::Test { |
| 42 | protected: | 45 | protected: |
| 43 | static void SetUpTestCase() | 46 | static void SetUpTestCase() |
| 44 | { | 47 | { |
| 48 | + AxpyOpTypeId(); | ||
| 49 | + SortOpTypeId(); | ||
| 45 | // aclInit(nullptr) | 50 | // aclInit(nullptr) |
| 46 | setenv("ASCEND_OPP_PATH", OP_API_COMMON_UT_SRC_DIR, 1); // does overwrite | 51 | setenv("ASCEND_OPP_PATH", OP_API_COMMON_UT_SRC_DIR, 1); // does overwrite |
| 47 | op::internal::GetThreadLocalContext().cacheHasFull_ = true; | 52 | op::internal::GetThreadLocalContext().cacheHasFull_ = true; |
| @@ -413,7 +418,7 @@ static void SetCoreNumTest310PMIXAIV() | |||
| 413 | PlatformInfoStub::GetInstance()->Reset(); | 418 | PlatformInfoStub::GetInstance()->Reset(); |
| 414 | } | 419 | } |
| 415 | 420 | ||
| 416 | -TEST_F(TilingCtxBuildUT, TilingCtxBuildUT_StringATTR) | 421 | +TEST_F(TilingCtxBuildUT, TilingCtxBuildUT_AttrTypes) |
| 417 | { | 422 | { |
| 418 | op::Shape selfShape{33, 15, 1, 48}; | 423 | op::Shape selfShape{33, 15, 1, 48}; |
| 419 | op::Shape otherShape{33, 15, 14, 48}; | 424 | op::Shape otherShape{33, 15, 14, 48}; |
| @@ -421,23 +426,59 @@ TEST_F(TilingCtxBuildUT, TilingCtxBuildUT_StringATTR) | |||
| 421 | 426 | ||
| 422 | auto self = std::make_unique<aclTensor>(selfShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | 427 | auto self = std::make_unique<aclTensor>(selfShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); |
| 423 | auto other = std::make_unique<aclTensor>(otherShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | 428 | auto other = std::make_unique<aclTensor>(otherShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); |
| 424 | - float alpha = 13.37; | ||
| 425 | auto out = std::make_unique<aclTensor>(outShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | 429 | auto out = std::make_unique<aclTensor>(outShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); |
| 426 | 430 | ||
| 431 | + // 构造覆盖 dispatch 全部 9 个 case 分支的 attr 值 | ||
| 432 | + bool boolVal = true; | ||
| 433 | + int32_t intVal = 123; | ||
| 434 | + uint32_t uintVal = 456u; | ||
| 435 | + float floatVal = 1.5f; | ||
| 436 | + double doubleVal = 2.5; | ||
| 437 | + op::DataType dtVal = op::DataType::DT_FLOAT; | ||
| 438 | + op::OpImplMode modeVal = op::OpImplMode::IMPL_MODE_HIGH_PERFORMANCE; | ||
| 439 | + const char* strVal = "hello"; | ||
| 440 | + | ||
| 441 | + int64_t scalarData = 42; | ||
| 442 | + auto scalar = std::make_unique<aclScalar>(&scalarData, op::DataType::DT_INT64); | ||
| 443 | + aclScalar* scalarVal = scalar.get(); | ||
| 444 | + | ||
| 445 | + int64_t intArrData[] = {1, 2, 3}; | ||
| 446 | + aclIntArray intArrVal(intArrData, 3); | ||
| 447 | + | ||
| 448 | + float floatArrData[] = {1.1f, 2.2f}; | ||
| 449 | + aclFloatArray floatArrVal(floatArrData, 2); | ||
| 450 | + | ||
| 451 | + bool boolArrData[] = {true, false}; | ||
| 452 | + aclBoolArray boolArrVal(boolArrData, 2); | ||
| 453 | + | ||
| 427 | uint32_t opType = op::OpTypeDict::ToOpType("Axpy"); | 454 | uint32_t opType = op::OpTypeDict::ToOpType("Axpy"); |
| 428 | auto input = OP_INPUT(self.get(), other.get()); | 455 | auto input = OP_INPUT(self.get(), other.get()); |
| 429 | auto output = OP_OUTPUT(out.get()); | 456 | auto output = OP_OUTPUT(out.get()); |
| 430 | - auto attr = OP_ATTR(alpha); | 457 | + auto attr = OP_ATTR(boolVal, intVal, uintVal, floatVal, doubleVal, dtVal, modeVal, strVal, scalarVal, &intArrVal, |
| 458 | + &floatArrVal, &boolArrVal); | ||
| 431 | auto ws = OP_WORKSPACE(out.get()); | 459 | auto ws = OP_WORKSPACE(out.get()); |
| 460 | + auto ctx = op::MakeOpArgContext(input, output, attr, ws); | ||
| 432 | 461 | ||
| 433 | ge::AscendString opTypeAscendStr = op::OpTypeDict::ToString(opType); | 462 | ge::AscendString opTypeAscendStr = op::OpTypeDict::ToString(opType); |
| 434 | const char* opTypeStr = opTypeAscendStr.GetString(); | 463 | const char* opTypeStr = opTypeAscendStr.GetString(); |
| 435 | - string attrs = "1234"; | 464 | + |
| 436 | - int64_t v = 7; | 465 | + // 第一部分:UpdateComputeNodeInfo 内部走 attr.VisitBy → UpdateAttrArg(OpArg&) → dispatch → 各具体重载 |
| 437 | - op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateAttrDefOffset(3, 1); | 466 | + // 覆盖:VisitBy 遍历、dispatch switch 的全部 9 个 case、EnsureAttrCapacity、attrDef_->offset[idx] |
| 438 | - auto res = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateAttrArg( | 467 | + auto res = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateComputeNodeInfo( |
| 439 | - 0, v, op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.attrDataStart_); | 468 | + opTypeStr, *ctx->GetOpArg(op::OpArgDef::OP_INPUT_ARG), *ctx->GetOpArg(op::OpArgDef::OP_OUTPUT_ARG), |
| 469 | + *ctx->GetOpArg(op::OpArgDef::OP_ATTR_ARG)); | ||
| 440 | EXPECT_EQ(res, ACLNN_SUCCESS); | 470 | EXPECT_EQ(res, ACLNN_SUCCESS); |
| 471 | + op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateKernelExtendInfo(opTypeStr, opTypeStr); | ||
| 472 | + | ||
| 473 | + // 第二部分:验证不支持的数据类型走 dispatch default 分支返回错误 | ||
| 474 | + // OPARG_UINT_LIST 在 UpdateAttrArg switch 中无对应 case,走 default 容错分支 | ||
| 475 | + op::OpArg badArg; | ||
| 476 | + badArg.type = op::OpArgType::OPARG_UINT_LIST; | ||
| 477 | + void* attrPtr = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.attrDataStart_; | ||
| 478 | + auto badRes = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateAttrArg(0, badArg, attrPtr); | ||
| 479 | + EXPECT_NE(badRes, ACLNN_SUCCESS); | ||
| 480 | + | ||
| 481 | + op::DestroyOpArgContext(ctx); | ||
| 441 | } | 482 | } |
| 442 | 483 | ||
| 443 | TEST_F(TilingCtxBuildUT, TilingCtxMultiThreadTest) | 484 | TEST_F(TilingCtxBuildUT, TilingCtxMultiThreadTest) |
| @@ -489,12 +530,38 @@ static void TilingCtxBuildLaunchOneThread(op::internal::OpKernelBin* opKernelBin | |||
| 489 | *ctx->GetOpArg(op::OpArgDef::OP_ATTR_ARG)); | 530 | *ctx->GetOpArg(op::OpArgDef::OP_ATTR_ARG)); |
| 490 | op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateKernelExtendInfo(opTypeStr, opTypeStr); | 531 | op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateKernelExtendInfo(opTypeStr, opTypeStr); |
| 491 | 532 | ||
| 533 | + // 设置本线程独立的 deterministicLevel,验证多线程场景下每个线程能读到自己的值 | ||
| 534 | + // 不同线程设置不同 level(基于线程 ID hash),验证每个线程读到自己的值而非其他线程覆盖的值 | ||
| 535 | + int8_t myLevel = static_cast<int8_t>(std::hash<std::thread::id>{}(std::this_thread::get_id()) % 4); | ||
| 536 | + op::internal::GetThreadLocalContext().opConfigInfo_.deterministicLevel_ = myLevel; | ||
| 537 | + op::internal::GetThreadLocalContext().opConfigInfo_.isDeterministicOn_ = (myLevel >= 1); | ||
| 538 | + | ||
| 492 | uint32_t aic = op::internal::GetThreadLocalContext().opConfigInfo_.aicNum_; | 539 | uint32_t aic = op::internal::GetThreadLocalContext().opConfigInfo_.aicNum_; |
| 493 | uint32_t aiv = op::internal::GetThreadLocalContext().opConfigInfo_.aivNum_; | 540 | uint32_t aiv = op::internal::GetThreadLocalContext().opConfigInfo_.aivNum_; |
| 494 | auto res = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.UpdateTilingCtx( | 541 | auto res = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.UpdateTilingCtx( |
| 495 | &(op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_), | 542 | &(op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_), |
| 496 | opKernelBin->tilingParseCtxHolder_[op::internal::ThreadCoreNum(aic, aiv)].get()); | 543 | opKernelBin->tilingParseCtxHolder_[op::internal::ThreadCoreNum(aic, aiv)].get()); |
| 497 | EXPECT_EQ(res, ACLNN_SUCCESS); | 544 | EXPECT_EQ(res, ACLNN_SUCCESS); |
| 545 | + | ||
| 546 | + // 验证 tilingCtx 中的 deterministic / deterministicLevel 与本线程设置的一致 | ||
| 547 | + // deterministicValue_ / deterministicLevelValue_ 是 TilingCtxHolder 的 thread_local 成员, | ||
| 548 | + // 每个线程应读到自己设置的值,而非其他线程覆盖的值 | ||
| 549 | + size_t opInputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.inputNum_; | ||
| 550 | + size_t opOutputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.outputNum_; | ||
| 551 | + constexpr size_t TILING_INPUT_OTHER_NUM = 5; | ||
| 552 | + constexpr size_t DETERMINISTIC_IDX = 2; | ||
| 553 | + size_t tilingInputNum = opInputNum + opOutputNum + TILING_INPUT_OTHER_NUM; | ||
| 554 | + | ||
| 555 | + auto* deterministicPtr = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 556 | + ->values[tilingInputNum - DETERMINISTIC_IDX]; | ||
| 557 | + int32_t deterministicVal = *reinterpret_cast<int32_t*>(deterministicPtr->data.inplace); | ||
| 558 | + auto* deterministicLevelPtr = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 559 | + ->values[tilingInputNum - 1]; | ||
| 560 | + int32_t deterministicLevelVal = *reinterpret_cast<int32_t*>(deterministicLevelPtr->data.inplace); | ||
| 561 | + | ||
| 562 | + EXPECT_EQ(deterministicLevelVal, myLevel); | ||
| 563 | + EXPECT_EQ(deterministicVal, (myLevel >= 1) ? 1 : 0); | ||
| 564 | + | ||
| 498 | op::DestroyOpArgContext(ctx); | 565 | op::DestroyOpArgContext(ctx); |
| 499 | } | 566 | } |
| 500 | 567 | ||
| @@ -551,206 +618,6 @@ TEST_F(TilingCtxBuildUT, TilingCtxMultiThreadTest3) | |||
| 551 | delete fakeBin; | 618 | delete fakeBin; |
| 552 | } | 619 | } |
| 553 | 620 | ||
| 554 | -// 测试 deterministicLevel 参数的传递和获取 | ||
| 555 | -static void TilingCtxDeterministicLevelTest() | ||
| 556 | -{ | ||
| 557 | - op::Shape selfShape{33, 15, 1, 48}; | ||
| 558 | - op::Shape otherShape{33, 15, 14, 48}; | ||
| 559 | - op::Shape outShape{33, 15, 14, 48}; | ||
| 560 | - | ||
| 561 | - auto self = std::make_unique<aclTensor>(selfShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | ||
| 562 | - auto other = std::make_unique<aclTensor>(otherShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | ||
| 563 | - float alpha = 13.37; | ||
| 564 | - auto out = std::make_unique<aclTensor>(outShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | ||
| 565 | - | ||
| 566 | - uint32_t opType = op::OpTypeDict::ToOpType("Axpy"); | ||
| 567 | - auto input = OP_INPUT(self.get(), other.get()); | ||
| 568 | - auto output = OP_OUTPUT(out.get()); | ||
| 569 | - auto attr = OP_ATTR(alpha); | ||
| 570 | - auto ws = OP_WORKSPACE(out.get()); | ||
| 571 | - | ||
| 572 | - const char* p = std::getenv("ASCEND_OPP_PATH"); | ||
| 573 | - EXPECT_NE(p, nullptr); | ||
| 574 | - op::internal::KeyAndDetail key; | ||
| 575 | - key.key = "hahaha"; | ||
| 576 | - size_t hashKey = 125; | ||
| 577 | - char jsonPath[1024]; | ||
| 578 | - char binPath[1024]; | ||
| 579 | - snprintf_s(jsonPath, sizeof(jsonPath), sizeof(jsonPath), | ||
| 580 | - "%s/built-in/op_impl/ai_core/tbe/kernel/ascend910/axpy/" | ||
| 581 | - "Axpy_233851a3505389e43928a8bba133a74d_high_performance.json", | ||
| 582 | - p); | ||
| 583 | - snprintf_s(binPath, sizeof(binPath), sizeof(binPath), | ||
| 584 | - "%s/built-in/op_impl/ai_core/tbe/kernel/ascend910/axpy/" | ||
| 585 | - "Axpy_233851a3505389e43928a8bba133a74d_high_performance.o", | ||
| 586 | - p); | ||
| 587 | - | ||
| 588 | - op::internal::OpKernelBin kernelBin(opType, jsonPath, jsonPath, binPath, key, hashKey, | ||
| 589 | - op::internal::BinType::DYNAMIC_BIN, false, false); | ||
| 590 | - EXPECT_EQ(kernelBin.InitTilingParseCtx(), ACLNN_SUCCESS); | ||
| 591 | - | ||
| 592 | - auto ctx = op::MakeOpArgContext(input, output, attr, ws); | ||
| 593 | - ge::AscendString opTypeAscendStr = op::OpTypeDict::ToString(opType); | ||
| 594 | - const char* opTypeStr = opTypeAscendStr.GetString(); | ||
| 595 | - op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateComputeNodeInfo( | ||
| 596 | - opTypeStr, *ctx->GetOpArg(op::OpArgDef::OP_INPUT_ARG), *ctx->GetOpArg(op::OpArgDef::OP_OUTPUT_ARG), | ||
| 597 | - *ctx->GetOpArg(op::OpArgDef::OP_ATTR_ARG)); | ||
| 598 | - op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateKernelExtendInfo(opTypeStr, opTypeStr); | ||
| 599 | - | ||
| 600 | - uint32_t aic = op::internal::GetThreadLocalContext().opConfigInfo_.aicNum_; | ||
| 601 | - uint32_t aiv = op::internal::GetThreadLocalContext().opConfigInfo_.aivNum_; | ||
| 602 | - | ||
| 603 | - // 获取 tilingParseCtxHolder | ||
| 604 | - auto* tilingParseCtxHolder = kernelBin.tilingParseCtxHolder_[op::internal::ThreadCoreNum(aic, aiv)].get(); | ||
| 605 | - EXPECT_NE(tilingParseCtxHolder, nullptr); | ||
| 606 | - | ||
| 607 | - // 验证 GetDeterministicLevel() 方法可以正确返回指针 | ||
| 608 | - auto* deterministicLevelValue = tilingParseCtxHolder->GetDeterministicLevel(); | ||
| 609 | - EXPECT_NE(deterministicLevelValue, nullptr); | ||
| 610 | - | ||
| 611 | - // 验证 GetDeterministic() 方法可以正确返回指针 | ||
| 612 | - auto* deterministicValue = tilingParseCtxHolder->GetDeterministic(); | ||
| 613 | - EXPECT_NE(deterministicValue, nullptr); | ||
| 614 | - | ||
| 615 | - // 更新 tiling context | ||
| 616 | - auto res = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.UpdateTilingCtx( | ||
| 617 | - &(op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_), tilingParseCtxHolder); | ||
| 618 | - EXPECT_EQ(res, ACLNN_SUCCESS); | ||
| 619 | - | ||
| 620 | - // 验证 tilingCtx 中正确设置了 deterministic 和 deterministicLevel | ||
| 621 | - size_t opInputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.inputNum_; | ||
| 622 | - size_t opOutputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.outputNum_; | ||
| 623 | - constexpr size_t TILING_INPUT_OTHER_NUM = 5; | ||
| 624 | - constexpr size_t DETERMINISTIC_IDX = 2; | ||
| 625 | - size_t tilingInputNum = opInputNum + opOutputNum + TILING_INPUT_OTHER_NUM; | ||
| 626 | - | ||
| 627 | - // 验证 deterministic 值的正确性 | ||
| 628 | - auto* deterministicPtr = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 629 | - ->values[tilingInputNum - DETERMINISTIC_IDX]; | ||
| 630 | - EXPECT_NE(deterministicPtr, nullptr); | ||
| 631 | - int32_t deterministicVal = *reinterpret_cast<int32_t*>(deterministicPtr->data.inplace); | ||
| 632 | - EXPECT_GE(deterministicVal, 0); // 验证值为非负 | ||
| 633 | - EXPECT_LE(deterministicVal, 1); // deterministic 值为 0 或 1 | ||
| 634 | - | ||
| 635 | - // 验证 deterministicLevel 值的正确性 | ||
| 636 | - auto* deterministicLevelPtr = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 637 | - ->values[tilingInputNum - 1]; | ||
| 638 | - EXPECT_NE(deterministicLevelPtr, nullptr); | ||
| 639 | - int32_t deterministicLevelVal = *reinterpret_cast<int32_t*>(deterministicLevelPtr->data.inplace); | ||
| 640 | - EXPECT_GE(deterministicLevelVal, 0); // Level 范围是 0-2 | ||
| 641 | - EXPECT_LE(deterministicLevelVal, 2); | ||
| 642 | - | ||
| 643 | - // 验证 deterministicLevel 的逻辑正确性 | ||
| 644 | - // Level 0: deterministic=0 (consistency=0 或 consistency=1) | ||
| 645 | - // Level 1: deterministic=1, consistency=0 | ||
| 646 | - // Level 2: deterministic=1, consistency=1 | ||
| 647 | - if (deterministicVal == 0) { | ||
| 648 | - // deterministic=0 时,无论 consistency 值如何,level 都为 0 | ||
| 649 | - EXPECT_EQ(deterministicLevelVal, 0); | ||
| 650 | - } else { | ||
| 651 | - // deterministic=1 时,根据 consistency 值决定 level 是 1 或 2 | ||
| 652 | - EXPECT_GE(deterministicLevelVal, 1); | ||
| 653 | - EXPECT_LE(deterministicLevelVal, 2); | ||
| 654 | - } | ||
| 655 | - | ||
| 656 | - OP_LOGI("TilingCtxDeterministicLevelTest: deterministic = %d, deterministicLevel = %d", deterministicVal, | ||
| 657 | - deterministicLevelVal); | ||
| 658 | - | ||
| 659 | - for (auto& [key, value] : kernelBin.tilingParseCtxHolder_) { | ||
| 660 | - if (value.get()) { | ||
| 661 | - value.get()->ReleaseTilingParse(); | ||
| 662 | - } | ||
| 663 | - } | ||
| 664 | - op::DestroyOpArgContext(ctx); | ||
| 665 | -} | ||
| 666 | - | ||
| 667 | -// 测试 deterministicLevel 参数的线程安全性 | ||
| 668 | -static void TilingCtxDeterministicLevelThreadSafetyTest() | ||
| 669 | -{ | ||
| 670 | - op::Shape selfShape{16, 32, 64}; | ||
| 671 | - op::Shape outShape{16, 32, 64}; | ||
| 672 | - | ||
| 673 | - auto self = std::make_unique<aclTensor>(selfShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | ||
| 674 | - auto out = std::make_unique<aclTensor>(outShape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND, nullptr); | ||
| 675 | - | ||
| 676 | - uint32_t opType = op::OpTypeDict::ToOpType("Axpy"); | ||
| 677 | - auto input = OP_INPUT(self.get()); | ||
| 678 | - auto output = OP_OUTPUT(out.get()); | ||
| 679 | - auto attr = OP_ATTR(1.0f); | ||
| 680 | - auto ws = OP_WORKSPACE(out.get()); | ||
| 681 | - | ||
| 682 | - const char* p = std::getenv("ASCEND_OPP_PATH"); | ||
| 683 | - EXPECT_NE(p, nullptr); | ||
| 684 | - op::internal::KeyAndDetail key; | ||
| 685 | - key.key = "hahaha"; | ||
| 686 | - size_t hashKey = 125; | ||
| 687 | - char jsonPath[1024]; | ||
| 688 | - char binPath[1024]; | ||
| 689 | - snprintf_s(jsonPath, sizeof(jsonPath), sizeof(jsonPath), | ||
| 690 | - "%s/built-in/op_impl/ai_core/tbe/kernel/ascend910/axpy/" | ||
| 691 | - "Axpy_233851a3505389e43928a8bba133a74d_high_performance.json", | ||
| 692 | - p); | ||
| 693 | - snprintf_s(binPath, sizeof(binPath), sizeof(binPath), | ||
| 694 | - "%s/built-in/op_impl/ai_core/tbe/kernel/ascend910/axpy/" | ||
| 695 | - "Axpy_233851a3505389e43928a8bba133a74d_high_performance.o", | ||
| 696 | - p); | ||
| 697 | - | ||
| 698 | - op::internal::OpKernelBin kernelBin(opType, jsonPath, jsonPath, binPath, key, hashKey, | ||
| 699 | - op::internal::BinType::DYNAMIC_BIN, false, false); | ||
| 700 | - EXPECT_EQ(kernelBin.InitTilingParseCtx(), ACLNN_SUCCESS); | ||
| 701 | - | ||
| 702 | - auto ctx = op::MakeOpArgContext(input, output, attr, ws); | ||
| 703 | - ge::AscendString opTypeAscendStr = op::OpTypeDict::ToString(opType); | ||
| 704 | - const char* opTypeStr = opTypeAscendStr.GetString(); | ||
| 705 | - op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateComputeNodeInfo( | ||
| 706 | - opTypeStr, *ctx->GetOpArg(op::OpArgDef::OP_INPUT_ARG), *ctx->GetOpArg(op::OpArgDef::OP_OUTPUT_ARG), | ||
| 707 | - *ctx->GetOpArg(op::OpArgDef::OP_ATTR_ARG)); | ||
| 708 | - op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.UpdateKernelExtendInfo(opTypeStr, opTypeStr); | ||
| 709 | - | ||
| 710 | - uint32_t aic = op::internal::GetThreadLocalContext().opConfigInfo_.aicNum_; | ||
| 711 | - uint32_t aiv = op::internal::GetThreadLocalContext().opConfigInfo_.aivNum_; | ||
| 712 | - auto* tilingParseCtxHolder = kernelBin.tilingParseCtxHolder_[op::internal::ThreadCoreNum(aic, aiv)].get(); | ||
| 713 | - EXPECT_NE(tilingParseCtxHolder, nullptr); | ||
| 714 | - | ||
| 715 | - // 多次调用 UpdateTilingCtx 验证 deterministicLevel 值的一致性 | ||
| 716 | - auto res1 = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.UpdateTilingCtx( | ||
| 717 | - &(op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_), tilingParseCtxHolder); | ||
| 718 | - EXPECT_EQ(res1, ACLNN_SUCCESS); | ||
| 719 | - | ||
| 720 | - size_t opInputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.inputNum_; | ||
| 721 | - size_t opOutputNum = op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_.outputNum_; | ||
| 722 | - constexpr size_t TILING_INPUT_OTHER_NUM = 5; | ||
| 723 | - size_t tilingInputNum = opInputNum + opOutputNum + TILING_INPUT_OTHER_NUM; | ||
| 724 | - | ||
| 725 | - auto* deterministicLevelPtr1 = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 726 | - ->values[tilingInputNum - 1]; | ||
| 727 | - EXPECT_NE(deterministicLevelPtr1, nullptr); | ||
| 728 | - int32_t deterministicLevelVal1 = *reinterpret_cast<int32_t*>(deterministicLevelPtr1->data.inplace); | ||
| 729 | - | ||
| 730 | - // 再次调用,验证 deterministicLevel 值是否一致(因为使用静态变量和 call_once) | ||
| 731 | - auto res2 = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.UpdateTilingCtx( | ||
| 732 | - &(op::internal::OpRunContextMgr::opRunCtx_.kernelCtx_), tilingParseCtxHolder); | ||
| 733 | - EXPECT_EQ(res2, ACLNN_SUCCESS); | ||
| 734 | - | ||
| 735 | - auto* deterministicLevelPtr2 = op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_ | ||
| 736 | - ->values[tilingInputNum - 1]; | ||
| 737 | - EXPECT_NE(deterministicLevelPtr2, nullptr); | ||
| 738 | - int32_t deterministicLevelVal2 = *reinterpret_cast<int32_t*>(deterministicLevelPtr2->data.inplace); | ||
| 739 | - | ||
| 740 | - // 验证两次获取的 deterministicLevel 值相同 | ||
| 741 | - EXPECT_EQ(deterministicLevelVal1, deterministicLevelVal2); | ||
| 742 | - | ||
| 743 | - OP_LOGI("TilingCtxDeterministicLevelThreadSafetyTest: deterministicLevelVal1 = %d, deterministicLevelVal2 = %d", | ||
| 744 | - deterministicLevelVal1, deterministicLevelVal2); | ||
| 745 | - | ||
| 746 | - for (auto& [key, value] : kernelBin.tilingParseCtxHolder_) { | ||
| 747 | - if (value.get()) { | ||
| 748 | - value.get()->ReleaseTilingParse(); | ||
| 749 | - } | ||
| 750 | - } | ||
| 751 | - op::DestroyOpArgContext(ctx); | ||
| 752 | -} | ||
| 753 | - | ||
| 754 | // 测试 deterministicLevel 参数在没有 tilingParseCtx 时的行为 | 621 | // 测试 deterministicLevel 参数在没有 tilingParseCtx 时的行为 |
| 755 | static void TilingCtxDeterministicLevelNullTest() | 622 | static void TilingCtxDeterministicLevelNullTest() |
| 756 | { | 623 | { |
| @@ -792,41 +659,20 @@ static void TilingCtxDeterministicLevelNullTest() | |||
| 792 | nullptr); // CompiledInfoStruct | 659 | nullptr); // CompiledInfoStruct |
| 793 | EXPECT_EQ( | 660 | EXPECT_EQ( |
| 794 | op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - TILING_PLATFORM_IDX], | 661 | op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - TILING_PLATFORM_IDX], |
| 795 | - nullptr); // PlatformInfo | 662 | + nullptr); // PlatformInfo |
| 796 | EXPECT_EQ(op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - TILING_FUNC_IDX], | 663 | EXPECT_EQ(op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - TILING_FUNC_IDX], |
| 797 | nullptr); // TilingFunc | 664 | nullptr); // TilingFunc |
| 798 | EXPECT_EQ( | 665 | EXPECT_EQ( |
| 799 | op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - DETERMINISTIC_IDX], | 666 | op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - DETERMINISTIC_IDX], |
| 800 | - nullptr); // Deterministic | 667 | + nullptr); // Deterministic |
| 801 | EXPECT_EQ(op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - 1], | 668 | EXPECT_EQ(op::internal::OpRunContextMgr::opRunCtx_.tilingCtx_.tilingCtx_->values[tilingInputNum - 1], |
| 802 | nullptr); // DeterministicLevel | 669 | nullptr); // DeterministicLevel |
| 803 | 670 | ||
| 804 | op::DestroyOpArgContext(ctx); | 671 | op::DestroyOpArgContext(ctx); |
| 805 | } | 672 | } |
| 806 | 673 | ||
| 807 | -TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelParameterTest) { TilingCtxDeterministicLevelTest(); } | ||
| 808 | - | ||
| 809 | -TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelThreadSafetyTest) { TilingCtxDeterministicLevelThreadSafetyTest(); } | ||
| 810 | - | ||
| 811 | TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelNullTest) { TilingCtxDeterministicLevelNullTest(); } | 674 | TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelNullTest) { TilingCtxDeterministicLevelNullTest(); } |
| 812 | 675 | ||
| 813 | -TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelMultiThreadTest) | ||
| 814 | -{ | ||
| 815 | - vector<Functional> funVec = {TilingCtxDeterministicLevelTest, TilingCtxDeterministicLevelThreadSafetyTest, | ||
| 816 | - TilingCtxDeterministicLevelNullTest}; | ||
| 817 | - std::random_device rd; | ||
| 818 | - std::mt19937 gen(rd()); | ||
| 819 | - std::uniform_int_distribution<> distrib(0, funVec.size() - 1); | ||
| 820 | - const uint64_t threadCount = 50; | ||
| 821 | - vector<std::thread> threadVec; | ||
| 822 | - for (int i = 0; i < threadCount; i++) { | ||
| 823 | - threadVec.emplace_back(std::thread(funVec[distrib(gen)])); | ||
| 824 | - } | ||
| 825 | - for (int i = 0; i < threadCount; i++) { | ||
| 826 | - threadVec[i].join(); | ||
| 827 | - } | ||
| 828 | -} | ||
| 829 | - | ||
| 830 | // 测试静态bin场景下 UpdateTilingCtx(kernelCtx, opJson) 函数 | 676 | // 测试静态bin场景下 UpdateTilingCtx(kernelCtx, opJson) 函数 |
| 831 | static void UpdateTilingCtxWithOpJsonTest() | 677 | static void UpdateTilingCtxWithOpJsonTest() |
| 832 | { | 678 | { |