callstack added

This commit is contained in:
VaclavT 2021-04-09 00:07:20 +02:00
parent 5afa7dd69f
commit 9ab0a2c98d
5 changed files with 72 additions and 27 deletions

View File

@ -7,19 +7,28 @@
### TODO ### TODO
- replace to_string macro in ml.cpp
- add debug support, at least call stack - add debug support, at least call stack
- documentation
- add url of source/inspiration to clib/*.cpp
- add stdtest - to test every functionality - 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) - multiline editing (kilo editor)
- execute system command should capture stderr - execute system command should capture stderr
- add some mem stats to benchmark - 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 - support for (), nil, t, in lsp code replace 0 by nil in logicals
- file functions - file functions
- name it here - open file
- read line
- write line
- close file
- string functions - string functions
- itok - integer to char, chartoint (better names) - mini printf can be useed for it (%d)
- compare - needed for sorting, cmp ignore case - compare - needed for sorting, cmp ignore case
- regexp functions - regexp functions
- date support - date support
@ -31,7 +40,6 @@
- mapcar (funcall, apply) - mapcar (funcall, apply)
- syntax highlighting do VS Code - syntax highlighting do VS Code
- add hash datatype - add hash datatype
- create pastebin like web using ml
#### Performance #### Performance
- define is one of most frequent callee, when in scope with very few vars, lookup sequentially - 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 - mini_sprintf - unnecesary copying between vector and list
- (do, scope ..) repeatedly assign to acc - (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 #### Install
``` ```
cp build/ml /usr/local/bin/ml cp build/ml /usr/local/bin/ml
cp stdlib/*.lsp /usr/local/var/mlisp/ 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 ### Example of use
``` ```
time ./build/ml -c '(include "../example.lisp") (print (fact 1000))'
./build/ml -f debug.lisp ./build/ml -f debug.lisp
``` ```

View File

@ -46,4 +46,12 @@
(print (and (print "xx") (= 1 0) (print "yy"))) (print (and (print "xx") (= 1 0) (print "yy")))
(defun aa () (do
(print "prvni")
(+ 1 xx)
(print "druhy")
))
(aa)
; (sleep 1.5) ; (sleep 1.5)

23
ml.cpp
View File

@ -51,10 +51,10 @@
// Convert an object to a string using a string stream conveniently // Convert an object to a string using a string stream conveniently
#if __APPLE_ #if __linux
#define to_string(x) static_cast<std::ostringstream>((std::ostringstream() << std::dec << x )).str()
#elif __linux
#define to_string(x) static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x )).str() #define to_string(x) static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x )).str()
#else
#define to_string(x) static_cast<std::ostringstream>((std::ostringstream() << std::dec << x )).str()
#endif #endif
// Is this character a valid lisp symbol character // Is this character a valid lisp symbol character
@ -624,7 +624,8 @@ MlError::~MlError() {
std::string MlError::description() { 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() + "` 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) { void MlEnvironment::combine(MlEnvironment const &other) {
@ -693,6 +694,7 @@ MlValue MlValue::apply(std::vector<MlValue> args, MlEnvironment &env) {
MlValue MlValue::eval(MlEnvironment &env) { MlValue MlValue::eval(MlEnvironment &env) {
std::vector<MlValue> args; std::vector<MlValue> args;
MlValue function; MlValue function;
MlValue res;
MlEnvironment e; MlEnvironment e;
switch (type) { switch (type) {
case QUOTE: case QUOTE:
@ -715,11 +717,10 @@ MlValue MlValue::eval(MlEnvironment &env) {
args[i] = args[i].eval(env); args[i] = args[i].eval(env);
MlPerfMon::instance().add_method_call(function.type == LAMBDA ? "lambda" : function.str); MlPerfMon::instance().add_method_call(function.type == LAMBDA ? "lambda" : function.str);
res = function.apply( args, env );
MlPerfMon::instance().end_method_call();
return function.apply( return res;
args,
env
);
default: default:
return *this; return *this;
@ -1015,7 +1016,7 @@ namespace builtin {
eval_args(args, env); eval_args(args, env);
std::exit(args.size() < 1 ? 0 : args[0].cast_to_int().as_int()); 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 // Print several values and return the last one
@ -1557,7 +1558,7 @@ namespace builtin {
if (args.size() != 2) if (args.size() != 2)
throw MlError(MlValue("string-split", string_split), env, args.size() > 2 ? TOO_MANY_ARGS : TOO_FEW_ARGS); 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<std::string> elements = regexp_strsplit(args[0].as_string(), args[1].as_string()); std::vector<std::string> elements = regexp_strsplit(args[0].as_string(), args[1].as_string());
std::vector<MlValue> result{}; std::vector<MlValue> result{};
@ -1970,7 +1971,7 @@ int main(int argc, char *argv[]) {
} catch (MlError &e) { } catch (MlError &e) {
std::cerr << e.description() << std::endl; std::cerr << e.description() << std::endl;
} catch (std::runtime_error &e) { } catch (std::runtime_error &e) {
std::cerr << e.what() << std::endl; std::cerr << MlPerfMon::instance().callstack() << e.what() << std::endl;
} }
return 1; return 1;

View File

@ -2,9 +2,10 @@
#include "ml_profiler.h" #include "ml_profiler.h"
#include <iostream> #include <iostream>
#include <algorithm>
// for linux gcc
#include <iomanip> #include <iomanip>
#include <numeric> #include <numeric>
#include <algorithm>
using namespace std::chrono; using namespace std::chrono;
@ -15,6 +16,8 @@ void MlPerfMon::turnOn() {
} }
void MlPerfMon::add_method_call(const std::string &method) { void MlPerfMon::add_method_call(const std::string &method) {
call_stack.push_back(method);
if (perfOn) { if (perfOn) {
auto search = calls_counter.find(method); auto search = calls_counter.find(method);
if (search != calls_counter.end()) { 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() { void MlPerfMon::print_results() {
if (perfOn) { if (perfOn) {
std::chrono::time_point<std::chrono::high_resolution_clock> end_time = std::chrono::high_resolution_clock::now(); std::chrono::time_point<std::chrono::high_resolution_clock> end_time = std::chrono::high_resolution_clock::now();

View File

@ -3,10 +3,12 @@
#include "ml.h" #include "ml.h"
#include <unordered_map> #include <unordered_map>
#include <deque>
#include <chrono> #include <chrono>
static const int method_name_print_len = 15; static const int method_name_print_len = 15;
static const int print_top_methods = 15; static const int print_top_methods = 15;
static const int call_stack_max_methods = 10;
class MlPerfMon { class MlPerfMon {
@ -24,10 +26,13 @@ public:
void turnOn(); void turnOn();
void add_method_call(const std::string &method); void add_method_call(const std::string &method);
void end_method_call();
std::string callstack() const;
void print_results(); void print_results();
private: private:
bool perfOn; bool perfOn;
std::unordered_map<std::string, long> calls_counter; std::unordered_map<std::string, long> calls_counter;
std::chrono::time_point<std::chrono::high_resolution_clock> start_time; std::chrono::time_point<std::chrono::high_resolution_clock> start_time;
std::deque<std::string> call_stack;
}; };