From 9ab0a2c98d6e77ed69081092d041e19e781400b7 Mon Sep 17 00:00:00 2001 From: VaclavT Date: Fri, 9 Apr 2021 00:07:20 +0200 Subject: [PATCH] callstack added --- Readme.md | 39 ++++++++++++++++++++++++--------------- debug.lsp | 8 ++++++++ ml.cpp | 23 ++++++++++++----------- ml_profiler.cpp | 24 +++++++++++++++++++++++- ml_profiler.h | 5 +++++ 5 files changed, 72 insertions(+), 27 deletions(-) diff --git a/Readme.md b/Readme.md index 028abb1..d39f20b 100644 --- a/Readme.md +++ b/Readme.md @@ -7,19 +7,28 @@ ### TODO -- replace to_string macro in ml.cpp - add debug support, at least call stack -- documentation -- add url of source/inspiration to clib/*.cpp - add stdtest - to test every functionality -- add instrumentation (time, nr of evals, num of atoms, debug info, debug environment etc) +- add parenthesis coloring into linenoise - multiline editing (kilo editor) - execute system command should capture stderr - add some mem stats to benchmark +- create pastebin like web using ml +#### Code +- documentation +- rename constants in ml_profiler.h +- replace to_string macro in ml.cpp +- add url of source/inspiration to clib/*.cpp +- add instrumentation (time, nr of evals, num of atoms, debug info, debug environment etc) +#### Language - support for (), nil, t, in lsp code replace 0 by nil in logicals - file functions - - name it here + - open file + - read line + - write line + - close file - string functions + - itok - integer to char, chartoint (better names) - mini printf can be useed for it (%d) - compare - needed for sorting, cmp ignore case - regexp functions - date support @@ -31,7 +40,6 @@ - mapcar (funcall, apply) - syntax highlighting do VS Code - add hash datatype -- create pastebin like web using ml #### Performance - define is one of most frequent callee, when in scope with very few vars, lookup sequentially @@ -40,24 +48,25 @@ - mini_sprintf - unnecesary copying between vector and list - (do, scope ..) repeatedly assign to acc +#### Compile +``` +mkdir -p build +gcc -std=c99 -c -O2 -o linenoise.o clib/linenoise.c +c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp +// on linux c++ -o build/ml -O2 -L/usr/local/lib -L/usr/local/opt/openssl/lib -lm -lstdc++ -lcrypto -lssl *.o +c++ -o build/ml -O2 -L/usr/local/lib -L/usr/local/opt/openssl/lib -lm -lstdc++ -lcrypto -lssl -Wl,-stack_size -Wl,0x1000000 *.o +``` +// or cmake + #### Install ``` cp build/ml /usr/local/bin/ml cp stdlib/*.lsp /usr/local/var/mlisp/ ``` -#### Compile -``` -gcc -std=c99 -c -O2 -o linenoise.o clib/linenoise.c -c++ -c -O2 -I/usr/local/opt/openssl/include -Iclib --std=c++17 ml.cpp ml_io.cpp ml_date.cpp ml_string.cpp ml_util.cpp ml_profiler.cpp clib/json11.cpp clib/csvparser.cpp clib/sslclient.cpp clib/printf.cpp -c++ -o ml -O2 -L/usr/local/lib -L/usr/local/opt/openssl/lib -lm -lstdc++ -lcrypto -lssl -Wl,-stack_size -Wl,0x1000000 *.o -``` -or -cmake ### Example of use ``` -time ./build/ml -c '(include "../example.lisp") (print (fact 1000))' ./build/ml -f debug.lisp ``` diff --git a/debug.lsp b/debug.lsp index e2610db..d641707 100644 --- a/debug.lsp +++ b/debug.lsp @@ -46,4 +46,12 @@ (print (and (print "xx") (= 1 0) (print "yy"))) +(defun aa () (do + (print "prvni") + (+ 1 xx) + (print "druhy") +)) + +(aa) + ; (sleep 1.5) \ No newline at end of file diff --git a/ml.cpp b/ml.cpp index 7af1322..b07f556 100644 --- a/ml.cpp +++ b/ml.cpp @@ -51,10 +51,10 @@ // Convert an object to a string using a string stream conveniently -#if __APPLE_ -#define to_string(x) static_cast((std::ostringstream() << std::dec << x )).str() -#elif __linux +#if __linux #define to_string(x) static_cast((std::ostringstream() << std::dec << x )).str() +#else +#define to_string(x) static_cast((std::ostringstream() << std::dec << x )).str() #endif // Is this character a valid lisp symbol character @@ -624,7 +624,8 @@ MlError::~MlError() { std::string MlError::description() { // return "error: the expression `" + cause->debug() + "` failed in scope " + to_string(env) + " with message \"" + msg + "\""; - return "error: the expression `" + cause->debug() + "` with message \"" + msg + "\""; + return MlPerfMon::instance().callstack() + + "error: the expression `" + cause->debug() + "` with message \"" + msg + "\""; } void MlEnvironment::combine(MlEnvironment const &other) { @@ -693,6 +694,7 @@ MlValue MlValue::apply(std::vector args, MlEnvironment &env) { MlValue MlValue::eval(MlEnvironment &env) { std::vector args; MlValue function; + MlValue res; MlEnvironment e; switch (type) { case QUOTE: @@ -715,11 +717,10 @@ MlValue MlValue::eval(MlEnvironment &env) { args[i] = args[i].eval(env); MlPerfMon::instance().add_method_call(function.type == LAMBDA ? "lambda" : function.str); + res = function.apply( args, env ); + MlPerfMon::instance().end_method_call(); - return function.apply( - args, - env - ); + return res; default: return *this; @@ -1015,7 +1016,7 @@ namespace builtin { eval_args(args, env); std::exit(args.size() < 1 ? 0 : args[0].cast_to_int().as_int()); - return MlValue(); + return MlValue(); // will not be called :-) } // Print several values and return the last one @@ -1557,7 +1558,7 @@ namespace builtin { if (args.size() != 2) throw MlError(MlValue("string-split", string_split), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS); - // TODO more efficient + // TODO do it more efficient std::vector elements = regexp_strsplit(args[0].as_string(), args[1].as_string()); std::vector result{}; @@ -1970,7 +1971,7 @@ int main(int argc, char *argv[]) { } catch (MlError &e) { std::cerr << e.description() << std::endl; } catch (std::runtime_error &e) { - std::cerr << e.what() << std::endl; + std::cerr << MlPerfMon::instance().callstack() << e.what() << std::endl; } return 1; diff --git a/ml_profiler.cpp b/ml_profiler.cpp index d333d69..50cc81e 100644 --- a/ml_profiler.cpp +++ b/ml_profiler.cpp @@ -2,9 +2,10 @@ #include "ml_profiler.h" #include +#include +// for linux gcc #include #include -#include using namespace std::chrono; @@ -15,6 +16,8 @@ void MlPerfMon::turnOn() { } void MlPerfMon::add_method_call(const std::string &method) { + call_stack.push_back(method); + if (perfOn) { auto search = calls_counter.find(method); if (search != calls_counter.end()) { @@ -25,6 +28,25 @@ void MlPerfMon::add_method_call(const std::string &method) { } } +void MlPerfMon::end_method_call() { + if (!call_stack.empty()){ + call_stack.pop_back(); + } +} + +std::string MlPerfMon::callstack() const { + std::string cs {"call 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"); +} + void MlPerfMon::print_results() { if (perfOn) { std::chrono::time_point end_time = std::chrono::high_resolution_clock::now(); diff --git a/ml_profiler.h b/ml_profiler.h index 042c780..5fefa47 100644 --- a/ml_profiler.h +++ b/ml_profiler.h @@ -3,10 +3,12 @@ #include "ml.h" #include +#include #include static const int method_name_print_len = 15; static const int print_top_methods = 15; +static const int call_stack_max_methods = 10; class MlPerfMon { @@ -24,10 +26,13 @@ public: void turnOn(); void add_method_call(const std::string &method); + void end_method_call(); + std::string callstack() const; void print_results(); private: bool perfOn; std::unordered_map calls_counter; std::chrono::time_point start_time; + std::deque call_stack; };