basic version of profiler class

This commit is contained in:
VaclavT 2021-03-22 06:50:15 +01:00
parent a931661608
commit 56407f3516
4 changed files with 94 additions and 11 deletions

View File

@ -14,7 +14,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-stack_size -Wl,0x1000
# otool -lV build/ml | grep stack
# set(CMAKE_CXX_FLAGS "-Wall -Wextra")
# set(CMAKE_CXX_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
include_directories(/usr/local/opt/openssl/include ${CMAKE_SOURCE_DIR}/clib ${CMAKE_SOURCE_DIR} )
@ -30,6 +30,7 @@ set(SOURCE
ml_date.cpp
ml_string.cpp
ml_util.cpp
ml_profiler.cpp
clib/csvparser.cpp
clib/sslclient.cpp
clib/json11.cpp

30
ml.cpp
View File

@ -4,6 +4,7 @@
#include "ml_date.h"
#include "ml_string.h"
#include "ml_util.h"
#include "ml_profiler.h"
#include "clib/csvparser.h"
#include "clib/sslclient.h"
@ -710,6 +711,8 @@ MlValue MlValue::eval(MlEnvironment &env) {
for (size_t i = 0; i < args.size(); i++)
args[i] = args[i].eval(env);
MlPerfMon::instance().add_method_call(function.type == LAMBDA ? "lambda" : function.str);
return function.apply(
args,
env
@ -1651,7 +1654,7 @@ namespace builtin {
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double, std::milli> time_span = t2 - t1;
std::cout << args[0].as_string() << " " << time_span.count() << " ms" << std::endl;
std::cerr << args[0].as_string() << " " << time_span.count() << " ms" << std::endl;
return acc;
}
@ -1718,20 +1721,15 @@ bool MlEnvironment::has(std::string name) const {
// Get the value associated with this name in this scope
MlValue MlEnvironment::get(const std::string &name) const {
// Meta operations
if (name == "eval") return MlValue("eval", builtin::eval);
if (name == "type") return MlValue("type", builtin::get_type_name);
if (name == "parse") return MlValue("parse", builtin::parse);
// Special forms
if (name == "do") return MlValue("do", builtin::do_block);
if (name == "if") return MlValue("if", builtin::if_then_else);
if (name == "define") return MlValue("define", builtin::define);
if (name == "do") return MlValue("do", builtin::do_block);
if (name == "for") return MlValue("for", builtin::for_loop);
if (name == "while") return MlValue("while", builtin::while_loop);
if (name == "scope") return MlValue("scope", builtin::scope);
if (name == "quote") return MlValue("quote", builtin::quote);
if (name == "defun") return MlValue("defun", builtin::defun);
if (name == "define") return MlValue("define", builtin::define);
if (name == "lambda") return MlValue("lambda", builtin::lambda);
if (name == "benchmark") return MlValue("benchmark", builtin::benchmark);
@ -1743,6 +1741,11 @@ MlValue MlEnvironment::get(const std::string &name) const {
if (name == ">=") return MlValue(">=", builtin::greater_eq);
if (name == "<=") return MlValue("<=", builtin::less_eq);
// Meta operations
if (name == "eval") return MlValue("eval", builtin::eval);
if (name == "type") return MlValue("type", builtin::get_type_name);
if (name == "parse") return MlValue("parse", builtin::parse);
// Arithmetic operations
if (name == "+") return MlValue("+", builtin::sum);
if (name == "-") return MlValue("-", builtin::subtract);
@ -1862,7 +1865,7 @@ int main(int argc, char *argv[]) {
}
// help
if (cmdOptionExists(argv, argv + argc, "-h")) {
std::cout << "Usage:\n\t-h print this help\n\t-f source_file - executes code in file\n\t-c code - runs passed code\n\t-i runs repl\n\t-b skip stdlib loading\n\t-v prints version string\n\n";
std::cout << "Usage:\n\t-h print this help\n\t-f source_file - executes code in file\n\t-c code - runs passed code\n\t-i runs repl\n\t-b skip stdlib loading\n\t-p prints profile info at the end\n\t-v prints version string\n\n";
return 0;
}
// version
@ -1870,6 +1873,9 @@ int main(int argc, char *argv[]) {
std::cout << VERSION << std::endl;
return 0;
}
// performance monitor on
if (cmdOptionExists(argv, argv + argc, "-p"))
MlPerfMon::instance().turnOn();
// passed code
if (cmdOptionExists(argv, argv + argc, "-c")) {
std::vector<std::string> codes = getCmdOption(argv, argc, "-c");
@ -1885,11 +1891,15 @@ int main(int argc, char *argv[]) {
repl(env);
}
MlPerfMon::instance().print_results();
return 0;
} catch (MlError &e) {
std::cerr << e.description() << std::endl;
} catch (std::runtime_error &e) {
std::cerr << e.what() << std::endl;
}
return 0;
return 1;
}

44
ml_profiler.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "ml_profiler.h"
#include <iostream>
#include <iomanip>
void MlPerfMon::turnOn() {
perfOn = true;
}
void MlPerfMon::add_method_call(const std::string &method) {
if (perfOn) {
auto search = calls_counter.find(method);
if (search != calls_counter.end()) {
calls_counter[method] = search->second + 1;
} else {
calls_counter.insert({method, 1});
}
}
}
void MlPerfMon::print_results() {
if (perfOn) {
std::cerr << std::endl << std::endl << "Call Frequency" << std::endl;
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; });
int i {0};
for(auto &p : v) {
// TODO when method name longer than 15 chars, here it crashes
p.first.insert(p.first.end(), 15 - p.first.size(), ' ');
std::cerr << p.first << " " << p.second << std::endl;
i++;
if (i > 10) break;
}
std::cerr << std::endl;
}
}

28
ml_profiler.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include "ml.h"
#include <unordered_map>
class MlPerfMon {
private:
MlPerfMon() : perfOn(false) {};
public:
// https://stackoverflow.com/questions/43523509/simple-singleton-example-in-c
static MlPerfMon& instance(){
static MlPerfMon instance;
return instance;
}
void turnOn();
void add_method_call(const std::string &method);
void print_results();
private:
bool perfOn;
std::unordered_map<std::string, long> calls_counter;
};