1 /**
2 * Copyright 2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "include/common/profiler.h"
18 #include <functional>
19 #include <iomanip>
20 #include <utility>
21 #include "utils/file_utils.h"
22 #include "include/common/utils/utils.h"
23 #include "include/common/debug/common.h"
24 #ifdef ENABLE_DEBUGGER
25 #include "include/backend/debug/profiler/profiling.h"
26 #include "common/debug/profiler/profiling_framework_data.h"
27 #endif
28
29 namespace mindspore {
30 namespace runtime {
31 static const int kPrecisionDigits = 2;
32 static const double kNsToUs = 1000;
33
34 // The string of json file.
35 static const char kJsonName[] = "name";
36 static const char kJsonPh[] = "ph";
37 static const char kJsonPid[] = "pid";
38 static const char kJsonTid[] = "tid";
39 static const char kJsonTs[] = "ts";
40 static const char kJsonDur[] = "dur";
41 static const char kJsonPhX[] = "X";
42 static const char kJsonArgs[] = "args";
43 static const char kJsonFlowId[] = "flow_id";
44 static const char kJsonPyStack[] = "py-stack";
45 static const char kNameFlow[] = "flow";
46
47 // The env of runtime profiler.
48 static const char kEnableRuntimeProfiler[] = "MS_ENABLE_RUNTIME_PROFILER";
49 static const char kRuntimeProfilerTopNum[] = "MS_ENABLE_PROFILER_TOP_NUM";
50
51 // Save file name.
52 static const char kJsonFileName[] = "RuntimeProfilerJson";
53 static const char kSummaryInfoFileName[] = "RuntimeProfilerSummary";
54 static const char kDetailInfoFileName[] = "RuntimeProfilerDetail";
55
56 namespace {
GetRealPathName(const std::string & name)57 std::string GetRealPathName(const std::string &name) {
58 auto path_name = GetSaveGraphsPathName(name);
59 auto real_path = mindspore::Common::CreatePrefixPath(path_name);
60 if (!real_path.has_value()) {
61 MS_LOG(ERROR) << "Get real path failed, path: " << path_name;
62 return ("./" + name);
63 }
64 return real_path.value();
65 }
66
GetClockTimeNs()67 uint64_t GetClockTimeNs() {
68 auto ts = std::chrono::system_clock::now();
69 int64_t system_t = std::chrono::duration_cast<std::chrono::nanoseconds>(ts.time_since_epoch()).count();
70 return static_cast<uint64_t>(system_t);
71 }
72 } // namespace
73
ProfilerRecorder(ProfilerModule module,ProfilerEvent event,const std::string & op_name,bool is_inner_event,bool need_py_stack,uint64_t flow_id)74 ProfilerRecorder::ProfilerRecorder(ProfilerModule module, ProfilerEvent event, const std::string &op_name,
75 bool is_inner_event, bool need_py_stack, uint64_t flow_id) {
76 auto &profiler = ProfilerAnalyzer::GetInstance();
77 if (!profiler.profiler_enable()) {
78 return;
79 }
80 data_ = std::make_unique<Data>(module, event, profiler.GetBriefName(op_name),
81 !profiler.enable_by_env() && need_py_stack ? GetPythonStackStr_() : std::string(),
82 profiler.GetTimeStamp(), flow_id, is_inner_event);
83 }
84
~ProfilerRecorder()85 ProfilerRecorder::~ProfilerRecorder() {
86 auto &profiler = ProfilerAnalyzer::GetInstance();
87 if (!profiler.profiler_enable()) {
88 return;
89 }
90 if (data_ == nullptr) {
91 return;
92 }
93 profiler.RecordData(std::make_shared<ProfilerData>(data_->module_, data_->event_, data_->op_name_,
94 data_->is_inner_event_, data_->start_time_,
95 profiler.GetTimeStamp(), data_->flow_id_, data_->py_stack_));
96 }
97
PythonProfilerRecorder(const std::string & record_name)98 PythonProfilerRecorder::PythonProfilerRecorder(const std::string &record_name)
99 : start_time_(0),
100 record_name_(record_name),
101 module_(ProfilerModule::kPython),
102 event_(ProfilerEvent::kPythonObserved) {}
103
record_start()104 void PythonProfilerRecorder::record_start() {
105 if (runtime::ProfilerAnalyzer::GetInstance().profiler_enable()) {
106 start_time_ = runtime::ProfilerAnalyzer::GetInstance().GetTimeStamp();
107 }
108 }
109
record_end()110 void PythonProfilerRecorder::record_end() {
111 if (runtime::ProfilerAnalyzer::GetInstance().profiler_enable()) {
112 auto end_time = runtime::ProfilerAnalyzer::GetInstance().GetTimeStamp();
113 runtime::ProfilerAnalyzer::GetInstance().RecordData(
114 std::make_shared<runtime::ProfilerData>(module_, event_, record_name_, false, start_time_, end_time));
115 }
116 }
117
ProfilerStageRecorder(ProfilerStage stage)118 ProfilerStageRecorder::ProfilerStageRecorder(ProfilerStage stage) {
119 if (!ProfilerAnalyzer::GetInstance().profiler_enable()) {
120 return;
121 }
122 start_time_ = ProfilerAnalyzer::GetInstance().GetTimeStamp();
123 stage_ = stage;
124 }
125
~ProfilerStageRecorder()126 ProfilerStageRecorder::~ProfilerStageRecorder() {
127 if (!ProfilerAnalyzer::GetInstance().profiler_enable()) {
128 return;
129 }
130 ProfilerAnalyzer::GetInstance().RecordData(
131 std::make_shared<runtime::ProfilerData>(stage_, start_time_, ProfilerAnalyzer::GetInstance().GetTimeStamp()));
132 }
133
GetInstance()134 ProfilerAnalyzer &ProfilerAnalyzer::GetInstance() noexcept {
135 static ProfilerAnalyzer instance{};
136 return instance;
137 }
138
Initialize()139 void ProfilerAnalyzer::Initialize() {
140 if (init_) {
141 return;
142 }
143 std::unique_lock<SpinLock> lock(data_mutex_);
144 init_ = true;
145
146 if (common::GetEnv(kEnableRuntimeProfiler) != "1") {
147 return;
148 }
149 profiler_enable_ = true;
150 auto top_num_env = common::GetEnv(kRuntimeProfilerTopNum);
151 if (top_num_env != std::string()) {
152 try {
153 show_top_num_ = stoi(top_num_env);
154 } catch (const std::exception &e) {
155 MS_LOG(EXCEPTION) << "Invalid argument: " << e.what() << " when parse " << top_num_env;
156 }
157 }
158
159 auto now_time = std::to_string(GetTimeStamp());
160 json_file_name_ = GetRealPathName(kJsonFileName + now_time + ".json");
161 summary_info_file_name_ = GetRealPathName(kSummaryInfoFileName + now_time + ".csv");
162 detail_info_file_name_ = GetRealPathName(kDetailInfoFileName + now_time + ".csv");
163 }
164
profiler_enable() const165 bool ProfilerAnalyzer::profiler_enable() const { return profiler_enable_ || mi_profiler_enable_; }
166
SetThreadIdToName(const std::thread::id & id,const std::string & name)167 void ProfilerAnalyzer::SetThreadIdToName(const std::thread::id &id, const std::string &name) {
168 std::unique_lock<SpinLock> lock(data_mutex_);
169 thread_id_to_name_[id] = name;
170 }
171
ProcessData()172 void ProfilerAnalyzer::ProcessData() {
173 for (const auto &[step_info_ptr, span] : data_line_) {
174 step_time_ = step_info_ptr->step_time_;
175 // Process module overlapping data.
176 ProcessModuleSummaryData(span);
177 // Process data.
178 for (auto &data : span) {
179 SaveJsonData(data);
180 AnalyzeSummaryData(data);
181 }
182 AddPythonSummaryData(step_info_ptr->step_time_);
183 // Dump data.
184 DumpDetailData(step_info_ptr->step_, span);
185 DumpSummaryData(step_info_ptr->step_);
186 // Clear temp data.
187 module_total_time_ = 0ull;
188 module_infos_.clear();
189 stage_infos_.clear();
190 }
191 }
192
Clear()193 void ProfilerAnalyzer::Clear() noexcept {
194 std::unique_lock<SpinLock> lock(data_mutex_);
195 if (!init_ || !profiler_enable_ || data_line_.empty()) {
196 return;
197 }
198 ProcessData();
199
200 // Dump json data.
201 DumpJsonData();
202 #ifdef WITH_BACKEND
203 json_infos_.clear();
204 #endif
205 data_.clear();
206 data_line_.clear();
207 init_ = false;
208 }
209
EnableMiProfile()210 void ProfilerAnalyzer::EnableMiProfile() { mi_profiler_enable_ = true; }
211
GetTimeStamp() const212 uint64_t ProfilerAnalyzer::GetTimeStamp() const noexcept {
213 if (profiler_enable_) {
214 return GetClockTimeNs();
215 }
216 #if !defined(_WIN32) && !defined(_WIN64) && !defined(__ANDROID__) && !defined(ANDROID) && !defined(__APPLE__) && \
217 defined(ENABLE_DEBUGGER)
218 return profiler::GetClockSyscnt();
219 #else
220 return 0;
221 #endif
222 }
223
224 // For example: ScopeName(XX/XX/ReLU-op1) --> BriefName(ReLU)
GetBriefName(const std::string & scope_name) const225 std::string ProfilerAnalyzer::GetBriefName(const std::string &scope_name) const {
226 auto first_index = scope_name.rfind('/');
227 auto second_index = scope_name.rfind("-op");
228 if ((first_index != std::string::npos) && (second_index != std::string::npos) &&
229 (first_index + 1 < scope_name.size()) && (first_index + 1 < second_index)) {
230 return scope_name.substr(first_index + 1, second_index - first_index - 1);
231 }
232 return scope_name;
233 }
234
RecordData(const ProfilerDataPtr & data)235 void ProfilerAnalyzer::RecordData(const ProfilerDataPtr &data) noexcept {
236 #if !defined(_WIN32) && !defined(_WIN64) && !defined(__ANDROID__) && !defined(ANDROID) && !defined(__APPLE__)
237 MS_EXCEPTION_IF_NULL(data);
238 std::unique_lock<SpinLock> lock(data_mutex_);
239 if (profiler_enable_) {
240 (void)data_.emplace_back(data);
241 }
242 if (mi_profiler_enable_) {
243 #if defined(ENABLE_DEBUGGER)
244 auto ascend_profiler = mindspore::profiler::Profiler::GetInstance(kAscendDevice);
245 if (ascend_profiler != nullptr && ascend_profiler->EnableHostStack()) {
246 profiler::ascend::ProfilingFrameworkData::RecordHostProfile(data, step_);
247 }
248 #endif
249 }
250 #endif
251 }
252
RecordFlowData(uint64_t flow_id)253 void ProfilerAnalyzer::RecordFlowData(uint64_t flow_id) {
254 if (!ProfilerAnalyzer::GetInstance().profiler_enable()) {
255 return;
256 }
257 ProfilerAnalyzer::GetInstance().RecordData(std::make_shared<ProfilerData>(
258 ProfilerModule::kDefault, ProfilerEvent::kDefault, kNameFlow, true, ProfilerAnalyzer::GetInstance().GetTimeStamp(),
259 ProfilerAnalyzer::GetInstance().GetTimeStamp(), flow_id));
260 }
261
StartStep()262 void ProfilerAnalyzer::StartStep() {
263 Initialize();
264 if (!profiler_enable()) {
265 return;
266 }
267
268 std::unique_lock<SpinLock> lock(data_mutex_);
269 ++step_;
270 // Reset the saved data.
271 data_.clear();
272 step_start_time_ = GetTimeStamp();
273 }
274
ProcessModuleSummaryData(const ProfilerDataSpan & span)275 void ProfilerAnalyzer::ProcessModuleSummaryData(const ProfilerDataSpan &span) {
276 if (span.empty()) {
277 return;
278 }
279
280 // Use multimap as start_time_ may be same.
281 std::map<ProfilerModule, std::multimap<uint64_t, ProfilerDataPtr>> ordered_data;
282 for (auto &data : span) {
283 (void)ordered_data[data->module_].emplace(data->start_time_, data);
284 }
285 for (const auto &data_item : ordered_data) {
286 ProfilerDataPtr last_data = nullptr;
287 for (const auto &[start_time, data] : data_item.second) {
288 // Skip stage data and inner event data.
289 if (data->is_stage_ || data->is_inner_event_) {
290 continue;
291 }
292 // last_data is null or current range is not in last range, add current range and update last_data.
293 if (last_data == nullptr || start_time >= last_data->end_time_) {
294 AnalyzeModuleSummaryData(data);
295 last_data = data;
296 continue;
297 }
298 // Current range is in last range, just skip.
299 if (data->end_time_ <= last_data->end_time_) {
300 auto old_dur_time = data->dur_time_;
301 data->dur_time_ = 0;
302 AnalyzeModuleSummaryData(data);
303 data->dur_time_ = old_dur_time;
304 continue;
305 }
306 // Process overlapping range of current range, data need deep copy.
307 auto data_ptr = std::make_shared<ProfilerData>(*data);
308 data_ptr->start_time_ = last_data->end_time_;
309 data_ptr->dur_time_ = data_ptr->end_time_ - data_ptr->start_time_;
310 AnalyzeModuleSummaryData(data);
311 last_data = data_ptr;
312 }
313 }
314 }
315
EndStep()316 void ProfilerAnalyzer::EndStep() {
317 if (!profiler_enable()) {
318 return;
319 }
320
321 std::unique_lock<SpinLock> lock(data_mutex_);
322 if (data_.empty()) {
323 return;
324 }
325
326 #ifdef WITH_BACKEND
327 step_time_ = GetTimeStamp() - step_start_time_;
328 #endif
329 (void)data_line_.emplace_back(std::make_shared<StepInfo>(step_, step_time_), std::move(data_));
330 }
331
SaveJsonData(const ProfilerDataPtr & data)332 void ProfilerAnalyzer::SaveJsonData(const ProfilerDataPtr &data) {
333 MS_EXCEPTION_IF_NULL(data);
334 nlohmann::json json_data;
335 if (data->is_stage_) {
336 json_data[kJsonName] = kProfilerStageString.at(data->stage_);
337 } else {
338 json_data[kJsonName] =
339 kProfilerModuleString.at(data->module_) + "::" + kProfilerEventString.at(data->event_) + "::" + data->op_name_;
340 }
341 json_data[kJsonPh] = kJsonPhX;
342 json_data[kJsonPid] = std::to_string(data->pid_);
343 json_data[kJsonTid] = std::to_string(data->tid_);
344 json_data[kJsonTs] = static_cast<double>(data->start_time_) / kNsToUs;
345 json_data[kJsonDur] = static_cast<double>(data->dur_time_) / kNsToUs;
346 nlohmann::json args;
347 args[kJsonFlowId] = data->flow_id_;
348 if (!data->py_stack_.empty()) {
349 args[kJsonPyStack] = data->py_stack_;
350 }
351 json_data[kJsonArgs] = args;
352
353 (void)json_infos_.emplace_back(json_data);
354 }
355
AddPythonSummaryData(const uint64_t span_time)356 void ProfilerAnalyzer::AddPythonSummaryData(const uint64_t span_time) {
357 uint64_t python_time = span_time;
358 (void)std::for_each(stage_infos_.begin(), stage_infos_.end(),
359 [&python_time](const std::pair<ProfilerStage, ProfilerStatisticsInfoPtr> &iter) {
360 python_time -= iter.second->total_time_;
361 });
362 auto stage_info = std::make_shared<ProfilerStatisticsInfo>(kProfilerStageString.at(ProfilerStage::kPython), false);
363 stage_info->AccumulateTime(python_time);
364 (void)stage_infos_.emplace(ProfilerStage::kPython, stage_info);
365
366 auto module_info = std::make_shared<ProfilerModuleInfo>();
367 module_info->module_statistics_info_ =
368 std::make_shared<ProfilerStatisticsInfo>(kProfilerModuleString.at(ProfilerModule::kPython));
369 module_info->module_statistics_info_->AccumulateTime(python_time);
370 module_total_time_ += python_time;
371 (void)module_infos_.emplace(ProfilerModule::kPython, module_info);
372 }
373
AnalyzeSummaryData(const ProfilerDataPtr & data)374 void ProfilerAnalyzer::AnalyzeSummaryData(const ProfilerDataPtr &data) {
375 if (data->is_stage_) {
376 AnalyzeStageSummaryData(data);
377 } else {
378 AnalyzeEventSummaryData(data);
379 }
380 }
381
AnalyzeStageSummaryData(const ProfilerDataPtr & data)382 void ProfilerAnalyzer::AnalyzeStageSummaryData(const ProfilerDataPtr &data) {
383 MS_EXCEPTION_IF_NULL(data);
384 if (stage_infos_.count(data->stage_) > 0) {
385 auto &stage_info = stage_infos_[data->stage_];
386 MS_EXCEPTION_IF_NULL(stage_info);
387 stage_info->AccumulateTime(data->dur_time_);
388 } else {
389 auto stage_info =
390 std::make_shared<ProfilerStatisticsInfo>(kProfilerStageString.at(data->stage_), data->is_inner_event_);
391 stage_info->AccumulateTime(data->dur_time_);
392 (void)stage_infos_.emplace(data->stage_, stage_info);
393 }
394 }
395
AnalyzeModuleSummaryData(const ProfilerDataPtr & data)396 void ProfilerAnalyzer::AnalyzeModuleSummaryData(const ProfilerDataPtr &data) {
397 MS_EXCEPTION_IF_NULL(data);
398 if (module_infos_.count(data->module_) == 0) {
399 auto module_info_ptr = std::make_shared<ProfilerModuleInfo>();
400 module_info_ptr->module_statistics_info_ =
401 std::make_shared<ProfilerStatisticsInfo>(kProfilerModuleString.at(data->module_));
402 (void)module_infos_.emplace(data->module_, module_info_ptr);
403 }
404
405 auto &module_info_ptr = module_infos_[data->module_];
406 module_info_ptr->module_statistics_info_->AccumulateTime(data->dur_time_);
407 module_total_time_ += data->dur_time_;
408 }
409
AnalyzeEventSummaryData(const ProfilerDataPtr & data)410 void ProfilerAnalyzer::AnalyzeEventSummaryData(const ProfilerDataPtr &data) {
411 MS_EXCEPTION_IF_NULL(data);
412 if (module_infos_.count(data->module_) == 0) {
413 MS_LOG(INFO) << "Summarize Unknown module : " << data->module_ << ", will skip current data.";
414 return;
415 }
416
417 auto &module_info_ptr = module_infos_[data->module_];
418 auto event_infos_ptr = &(module_info_ptr->event_infos_);
419 if (event_infos_ptr->count(data->event_) == 0) {
420 auto event_info_ptr = std::make_shared<ProfilerEventInfo>();
421 event_info_ptr->event_statistics_info_ =
422 std::make_shared<ProfilerStatisticsInfo>(kProfilerEventString.at(data->event_), data->is_inner_event_);
423 (void)event_infos_ptr->emplace(data->event_, event_info_ptr);
424 }
425
426 auto &event_info_ptr = (*event_infos_ptr)[data->event_];
427 event_info_ptr->event_statistics_info_->AccumulateTime(data->dur_time_);
428 AnalyzeOpSummaryData(&event_info_ptr->op_infos_, data);
429 }
430
AnalyzeOpSummaryData(mindspore::HashMap<std::string,ProfilerStatisticsInfoPtr> * const op_infos,const ProfilerDataPtr & data)431 void ProfilerAnalyzer::AnalyzeOpSummaryData(mindspore::HashMap<std::string, ProfilerStatisticsInfoPtr> *const op_infos,
432 const ProfilerDataPtr &data) {
433 MS_EXCEPTION_IF_NULL(op_infos);
434 MS_EXCEPTION_IF_NULL(data);
435 if (op_infos->count(data->op_name_) > 0) {
436 auto &op_info = (*op_infos)[data->op_name_];
437 MS_EXCEPTION_IF_NULL(op_info);
438 return op_info->AccumulateTime(data->dur_time_);
439 }
440
441 auto op_info = std::make_shared<ProfilerStatisticsInfo>(data->op_name_, data->is_inner_event_);
442 op_info->AccumulateTime(data->dur_time_);
443 (void)op_infos->emplace(data->op_name_, op_info);
444 }
445
DumpJsonData() const446 void ProfilerAnalyzer::DumpJsonData() const {
447 ChangeFileMode(json_file_name_, S_IWUSR);
448 std::ofstream ofs(json_file_name_, std::ofstream::app);
449 if (!ofs.is_open()) {
450 MS_LOG(ERROR) << "Open file [" << json_file_name_ << "] failed!";
451 return;
452 }
453 ofs << json_infos_.dump();
454 ChangeFileMode(json_file_name_, S_IRUSR);
455 }
456
DumpDetailData(const size_t step,const ProfilerDataSpan & span) const457 void ProfilerAnalyzer::DumpDetailData(const size_t step, const ProfilerDataSpan &span) const {
458 ChangeFileMode(detail_info_file_name_, S_IWUSR);
459 std::ofstream ofs(detail_info_file_name_, std::ofstream::app);
460 if (!ofs.is_open()) {
461 MS_LOG(ERROR) << "Open file [" << detail_info_file_name_ << "] failed!";
462 return;
463 }
464
465 ofs << "[Step:" << step << " step_time:" << step_time_ << "ns, module_total_time:" << module_total_time_ << "ns]\n";
466 for (auto &data : span) {
467 MS_EXCEPTION_IF_NULL(data);
468 std::string title_name = data->is_stage_ ? ("stage:" + kProfilerStageString.at(data->stage_))
469 : ("module:" + kProfilerModuleString.at(data->module_));
470 ofs << title_name << ", event:" << kProfilerEventString.at(data->event_) << ", op:" << data->op_name_
471 << ", start_time:" << data->start_time_ << ", end_time:" << data->end_time_ << ", dur_time:," << data->dur_time_
472 << ",ns, tid:" << std::to_string(data->tid_) << ", pid:" << data->pid_ << "\n";
473 }
474 ofs << "\n";
475
476 ChangeFileMode(detail_info_file_name_, S_IRUSR);
477 }
478
DumpSummaryData(const size_t step) const479 void ProfilerAnalyzer::DumpSummaryData(const size_t step) const {
480 // Fill the summary info.
481 std::stringstream string_stream;
482 string_stream << "[Step:" << step << ", step_time:" << step_time_ << "ns, module_total_time:" << module_total_time_
483 << "ns]\n";
484 DumpModuleSummaryData(string_stream);
485 DumpStageSummaryData(string_stream);
486 std::cout << string_stream.str() << std::endl;
487
488 ChangeFileMode(summary_info_file_name_, S_IWUSR);
489 std::ofstream ofs(summary_info_file_name_, std::ofstream::app);
490 if (!ofs.is_open()) {
491 MS_LOG(ERROR) << "Open file [" << summary_info_file_name_ << "] failed!";
492 return;
493 }
494 ofs << string_stream.str();
495 ChangeFileMode(summary_info_file_name_, S_IRUSR);
496 }
497
DumpStageSummaryData(std::stringstream & string_stream) const498 void ProfilerAnalyzer::DumpStageSummaryData(std::stringstream &string_stream) const {
499 // Order module info by total time.
500 std::multimap<uint64_t, ProfilerStatisticsInfo *, std::greater_equal<uint64_t>> order_stage_infos;
501 for (auto &stage_info : stage_infos_) {
502 auto &stage_statistics_info = stage_info.second;
503 MS_EXCEPTION_IF_NULL(stage_statistics_info);
504 stage_statistics_info->Average();
505 stage_statistics_info->CalculatePercent(step_time_);
506 (void)order_stage_infos.emplace(stage_statistics_info->total_time_, stage_statistics_info.get());
507 }
508
509 string_stream << "==========================================[Stage]==========================================\n";
510 for (auto &order_stage_info : order_stage_infos) {
511 auto &stage_statistics_info = order_stage_info.second;
512 string_stream << "Stage:" << stage_statistics_info->name_ << std::fixed << std::setprecision(kPrecisionDigits)
513 << ", total_time:" << stage_statistics_info->total_time_
514 << "ns, average_time:" << stage_statistics_info->average_time_
515 << "ns, total_count:" << stage_statistics_info->count_
516 << ", percent:" << stage_statistics_info->percent_ << "%\n";
517 string_stream << "\n";
518 }
519
520 string_stream << "\n";
521 }
522
DumpModuleSummaryData(std::stringstream & string_stream) const523 void ProfilerAnalyzer::DumpModuleSummaryData(std::stringstream &string_stream) const {
524 // Order module info by total time.
525 std::multimap<uint64_t, ProfilerModuleInfo *, std::greater_equal<uint64_t>> order_module_infos;
526 for (auto &module_info : module_infos_) {
527 MS_EXCEPTION_IF_NULL(module_info.second);
528 auto &module_statistics_info = module_info.second->module_statistics_info_;
529 MS_EXCEPTION_IF_NULL(module_statistics_info);
530 module_statistics_info->Average();
531 module_statistics_info->CalculatePercent(module_total_time_);
532 (void)order_module_infos.emplace(module_statistics_info->total_time_, module_info.second.get());
533 }
534
535 string_stream << "==========================================[Module]==========================================\n";
536 for (auto &order_module_info : order_module_infos) {
537 auto &module_statistics_info = order_module_info.second->module_statistics_info_;
538 string_stream << "Module:" << module_statistics_info->name_ << std::fixed << std::setprecision(kPrecisionDigits)
539 << ", total_time:" << module_statistics_info->total_time_
540 << "ns, average_time:" << module_statistics_info->average_time_
541 << "ns, total_count:" << module_statistics_info->count_
542 << ", percent:" << module_statistics_info->percent_ << "%\n";
543 DumpEventSummaryData(order_module_info.second->event_infos_, string_stream);
544 }
545
546 string_stream << "\n";
547 }
548
DumpEventSummaryData(const std::map<ProfilerEvent,ProfilerEventInfoPtr> & event_infos,std::stringstream & string_stream) const549 void ProfilerAnalyzer::DumpEventSummaryData(const std::map<ProfilerEvent, ProfilerEventInfoPtr> &event_infos,
550 std::stringstream &string_stream) const {
551 // Order event info by total time.
552 std::multimap<uint64_t, ProfilerEventInfo *, std::greater_equal<uint64_t>> order_event_infos;
553 std::multimap<uint64_t, ProfilerEventInfo *, std::greater_equal<uint64_t>> order_inner_event_infos;
554 for (auto &event_info : event_infos) {
555 MS_EXCEPTION_IF_NULL(event_info.second);
556 auto &event_statistics_info = event_info.second->event_statistics_info_;
557 MS_EXCEPTION_IF_NULL(event_statistics_info);
558 event_statistics_info->Average();
559 event_statistics_info->CalculatePercent(module_total_time_);
560 if (event_statistics_info->is_inner_info_) {
561 (void)order_inner_event_infos.emplace(event_statistics_info->total_time_, event_info.second.get());
562 } else {
563 (void)order_event_infos.emplace(event_statistics_info->total_time_, event_info.second.get());
564 }
565 }
566
567 for (auto &order_event_info : order_event_infos) {
568 auto &event_statistics_info = order_event_info.second->event_statistics_info_;
569 string_stream << " Event:" << event_statistics_info->name_ << std::fixed << std::setprecision(kPrecisionDigits)
570 << ", total_time:" << event_statistics_info->total_time_
571 << "ns, average_time:" << event_statistics_info->average_time_
572 << "ns, total_count:" << event_statistics_info->count_
573 << ", percent:" << event_statistics_info->percent_ << "%\n";
574 DumpOpSummaryData(order_event_info.second->op_infos_, string_stream);
575 }
576
577 // Inner event.
578 for (auto &order_inner_event_info : order_inner_event_infos) {
579 auto &event_statistics_info = order_inner_event_info.second->event_statistics_info_;
580 string_stream << " EventInner:" << event_statistics_info->name_ << std::fixed
581 << std::setprecision(kPrecisionDigits) << ", total_time:" << event_statistics_info->total_time_
582 << "ns, average_time:" << event_statistics_info->average_time_
583 << "ns, total_count:" << event_statistics_info->count_ << "\n";
584 DumpOpSummaryData(order_inner_event_info.second->op_infos_, string_stream);
585 }
586
587 string_stream << "\n";
588 }
589
DumpOpSummaryData(const mindspore::HashMap<std::string,ProfilerStatisticsInfoPtr> & op_infos,std::stringstream & string_stream) const590 void ProfilerAnalyzer::DumpOpSummaryData(const mindspore::HashMap<std::string, ProfilerStatisticsInfoPtr> &op_infos,
591 std::stringstream &string_stream) const {
592 if (show_top_num_ == 0) {
593 return;
594 }
595
596 // Order op info by total time and average time.
597 std::multimap<uint64_t, ProfilerStatisticsInfo *, std::greater_equal<uint64_t>> total_time_order_op_infos;
598 std::multimap<double, ProfilerStatisticsInfo *, std::greater_equal<double>> average_time_order_op_infos;
599 for (auto &op_info : op_infos) {
600 auto &op_statistics_info = op_info.second;
601 MS_EXCEPTION_IF_NULL(op_statistics_info);
602 op_statistics_info->Average();
603 op_statistics_info->CalculatePercent(module_total_time_);
604 (void)total_time_order_op_infos.emplace(op_statistics_info->total_time_, op_statistics_info.get());
605 (void)average_time_order_op_infos.emplace(op_statistics_info->average_time_, op_statistics_info.get());
606 }
607
608 // Show the op info by the total time top num.
609 string_stream << " Total time top " << show_top_num_ << " op:\n";
610 int show_num = 0;
611 for (auto &order_op_info : total_time_order_op_infos) {
612 if (++show_num > show_top_num_) {
613 break;
614 }
615 auto &op_statistics_info = order_op_info.second;
616 string_stream << " Op:" << op_statistics_info->name_ << std::fixed << std::setprecision(kPrecisionDigits)
617 << ", total_time:" << op_statistics_info->total_time_
618 << "ns, average_time:" << op_statistics_info->average_time_
619 << "ns, total_count:" << op_statistics_info->count_;
620 if (op_statistics_info->is_inner_info_) {
621 string_stream << "\n";
622 } else {
623 string_stream << ", percent:" << op_statistics_info->percent_ << "%\n";
624 }
625 }
626
627 // Show the op info by the average time top num.
628 string_stream << " Average time top " << show_top_num_ << " op:\n";
629 show_num = 0;
630 for (auto &order_op_info : average_time_order_op_infos) {
631 if (++show_num > show_top_num_) {
632 break;
633 }
634 auto &op_statistics_info = order_op_info.second;
635 string_stream << " Op:" << op_statistics_info->name_ << std::fixed << std::setprecision(kPrecisionDigits)
636 << ", average_time:" << op_statistics_info->average_time_
637 << "ns, total_time:" << op_statistics_info->total_time_
638 << "ns, total_count:" << op_statistics_info->count_;
639 if (op_statistics_info->is_inner_info_) {
640 string_stream << "\n";
641 } else {
642 string_stream << ", percent:" << op_statistics_info->percent_ << "%\n";
643 }
644 }
645
646 string_stream << "\n";
647 }
648 } // namespace runtime
649 } // namespace mindspore
650