Line data Source code
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 : #include "microcode_optimizer.h"
12 :
13 : #include <chrono>
14 : #include <sstream>
15 : #include <string>
16 :
17 : #include "ccu_log.h"
18 : #include "ccu_microcode_v1.h" // hcomm::CcuRep::CcuV2::ParseInstrV2, 供 opt_log 输出可读形式
19 :
20 : namespace hcomm {
21 : namespace CcuOpt {
22 :
23 17 : MicrocodeOptimizer::MicrocodeOptimizer() = default;
24 :
25 18 : OptimizerOptions MicrocodeOptimizer::DefaultOptions()
26 : {
27 : // 极简后端优化恒为 CkeOnly (只处理 CKE 写后读), 无其他档位, 运行时不可改.
28 18 : OptimizerOptions opts{};
29 18 : opts.schedLevel = SchedLevel::CkeOnly;
30 18 : return opts;
31 : }
32 :
33 17 : CcuRep::CcuInstrInfo MicrocodeOptimizer::Optimize(const CcuRep::CcuInstrInfo& input)
34 : {
35 17 : schedOpts_.level = opts_.schedLevel;
36 :
37 : using Clock = std::chrono::steady_clock;
38 34 : auto usSince = [](Clock::time_point startTime) -> uint64_t {
39 : return static_cast<uint64_t>(
40 34 : std::chrono::duration_cast<std::chrono::microseconds>(Clock::now() - startTime).count());
41 : };
42 :
43 17 : const auto totalStart = Clock::now();
44 :
45 17 : const auto pass1Start = Clock::now();
46 17 : InstructionScheduler sched(schedOpts_);
47 17 : CcuRep::CcuInstrInfo afterSched = sched.Schedule(input);
48 17 : stats_.sched = sched.Stats();
49 17 : stats_.pass1DurationUs = usSince(pass1Start);
50 17 : stats_.totalDurationUs = usSince(totalStart);
51 :
52 17 : HCCL_INFO(
53 : "[CcuMicrocodeOpt][timing] total=%lluus, pass1(sched)=%lluus",
54 : static_cast<unsigned long long>(stats_.totalDurationUs),
55 : static_cast<unsigned long long>(stats_.pass1DurationUs));
56 :
57 17 : DumpOptLog(input, afterSched);
58 17 : return afterSched;
59 17 : }
60 :
61 : namespace {
62 :
63 : // 打印输入序列 (用户视角的原始指令). 全局 id = startInstrId + local, 与硬件视角一致.
64 17 : void DumpOptLogInput(const CcuRep::CcuInstrInfo& input)
65 : {
66 17 : const uint16_t inStart = input.startInstrId;
67 771 : for (size_t i = 0; i < input.instrVec.size(); ++i) {
68 754 : HCCL_INFO(
69 : "[CcuMicrocodeOpt][optlog] input [%3zu] gid=%u: %s", i, static_cast<unsigned>(inStart + i),
70 : CcuRep::CcuV2::ParseInstrV2(input.instrVec.data() + i).c_str());
71 : }
72 17 : }
73 :
74 : // 打印输出序列 + 后→前映射. runlog 里报"指令 gid=X 挂了", 用户在此段直接搜 gid=X 即可
75 : // 定位到 src 行, src=-1 表示是新插入的 NOP.
76 17 : void DumpOptLogOutput(
77 : const CcuRep::CcuInstrInfo& input, const CcuRep::CcuInstrInfo& output,
78 : const std::vector<int32_t>& originIndex, bool mapConsistent)
79 : {
80 17 : const uint16_t inStart = input.startInstrId;
81 17 : const uint16_t outStart = output.startInstrId;
82 831 : for (size_t i = 0; i < output.instrVec.size(); ++i) {
83 814 : const char* srcTag = "NEW (inserted NOP)";
84 814 : std::string srcBuf;
85 814 : if (mapConsistent) {
86 814 : int32_t src = originIndex[i];
87 814 : if (src >= 0) {
88 754 : std::ostringstream oss;
89 754 : oss << "src[" << src << "] gid=" << (inStart + static_cast<uint32_t>(src));
90 754 : srcBuf = oss.str();
91 754 : srcTag = srcBuf.c_str();
92 754 : }
93 : } else {
94 0 : srcTag = "N/A (mapping omitted)";
95 : }
96 814 : HCCL_INFO(
97 : "[CcuMicrocodeOpt][optlog] output [%3zu] gid=%u <- %s : %s", i,
98 : static_cast<unsigned>(outStart + i), srcTag,
99 : CcuRep::CcuV2::ParseInstrV2(output.instrVec.data() + i).c_str());
100 814 : }
101 17 : }
102 :
103 : } // namespace
104 :
105 17 : void MicrocodeOptimizer::DumpOptLog(const CcuRep::CcuInstrInfo& input, const CcuRep::CcuInstrInfo& output) const
106 : {
107 17 : const auto& originIndex = stats_.sched.originIndex;
108 17 : const bool mapConsistent = originIndex.size() == output.instrVec.size();
109 17 : if (!mapConsistent) {
110 0 : HCCL_WARNING(
111 : "[CcuMicrocodeOpt][optlog] origin index size mismatch: "
112 : "originIndex=%zu, output=%zu; mapping will be omitted.",
113 : originIndex.size(), output.instrVec.size());
114 : }
115 :
116 17 : HCCL_INFO(
117 : "[CcuMicrocodeOpt][optlog] === begin "
118 : "(inputInstrCount=%u, outputInstrCount=%u, "
119 : "missionStart before=%u after=%u) ===",
120 : input.instrCount, output.instrCount, input.missionStartInstrId, output.missionStartInstrId);
121 :
122 17 : DumpOptLogInput(input);
123 17 : DumpOptLogOutput(input, output, originIndex, mapConsistent);
124 :
125 17 : HCCL_INFO("[CcuMicrocodeOpt][optlog] === end ===");
126 17 : }
127 :
128 : CcuRep::CcuInstrInfo
129 17 : MicrocodeOptimizer::Run(const CcuRep::CcuInstrInfo& input, uint16_t reserveXnId, uint16_t reserveCkeId)
130 : {
131 17 : OptimizerOptions opts = DefaultOptions(); // 恒 CkeOnly.
132 17 : HCCL_INFO(
133 : "[CcuMicrocodeOpt] active options: sched=CkeOnly, reserveXn=%u, reserveCke=%u",
134 : static_cast<unsigned>(reserveXnId), static_cast<unsigned>(reserveCkeId));
135 :
136 17 : MicrocodeOptimizer opt;
137 17 : opt.SetOptions(opts);
138 34 : return opt.Optimize(input);
139 17 : }
140 :
141 : } // namespace CcuOpt
142 : } // namespace hcomm
|