已合并
feat: 支持静态Shape根据ub大小过滤非法template #964
zhang_shengjie创建于 6月21日
feat: 支持静态Shape根据ub大小过滤非法template #964
已合并
共 34 个文件变更+3148-797
| @@ -10,7 +10,10 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | + | ||
| 13 | 14 | ||
| 15 | + | ||
| 16 | + | ||
| 14 | 17 | ||
| 15 | 18 | ||
| 16 | 19 | ||
| @@ -37,6 +40,76 @@ constexpr uint32_t kConstType = 1U; | |||
| 37 | constexpr uint32_t kVarType = 2U; | 40 | constexpr uint32_t kVarType = 2U; |
| 38 | constexpr uint32_t kDefaultAlignValue = 1U; | 41 | constexpr uint32_t kDefaultAlignValue = 1U; |
| 39 | const std::string kModelInfoFilePath = "./"; | 42 | const std::string kModelInfoFilePath = "./"; |
| 43 | + | ||
| 44 | +std::set<std::string> GetUbContainerNames(const ModelInfo &model_info) { | ||
| 45 | + std::set<std::string> names; | ||
| 46 | + const auto ub_iter = model_info.hardware_cons.find(HardwareDef::UB); | ||
| 47 | + if (ub_iter == model_info.hardware_cons.cend()) { | ||
| 48 | + return names; | ||
| 49 | + } | ||
| 50 | + for (const auto &symbol : ub_iter->second.FreeSymbols()) { | ||
| 51 | + const auto name_iter = model_info.variable_name_map.find(symbol); | ||
| 52 | + const auto name = name_iter == model_info.variable_name_map.cend() ? Str(symbol) : name_iter->second; | ||
| 53 | + if (model_info.container_exprs.find(name) != model_info.container_exprs.cend()) { | ||
| 54 | + names.insert(name); | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + return names; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +void EraseVariableByName(ExprExprMap &variable_expr_map, std::map<Expr, std::string, ExprCmp> &variable_name_map, | ||
| 61 | + const std::string &name) { | ||
| 62 | + for (auto iter = variable_name_map.begin(); iter != variable_name_map.end();) { | ||
| 63 | + if (iter->second == name || Str(iter->first) == name) { | ||
| 64 | + variable_expr_map.erase(iter->first); | ||
| 65 | + iter = variable_name_map.erase(iter); | ||
| 66 | + } else { | ||
| 67 | + ++iter; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + for (auto iter = variable_expr_map.begin(); iter != variable_expr_map.end();) { | ||
| 71 | + if (Str(iter->first) == name) { | ||
| 72 | + iter = variable_expr_map.erase(iter); | ||
| 73 | + } else { | ||
| 74 | + ++iter; | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +void EraseContainerExprs(const std::set<std::string> &container_names, ModelInfo &model_info) { | ||
| 80 | + for (const auto &name : container_names) { | ||
| 81 | + model_info.container_exprs.erase(name); | ||
| 82 | + EraseVariableByName(model_info.variable_expr_map, model_info.variable_name_map, name); | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +void ApplyCommonUbExprContext(const ascir::UbExprContext &context, ModelInfo &model_info) { | ||
| 87 | + const auto old_ub_container_names = GetUbContainerNames(model_info); | ||
| 88 | + const auto ub_expr_result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 89 | + if (ub_expr_result.has_ub_expr) { | ||
| 90 | + model_info.hardware_cons[HardwareDef::UB] = ub_expr_result.ub_expr; | ||
| 91 | + } else { | ||
| 92 | + model_info.hardware_cons.erase(HardwareDef::UB); | ||
| 93 | + } | ||
| 94 | + EraseContainerExprs(old_ub_container_names, model_info); | ||
| 95 | + for (const auto &container : context.container_names) { | ||
| 96 | + const auto expr_iter = context.container_expr.find(container.first); | ||
| 97 | + if (expr_iter == context.container_expr.cend()) { | ||
| 98 | + continue; | ||
| 99 | + } | ||
| 100 | + model_info.container_exprs[container.second] = expr_iter->second; | ||
| 101 | + model_info.variable_expr_map[container.first] = expr_iter->second; | ||
| 102 | + model_info.variable_name_map[container.first] = container.second; | ||
| 103 | + } | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +af::Status RefreshCommonUbExprContext(const af::AscGraph &graph, ModelInfo &model_info) { | ||
| 107 | + ascir::UbExprContext context; | ||
| 108 | + GE_ASSERT_SUCCESS(ascir::AscGraphUbExprBuilder().Build(graph, context), "Build common UB expr failed, graph:[%s].", | ||
| 109 | + graph.GetName().c_str()); | ||
| 110 | + ApplyCommonUbExprContext(context, model_info); | ||
| 111 | + return af::SUCCESS; | ||
| 112 | +} | ||
| 40 | } // namespace | 113 | } // namespace |
| 41 | 114 | ||
| 42 | af::Status GenerateModelInfo(const af::AscGraph &graph, ModelInfo &model_info, TuningSpacePtr &tuning_space, | 115 | af::Status GenerateModelInfo(const af::AscGraph &graph, ModelInfo &model_info, TuningSpacePtr &tuning_space, |
| @@ -52,6 +125,7 @@ af::Status GenerateModelInfo(const af::AscGraph &graph, ModelInfo &model_info, T | |||
| 52 | // step2: get basic expr constraint | 125 | // step2: get basic expr constraint |
| 53 | att::GenerateTilingExpr tiling_expr(tuning_space); | 126 | att::GenerateTilingExpr tiling_expr(tuning_space); |
| 54 | GE_ASSERT_SUCCESS(tiling_expr.Generate(model_info), "Get basic expr constraint failed."); | 127 | GE_ASSERT_SUCCESS(tiling_expr.Generate(model_info), "Get basic expr constraint failed."); |
| 128 | + GE_ASSERT_SUCCESS(RefreshCommonUbExprContext(graph, model_info), "Refresh common UB expr failed."); | ||
| 55 | // step3: call passes to get configs | 129 | // step3: call passes to get configs |
| 56 | ATTConfig att_config; | 130 | ATTConfig att_config; |
| 57 | std::vector<PassFunc> pass_funcs; | 131 | std::vector<PassFunc> pass_funcs; |
| @@ -14,6 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | + | ||
| 17 | 18 | ||
| 18 | using namespace ascgen_utils; | 19 | using namespace ascgen_utils; |
| 19 | 20 | ||
| @@ -403,7 +404,15 @@ std::string AxesReorderSolverGen::GenGetUbSizeStaticFunc() { | |||
| 403 | bool ub_exist = false; | 404 | bool ub_exist = false; |
| 404 | auto ub_iter = hardware_use_map_.find(HardwareDef::UB); | 405 | auto ub_iter = hardware_use_map_.find(HardwareDef::UB); |
| 405 | if (ub_iter != hardware_use_map_.end()) { | 406 | if (ub_iter != hardware_use_map_.end()) { |
| 406 | - auto tmp_func_pair = GenNamedOriginBufExpr(ub_iter->second, " "); | 407 | + ascir::UbExprContext context; |
| 408 | + context.ub_expr = ub_iter->second; | ||
| 409 | + for (const auto &item : container_expr_) { | ||
| 410 | + context.container_expr[item.first] = item.second; | ||
| 411 | + } | ||
| 412 | + for (const auto &item : container_names_) { | ||
| 413 | + context.container_names[item.first] = item.second; | ||
| 414 | + } | ||
| 415 | + auto tmp_func_pair = BuildNamedUbExpr(context, " "); | ||
| 407 | std::string tmp_def = tmp_func_pair.first; | 416 | std::string tmp_def = tmp_func_pair.first; |
| 408 | std::string func_return_expr = tmp_func_pair.second; | 417 | std::string func_return_expr = tmp_func_pair.second; |
| 409 | codes += tmp_def; | 418 | codes += tmp_def; |
| @@ -0,0 +1,48 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace att { | ||
| 17 | +namespace { | ||
| 18 | + | ||
| 19 | +ExprExprMap ToAttExprMap(const ascir::UbExprExprMap &expr_map) { | ||
| 20 | + ExprExprMap result; | ||
| 21 | + for (const auto &item : expr_map) { | ||
| 22 | + result[item.first] = item.second; | ||
| 23 | + } | ||
| 24 | + return result; | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +std::map<Expr, std::string, ExprCmp> ToAttExprNameMap( | ||
| 28 | + const std::map<ascir::UbExpr, std::string, ascir::UbExprCmp> &expr_names) { | ||
| 29 | + std::map<Expr, std::string, ExprCmp> result; | ||
| 30 | + for (const auto &item : expr_names) { | ||
| 31 | + result[item.first] = item.second; | ||
| 32 | + } | ||
| 33 | + return result; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +} // namespace | ||
| 37 | + | ||
| 38 | +std::pair<std::string, std::string> BuildNamedUbExpr(const ascir::UbExprContext &context, const std::string &indent) { | ||
| 39 | + const auto ub_expr_result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 40 | + if (!ub_expr_result.has_ub_expr) { | ||
| 41 | + return {"", ""}; | ||
| 42 | + } | ||
| 43 | + const auto container_expr = ToAttExprMap(context.container_expr); | ||
| 44 | + const auto container_names = ToAttExprNameMap(context.container_names); | ||
| 45 | + return NamedOriginBufExprGenerator(container_expr, container_names).Generate(ub_expr_result.ub_expr, indent); | ||
| 46 | +} | ||
| 47 | + | ||
| 48 | +} // namespace att | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +namespace att { | ||
| 20 | + | ||
| 21 | +std::pair<std::string, std::string> BuildNamedUbExpr(const ascir::UbExprContext &context, const std::string &indent); | ||
| 22 | + | ||
| 23 | +} // namespace att | ||
| 24 | + | ||
| 25 | + | ||
| @@ -49,6 +49,10 @@ void PlatformContext::SetPlatform(const std::string &platform_name) { | |||
| 49 | 49 | ||
| 50 | void PlatformContext::SetPlatformInfo(const PlatformInfo &platform_info) { | 50 | void PlatformContext::SetPlatformInfo(const PlatformInfo &platform_info) { |
| 51 | std::lock_guard<std::mutex> lg(mutex_); | 51 | std::lock_guard<std::mutex> lg(mutex_); |
| 52 | + if (platform_info.ub_size > 0) { | ||
| 53 | + ub_size_override_ = platform_info.ub_size; | ||
| 54 | + has_ub_size_override_ = true; | ||
| 55 | + } | ||
| 52 | if (!platform_info.soc_ver.empty()) { | 56 | if (!platform_info.soc_ver.empty()) { |
| 53 | platform_info_ = platform_info; | 57 | platform_info_ = platform_info; |
| 54 | initialized_ = true; | 58 | initialized_ = true; |
| @@ -57,6 +61,13 @@ void PlatformContext::SetPlatformInfo(const PlatformInfo &platform_info) { | |||
| 57 | } | 61 | } |
| 58 | } | 62 | } |
| 59 | 63 | ||
| 64 | +void PlatformContext::SetUbSizeOverride(int64_t ub_size) { | ||
| 65 | + std::lock_guard<std::mutex> lg(mutex_); | ||
| 66 | + ub_size_override_ = ub_size; | ||
| 67 | + has_ub_size_override_ = true; | ||
| 68 | + GELOGI("Set UB size override: ub_size=%lld", ub_size_override_); | ||
| 69 | +} | ||
| 70 | + | ||
| 60 | af::Status PlatformContext::GetCurrentPlatformString(std::string &platform_name) { | 71 | af::Status PlatformContext::GetCurrentPlatformString(std::string &platform_name) { |
| 61 | if (!initialized_) { | 72 | if (!initialized_) { |
| 62 | GE_ASSERT_SUCCESS(Initialize(), "Failed to init platform info with name %s.", platform_name.c_str()); | 73 | GE_ASSERT_SUCCESS(Initialize(), "Failed to init platform info with name %s.", platform_name.c_str()); |
| @@ -108,4 +119,24 @@ af::Status PlatformContext::GetPlatformInfo(PlatformInfo &platform_info) { | |||
| 108 | platform_info_.aiv_num, platform_info_.ub_size); | 119 | platform_info_.aiv_num, platform_info_.ub_size); |
| 109 | return af::SUCCESS; | 120 | return af::SUCCESS; |
| 110 | } | 121 | } |
| 122 | + | ||
| 123 | +bool PlatformContext::TryGetInitializedPlatformInfo(PlatformInfo &platform_info) { | ||
| 124 | + std::lock_guard<std::mutex> lg(mutex_); | ||
| 125 | + if (!initialized_) { | ||
| 126 | + platform_info = PlatformInfo{}; | ||
| 127 | + return false; | ||
| 128 | + } | ||
| 129 | + platform_info = platform_info_; | ||
| 130 | + return true; | ||
| 131 | +} | ||
| 132 | + | ||
| 133 | +bool PlatformContext::TryGetUbSizeOverride(int64_t &ub_size) const { | ||
| 134 | + std::lock_guard<std::mutex> lg(mutex_); | ||
| 135 | + if (!has_ub_size_override_) { | ||
| 136 | + ub_size = 0; | ||
| 137 | + return false; | ||
| 138 | + } | ||
| 139 | + ub_size = ub_size_override_; | ||
| 140 | + return true; | ||
| 141 | +} | ||
| 111 | } // namespace ge | 142 | } // namespace ge |
| @@ -0,0 +1,333 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace ascir { | ||
| 22 | +namespace { | ||
| 23 | +constexpr int64_t kMinTmpBufferSize = 8 * 1024; | ||
| 24 | +constexpr int64_t kSimtDcacheSize = 32 * 1024; | ||
| 25 | +constexpr int64_t kBlockAlignBytes = 32; | ||
| 26 | + | ||
| 27 | +std::string MakeQueueName(int64_t id) { | ||
| 28 | + return "q" + std::to_string(id) + "_size"; | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +std::string MakeBufferName(int64_t id) { | ||
| 32 | + return "b" + std::to_string(id) + "_size"; | ||
| 33 | +} | ||
| 34 | + | ||
| 35 | +std::string GetQueueName(const af::AscTensorAttr &attr) { | ||
| 36 | + return attr.que.name.empty() ? MakeQueueName(attr.que.id) : attr.que.name; | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +std::string GetBufferName(const af::AscTensorAttr &attr) { | ||
| 40 | + return attr.buf.name.empty() ? MakeBufferName(attr.buf.id) : attr.buf.name; | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +uint32_t GetTypeSize(ge::DataType dtype) { | ||
| 44 | + uint32_t type_size = 0U; | ||
| 45 | + if (!ge::TypeUtils::GetDataTypeLength(dtype, type_size)) { | ||
| 46 | + return 1U; | ||
| 47 | + } | ||
| 48 | + return type_size > 0U ? type_size : 1U; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +UbExpr AlignToBlock(const UbExpr &size) { | ||
| 52 | + return af::sym::Mul(af::Symbol(kBlockAlignBytes), af::sym::Ceiling(af::sym::Div(size, af::Symbol(kBlockAlignBytes)))); | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +bool HasPrintableExpr(const UbExpr &expr) { | ||
| 56 | + if (!expr.IsValid()) { | ||
| 57 | + return false; | ||
| 58 | + } | ||
| 59 | + const auto expr_str = expr.Str(); | ||
| 60 | + return expr_str != nullptr && expr_str[0] != '\0'; | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +UbExpr TensorVectorizedElementSize(const af::AscGraph &graph, const af::AscTensorAttr &attr) { | ||
| 64 | + if (attr.vectorized_axis.empty()) { | ||
| 65 | + return af::sym::kSymbolOne; | ||
| 66 | + } | ||
| 67 | + for (size_t i = 0UL; i < attr.vectorized_axis.size(); ++i) { | ||
| 68 | + if (i >= attr.vectorized_strides.size()) { | ||
| 69 | + continue; | ||
| 70 | + } | ||
| 71 | + const auto &stride = attr.vectorized_strides[i]; | ||
| 72 | + if (stride == af::sym::kSymbolZero) { | ||
| 73 | + continue; | ||
| 74 | + } | ||
| 75 | + if (attr.axis.empty() && i < attr.repeats.size()) { | ||
| 76 | + return stride == af::sym::kSymbolOne ? attr.repeats[i] : attr.repeats[i] * stride; | ||
| 77 | + } | ||
| 78 | + auto axis_iter = std::find(attr.axis.cbegin(), attr.axis.cend(), attr.vectorized_axis[i]); | ||
| 79 | + if (axis_iter == attr.axis.cend()) { | ||
| 80 | + GELOGW("[AscGraphUbExprBuilder] cannot find vectorized axis %ld in tensor attr of graph %s", | ||
| 81 | + attr.vectorized_axis[i], graph.GetName().c_str()); | ||
| 82 | + return {}; | ||
| 83 | + } | ||
| 84 | + const auto axis_index = static_cast<size_t>(std::distance(attr.axis.cbegin(), axis_iter)); | ||
| 85 | + if (axis_index >= attr.repeats.size()) { | ||
| 86 | + GELOGW("[AscGraphUbExprBuilder] vectorized axis %ld repeat index %zu is invalid in graph %s", | ||
| 87 | + attr.vectorized_axis[i], axis_index, graph.GetName().c_str()); | ||
| 88 | + return {}; | ||
| 89 | + } | ||
| 90 | + return stride == af::sym::kSymbolOne ? attr.repeats[axis_index] : attr.repeats[axis_index] * stride; | ||
| 91 | + } | ||
| 92 | + return af::sym::kSymbolOne; | ||
| 93 | +} | ||
| 94 | + | ||
| 95 | +UbExpr TensorBytes(const af::AscGraph &graph, const af::AscTensorAttr &attr) { | ||
| 96 | + return AlignToBlock(TensorVectorizedElementSize(graph, attr) * af::Symbol(GetTypeSize(attr.dtype))); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +void AppendUniqueVar(const UbExpr &var, std::vector<UbExpr> &vars) { | ||
| 100 | + if (!HasPrintableExpr(var)) { | ||
| 101 | + return; | ||
| 102 | + } | ||
| 103 | + const auto iter = std::find_if(vars.cbegin(), vars.cend(), [&var](const auto &item) { return item == var; }); | ||
| 104 | + if (iter == vars.cend()) { | ||
| 105 | + vars.emplace_back(var); | ||
| 106 | + } | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +void CollectVars(const UbExpr &expr, std::vector<UbExpr> &vars) { | ||
| 110 | + if (!HasPrintableExpr(expr)) { | ||
| 111 | + return; | ||
| 112 | + } | ||
| 113 | + for (const auto &var : expr.FreeSymbols()) { | ||
| 114 | + AppendUniqueVar(var, vars); | ||
| 115 | + } | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +void AppendMax(UbExpr &expr, const UbExpr &item) { | ||
| 119 | + if (!HasPrintableExpr(item)) { | ||
| 120 | + return; | ||
| 121 | + } | ||
| 122 | + expr = HasPrintableExpr(expr) ? af::sym::Max(expr, item) : item; | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +void AppendAdd(UbExpr &expr, const UbExpr &item) { | ||
| 126 | + if (!HasPrintableExpr(item)) { | ||
| 127 | + return; | ||
| 128 | + } | ||
| 129 | + expr = HasPrintableExpr(expr) ? expr + item : item; | ||
| 130 | +} | ||
| 131 | + | ||
| 132 | +struct ContainerState { | ||
| 133 | + std::string name; | ||
| 134 | + UbExpr normal_max; | ||
| 135 | + uint32_t buf_num = 0U; | ||
| 136 | + std::map<int64_t, UbExpr> share_group_bytes; | ||
| 137 | +}; | ||
| 138 | + | ||
| 139 | +void AddContainerTensor(const af::AscGraph &graph, const af::AscTensorAttr &attr, ContainerState &state) { | ||
| 140 | + const auto bytes = TensorBytes(graph, attr); | ||
| 141 | + AppendMax(state.normal_max, bytes); | ||
| 142 | + if (attr.mem.reuse_id == af::kIdNone) { | ||
| 143 | + return; | ||
| 144 | + } | ||
| 145 | + AppendAdd(state.share_group_bytes[attr.mem.reuse_id], bytes); | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +void AddQueueTensor(const af::AscGraph &graph, const af::AscTensorAttr &attr, ContainerState &state) { | ||
| 149 | + if (state.name.empty()) { | ||
| 150 | + state.name = GetQueueName(attr); | ||
| 151 | + } | ||
| 152 | + AddContainerTensor(graph, attr, state); | ||
| 153 | + state.buf_num = std::max(state.buf_num, static_cast<uint32_t>(std::max<int64_t>(attr.que.buf_num, 0))); | ||
| 154 | +} | ||
| 155 | + | ||
| 156 | +void AddBufferTensor(const af::AscGraph &graph, const af::AscTensorAttr &attr, ContainerState &state) { | ||
| 157 | + if (state.name.empty()) { | ||
| 158 | + state.name = GetBufferName(attr); | ||
| 159 | + } | ||
| 160 | + AddContainerTensor(graph, attr, state); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +UbExpr ContainerSlotBytes(const ContainerState &state) { | ||
| 164 | + UbExpr size = state.normal_max; | ||
| 165 | + for (const auto &item : state.share_group_bytes) { | ||
| 166 | + AppendMax(size, item.second); | ||
| 167 | + } | ||
| 168 | + return size; | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +UbExpr QueueTotalBytes(const ContainerState &state, const UbExpr &slot_bytes) { | ||
| 172 | + if (!slot_bytes.IsValid()) { | ||
| 173 | + return {}; | ||
| 174 | + } | ||
| 175 | + const uint32_t buf_num = state.buf_num == 0U ? 1U : state.buf_num; | ||
| 176 | + return buf_num == 1U ? slot_bytes : slot_bytes * af::Symbol(buf_num); | ||
| 177 | +} | ||
| 178 | + | ||
| 179 | +bool IsUbAlloc(const af::AscTensorAttr &attr) { | ||
| 180 | + return attr.mem.hardware == af::MemHardware::kMemHardwareUB && | ||
| 181 | + (attr.mem.alloc_type == af::AllocType::kAllocTypeQueue || | ||
| 182 | + attr.mem.alloc_type == af::AllocType::kAllocTypeBuffer); | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +bool IsUbTmpBuffer(const af::TmpBuffer &tmp_buffer) { | ||
| 186 | + return tmp_buffer.id != af::kIdNone; | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +void AddContainer(UbExprContext &context, const std::string &name, const UbExpr &expr, const UbExpr &total_expr) { | ||
| 190 | + if (!HasPrintableExpr(expr) || !HasPrintableExpr(total_expr)) { | ||
| 191 | + return; | ||
| 192 | + } | ||
| 193 | + const UbExpr symbol = af::Symbol(name.c_str()); | ||
| 194 | + context.container_expr[symbol] = expr; | ||
| 195 | + context.container_names[symbol] = name; | ||
| 196 | + AppendAdd(context.ub_expr, total_expr); | ||
| 197 | + CollectVars(expr, context.ub_related_vars); | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +void AddContainer(UbExprContext &context, const std::string &name, const UbExpr &expr) { | ||
| 201 | + const UbExpr symbol = af::Symbol(name.c_str()); | ||
| 202 | + AddContainer(context, name, expr, symbol); | ||
| 203 | +} | ||
| 204 | + | ||
| 205 | +bool IsConstZero(const UbExpr &expr) { | ||
| 206 | + int64_t value = 0; | ||
| 207 | + return HasPrintableExpr(expr) && expr.GetConstValue(value) && value == 0; | ||
| 208 | +} | ||
| 209 | + | ||
| 210 | +void AddBuiltinTmpBuffer(const af::AscGraph &graph, UbExprContext &context) { | ||
| 211 | + const auto builtin_tmp_buffer = ascgen_utils::CalcExtraTmpBufForAscGraph(graph); | ||
| 212 | + if (IsConstZero(builtin_tmp_buffer)) { | ||
| 213 | + return; | ||
| 214 | + } | ||
| 215 | + AppendAdd(context.ub_expr, builtin_tmp_buffer); | ||
| 216 | + CollectVars(builtin_tmp_buffer, context.ub_related_vars); | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +UbExpr CalcReservedUbSize(const af::AscGraph &graph) { | ||
| 220 | + UbExpr reserved_ub_size = af::Symbol(ascgen_utils::CalcReservedTmpBufSizeForAscGraph(graph)); | ||
| 221 | + for (const auto &node : graph.GetAllNodes()) { | ||
| 222 | + GE_ASSERT_NOTNULL(node); | ||
| 223 | + if (node->GetType() == af::ascir_op::Gather::Type) { | ||
| 224 | + reserved_ub_size = reserved_ub_size + af::Symbol(kSimtDcacheSize); | ||
| 225 | + break; | ||
| 226 | + } | ||
| 227 | + } | ||
| 228 | + return reserved_ub_size; | ||
| 229 | +} | ||
| 230 | + | ||
| 231 | +void AddReservedUb(const af::AscGraph &graph, UbExprContext &context) { | ||
| 232 | + const auto reserved_ub_size = CalcReservedUbSize(graph); | ||
| 233 | + if (IsConstZero(reserved_ub_size)) { | ||
| 234 | + return; | ||
| 235 | + } | ||
| 236 | + AppendAdd(context.ub_expr, reserved_ub_size); | ||
| 237 | +} | ||
| 238 | + | ||
| 239 | +bool IsDynamicSizeVar(const af::SizeVarPtr &size_var) { | ||
| 240 | + return size_var != nullptr && HasPrintableExpr(size_var->expr) && !size_var->expr.IsConstExpr(); | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +void FillSizeVars(const af::AscGraph &graph, UbExprContext &context) { | ||
| 244 | + for (const auto &size_var : graph.GetAllSizeVar()) { | ||
| 245 | + if (IsDynamicSizeVar(size_var)) { | ||
| 246 | + AppendUniqueVar(size_var->expr, context.dynamic_size_vars); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +void FillTileVars(const af::AscGraph &graph, UbExprContext &context) { | ||
| 252 | + for (const auto &axis : graph.GetAllAxis()) { | ||
| 253 | + if (axis == nullptr || !HasPrintableExpr(axis->size)) { | ||
| 254 | + continue; | ||
| 255 | + } | ||
| 256 | + if (axis->type == af::Axis::kAxisTypeTileInner) { | ||
| 257 | + context.var_min_values[axis->size] = af::sym::kSymbolOne; | ||
| 258 | + AppendUniqueVar(axis->size, context.ub_related_vars); | ||
| 259 | + continue; | ||
| 260 | + } | ||
| 261 | + if (axis->type == af::Axis::kAxisTypeOriginal && !axis->size.IsConstExpr()) { | ||
| 262 | + AppendUniqueVar(axis->size, context.dynamic_size_vars); | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | +} | ||
| 266 | + | ||
| 267 | +void AddTmpBuffer(const af::TmpBuffer &tmp_buffer, std::map<int64_t, UbExpr> &node_tmp_buffer_bytes) { | ||
| 268 | + if (!IsUbTmpBuffer(tmp_buffer) || !HasPrintableExpr(tmp_buffer.buf_desc.size)) { | ||
| 269 | + return; | ||
| 270 | + } | ||
| 271 | + AppendAdd(node_tmp_buffer_bytes[tmp_buffer.id], tmp_buffer.buf_desc.size); | ||
| 272 | +} | ||
| 273 | + | ||
| 274 | +void MergeNodeTmpBuffers(const std::map<int64_t, UbExpr> &node_tmp_buffer_bytes, | ||
| 275 | + std::map<int64_t, ContainerState> &buffer_bytes) { | ||
| 276 | + for (const auto &item : node_tmp_buffer_bytes) { | ||
| 277 | + AppendMax(buffer_bytes[item.first].normal_max, af::sym::Max(item.second, af::Symbol(kMinTmpBufferSize))); | ||
| 278 | + } | ||
| 279 | +} | ||
| 280 | + | ||
| 281 | +void AddTensor(const af::AscGraph &graph, const af::AscTensorAttr &attr, std::map<int64_t, ContainerState> &queue_bytes, | ||
| 282 | + std::map<int64_t, ContainerState> &buffer_bytes) { | ||
| 283 | + if (!IsUbAlloc(attr)) { | ||
| 284 | + return; | ||
| 285 | + } | ||
| 286 | + if (attr.mem.alloc_type == af::AllocType::kAllocTypeQueue && attr.que.id != af::kIdNone) { | ||
| 287 | + AddQueueTensor(graph, attr, queue_bytes[attr.que.id]); | ||
| 288 | + return; | ||
| 289 | + } | ||
| 290 | + if (attr.mem.alloc_type == af::AllocType::kAllocTypeBuffer && attr.buf.id != af::kIdNone) { | ||
| 291 | + AddBufferTensor(graph, attr, buffer_bytes[attr.buf.id]); | ||
| 292 | + } | ||
| 293 | +} | ||
| 294 | + | ||
| 295 | +} // namespace | ||
| 296 | + | ||
| 297 | +af::Status AscGraphUbExprBuilder::Build(const af::AscGraph &graph, UbExprContext &context) const { | ||
| 298 | + context = UbExprContext{}; | ||
| 299 | + context.graph_name = graph.GetName(); | ||
| 300 | + context.tiling_case_id = graph.GetTilingKey(); | ||
| 301 | + FillSizeVars(graph, context); | ||
| 302 | + FillTileVars(graph, context); | ||
| 303 | + | ||
| 304 | + std::map<int64_t, ContainerState> queue_bytes; | ||
| 305 | + std::map<int64_t, ContainerState> buffer_bytes; | ||
| 306 | + for (const auto &node : graph.GetAllNodes()) { | ||
| 307 | + GE_ASSERT_NOTNULL(node); | ||
| 308 | + for (const auto &output : node->outputs()) { | ||
| 309 | + AddTensor(graph, output->attr, queue_bytes, buffer_bytes); | ||
| 310 | + } | ||
| 311 | + std::map<int64_t, UbExpr> node_tmp_buffer_bytes; | ||
| 312 | + for (const auto &tmp_buffer : node->attr.tmp_buffers) { | ||
| 313 | + AddTmpBuffer(tmp_buffer, node_tmp_buffer_bytes); | ||
| 314 | + } | ||
| 315 | + MergeNodeTmpBuffers(node_tmp_buffer_bytes, buffer_bytes); | ||
| 316 | + } | ||
| 317 | + | ||
| 318 | + for (const auto &item : queue_bytes) { | ||
| 319 | + const auto name = item.second.name.empty() ? MakeQueueName(item.first) : item.second.name; | ||
| 320 | + const auto symbol = af::Symbol(name.c_str()); | ||
| 321 | + const auto slot_bytes = ContainerSlotBytes(item.second); | ||
| 322 | + AddContainer(context, name, slot_bytes, QueueTotalBytes(item.second, symbol)); | ||
| 323 | + } | ||
| 324 | + for (const auto &item : buffer_bytes) { | ||
| 325 | + const auto name = item.second.name.empty() ? MakeBufferName(item.first) : item.second.name; | ||
| 326 | + AddContainer(context, name, ContainerSlotBytes(item.second)); | ||
| 327 | + } | ||
| 328 | + AddBuiltinTmpBuffer(graph, context); | ||
| 329 | + AddReservedUb(graph, context); | ||
| 330 | + return af::SUCCESS; | ||
| 331 | +} | ||
| 332 | + | ||
| 333 | +} // namespace ascir | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +namespace ascir { | ||
| 18 | + | ||
| 19 | +class AscGraphUbExprBuilder { | ||
| 20 | + public: | ||
| 21 | + af::Status Build(const af::AscGraph &graph, UbExprContext &context) const; | ||
| 22 | +}; | ||
| 23 | + | ||
| 24 | +} // namespace ascir | ||
| 25 | + | ||
| 26 | + | ||
| @@ -0,0 +1,63 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | +namespace ascir { | ||
| 22 | + | ||
| 23 | +using UbExpr = af::Expression; | ||
| 24 | + | ||
| 25 | +struct UbExprCmp { | ||
| 26 | + bool operator()(const UbExpr &lhs, const UbExpr &rhs) const { | ||
| 27 | + if (!lhs.IsValid()) { | ||
| 28 | + return rhs.IsValid(); | ||
| 29 | + } | ||
| 30 | + if (!rhs.IsValid()) { | ||
| 31 | + return false; | ||
| 32 | + } | ||
| 33 | + return lhs.Compare(rhs) < 0; | ||
| 34 | + } | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +using UbExprExprMap = std::map<UbExpr, UbExpr, UbExprCmp>; | ||
| 38 | +using UbExprUintMap = std::map<UbExpr, uint32_t, UbExprCmp>; | ||
| 39 | + | ||
| 40 | +struct UbExprContext { | ||
| 41 | + UbExpr ub_expr; | ||
| 42 | + UbExprExprMap container_expr; | ||
| 43 | + std::map<UbExpr, std::string, UbExprCmp> container_names; | ||
| 44 | + std::vector<UbExpr> ub_related_vars; | ||
| 45 | + UbExprExprMap var_min_values; | ||
| 46 | + UbExprUintMap const_vars; | ||
| 47 | + UbExprExprMap static_size_vars; | ||
| 48 | + std::vector<UbExpr> dynamic_size_vars; | ||
| 49 | + std::vector<std::pair<UbExpr, UbExpr>> expr_relations; | ||
| 50 | + std::string graph_name; | ||
| 51 | + std::string template_name; | ||
| 52 | + int64_t tiling_case_id = 0; | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +struct UbExprBuildResult { | ||
| 56 | + bool has_ub_expr = false; | ||
| 57 | + UbExpr ub_expr; | ||
| 58 | + std::string origin_expr; | ||
| 59 | +}; | ||
| 60 | + | ||
| 61 | +} // namespace ascir | ||
| 62 | + | ||
| 63 | + | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +namespace ascir { | ||
| 14 | + | ||
| 15 | +UbExprBuildResult UbExprUtils::BuildUbExpr(const UbExprContext &context) { | ||
| 16 | + UbExprBuildResult result; | ||
| 17 | + if (!context.ub_expr.IsValid() || context.ub_expr.Str() == nullptr) { | ||
| 18 | + return result; | ||
| 19 | + } | ||
| 20 | + result.has_ub_expr = true; | ||
| 21 | + result.ub_expr = context.ub_expr; | ||
| 22 | + result.origin_expr = context.ub_expr.Str().get(); | ||
| 23 | + return result; | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +} // namespace ascir | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace ascir { | ||
| 17 | + | ||
| 18 | +class UbExprUtils { | ||
| 19 | + public: | ||
| 20 | + static UbExprBuildResult BuildUbExpr(const UbExprContext &context); | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +} // namespace ascir | ||
| 24 | + | ||
| 25 | + | ||
| @@ -36,6 +36,8 @@ class PlatformContext { | |||
| 36 | 36 | ||
| 37 | void SetPlatformInfo(const PlatformInfo &platform_info); | 37 | void SetPlatformInfo(const PlatformInfo &platform_info); |
| 38 | 38 | ||
| 39 | + void SetUbSizeOverride(int64_t ub_size); | ||
| 40 | + | ||
| 39 | // 获取当前 platform 字符串 | 41 | // 获取当前 platform 字符串 |
| 40 | af::Status GetCurrentPlatformString(std::string &platform_name); | 42 | af::Status GetCurrentPlatformString(std::string &platform_name); |
| 41 | 43 | ||
| @@ -44,15 +46,23 @@ class PlatformContext { | |||
| 44 | platform_info_.soc_ver = ""; | 46 | platform_info_.soc_ver = ""; |
| 45 | platform_info_.aiv_num = 0; | 47 | platform_info_.aiv_num = 0; |
| 46 | platform_info_.ub_size = 0; | 48 | platform_info_.ub_size = 0; |
| 49 | + ub_size_override_ = 0; | ||
| 50 | + has_ub_size_override_ = false; | ||
| 47 | } | 51 | } |
| 48 | 52 | ||
| 49 | af::Status GetPlatformInfo(PlatformInfo &platform_info); | 53 | af::Status GetPlatformInfo(PlatformInfo &platform_info); |
| 50 | 54 | ||
| 55 | + bool TryGetInitializedPlatformInfo(PlatformInfo &platform_info); | ||
| 56 | + | ||
| 57 | + bool TryGetUbSizeOverride(int64_t &ub_size) const; | ||
| 58 | + | ||
| 51 | private: | 59 | private: |
| 52 | af::Status Initialize(); | 60 | af::Status Initialize(); |
| 53 | af::Status InitPlatformInfo(); | 61 | af::Status InitPlatformInfo(); |
| 54 | PlatformContext() = default; | 62 | PlatformContext() = default; |
| 55 | PlatformInfo platform_info_; | 63 | PlatformInfo platform_info_; |
| 64 | + int64_t ub_size_override_ = 0; | ||
| 65 | + bool has_ub_size_override_ = false; | ||
| 56 | bool initialized_ = false; | 66 | bool initialized_ = false; |
| 57 | static std::mutex mutex_; | 67 | static std::mutex mutex_; |
| 58 | }; | 68 | }; |
| @@ -160,6 +160,12 @@ Status BufQueAllocator::AllocBufQueForSingleImplGraph(af::AscGraph &impl_graph, | |||
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | Status BufQueAllocator::AllocBufQue(::ascir::FusedScheduledResult &fused_scheduled_result) { | 162 | Status BufQueAllocator::AllocBufQue(::ascir::FusedScheduledResult &fused_scheduled_result) { |
| 163 | + GE_CHK_STATUS_RET(PrepareImplGraphMemoryPlan(fused_scheduled_result), "PrepareImplGraphMemoryPlan failed"); | ||
| 164 | + GE_CHK_STATUS_RET(CollectFusedIoNodes(fused_scheduled_result), "CollectFusedIoNodes failed"); | ||
| 165 | + return ge::GRAPH_SUCCESS; | ||
| 166 | +} | ||
| 167 | + | ||
| 168 | +Status BufQueAllocator::PrepareImplGraphMemoryPlan(::ascir::FusedScheduledResult &fused_scheduled_result) { | ||
| 163 | const auto &platform = PlatformFactory::GetInstance().GetPlatform(); | 169 | const auto &platform = PlatformFactory::GetInstance().GetPlatform(); |
| 164 | GE_CHECK_NOTNULL(platform, "Platform is not found."); | 170 | GE_CHECK_NOTNULL(platform, "Platform is not found."); |
| 165 | 171 | ||
| @@ -179,6 +185,25 @@ Status BufQueAllocator::AllocBufQue(::ascir::FusedScheduledResult &fused_schedul | |||
| 179 | return ge::GRAPH_SUCCESS; | 185 | return ge::GRAPH_SUCCESS; |
| 180 | } | 186 | } |
| 181 | 187 | ||
| 188 | +Status BufQueAllocator::CollectFusedIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result) { | ||
| 189 | + fused_scheduled_result.input_nodes.clear(); | ||
| 190 | + fused_scheduled_result.output_nodes.clear(); | ||
| 191 | + fused_scheduled_result.workspace_nodes.clear(); | ||
| 192 | + node_type_to_index_to_node_.clear(); | ||
| 193 | + for (const auto &scheduled_results : fused_scheduled_result.node_idx_to_scheduled_results) { | ||
| 194 | + for (const auto &result : scheduled_results) { | ||
| 195 | + for (const auto &schedule_group : result.schedule_groups) { | ||
| 196 | + for (const auto &impl_graph : schedule_group.impl_graphs) { | ||
| 197 | + GE_CHK_STATUS_RET(CollectIoNodes(impl_graph), "CollectIoNodes failed, graph = %s", | ||
| 198 | + impl_graph.GetName().c_str()); | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + } | ||
| 202 | + } | ||
| 203 | + AppendCollectedIoNodes(fused_scheduled_result); | ||
| 204 | + return ge::GRAPH_SUCCESS; | ||
| 205 | +} | ||
| 206 | + | ||
| 182 | Status BufQueAllocator::AllocateForIoNodes(const af::AscGraph &impl_graph) { | 207 | Status BufQueAllocator::AllocateForIoNodes(const af::AscGraph &impl_graph) { |
| 183 | for (const auto &node : impl_graph.GetAllNodes()) { | 208 | for (const auto &node : impl_graph.GetAllNodes()) { |
| 184 | GE_ASSERT_NOTNULL(node); | 209 | GE_ASSERT_NOTNULL(node); |
| @@ -193,7 +218,8 @@ Status BufQueAllocator::AllocateForIoNodes(const af::AscGraph &impl_graph) { | |||
| 193 | tensor_id = it->second; | 218 | tensor_id = it->second; |
| 194 | GELOGI("same index, cur_node: %s", node->GetName().c_str()); | 219 | GELOGI("same index, cur_node: %s", node->GetName().c_str()); |
| 195 | auto &index_to_node = node_type_to_index_to_node_[node->GetType()]; | 220 | auto &index_to_node = node_type_to_index_to_node_[node->GetType()]; |
| 196 | - if (node->GetName().size() < index_to_node[index]->GetName().size()) { | 221 | + auto node_it = index_to_node.find(index); |
| 222 | + if (node_it == index_to_node.end() || ShouldReplaceRepresentative(node_it->second, node)) { | ||
| 197 | index_to_node[index] = node; | 223 | index_to_node[index] = node; |
| 198 | } | 224 | } |
| 199 | } else { | 225 | } else { |
| @@ -244,18 +270,65 @@ Status BufQueAllocator::AllocateForIoNodes(::ascir::FusedScheduledResult &fused_ | |||
| 244 | } | 270 | } |
| 245 | } | 271 | } |
| 246 | } | 272 | } |
| 273 | + return ge::GRAPH_SUCCESS; | ||
| 274 | +} | ||
| 275 | + | ||
| 276 | +bool BufQueAllocator::ShouldReplaceRepresentative(const ascir::NodeView ¤t, const ascir::NodeView &candidate) { | ||
| 277 | + if (current == nullptr) { | ||
| 278 | + return true; | ||
| 279 | + } | ||
| 280 | + if (candidate == nullptr) { | ||
| 281 | + return false; | ||
| 282 | + } | ||
| 283 | + return candidate->GetName().size() < current->GetName().size(); | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +Status BufQueAllocator::CollectIoNodes(const af::AscGraph &impl_graph) { | ||
| 287 | + for (const auto &node : impl_graph.GetAllNodes()) { | ||
| 288 | + GE_ASSERT_NOTNULL(node); | ||
| 289 | + if (ScheduleUtils::IsDataInput(node) || IsOps<Output>(node)) { | ||
| 290 | + int64_t index = -1; | ||
| 291 | + GE_CHK_STATUS_RET(node->attr.ir_attr->GetAttrValue("index", index), "Get attr index failed, node = %s[%s]", | ||
| 292 | + node->GetNamePtr(), node->GetTypePtr()); | ||
| 293 | + auto &index_to_node = node_type_to_index_to_node_[node->GetType()]; | ||
| 294 | + const auto iter = index_to_node.find(index); | ||
| 295 | + if (iter == index_to_node.end() || ShouldReplaceRepresentative(iter->second, node)) { | ||
| 296 | + index_to_node[index] = node; | ||
| 297 | + } | ||
| 298 | + continue; | ||
| 299 | + } | ||
| 300 | + if (IsOps<Workspace>(node)) { | ||
| 301 | + const auto iter = workspace_name_to_tensor_id_.find(node->GetName()); | ||
| 302 | + GE_ASSERT_TRUE(iter != workspace_name_to_tensor_id_.end(), "Workspace tensor id is not allocated, node = %s", | ||
| 303 | + node->GetNamePtr()); | ||
| 304 | + node_type_to_index_to_node_[node->GetType()][iter->second] = node; | ||
| 305 | + } | ||
| 306 | + } | ||
| 307 | + return ge::GRAPH_SUCCESS; | ||
| 308 | +} | ||
| 309 | + | ||
| 310 | +void BufQueAllocator::AppendCollectedIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result) const { | ||
| 247 | for (const auto &type : {Data::Type, af::ascir_op::ScalarData::Type}) { | 311 | for (const auto &type : {Data::Type, af::ascir_op::ScalarData::Type}) { |
| 248 | - for (const auto &index_and_node : node_type_to_index_to_node_[type]) { | 312 | + const auto iter = node_type_to_index_to_node_.find(type); |
| 313 | + if (iter == node_type_to_index_to_node_.cend()) { | ||
| 314 | + continue; | ||
| 315 | + } | ||
| 316 | + for (const auto &index_and_node : iter->second) { | ||
| 249 | fused_scheduled_result.input_nodes.emplace_back(index_and_node.second); | 317 | fused_scheduled_result.input_nodes.emplace_back(index_and_node.second); |
| 250 | } | 318 | } |
| 251 | } | 319 | } |
| 252 | - for (const auto &index_and_node : node_type_to_index_to_node_[Output::Type]) { | 320 | + const auto output_iter = node_type_to_index_to_node_.find(Output::Type); |
| 253 | - fused_scheduled_result.output_nodes.emplace_back(index_and_node.second); | 321 | + if (output_iter != node_type_to_index_to_node_.cend()) { |
| 322 | + for (const auto &index_and_node : output_iter->second) { | ||
| 323 | + fused_scheduled_result.output_nodes.emplace_back(index_and_node.second); | ||
| 324 | + } | ||
| 254 | } | 325 | } |
| 255 | - for (const auto &index_and_node : node_type_to_index_to_node_[Workspace::Type]) { | 326 | + const auto workspace_iter = node_type_to_index_to_node_.find(Workspace::Type); |
| 256 | - fused_scheduled_result.workspace_nodes.emplace_back(index_and_node.second); | 327 | + if (workspace_iter != node_type_to_index_to_node_.cend()) { |
| 328 | + for (const auto &index_and_node : workspace_iter->second) { | ||
| 329 | + fused_scheduled_result.workspace_nodes.emplace_back(index_and_node.second); | ||
| 330 | + } | ||
| 257 | } | 331 | } |
| 258 | - return ge::GRAPH_SUCCESS; | ||
| 259 | } | 332 | } |
| 260 | 333 | ||
| 261 | Status BufQueAllocator::SetOutputTensorAttr(const af::AscGraph &impl_graph) const { | 334 | Status BufQueAllocator::SetOutputTensorAttr(const af::AscGraph &impl_graph) const { |
| @@ -22,6 +22,8 @@ namespace optimize { | |||
| 22 | class BufQueAllocator { | 22 | class BufQueAllocator { |
| 23 | public: | 23 | public: |
| 24 | Status AllocBufQue(::ascir::FusedScheduledResult &fused_scheduled_result); | 24 | Status AllocBufQue(::ascir::FusedScheduledResult &fused_scheduled_result); |
| 25 | + Status PrepareImplGraphMemoryPlan(::ascir::FusedScheduledResult &fused_scheduled_result); | ||
| 26 | + Status CollectFusedIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result); | ||
| 25 | 27 | ||
| 26 | private: | 28 | private: |
| 27 | Status AllocBufQueForSingleImplGraph(af::AscGraph &impl_graph, size_t max_que_num, | 29 | Status AllocBufQueForSingleImplGraph(af::AscGraph &impl_graph, size_t max_que_num, |
| @@ -30,8 +32,11 @@ class BufQueAllocator { | |||
| 30 | bool is_reduce_mem_reuse); | 32 | bool is_reduce_mem_reuse); |
| 31 | Status AllocateForIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result); | 33 | Status AllocateForIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result); |
| 32 | Status AllocateForIoNodes(const af::AscGraph &impl_graph); | 34 | Status AllocateForIoNodes(const af::AscGraph &impl_graph); |
| 35 | + Status CollectIoNodes(const af::AscGraph &impl_graph); | ||
| 36 | + void AppendCollectedIoNodes(::ascir::FusedScheduledResult &fused_scheduled_result) const; | ||
| 33 | Status SetOutputTensorAttr(const af::AscGraph &impl_graph) const; | 37 | Status SetOutputTensorAttr(const af::AscGraph &impl_graph) const; |
| 34 | static void SetGlobalMemInfo(const af::AscTensor &tensor, int64_t tensor_id); | 38 | static void SetGlobalMemInfo(const af::AscTensor &tensor, int64_t tensor_id); |
| 39 | + static bool ShouldReplaceRepresentative(const ascir::NodeView ¤t, const ascir::NodeView &candidate); | ||
| 35 | void InitTensorReuseInfoAndLifeTime(const ascir::NodeView &node, const af::AscTensor *output, TensorInfo &tensor_info, | 40 | void InitTensorReuseInfoAndLifeTime(const ascir::NodeView &node, const af::AscTensor *output, TensorInfo &tensor_info, |
| 36 | bool is_reduce_mem_reuse, bool is_cube_none_db) const; | 41 | bool is_reduce_mem_reuse, bool is_cube_none_db) const; |
| 37 | void InitTensorReuseInfo(const ascir::NodeView &node, const af::AscTensor *output, TensorInfo &tensor_info, | 42 | void InitTensorReuseInfo(const ascir::NodeView &node, const af::AscTensor *output, TensorInfo &tensor_info, |
| @@ -31,6 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | 33 | ||
| 34 | + | ||
| 34 | 35 | ||
| 35 | using namespace ascir; | 36 | using namespace ascir; |
| 36 | using namespace optimize; | 37 | using namespace optimize; |
| @@ -638,7 +639,10 @@ Status Optimizer::OptimizeFusedAscBackend(const af::ComputeGraphPtr &fused_graph | |||
| 638 | } | 639 | } |
| 639 | } | 640 | } |
| 640 | fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end()); | 641 | fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end()); |
| 641 | - GE_CHK_STATUS_RET(BufQueAllocator().AllocBufQue(fused_scheduled_result)); | 642 | + BufQueAllocator allocator; |
| 643 | + GE_CHK_STATUS_RET(allocator.PrepareImplGraphMemoryPlan(fused_scheduled_result)); | ||
| 644 | + GE_CHK_STATUS_RET(StaticUbTemplateFilter().Filter(fused_scheduled_result)); | ||
| 645 | + GE_CHK_STATUS_RET(allocator.CollectFusedIoNodes(fused_scheduled_result)); | ||
| 642 | GELOGI("AllocBufQue end"); | 646 | GELOGI("AllocBufQue end"); |
| 643 | TryEnableGroupParallel(fused_scheduled_result); | 647 | TryEnableGroupParallel(fused_scheduled_result); |
| 644 | for (auto &scheduled_results : fused_scheduled_result.node_idx_to_scheduled_results) { | 648 | for (auto &scheduled_results : fused_scheduled_result.node_idx_to_scheduled_results) { |
| @@ -957,11 +961,14 @@ Status Optimizer::Optimize(af::AscGraph &hint_graph, FusedScheduledResult &fused | |||
| 957 | GE_ASSERT_SUCCESS(OptimizeForHintGraph(hint_graph, fused_scheduled_result.node_idx_to_scheduled_results[0UL]), | 961 | GE_ASSERT_SUCCESS(OptimizeForHintGraph(hint_graph, fused_scheduled_result.node_idx_to_scheduled_results[0UL]), |
| 958 | "Failed to optimize for graph:[%s].", hint_graph.GetName().c_str()); | 962 | "Failed to optimize for graph:[%s].", hint_graph.GetName().c_str()); |
| 959 | // 内存分配 | 963 | // 内存分配 |
| 960 | - GE_CHK_STATUS_RET(BufQueAllocator().AllocBufQue(fused_scheduled_result)); | 964 | + BufQueAllocator allocator; |
| 965 | + GE_CHK_STATUS_RET(allocator.PrepareImplGraphMemoryPlan(fused_scheduled_result)); | ||
| 961 | if (options_.graph_type == GraphType::kAscGraph) { | 966 | if (options_.graph_type == GraphType::kAscGraph) { |
| 962 | fused_scheduled_result.fused_graph_name = hint_graph.GetName().c_str(); | 967 | fused_scheduled_result.fused_graph_name = hint_graph.GetName().c_str(); |
| 963 | fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end()); | 968 | fused_scheduled_result.origin_vars.assign(original_var_set.begin(), original_var_set.end()); |
| 964 | } | 969 | } |
| 970 | + GE_CHK_STATUS_RET(StaticUbTemplateFilter().Filter(fused_scheduled_result)); | ||
| 971 | + GE_CHK_STATUS_RET(allocator.CollectFusedIoNodes(fused_scheduled_result)); | ||
| 965 | GELOGI("AllocBufQue end"); | 972 | GELOGI("AllocBufQue end"); |
| 966 | TryEnableGroupParallel(fused_scheduled_result); | 973 | TryEnableGroupParallel(fused_scheduled_result); |
| 967 | ExecSeqAdvancedOfLoad(fused_scheduled_result); | 974 | ExecSeqAdvancedOfLoad(fused_scheduled_result); |
| @@ -0,0 +1,416 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +namespace optimize { | ||
| 28 | +namespace { | ||
| 29 | +constexpr const char *kLogPrefix = "[StaticUbTemplateFilter]"; | ||
| 30 | +constexpr size_t kMaxExprLogLength = 512UL; | ||
| 31 | +constexpr uint32_t kMaxRuntimeSpecValueLen = 16U; | ||
| 32 | +constexpr const char *kAicoreSpecLabel = "AICoreSpec"; | ||
| 33 | +constexpr const char *kUbSizeSpecKey = "ub_size"; | ||
| 34 | + | ||
| 35 | +enum class EvalStatus { | ||
| 36 | + kKnown, | ||
| 37 | + kUnknown, | ||
| 38 | + kFailed, | ||
| 39 | +}; | ||
| 40 | + | ||
| 41 | +struct EvalResult { | ||
| 42 | + EvalStatus status = EvalStatus::kUnknown; | ||
| 43 | + int64_t min_ub_usage = 0; | ||
| 44 | + af::Expression origin_expr; | ||
| 45 | + af::Expression min_expr; | ||
| 46 | +}; | ||
| 47 | + | ||
| 48 | +struct TemplatePosition { | ||
| 49 | + size_t node_idx = 0UL; | ||
| 50 | + size_t result_idx = 0UL; | ||
| 51 | + size_t group_idx = 0UL; | ||
| 52 | + size_t impl_idx = 0UL; | ||
| 53 | +}; | ||
| 54 | + | ||
| 55 | +struct FilterState { | ||
| 56 | + ascir::FusedScheduledResult &fused_scheduled_result; | ||
| 57 | + int64_t ub_size = 0; | ||
| 58 | +}; | ||
| 59 | + | ||
| 60 | +struct UbLimitResult { | ||
| 61 | + bool has_ub_limit = false; | ||
| 62 | + int64_t ub_size = 0; | ||
| 63 | +}; | ||
| 64 | + | ||
| 65 | +std::string ExprToString(const af::Expression &expr) { | ||
| 66 | + if (!expr.IsValid()) { | ||
| 67 | + return "<invalid>"; | ||
| 68 | + } | ||
| 69 | + const auto expr_str_ptr = expr.Str(); | ||
| 70 | + if (expr_str_ptr == nullptr || expr_str_ptr.get() == nullptr) { | ||
| 71 | + return "<null>"; | ||
| 72 | + } | ||
| 73 | + std::string expr_str = expr_str_ptr.get(); | ||
| 74 | + if (expr_str.size() <= kMaxExprLogLength) { | ||
| 75 | + return expr_str; | ||
| 76 | + } | ||
| 77 | + return expr_str.substr(0UL, kMaxExprLogLength) + "..."; | ||
| 78 | +} | ||
| 79 | + | ||
| 80 | +const char *GetGraphName(const ge::AscendString &graph_name) { | ||
| 81 | + const auto *name = graph_name.GetString(); | ||
| 82 | + return (name == nullptr || name[0] == '\0') ? "<null>" : name; | ||
| 83 | +} | ||
| 84 | + | ||
| 85 | +std::string BuildTemplateName(size_t node_idx, size_t result_idx, size_t group_idx, size_t impl_idx) { | ||
| 86 | + return "node" + std::to_string(node_idx) + "_result" + std::to_string(result_idx) + "_group" + | ||
| 87 | + std::to_string(group_idx) + "_impl" + std::to_string(impl_idx); | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +void AppendReplacement(const af::Expression &src, const af::Expression &dst, | ||
| 91 | + std::vector<std::pair<af::Expression, af::Expression>> &replacements) { | ||
| 92 | + if (!src.IsValid() || !dst.IsValid()) { | ||
| 93 | + return; | ||
| 94 | + } | ||
| 95 | + const auto iter = | ||
| 96 | + std::find_if(replacements.cbegin(), replacements.cend(), [&src](const auto &item) { return item.first == src; }); | ||
| 97 | + if (iter == replacements.cend()) { | ||
| 98 | + replacements.emplace_back(src, dst); | ||
| 99 | + } | ||
| 100 | +} | ||
| 101 | + | ||
| 102 | +void AppendVarOneReplacements(const std::vector<af::Expression> &vars, | ||
| 103 | + std::vector<std::pair<af::Expression, af::Expression>> &replacements) { | ||
| 104 | + for (const auto &var : vars) { | ||
| 105 | + AppendReplacement(var, af::sym::kSymbolOne, replacements); | ||
| 106 | + } | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +void BuildReplacements(const ascir::UbExprContext &context, | ||
| 110 | + std::vector<std::pair<af::Expression, af::Expression>> &container_replacements, | ||
| 111 | + std::vector<std::pair<af::Expression, af::Expression>> &var_replacements) { | ||
| 112 | + for (const auto &item : context.container_expr) { | ||
| 113 | + AppendReplacement(item.first, item.second, container_replacements); | ||
| 114 | + } | ||
| 115 | + for (const auto &item : context.var_min_values) { | ||
| 116 | + AppendReplacement(item.first, item.second, var_replacements); | ||
| 117 | + } | ||
| 118 | + for (const auto &item : context.const_vars) { | ||
| 119 | + AppendReplacement(item.first, af::Symbol(item.second), var_replacements); | ||
| 120 | + } | ||
| 121 | + for (const auto &item : context.static_size_vars) { | ||
| 122 | + AppendReplacement(item.first, item.second, var_replacements); | ||
| 123 | + } | ||
| 124 | + AppendVarOneReplacements(context.dynamic_size_vars, var_replacements); | ||
| 125 | +} | ||
| 126 | + | ||
| 127 | +af::Expression ApplyReplacements(const af::Expression &expr, | ||
| 128 | + const std::vector<std::pair<af::Expression, af::Expression>> &complex_replacements, | ||
| 129 | + const std::vector<std::pair<af::Expression, af::Expression>> &symbol_replacements) { | ||
| 130 | + af::Expression result = expr; | ||
| 131 | + if (!complex_replacements.empty()) { | ||
| 132 | + result = result.Replace(complex_replacements); | ||
| 133 | + } | ||
| 134 | + if (!symbol_replacements.empty()) { | ||
| 135 | + result = result.Subs(symbol_replacements); | ||
| 136 | + } | ||
| 137 | + if (result.IsValid()) { | ||
| 138 | + result = result.Simplify(); | ||
| 139 | + } | ||
| 140 | + return result; | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +bool TryGetConstInt64(const af::Expression &expr, int64_t &value) { | ||
| 144 | + if (!expr.IsValid() || !expr.IsConstExpr()) { | ||
| 145 | + return false; | ||
| 146 | + } | ||
| 147 | + if (expr.GetExprType() == af::ExprType::kExprConstantInteger) { | ||
| 148 | + return expr.GetConstValue(value); | ||
| 149 | + } | ||
| 150 | + if (expr.GetExprType() != af::ExprType::kExprConstantRation && | ||
| 151 | + expr.GetExprType() != af::ExprType::kExprConstantRealDouble) { | ||
| 152 | + return false; | ||
| 153 | + } | ||
| 154 | + double double_value = 0.0; | ||
| 155 | + if (!expr.GetConstValue(double_value) || !std::isfinite(double_value)) { | ||
| 156 | + return false; | ||
| 157 | + } | ||
| 158 | + if (double_value < static_cast<double>(std::numeric_limits<int64_t>::min()) || | ||
| 159 | + double_value > static_cast<double>(std::numeric_limits<int64_t>::max())) { | ||
| 160 | + return false; | ||
| 161 | + } | ||
| 162 | + double integer_value = 0.0; | ||
| 163 | + const double fraction_value = std::modf(double_value, &integer_value); | ||
| 164 | + if (fraction_value > 0.0 || fraction_value < 0.0) { | ||
| 165 | + return false; | ||
| 166 | + } | ||
| 167 | + value = static_cast<int64_t>(integer_value); | ||
| 168 | + return true; | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +EvalResult EvalMinUbUsage(const ascir::UbExprContext &context) { | ||
| 172 | + EvalResult eval_result; | ||
| 173 | + const auto build_result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 174 | + if (!build_result.has_ub_expr) { | ||
| 175 | + eval_result.status = EvalStatus::kUnknown; | ||
| 176 | + return eval_result; | ||
| 177 | + } | ||
| 178 | + eval_result.origin_expr = build_result.ub_expr; | ||
| 179 | + | ||
| 180 | + std::vector<std::pair<af::Expression, af::Expression>> container_replacements; | ||
| 181 | + std::vector<std::pair<af::Expression, af::Expression>> var_replacements; | ||
| 182 | + BuildReplacements(context, container_replacements, var_replacements); | ||
| 183 | + eval_result.min_expr = ApplyReplacements(build_result.ub_expr, container_replacements, var_replacements); | ||
| 184 | + if (!eval_result.min_expr.IsValid()) { | ||
| 185 | + eval_result.status = EvalStatus::kFailed; | ||
| 186 | + return eval_result; | ||
| 187 | + } | ||
| 188 | + if (!eval_result.min_expr.FreeSymbols().empty()) { | ||
| 189 | + eval_result.status = EvalStatus::kUnknown; | ||
| 190 | + return eval_result; | ||
| 191 | + } | ||
| 192 | + if (!TryGetConstInt64(eval_result.min_expr, eval_result.min_ub_usage) || eval_result.min_ub_usage < 0) { | ||
| 193 | + eval_result.status = EvalStatus::kFailed; | ||
| 194 | + return eval_result; | ||
| 195 | + } | ||
| 196 | + eval_result.status = EvalStatus::kKnown; | ||
| 197 | + return eval_result; | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +EvalResult EvalGraphMinUbUsage(const af::AscGraph &graph) { | ||
| 201 | + ascir::UbExprContext context; | ||
| 202 | + try { | ||
| 203 | + const auto status = ascir::AscGraphUbExprBuilder().Build(graph, context); | ||
| 204 | + if (status != af::SUCCESS) { | ||
| 205 | + GELOGD("%s build UB expr failed, graph=%s", kLogPrefix, graph.GetName().c_str()); | ||
| 206 | + EvalResult result; | ||
| 207 | + result.status = EvalStatus::kFailed; | ||
| 208 | + return result; | ||
| 209 | + } | ||
| 210 | + return EvalMinUbUsage(context); | ||
| 211 | + } catch (const std::exception &e) { | ||
| 212 | + GELOGD("%s eval UB expr failed, graph=%s, reason=%s", kLogPrefix, graph.GetName().c_str(), e.what()); | ||
| 213 | + } catch (...) { | ||
| 214 | + GELOGD("%s eval UB expr failed, graph=%s, reason=unknown exception", kLogPrefix, graph.GetName().c_str()); | ||
| 215 | + } | ||
| 216 | + EvalResult result; | ||
| 217 | + result.status = EvalStatus::kFailed; | ||
| 218 | + result.origin_expr = context.ub_expr; | ||
| 219 | + return result; | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +bool TryParseRuntimeUbSize(const char *ub_size_str, int64_t &ub_size) { | ||
| 223 | + try { | ||
| 224 | + size_t parsed_size = 0UL; | ||
| 225 | + const std::string str_value(ub_size_str); | ||
| 226 | + ub_size = static_cast<int64_t>(std::stoll(str_value, &parsed_size)); | ||
| 227 | + if (parsed_size == str_value.size()) { | ||
| 228 | + return true; | ||
| 229 | + } | ||
| 230 | + GELOGD("%s parse runtime ub_size failed, value=%s", kLogPrefix, ub_size_str); | ||
| 231 | + } catch (const std::exception &e) { | ||
| 232 | + GELOGD("%s parse runtime ub_size failed, value=%s, reason=%s", kLogPrefix, ub_size_str, e.what()); | ||
| 233 | + } catch (...) { | ||
| 234 | + GELOGD("%s parse runtime ub_size failed, value=%s, reason=unknown exception", kLogPrefix, ub_size_str); | ||
| 235 | + } | ||
| 236 | + ub_size = 0; | ||
| 237 | + return false; | ||
| 238 | +} | ||
| 239 | + | ||
| 240 | +bool TryGetRuntimeUbSize(int64_t &ub_size) { | ||
| 241 | + char ub_size_str[kMaxRuntimeSpecValueLen] = {}; | ||
| 242 | + const auto ret = rtGetSocSpec(kAicoreSpecLabel, kUbSizeSpecKey, ub_size_str, kMaxRuntimeSpecValueLen); | ||
| 243 | + if (ret != RT_ERROR_NONE) { | ||
| 244 | + GELOGD("%s get runtime ub_size failed, ret=%d", kLogPrefix, ret); | ||
| 245 | + ub_size = 0; | ||
| 246 | + return false; | ||
| 247 | + } | ||
| 248 | + return TryParseRuntimeUbSize(ub_size_str, ub_size); | ||
| 249 | +} | ||
| 250 | + | ||
| 251 | +bool ShouldDropImplGraph(const af::AscGraph &impl_graph, int64_t ub_size, const TemplatePosition &position) { | ||
| 252 | + const auto eval_result = EvalGraphMinUbUsage(impl_graph); | ||
| 253 | + const auto template_name = | ||
| 254 | + BuildTemplateName(position.node_idx, position.result_idx, position.group_idx, position.impl_idx); | ||
| 255 | + if (eval_result.status == EvalStatus::kUnknown) { | ||
| 256 | + GELOGD( | ||
| 257 | + "%s keep template due to unknown UB expr, graph=%s, template=%s, tiling_case=%ld, ub_expr=%s, " | ||
| 258 | + "platform_ub_size=%ld", | ||
| 259 | + kLogPrefix, impl_graph.GetName().c_str(), template_name.c_str(), impl_graph.GetTilingKey(), | ||
| 260 | + ExprToString(eval_result.origin_expr).c_str(), ub_size); | ||
| 261 | + return false; | ||
| 262 | + } | ||
| 263 | + if (eval_result.status == EvalStatus::kFailed) { | ||
| 264 | + GELOGD( | ||
| 265 | + "%s keep template due to failed UB expr eval, graph=%s, template=%s, tiling_case=%ld, ub_expr=%s, min_expr=%s, " | ||
| 266 | + "platform_ub_size=%ld", | ||
| 267 | + kLogPrefix, impl_graph.GetName().c_str(), template_name.c_str(), impl_graph.GetTilingKey(), | ||
| 268 | + ExprToString(eval_result.origin_expr).c_str(), ExprToString(eval_result.min_expr).c_str(), ub_size); | ||
| 269 | + return false; | ||
| 270 | + } | ||
| 271 | + if (eval_result.min_ub_usage <= ub_size) { | ||
| 272 | + GELOGD( | ||
| 273 | + "%s keep template, graph=%s, template=%s, tiling_case=%ld, ub_expr=%s, min_expr=%s, min_ub_usage=%ld, " | ||
| 274 | + "platform_ub_size=%ld", | ||
| 275 | + kLogPrefix, impl_graph.GetName().c_str(), template_name.c_str(), impl_graph.GetTilingKey(), | ||
| 276 | + ExprToString(eval_result.origin_expr).c_str(), ExprToString(eval_result.min_expr).c_str(), | ||
| 277 | + eval_result.min_ub_usage, ub_size); | ||
| 278 | + return false; | ||
| 279 | + } | ||
| 280 | + GELOGD( | ||
| 281 | + "%s drop template, graph=%s, template=%s, tiling_case=%ld, ub_expr=%s, min_expr=%s, min_ub_usage=%ld, " | ||
| 282 | + "platform_ub_size=%ld, reason=min_ub_usage exceeds platform_ub_size", | ||
| 283 | + kLogPrefix, impl_graph.GetName().c_str(), template_name.c_str(), impl_graph.GetTilingKey(), | ||
| 284 | + ExprToString(eval_result.origin_expr).c_str(), ExprToString(eval_result.min_expr).c_str(), | ||
| 285 | + eval_result.min_ub_usage, ub_size); | ||
| 286 | + return true; | ||
| 287 | +} | ||
| 288 | + | ||
| 289 | +size_t CountImplGraphs(const std::vector<ascir::ScheduledResult> &scheduled_results) { | ||
| 290 | + size_t count = 0UL; | ||
| 291 | + for (const auto &scheduled_result : scheduled_results) { | ||
| 292 | + for (const auto &schedule_group : scheduled_result.schedule_groups) { | ||
| 293 | + count += schedule_group.impl_graphs.size(); | ||
| 294 | + } | ||
| 295 | + } | ||
| 296 | + return count; | ||
| 297 | +} | ||
| 298 | + | ||
| 299 | +bool FilterScheduledResult(FilterState &state, ascir::ScheduledResult &scheduled_result, size_t node_idx, | ||
| 300 | + size_t result_idx) { | ||
| 301 | + bool keep_scheduled_result = true; | ||
| 302 | + for (size_t group_idx = 0UL; group_idx < scheduled_result.schedule_groups.size(); ++group_idx) { | ||
| 303 | + auto &schedule_group = scheduled_result.schedule_groups[group_idx]; | ||
| 304 | + const size_t before_group_size = schedule_group.impl_graphs.size(); | ||
| 305 | + size_t impl_idx = 0UL; | ||
| 306 | + schedule_group.impl_graphs.erase( | ||
| 307 | + std::remove_if(schedule_group.impl_graphs.begin(), schedule_group.impl_graphs.end(), | ||
| 308 | + [&](const af::AscGraph &impl_graph) { | ||
| 309 | + const size_t current_impl_idx = impl_idx++; | ||
| 310 | + const TemplatePosition position = {node_idx, result_idx, group_idx, current_impl_idx}; | ||
| 311 | + const bool drop = ShouldDropImplGraph(impl_graph, state.ub_size, position); | ||
| 312 | + if (drop) { | ||
| 313 | + schedule_group.graph_name_to_score_funcs.erase(impl_graph.GetName()); | ||
| 314 | + } | ||
| 315 | + return drop; | ||
| 316 | + }), | ||
| 317 | + schedule_group.impl_graphs.end()); | ||
| 318 | + if (before_group_size > 0UL && schedule_group.impl_graphs.empty()) { | ||
| 319 | + GELOGD( | ||
| 320 | + "%s drop scheduled result because all templates in group are filtered, graph=%s, node_idx=%zu, " | ||
| 321 | + "result_idx=%zu, group_idx=%zu", | ||
| 322 | + kLogPrefix, GetGraphName(state.fused_scheduled_result.fused_graph_name), node_idx, result_idx, group_idx); | ||
| 323 | + keep_scheduled_result = false; | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | + return keep_scheduled_result; | ||
| 327 | +} | ||
| 328 | + | ||
| 329 | +af::Status FilterNodeScheduledResults(ascir::FusedScheduledResult &fused_scheduled_result, | ||
| 330 | + std::vector<ascir::ScheduledResult> &scheduled_results, int64_t ub_size, | ||
| 331 | + size_t node_idx, size_t &total_dropped) { | ||
| 332 | + const size_t before = CountImplGraphs(scheduled_results); | ||
| 333 | + FilterState state = {fused_scheduled_result, ub_size}; | ||
| 334 | + size_t result_idx = 0UL; | ||
| 335 | + scheduled_results.erase(std::remove_if(scheduled_results.begin(), scheduled_results.end(), | ||
| 336 | + [&](ascir::ScheduledResult &scheduled_result) { | ||
| 337 | + const size_t current_result_idx = result_idx++; | ||
| 338 | + return !FilterScheduledResult(state, scheduled_result, node_idx, | ||
| 339 | + current_result_idx); | ||
| 340 | + }), | ||
| 341 | + scheduled_results.end()); | ||
| 342 | + const size_t kept = CountImplGraphs(scheduled_results); | ||
| 343 | + const size_t dropped = before - kept; | ||
| 344 | + total_dropped += dropped; | ||
| 345 | + GELOGI("%s graph=%s, node_idx=%zu, templates_before=%zu, dropped=%zu, kept=%zu", kLogPrefix, | ||
| 346 | + GetGraphName(fused_scheduled_result.fused_graph_name), node_idx, before, dropped, kept); | ||
| 347 | + GE_ASSERT_TRUE(before == 0UL || !scheduled_results.empty(), "%s all templates are filtered, graph=%s, node_idx=%zu", | ||
| 348 | + kLogPrefix, GetGraphName(fused_scheduled_result.fused_graph_name), node_idx); | ||
| 349 | + return af::SUCCESS; | ||
| 350 | +} | ||
| 351 | + | ||
| 352 | +UbLimitResult GetUbLimit() { | ||
| 353 | + UbLimitResult result; | ||
| 354 | + int64_t ub_size_override = 0; | ||
| 355 | + const bool has_ub_size_override = ge::PlatformContext::GetInstance().TryGetUbSizeOverride(ub_size_override); | ||
| 356 | + if (has_ub_size_override && ub_size_override > 0) { | ||
| 357 | + result.has_ub_limit = true; | ||
| 358 | + result.ub_size = ub_size_override; | ||
| 359 | + return result; | ||
| 360 | + } | ||
| 361 | + | ||
| 362 | + ge::PlatformInfo platform_info; | ||
| 363 | + const bool has_platform_info = ge::PlatformContext::GetInstance().TryGetInitializedPlatformInfo(platform_info); | ||
| 364 | + if (has_platform_info && platform_info.ub_size > 0) { | ||
| 365 | + result.has_ub_limit = true; | ||
| 366 | + result.ub_size = platform_info.ub_size; | ||
| 367 | + return result; | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | + int64_t runtime_ub_size = 0; | ||
| 371 | + if (TryGetRuntimeUbSize(runtime_ub_size)) { | ||
| 372 | + result.has_ub_limit = true; | ||
| 373 | + result.ub_size = runtime_ub_size; | ||
| 374 | + return result; | ||
| 375 | + } | ||
| 376 | + | ||
| 377 | + if (has_ub_size_override) { | ||
| 378 | + result.has_ub_limit = true; | ||
| 379 | + result.ub_size = ub_size_override; | ||
| 380 | + return result; | ||
| 381 | + } | ||
| 382 | + if (has_platform_info) { | ||
| 383 | + result.has_ub_limit = true; | ||
| 384 | + result.ub_size = platform_info.ub_size; | ||
| 385 | + } | ||
| 386 | + return result; | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +} // namespace | ||
| 390 | + | ||
| 391 | +af::Status StaticUbTemplateFilter::Filter(ascir::FusedScheduledResult &fused_scheduled_result) const { | ||
| 392 | + const auto ub_limit = GetUbLimit(); | ||
| 393 | + if (!ub_limit.has_ub_limit) { | ||
| 394 | + GELOGD("%s skip UB template filter because platform info is not initialized, graph=%s", kLogPrefix, | ||
| 395 | + GetGraphName(fused_scheduled_result.fused_graph_name)); | ||
| 396 | + return af::SUCCESS; | ||
| 397 | + } | ||
| 398 | + const int64_t ub_size = ub_limit.ub_size; | ||
| 399 | + if (ub_size <= 0) { | ||
| 400 | + GELOGD("%s skip UB template filter because ub_size is invalid, graph=%s, ub_size=%ld", kLogPrefix, | ||
| 401 | + GetGraphName(fused_scheduled_result.fused_graph_name), ub_size); | ||
| 402 | + return af::SUCCESS; | ||
| 403 | + } | ||
| 404 | + | ||
| 405 | + size_t total_dropped = 0UL; | ||
| 406 | + for (size_t node_idx = 0UL; node_idx < fused_scheduled_result.node_idx_to_scheduled_results.size(); ++node_idx) { | ||
| 407 | + auto &scheduled_results = fused_scheduled_result.node_idx_to_scheduled_results[node_idx]; | ||
| 408 | + GE_CHK_STATUS_RET( | ||
| 409 | + FilterNodeScheduledResults(fused_scheduled_result, scheduled_results, ub_size, node_idx, total_dropped)); | ||
| 410 | + } | ||
| 411 | + GELOGI("%s graph=%s, total_dropped=%zu, platform_ub_size=%ld", kLogPrefix, | ||
| 412 | + GetGraphName(fused_scheduled_result.fused_graph_name), total_dropped, ub_size); | ||
| 413 | + return af::SUCCESS; | ||
| 414 | +} | ||
| 415 | + | ||
| 416 | +} // namespace optimize | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +namespace optimize { | ||
| 17 | + | ||
| 18 | +class StaticUbTemplateFilter { | ||
| 19 | + public: | ||
| 20 | + af::Status Filter(ascir::FusedScheduledResult &fused_scheduled_result) const; | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +} // namespace optimize | ||
| 24 | + | ||
| 25 | + | ||
| @@ -43,6 +43,18 @@ rtError_t RuntimeStub::rtGetSocVersion(char *version, const uint32_t maxLen) { | |||
| 43 | 43 | ||
| 44 | rtError_t RuntimeStub::rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) { | 44 | rtError_t RuntimeStub::rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) { |
| 45 | (void)label; | 45 | (void)label; |
| 46 | + if (strcmp(key, "NpuArch") == 0) { | ||
| 47 | + (void)strcpy_s(val, maxLen, "2201"); | ||
| 48 | + return RT_ERROR_NONE; | ||
| 49 | + } | ||
| 50 | + if (strcmp(key, "vector_core_cnt") == 0) { | ||
| 51 | + (void)strcpy_s(val, maxLen, "48"); | ||
| 52 | + return RT_ERROR_NONE; | ||
| 53 | + } | ||
| 54 | + if (strcmp(key, "ub_size") == 0) { | ||
| 55 | + (void)strcpy_s(val, maxLen, "245760"); | ||
| 56 | + return RT_ERROR_NONE; | ||
| 57 | + } | ||
| 46 | // 返回 padding_size = 32 (兼容旧平台) | 58 | // 返回 padding_size = 32 (兼容旧平台) |
| 47 | if (strcmp(key, "padding_size") == 0) { | 59 | if (strcmp(key, "padding_size") == 0) { |
| 48 | (void)strcpy_s(val, maxLen, "32"); | 60 | (void)strcpy_s(val, maxLen, "32"); |
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | + | ||
| 15 | 16 | ||
| 16 | 17 | ||
| 17 | 18 | ||
| @@ -21,6 +22,34 @@ | |||
| 21 | using rtError_t = int32_t; | 22 | using rtError_t = int32_t; |
| 22 | constexpr rtError_t RT_ERROR_NONE = 0; | 23 | constexpr rtError_t RT_ERROR_NONE = 0; |
| 23 | namespace ge { | 24 | namespace ge { |
| 25 | +struct RuntimeSocSpecDefaults { | ||
| 26 | + const char *npu_arch = "3510"; | ||
| 27 | + const char *fallback = "0"; | ||
| 28 | +}; | ||
| 29 | + | ||
| 30 | +struct RuntimeSocSpecValue { | ||
| 31 | + const char *key; | ||
| 32 | + const char *value; | ||
| 33 | +}; | ||
| 34 | + | ||
| 35 | +inline rtError_t CopyRuntimeSocSpecValue(const char *label, const char *key, char *val, const uint32_t maxLen, | ||
| 36 | + const RuntimeSocSpecDefaults &defaults) { | ||
| 37 | + (void)label; | ||
| 38 | + const RuntimeSocSpecValue specs[] = { | ||
| 39 | + {"NpuArch", defaults.npu_arch}, | ||
| 40 | + {"vector_core_cnt", "48"}, | ||
| 41 | + {"ub_size", "245760"}, | ||
| 42 | + }; | ||
| 43 | + for (const auto &spec : specs) { | ||
| 44 | + if (std::strcmp(key, spec.key) == 0) { | ||
| 45 | + (void)strcpy_s(val, maxLen, spec.value); | ||
| 46 | + return RT_ERROR_NONE; | ||
| 47 | + } | ||
| 48 | + } | ||
| 49 | + (void)strcpy_s(val, maxLen, defaults.fallback); | ||
| 50 | + return RT_ERROR_NONE; | ||
| 51 | +} | ||
| 52 | + | ||
| 24 | class RuntimeStub { | 53 | class RuntimeStub { |
| 25 | public: | 54 | public: |
| 26 | virtual ~RuntimeStub() = default; | 55 | virtual ~RuntimeStub() = default; |
| @@ -55,10 +84,7 @@ class RuntimeStubV2Common : public RuntimeStub { | |||
| 55 | } | 84 | } |
| 56 | 85 | ||
| 57 | rtError_t rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) override { | 86 | rtError_t rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) override { |
| 58 | - (void)label; | 87 | + return CopyRuntimeSocSpecValue(label, key, val, maxLen, RuntimeSocSpecDefaults{"3510", "0"}); |
| 59 | - (void)key; | ||
| 60 | - (void)strcpy_s(val, maxLen, "3510"); | ||
| 61 | - return RT_ERROR_NONE; | ||
| 62 | } | 88 | } |
| 63 | }; | 89 | }; |
| 64 | } // namespace ge | 90 | } // namespace ge |
| @@ -10,6 +10,7 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | + | ||
| 13 | #include_next <runtime_stub.h> | 14 | #include_next <runtime_stub.h> |
| 14 | namespace af { | 15 | namespace af { |
| 15 | using ge::RuntimeStub; | 16 | using ge::RuntimeStub; |
| @@ -21,10 +22,7 @@ class RuntimeStubV2 : public ge::RuntimeStub { | |||
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | rtError_t rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) override { | 24 | rtError_t rtGetSocSpec(const char *label, const char *key, char *val, const uint32_t maxLen) override { |
| 24 | - (void)label; | 25 | + return ge::CopyRuntimeSocSpecValue(label, key, val, maxLen, ge::RuntimeSocSpecDefaults{"3510", "0"}); |
| 25 | - (void)key; | ||
| 26 | - (void)strcpy_s(val, maxLen, "3510"); | ||
| 27 | - return RT_ERROR_NONE; | ||
| 28 | } | 26 | } |
| 29 | }; | 27 | }; |
| 30 | } // namespace af | 28 | } // namespace af |
| @@ -4053,7 +4053,7 @@ TEST_F(OptimizerSt, NodeCacheMarkerReduce) { | |||
| 4053 | ::ascir::FusedScheduledResult fused_scheduled_result; | 4053 | ::ascir::FusedScheduledResult fused_scheduled_result; |
| 4054 | Status res = optimizer.Optimize(graph, fused_scheduled_result); | 4054 | Status res = optimizer.Optimize(graph, fused_scheduled_result); |
| 4055 | EXPECT_EQ(res, af::SUCCESS); | 4055 | EXPECT_EQ(res, af::SUCCESS); |
| 4056 | - EXPECT_EQ(fused_scheduled_result.node_idx_to_scheduled_results[0].size(), 4UL); | 4056 | + EXPECT_EQ(fused_scheduled_result.node_idx_to_scheduled_results[0].size(), 3UL); |
| 4057 | const auto &impl_graphs = fused_scheduled_result.node_idx_to_scheduled_results[0][0].schedule_groups[0].impl_graphs; | 4057 | const auto &impl_graphs = fused_scheduled_result.node_idx_to_scheduled_results[0][0].schedule_groups[0].impl_graphs; |
| 4058 | EXPECT_EQ(impl_graphs.size(), 2); | 4058 | EXPECT_EQ(impl_graphs.size(), 2); |
| 4059 | 4059 | ||
| @@ -1,21 +1,21 @@ | |||
| 1 | # -*- coding: utf-8 -*- | 1 | # -*- coding: utf-8 -*- |
| 2 | # ----------------------------------------------------------------------------------------------------------- | 2 | # ----------------------------------------------------------------------------------------------------------- |
| 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. | 3 | # Copyright (c) 2025 Huawei Technologies Co., Ltd. |
| 4 | -# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of |
| 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). | 5 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. | 6 | # Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, |
| 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 8 | # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. |
| 9 | # See LICENSE in the root of the software repository for the full text of the License. | 9 | # See LICENSE in the root of the software repository for the full text of the License. |
| 10 | # ----------------------------------------------------------------------------------------------------------- | 10 | # ----------------------------------------------------------------------------------------------------------- |
| 11 | 11 | ||
| 12 | -import math | ||
| 13 | import pytest | 12 | import pytest |
| 14 | import json | 13 | import json |
| 15 | import time | 14 | import time |
| 16 | import os | 15 | import os |
| 17 | import shutil | 16 | import shutil |
| 18 | from autofuse.pyautofuse import ascir, Autofuser, AutofuserOptions, Schedule, CodeGen | 17 | from autofuse.pyautofuse import ascir, Autofuser, AutofuserOptions, Schedule, CodeGen |
| 18 | + | ||
| 19 | try: | 19 | try: |
| 20 | from autofuse import ascir_api | 20 | from autofuse import ascir_api |
| 21 | except ImportError: | 21 | except ImportError: |
| @@ -24,19 +24,19 @@ from ascir import Max, Min, Mod | |||
| 24 | 24 | ||
| 25 | PYF_PATH = os.path.dirname(os.path.realpath(__file__)) | 25 | PYF_PATH = os.path.dirname(os.path.realpath(__file__)) |
| 26 | 26 | ||
| 27 | -ascir.utils.set_platform("2201", 1, 1024) | 27 | +ascir.utils.set_platform("2201", 1, 245760) |
| 28 | 28 | ||
| 29 | 29 | ||
| 30 | # pyascir 构图能力暂不支持 | 30 | # pyascir 构图能力暂不支持 |
| 31 | -class TestAscir(): | 31 | +class TestAscir: |
| 32 | 32 | ||
| 33 | def test_graph_create_size_expr_by_long(): | 33 | def test_graph_create_size_expr_by_long(): |
| 34 | s0 = ascir.SizeExpr() | 34 | s0 = ascir.SizeExpr() |
| 35 | assert s0 == 1 | 35 | assert s0 == 1 |
| 36 | try: | 36 | try: |
| 37 | - s0 = ascir.SizeExpr('100') | 37 | + s0 = ascir.SizeExpr("100") |
| 38 | except Exception as e: | 38 | except Exception as e: |
| 39 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 39 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 40 | 40 | ||
| 41 | assert s0 == 1 | 41 | assert s0 == 1 |
| 42 | s0 = ascir.SizeExpr(0) | 42 | s0 = ascir.SizeExpr(0) |
| @@ -67,20 +67,22 @@ class TestAscir(): | |||
| 67 | 67 | ||
| 68 | def test_graph_create_size(): | 68 | def test_graph_create_size(): |
| 69 | graph = ascir.HintGraph("test") | 69 | graph = ascir.HintGraph("test") |
| 70 | - s0 = graph.create_size("s0") | 70 | + graph.create_size("s0") |
| 71 | - s1 = graph.create_size("s1") | 71 | + graph.create_size("s1") |
| 72 | - s2 = graph.create_size("s2") | 72 | + graph.create_size("s2") |
| 73 | 73 | ||
| 74 | debug_str = ascir.utils.debug_str(graph) | 74 | debug_str = ascir.utils.debug_str(graph) |
| 75 | - assert debug_str == "".join([ | 75 | + assert debug_str == "".join( |
| 76 | - "Graph: test\n", | 76 | + [ |
| 77 | - "Sizes:\n", | 77 | + "Graph: test\n", |
| 78 | - " s0: VAR\n", | 78 | + "Sizes:\n", |
| 79 | - " s1: VAR\n", | 79 | + " s0: VAR\n", |
| 80 | - " s2: VAR\n", | 80 | + " s1: VAR\n", |
| 81 | - "Axis:\n", | 81 | + " s2: VAR\n", |
| 82 | - "Nodes:\n", | 82 | + "Axis:\n", |
| 83 | - ]) | 83 | + "Nodes:\n", |
| 84 | + ] | ||
| 85 | + ) | ||
| 84 | 86 | ||
| 85 | 87 | ||
| 86 | def test_graph_create_axis(): | 88 | def test_graph_create_axis(): |
| @@ -89,33 +91,35 @@ class TestAscir(): | |||
| 89 | s1 = graph.create_size("s1") | 91 | s1 = graph.create_size("s1") |
| 90 | s2 = graph.create_size("s2") | 92 | s2 = graph.create_size("s2") |
| 91 | 93 | ||
| 92 | - z0 = graph.create_axis("z0", s0) | 94 | + graph.create_axis("z0", s0) |
| 93 | - z1 = graph.create_axis("z1", s1) | 95 | + graph.create_axis("z1", s1) |
| 94 | - z2 = graph.create_axis("z2", s2) | 96 | + graph.create_axis("z2", s2) |
| 95 | - z3 = graph.create_axis("z3", 512) | 97 | + graph.create_axis("z3", 512) |
| 96 | - z4 = graph.create_axis("z4", s1 + s2) | 98 | + graph.create_axis("z4", s1 + s2) |
| 97 | 99 | ||
| 98 | debug_str = ascir.utils.debug_str(graph) | 100 | debug_str = ascir.utils.debug_str(graph) |
| 99 | - assert debug_str == "".join([ | 101 | + assert debug_str == "".join( |
| 100 | - "Graph: test\n", | 102 | + [ |
| 101 | - "Sizes:\n", | 103 | + "Graph: test\n", |
| 102 | - " s0: VAR\n", | 104 | + "Sizes:\n", |
| 103 | - " s1: VAR\n", | 105 | + " s0: VAR\n", |
| 104 | - " s2: VAR\n", | 106 | + " s1: VAR\n", |
| 105 | - "Axis:\n", | 107 | + " s2: VAR\n", |
| 106 | - " z0(0) : ORIGINAL, size:s0, \n", | 108 | + "Axis:\n", |
| 107 | - " z1(1) : ORIGINAL, size:s1, \n", | 109 | + " z0(0) : ORIGINAL, size:s0, \n", |
| 108 | - " z2(2) : ORIGINAL, size:s2, \n", | 110 | + " z1(1) : ORIGINAL, size:s1, \n", |
| 109 | - " z3(3) : ORIGINAL, size:512, \n", | 111 | + " z2(2) : ORIGINAL, size:s2, \n", |
| 110 | - " z4(4) : ORIGINAL, size:(s1 + s2), \n", | 112 | + " z3(3) : ORIGINAL, size:512, \n", |
| 111 | - "Nodes:\n", | 113 | + " z4(4) : ORIGINAL, size:(s1 + s2), \n", |
| 112 | - ]) | 114 | + "Nodes:\n", |
| 115 | + ] | ||
| 116 | + ) | ||
| 113 | 117 | ||
| 114 | 118 | ||
| 115 | def test_graph_create_node(): | 119 | def test_graph_create_node(): |
| 116 | graph = ascir.HintGraph("test") | 120 | graph = ascir.HintGraph("test") |
| 117 | 121 | ||
| 118 | - x = ascir.ops.Data("x", graph) | 122 | + ascir.ops.Data("x", graph) |
| 119 | debug_str = ascir.utils.debug_str(graph) | 123 | debug_str = ascir.utils.debug_str(graph) |
| 120 | assert debug_str | 124 | assert debug_str |
| 121 | 125 | ||
| @@ -134,8 +138,12 @@ class TestAscir(): | |||
| 134 | try: | 138 | try: |
| 135 | graph.infer_dtypes() | 139 | graph.infer_dtypes() |
| 136 | except Exception as e: | 140 | except Exception as e: |
| 137 | - assert e.args[0] == 'Check dtype failed for cast Cast; input_dtypes: [DT_INT8], output_dytpes: [DT_INT4]' | 141 | + assert ( |
| 142 | + e.args[0] | ||
| 143 | + == "Check dtype failed for cast Cast; input_dtypes: [DT_INT8], output_dytpes: [DT_INT4]" | ||
| 144 | + ) | ||
| 138 | import sys | 145 | import sys |
| 146 | + | ||
| 139 | # 通常为2 (变量 + getrefcount 参数) | 147 | # 通常为2 (变量 + getrefcount 参数) |
| 140 | print(f"x.attr ref count is {sys.getrefcount(x.attr)}") | 148 | print(f"x.attr ref count is {sys.getrefcount(x.attr)}") |
| 141 | del x.attr | 149 | del x.attr |
| @@ -145,21 +153,23 @@ class TestAscir(): | |||
| 145 | graph = ascir.HintGraph("test") | 153 | graph = ascir.HintGraph("test") |
| 146 | 154 | ||
| 147 | x = ascir_api.Data(graph, dtype=ascir.dtypes.int8) | 155 | x = ascir_api.Data(graph, dtype=ascir.dtypes.int8) |
| 148 | - cast = None | ||
| 149 | try: | 156 | try: |
| 150 | - cast = ascir_api.Cast(graph, x, dtype=ascir.dtypes.int4, axis=[]) | 157 | + ascir_api.Cast(graph, x, dtype=ascir.dtypes.int4, axis=[]) |
| 151 | except Exception as e: | 158 | except Exception as e: |
| 152 | - assert e.args[0] == 'Check dtype failed for cast_0 Cast; input_dtypes: [DT_INT8], output_dytpes: [DT_INT4]' | 159 | + assert ( |
| 160 | + e.args[0] | ||
| 161 | + == "Check dtype failed for cast_0 Cast; input_dtypes: [DT_INT8], output_dytpes: [DT_INT4]" | ||
| 162 | + ) | ||
| 153 | 163 | ||
| 154 | 164 | ||
| 155 | def test_graph_create_const_node_with_value_str_attr(): | 165 | def test_graph_create_const_node_with_value_str_attr(): |
| 156 | graph = ascir.HintGraph("test") | 166 | graph = ascir.HintGraph("test") |
| 157 | 167 | ||
| 158 | x = ascir.ops.Scalar("x", graph) | 168 | x = ascir.ops.Scalar("x", graph) |
| 159 | - x.attr.ir_attr.value = '11.1' | 169 | + x.attr.ir_attr.value = "11.1" |
| 160 | x.y.dtype = ascir.dtypes.float32 | 170 | x.y.dtype = ascir.dtypes.float32 |
| 161 | debug_str = ascir.utils.debug_str(graph) | 171 | debug_str = ascir.utils.debug_str(graph) |
| 162 | - assert x.attr.ir_attr.value == '11.1' | 172 | + assert x.attr.ir_attr.value == "11.1" |
| 163 | assert debug_str | 173 | assert debug_str |
| 164 | 174 | ||
| 165 | 175 | ||
| @@ -176,7 +186,7 @@ class TestAscir(): | |||
| 176 | x = ascir.ops.Data("x", graph) | 186 | x = ascir.ops.Data("x", graph) |
| 177 | x.attr.sched.axis = [z0, z1, z2] | 187 | x.attr.sched.axis = [z0, z1, z2] |
| 178 | 188 | ||
| 179 | - load = ascir.ops.Load("load") | 189 | + ascir.ops.Load("load") |
| 180 | x.y.dtype = ascir.dtypes.float16 | 190 | x.y.dtype = ascir.dtypes.float16 |
| 181 | x.y.axis = [z0, z1, z2] | 191 | x.y.axis = [z0, z1, z2] |
| 182 | assert x.y.axis == [z0.id, z1.id, z2.id] | 192 | assert x.y.axis == [z0.id, z1.id, z2.id] |
| @@ -198,7 +208,10 @@ class TestAscir(): | |||
| 198 | try: | 208 | try: |
| 199 | graph.infer_dtypes() | 209 | graph.infer_dtypes() |
| 200 | except Exception as e: | 210 | except Exception as e: |
| 201 | - assert e.args[0] == 'Infer dtype failed for load Load; input_dtypes: [DT_INT64] is not supportted now' | 211 | + assert ( |
| 212 | + e.args[0] | ||
| 213 | + == "Infer dtype failed for load Load; input_dtypes: [DT_INT64] is not supportted now" | ||
| 214 | + ) | ||
| 202 | graph.infer_dtypes() | 215 | graph.infer_dtypes() |
| 203 | debug_str = ascir.utils.debug_str(graph) | 216 | debug_str = ascir.utils.debug_str(graph) |
| 204 | assert debug_str | 217 | assert debug_str |
| @@ -220,25 +233,27 @@ class TestAscir(): | |||
| 220 | start = time.time() | 233 | start = time.time() |
| 221 | time.sleep(0.1) | 234 | time.sleep(0.1) |
| 222 | end = time.time() | 235 | end = time.time() |
| 223 | - ascir.utils.duration_record(["device", "fused_graph"], int(start * 1e9), int((end - start) * 1e9)) | 236 | + ascir.utils.duration_record( |
| 237 | + ["device", "fused_graph"], int(start * 1e9), int((end - start) * 1e9) | ||
| 238 | + ) | ||
| 224 | ascir.utils.report_durations() | 239 | ascir.utils.report_durations() |
| 225 | try: | 240 | try: |
| 226 | ascir.utils.duration_record(["device", "fused_graph"], "time") | 241 | ascir.utils.duration_record(["device", "fused_graph"], "time") |
| 227 | except TypeError as e: | 242 | except TypeError as e: |
| 228 | - assert e.args[0] == 'UtilsDurationRecord param parse failed' | 243 | + assert e.args[0] == "UtilsDurationRecord param parse failed" |
| 229 | 244 | ||
| 230 | try: | 245 | try: |
| 231 | ascir.utils.duration_record(["device", "fused_graph"], int(-1), int(-1)) | 246 | ascir.utils.duration_record(["device", "fused_graph"], int(-1), int(-1)) |
| 232 | except TypeError as e: | 247 | except TypeError as e: |
| 233 | - assert e.args[0] == 'duration param is invalid' | 248 | + assert e.args[0] == "duration param is invalid" |
| 234 | 249 | ||
| 235 | try: | 250 | try: |
| 236 | ascir.utils.duration_record([0, 1], int(-1), int(-1)) | 251 | ascir.utils.duration_record([0, 1], int(-1), int(-1)) |
| 237 | except TypeError as e: | 252 | except TypeError as e: |
| 238 | - assert e.args[0] == 'target param is invalid' | 253 | + assert e.args[0] == "target param is invalid" |
| 239 | 254 | ||
| 240 | 255 | ||
| 241 | -class TestAutofuseLoadAbsStore(): | 256 | +class TestAutofuseLoadAbsStore: |
| 242 | 257 | ||
| 243 | def construct_graph(): | 258 | def construct_graph(): |
| 244 | graph = ascir.HintGraph("LoadAbsStore") | 259 | graph = ascir.HintGraph("LoadAbsStore") |
| @@ -266,7 +281,7 @@ class TestAutofuseLoadAbsStore(): | |||
| 266 | try: | 281 | try: |
| 267 | load.attr.ir_attr.offset = "3" | 282 | load.attr.ir_attr.offset = "3" |
| 268 | except Exception as e: | 283 | except Exception as e: |
| 269 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 284 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 270 | offset_of_0 = ascir.SizeExpr(0) | 285 | offset_of_0 = ascir.SizeExpr(0) |
| 271 | load.attr.ir_attr.offset = offset_of_0 | 286 | load.attr.ir_attr.offset = offset_of_0 |
| 272 | assert load.attr.ir_attr.offset.expression == "0" | 287 | assert load.attr.ir_attr.offset.expression == "0" |
| @@ -289,7 +304,7 @@ class TestAutofuseLoadAbsStore(): | |||
| 289 | try: | 304 | try: |
| 290 | store.attr.ir_attr.offset = "4" | 305 | store.attr.ir_attr.offset = "4" |
| 291 | except Exception as e: | 306 | except Exception as e: |
| 292 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 307 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 293 | store.attr.ir_attr.offset = offset_of_0 + 1 | 308 | store.attr.ir_attr.offset = offset_of_0 + 1 |
| 294 | assert store.attr.ir_attr.offset.expression == "1" | 309 | assert store.attr.ir_attr.offset.expression == "1" |
| 295 | store.x = abs_op | 310 | store.x = abs_op |
| @@ -322,9 +337,9 @@ class TestAutofuseLoadAbsStore(): | |||
| 322 | 337 | ||
| 323 | hint_graph = self.construct_graph() | 338 | hint_graph = self.construct_graph() |
| 324 | schedule_results = fuser.schedule(hint_graph) | 339 | schedule_results = fuser.schedule(hint_graph) |
| 325 | - graph_name = schedule_results.get_name() | 340 | + schedule_results.get_name() |
| 326 | - input_num = schedule_results.get_input_num() | 341 | + schedule_results.get_input_num() |
| 327 | - output_num = schedule_results.get_output_num() | 342 | + schedule_results.get_output_num() |
| 328 | 343 | ||
| 329 | def test_codegen(self): | 344 | def test_codegen(self): |
| 330 | options = AutofuserOptions() | 345 | options = AutofuserOptions() |
| @@ -351,10 +366,12 @@ class TestAutofuseLoadAbsStore(): | |||
| 351 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" | 366 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" |
| 352 | 367 | ||
| 353 | # 验证字典中包含预期的键(可能是"ub"、"common"或"default") | 368 | # 验证字典中包含预期的键(可能是"ub"、"common"或"default") |
| 354 | - assert any(key in tiling_dict for key in ["ub", "common", "default"]), \ | 369 | + assert any(key in tiling_dict for key in ["ub", "common", "default"]), ( |
| 355 | "tiling_dict should contain at least one of the expected keys" | 370 | "tiling_dict should contain at least one of the expected keys" |
| 356 | - assert any(key in kernel_dict for key in ["ub", "common", "default"]), \ | 371 | + ) |
| 372 | + assert any(key in kernel_dict for key in ["ub", "common", "default"]), ( | ||
| 357 | "kernel_dict should contain at least one of the expected keys" | 373 | "kernel_dict should contain at least one of the expected keys" |
| 374 | + ) | ||
| 358 | 375 | ||
| 359 | def test_host_code_generator(self): | 376 | def test_host_code_generator(self): |
| 360 | # 测试host_code_generator方法 | 377 | # 测试host_code_generator方法 |
| @@ -381,9 +398,9 @@ class TestAutofuseLoadAbsStore(): | |||
| 381 | assert isinstance(infer_shape, str), "infer_shape should be a string" | 398 | assert isinstance(infer_shape, str), "infer_shape should be a string" |
| 382 | 399 | ||
| 383 | # 验证py_tilings中包含预期的键(可能是"ub"、"common"或"default") | 400 | # 验证py_tilings中包含预期的键(可能是"ub"、"common"或"default") |
| 384 | - assert any(key in py_tilings for key in ["ub", "common", "default"]), \ | 401 | + assert any(key in py_tilings for key in ["ub", "common", "default"]), ( |
| 385 | "py_tilings should contain at least one of the expected keys" | 402 | "py_tilings should contain at least one of the expected keys" |
| 386 | - | 403 | + ) |
| 387 | 404 | ||
| 388 | def test_autofuse_backend(self): | 405 | def test_autofuse_backend(self): |
| 389 | options = AutofuserOptions() | 406 | options = AutofuserOptions() |
| @@ -393,7 +410,7 @@ class TestAutofuseLoadAbsStore(): | |||
| 393 | tiling_def, host_tiling, op_kernel = fuser.autofuse_backend(hint_graph) | 410 | tiling_def, host_tiling, op_kernel = fuser.autofuse_backend(hint_graph) |
| 394 | 411 | ||
| 395 | 412 | ||
| 396 | -class TestAutofuseLoadMatMulStore(): | 413 | +class TestAutofuseLoadMatMulStore: |
| 397 | 414 | ||
| 398 | def construct_graph(): | 415 | def construct_graph(): |
| 399 | graph = ascir.HintGraph("LoadCubeStore") | 416 | graph = ascir.HintGraph("LoadCubeStore") |
| @@ -421,7 +438,7 @@ class TestAutofuseLoadMatMulStore(): | |||
| 421 | try: | 438 | try: |
| 422 | load.attr.ir_attr.offset = "3" | 439 | load.attr.ir_attr.offset = "3" |
| 423 | except Exception as e: | 440 | except Exception as e: |
| 424 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 441 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 425 | offset_of_0 = ascir.SizeExpr(0) | 442 | offset_of_0 = ascir.SizeExpr(0) |
| 426 | load.attr.ir_attr.offset = offset_of_0 | 443 | load.attr.ir_attr.offset = offset_of_0 |
| 427 | assert load.attr.ir_attr.offset.expression == "0" | 444 | assert load.attr.ir_attr.offset.expression == "0" |
| @@ -451,7 +468,7 @@ class TestAutofuseLoadMatMulStore(): | |||
| 451 | try: | 468 | try: |
| 452 | store.attr.ir_attr.offset = "4" | 469 | store.attr.ir_attr.offset = "4" |
| 453 | except Exception as e: | 470 | except Exception as e: |
| 454 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 471 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 455 | store.attr.ir_attr.offset = offset_of_0 + 1 | 472 | store.attr.ir_attr.offset = offset_of_0 + 1 |
| 456 | assert store.attr.ir_attr.offset.expression == "1" | 473 | assert store.attr.ir_attr.offset.expression == "1" |
| 457 | store.x = matmul_op | 474 | store.x = matmul_op |
| @@ -480,8 +497,8 @@ class TestAutofuseLoadMatMulStore(): | |||
| 480 | 497 | ||
| 481 | hint_graph = self.construct_graph() | 498 | hint_graph = self.construct_graph() |
| 482 | schedule_results = fuser.schedule(hint_graph) | 499 | schedule_results = fuser.schedule(hint_graph) |
| 483 | - attr = schedule_results.is_cube_type() | 500 | + schedule_results.is_cube_type() |
| 484 | - attr = schedule_results.get_cube_attributes() | 501 | + schedule_results.get_cube_attributes() |
| 485 | 502 | ||
| 486 | def test_device_code_generator(self): | 503 | def test_device_code_generator(self): |
| 487 | # 测试device_code_generator方法 | 504 | # 测试device_code_generator方法 |
| @@ -500,10 +517,12 @@ class TestAutofuseLoadMatMulStore(): | |||
| 500 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" | 517 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" |
| 501 | 518 | ||
| 502 | # 验证字典中包含预期的键(可能是"ub"、"common"或"default") | 519 | # 验证字典中包含预期的键(可能是"ub"、"common"或"default") |
| 503 | - assert any(key in tiling_dict for key in ["ub", "common", "default"]), \ | 520 | + assert any(key in tiling_dict for key in ["ub", "common", "default"]), ( |
| 504 | "tiling_dict should contain at least one of the expected keys" | 521 | "tiling_dict should contain at least one of the expected keys" |
| 505 | - assert any(key in kernel_dict for key in ["ub", "common", "default"]), \ | 522 | + ) |
| 523 | + assert any(key in kernel_dict for key in ["ub", "common", "default"]), ( | ||
| 506 | "kernel_dict should contain at least one of the expected keys" | 524 | "kernel_dict should contain at least one of the expected keys" |
| 525 | + ) | ||
| 507 | 526 | ||
| 508 | def test_host_code_generator(self): | 527 | def test_host_code_generator(self): |
| 509 | # 测试host_code_generator方法 | 528 | # 测试host_code_generator方法 |
| @@ -530,15 +549,18 @@ class TestAutofuseLoadMatMulStore(): | |||
| 530 | assert isinstance(infer_shape, str), "infer_shape should be a string" | 549 | assert isinstance(infer_shape, str), "infer_shape should be a string" |
| 531 | 550 | ||
| 532 | # 验证py_tilings中包含预期的键(可能是"ub"、"common"或"default") | 551 | # 验证py_tilings中包含预期的键(可能是"ub"、"common"或"default") |
| 533 | - assert any(key in py_tilings for key in ["ub", "common", "default"]), \ | 552 | + assert any(key in py_tilings for key in ["ub", "common", "default"]), ( |
| 534 | "py_tilings should contain at least one of the expected keys" | 553 | "py_tilings should contain at least one of the expected keys" |
| 554 | + ) | ||
| 535 | 555 | ||
| 536 | # 验证每个值也是字典 | 556 | # 验证每个值也是字典 |
| 537 | for key, value in py_tilings.items(): | 557 | for key, value in py_tilings.items(): |
| 538 | - assert isinstance(value, dict), f"Value for key {key} should be a dictionary" | 558 | + assert isinstance(value, dict), ( |
| 559 | + f"Value for key {key} should be a dictionary" | ||
| 560 | + ) | ||
| 539 | 561 | ||
| 540 | 562 | ||
| 541 | -class TestAutofuseLoadBatchMatmulStore(): | 563 | +class TestAutofuseLoadBatchMatmulStore: |
| 542 | 564 | ||
| 543 | def construct_graph(): | 565 | def construct_graph(): |
| 544 | graph = ascir.HintGraph("LoadBatchMatMulStore") | 566 | graph = ascir.HintGraph("LoadBatchMatMulStore") |
| @@ -566,7 +588,7 @@ class TestAutofuseLoadBatchMatmulStore(): | |||
| 566 | try: | 588 | try: |
| 567 | load.attr.ir_attr.offset = "3" | 589 | load.attr.ir_attr.offset = "3" |
| 568 | except Exception as e: | 590 | except Exception as e: |
| 569 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 591 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 570 | offset_of_0 = ascir.SizeExpr(0) | 592 | offset_of_0 = ascir.SizeExpr(0) |
| 571 | load.attr.ir_attr.offset = offset_of_0 | 593 | load.attr.ir_attr.offset = offset_of_0 |
| 572 | assert load.attr.ir_attr.offset.expression == "0" | 594 | assert load.attr.ir_attr.offset.expression == "0" |
| @@ -596,7 +618,7 @@ class TestAutofuseLoadBatchMatmulStore(): | |||
| 596 | try: | 618 | try: |
| 597 | store.attr.ir_attr.offset = "4" | 619 | store.attr.ir_attr.offset = "4" |
| 598 | except Exception as e: | 620 | except Exception as e: |
| 599 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 621 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 600 | store.attr.ir_attr.offset = offset_of_0 + 1 | 622 | store.attr.ir_attr.offset = offset_of_0 + 1 |
| 601 | assert store.attr.ir_attr.offset.expression == "1" | 623 | assert store.attr.ir_attr.offset.expression == "1" |
| 602 | store.x = matmul_op | 624 | store.x = matmul_op |
| @@ -625,11 +647,11 @@ class TestAutofuseLoadBatchMatmulStore(): | |||
| 625 | 647 | ||
| 626 | hint_graph = self.construct_graph() | 648 | hint_graph = self.construct_graph() |
| 627 | schedule_results = fuser.schedule(hint_graph) | 649 | schedule_results = fuser.schedule(hint_graph) |
| 628 | - attr = schedule_results.is_cube_type() | 650 | + schedule_results.is_cube_type() |
| 629 | - attr = schedule_results.get_cube_attributes() | 651 | + schedule_results.get_cube_attributes() |
| 630 | 652 | ||
| 631 | 653 | ||
| 632 | -class TestAutofuseLoadMatMulStoreNew(): | 654 | +class TestAutofuseLoadMatMulStoreNew: |
| 633 | 655 | ||
| 634 | def construct_graph(): | 656 | def construct_graph(): |
| 635 | graph = ascir.HintGraph("LoadCubeStoreNew") | 657 | graph = ascir.HintGraph("LoadCubeStoreNew") |
| @@ -695,8 +717,8 @@ class TestAutofuseLoadMatMulStoreNew(): | |||
| 695 | matmul_op.attr.ir_attr.enable_hf32 = 1 | 717 | matmul_op.attr.ir_attr.enable_hf32 = 1 |
| 696 | matmul_op.attr.ir_attr.transpose_x1 = 0 # X1不转置 | 718 | matmul_op.attr.ir_attr.transpose_x1 = 0 # X1不转置 |
| 697 | matmul_op.attr.ir_attr.transpose_x2 = 0 # X2不转置 | 719 | matmul_op.attr.ir_attr.transpose_x2 = 0 # X2不转置 |
| 698 | - matmul_op.attr.ir_attr.has_relu = 0 # 不使用ReLU | 720 | + matmul_op.attr.ir_attr.has_relu = 0 # 不使用ReLU |
| 699 | - matmul_op.attr.ir_attr.offset_x = 0 # 偏移量为0 | 721 | + matmul_op.attr.ir_attr.offset_x = 0 # 偏移量为0 |
| 700 | matmul_op.y.dtype = ascir.dtypes.float16 | 722 | matmul_op.y.dtype = ascir.dtypes.float16 |
| 701 | matmul_op.y.axis = [m, n] | 723 | matmul_op.y.axis = [m, n] |
| 702 | matmul_op.y.size = [s0, s2] | 724 | matmul_op.y.size = [s0, s2] |
| @@ -743,8 +765,8 @@ class TestAutofuseLoadMatMulStoreNew(): | |||
| 743 | 765 | ||
| 744 | hint_graph = self.construct_graph() | 766 | hint_graph = self.construct_graph() |
| 745 | schedule_results = fuser.schedule(hint_graph) | 767 | schedule_results = fuser.schedule(hint_graph) |
| 746 | - attr = schedule_results.is_cube_type() | 768 | + schedule_results.is_cube_type() |
| 747 | - attr = schedule_results.get_cube_attributes() | 769 | + schedule_results.get_cube_attributes() |
| 748 | 770 | ||
| 749 | def test_device_code_generator(self): | 771 | def test_device_code_generator(self): |
| 750 | # 测试device_code_generator方法 | 772 | # 测试device_code_generator方法 |
| @@ -763,15 +785,19 @@ class TestAutofuseLoadMatMulStoreNew(): | |||
| 763 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" | 785 | assert isinstance(kernel_dict, dict), "kernel_dict should be a dictionary" |
| 764 | 786 | ||
| 765 | # 验证字典中只包含"ub"或"common"键 | 787 | # 验证字典中只包含"ub"或"common"键 |
| 766 | - assert any(key in tiling_dict for key in ["ub", "common", "default"]), \ | 788 | + assert any(key in tiling_dict for key in ["ub", "common", "default"]), ( |
| 767 | "tiling_dict should contain either 'ub', 'common' or 'default' key" | 789 | "tiling_dict should contain either 'ub', 'common' or 'default' key" |
| 768 | - assert all(key in ["ub", "common", "default"] for key in tiling_dict.keys()), \ | 790 | + ) |
| 791 | + assert all(key in ["ub", "common", "default"] for key in tiling_dict.keys()), ( | ||
| 769 | "tiling_dict should only contain 'ub', 'common' or 'default' keys" | 792 | "tiling_dict should only contain 'ub', 'common' or 'default' keys" |
| 793 | + ) | ||
| 770 | 794 | ||
| 771 | - assert any(key in kernel_dict for key in ["ub", "common", "default"]), \ | 795 | + assert any(key in kernel_dict for key in ["ub", "common", "default"]), ( |
| 772 | "kernel_dict should contain either 'ub', 'common' or 'default' key" | 796 | "kernel_dict should contain either 'ub', 'common' or 'default' key" |
| 773 | - assert all(key in ["ub", "common", "default"] for key in kernel_dict.keys()), \ | 797 | + ) |
| 798 | + assert all(key in ["ub", "common", "default"] for key in kernel_dict.keys()), ( | ||
| 774 | "kernel_dict should only contain 'ub', 'common' or 'default' keys" | 799 | "kernel_dict should only contain 'ub', 'common' or 'default' keys" |
| 800 | + ) | ||
| 775 | 801 | ||
| 776 | def test_host_code_generator(self): | 802 | def test_host_code_generator(self): |
| 777 | # 测试host_code_generator方法 | 803 | # 测试host_code_generator方法 |
| @@ -798,14 +824,18 @@ class TestAutofuseLoadMatMulStoreNew(): | |||
| 798 | assert isinstance(infer_shape, str), "infer_shape should be a string" | 824 | assert isinstance(infer_shape, str), "infer_shape should be a string" |
| 799 | 825 | ||
| 800 | # 验证py_tilings中只包含"ub"或"common"键 | 826 | # 验证py_tilings中只包含"ub"或"common"键 |
| 801 | - assert any(key in py_tilings for key in ["ub", "common", "default"]), \ | 827 | + assert any(key in py_tilings for key in ["ub", "common", "default"]), ( |
| 802 | "py_tilings should contain either 'ub', 'common' or 'default' key" | 828 | "py_tilings should contain either 'ub', 'common' or 'default' key" |
| 803 | - assert all(key in ["ub", "common", "default"] for key in py_tilings.keys()), \ | 829 | + ) |
| 830 | + assert all(key in ["ub", "common", "default"] for key in py_tilings.keys()), ( | ||
| 804 | "py_tilings should only contain 'ub', 'common' or 'default' keys" | 831 | "py_tilings should only contain 'ub', 'common' or 'default' keys" |
| 832 | + ) | ||
| 805 | 833 | ||
| 806 | # 验证每个值也是字典 | 834 | # 验证每个值也是字典 |
| 807 | for key, value in py_tilings.items(): | 835 | for key, value in py_tilings.items(): |
| 808 | - assert isinstance(value, dict), f"Value for key {key} should be a dictionary" | 836 | + assert isinstance(value, dict), ( |
| 837 | + f"Value for key {key} should be a dictionary" | ||
| 838 | + ) | ||
| 809 | 839 | ||
| 810 | 840 | ||
| 811 | class TestCubeAttributes: | 841 | class TestCubeAttributes: |
| @@ -931,7 +961,7 @@ class TestCubeAttributes: | |||
| 931 | # assert attr_dict["input_num"] == 2, "input_num should be 2" | 961 | # assert attr_dict["input_num"] == 2, "input_num should be 2" |
| 932 | 962 | ||
| 933 | 963 | ||
| 934 | -class TestAutofuseGatherAbsStore(): | 964 | +class TestAutofuseGatherAbsStore: |
| 935 | 965 | ||
| 936 | def construct_graph(): | 966 | def construct_graph(): |
| 937 | graph = ascir.HintGraph("GatherAbsStore") | 967 | graph = ascir.HintGraph("GatherAbsStore") |
| @@ -1004,7 +1034,7 @@ class TestAutofuseGatherAbsStore(): | |||
| 1004 | options = AutofuserOptions() | 1034 | options = AutofuserOptions() |
| 1005 | fuser = Autofuser(options) | 1035 | fuser = Autofuser(options) |
| 1006 | hint_graph = self.construct_graph() | 1036 | hint_graph = self.construct_graph() |
| 1007 | - schedule_results = fuser.autofuse(hint_graph) | 1037 | + fuser.autofuse(hint_graph) |
| 1008 | 1038 | ||
| 1009 | 1039 | ||
| 1010 | def test_codegen(self): | 1040 | def test_codegen(self): |
| @@ -1016,25 +1046,25 @@ class TestAutofuseGatherAbsStore(): | |||
| 1016 | tiling_def, host_tiling, op_kernel = fuser.codegen(impl_graphs) | 1046 | tiling_def, host_tiling, op_kernel = fuser.codegen(impl_graphs) |
| 1017 | 1047 | ||
| 1018 | 1048 | ||
| 1019 | -class TestAutofuseLoadConcatStore(): | 1049 | +class TestAutofuseLoadConcatStore: |
| 1020 | 1050 | ||
| 1021 | def construct_graph(): | 1051 | def construct_graph(): |
| 1022 | try: | 1052 | try: |
| 1023 | - NpuKernel0Graph = ascir.HintGraph(100) | 1053 | + npu_kernel0_graph = ascir.HintGraph(100) |
| 1024 | except Exception as e: | 1054 | except Exception as e: |
| 1025 | - assert e.args[0] == 'argument 1 must be str, not int' | 1055 | + assert e.args[0] == "argument 1 must be str, not int" |
| 1026 | - NpuKernel0Graph = ascir.HintGraph('LoadConcatStore') | 1056 | + npu_kernel0_graph = ascir.HintGraph("LoadConcatStore") |
| 1027 | - s0 = NpuKernel0Graph.create_size("s0") | 1057 | + s0 = npu_kernel0_graph.create_size("s0") |
| 1028 | - s1 = NpuKernel0Graph.create_size("s1") | 1058 | + s1 = npu_kernel0_graph.create_size("s1") |
| 1029 | - z0 = NpuKernel0Graph.create_axis("z0", s0) | 1059 | + z0 = npu_kernel0_graph.create_axis("z0", s0) |
| 1030 | - z1 = NpuKernel0Graph.create_axis("z1", s1 * 2) | 1060 | + z1 = npu_kernel0_graph.create_axis("z1", s1 * 2) |
| 1031 | - arg2_1 = ascir.ops.Data('arg2_1', NpuKernel0Graph) | 1061 | + arg2_1 = ascir.ops.Data("arg2_1", npu_kernel0_graph) |
| 1032 | arg2_1.y.dtype = ascir.dtypes.float16 | 1062 | arg2_1.y.dtype = ascir.dtypes.float16 |
| 1033 | - load = ascir.ops.Load('load') | 1063 | + load = ascir.ops.Load("load") |
| 1034 | try: | 1064 | try: |
| 1035 | load.infer_dtype() | 1065 | load.infer_dtype() |
| 1036 | except Exception as e: | 1066 | except Exception as e: |
| 1037 | - assert e.args[0] == 'node load Load need set input before call infer dype' | 1067 | + assert e.args[0] == "node load Load need set input before call infer dype" |
| 1038 | load.attr.sched.axis = [z0, z1] | 1068 | load.attr.sched.axis = [z0, z1] |
| 1039 | load.x = arg2_1.y | 1069 | load.x = arg2_1.y |
| 1040 | load.y.axis = [z0, z1] | 1070 | load.y.axis = [z0, z1] |
| @@ -1042,32 +1072,32 @@ class TestAutofuseLoadConcatStore(): | |||
| 1042 | load.y.size = [s0, s1] | 1072 | load.y.size = [s0, s1] |
| 1043 | load.infer_dtype() | 1073 | load.infer_dtype() |
| 1044 | assert load.y.dtype == ascir.dtypes.float16 | 1074 | assert load.y.dtype == ascir.dtypes.float16 |
| 1045 | - arg3_1 = ascir.ops.Data('arg3_1', NpuKernel0Graph) | 1075 | + arg3_1 = ascir.ops.Data("arg3_1", npu_kernel0_graph) |
| 1046 | arg3_1.y.dtype = ascir.dtypes.float16 | 1076 | arg3_1.y.dtype = ascir.dtypes.float16 |
| 1047 | - load1 = ascir.ops.Load('load1') | 1077 | + load1 = ascir.ops.Load("load1") |
| 1048 | load1.attr.sched.axis = [z0, z1] | 1078 | load1.attr.sched.axis = [z0, z1] |
| 1049 | assert load1.attr.sched.axis == [z0.id, z1.id] | 1079 | assert load1.attr.sched.axis == [z0.id, z1.id] |
| 1050 | load1.x = arg3_1.y | 1080 | load1.x = arg3_1.y |
| 1051 | load1.y.axis = [z0, z1] | 1081 | load1.y.axis = [z0, z1] |
| 1052 | load1.y.strides = [s1, ascir.SizeExpr(1)] | 1082 | load1.y.strides = [s1, ascir.SizeExpr(1)] |
| 1053 | load1.y.size = [s0, s1] | 1083 | load1.y.size = [s0, s1] |
| 1054 | - concat = ascir.ops.Concat('concat') | 1084 | + concat = ascir.ops.Concat("concat") |
| 1055 | concat.attr.sched.axis = [z0, z1] | 1085 | concat.attr.sched.axis = [z0, z1] |
| 1056 | concat.x = [load, load1.y] | 1086 | concat.x = [load, load1.y] |
| 1057 | concat.y.axis = [z0, z1] | 1087 | concat.y.axis = [z0, z1] |
| 1058 | concat.y.strides = [s1 + s1, ascir.SizeExpr(1)] | 1088 | concat.y.strides = [s1 + s1, ascir.SizeExpr(1)] |
| 1059 | concat.y.size = [s0, s1 * 2] | 1089 | concat.y.size = [s0, s1 * 2] |
| 1060 | - store = ascir.ops.Store('store') | 1090 | + store = ascir.ops.Store("store") |
| 1061 | store.attr.sched.axis = [z0, z1] | 1091 | store.attr.sched.axis = [z0, z1] |
| 1062 | store.x = concat.y | 1092 | store.x = concat.y |
| 1063 | store.y.axis = [z0, z1] | 1093 | store.y.axis = [z0, z1] |
| 1064 | store.y.strides = [s1 * 2, ascir.SizeExpr(1)] | 1094 | store.y.strides = [s1 * 2, ascir.SizeExpr(1)] |
| 1065 | store.y.size = [s0, s1 * 2] | 1095 | store.y.size = [s0, s1 * 2] |
| 1066 | - buf0 = ascir.ops.Output('buf0') | 1096 | + buf0 = ascir.ops.Output("buf0") |
| 1067 | buf0.x = store.y | 1097 | buf0.x = store.y |
| 1068 | buf0.y.dtype = ascir.dtypes.float16 | 1098 | buf0.y.dtype = ascir.dtypes.float16 |
| 1069 | - NpuKernel0Graph.infer_dtypes() | 1099 | + npu_kernel0_graph.infer_dtypes() |
| 1070 | - return NpuKernel0Graph | 1100 | + return npu_kernel0_graph |
| 1071 | 1101 | ||
| 1072 | def test_construct_graph(self): | 1102 | def test_construct_graph(self): |
| 1073 | graph = self.construct_graph() | 1103 | graph = self.construct_graph() |
| @@ -1079,10 +1109,10 @@ class TestAutofuseLoadConcatStore(): | |||
| 1079 | fuser = Autofuser(options) | 1109 | fuser = Autofuser(options) |
| 1080 | 1110 | ||
| 1081 | hint_graph = self.construct_graph() | 1111 | hint_graph = self.construct_graph() |
| 1082 | - schedule_results = fuser.schedule(hint_graph) | 1112 | + fuser.schedule(hint_graph) |
| 1083 | 1113 | ||
| 1084 | 1114 | ||
| 1085 | -class TestAutofuseLoadSplitStore(): | 1115 | +class TestAutofuseLoadSplitStore: |
| 1086 | 1116 | ||
| 1087 | def construct_graph(): | 1117 | def construct_graph(): |
| 1088 | graph = ascir.HintGraph("LoadSplitStore") | 1118 | graph = ascir.HintGraph("LoadSplitStore") |
| @@ -1148,51 +1178,51 @@ class TestAutofuseLoadSplitStore(): | |||
| 1148 | debug_graph = ascir.utils.debug_str(graph) | 1178 | debug_graph = ascir.utils.debug_str(graph) |
| 1149 | assert debug_graph != "" | 1179 | assert debug_graph != "" |
| 1150 | finally: | 1180 | finally: |
| 1151 | - ascir.utils.set_platform("2201", 1, 1024) | 1181 | + ascir.utils.set_platform("2201", 1, 245760) |
| 1152 | 1182 | ||
| 1153 | 1183 | ||
| 1154 | -class TestWorkspaceOptimize(): | 1184 | +class TestWorkspaceOptimize: |
| 1155 | 1185 | ||
| 1156 | def construct_graph(): | 1186 | def construct_graph(): |
| 1157 | - NpuKernel0Graph = ascir.HintGraph('workspace') | 1187 | + npu_kernel0_graph = ascir.HintGraph("workspace") |
| 1158 | - s0 = NpuKernel0Graph.create_size("s0") | 1188 | + s0 = npu_kernel0_graph.create_size("s0") |
| 1159 | - z0 = NpuKernel0Graph.create_axis("z0", s0) | 1189 | + z0 = npu_kernel0_graph.create_axis("z0", s0) |
| 1160 | - arg2_1 = ascir.ops.Data('arg2_1', NpuKernel0Graph) | 1190 | + arg2_1 = ascir.ops.Data("arg2_1", npu_kernel0_graph) |
| 1161 | arg2_1.y.dtype = ascir.dtypes.float16 | 1191 | arg2_1.y.dtype = ascir.dtypes.float16 |
| 1162 | - load = ascir.ops.Load('load') | 1192 | + load = ascir.ops.Load("load") |
| 1163 | load.attr.sched.axis = [z0] | 1193 | load.attr.sched.axis = [z0] |
| 1164 | load.x = arg2_1.y | 1194 | load.x = arg2_1.y |
| 1165 | load.y.axis = [z0] | 1195 | load.y.axis = [z0] |
| 1166 | load.y.strides = [ascir.SizeExpr(1)] | 1196 | load.y.strides = [ascir.SizeExpr(1)] |
| 1167 | load.y.size = [s0] | 1197 | load.y.size = [s0] |
| 1168 | - store = ascir.ops.Store('store') | 1198 | + store = ascir.ops.Store("store") |
| 1169 | store.attr.sched.axis = [z0] | 1199 | store.attr.sched.axis = [z0] |
| 1170 | store.x = load.y | 1200 | store.x = load.y |
| 1171 | store.y.axis = [z0] | 1201 | store.y.axis = [z0] |
| 1172 | store.y.strides = [ascir.SizeExpr(1)] | 1202 | store.y.strides = [ascir.SizeExpr(1)] |
| 1173 | store.y.size = [s0] | 1203 | store.y.size = [s0] |
| 1174 | - ws = ascir.ops.Workspace('buf8') | 1204 | + ws = ascir.ops.Workspace("buf8") |
| 1175 | ws.attr.sched.axis = [z0] | 1205 | ws.attr.sched.axis = [z0] |
| 1176 | ws.x = store.y | 1206 | ws.x = store.y |
| 1177 | ws.y.size = [s0] | 1207 | ws.y.size = [s0] |
| 1178 | ws.y.dtype = ascir.dtypes.float16 | 1208 | ws.y.dtype = ascir.dtypes.float16 |
| 1179 | ws.y.axis = [z0] | 1209 | ws.y.axis = [z0] |
| 1180 | ws.y.strides = [ascir.SizeExpr(1)] | 1210 | ws.y.strides = [ascir.SizeExpr(1)] |
| 1181 | - load1 = ascir.ops.Load('load1') | 1211 | + load1 = ascir.ops.Load("load1") |
| 1182 | load1.attr.sched.axis = [z0] | 1212 | load1.attr.sched.axis = [z0] |
| 1183 | load1.x = ws.y | 1213 | load1.x = ws.y |
| 1184 | load1.y.axis = [z0] | 1214 | load1.y.axis = [z0] |
| 1185 | load1.y.strides = [ascir.SizeExpr(1)] | 1215 | load1.y.strides = [ascir.SizeExpr(1)] |
| 1186 | load1.y.size = [s0] | 1216 | load1.y.size = [s0] |
| 1187 | 1217 | ||
| 1188 | - store1 = ascir.ops.Store('store1') | 1218 | + store1 = ascir.ops.Store("store1") |
| 1189 | store1.attr.sched.axis = [z0] | 1219 | store1.attr.sched.axis = [z0] |
| 1190 | store1.x = load1.y | 1220 | store1.x = load1.y |
| 1191 | store1.y.axis = [z0] | 1221 | store1.y.axis = [z0] |
| 1192 | store1.y.strides = [ascir.SizeExpr(1)] | 1222 | store1.y.strides = [ascir.SizeExpr(1)] |
| 1193 | store1.y.size = [s0] | 1223 | store1.y.size = [s0] |
| 1194 | 1224 | ||
| 1195 | - ws1 = ascir.ops.Workspace('buf2') | 1225 | + ws1 = ascir.ops.Workspace("buf2") |
| 1196 | ws1.attr.sched.axis = [z0] | 1226 | ws1.attr.sched.axis = [z0] |
| 1197 | ws1.x = store1.y | 1227 | ws1.x = store1.y |
| 1198 | ws1.y.size = [s0] | 1228 | ws1.y.size = [s0] |
| @@ -1200,21 +1230,21 @@ class TestWorkspaceOptimize(): | |||
| 1200 | ws1.y.axis = [z0] | 1230 | ws1.y.axis = [z0] |
| 1201 | ws1.y.strides = [ascir.SizeExpr(1)] | 1231 | ws1.y.strides = [ascir.SizeExpr(1)] |
| 1202 | 1232 | ||
| 1203 | - load2 = ascir.ops.Load('load2') | 1233 | + load2 = ascir.ops.Load("load2") |
| 1204 | load2.attr.sched.axis = [z0] | 1234 | load2.attr.sched.axis = [z0] |
| 1205 | load2.x = ws1.y | 1235 | load2.x = ws1.y |
| 1206 | load2.y.axis = [z0] | 1236 | load2.y.axis = [z0] |
| 1207 | load2.y.strides = [ascir.SizeExpr(1)] | 1237 | load2.y.strides = [ascir.SizeExpr(1)] |
| 1208 | load2.y.size = [s0] | 1238 | load2.y.size = [s0] |
| 1209 | 1239 | ||
| 1210 | - load3 = ascir.ops.Load('load3') | 1240 | + load3 = ascir.ops.Load("load3") |
| 1211 | load3.attr.sched.axis = [z0] | 1241 | load3.attr.sched.axis = [z0] |
| 1212 | load3.x = ws1.y | 1242 | load3.x = ws1.y |
| 1213 | load3.y.axis = [z0] | 1243 | load3.y.axis = [z0] |
| 1214 | load3.y.strides = [ascir.SizeExpr(1)] | 1244 | load3.y.strides = [ascir.SizeExpr(1)] |
| 1215 | load3.y.size = [s0] | 1245 | load3.y.size = [s0] |
| 1216 | - NpuKernel0Graph.infer_dtypes() | 1246 | + npu_kernel0_graph.infer_dtypes() |
| 1217 | - return NpuKernel0Graph | 1247 | + return npu_kernel0_graph |
| 1218 | 1248 | ||
| 1219 | def test_construct_graph(self): | 1249 | def test_construct_graph(self): |
| 1220 | graph = self.construct_graph() | 1250 | graph = self.construct_graph() |
| @@ -1226,9 +1256,10 @@ class TestWorkspaceOptimize(): | |||
| 1226 | fuser = Autofuser(options) | 1256 | fuser = Autofuser(options) |
| 1227 | 1257 | ||
| 1228 | hint_graph = self.construct_graph() | 1258 | hint_graph = self.construct_graph() |
| 1229 | - schedule_results = fuser.schedule(hint_graph) | 1259 | + fuser.schedule(hint_graph) |
| 1230 | 1260 | ||
| 1231 | -class TestCodeGenLoadAbsStore(): | 1261 | + |
| 1262 | +class TestCodeGenLoadAbsStore: | ||
| 1232 | 1263 | ||
| 1233 | def construct_graph(): | 1264 | def construct_graph(): |
| 1234 | graph = ascir.HintGraph("LoadAbsStore") | 1265 | graph = ascir.HintGraph("LoadAbsStore") |
| @@ -1298,7 +1329,7 @@ class TestCodeGenLoadAbsStore(): | |||
| 1298 | scheduler = Schedule(options) | 1329 | scheduler = Schedule(options) |
| 1299 | 1330 | ||
| 1300 | hint_graph = self.construct_graph() | 1331 | hint_graph = self.construct_graph() |
| 1301 | - impl_graphs = scheduler.schedule(hint_graph) | 1332 | + scheduler.schedule(hint_graph) |
| 1302 | 1333 | ||
| 1303 | 1334 | ||
| 1304 | def test_codegen(self): | 1335 | def test_codegen(self): |
| @@ -1307,9 +1338,13 @@ class TestCodeGenLoadAbsStore(): | |||
| 1307 | 1338 | ||
| 1308 | hint_graph = self.construct_graph() | 1339 | hint_graph = self.construct_graph() |
| 1309 | impl_graphs = scheduler.schedule(hint_graph) | 1340 | impl_graphs = scheduler.schedule(hint_graph) |
| 1310 | - shape_info = ascir.ShapeInfo({"s0": "GetDimValueFromGraphInputData(0, 0);", | 1341 | + shape_info = ascir.ShapeInfo( |
| 1311 | - "s1": "GetDimValueFromGraphInputData(0, 1);", | 1342 | + { |
| 1312 | - "s2": "GetDimValueFromGraphInputData(1, 0);"}) | 1343 | + "s0": "GetDimValueFromGraphInputData(0, 0);", |
| 1344 | + "s1": "GetDimValueFromGraphInputData(0, 1);", | ||
| 1345 | + "s2": "GetDimValueFromGraphInputData(1, 0);", | ||
| 1346 | + } | ||
| 1347 | + ) | ||
| 1313 | 1348 | ||
| 1314 | kernel_path = "./fused_graph_kernel.o" | 1349 | kernel_path = "./fused_graph_kernel.o" |
| 1315 | with open(kernel_path, "wb") as o_file: | 1350 | with open(kernel_path, "wb") as o_file: |
| @@ -1319,73 +1354,79 @@ class TestCodeGenLoadAbsStore(): | |||
| 1319 | "name": "Alice", | 1354 | "name": "Alice", |
| 1320 | "age": 30, | 1355 | "age": 30, |
| 1321 | "is_student": False, | 1356 | "is_student": False, |
| 1322 | - "courses": ["Math", "Science", "History"] | 1357 | + "courses": ["Math", "Science", "History"], |
| 1323 | } | 1358 | } |
| 1324 | json_path = "./fused_graph_kernel.json" | 1359 | json_path = "./fused_graph_kernel.json" |
| 1325 | with open(json_path, "w") as json_file: | 1360 | with open(json_path, "w") as json_file: |
| 1326 | json.dump(data, json_file, indent=4) | 1361 | json.dump(data, json_file, indent=4) |
| 1327 | 1362 | ||
| 1328 | tiling_data, op_kernel = codegen.device_code_generator(hint_graph, impl_graphs) | 1363 | tiling_data, op_kernel = codegen.device_code_generator(hint_graph, impl_graphs) |
| 1329 | - tiling, infer_shape = codegen.host_code_generator(hint_graph, impl_graphs, shape_info, "", ["", ""]) | 1364 | + tiling, infer_shape = codegen.host_code_generator( |
| 1365 | + hint_graph, impl_graphs, shape_info, "", ["", ""] | ||
| 1366 | + ) | ||
| 1330 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) | 1367 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) |
| 1331 | os.remove(kernel_path) | 1368 | os.remove(kernel_path) |
| 1332 | os.remove(json_path) | 1369 | os.remove(json_path) |
| 1333 | - assert tiling_data == "".join([ | 1370 | + assert tiling_data == "".join( |
| 1334 | - "#ifndef __Autofuse_Tiling_Data_H__\n" | 1371 | + [ |
| 1335 | - "#define __Autofuse_Tiling_Data_H__\n" | 1372 | + "#ifndef __Autofuse_Tiling_Data_H__\n" |
| 1336 | - "#include <stdint.h>\n" | 1373 | + "#define __Autofuse_Tiling_Data_H__\n" |
| 1337 | - "#include \"kernel_tiling/kernel_tiling.h\"\n" | 1374 | + "#include <stdint.h>\n" |
| 1338 | - "#define BEGIN_TILING_DATA_DEF_T(name) struct name {\n" | 1375 | + '#include "kernel_tiling/kernel_tiling.h"\n' |
| 1339 | - "#define TILING_DATA_FIELD_DEF_T(type, name) \\\n" | 1376 | + "#define BEGIN_TILING_DATA_DEF_T(name) struct name {\n" |
| 1340 | - " type name; \\\n" | 1377 | + "#define TILING_DATA_FIELD_DEF_T(type, name) \\\n" |
| 1341 | - " inline void set_##name(type value) { name = value; } \\\n", | 1378 | + " type name; \\\n" |
| 1342 | - " inline type get_##name() { return name; } \\\n" | 1379 | + " inline void set_##name(type value) { name = value; } \\\n", |
| 1343 | - " inline type* get_addr_##name() {return &name;}\n" | 1380 | + " inline type get_##name() { return name; } \\\n" |
| 1344 | - "#define END_TILING_DATA_DEF_T };\n" | 1381 | + " inline type* get_addr_##name() {return &name;}\n" |
| 1345 | - "#define TILING_DATA_FIELD_DEF_T_STRUCT(struct_type, filed_name) \\\n" | 1382 | + "#define END_TILING_DATA_DEF_T };\n" |
| 1346 | - " struct_type filed_name;\n\n" | 1383 | + "#define TILING_DATA_FIELD_DEF_T_STRUCT(struct_type, filed_name) \\\n" |
| 1347 | - "BEGIN_TILING_DATA_DEF_T(AutofuseTilingData)\n" | 1384 | + " struct_type filed_name;\n\n" |
| 1348 | - " TILING_DATA_FIELD_DEF_T(uint32_t, block_dim);\n" | 1385 | + "BEGIN_TILING_DATA_DEF_T(AutofuseTilingData)\n" |
| 1349 | - " TILING_DATA_FIELD_DEF_T(uint32_t, corenum);\n" | 1386 | + " TILING_DATA_FIELD_DEF_T(uint32_t, block_dim);\n" |
| 1350 | - " TILING_DATA_FIELD_DEF_T(uint32_t, ub_size);\n" | 1387 | + " TILING_DATA_FIELD_DEF_T(uint32_t, corenum);\n" |
| 1351 | - " TILING_DATA_FIELD_DEF_T(uint32_t, hbm_size);\n" | 1388 | + " TILING_DATA_FIELD_DEF_T(uint32_t, ub_size);\n" |
| 1352 | - " TILING_DATA_FIELD_DEF_T(uint32_t, tiling_key);\n" | 1389 | + " TILING_DATA_FIELD_DEF_T(uint32_t, hbm_size);\n" |
| 1353 | - " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2t_size);\n" | 1390 | + " TILING_DATA_FIELD_DEF_T(uint32_t, tiling_key);\n" |
| 1354 | - " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2Tb_size);\n" | 1391 | + " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2t_size);\n" |
| 1355 | - "END_TILING_DATA_DEF_T;\n\n" | 1392 | + " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2Tb_size);\n" |
| 1356 | - "struct AutofuseTilingDataPerf {\n" | 1393 | + "END_TILING_DATA_DEF_T;\n\n" |
| 1357 | - " AutofuseTilingData tiling_data;\n" | 1394 | + "struct AutofuseTilingDataPerf {\n" |
| 1358 | - " double best_perf;\n" | 1395 | + " AutofuseTilingData tiling_data;\n" |
| 1359 | - "};\n" | 1396 | + " double best_perf;\n" |
| 1360 | - "#endif\n" | 1397 | + "};\n" |
| 1361 | - ]) | 1398 | + "#endif\n", |
| 1399 | + ] | ||
| 1400 | + ) | ||
| 1362 | 1401 | ||
| 1363 | - assert infer_shape == "".join([ | 1402 | + assert infer_shape == "".join([""]) |
| 1364 | - ""]) | ||
| 1365 | 1403 | ||
| 1366 | - assert get_kernel == "".join([ | 1404 | + assert get_kernel == "".join( |
| 1367 | - "#include <cstdint>\n" | 1405 | + [ |
| 1368 | - "#include <cstring>\n" | 1406 | + "#include <cstdint>\n" |
| 1369 | - "#include <vector>\n" | 1407 | + "#include <cstring>\n" |
| 1370 | - "extern \"C\" void GetKernelBin(std::vector<char> &kernel_bin) {\n" | 1408 | + "#include <vector>\n" |
| 1371 | - " std::vector<uint8_t> temp_kernel = {\n" | 1409 | + 'extern "C" void GetKernelBin(std::vector<char> &kernel_bin) {\n' |
| 1372 | - " 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 46, 111, 32, 102, 105, 108, 101, 32, 99, 111, \n" | 1410 | + " std::vector<uint8_t> temp_kernel = {\n" |
| 1373 | - " 110, 116, 101, 110, 116, 46, };\n" | 1411 | + " 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 46, 111, 32, 102, 105, 108, 101, 32, 99, 111, \n" |
| 1374 | - " kernel_bin.resize(temp_kernel.size());\n" | 1412 | + " 110, 116, 101, 110, 116, 46, };\n" |
| 1375 | - " std::memcpy(kernel_bin.data(), temp_kernel.data(), temp_kernel.size() * sizeof(uint8_t));\n" | 1413 | + " kernel_bin.resize(temp_kernel.size());\n" |
| 1376 | - "}"]) | 1414 | + " std::memcpy(kernel_bin.data(), temp_kernel.data(), temp_kernel.size() * sizeof(uint8_t));\n" |
| 1415 | + "}" | ||
| 1416 | + ] | ||
| 1417 | + ) | ||
| 1377 | 1418 | ||
| 1378 | 1419 | ||
| 1379 | -class TestComputeGraphInput(): | 1420 | +class TestComputeGraphInput: |
| 1380 | 1421 | ||
| 1381 | def construct_compute_graph(): | 1422 | def construct_compute_graph(): |
| 1382 | test_graph = os.path.join(PYF_PATH, "test_graph.txt") | 1423 | test_graph = os.path.join(PYF_PATH, "test_graph.txt") |
| 1383 | - with open(test_graph, 'r', encoding='utf-8') as file: | 1424 | + with open(test_graph, "r", encoding="utf-8") as file: |
| 1384 | content = file.read() | 1425 | content = file.read() |
| 1385 | compute_graph = ascir.utils.deserialize("compute_graph", content) | 1426 | compute_graph = ascir.utils.deserialize("compute_graph", content) |
| 1386 | print(compute_graph.get_name(), flush=True) | 1427 | print(compute_graph.get_name(), flush=True) |
| 1387 | print(compute_graph.get_info(), flush=True) | 1428 | print(compute_graph.get_info(), flush=True) |
| 1388 | - assert compute_graph != None | 1429 | + assert compute_graph is not None |
| 1389 | return compute_graph | 1430 | return compute_graph |
| 1390 | 1431 | ||
| 1391 | 1432 | ||
| @@ -1394,7 +1435,7 @@ class TestComputeGraphInput(): | |||
| 1394 | scheduler = Schedule(options) | 1435 | scheduler = Schedule(options) |
| 1395 | 1436 | ||
| 1396 | compute_graph = self.construct_compute_graph() | 1437 | compute_graph = self.construct_compute_graph() |
| 1397 | - schedule_results = scheduler.scheduleV2(compute_graph) | 1438 | + scheduler.scheduleV2(compute_graph) |
| 1398 | 1439 | ||
| 1399 | def test_scheduleV2_fail(self): | 1440 | def test_scheduleV2_fail(self): |
| 1400 | options = AutofuserOptions() | 1441 | options = AutofuserOptions() |
| @@ -1403,8 +1444,9 @@ class TestComputeGraphInput(): | |||
| 1403 | compute_graph = ascir.HintComputeGraph("test") | 1444 | compute_graph = ascir.HintComputeGraph("test") |
| 1404 | try: | 1445 | try: |
| 1405 | scheduler.scheduleV2(compute_graph) | 1446 | scheduler.scheduleV2(compute_graph) |
| 1406 | - except RuntimeError as e: | 1447 | + except RuntimeError: |
| 1407 | pass | 1448 | pass |
| 1449 | + | ||
| 1408 | 1450 | ||
| 1409 | def test_computegraph_codegen(self): | 1451 | def test_computegraph_codegen(self): |
| 1410 | scheduler = Schedule() | 1452 | scheduler = Schedule() |
| @@ -1412,9 +1454,13 @@ class TestComputeGraphInput(): | |||
| 1412 | 1454 | ||
| 1413 | compute_graph = self.construct_compute_graph() | 1455 | compute_graph = self.construct_compute_graph() |
| 1414 | schedule_results = scheduler.scheduleV2(compute_graph) | 1456 | schedule_results = scheduler.scheduleV2(compute_graph) |
| 1415 | - shape_info = ascir.ShapeInfo({"s0": "GetDimValueFromGraphInputData(0, 0);", | 1457 | + shape_info = ascir.ShapeInfo( |
| 1416 | - "s1": "GetDimValueFromGraphInputData(0, 1);", | 1458 | + { |
| 1417 | - "s2": "GetDimValueFromGraphInputData(1, 0);"}) | 1459 | + "s0": "GetDimValueFromGraphInputData(0, 0);", |
| 1460 | + "s1": "GetDimValueFromGraphInputData(0, 1);", | ||
| 1461 | + "s2": "GetDimValueFromGraphInputData(1, 0);", | ||
| 1462 | + } | ||
| 1463 | + ) | ||
| 1418 | 1464 | ||
| 1419 | kernel_path = "./fused_graph_kernel.o" | 1465 | kernel_path = "./fused_graph_kernel.o" |
| 1420 | with open(kernel_path, "wb") as o_file: | 1466 | with open(kernel_path, "wb") as o_file: |
| @@ -1424,90 +1470,98 @@ class TestComputeGraphInput(): | |||
| 1424 | "name": "Alice", | 1470 | "name": "Alice", |
| 1425 | "age": 30, | 1471 | "age": 30, |
| 1426 | "is_student": False, | 1472 | "is_student": False, |
| 1427 | - "courses": ["Math", "Science", "History"] | 1473 | + "courses": ["Math", "Science", "History"], |
| 1428 | } | 1474 | } |
| 1429 | json_path = "./fused_graph_kernel.json" | 1475 | json_path = "./fused_graph_kernel.json" |
| 1430 | with open(json_path, "w") as json_file: | 1476 | with open(json_path, "w") as json_file: |
| 1431 | json.dump(data, json_file, indent=4) | 1477 | json.dump(data, json_file, indent=4) |
| 1432 | 1478 | ||
| 1433 | tiling_data, op_kernel = codegen.device_code_generator(schedule_results) | 1479 | tiling_data, op_kernel = codegen.device_code_generator(schedule_results) |
| 1434 | - assert tiling_data == "".join([ | 1480 | + assert tiling_data == "".join( |
| 1435 | - "#ifndef __Autofuse_Tiling_Data_H__\n" | 1481 | + [ |
| 1436 | - "#define __Autofuse_Tiling_Data_H__\n" | 1482 | + "#ifndef __Autofuse_Tiling_Data_H__\n" |
| 1437 | - "#include <stdint.h>\n" | 1483 | + "#define __Autofuse_Tiling_Data_H__\n" |
| 1438 | - "#include \"kernel_tiling/kernel_tiling.h\"\n" | 1484 | + "#include <stdint.h>\n" |
| 1439 | - "#define BEGIN_TILING_DATA_DEF_T(name) struct name {\n" | 1485 | + '#include "kernel_tiling/kernel_tiling.h"\n' |
| 1440 | - "#define TILING_DATA_FIELD_DEF_T(type, name) \\\n" | 1486 | + "#define BEGIN_TILING_DATA_DEF_T(name) struct name {\n" |
| 1441 | - " type name; \\\n" | 1487 | + "#define TILING_DATA_FIELD_DEF_T(type, name) \\\n" |
| 1442 | - " inline void set_##name(type value) { name = value; } \\\n", | 1488 | + " type name; \\\n" |
| 1443 | - " inline type get_##name() { return name; } \\\n" | 1489 | + " inline void set_##name(type value) { name = value; } \\\n", |
| 1444 | - " inline type* get_addr_##name() {return &name;}\n" | 1490 | + " inline type get_##name() { return name; } \\\n" |
| 1445 | - "#define END_TILING_DATA_DEF_T };\n" | 1491 | + " inline type* get_addr_##name() {return &name;}\n" |
| 1446 | - "#define TILING_DATA_FIELD_DEF_T_STRUCT(struct_type, filed_name) \\\n" | 1492 | + "#define END_TILING_DATA_DEF_T };\n" |
| 1447 | - " struct_type filed_name;\n\n" | 1493 | + "#define TILING_DATA_FIELD_DEF_T_STRUCT(struct_type, filed_name) \\\n" |
| 1448 | - "BEGIN_TILING_DATA_DEF_T(AutofuseTilingData)\n" | 1494 | + " struct_type filed_name;\n\n" |
| 1449 | - " TILING_DATA_FIELD_DEF_T(uint32_t, block_dim);\n" | 1495 | + "BEGIN_TILING_DATA_DEF_T(AutofuseTilingData)\n" |
| 1450 | - " TILING_DATA_FIELD_DEF_T(uint32_t, corenum);\n" | 1496 | + " TILING_DATA_FIELD_DEF_T(uint32_t, block_dim);\n" |
| 1451 | - " TILING_DATA_FIELD_DEF_T(uint32_t, ub_size);\n" | 1497 | + " TILING_DATA_FIELD_DEF_T(uint32_t, corenum);\n" |
| 1452 | - " TILING_DATA_FIELD_DEF_T(uint32_t, hbm_size);\n" | 1498 | + " TILING_DATA_FIELD_DEF_T(uint32_t, ub_size);\n" |
| 1453 | - " TILING_DATA_FIELD_DEF_T(uint32_t, tiling_key);\n" | 1499 | + " TILING_DATA_FIELD_DEF_T(uint32_t, hbm_size);\n" |
| 1454 | - " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2t_size);\n" | 1500 | + " TILING_DATA_FIELD_DEF_T(uint32_t, tiling_key);\n" |
| 1455 | - " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2Tb_size);\n" | 1501 | + " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2t_size);\n" |
| 1456 | - " TILING_DATA_FIELD_DEF_T(uint32_t, q0_size);\n" | 1502 | + " TILING_DATA_FIELD_DEF_T(uint32_t, z0z1z2Tb_size);\n" |
| 1457 | - " TILING_DATA_FIELD_DEF_T(uint32_t, q1_size);\n" | 1503 | + " TILING_DATA_FIELD_DEF_T(uint32_t, q0_size);\n" |
| 1458 | - " TILING_DATA_FIELD_DEF_T(uint32_t, b0_size);\n" | 1504 | + " TILING_DATA_FIELD_DEF_T(uint32_t, q1_size);\n" |
| 1459 | - "END_TILING_DATA_DEF_T;\n\n" | 1505 | + " TILING_DATA_FIELD_DEF_T(uint32_t, b0_size);\n" |
| 1460 | - "struct AutofuseTilingDataPerf {\n" | 1506 | + "END_TILING_DATA_DEF_T;\n\n" |
| 1461 | - " AutofuseTilingData tiling_data;\n" | 1507 | + "struct AutofuseTilingDataPerf {\n" |
| 1462 | - " double best_perf;\n" | 1508 | + " AutofuseTilingData tiling_data;\n" |
| 1463 | - "};\n" | 1509 | + " double best_perf;\n" |
| 1464 | - "#endif\n" | 1510 | + "};\n" |
| 1465 | - ]) | 1511 | + "#endif\n", |
| 1512 | + ] | ||
| 1513 | + ) | ||
| 1466 | 1514 | ||
| 1467 | output_shape = [["s0", "s1"]] | 1515 | output_shape = [["s0", "s1"]] |
| 1468 | vector_core_num = "0" | 1516 | vector_core_num = "0" |
| 1469 | - tiling, infer_shape = codegen.host_code_generator(schedule_results, shape_info, output_shape, "", vector_core_num) | 1517 | + tiling, infer_shape = codegen.host_code_generator( |
| 1470 | - pgo_src = codegen.pgo_code_generator(schedule_results, "") | 1518 | + schedule_results, shape_info, output_shape, "", vector_core_num |
| 1519 | + ) | ||
| 1520 | + codegen.pgo_code_generator(schedule_results, "") | ||
| 1471 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) | 1521 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) |
| 1472 | os.remove(kernel_path) | 1522 | os.remove(kernel_path) |
| 1473 | os.remove(json_path) | 1523 | os.remove(json_path) |
| 1474 | - assert get_kernel == "".join([ | 1524 | + assert get_kernel == "".join( |
| 1475 | - "#include <cstdint>\n" | 1525 | + [ |
| 1476 | - "#include <cstring>\n" | 1526 | + "#include <cstdint>\n" |
| 1477 | - "#include <vector>\n" | 1527 | + "#include <cstring>\n" |
| 1478 | - "extern \"C\" void GetKernelBin(std::vector<char> &kernel_bin) {\n" | 1528 | + "#include <vector>\n" |
| 1479 | - " std::vector<uint8_t> temp_kernel = {\n" | 1529 | + 'extern "C" void GetKernelBin(std::vector<char> &kernel_bin) {\n' |
| 1480 | - " 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 46, 111, 32, 102, 105, 108, 101, 32, 99, 111, \n" | 1530 | + " std::vector<uint8_t> temp_kernel = {\n" |
| 1481 | - " 110, 116, 101, 110, 116, 46, };\n" | 1531 | + " 84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 46, 111, 32, 102, 105, 108, 101, 32, 99, 111, \n" |
| 1482 | - " kernel_bin.resize(temp_kernel.size());\n" | 1532 | + " 110, 116, 101, 110, 116, 46, };\n" |
| 1483 | - " std::memcpy(kernel_bin.data(), temp_kernel.data(), temp_kernel.size() * sizeof(uint8_t));\n" | 1533 | + " kernel_bin.resize(temp_kernel.size());\n" |
| 1484 | - "}"]) | 1534 | + " std::memcpy(kernel_bin.data(), temp_kernel.data(), temp_kernel.size() * sizeof(uint8_t));\n" |
| 1535 | + "}" | ||
| 1536 | + ] | ||
| 1537 | + ) | ||
| 1485 | 1538 | ||
| 1486 | try: | 1539 | try: |
| 1487 | output_shape = ["s0"] | 1540 | output_shape = ["s0"] |
| 1488 | vector_core_num = "0" | 1541 | vector_core_num = "0" |
| 1489 | - tiling, infer_shape = codegen.host_code_generator(schedule_results, shape_info, | 1542 | + tiling, infer_shape = codegen.host_code_generator( |
| 1490 | - output_shape, "", vector_core_num) | 1543 | + schedule_results, shape_info, output_shape, "", vector_core_num |
| 1491 | - except ValueError as e: | 1544 | + ) |
| 1545 | + except ValueError: | ||
| 1492 | pass | 1546 | pass |
| 1493 | 1547 | ||
| 1494 | try: | 1548 | try: |
| 1495 | - pgo_src = codegen.pgo_code_generator(schedule_results) | 1549 | + codegen.pgo_code_generator(schedule_results) |
| 1496 | - except ValueError as e: | 1550 | + except ValueError: |
| 1497 | pass | 1551 | pass |
| 1498 | 1552 | ||
| 1499 | try: | 1553 | try: |
| 1500 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) | 1554 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path, json_path) |
| 1501 | - except ValueError as e: | 1555 | + except ValueError: |
| 1502 | pass | 1556 | pass |
| 1503 | 1557 | ||
| 1504 | try: | 1558 | try: |
| 1505 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path) | 1559 | get_kernel = codegen.get_kernel_and_json_generator(kernel_path) |
| 1506 | - except ValueError as e: | 1560 | + except ValueError: |
| 1507 | pass | 1561 | pass |
| 1508 | 1562 | ||
| 1509 | 1563 | ||
| 1510 | -class TestHintGraph(): | 1564 | +class TestHintGraph: |
| 1511 | 1565 | ||
| 1512 | def construct_graph(): | 1566 | def construct_graph(): |
| 1513 | graph = ascir.HintGraph("LoadAbsStore") | 1567 | graph = ascir.HintGraph("LoadAbsStore") |
| @@ -1567,35 +1621,35 @@ class TestHintGraph(): | |||
| 1567 | asc_graph = self.construct_graph() | 1621 | asc_graph = self.construct_graph() |
| 1568 | try: | 1622 | try: |
| 1569 | asc_graph.set_name(2) | 1623 | asc_graph.set_name(2) |
| 1570 | - except TypeError as e: | 1624 | + except TypeError: |
| 1571 | assert asc_graph.get_name() == "".join(["LoadAbsStore"]) | 1625 | assert asc_graph.get_name() == "".join(["LoadAbsStore"]) |
| 1572 | 1626 | ||
| 1573 | asc_graph.set_name("test_graph") | 1627 | asc_graph.set_name("test_graph") |
| 1574 | assert asc_graph.get_name() == "".join(["test_graph"]) | 1628 | assert asc_graph.get_name() == "".join(["test_graph"]) |
| 1575 | 1629 | ||
| 1576 | 1630 | ||
| 1577 | -class TestFusedGraph(): | 1631 | +class TestFusedGraph: |
| 1578 | 1632 | ||
| 1579 | def construct_add_ascgraph(name: str) -> ascir.HintGraph: | 1633 | def construct_add_ascgraph(name: str) -> ascir.HintGraph: |
| 1580 | - NpuKernel0Graph = ascir.HintGraph(name) | 1634 | + npu_kernel0_graph = ascir.HintGraph(name) |
| 1581 | - s0 = NpuKernel0Graph.create_size("s0") | 1635 | + s0 = npu_kernel0_graph.create_size("s0") |
| 1582 | - s1 = NpuKernel0Graph.create_size("s1") | 1636 | + s1 = npu_kernel0_graph.create_size("s1") |
| 1583 | - z0 = NpuKernel0Graph.create_axis("z0", s0) | 1637 | + z0 = npu_kernel0_graph.create_axis("z0", s0) |
| 1584 | - z1 = NpuKernel0Graph.create_axis("z1", s1) | 1638 | + z1 = npu_kernel0_graph.create_axis("z1", s1) |
| 1585 | - sub_data0 = ascir.ops.Data('sub_data0', NpuKernel0Graph) | 1639 | + sub_data0 = ascir.ops.Data("sub_data0", npu_kernel0_graph) |
| 1586 | sub_data0.y.dtype = ascir.dtypes.float16 | 1640 | sub_data0.y.dtype = ascir.dtypes.float16 |
| 1587 | sub_data0.attr.ir_attr.index = 0 | 1641 | sub_data0.attr.ir_attr.index = 0 |
| 1588 | - load0 = ascir.ops.Load('load') | 1642 | + load0 = ascir.ops.Load("load") |
| 1589 | load0.attr.ir_attr.offset = 0 | 1643 | load0.attr.ir_attr.offset = 0 |
| 1590 | load0.attr.sched.axis = [z0, z1] | 1644 | load0.attr.sched.axis = [z0, z1] |
| 1591 | load0.x = sub_data0.y | 1645 | load0.x = sub_data0.y |
| 1592 | load0.y.axis = [z0, z1] | 1646 | load0.y.axis = [z0, z1] |
| 1593 | load0.y.strides = [s1, ascir.SizeExpr(1)] | 1647 | load0.y.strides = [s1, ascir.SizeExpr(1)] |
| 1594 | load0.y.size = [s0, s1] | 1648 | load0.y.size = [s0, s1] |
| 1595 | - sub_data1 = ascir.ops.Data('sub_data1', NpuKernel0Graph) | 1649 | + sub_data1 = ascir.ops.Data("sub_data1", npu_kernel0_graph) |
| 1596 | sub_data1.y.dtype = ascir.dtypes.float16 | 1650 | sub_data1.y.dtype = ascir.dtypes.float16 |
| 1597 | sub_data1.attr.ir_attr.index = 1 | 1651 | sub_data1.attr.ir_attr.index = 1 |
| 1598 | - load1 = ascir.ops.Load('load') | 1652 | + load1 = ascir.ops.Load("load") |
| 1599 | load1.attr.ir_attr.offset = ascir.SizeExpr(0) | 1653 | load1.attr.ir_attr.offset = ascir.SizeExpr(0) |
| 1600 | load1.attr.sched.axis = [z0, z1] | 1654 | load1.attr.sched.axis = [z0, z1] |
| 1601 | load1.x = sub_data1.y | 1655 | load1.x = sub_data1.y |
| @@ -1603,7 +1657,7 @@ class TestFusedGraph(): | |||
| 1603 | load1.y.strides = [s1, ascir.SizeExpr(1)] | 1657 | load1.y.strides = [s1, ascir.SizeExpr(1)] |
| 1604 | load1.y.size = [s0, s1] | 1658 | load1.y.size = [s0, s1] |
| 1605 | 1659 | ||
| 1606 | - add0 = ascir.ops.Add('add') | 1660 | + add0 = ascir.ops.Add("add") |
| 1607 | add0.attr.sched.axis = [z0, z1] | 1661 | add0.attr.sched.axis = [z0, z1] |
| 1608 | add0.x1 = load0.y | 1662 | add0.x1 = load0.y |
| 1609 | add0.x2 = load1.y | 1663 | add0.x2 = load1.y |
| @@ -1611,52 +1665,52 @@ class TestFusedGraph(): | |||
| 1611 | add0.y.strides = [s1 + s1, ascir.SizeExpr(1)] | 1665 | add0.y.strides = [s1 + s1, ascir.SizeExpr(1)] |
| 1612 | add0.y.size = [s0, s1 * 2] | 1666 | add0.y.size = [s0, s1 * 2] |
| 1613 | 1667 | ||
| 1614 | - store0 = ascir.ops.Store('store') | 1668 | + store0 = ascir.ops.Store("store") |
| 1615 | store0.attr.ir_attr.offset = ascir.SizeExpr(0) | 1669 | store0.attr.ir_attr.offset = ascir.SizeExpr(0) |
| 1616 | store0.attr.sched.axis = [z0, z1] | 1670 | store0.attr.sched.axis = [z0, z1] |
| 1617 | store0.x = add0.y | 1671 | store0.x = add0.y |
| 1618 | store0.y.axis = [z0, z1] | 1672 | store0.y.axis = [z0, z1] |
| 1619 | - store0.y.strides = [s1 ** 2, ascir.SizeExpr(1)] | 1673 | + store0.y.strides = [s1**2, ascir.SizeExpr(1)] |
| 1620 | store0.y.size = [s0, s1 * 2] | 1674 | store0.y.size = [s0, s1 * 2] |
| 1621 | 1675 | ||
| 1622 | - store1 = ascir.ops.Store('store') | 1676 | + store1 = ascir.ops.Store("store") |
| 1623 | store1.attr.ir_attr.offset = ascir.SizeExpr(10) | 1677 | store1.attr.ir_attr.offset = ascir.SizeExpr(10) |
| 1624 | store1.attr.sched.axis = [z0, z1] | 1678 | store1.attr.sched.axis = [z0, z1] |
| 1625 | store1.x = add0.y | 1679 | store1.x = add0.y |
| 1626 | store1.y.axis = [z0, z1] | 1680 | store1.y.axis = [z0, z1] |
| 1627 | store1.y.strides = [s1 * 2, ascir.SizeExpr(1)] | 1681 | store1.y.strides = [s1 * 2, ascir.SizeExpr(1)] |
| 1628 | store1.y.size = [s0, s1 * 2] | 1682 | store1.y.size = [s0, s1 * 2] |
| 1629 | - buf0 = ascir.ops.Output('buf0') | 1683 | + buf0 = ascir.ops.Output("buf0") |
| 1630 | buf0.attr.ir_attr.index = 0 | 1684 | buf0.attr.ir_attr.index = 0 |
| 1631 | # store0, strore1 写到同一个output上,偏移不同 | 1685 | # store0, strore1 写到同一个output上,偏移不同 |
| 1632 | buf0.x = [store0.y, store1] | 1686 | buf0.x = [store0.y, store1] |
| 1633 | buf0.y.dtype = ascir.dtypes.float16 | 1687 | buf0.y.dtype = ascir.dtypes.float16 |
| 1634 | - buf1 = ascir.ops.Output('buf1') | 1688 | + buf1 = ascir.ops.Output("buf1") |
| 1635 | buf1.attr.ir_attr.index = 1 | 1689 | buf1.attr.ir_attr.index = 1 |
| 1636 | buf1.x = store1.y | 1690 | buf1.x = store1.y |
| 1637 | - NpuKernel0Graph.infer_dtypes() | 1691 | + npu_kernel0_graph.infer_dtypes() |
| 1638 | - ascir.utils.dump(NpuKernel0Graph) | 1692 | + ascir.utils.dump(npu_kernel0_graph) |
| 1639 | - return NpuKernel0Graph | 1693 | + return npu_kernel0_graph |
| 1640 | 1694 | ||
| 1641 | 1695 | ||
| 1642 | def construct_add_ascgraph_without_data(name: str) -> ascir.HintGraph: | 1696 | def construct_add_ascgraph_without_data(name: str) -> ascir.HintGraph: |
| 1643 | - NpuKernel0Graph = ascir.HintGraph(name) | 1697 | + npu_kernel0_graph = ascir.HintGraph(name) |
| 1644 | - s0 = NpuKernel0Graph.create_size("s0") | 1698 | + s0 = npu_kernel0_graph.create_size("s0") |
| 1645 | - s1 = NpuKernel0Graph.create_size("s1") | 1699 | + s1 = npu_kernel0_graph.create_size("s1") |
| 1646 | - z0 = NpuKernel0Graph.create_axis("z0", s0) | 1700 | + z0 = npu_kernel0_graph.create_axis("z0", s0) |
| 1647 | - z1 = NpuKernel0Graph.create_axis("z1", s1) | 1701 | + z1 = npu_kernel0_graph.create_axis("z1", s1) |
| 1648 | - sub_data0 = ascir.ops.Scalar('sub_data0', NpuKernel0Graph) | 1702 | + sub_data0 = ascir.ops.Scalar("sub_data0", npu_kernel0_graph) |
| 1649 | sub_data0.y.dtype = ascir.dtypes.float16 | 1703 | sub_data0.y.dtype = ascir.dtypes.float16 |
| 1650 | - load0 = ascir.ops.Load('load') | 1704 | + load0 = ascir.ops.Load("load") |
| 1651 | load0.attr.ir_attr.offset = 0 | 1705 | load0.attr.ir_attr.offset = 0 |
| 1652 | load0.attr.sched.axis = [z0, z1] | 1706 | load0.attr.sched.axis = [z0, z1] |
| 1653 | load0.x = sub_data0.y | 1707 | load0.x = sub_data0.y |
| 1654 | load0.y.axis = [z0, z1] | 1708 | load0.y.axis = [z0, z1] |
| 1655 | load0.y.strides = [s1, ascir.SizeExpr(1)] | 1709 | load0.y.strides = [s1, ascir.SizeExpr(1)] |
| 1656 | load0.y.size = [s0, s1] | 1710 | load0.y.size = [s0, s1] |
| 1657 | - sub_data1 = ascir.ops.Scalar('sub_data1', NpuKernel0Graph) | 1711 | + sub_data1 = ascir.ops.Scalar("sub_data1", npu_kernel0_graph) |
| 1658 | sub_data1.y.dtype = ascir.dtypes.float16 | 1712 | sub_data1.y.dtype = ascir.dtypes.float16 |
| 1659 | - load1 = ascir.ops.Load('load') | 1713 | + load1 = ascir.ops.Load("load") |
| 1660 | load1.attr.ir_attr.offset = ascir.SizeExpr(0) | 1714 | load1.attr.ir_attr.offset = ascir.SizeExpr(0) |
| 1661 | load1.attr.sched.axis = [z0, z1] | 1715 | load1.attr.sched.axis = [z0, z1] |
| 1662 | load1.x = sub_data1.y | 1716 | load1.x = sub_data1.y |
| @@ -1664,7 +1718,7 @@ class TestFusedGraph(): | |||
| 1664 | load1.y.strides = [s1, ascir.SizeExpr(1)] | 1718 | load1.y.strides = [s1, ascir.SizeExpr(1)] |
| 1665 | load1.y.size = [s0, s1] | 1719 | load1.y.size = [s0, s1] |
| 1666 | 1720 | ||
| 1667 | - add0 = ascir.ops.Add('add') | 1721 | + add0 = ascir.ops.Add("add") |
| 1668 | add0.attr.sched.axis = [z0, z1] | 1722 | add0.attr.sched.axis = [z0, z1] |
| 1669 | add0.x1 = load0.y | 1723 | add0.x1 = load0.y |
| 1670 | add0.x2 = load1.y | 1724 | add0.x2 = load1.y |
| @@ -1672,134 +1726,158 @@ class TestFusedGraph(): | |||
| 1672 | add0.y.strides = [s1 + s1, ascir.SizeExpr(1)] | 1726 | add0.y.strides = [s1 + s1, ascir.SizeExpr(1)] |
| 1673 | add0.y.size = [s0, s1 * 2] | 1727 | add0.y.size = [s0, s1 * 2] |
| 1674 | 1728 | ||
| 1675 | - store0 = ascir.ops.Store('store') | 1729 | + store0 = ascir.ops.Store("store") |
| 1676 | store0.attr.ir_attr.offset = ascir.SizeExpr(0) | 1730 | store0.attr.ir_attr.offset = ascir.SizeExpr(0) |
| 1677 | store0.attr.sched.axis = [z0, z1] | 1731 | store0.attr.sched.axis = [z0, z1] |
| 1678 | store0.x = add0.y | 1732 | store0.x = add0.y |
| 1679 | store0.y.axis = [z0, z1] | 1733 | store0.y.axis = [z0, z1] |
| 1680 | - store0.y.strides = [s1 ** 2, ascir.SizeExpr(1)] | 1734 | + store0.y.strides = [s1**2, ascir.SizeExpr(1)] |
| 1681 | store0.y.size = [s0, s1 * 2] | 1735 | store0.y.size = [s0, s1 * 2] |
| 1682 | 1736 | ||
| 1683 | - store1 = ascir.ops.Store('store') | 1737 | + store1 = ascir.ops.Store("store") |
| 1684 | store1.attr.ir_attr.offset = ascir.SizeExpr(10) | 1738 | store1.attr.ir_attr.offset = ascir.SizeExpr(10) |
| 1685 | store1.attr.sched.axis = [z0, z1] | 1739 | store1.attr.sched.axis = [z0, z1] |
| 1686 | store1.x = add0.y | 1740 | store1.x = add0.y |
| 1687 | store1.y.axis = [z0, z1] | 1741 | store1.y.axis = [z0, z1] |
| 1688 | store1.y.strides = [s1 * 2, ascir.SizeExpr(1)] | 1742 | store1.y.strides = [s1 * 2, ascir.SizeExpr(1)] |
| 1689 | store1.y.size = [s0, s1 * 2] | 1743 | store1.y.size = [s0, s1 * 2] |
| 1690 | - buf0 = ascir.ops.Output('buf0') | 1744 | + buf0 = ascir.ops.Output("buf0") |
| 1691 | buf0.attr.ir_attr.index = 0 | 1745 | buf0.attr.ir_attr.index = 0 |
| 1692 | # store0, strore1 写到同一个output上,偏移不同 | 1746 | # store0, strore1 写到同一个output上,偏移不同 |
| 1693 | buf0.x = [store0.y, store1] | 1747 | buf0.x = [store0.y, store1] |
| 1694 | buf0.y.dtype = ascir.dtypes.float16 | 1748 | buf0.y.dtype = ascir.dtypes.float16 |
| 1695 | - buf1 = ascir.ops.Output('buf1') | 1749 | + buf1 = ascir.ops.Output("buf1") |
| 1696 | buf1.attr.ir_attr.index = 1 | 1750 | buf1.attr.ir_attr.index = 1 |
| 1697 | buf1.x = store1.y | 1751 | buf1.x = store1.y |
| 1698 | - NpuKernel0Graph.infer_dtypes() | 1752 | + npu_kernel0_graph.infer_dtypes() |
| 1699 | - ascir.utils.dump(NpuKernel0Graph) | 1753 | + ascir.utils.dump(npu_kernel0_graph) |
| 1700 | - return NpuKernel0Graph | 1754 | + return npu_kernel0_graph |
| 1701 | 1755 | ||
| 1702 | def test_fused_graph_construct_and_dump_with_ascbackend_node(self): | 1756 | def test_fused_graph_construct_and_dump_with_ascbackend_node(self): |
| 1703 | - FusedGraph = ascir.FusedGraph('fused_graph') | 1757 | + fused_graph = ascir.FusedGraph("fused_graph") |
| 1704 | - data0 = ascir.ops.Data('data0', FusedGraph) | 1758 | + data0 = ascir.ops.Data("data0", fused_graph) |
| 1705 | data0.attr.ir_attr.index = 0 | 1759 | data0.attr.ir_attr.index = 0 |
| 1706 | - data1 = ascir.ops.Data('data1', FusedGraph) | 1760 | + data1 = ascir.ops.Data("data1", fused_graph) |
| 1707 | data1.attr.ir_attr.index = 0 | 1761 | data1.attr.ir_attr.index = 0 |
| 1708 | - ascgraph_node0 = ascir.ops.AscBackend("ascgraph_node0", self.construct_add_ascgraph_without_data("ascgraph0"), | 1762 | + ascgraph_node0 = ascir.ops.AscBackend( |
| 1709 | - FusedGraph) | 1763 | + "ascgraph_node0", |
| 1710 | - ascgraph_node1 = ascir.ops.AscBackend("ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), FusedGraph) | 1764 | + self.construct_add_ascgraph_without_data("ascgraph0"), |
| 1765 | + fused_graph, | ||
| 1766 | + ) | ||
| 1767 | + ascgraph_node1 = ascir.ops.AscBackend( | ||
| 1768 | + "ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), fused_graph | ||
| 1769 | + ) | ||
| 1711 | ascgraph_node1.x = [data0.y, data1.y] | 1770 | ascgraph_node1.x = [data0.y, data1.y] |
| 1712 | - ascgraph_node2 = ascir.ops.AscBackend("ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), FusedGraph) | 1771 | + ascgraph_node2 = ascir.ops.AscBackend( |
| 1772 | + "ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), fused_graph | ||
| 1773 | + ) | ||
| 1713 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[1]] | 1774 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[1]] |
| 1714 | - output = ascir.ops.Output('output', FusedGraph) | 1775 | + output = ascir.ops.Output("output", fused_graph) |
| 1715 | output.x = ascgraph_node2.y[1] | 1776 | output.x = ascgraph_node2.y[1] |
| 1716 | - ascir.utils.dump(FusedGraph) | 1777 | + ascir.utils.dump(fused_graph) |
| 1717 | 1778 | ||
| 1718 | def test_fused_graph_inductor(self): | 1779 | def test_fused_graph_inductor(self): |
| 1719 | - FusedGraph = ascir.FusedGraph('fused_graph') | 1780 | + fused_graph = ascir.FusedGraph("fused_graph") |
| 1720 | 1781 | ||
| 1721 | options = AutofuserOptions() | 1782 | options = AutofuserOptions() |
| 1722 | - scheduler = Schedule(options) | 1783 | + Schedule(options) |
| 1723 | fuser = Autofuser(options) | 1784 | fuser = Autofuser(options) |
| 1724 | try: | 1785 | try: |
| 1725 | - schedule_results = fuser.schedule(FusedGraph) | 1786 | + fuser.schedule(fused_graph) |
| 1726 | - tiling_def, host_tiling, op_kernel = fuser.autofuse_backend(FusedGraph) | 1787 | + tiling_def, host_tiling, op_kernel = fuser.autofuse_backend(fused_graph) |
| 1727 | - except RuntimeError as e: | 1788 | + except RuntimeError: |
| 1728 | pass | 1789 | pass |
| 1729 | 1790 | ||
| 1730 | def test_fused_graph_construct_and_dump_with_ascgraph_node(self): | 1791 | def test_fused_graph_construct_and_dump_with_ascgraph_node(self): |
| 1731 | - FusedGraph = ascir.FusedGraph('fused_graph') | 1792 | + fused_graph = ascir.FusedGraph("fused_graph") |
| 1732 | - data0 = ascir.ops.Data('data0', FusedGraph) | 1793 | + data0 = ascir.ops.Data("data0", fused_graph) |
| 1733 | data0.attr.ir_attr.index = 0 | 1794 | data0.attr.ir_attr.index = 0 |
| 1734 | - data1 = ascir.ops.Data('data1', FusedGraph) | 1795 | + data1 = ascir.ops.Data("data1", fused_graph) |
| 1735 | data1.attr.ir_attr.index = 0 | 1796 | data1.attr.ir_attr.index = 0 |
| 1736 | - ascgraph_node0 = ascir.ops.AscGraph("ascgraph_node0", self.construct_add_ascgraph("ascgraph0"), FusedGraph) | 1797 | + ascgraph_node0 = ascir.ops.AscGraph( |
| 1798 | + "ascgraph_node0", self.construct_add_ascgraph("ascgraph0"), fused_graph | ||
| 1799 | + ) | ||
| 1737 | ascgraph_node0.x = [data0.y, data1.y] | 1800 | ascgraph_node0.x = [data0.y, data1.y] |
| 1738 | - ascgraph_node1 = ascir.ops.AscGraph("ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), FusedGraph) | 1801 | + ascgraph_node1 = ascir.ops.AscGraph( |
| 1802 | + "ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), fused_graph | ||
| 1803 | + ) | ||
| 1739 | ascgraph_node1.x = [data0.y, data1.y] | 1804 | ascgraph_node1.x = [data0.y, data1.y] |
| 1740 | - ascgraph_node2 = ascir.ops.AscGraph("ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), FusedGraph) | 1805 | + ascgraph_node2 = ascir.ops.AscGraph( |
| 1806 | + "ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), fused_graph | ||
| 1807 | + ) | ||
| 1741 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[0]] | 1808 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[0]] |
| 1742 | - output = ascir.ops.Output('output', FusedGraph) | 1809 | + output = ascir.ops.Output("output", fused_graph) |
| 1743 | output.x = ascgraph_node2.y[0] | 1810 | output.x = ascgraph_node2.y[0] |
| 1744 | try: | 1811 | try: |
| 1745 | ascgraph_node2.x = [ascgraph_node0.y[0].dtype, ascgraph_node1.y[0]] | 1812 | ascgraph_node2.x = [ascgraph_node0.y[0].dtype, ascgraph_node1.y[0]] |
| 1746 | except TypeError as e: | 1813 | except TypeError as e: |
| 1747 | assert e.args[0] == "Input Type is invalid." | 1814 | assert e.args[0] == "Input Type is invalid." |
| 1748 | 1815 | ||
| 1749 | - ascir.utils.dump(FusedGraph) | 1816 | + ascir.utils.dump(fused_graph) |
| 1750 | try: | 1817 | try: |
| 1751 | ascir.utils.dump(data0) | 1818 | ascir.utils.dump(data0) |
| 1752 | except TypeError as e: | 1819 | except TypeError as e: |
| 1753 | - assert e.args[0] == "Argument must be a HintGraph or FusedGraph object, got Data" | 1820 | + assert ( |
| 1821 | + e.args[0] | ||
| 1822 | + == "Argument must be a HintGraph or FusedGraph object, got Data" | ||
| 1823 | + ) | ||
| 1754 | 1824 | ||
| 1755 | 1825 | ||
| 1756 | -class TestFusedGraphByApi(): | 1826 | +class TestFusedGraphByApi: |
| 1757 | 1827 | ||
| 1758 | def construct_add_ascgraph(name: str) -> ascir.HintGraph: | 1828 | def construct_add_ascgraph(name: str) -> ascir.HintGraph: |
| 1759 | - NpuKernel0Graph = ascir.HintGraph(name) | 1829 | + npu_kernel0_graph = ascir.HintGraph(name) |
| 1760 | - s0 = NpuKernel0Graph.create_size("s0") | 1830 | + s0 = npu_kernel0_graph.create_size("s0") |
| 1761 | - s1 = NpuKernel0Graph.create_size("s1") | 1831 | + s1 = npu_kernel0_graph.create_size("s1") |
| 1762 | - z0 = NpuKernel0Graph.create_axis("z0", s0) | 1832 | + z0 = npu_kernel0_graph.create_axis("z0", s0) |
| 1763 | - z1 = NpuKernel0Graph.create_axis("z1", s1) | 1833 | + z1 = npu_kernel0_graph.create_axis("z1", s1) |
| 1764 | - sub_data0 = ascir_api.Data(NpuKernel0Graph, dtype=ascir.dtypes.float16) | 1834 | + sub_data0 = ascir_api.Data(npu_kernel0_graph, dtype=ascir.dtypes.float16) |
| 1765 | - load0 = ascir_api.Load(NpuKernel0Graph, sub_data0, offset=0, axis=[z0, z1]) | 1835 | + load0 = ascir_api.Load(npu_kernel0_graph, sub_data0, offset=0, axis=[z0, z1]) |
| 1766 | assert load0.axis == [z0.id, z1.id] | 1836 | assert load0.axis == [z0.id, z1.id] |
| 1767 | assert load0.size == [s0, s1] | 1837 | assert load0.size == [s0, s1] |
| 1768 | assert load0.strides == [s1, 1] | 1838 | assert load0.strides == [s1, 1] |
| 1769 | - sub_data1 = ascir_api.Data(NpuKernel0Graph, dtype=ascir.dtypes.float16) | 1839 | + sub_data1 = ascir_api.Data(npu_kernel0_graph, dtype=ascir.dtypes.float16) |
| 1770 | - load1 = ascir_api.Load(NpuKernel0Graph, sub_data1, offset=0, axis=[z0, z1]) | 1840 | + load1 = ascir_api.Load(npu_kernel0_graph, sub_data1, offset=0, axis=[z0, z1]) |
| 1771 | - add0 = ascir_api.Add(NpuKernel0Graph, load0, load1, axis=[z0, z1]) | 1841 | + add0 = ascir_api.Add(npu_kernel0_graph, load0, load1, axis=[z0, z1]) |
| 1772 | assert add0.axis == [z0.id, z1.id] | 1842 | assert add0.axis == [z0.id, z1.id] |
| 1773 | assert add0.size == [s0, s1] | 1843 | assert add0.size == [s0, s1] |
| 1774 | assert add0.strides == [s1, 1] | 1844 | assert add0.strides == [s1, 1] |
| 1775 | - store0 = ascir_api.Store(NpuKernel0Graph, add0, offset=0, axis=[z0, z1]) | 1845 | + store0 = ascir_api.Store(npu_kernel0_graph, add0, offset=0, axis=[z0, z1]) |
| 1776 | - store1 = ascir_api.Store(NpuKernel0Graph, add0, offset=10, axis=[z0, z1]) | 1846 | + store1 = ascir_api.Store(npu_kernel0_graph, add0, offset=10, axis=[z0, z1]) |
| 1777 | # store0, strore1 写到同一个output上,偏移不同 | 1847 | # store0, strore1 写到同一个output上,偏移不同 |
| 1778 | - buf0 = ascir_api.Output(NpuKernel0Graph, [store0, store1], dtype=ascir.dtypes.float16) | 1848 | + ascir_api.Output( |
| 1779 | - buf1 = ascir_api.Output(NpuKernel0Graph, store1) # infer | 1849 | + npu_kernel0_graph, [store0, store1], dtype=ascir.dtypes.float16 |
| 1850 | + ) | ||
| 1851 | + buf1 = ascir_api.Output(npu_kernel0_graph, store1) # infer | ||
| 1780 | assert buf1.dtype == ascir.dtypes.float16 | 1852 | assert buf1.dtype == ascir.dtypes.float16 |
| 1781 | - print(ascir.utils.debug_str(NpuKernel0Graph)) | 1853 | + print(ascir.utils.debug_str(npu_kernel0_graph)) |
| 1782 | - return NpuKernel0Graph | 1854 | + return npu_kernel0_graph |
| 1783 | 1855 | ||
| 1784 | def test_fused_graph_construct_and_dump_with_ascbackend_node(self): | 1856 | def test_fused_graph_construct_and_dump_with_ascbackend_node(self): |
| 1785 | - FusedGraph = ascir.FusedGraph('fused_graph') | 1857 | + fused_graph = ascir.FusedGraph("fused_graph") |
| 1786 | - data0 = ascir.ops.Data('data0', FusedGraph) | 1858 | + data0 = ascir.ops.Data("data0", fused_graph) |
| 1787 | data0.attr.ir_attr.index = 0 | 1859 | data0.attr.ir_attr.index = 0 |
| 1788 | - data1 = ascir.ops.Data('data1', FusedGraph) | 1860 | + data1 = ascir.ops.Data("data1", fused_graph) |
| 1789 | data1.attr.ir_attr.index = 0 | 1861 | data1.attr.ir_attr.index = 0 |
| 1790 | - ascgraph_node0 = ascir.ops.AscGraph("ascgraph_node0", self.construct_add_ascgraph("ascgraph0"), | 1862 | + ascgraph_node0 = ascir.ops.AscGraph( |
| 1791 | - FusedGraph) | 1863 | + "ascgraph_node0", self.construct_add_ascgraph("ascgraph0"), fused_graph |
| 1864 | + ) | ||
| 1792 | ascgraph_node0.x = [data0.y, data1.y] | 1865 | ascgraph_node0.x = [data0.y, data1.y] |
| 1793 | - ascgraph_node1 = ascir.ops.AscGraph("ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), FusedGraph) | 1866 | + ascgraph_node1 = ascir.ops.AscGraph( |
| 1867 | + "ascgraph_node1", self.construct_add_ascgraph("ascgraph1"), fused_graph | ||
| 1868 | + ) | ||
| 1794 | ascgraph_node1.x = [data0.y, data1.y] | 1869 | ascgraph_node1.x = [data0.y, data1.y] |
| 1795 | - ascgraph_node2 = ascir.ops.AscGraph("ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), FusedGraph) | 1870 | + ascgraph_node2 = ascir.ops.AscGraph( |
| 1871 | + "ascgraph_node2", self.construct_add_ascgraph("ascgraph2"), fused_graph | ||
| 1872 | + ) | ||
| 1796 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[1]] | 1873 | ascgraph_node2.x = [ascgraph_node0.y[0], ascgraph_node1.y[1]] |
| 1797 | - output = ascir.ops.Output('output', FusedGraph) | 1874 | + output = ascir.ops.Output("output", fused_graph) |
| 1798 | output.x = ascgraph_node2.y[1] | 1875 | output.x = ascgraph_node2.y[1] |
| 1799 | - ascir.utils.dump(FusedGraph) | 1876 | + ascir.utils.dump(fused_graph) |
| 1877 | + | ||
| 1800 | 1878 | ||
| 1801 | # 测试包含transpose的sched, codegen的流程, 执行不抛异常, 返回结果非空 | 1879 | # 测试包含transpose的sched, codegen的流程, 执行不抛异常, 返回结果非空 |
| 1802 | -class TestAutofuseLoadTransposeStore(): | 1880 | +class TestAutofuseLoadTransposeStore: |
| 1803 | 1881 | ||
| 1804 | def construct_invalid_graph(): | 1882 | def construct_invalid_graph(): |
| 1805 | graph = ascir.HintGraph("LoadTransposeStore") | 1883 | graph = ascir.HintGraph("LoadTransposeStore") |
| @@ -1835,7 +1913,7 @@ class TestAutofuseLoadTransposeStore(): | |||
| 1835 | buf_z2 = graph.create_axis("buf_z2", s2) | 1913 | buf_z2 = graph.create_axis("buf_z2", s2) |
| 1836 | 1914 | ||
| 1837 | arg3_1 = ascir.ops.Data("arg3_1", graph) | 1915 | arg3_1 = ascir.ops.Data("arg3_1", graph) |
| 1838 | - arg3_1.attr.ir_attr.index= 0 | 1916 | + arg3_1.attr.ir_attr.index = 0 |
| 1839 | arg3_1.attr.sched.axis = [z0, z1, z2] | 1917 | arg3_1.attr.sched.axis = [z0, z1, z2] |
| 1840 | arg3_1.y.dtype = ascir.dtypes.float16 | 1918 | arg3_1.y.dtype = ascir.dtypes.float16 |
| 1841 | arg3_1.y.axis = [z0, z1, z2] | 1919 | arg3_1.y.axis = [z0, z1, z2] |
| @@ -1846,7 +1924,7 @@ class TestAutofuseLoadTransposeStore(): | |||
| 1846 | try: | 1924 | try: |
| 1847 | load.attr.ir_attr.offset = "3" | 1925 | load.attr.ir_attr.offset = "3" |
| 1848 | except Exception as e: | 1926 | except Exception as e: |
| 1849 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 1927 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 1850 | offset_of_0 = ascir.SizeExpr(0) | 1928 | offset_of_0 = ascir.SizeExpr(0) |
| 1851 | load.attr.ir_attr.offset = offset_of_0 | 1929 | load.attr.ir_attr.offset = offset_of_0 |
| 1852 | assert load.attr.ir_attr.offset.expression == "0" | 1930 | assert load.attr.ir_attr.offset.expression == "0" |
| @@ -1869,7 +1947,7 @@ class TestAutofuseLoadTransposeStore(): | |||
| 1869 | try: | 1947 | try: |
| 1870 | store.attr.ir_attr.offset = "4" | 1948 | store.attr.ir_attr.offset = "4" |
| 1871 | except Exception as e: | 1949 | except Exception as e: |
| 1872 | - assert e.args[0] == 'Only support type of SizeExpr or long' | 1950 | + assert e.args[0] == "Only support type of SizeExpr or long" |
| 1873 | store.attr.ir_attr.offset = offset_of_0 + 1 | 1951 | store.attr.ir_attr.offset = offset_of_0 + 1 |
| 1874 | assert store.attr.ir_attr.offset.expression == "1" | 1952 | assert store.attr.ir_attr.offset.expression == "1" |
| 1875 | store.x = transpose0_op | 1953 | store.x = transpose0_op |
| @@ -1888,7 +1966,7 @@ class TestAutofuseLoadTransposeStore(): | |||
| 1888 | buf1.y.axis = [z1, z0, z2] | 1966 | buf1.y.axis = [z1, z0, z2] |
| 1889 | buf1.y.size = [s1, s0, s2] | 1967 | buf1.y.size = [s1, s0, s2] |
| 1890 | buf1.y.strides = [s0 * s2, s2, ascir.SizeExpr(1)] | 1968 | buf1.y.strides = [s0 * s2, s2, ascir.SizeExpr(1)] |
| 1891 | - graph.set_axis_map({z0:[buf_z0], z1:[buf_z1], z2:[buf_z2]}) | 1969 | + graph.set_axis_map({z0: [buf_z0], z1: [buf_z1], z2: [buf_z2]}) |
| 1892 | return graph | 1970 | return graph |
| 1893 | 1971 | ||
| 1894 | def test_construct_graph(self): | 1972 | def test_construct_graph(self): |
| @@ -1897,33 +1975,35 @@ class TestAutofuseLoadTransposeStore(): | |||
| 1897 | assert debug_str | 1975 | assert debug_str |
| 1898 | 1976 | ||
| 1899 | def test_autofuse_backend(self): | 1977 | def test_autofuse_backend(self): |
| 1900 | - options = AutofuserOptions() | 1978 | + options = AutofuserOptions() |
| 1901 | - fuser = Autofuser(options) | 1979 | + fuser = Autofuser(options) |
| 1902 | - try: | 1980 | + try: |
| 1903 | hint_graph = self.construct_graph() | 1981 | hint_graph = self.construct_graph() |
| 1904 | sched_result = fuser.schedule(hint_graph) | 1982 | sched_result = fuser.schedule(hint_graph) |
| 1905 | tiling_def, host_tiling, op_kernel = fuser.codegen(sched_result) | 1983 | tiling_def, host_tiling, op_kernel = fuser.codegen(sched_result) |
| 1906 | assert len(tiling_def) > 0 | 1984 | assert len(tiling_def) > 0 |
| 1907 | assert len(host_tiling) > 0 | 1985 | assert len(host_tiling) > 0 |
| 1908 | assert len(op_kernel) > 0 | 1986 | assert len(op_kernel) > 0 |
| 1909 | - except RuntimeError as e: | 1987 | + except RuntimeError: |
| 1910 | pass | 1988 | pass |
| 1989 | + | ||
| 1911 | import os | 1990 | import os |
| 1991 | + | ||
| 1912 | def test_autofuse_backend_faild_dump_graph(self): | 1992 | def test_autofuse_backend_faild_dump_graph(self): |
| 1913 | options = AutofuserOptions() | 1993 | options = AutofuserOptions() |
| 1914 | fuser = Autofuser(options) | 1994 | fuser = Autofuser(options) |
| 1915 | hint_graph = self.construct_invalid_graph() | 1995 | hint_graph = self.construct_invalid_graph() |
| 1916 | - with pytest.raises(RuntimeError, match=r'^Optimize fail$'): | 1996 | + with pytest.raises(RuntimeError, match=r"^Optimize fail$"): |
| 1917 | - sched_result = fuser.schedule(hint_graph) | 1997 | + fuser.schedule(hint_graph) |
| 1918 | - target_dir = './' | 1998 | + target_dir = "./" |
| 1919 | for item in os.listdir(target_dir): | 1999 | for item in os.listdir(target_dir): |
| 1920 | item_path = os.path.join(target_dir, item) | 2000 | item_path = os.path.join(target_dir, item) |
| 1921 | - if os.path.isdir(item_path) and item.startswith('ascgen_dump_pid'): | 2001 | + if os.path.isdir(item_path) and item.startswith("ascgen_dump_pid"): |
| 1922 | print(f"delete dump dir :{item_path}") | 2002 | print(f"delete dump dir :{item_path}") |
| 1923 | shutil.rmtree(item_path) | 2003 | shutil.rmtree(item_path) |
| 1924 | 2004 | ||
| 1925 | 2005 | ||
| 1926 | -class TestSizeExprMaxMin(): | 2006 | +class TestSizeExprMaxMin: |
| 1927 | """Test Max and Min functions for SizeExpr""" | 2007 | """Test Max and Min functions for SizeExpr""" |
| 1928 | 2008 | ||
| 1929 | 2009 | ||
| @@ -2001,7 +2081,7 @@ class TestSizeExprMaxMin(): | |||
| 2001 | s1 = ascir.SizeExpr(20) | 2081 | s1 = ascir.SizeExpr(20) |
| 2002 | s2 = ascir.SizeExpr(30) | 2082 | s2 = ascir.SizeExpr(30) |
| 2003 | expr1 = s0 + s1 # 30 | 2083 | expr1 = s0 + s1 # 30 |
| 2004 | - expr2 = s2 # 30 | 2084 | + expr2 = s2 # 30 |
| 2005 | max_expr = Max(expr1, expr2) | 2085 | max_expr = Max(expr1, expr2) |
| 2006 | assert max_expr == 30 | 2086 | assert max_expr == 30 |
| 2007 | 2087 | ||
| @@ -2012,7 +2092,7 @@ class TestSizeExprMaxMin(): | |||
| 2012 | s1 = ascir.SizeExpr(20) | 2092 | s1 = ascir.SizeExpr(20) |
| 2013 | s2 = ascir.SizeExpr(5) | 2093 | s2 = ascir.SizeExpr(5) |
| 2014 | expr1 = s0 + s1 # 30 | 2094 | expr1 = s0 + s1 # 30 |
| 2015 | - expr2 = s2 # 5 | 2095 | + expr2 = s2 # 5 |
| 2016 | min_expr = Min(expr1, expr2) | 2096 | min_expr = Min(expr1, expr2) |
| 2017 | assert min_expr == 5 | 2097 | assert min_expr == 5 |
| 2018 | 2098 | ||
| @@ -2045,7 +2125,7 @@ class TestSizeExprMaxMin(): | |||
| 2045 | assert min_val == 20 | 2125 | assert min_val == 20 |
| 2046 | 2126 | ||
| 2047 | 2127 | ||
| 2048 | -class TestSizeExprMod(): | 2128 | +class TestSizeExprMod: |
| 2049 | """Test Mod function for SizeExpr""" | 2129 | """Test Mod function for SizeExpr""" |
| 2050 | 2130 | ||
| 2051 | 2131 | ||
| @@ -2103,7 +2183,7 @@ class TestSizeExprMod(): | |||
| 2103 | assert mod_abc == 2 | 2183 | assert mod_abc == 2 |
| 2104 | 2184 | ||
| 2105 | 2185 | ||
| 2106 | -class TestSizeExprArithmetic(): | 2186 | +class TestSizeExprArithmetic: |
| 2107 | """Test SizeExpr arithmetic operators in various scenarios""" | 2187 | """Test SizeExpr arithmetic operators in various scenarios""" |
| 2108 | 2188 | ||
| 2109 | 2189 | ||
| @@ -2113,8 +2193,8 @@ class TestSizeExprArithmetic(): | |||
| 2113 | base_size = graph.create_size("base") | 2193 | base_size = graph.create_size("base") |
| 2114 | 2194 | ||
| 2115 | # Block size = base^2 | 2195 | # Block size = base^2 |
| 2116 | - block_size = base_size ** 2 | 2196 | + block_size = base_size**2 |
| 2117 | - z0 = graph.create_axis("z0", block_size) | 2197 | + graph.create_axis("z0", block_size) |
| 2118 | 2198 | ||
| 2119 | debug_str = ascir.utils.debug_str(graph) | 2199 | debug_str = ascir.utils.debug_str(graph) |
| 2120 | assert debug_str | 2200 | assert debug_str |
| @@ -2130,7 +2210,7 @@ class TestSizeExprArithmetic(): | |||
| 2130 | 2210 | ||
| 2131 | # Total elements = batch * seq * hidden | 2211 | # Total elements = batch * seq * hidden |
| 2132 | total_elements = batch_size * seq_len * hidden_size | 2212 | total_elements = batch_size * seq_len * hidden_size |
| 2133 | - z0 = graph.create_axis("z0", total_elements) | 2213 | + graph.create_axis("z0", total_elements) |
| 2134 | 2214 | ||
| 2135 | debug_str = ascir.utils.debug_str(graph) | 2215 | debug_str = ascir.utils.debug_str(graph) |
| 2136 | assert debug_str | 2216 | assert debug_str |
| @@ -2145,7 +2225,7 @@ class TestSizeExprArithmetic(): | |||
| 2145 | 2225 | ||
| 2146 | # Split size = total / num_splits | 2226 | # Split size = total / num_splits |
| 2147 | split_size = total_size / num_splits | 2227 | split_size = total_size / num_splits |
| 2148 | - z0 = graph.create_axis("z0", split_size) | 2228 | + graph.create_axis("z0", split_size) |
| 2149 | 2229 | ||
| 2150 | debug_str = ascir.utils.debug_str(graph) | 2230 | debug_str = ascir.utils.debug_str(graph) |
| 2151 | assert debug_str | 2231 | assert debug_str |
| @@ -2161,12 +2241,11 @@ class TestSizeExprArithmetic(): | |||
| 2161 | 2241 | ||
| 2162 | # Total size = size1 + size2 + constant | 2242 | # Total size = size1 + size2 + constant |
| 2163 | total_size = size1 + size2 + constant | 2243 | total_size = size1 + size2 + constant |
| 2164 | - z0 = graph.create_axis("z0", total_size) | 2244 | + graph.create_axis("z0", total_size) |
| 2165 | 2245 | ||
| 2166 | debug_str = ascir.utils.debug_str(graph) | 2246 | debug_str = ascir.utils.debug_str(graph) |
| 2167 | assert debug_str | 2247 | assert debug_str |
| 2168 | 2248 | ||
| 2169 | - | ||
| 2170 | 2249 | ||
| 2171 | def test_subtraction_basic(): | 2250 | def test_subtraction_basic(): |
| 2172 | """Test basic subtraction between SizeExpr""" | 2251 | """Test basic subtraction between SizeExpr""" |
| @@ -2213,7 +2292,7 @@ class TestSizeExprArithmetic(): | |||
| 2213 | assert result == 7 | 2292 | assert result == 7 |
| 2214 | 2293 | ||
| 2215 | 2294 | ||
| 2216 | -class TestSizeExprEdgeCases(): | 2295 | +class TestSizeExprEdgeCases: |
| 2217 | """Test SizeExpr edge cases and boundary conditions""" | 2296 | """Test SizeExpr edge cases and boundary conditions""" |
| 2218 | 2297 | ||
| 2219 | 2298 | ||
| @@ -2277,7 +2356,7 @@ class TestSizeExprEdgeCases(): | |||
| 2277 | assert min_val == 0 | 2356 | assert min_val == 0 |
| 2278 | 2357 | ||
| 2279 | 2358 | ||
| 2280 | -class TestSizeExprInRealScenarios(): | 2359 | +class TestSizeExprInRealScenarios: |
| 2281 | """Test SizeExpr in real-world scenarios""" | 2360 | """Test SizeExpr in real-world scenarios""" |
| 2282 | 2361 | ||
| 2283 | 2362 | ||
| @@ -2292,7 +2371,7 @@ class TestSizeExprInRealScenarios(): | |||
| 2292 | # Clamp tile size: at least min_tile, at most max_tile | 2371 | # Clamp tile size: at least min_tile, at most max_tile |
| 2293 | clamped_size = Min(Max(requested_size, min_tile), max_tile) | 2372 | clamped_size = Min(Max(requested_size, min_tile), max_tile) |
| 2294 | 2373 | ||
| 2295 | - z0 = graph.create_axis("z0", clamped_size) | 2374 | + graph.create_axis("z0", clamped_size) |
| 2296 | 2375 | ||
| 2297 | debug_str = ascir.utils.debug_str(graph) | 2376 | debug_str = ascir.utils.debug_str(graph) |
| 2298 | assert debug_str | 2377 | assert debug_str |
| @@ -2311,13 +2390,13 @@ class TestSizeExprInRealScenarios(): | |||
| 2311 | # offset = n*C*H*W + c*H*W + h*W + w | 2390 | # offset = n*C*H*W + c*H*W + h*W + w |
| 2312 | offset = n * c * h * w + c * h * w + h * w + w | 2391 | offset = n * c * h * w + c * h * w + h * w + w |
| 2313 | 2392 | ||
| 2314 | - z0 = graph.create_axis("z0", offset) | 2393 | + graph.create_axis("z0", offset) |
| 2315 | 2394 | ||
| 2316 | debug_str = ascir.utils.debug_str(graph) | 2395 | debug_str = ascir.utils.debug_str(graph) |
| 2317 | assert debug_str | 2396 | assert debug_str |
| 2318 | 2397 | ||
| 2319 | 2398 | ||
| 2320 | -class TestSizeExprOperatorCombination(): | 2399 | +class TestSizeExprOperatorCombination: |
| 2321 | """Test SizeExpr operator combinations""" | 2400 | """Test SizeExpr operator combinations""" |
| 2322 | 2401 | ||
| 2323 | 2402 | ||
| @@ -2333,8 +2412,8 @@ class TestSizeExprOperatorCombination(): | |||
| 2333 | remainder = total_size % block_size | 2412 | remainder = total_size % block_size |
| 2334 | 2413 | ||
| 2335 | # Create axes for both | 2414 | # Create axes for both |
| 2336 | - z_blocks = graph.create_axis("z_blocks", num_blocks) | 2415 | + graph.create_axis("z_blocks", num_blocks) |
| 2337 | - z_remain = graph.create_axis("z_remain", remainder) | 2416 | + graph.create_axis("z_remain", remainder) |
| 2338 | 2417 | ||
| 2339 | debug_str = ascir.utils.debug_str(graph) | 2418 | debug_str = ascir.utils.debug_str(graph) |
| 2340 | assert debug_str | 2419 | assert debug_str |
| @@ -2352,7 +2431,7 @@ class TestSizeExprOperatorCombination(): | |||
| 2352 | # Clamp value between min and max | 2431 | # Clamp value between min and max |
| 2353 | clamped = Min(Max(value, min_val), max_val) | 2432 | clamped = Min(Max(value, min_val), max_val) |
| 2354 | 2433 | ||
| 2355 | - z0 = graph.create_axis("z0", clamped) | 2434 | + graph.create_axis("z0", clamped) |
| 2356 | 2435 | ||
| 2357 | debug_str = ascir.utils.debug_str(graph) | 2436 | debug_str = ascir.utils.debug_str(graph) |
| 2358 | assert debug_str | 2437 | assert debug_str |
| @@ -2369,7 +2448,7 @@ class TestSizeExprOperatorCombination(): | |||
| 2369 | # For concat, output size in non-concat dim is max of inputs | 2448 | # For concat, output size in non-concat dim is max of inputs |
| 2370 | max_dim_size = Max(Max(size1, size2), size3) | 2449 | max_dim_size = Max(Max(size1, size2), size3) |
| 2371 | 2450 | ||
| 2372 | - z0 = graph.create_axis("z0", max_dim_size) | 2451 | + graph.create_axis("z0", max_dim_size) |
| 2373 | 2452 | ||
| 2374 | debug_str = ascir.utils.debug_str(graph) | 2453 | debug_str = ascir.utils.debug_str(graph) |
| 2375 | assert debug_str | 2454 | assert debug_str |
| @@ -2386,13 +2465,13 @@ class TestSizeExprOperatorCombination(): | |||
| 2386 | # Min helps check the smaller dimension | 2465 | # Min helps check the smaller dimension |
| 2387 | min_size = Min(size1, size2) | 2466 | min_size = Min(size1, size2) |
| 2388 | 2467 | ||
| 2389 | - z0 = graph.create_axis("z0", min_size) | 2468 | + graph.create_axis("z0", min_size) |
| 2390 | 2469 | ||
| 2391 | debug_str = ascir.utils.debug_str(graph) | 2470 | debug_str = ascir.utils.debug_str(graph) |
| 2392 | assert debug_str | 2471 | assert debug_str |
| 2393 | 2472 | ||
| 2394 | 2473 | ||
| 2395 | -class TestSizeExprErrorScenarios(): | 2474 | +class TestSizeExprErrorScenarios: |
| 2396 | """Test SizeExpr error handling and edge cases""" | 2475 | """Test SizeExpr error handling and edge cases""" |
| 2397 | 2476 | ||
| 2398 | 2477 | ||
| @@ -2402,9 +2481,9 @@ class TestSizeExprErrorScenarios(): | |||
| 2402 | graph.create_size("size1") | 2481 | graph.create_size("size1") |
| 2403 | # Max with no arguments should raise TypeError | 2482 | # Max with no arguments should raise TypeError |
| 2404 | try: | 2483 | try: |
| 2405 | - result = Max() | 2484 | + Max() |
| 2406 | assert False, "Expected TypeError for Max() with no arguments" | 2485 | assert False, "Expected TypeError for Max() with no arguments" |
| 2407 | - except (TypeError, AttributeError) as e: | 2486 | + except (TypeError, AttributeError): |
| 2408 | # Expected - invalid number of arguments | 2487 | # Expected - invalid number of arguments |
| 2409 | pass | 2488 | pass |
| 2410 | 2489 | ||
| @@ -2415,7 +2494,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2415 | size1 = graph.create_size("size1") | 2494 | size1 = graph.create_size("size1") |
| 2416 | # Max with single argument should raise TypeError | 2495 | # Max with single argument should raise TypeError |
| 2417 | try: | 2496 | try: |
| 2418 | - result = Max(size1) | 2497 | + Max(size1) |
| 2419 | assert False, "Expected TypeError for Max() with single argument" | 2498 | assert False, "Expected TypeError for Max() with single argument" |
| 2420 | except TypeError: | 2499 | except TypeError: |
| 2421 | # Expected - invalid number of arguments | 2500 | # Expected - invalid number of arguments |
| @@ -2430,7 +2509,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2430 | size3 = graph.create_size("size3") | 2509 | size3 = graph.create_size("size3") |
| 2431 | # Max with three arguments should raise TypeError | 2510 | # Max with three arguments should raise TypeError |
| 2432 | try: | 2511 | try: |
| 2433 | - result = Max(size1, size2, size3) | 2512 | + Max(size1, size2, size3) |
| 2434 | assert False, "Expected TypeError for Max() with three arguments" | 2513 | assert False, "Expected TypeError for Max() with three arguments" |
| 2435 | except TypeError: | 2514 | except TypeError: |
| 2436 | # Expected - invalid number of arguments | 2515 | # Expected - invalid number of arguments |
| @@ -2443,14 +2522,14 @@ class TestSizeExprErrorScenarios(): | |||
| 2443 | size1 = graph.create_size("size1") | 2522 | size1 = graph.create_size("size1") |
| 2444 | # Max with string argument | 2523 | # Max with string argument |
| 2445 | try: | 2524 | try: |
| 2446 | - result = Max(size1, "invalid") | 2525 | + Max(size1, "invalid") |
| 2447 | # If it doesn't raise, at least verify it handles gracefully | 2526 | # If it doesn't raise, at least verify it handles gracefully |
| 2448 | except (TypeError, AttributeError, SystemError): | 2527 | except (TypeError, AttributeError, SystemError): |
| 2449 | # Expected - invalid type | 2528 | # Expected - invalid type |
| 2450 | pass | 2529 | pass |
| 2451 | # Max with None argument | 2530 | # Max with None argument |
| 2452 | try: | 2531 | try: |
| 2453 | - result = Max(size1, None) | 2532 | + Max(size1, None) |
| 2454 | # If it doesn't raise, at least verify it handles gracefully | 2533 | # If it doesn't raise, at least verify it handles gracefully |
| 2455 | except (TypeError, AttributeError, SystemError): | 2534 | except (TypeError, AttributeError, SystemError): |
| 2456 | # Expected - invalid type | 2535 | # Expected - invalid type |
| @@ -2463,7 +2542,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2463 | graph.create_size("size1") | 2542 | graph.create_size("size1") |
| 2464 | # Min with no arguments should raise TypeError | 2543 | # Min with no arguments should raise TypeError |
| 2465 | try: | 2544 | try: |
| 2466 | - result = Min() | 2545 | + Min() |
| 2467 | assert False, "Expected TypeError for Min() with no arguments" | 2546 | assert False, "Expected TypeError for Min() with no arguments" |
| 2468 | except (TypeError, AttributeError): | 2547 | except (TypeError, AttributeError): |
| 2469 | # Expected - invalid number of arguments | 2548 | # Expected - invalid number of arguments |
| @@ -2476,7 +2555,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2476 | size1 = graph.create_size("size1") | 2555 | size1 = graph.create_size("size1") |
| 2477 | # Min with single argument should raise TypeError | 2556 | # Min with single argument should raise TypeError |
| 2478 | try: | 2557 | try: |
| 2479 | - result = Min(size1) | 2558 | + Min(size1) |
| 2480 | assert False, "Expected TypeError for Min() with single argument" | 2559 | assert False, "Expected TypeError for Min() with single argument" |
| 2481 | except TypeError: | 2560 | except TypeError: |
| 2482 | # Expected - invalid number of arguments | 2561 | # Expected - invalid number of arguments |
| @@ -2489,14 +2568,14 @@ class TestSizeExprErrorScenarios(): | |||
| 2489 | size1 = graph.create_size("size1") | 2568 | size1 = graph.create_size("size1") |
| 2490 | # Min with integer argument | 2569 | # Min with integer argument |
| 2491 | try: | 2570 | try: |
| 2492 | - result = Min(size1, 42) | 2571 | + Min(size1, 42) |
| 2493 | # If it doesn't raise, at least verify it handles gracefully | 2572 | # If it doesn't raise, at least verify it handles gracefully |
| 2494 | except (TypeError, AttributeError, SystemError): | 2573 | except (TypeError, AttributeError, SystemError): |
| 2495 | # Expected - invalid type | 2574 | # Expected - invalid type |
| 2496 | pass | 2575 | pass |
| 2497 | # Min with dict argument | 2576 | # Min with dict argument |
| 2498 | try: | 2577 | try: |
| 2499 | - result = Min(size1, {"key": "value"}) | 2578 | + Min(size1, {"key": "value"}) |
| 2500 | # If it doesn't raise, at least verify it handles gracefully | 2579 | # If it doesn't raise, at least verify it handles gracefully |
| 2501 | except (TypeError, AttributeError, SystemError): | 2580 | except (TypeError, AttributeError, SystemError): |
| 2502 | # Expected - invalid type | 2581 | # Expected - invalid type |
| @@ -2509,7 +2588,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2509 | graph.create_size("size1") | 2588 | graph.create_size("size1") |
| 2510 | # Mod with no arguments should raise TypeError | 2589 | # Mod with no arguments should raise TypeError |
| 2511 | try: | 2590 | try: |
| 2512 | - result = Mod() | 2591 | + Mod() |
| 2513 | assert False, "Expected TypeError for Mod() with no arguments" | 2592 | assert False, "Expected TypeError for Mod() with no arguments" |
| 2514 | except (TypeError, AttributeError): | 2593 | except (TypeError, AttributeError): |
| 2515 | # Expected - invalid number of arguments | 2594 | # Expected - invalid number of arguments |
| @@ -2522,7 +2601,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2522 | size1 = graph.create_size("size1") | 2601 | size1 = graph.create_size("size1") |
| 2523 | # Mod with single argument should raise TypeError | 2602 | # Mod with single argument should raise TypeError |
| 2524 | try: | 2603 | try: |
| 2525 | - result = Mod(size1) | 2604 | + Mod(size1) |
| 2526 | assert False, "Expected TypeError for Mod() with single argument" | 2605 | assert False, "Expected TypeError for Mod() with single argument" |
| 2527 | except TypeError: | 2606 | except TypeError: |
| 2528 | # Expected - invalid number of arguments | 2607 | # Expected - invalid number of arguments |
| @@ -2535,14 +2614,14 @@ class TestSizeExprErrorScenarios(): | |||
| 2535 | size1 = graph.create_size("size1") | 2614 | size1 = graph.create_size("size1") |
| 2536 | # Mod with list argument | 2615 | # Mod with list argument |
| 2537 | try: | 2616 | try: |
| 2538 | - result = Mod(size1, [1, 2, 3]) | 2617 | + Mod(size1, [1, 2, 3]) |
| 2539 | # If it doesn't raise, at least verify it handles gracefully | 2618 | # If it doesn't raise, at least verify it handles gracefully |
| 2540 | except (TypeError, AttributeError, SystemError): | 2619 | except (TypeError, AttributeError, SystemError): |
| 2541 | # Expected - invalid type | 2620 | # Expected - invalid type |
| 2542 | pass | 2621 | pass |
| 2543 | # Mod with tuple argument | 2622 | # Mod with tuple argument |
| 2544 | try: | 2623 | try: |
| 2545 | - result = Mod(size1, (1, 2)) | 2624 | + Mod(size1, (1, 2)) |
| 2546 | # If it doesn't raise, at least verify it handles gracefully | 2625 | # If it doesn't raise, at least verify it handles gracefully |
| 2547 | except (TypeError, AttributeError, SystemError): | 2626 | except (TypeError, AttributeError, SystemError): |
| 2548 | # Expected - invalid type | 2627 | # Expected - invalid type |
| @@ -2555,7 +2634,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2555 | s1 = ascir.SizeExpr(50) | 2634 | s1 = ascir.SizeExpr(50) |
| 2556 | # This tests the operator in reverse - string formatting with SizeExpr | 2635 | # This tests the operator in reverse - string formatting with SizeExpr |
| 2557 | try: | 2636 | try: |
| 2558 | - result = "invalid" % s1 | 2637 | + "invalid" % s1 |
| 2559 | # String % with SizeExpr - might work differently | 2638 | # String % with SizeExpr - might work differently |
| 2560 | except (TypeError, AttributeError): | 2639 | except (TypeError, AttributeError): |
| 2561 | # Expected - string formatting doesn't support SizeExpr | 2640 | # Expected - string formatting doesn't support SizeExpr |
| @@ -2566,7 +2645,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2566 | """Test FloorDiv with negative value edge case""" | 2645 | """Test FloorDiv with negative value edge case""" |
| 2567 | s0 = ascir.SizeExpr(100) | 2646 | s0 = ascir.SizeExpr(100) |
| 2568 | # Negative divisor - verify it handles without crashing | 2647 | # Negative divisor - verify it handles without crashing |
| 2569 | - result = s0 // -5 | 2648 | + s0 // -5 |
| 2570 | # Just verify it doesn't crash | 2649 | # Just verify it doesn't crash |
| 2571 | 2650 | ||
| 2572 | 2651 | ||
| @@ -2574,7 +2653,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2574 | """Test Max with None as left argument""" | 2653 | """Test Max with None as left argument""" |
| 2575 | # None is not a valid SizeExpr - should raise SystemError | 2654 | # None is not a valid SizeExpr - should raise SystemError |
| 2576 | try: | 2655 | try: |
| 2577 | - result = Max(None, ascir.SizeExpr(10)) | 2656 | + Max(None, ascir.SizeExpr(10)) |
| 2578 | except (SystemError, TypeError): | 2657 | except (SystemError, TypeError): |
| 2579 | # Expected - None is not a valid SizeExpr | 2658 | # Expected - None is not a valid SizeExpr |
| 2580 | pass | 2659 | pass |
| @@ -2584,7 +2663,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2584 | """Test Max with None as right argument""" | 2663 | """Test Max with None as right argument""" |
| 2585 | # None is not a valid SizeExpr - should raise SystemError | 2664 | # None is not a valid SizeExpr - should raise SystemError |
| 2586 | try: | 2665 | try: |
| 2587 | - result = Max(ascir.SizeExpr(10), None) | 2666 | + Max(ascir.SizeExpr(10), None) |
| 2588 | except (SystemError, TypeError): | 2667 | except (SystemError, TypeError): |
| 2589 | # Expected - None is not a valid SizeExpr | 2668 | # Expected - None is not a valid SizeExpr |
| 2590 | pass | 2669 | pass |
| @@ -2594,7 +2673,7 @@ class TestSizeExprErrorScenarios(): | |||
| 2594 | """Test Min with None as both arguments""" | 2673 | """Test Min with None as both arguments""" |
| 2595 | # None is not a valid SizeExpr - should raise SystemError | 2674 | # None is not a valid SizeExpr - should raise SystemError |
| 2596 | try: | 2675 | try: |
| 2597 | - result = Min(None, None) | 2676 | + Min(None, None) |
| 2598 | except (SystemError, TypeError): | 2677 | except (SystemError, TypeError): |
| 2599 | # Expected - None is not a valid SizeExpr | 2678 | # Expected - None is not a valid SizeExpr |
| 2600 | pass | 2679 | pass |
| @@ -2641,3 +2720,4 @@ class TestSizeExprErrorScenarios(): | |||
| 2641 | 2720 | ||
| 2642 | result = ascir.utils.set_platform("2201", 1, 1024) | 2721 | result = ascir.utils.set_platform("2201", 1, 1024) |
| 2643 | assert result is None, "set_platform should return None for valid input" | 2722 | assert result is None, "set_platform should return None for valid input" |
| 2723 | + ascir.utils.set_platform("2201", 1, 245760) | ||
| @@ -73,6 +73,15 @@ ascir::FusedScheduledResult CreateScheduleResultWithSingleAscGraph( | |||
| 73 | fused_schedule_result.node_idx_to_scheduled_results.emplace_back(schedule_results); | 73 | fused_schedule_result.node_idx_to_scheduled_results.emplace_back(schedule_results); |
| 74 | return fused_schedule_result; | 74 | return fused_schedule_result; |
| 75 | } | 75 | } |
| 76 | + | ||
| 77 | +bool HasVariableName(const ModelInfo &model_info, const std::string &name) { | ||
| 78 | + for (const auto &item : model_info.variable_name_map) { | ||
| 79 | + if (item.second == name) { | ||
| 80 | + return true; | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + return false; | ||
| 84 | +} | ||
| 76 | } // namespace | 85 | } // namespace |
| 77 | 86 | ||
| 78 | namespace af { | 87 | namespace af { |
| @@ -667,6 +676,21 @@ TEST_F(TestGenModelInfo, ModelInfoParser) { | |||
| 667 | EXPECT_EQ(MakeJson(model_info_list, json_info), af::SUCCESS); | 676 | EXPECT_EQ(MakeJson(model_info_list, json_info), af::SUCCESS); |
| 668 | } | 677 | } |
| 669 | 678 | ||
| 679 | +TEST_F(TestGenModelInfo, RefreshCommonUbExprKeepsNonContainerVariables) { | ||
| 680 | + std::vector<af::AscGraph> graphs; | ||
| 681 | + TilingModelInfo model_info_list; | ||
| 682 | + af::AscGraph graph("graph"); | ||
| 683 | + ASSERT_EQ(af::ascir::cg::Build2DTransposeAscendGraph(graph, {1, 0}), af::SUCCESS); | ||
| 684 | + graphs.emplace_back(graph); | ||
| 685 | + const auto &tiling_data_name = graph.GetName() + "TilingData"; | ||
| 686 | + ASSERT_EQ(GenerateModelInfo(graphs, model_info_list, {{kTilingDataTypeName, tiling_data_name}}), af::SUCCESS); | ||
| 687 | + | ||
| 688 | + ASSERT_EQ(model_info_list.size(), 1U); | ||
| 689 | + EXPECT_TRUE(HasVariableName(model_info_list[0], "transpose_output_0")); | ||
| 690 | + EXPECT_TRUE(HasVariableName(model_info_list[0], "add_output_0")); | ||
| 691 | + EXPECT_NE(model_info_list[0].container_exprs.find("q0_size"), model_info_list[0].container_exprs.end()); | ||
| 692 | +} | ||
| 693 | + | ||
| 670 | TEST_F(TestGenModelInfo, ModelInfoParserForTranspose10ApiTiling) { | 694 | TEST_F(TestGenModelInfo, ModelInfoParserForTranspose10ApiTiling) { |
| 671 | std::string json_info; | 695 | std::string json_info; |
| 672 | std::vector<af::AscGraph> graphs; | 696 | std::vector<af::AscGraph> graphs; |
| @@ -10,8 +10,10 @@ | |||
| 10 | 10 | ||
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | + | ||
| 13 | 14 | ||
| 14 | 15 | ||
| 16 | + | ||
| 15 | 17 | ||
| 16 | using namespace att; | 18 | using namespace att; |
| 17 | 19 | ||
| @@ -270,8 +272,7 @@ TEST_F(TestAxesReorderSolverGen, GenSolverFuncImplAppliesRuntimeReorderOnceBefor | |||
| 270 | EXPECT_LT(swap_pos, solver_pos); | 272 | EXPECT_LT(swap_pos, solver_pos); |
| 271 | } | 273 | } |
| 272 | 274 | ||
| 273 | -TEST_F(TestAxesReorderSolverGen, TEST_GEN_SOLVER_case2) | 275 | +TEST_F(TestAxesReorderSolverGen, TEST_GEN_SOLVER_case2) { |
| 274 | -{ | ||
| 275 | Expr x0 = CreateExpr("x0"); | 276 | Expr x0 = CreateExpr("x0"); |
| 276 | Expr x1 = CreateExpr("block_dim"); | 277 | Expr x1 = CreateExpr("block_dim"); |
| 277 | std::vector<Expr> cut_cons; | 278 | std::vector<Expr> cut_cons; |
| @@ -906,6 +907,20 @@ TEST_F(TestAxesReorderSolverGen, GenGetUbSizeStaticFunc_UsesNamedExprForSemantic | |||
| 906 | EXPECT_NE(actual.find("ub_size = (32 * Ceiling((Rational(1,32) * tensor_size_0)))"), std::string::npos) << actual; | 907 | EXPECT_NE(actual.find("ub_size = (32 * Ceiling((Rational(1,32) * tensor_size_0)))"), std::string::npos) << actual; |
| 907 | } | 908 | } |
| 908 | 909 | ||
| 910 | +TEST_F(TestAxesReorderSolverGen, BuildNamedUbExprUsesCommonOriginExpr) { | ||
| 911 | + Expr tensor = CreateExpr("tensor_size"); | ||
| 912 | + Expr tensor_value = CreateExpr("s0") * CreateExpr("s1"); | ||
| 913 | + ascir::UbExprContext context; | ||
| 914 | + context.ub_expr = af::sym::Mul(CreateExpr(32), af::sym::Ceiling(af::sym::Div(tensor, CreateExpr(32)))); | ||
| 915 | + context.container_expr[tensor] = tensor_value; | ||
| 916 | + context.container_names[tensor] = "load0"; | ||
| 917 | + | ||
| 918 | + const auto actual = BuildNamedUbExpr(context, " "); | ||
| 919 | + | ||
| 920 | + EXPECT_NE(actual.first.find("auto tensor_size_0 = (s0 * s1);"), std::string::npos) << actual.first; | ||
| 921 | + EXPECT_NE(actual.second.find("tensor_size_0"), std::string::npos) << actual.second; | ||
| 922 | +} | ||
| 923 | + | ||
| 909 | TEST_F(TestAxesReorderSolverGen, GenGetUbSizeStaticFunc_NamesExpandedUbExpr) { | 924 | TEST_F(TestAxesReorderSolverGen, GenGetUbSizeStaticFunc_NamesExpandedUbExpr) { |
| 910 | AxesReorderSolverGen solver("case_test", "TilingData"); | 925 | AxesReorderSolverGen solver("case_test", "TilingData"); |
| 911 | Expr s2 = CreateExpr("S2"); | 926 | Expr s2 = CreateExpr("S2"); |
| @@ -0,0 +1,89 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +class PlatformContextTest : public testing::Test { | ||
| 17 | + protected: | ||
| 18 | + void TearDown() override { | ||
| 19 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 20 | + } | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +TEST_F(PlatformContextTest, TryGetInitializedPlatformInfoReturnsFalseAfterReset) { | ||
| 24 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 25 | + | ||
| 26 | + ge::PlatformInfo info; | ||
| 27 | + EXPECT_FALSE(ge::PlatformContext::GetInstance().TryGetInitializedPlatformInfo(info)); | ||
| 28 | + EXPECT_EQ(info.ub_size, 0); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +TEST_F(PlatformContextTest, TryGetInitializedPlatformInfoReturnsInjectedInfo) { | ||
| 32 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 33 | + ge::PlatformInfo injected; | ||
| 34 | + injected.soc_ver = "mock_soc"; | ||
| 35 | + injected.aiv_num = 20; | ||
| 36 | + injected.ub_size = 262144; | ||
| 37 | + ge::PlatformContext::GetInstance().SetPlatformInfo(injected); | ||
| 38 | + | ||
| 39 | + ge::PlatformInfo actual; | ||
| 40 | + EXPECT_TRUE(ge::PlatformContext::GetInstance().TryGetInitializedPlatformInfo(actual)); | ||
| 41 | + EXPECT_EQ(actual.soc_ver, "mock_soc"); | ||
| 42 | + EXPECT_EQ(actual.aiv_num, 20); | ||
| 43 | + EXPECT_EQ(actual.ub_size, 262144); | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +TEST_F(PlatformContextTest, SetPlatformInfoWithEmptySocVerStoresUbSizeOverride) { | ||
| 47 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 48 | + ge::PlatformInfo injected; | ||
| 49 | + injected.ub_size = 262144; | ||
| 50 | + ge::PlatformContext::GetInstance().SetPlatformInfo(injected); | ||
| 51 | + | ||
| 52 | + ge::PlatformInfo actual; | ||
| 53 | + EXPECT_FALSE(ge::PlatformContext::GetInstance().TryGetInitializedPlatformInfo(actual)); | ||
| 54 | + | ||
| 55 | + int64_t ub_size = 0; | ||
| 56 | + EXPECT_TRUE(ge::PlatformContext::GetInstance().TryGetUbSizeOverride(ub_size)); | ||
| 57 | + EXPECT_EQ(ub_size, 262144); | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +TEST_F(PlatformContextTest, SetUbSizeOverrideDoesNotInitializePlatformInfo) { | ||
| 61 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 62 | + ge::PlatformContext::GetInstance().SetUbSizeOverride(2048); | ||
| 63 | + | ||
| 64 | + ge::PlatformInfo actual; | ||
| 65 | + int64_t ub_size = 0; | ||
| 66 | + EXPECT_FALSE(ge::PlatformContext::GetInstance().TryGetInitializedPlatformInfo(actual)); | ||
| 67 | + EXPECT_TRUE(ge::PlatformContext::GetInstance().TryGetUbSizeOverride(ub_size)); | ||
| 68 | + EXPECT_EQ(ub_size, 2048); | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +TEST_F(PlatformContextTest, ResetClearsUbSizeOverride) { | ||
| 72 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 73 | + ge::PlatformContext::GetInstance().SetUbSizeOverride(262144); | ||
| 74 | + ge::PlatformContext::GetInstance().Reset(); | ||
| 75 | + | ||
| 76 | + int64_t ub_size = 0; | ||
| 77 | + EXPECT_FALSE(ge::PlatformContext::GetInstance().TryGetUbSizeOverride(ub_size)); | ||
| 78 | + EXPECT_EQ(ub_size, 0); | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +TEST_F(PlatformContextTest, GetPlatformInfoInitializesUbSizeFromRuntime) { | ||
| 82 | + ge::RuntimeStub::Reset(); | ||
| 83 | + | ||
| 84 | + ge::PlatformInfo actual; | ||
| 85 | + EXPECT_EQ(ge::PlatformContext::GetInstance().GetPlatformInfo(actual), af::SUCCESS); | ||
| 86 | + EXPECT_EQ(actual.soc_ver, "2201"); | ||
| 87 | + EXPECT_EQ(actual.aiv_num, 48); | ||
| 88 | + EXPECT_EQ(actual.ub_size, 245760); | ||
| 89 | +} | ||
| @@ -0,0 +1,341 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 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 | ||
| 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. | ||
| 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. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | +namespace { | ||
| 19 | +struct UbQueueAttrConfig { | ||
| 20 | + ge::DataType dtype = ge::DT_FLOAT16; | ||
| 21 | + std::vector<af::Expression> repeats; | ||
| 22 | + std::vector<int64_t> vectorized_axis; | ||
| 23 | + std::vector<af::Expression> vectorized_strides; | ||
| 24 | + af::Position position = af::Position::kPositionVecIn; | ||
| 25 | + int64_t que_id = 0; | ||
| 26 | + int64_t buf_num = 1; | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +af::AscNodePtr BuildLoadNode(af::AscGraph &graph, const std::string &name) { | ||
| 30 | + const auto data_name = name + "_data"; | ||
| 31 | + af::ascir_op::Data data_op(data_name.c_str(), graph); | ||
| 32 | + af::ascir_op::Load load_op(name.c_str()); | ||
| 33 | + graph.AddNode(load_op); | ||
| 34 | + load_op.x = data_op.y; | ||
| 35 | + return graph.FindNode(name.c_str()); | ||
| 36 | +} | ||
| 37 | + | ||
| 38 | +void SetUbQueueOutputAttr(af::AscTensorAttr &attr, const UbQueueAttrConfig &config) { | ||
| 39 | + attr.dtype = config.dtype; | ||
| 40 | + attr.repeats = config.repeats; | ||
| 41 | + attr.vectorized_axis = config.vectorized_axis; | ||
| 42 | + attr.vectorized_strides = config.vectorized_strides; | ||
| 43 | + attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 44 | + attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 45 | + attr.mem.position = config.position; | ||
| 46 | + attr.que.id = config.que_id; | ||
| 47 | + attr.que.buf_num = config.buf_num; | ||
| 48 | +} | ||
| 49 | + | ||
| 50 | +af::Expression ReplaceContainers(const ascir::UbExprContext &context) { | ||
| 51 | + std::vector<std::pair<af::Expression, af::Expression>> replacements; | ||
| 52 | + for (const auto &container_expr : context.container_expr) { | ||
| 53 | + replacements.emplace_back(container_expr.first, container_expr.second); | ||
| 54 | + } | ||
| 55 | + return context.ub_expr.Replace(replacements).Simplify(); | ||
| 56 | +} | ||
| 57 | +} // namespace | ||
| 58 | + | ||
| 59 | +TEST(UbExprUtilsTest, BuildUbExprReturnsFalseForInvalidExpr) { | ||
| 60 | + ascir::UbExprContext context; | ||
| 61 | + | ||
| 62 | + const auto result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 63 | + | ||
| 64 | + EXPECT_FALSE(result.has_ub_expr); | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +TEST(UbExprUtilsTest, BuildUbExprReturnsOriginExpr) { | ||
| 68 | + ascir::UbExprContext context; | ||
| 69 | + context.ub_expr = af::sym::Add(af::Symbol("s0"), af::Symbol(32)); | ||
| 70 | + | ||
| 71 | + const auto result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 72 | + | ||
| 73 | + EXPECT_TRUE(result.has_ub_expr); | ||
| 74 | + EXPECT_EQ(result.ub_expr, context.ub_expr); | ||
| 75 | + EXPECT_EQ(result.origin_expr, context.ub_expr.Str().get()); | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +TEST(AscGraphUbExprBuilderTest, BuildReturnsFalseForGraphWithoutUbAllocation) { | ||
| 79 | + af::AscGraph graph("no_ub_alloc"); | ||
| 80 | + ascir::UbExprContext context; | ||
| 81 | + | ||
| 82 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 83 | + | ||
| 84 | + EXPECT_FALSE(ascir::UbExprUtils::BuildUbExpr(context).has_ub_expr); | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +TEST(AscGraphUbExprBuilderTest, BuildAggregatesQueueBufferAndTmpBuffer) { | ||
| 88 | + af::AscGraph graph("ub_alloc"); | ||
| 89 | + auto &axis = graph.CreateAxis("s0", af::Symbol("s0")); | ||
| 90 | + auto &tile_axis = graph.CreateAxis("t0", af::Axis::kAxisTypeTileInner, af::Symbol("t0"), {axis.id}, af::kIdNone); | ||
| 91 | + auto node = BuildLoadNode(graph, "load"); | ||
| 92 | + ASSERT_NE(node, nullptr); | ||
| 93 | + | ||
| 94 | + auto &output_attr = node->outputs[0].attr; | ||
| 95 | + output_attr.dtype = ge::DT_FLOAT16; | ||
| 96 | + output_attr.repeats = {tile_axis.size}; | ||
| 97 | + output_attr.vectorized_axis = {tile_axis.id}; | ||
| 98 | + output_attr.vectorized_strides = {af::Symbol(1)}; | ||
| 99 | + output_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 100 | + output_attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 101 | + output_attr.mem.position = af::Position::kPositionVecIn; | ||
| 102 | + output_attr.mem.reuse_id = 0; | ||
| 103 | + output_attr.que.id = 0; | ||
| 104 | + output_attr.que.buf_num = 2; | ||
| 105 | + | ||
| 106 | + af::TmpBuffer tmp_buffer; | ||
| 107 | + tmp_buffer.id = 1; | ||
| 108 | + tmp_buffer.buf_desc.size = af::Symbol(64); | ||
| 109 | + tmp_buffer.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 110 | + tmp_buffer.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 111 | + node->attr.tmp_buffers.emplace_back(tmp_buffer); | ||
| 112 | + | ||
| 113 | + ascir::UbExprContext context; | ||
| 114 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 115 | + const auto result = ascir::UbExprUtils::BuildUbExpr(context); | ||
| 116 | + | ||
| 117 | + EXPECT_TRUE(result.has_ub_expr); | ||
| 118 | + EXPECT_NE(result.origin_expr.find("q0_size"), std::string::npos); | ||
| 119 | + EXPECT_NE(result.origin_expr.find("b1_size"), std::string::npos); | ||
| 120 | + EXPECT_FALSE(context.container_expr.empty()); | ||
| 121 | + EXPECT_FALSE(context.ub_related_vars.empty()); | ||
| 122 | + EXPECT_EQ(context.graph_name, "ub_alloc"); | ||
| 123 | +} | ||
| 124 | + | ||
| 125 | +TEST(AscGraphUbExprBuilderTest, BuildAlignsTensorBytesAfterDtypeSize) { | ||
| 126 | + af::AscGraph graph("fp16_align"); | ||
| 127 | + auto &axis = graph.CreateAxis("s0", af::Symbol(33)); | ||
| 128 | + auto node = BuildLoadNode(graph, "load"); | ||
| 129 | + ASSERT_NE(node, nullptr); | ||
| 130 | + | ||
| 131 | + auto &output_attr = node->outputs[0].attr; | ||
| 132 | + SetUbQueueOutputAttr(output_attr, {ge::DT_FLOAT16, {axis.size}, {axis.id}, {af::Symbol(1)}}); | ||
| 133 | + | ||
| 134 | + ascir::UbExprContext context; | ||
| 135 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 136 | + ASSERT_EQ(context.container_expr.size(), 1U); | ||
| 137 | + auto min_expr = ReplaceContainers(context); | ||
| 138 | + | ||
| 139 | + int64_t min_ub_usage = 0; | ||
| 140 | + EXPECT_TRUE(min_expr.GetConstValue(min_ub_usage)) << min_expr.Str().get(); | ||
| 141 | + EXPECT_EQ(min_ub_usage, 96); | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | +TEST(AscGraphUbExprBuilderTest, BuildUsesRepeatStrideForVectorizedTensorSize) { | ||
| 145 | + af::AscGraph graph("repeat_stride_size"); | ||
| 146 | + auto &outer_axis = graph.CreateAxis("z0t", af::Symbol(100)); | ||
| 147 | + auto &inner_axis = graph.CreateAxis("z1", af::Symbol(8)); | ||
| 148 | + auto node = BuildLoadNode(graph, "load"); | ||
| 149 | + ASSERT_NE(node, nullptr); | ||
| 150 | + | ||
| 151 | + auto &output_attr = node->outputs[0].attr; | ||
| 152 | + SetUbQueueOutputAttr(output_attr, {ge::DT_INT32, | ||
| 153 | + {outer_axis.size, af::Symbol(16)}, | ||
| 154 | + {outer_axis.id, inner_axis.id}, | ||
| 155 | + {af::Symbol(16), af::Symbol(1)}, | ||
| 156 | + af::Position::kPositionVecOut, | ||
| 157 | + 1}); | ||
| 158 | + output_attr.axis = {outer_axis.id, inner_axis.id}; | ||
| 159 | + | ||
| 160 | + ascir::UbExprContext context; | ||
| 161 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 162 | + | ||
| 163 | + const auto q1_iter = context.container_expr.find(af::Symbol("q1_size")); | ||
| 164 | + ASSERT_NE(q1_iter, context.container_expr.end()); | ||
| 165 | + int64_t q1_size = 0; | ||
| 166 | + EXPECT_TRUE(q1_iter->second.GetConstValue(q1_size)) << q1_iter->second.Str().get(); | ||
| 167 | + EXPECT_EQ(q1_size, 6400); | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +TEST(AscGraphUbExprBuilderTest, BuildKeepsQueueContainerExprAsSingleBufferSlot) { | ||
| 171 | + af::AscGraph graph("queue_buf_num"); | ||
| 172 | + auto &axis = graph.CreateAxis("s0", af::Symbol(16)); | ||
| 173 | + auto node = BuildLoadNode(graph, "load"); | ||
| 174 | + ASSERT_NE(node, nullptr); | ||
| 175 | + | ||
| 176 | + auto &output_attr = node->outputs[0].attr; | ||
| 177 | + SetUbQueueOutputAttr(output_attr, | ||
| 178 | + {ge::DT_FLOAT16, {axis.size}, {axis.id}, {af::Symbol(1)}, af::Position::kPositionVecIn, 0, 2}); | ||
| 179 | + | ||
| 180 | + ascir::UbExprContext context; | ||
| 181 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 182 | + | ||
| 183 | + const auto q0_iter = context.container_expr.find(af::Symbol("q0_size")); | ||
| 184 | + ASSERT_NE(q0_iter, context.container_expr.end()); | ||
| 185 | + int64_t q0_size = 0; | ||
| 186 | + EXPECT_TRUE(q0_iter->second.GetConstValue(q0_size)) << q0_iter->second.Str().get(); | ||
| 187 | + EXPECT_EQ(q0_size, 32); | ||
| 188 | + | ||
| 189 | + int64_t ub_usage = 0; | ||
| 190 | + auto min_expr = ReplaceContainers(context); | ||
| 191 | + EXPECT_TRUE(min_expr.GetConstValue(ub_usage)) << min_expr.Str().get(); | ||
| 192 | + EXPECT_EQ(ub_usage, 64); | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +TEST(AscGraphUbExprBuilderTest, BuildKeepsUserDefinedContainerNames) { | ||
| 196 | + af::AscGraph graph("named_container"); | ||
| 197 | + auto &axis = graph.CreateAxis("s0", af::Symbol(16)); | ||
| 198 | + auto queue_node = BuildLoadNode(graph, "queue_load"); | ||
| 199 | + auto buffer_node = BuildLoadNode(graph, "buffer_load"); | ||
| 200 | + ASSERT_NE(queue_node, nullptr); | ||
| 201 | + ASSERT_NE(buffer_node, nullptr); | ||
| 202 | + | ||
| 203 | + auto &queue_attr = queue_node->outputs[0].attr; | ||
| 204 | + queue_attr.dtype = ge::DT_FLOAT16; | ||
| 205 | + queue_attr.repeats = {axis.size}; | ||
| 206 | + queue_attr.vectorized_axis = {axis.id}; | ||
| 207 | + queue_attr.vectorized_strides = {af::Symbol(1)}; | ||
| 208 | + queue_attr.mem.alloc_type = af::AllocType::kAllocTypeQueue; | ||
| 209 | + queue_attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 210 | + queue_attr.que.id = 0; | ||
| 211 | + queue_attr.que.name = "custom_queue_size"; | ||
| 212 | + queue_attr.que.buf_num = 2; | ||
| 213 | + | ||
| 214 | + auto &buffer_attr = buffer_node->outputs[0].attr; | ||
| 215 | + buffer_attr.dtype = ge::DT_FLOAT16; | ||
| 216 | + buffer_attr.repeats = {axis.size}; | ||
| 217 | + buffer_attr.vectorized_axis = {axis.id}; | ||
| 218 | + buffer_attr.vectorized_strides = {af::Symbol(1)}; | ||
| 219 | + buffer_attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 220 | + buffer_attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 221 | + buffer_attr.buf.id = 1; | ||
| 222 | + buffer_attr.buf.name = "custom_buffer_size"; | ||
| 223 | + | ||
| 224 | + ascir::UbExprContext context; | ||
| 225 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 226 | + | ||
| 227 | + EXPECT_NE(context.container_expr.find(af::Symbol("custom_queue_size")), context.container_expr.end()); | ||
| 228 | + EXPECT_NE(context.container_expr.find(af::Symbol("custom_buffer_size")), context.container_expr.end()); | ||
| 229 | + EXPECT_EQ(context.container_expr.find(af::Symbol("q0_size")), context.container_expr.end()); | ||
| 230 | + EXPECT_EQ(context.container_expr.find(af::Symbol("b1_size")), context.container_expr.end()); | ||
| 231 | +} | ||
| 232 | + | ||
| 233 | +TEST(AscGraphUbExprBuilderTest, BuildSumsCoexistBufferTensorsWithSameReuseId) { | ||
| 234 | + af::AscGraph graph("buffer_reuse_group"); | ||
| 235 | + auto &axis = graph.CreateAxis("s0", af::Symbol(16)); | ||
| 236 | + auto node0 = BuildLoadNode(graph, "load0"); | ||
| 237 | + auto node1 = BuildLoadNode(graph, "load1"); | ||
| 238 | + ASSERT_NE(node0, nullptr); | ||
| 239 | + ASSERT_NE(node1, nullptr); | ||
| 240 | + | ||
| 241 | + auto set_buffer_attr = [&axis](af::AscTensorAttr &attr) { | ||
| 242 | + attr.dtype = ge::DT_FLOAT16; | ||
| 243 | + attr.repeats = {axis.size}; | ||
| 244 | + attr.vectorized_axis = {axis.id}; | ||
| 245 | + attr.vectorized_strides = {af::Symbol(1)}; | ||
| 246 | + attr.mem.alloc_type = af::AllocType::kAllocTypeBuffer; | ||
| 247 | + attr.mem.hardware = af::MemHardware::kMemHardwareUB; | ||
| 248 | + attr.mem.position = af::Position::kPositionVecIn; | ||
| 249 | + attr.mem.reuse_id = 3; | ||
| 250 | + attr.buf.id = 2; | ||
| 251 | + }; | ||
| 252 | + set_buffer_attr(node0->outputs[0].attr); | ||
| 253 | + set_buffer_attr(node1->outputs[0].attr); | ||
| 254 | + | ||
| 255 | + ascir::UbExprContext context; | ||
| 256 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 257 | + | ||
| 258 | + const auto b2_iter = context.container_expr.find(af::Symbol("b2_size")); | ||
| 259 | + ASSERT_NE(b2_iter, context.container_expr.end()); | ||
| 260 | + int64_t b2_size = 0; | ||
| 261 | + EXPECT_TRUE(b2_iter->second.GetConstValue(b2_size)) << b2_iter->second.Str().get(); | ||
| 262 | + EXPECT_EQ(b2_size, 64); | ||
| 263 | +} | ||
| 264 | + | ||
| 265 | +TEST(AscGraphUbExprBuilderTest, BuildIncludesBuiltinTmpBuffer) { | ||
| 266 | + af::AscGraph graph("builtin_tmp_buffer"); | ||
| 267 | + auto &axis = graph.CreateAxis("s0", af::Symbol(1)); | ||
| 268 | + auto load_node = BuildLoadNode(graph, "load"); | ||
| 269 | + ASSERT_NE(load_node, nullptr); | ||
| 270 | + auto &load_attr = load_node->outputs[0].attr; | ||
| 271 | + load_attr.dtype = ge::DT_BOOL; | ||
| 272 | + load_attr.repeats = {axis.size}; | ||
| 273 | + load_attr.vectorized_axis = {axis.id}; | ||
| 274 | + load_attr.vectorized_strides = {af::Symbol(1)}; | ||
| 275 | + | ||
| 276 | + af::ascir_op::LogicalNot logical_not_op("logical_not"); | ||
| 277 | + graph.AddNode(logical_not_op); | ||
| 278 | + auto logical_not_node = graph.FindNode("logical_not"); | ||
| 279 | + ASSERT_NE(logical_not_node, nullptr); | ||
| 280 | + ASSERT_EQ(af::GraphUtils::AddEdge(load_node->GetOutDataAnchor(0), logical_not_node->GetInDataAnchor(0)), | ||
| 281 | + ge::GRAPH_SUCCESS); | ||
| 282 | + auto &logical_not_attr = logical_not_node->outputs[0].attr; | ||
| 283 | + logical_not_attr.dtype = ge::DT_BOOL; | ||
| 284 | + logical_not_attr.repeats = {axis.size}; | ||
| 285 | + logical_not_attr.vectorized_axis = {axis.id}; | ||
| 286 | + logical_not_attr.vectorized_strides = {af::Symbol(1)}; | ||
| 287 | + | ||
| 288 | + ascir::UbExprContext context; | ||
| 289 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 290 | + | ||
| 291 | + int64_t min_ub_usage = 0; | ||
| 292 | + EXPECT_TRUE(context.ub_expr.Simplify().GetConstValue(min_ub_usage)) << context.ub_expr.Str().get(); | ||
| 293 | + EXPECT_EQ(min_ub_usage, 32); | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +TEST(AscGraphUbExprBuilderTest, BuildSumsTmpBuffersWithSameIdInOneNode) { | ||
| 297 | + af::AscGraph graph("same_id_tmp_buffer"); | ||
| 298 | + af::Operator op("Compute", "Compute"); | ||
| 299 | + auto node = graph.AddNode(op); | ||
| 300 | + ASSERT_NE(node, nullptr); | ||
| 301 | + node->attr.tmp_buffers.emplace_back(af::TmpBuffer{{af::Symbol(4096), -1}, af::MemAttr(), 0}); | ||
| 302 | + node->attr.tmp_buffers.emplace_back(af::TmpBuffer{{af::Symbol(8192), -1}, af::MemAttr(), 0}); | ||
| 303 | + | ||
| 304 | + ascir::UbExprContext context; | ||
| 305 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 306 | + | ||
| 307 | + int64_t min_ub_usage = 0; | ||
| 308 | + auto min_expr = ReplaceContainers(context); | ||
| 309 | + EXPECT_TRUE(min_expr.GetConstValue(min_ub_usage)) << min_expr.Str().get(); | ||
| 310 | + EXPECT_EQ(min_ub_usage, 12288); | ||
| 311 | +} | ||
| 312 | + | ||
| 313 | +TEST(AscGraphUbExprBuilderTest, BuildIgnoresInvalidTmpBufferSize) { | ||
| 314 | + af::AscGraph graph("invalid_tmp_buffer_size"); | ||
| 315 | + af::Operator op("Compute", "Compute"); | ||
| 316 | + auto node = graph.AddNode(op); | ||
| 317 | + ASSERT_NE(node, nullptr); | ||
| 318 | + af::TmpBuffer tmp_buffer; | ||
| 319 | + tmp_buffer.id = 99; | ||
| 320 | + node->attr.tmp_buffers.emplace_back(tmp_buffer); | ||
| 321 | + | ||
| 322 | + ascir::UbExprContext context; | ||
| 323 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 324 | + | ||
| 325 | + EXPECT_EQ(context.container_expr.find(af::Symbol("b99_size")), context.container_expr.end()); | ||
| 326 | + EXPECT_EQ(ascir::UbExprUtils::BuildUbExpr(context).origin_expr.find("Max(,"), std::string::npos); | ||
| 327 | +} | ||
| 328 | + | ||
| 329 | +TEST(AscGraphUbExprBuilderTest, BuildIncludesReservedUbForGather) { | ||
| 330 | + af::AscGraph graph("reserved_ub"); | ||
| 331 | + af::Operator op("Gather", "Gather"); | ||
| 332 | + auto node = graph.AddNode(op); | ||
| 333 | + ASSERT_NE(node, nullptr); | ||
| 334 | + | ||
| 335 | + ascir::UbExprContext context; | ||
| 336 | + EXPECT_EQ(ascir::AscGraphUbExprBuilder().Build(graph, context), af::SUCCESS); | ||
| 337 | + | ||
| 338 | + int64_t min_ub_usage = 0; | ||
| 339 | + EXPECT_TRUE(context.ub_expr.Simplify().GetConstValue(min_ub_usage)) << context.ub_expr.Str().get(); | ||
| 340 | + EXPECT_EQ(min_ub_usage, 40960); | ||
| 341 | +} | ||
| @@ -54,6 +54,87 @@ class BufQueAllocatorUT : public ::testing::Test { | |||
| 54 | }; | 54 | }; |
| 55 | } // namespace optimize | 55 | } // namespace optimize |
| 56 | 56 | ||
| 57 | +static af::AscGraph MakeStaticLoadStoreGraph(const std::string &name, int64_t size, int64_t data_index = 0) { | ||
| 58 | + af::AscGraph graph(name.c_str()); | ||
| 59 | + const af::Expression s0 = graph.CreateSizeVar(size); | ||
| 60 | + auto z0 = graph.CreateAxis("z0", s0); | ||
| 61 | + | ||
| 62 | + af::ascir_op::Data data(("data" + std::to_string(data_index)).c_str(), graph); | ||
| 63 | + data.ir_attr.SetIndex(data_index); | ||
| 64 | + data.y.dtype = ge::DT_UINT8; | ||
| 65 | + | ||
| 66 | + af::ascir_op::Load load("load"); | ||
| 67 | + load.x = data.y; | ||
| 68 | + load.attr.api.compute_type = af::ComputeType::kComputeLoad; | ||
| 69 | + load.attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 70 | + load.y.dtype = ge::DT_UINT8; | ||
| 71 | + *load.y.axis = {z0.id}; | ||
| 72 | + *load.y.repeats = {s0}; | ||
| 73 | + *load.y.strides = {af::ops::One}; | ||
| 74 | + | ||
| 75 | + af::ascir_op::Store store("store"); | ||
| 76 | + store.x = load.y; | ||
| 77 | + store.attr.api.compute_type = af::ComputeType::kComputeStore; | ||
| 78 | + store.attr.api.unit = af::ComputeUnit::kUnitMTE2; | ||
| 79 | + store.y.dtype = ge::DT_UINT8; | ||
| 80 | + *store.y.axis = {z0.id}; | ||
| 81 | + *store.y.repeats = {s0}; | ||
| 82 | + *store.y.strides = {af::ops::One}; | ||
| 83 | + | ||
| 84 | + af::ascir_op::Output output(("output" + std::to_string(data_index)).c_str()); | ||
| 85 | + output.x = store.y; | ||
| 86 | + output.ir_attr.SetIndex(data_index); | ||
| 87 | + return graph; | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +static ascir::FusedScheduledResult MakeFusedScheduledResultWithGraphs(std::vector<af::AscGraph> &&impl_graphs) { | ||
| 91 | + ascir::FusedScheduledResult fused_result; | ||
| 92 | + fused_result.node_idx_to_scheduled_results.resize(1UL); | ||
| 93 | + auto &scheduled_result = fused_result.node_idx_to_scheduled_results[0].emplace_back(); | ||
| 94 | + auto &group = scheduled_result.schedule_groups.emplace_back(); | ||
| 95 | + group.impl_graphs = std::move(impl_graphs); | ||
| 96 | + return fused_result; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +TEST_F(BufQueAllocatorUT, PrepareImplGraphMemoryPlanDoesNotPopulateFusedIoNodes) { | ||
| 100 | + auto fused_result = MakeFusedScheduledResultWithGraphs({MakeStaticLoadStoreGraph("prepared", 16)}); | ||
| 101 | + | ||
| 102 | + BufQueAllocator allocator; | ||
| 103 | + ASSERT_EQ(allocator.PrepareImplGraphMemoryPlan(fused_result), af::SUCCESS); | ||
| 104 | + | ||
| 105 | + EXPECT_TRUE(fused_result.input_nodes.empty()); | ||
| 106 | + EXPECT_TRUE(fused_result.output_nodes.empty()); | ||
| 107 | + EXPECT_TRUE(fused_result.workspace_nodes.empty()); | ||
| 108 | + auto &impl_graph = fused_result.node_idx_to_scheduled_results[0][0].schedule_groups[0].impl_graphs[0]; | ||
| 109 | + auto load = impl_graph.FindNode("load"); | ||
| 110 | + ASSERT_NE(load, nullptr); | ||
| 111 | + EXPECT_EQ(load->outputs[0].attr.mem.hardware, af::MemHardware::kMemHardwareUB); | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +TEST_F(BufQueAllocatorUT, CollectFusedIoNodesOnlyUsesRetainedImplGraphs) { | ||
| 115 | + auto fused_result = MakeFusedScheduledResultWithGraphs( | ||
| 116 | + {MakeStaticLoadStoreGraph("dropped", 16, 0), MakeStaticLoadStoreGraph("kept", 16, 1)}); | ||
| 117 | + | ||
| 118 | + BufQueAllocator allocator; | ||
| 119 | + ASSERT_EQ(allocator.PrepareImplGraphMemoryPlan(fused_result), af::SUCCESS); | ||
| 120 | + auto &impl_graphs = fused_result.node_idx_to_scheduled_results[0][0].schedule_groups[0].impl_graphs; | ||
| 121 | + impl_graphs.erase(impl_graphs.begin()); | ||
| 122 | + ASSERT_EQ(allocator.CollectFusedIoNodes(fused_result), af::SUCCESS); | ||
| 123 | + | ||
| 124 | + ASSERT_EQ(fused_result.input_nodes.size(), 1UL); | ||
| 125 | + ASSERT_EQ(fused_result.output_nodes.size(), 1UL); | ||
| 126 | + EXPECT_EQ(fused_result.input_nodes[0]->GetName(), "data1"); | ||
| 127 | + EXPECT_EQ(fused_result.output_nodes[0]->GetName(), "output1"); | ||
| 128 | +} | ||
| 129 | + | ||
| 130 | +TEST_F(BufQueAllocatorUT, AllocBufQueKeepsOldOneShotBehavior) { | ||
| 131 | + auto fused_result = MakeFusedScheduledResultWithGraphs({MakeStaticLoadStoreGraph("one_shot", 16)}); | ||
| 132 | + | ||
| 133 | + ASSERT_EQ(BufQueAllocator().AllocBufQue(fused_result), af::SUCCESS); | ||
| 134 | + ASSERT_EQ(fused_result.input_nodes.size(), 1UL); | ||
| 135 | + ASSERT_EQ(fused_result.output_nodes.size(), 1UL); | ||
| 136 | +} | ||
| 137 | + | ||
| 57 | TEST_F(BufQueAllocatorUT, test_reuse_id_vecacc) { | 138 | TEST_F(BufQueAllocatorUT, test_reuse_id_vecacc) { |
| 58 | af::AscGraph graph("test_reuse_id_vecacc"); | 139 | af::AscGraph graph("test_reuse_id_vecacc"); |
| 59 | const af::Expression s0 = graph.CreateSizeVar("s0"); | 140 | const af::Expression s0 = graph.CreateSizeVar("s0"); |
🔵 Low Priority
在
FilterScheduledResult函数中(第 265-270 行),当某个 schedule_group 的所有 impl_graphs 全部被过滤掉后,函数立即return false,导致后续的 schedule_group(更高索引)不会被处理。虽然外层remove_if会整体移除该ScheduledResult,功能上正确,但state.total_dropped只会计数到当前处理过的 group 中被显式丢弃的模板数量,后续未处理的 group 中被隐式丢弃的模板不会被计数。最终在Filter::Filter()第 338 行日志中输出的total_dropped会低于实际丢弃的模板总数(低估)。而
FilterNodeScheduledResults第 291 行日志中使用的dropped = before - kept则能正确反映净减少数量。两者不一致会误导调试。建议:两种修复方向:1) 如果需要精确计数,可将早期返回改为先遍历完所有 group(仅标记结果为 false),确保所有 group 的丢弃都被计入
total_dropped;2) 如果接受近似计数,可将第 338 行日志中的total_dropped改为使用before - kept差值,或在注释中说明total_dropped仅计数显式丢弃。