已合并
支持确定性计算与一致性开关动态生效 #631
ren-botao创建于 7月9日
支持确定性计算与一致性开关动态生效 #631
已合并
ren-botao创建于 7月9日
共 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 of3+ * 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_H11#ifndef OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H
12#define OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H12#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 op48} // namespace op
46 49 
47-#endif // OP_API_OP_API_COMMON_INC_OPDEV_OP_CONFIG_H50+#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 
740std::size_t OpCacheKeyHash::operator()(const OpCacheKey& key) const { return MurmurHash(key.buf, key.len); }740std::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+ 
998void InitL2Phase1Context(const char* l2Name, [[maybe_unused]] aclOpExecutor** executor)1028void 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 
1022void InitL2Phase2Context([[maybe_unused]] const char* l2Name, aclOpExecutor* executor)1050void InitL2Phase2Context([[maybe_unused]] const char* l2Name, aclOpExecutor* executor)
@@ -49,15 +49,6 @@ using OpImplFunctions = gert::OpImplKernelRegistry::OpImplFunctions;
49constexpr size_t K_DEFAULT_INPUT_SIZE = 3;49constexpr size_t K_DEFAULT_INPUT_SIZE = 3;
50constexpr size_t K_DEFAULT_OUTPUT_SIZE = 1;50constexpr 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- 
61uint32_t CalcMixCoreNum(uint32_t cubeCoreNum, uint32_t vectorCoreNum, const Json& opJson)52uint32_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 {
36public:36public:
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::internal95} // 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 of3 * 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 management199 // Dynamic capacity management
@@ -261,12 +261,15 @@ aclError aclrtCacheLastTaskOpInfo(const void* const infoPtr, size_t infoSize)
261}261}
262 262 
263int64_t gDeterministicNew = 0;263int64_t gDeterministicNew = 0;
264+int64_t gStrongConsistencyNew = 0;
264 265 
265EXTERN_C266EXTERN_C
266aclError aclrtSetSysParamOpt(aclSysParamOpt opt, int64_t value)267aclError 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 
449TEST_F(OpExecutorTest, DeterministicTest)451TEST_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 
39typedef std::function<void(void)> Functional;39typedef std::function<void(void)> Functional;
40 40 
41+extern inline uint32_t AxpyOpTypeId();
42+extern inline uint32_t SortOpTypeId();
43+ 
41class TilingCtxBuildUT : public testing::Test {44class TilingCtxBuildUT : public testing::Test {
42protected:45protected:
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 overwrite51 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 
443TEST_F(TilingCtxBuildUT, TilingCtxMultiThreadTest)484TEST_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 时的行为
755static void TilingCtxDeterministicLevelNullTest()622static void TilingCtxDeterministicLevelNullTest()
756{623{
@@ -792,41 +659,20 @@ static void TilingCtxDeterministicLevelNullTest()
792 nullptr); // CompiledInfoStruct659 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); // PlatformInfo662+ 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); // TilingFunc664 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); // Deterministic667+ 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); // DeterministicLevel669 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- 
811TEST_F(TilingCtxBuildUT, TilingCtxDeterministicLevelNullTest) { TilingCtxDeterministicLevelNullTest(); }674TEST_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) 函数
831static void UpdateTilingCtxWithOpJsonTest()677static void UpdateTilingCtxWithOpJsonTest()
832{678{