1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "compiler_logger.h"
17 #include "optimizer/ir/graph.h"
18 #include "optimizer/ir/basicblock.h"
19 #include "pass_manager_statistics.h"
20
21 #include <iomanip>
22
23 namespace panda::compiler {
PassManagerStatistics(Graph * graph)24 PassManagerStatistics::PassManagerStatistics(Graph *graph)
25 : graph_(graph),
26 pass_stat_list_(graph->GetAllocator()->Adapter()),
27 pass_stat_stack_(graph->GetAllocator()->Adapter()),
28 enable_ir_stat_(options.IsCompilerEnableIrStats())
29 {
30 }
31
PrintStatistics() const32 void PassManagerStatistics::PrintStatistics() const
33 {
34 // clang-format off
35 #ifndef __clang_analyzer__
36 auto& out = std::cerr;
37 static constexpr size_t BUF_SIZE = 64;
38 static constexpr auto OFFSET_STAT = 2;
39 static constexpr auto OFFSET_ID = 4;
40 static constexpr auto OFFSET_DEFAULT = 12;
41 static constexpr auto OFFSET_PASS_NAME = 34;
42 static constexpr auto OFFSET_TOTAL = 41;
43 char space_buf[BUF_SIZE];
44 std::fill(space_buf, space_buf + BUF_SIZE, ' ');
45 size_t index = 0;
46 out << std::dec
47 << std::setw(OFFSET_ID) << std::right << "ID" << " " << std::left
48 << std::setw(OFFSET_PASS_NAME) << "Pass Name" << ": " << std::right
49 << std::setw(OFFSET_DEFAULT) << "IR mem" << std::right
50 << std::setw(OFFSET_DEFAULT) << "Local mem" << std::right
51 << std::setw(OFFSET_DEFAULT) << "Time,us" << std::endl;
52 out << "-----------------------------------------------------------------------------\n";
53 size_t total_time = 0;
54 for (const auto& stat : pass_stat_list_) {
55 auto indent = stat.run_depth * OFFSET_STAT;
56 space_buf[indent] = 0;
57 out << std::setw(OFFSET_ID) << std::right << index << space_buf << " " << std::left <<
58 std::setw(OFFSET_PASS_NAME - indent) << stat.pass_name << ": " << std::right <<
59 std::setw(OFFSET_DEFAULT) << stat.mem_used_ir << std::setw(OFFSET_DEFAULT) << stat.mem_used_local <<
60 std::setw(OFFSET_DEFAULT) << stat.time_us << std::endl;
61 space_buf[indent] = ' ';
62 index++;
63 total_time += stat.time_us;
64 }
65 out << "-----------------------------------------------------------------------------\n";
66 out << std::setw(OFFSET_TOTAL) << "TOTAL: "
67 << std::right << std::setw(OFFSET_DEFAULT) << graph_->GetAllocator()->GetAllocatedSize()
68 << std::setw(OFFSET_DEFAULT) << graph_->GetLocalAllocator()->GetAllocatedSize()
69 << std::setw(OFFSET_DEFAULT) << total_time << std::endl;
70 out << "PBC instruction number : " << pbc_inst_num_ << std::endl;
71 #endif
72 // clang-format on
73 }
74
ProcessBeforeRun(const Pass & pass)75 void PassManagerStatistics::ProcessBeforeRun(const Pass &pass)
76 {
77 size_t allocated_size = graph_->GetAllocator()->GetAllocatedSize();
78 constexpr auto OFFSET_NORMAL = 2;
79 std::string indent(pass_call_depth_ * OFFSET_NORMAL, '.');
80 COMPILER_LOG(DEBUG, PM) << "Run pass: " << indent << pass.GetPassName();
81
82 if (!pass_stat_stack_.empty()) {
83 auto top_pass = pass_stat_stack_.top();
84 ASSERT(allocated_size >= last_allocated_ir_);
85 ASSERT(top_pass != nullptr);
86 top_pass->mem_used_ir += allocated_size - last_allocated_ir_;
87 if (!options.IsCompilerResetLocalAllocator()) {
88 ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= last_allocated_local_);
89 top_pass->mem_used_local += graph_->GetLocalAllocator()->GetAllocatedSize() - last_allocated_local_;
90 }
91 top_pass->time_us +=
92 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - last_timestamp_)
93 .count();
94 }
95
96 pass_stat_list_.push_back({pass_call_depth_, pass.GetPassName(), {0, 0}, {0, 0}, 0, 0, 0});
97 if (enable_ir_stat_) {
98 for (auto block : graph_->GetVectorBlocks()) {
99 if (block == nullptr) {
100 continue;
101 }
102 pass_stat_list_.back().before_pass.num_of_basicblocks++;
103 for ([[maybe_unused]] auto inst : block->Insts()) {
104 pass_stat_list_.back().before_pass.num_of_instructions++;
105 }
106 }
107 }
108
109 pass_stat_stack_.push(&pass_stat_list_.back());
110 // Call `GetAllocator()->GetAllocatedSize()` again to exclude allocations caused by PassManagerStatistics itself:
111 last_allocated_ir_ = graph_->GetAllocator()->GetAllocatedSize();
112 last_allocated_local_ = graph_->GetLocalAllocator()->GetAllocatedSize();
113 last_timestamp_ = std::chrono::steady_clock::now();
114
115 pass_call_depth_++;
116 }
117
ProcessAfterRun(size_t local_mem_used)118 void PassManagerStatistics::ProcessAfterRun(size_t local_mem_used)
119 {
120 auto top_pass = pass_stat_stack_.top();
121 ASSERT(graph_->GetAllocator()->GetAllocatedSize() >= last_allocated_ir_);
122 top_pass->mem_used_ir += graph_->GetAllocator()->GetAllocatedSize() - last_allocated_ir_;
123 if (options.IsCompilerResetLocalAllocator()) {
124 top_pass->mem_used_local = local_mem_used;
125 } else {
126 ASSERT(graph_->GetLocalAllocator()->GetAllocatedSize() >= last_allocated_local_);
127 top_pass->mem_used_local += graph_->GetLocalAllocator()->GetAllocatedSize() - last_allocated_local_;
128 }
129 top_pass->time_us +=
130 std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - last_timestamp_)
131 .count();
132
133 if (enable_ir_stat_) {
134 for (auto block : graph_->GetVectorBlocks()) {
135 if (block == nullptr) {
136 continue;
137 }
138 top_pass->after_pass.num_of_basicblocks++;
139 for ([[maybe_unused]] auto inst : block->Insts()) {
140 top_pass->after_pass.num_of_instructions++;
141 }
142 }
143 }
144
145 pass_stat_stack_.pop();
146 last_allocated_ir_ = graph_->GetAllocator()->GetAllocatedSize();
147 last_allocated_local_ = graph_->GetLocalAllocator()->GetAllocatedSize();
148 last_timestamp_ = std::chrono::steady_clock::now();
149
150 pass_call_depth_--;
151 pass_run_index_++;
152 }
153
DumpStatisticsCsv(char sep) const154 void PassManagerStatistics::DumpStatisticsCsv(char sep) const
155 {
156 ASSERT(options.WasSetCompilerDumpStatsCsv());
157 static std::ofstream csv(options.GetCompilerDumpStatsCsv(), std::ofstream::trunc);
158 auto m_name = graph_->GetRuntime()->GetMethodFullName(graph_->GetMethod(), true);
159 for (const auto &i : pass_stat_list_) {
160 csv << "\"" << m_name << "\"" << sep;
161 csv << i.pass_name << sep;
162 csv << i.mem_used_ir << sep;
163 csv << i.mem_used_local << sep;
164 csv << i.time_us << sep;
165 if (enable_ir_stat_) {
166 csv << i.before_pass.num_of_basicblocks << sep;
167 csv << i.after_pass.num_of_basicblocks << sep;
168 csv << i.before_pass.num_of_instructions << sep;
169 csv << i.after_pass.num_of_instructions << sep;
170 }
171 csv << GetPbcInstNum();
172 csv << '\n';
173 }
174 // Flush stream because it is declared `static`:
175 csv << std::flush;
176 }
177 } // namespace panda::compiler
178