• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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