118 lines
3.6 KiB
C++
118 lines
3.6 KiB
C++
|
|
#include "ml_profiler.h"
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
// for linux gcc
|
|
#include <iomanip>
|
|
#include <numeric>
|
|
|
|
|
|
using namespace std::chrono;
|
|
|
|
|
|
void MlPerfMon::turnOn() {
|
|
perfOn = true;
|
|
start_time = std::chrono::high_resolution_clock::now();
|
|
}
|
|
|
|
void MlPerfMon::debugOn() {
|
|
debugStacktraceOn = true;
|
|
}
|
|
|
|
void MlPerfMon::add_method_call(const MlValue &function, const std::vector<MlValue> &args) {
|
|
// only main thread is logged, to prevent mixing from others threads so lock not needed
|
|
if (main_thread_id != std::this_thread::get_id()) return;
|
|
|
|
std::string method = function.type == MlValue::LAMBDA ? "lambda" : function.str;
|
|
|
|
if (debugStacktraceOn) {
|
|
// call stack with more info
|
|
std::string args_string;
|
|
for (size_t i = 0; i < args.size() && args_string.size() < call_stack_args_str_len; i++) {
|
|
args_string.append(" ");
|
|
args_string.append(args[i].display());
|
|
}
|
|
if (args_string.size() > call_stack_args_str_len)
|
|
args_string = args_string.substr(0, call_stack_args_str_len) + "..";
|
|
else
|
|
args_string.append(")");
|
|
|
|
call_stack.push_back("(" + method + args_string);
|
|
} else {
|
|
call_stack.push_back(method);
|
|
}
|
|
|
|
if (perfOn)
|
|
calls_counter[method]++;
|
|
}
|
|
|
|
void MlPerfMon::end_method_call() {
|
|
// only main thread is looged, to prevent mixing from others threads so lock not needed
|
|
if (main_thread_id != std::this_thread::get_id()) return;
|
|
|
|
if (!call_stack.empty())
|
|
call_stack.pop_back();
|
|
}
|
|
|
|
std::string MlPerfMon::callstack() const {
|
|
std::string cs {"\ncall stack:\n"};
|
|
|
|
int cnt = 0;
|
|
for (auto it = call_stack.rbegin(); it != call_stack.rend() && cnt < call_stack_max_methods; ++it, ++cnt)
|
|
cs.append(" " + std::string(*it) + "\n"); // << std::endl;
|
|
|
|
if (call_stack.size() > call_stack_max_methods)
|
|
cs.append("next " + std::to_string(call_stack.size() - call_stack_max_methods) + " entries skipped..\n");
|
|
|
|
return cs.append("\n");
|
|
}
|
|
|
|
size_t MlPerfMon::get_callstack_position() const {
|
|
return call_stack.size();
|
|
}
|
|
|
|
void MlPerfMon::restore_callstack_position(size_t to_position) {
|
|
if (to_position < call_stack.size()) {
|
|
call_stack.resize(to_position);
|
|
}
|
|
}
|
|
|
|
void MlPerfMon::clear_callstack() {
|
|
auto r = call_stack.empty();
|
|
}
|
|
|
|
void MlPerfMon::print_results() const {
|
|
if (perfOn) {
|
|
time_point<high_resolution_clock> end_time = high_resolution_clock::now();
|
|
|
|
using callcount = std::pair<std::string, long>;
|
|
std::vector<callcount> v(begin(calls_counter), end(calls_counter));
|
|
std::sort(std::begin(v), std::end(v), [](const callcount& a, const callcount& b) { return a.second > b.second; });
|
|
long total_calls = 0;
|
|
for(auto const& c : v) { total_calls += c.second; }
|
|
|
|
std::cerr << std::endl << std::endl;
|
|
std::cerr << "perf stats" << std::endl;
|
|
std::cerr << "run time : " << duration_cast<milliseconds>(end_time - start_time).count() << " ms " << std::endl;
|
|
std::cerr << "total calls : " << total_calls << std::endl;
|
|
std::cerr << "methods called : " << calls_counter.size() << std::endl;
|
|
std::cerr << std::endl;
|
|
|
|
int i {0};
|
|
for(auto &p : v) {
|
|
if (p.first.size() >= method_name_print_len)
|
|
p.first.erase(method_name_print_len, std::string::npos);
|
|
else
|
|
p.first.insert(p.first.end(), method_name_print_len - p.first.size(), ' ');
|
|
|
|
std::cerr << p.first << " " << p.second << std::endl;
|
|
|
|
i++;
|
|
if (i > print_top_methods) break;
|
|
}
|
|
|
|
std::cerr << std::endl;
|
|
}
|
|
}
|