forked from xxq250/Nasal-Interpreter
✨ add profiling tools in debug mode
This commit is contained in:
@@ -1,5 +1,94 @@
|
||||
#include "nasal_dbg.h"
|
||||
|
||||
void debug_prof_data::init_counter() {
|
||||
for(usize i = 0; i<debug_prof_data::operand_size; ++i) {
|
||||
operand_counter[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void debug_prof_data::load_file_line_counter(
|
||||
const std::vector<std::string>& file_list) {
|
||||
file_name_list = file_list;
|
||||
file_line_counter = {};
|
||||
file_contents = {};
|
||||
flstream fs;
|
||||
for(usize i =0; i<file_list.size(); ++i) {
|
||||
fs.load(file_list[i]);
|
||||
file_contents.push_back(fs.file_content());
|
||||
file_line_counter.push_back({});
|
||||
file_line_counter.back().resize(fs.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void debug_prof_data::init(const std::vector<std::string>& file_list) {
|
||||
init_counter();
|
||||
load_file_line_counter(file_list);
|
||||
}
|
||||
|
||||
void debug_prof_data::dump_counter() const {
|
||||
typedef std::pair<u32, u64> op_count;
|
||||
std::vector<op_count> opcall;
|
||||
u64 total = 0;
|
||||
for(usize i = 0; i<debug_prof_data::operand_size; ++i) {
|
||||
total += operand_counter[i];
|
||||
opcall.push_back({i, operand_counter[i]});
|
||||
}
|
||||
std::sort(opcall.begin(), opcall.end(),
|
||||
[](const op_count& a, const op_count& b) {
|
||||
return a.second>b.second;
|
||||
}
|
||||
);
|
||||
std::clog << "\noperands call info (<1% ignored)\n";
|
||||
for(const auto& i : opcall) {
|
||||
u64 rate = i.second*100/total;
|
||||
if (!rate) {
|
||||
break;
|
||||
}
|
||||
std::clog << " " << opname[i.first] << " : ";
|
||||
std::clog << i.second << " (" << rate << "%)\n";
|
||||
}
|
||||
std::clog << " total : " << total << '\n';
|
||||
}
|
||||
|
||||
void debug_prof_data::dump_code_line_counter(std::ostream& os) const {
|
||||
u64 max_call_time = 0;
|
||||
for(const auto& context : file_line_counter) {
|
||||
for(const auto& count : context) {
|
||||
max_call_time = count>max_call_time? count:max_call_time;
|
||||
}
|
||||
}
|
||||
auto pad_length = std::to_string(max_call_time).length();
|
||||
for(usize i = 0; i<file_name_list.size(); ++i) {
|
||||
os << "\ncode profiling data of " << file_name_list[i] << ":\n";
|
||||
const auto& context = file_contents[i];
|
||||
const auto& counter = file_line_counter[i];
|
||||
for(usize j = 0; j<context.size(); ++j) {
|
||||
os << " " << std::right << std::setw(pad_length);
|
||||
os << std::setfill(' ');
|
||||
os << (counter[j]==0? "":std::to_string(counter[j]));
|
||||
os << " " << context[j] << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void debug_prof_data::dump_this_file_line_counter(std::ostream& os) const {
|
||||
u64 max_call_time = 0;
|
||||
for(const auto& count : file_line_counter[0]) {
|
||||
max_call_time = count>max_call_time? count:max_call_time;
|
||||
}
|
||||
auto pad_length = std::to_string(max_call_time).length();
|
||||
|
||||
os << "\ncode profiling data of " << file_name_list[0] << ":\n";
|
||||
const auto& context = file_contents[0];
|
||||
const auto& counter = file_line_counter[0];
|
||||
for(usize i = 0; i<context.size(); ++i) {
|
||||
os << " " << std::right << std::setw(pad_length);
|
||||
os << std::setfill(' ');
|
||||
os << (counter[i]==0? "":std::to_string(counter[i]));
|
||||
os << " " << context[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> dbg::parse(const std::string& cmd) {
|
||||
std::vector<std::string> res;
|
||||
usize last = 0, pos = cmd.find(" ", 0);
|
||||
@@ -55,29 +144,6 @@ void dbg::list_file() const {
|
||||
}
|
||||
}
|
||||
|
||||
void dbg::call_sort(const u64* arr) const {
|
||||
typedef std::pair<u32,u64> op;
|
||||
std::vector<op> opcall;
|
||||
u64 total = 0;
|
||||
for(u32 i = 0; i<op_ret+1; ++i) {
|
||||
total += arr[i];
|
||||
opcall.push_back({i, arr[i]});
|
||||
}
|
||||
std::sort(opcall.begin(), opcall.end(),
|
||||
[](const op& a, const op& b) {return a.second>b.second;}
|
||||
);
|
||||
std::clog << "\noperands call info (<1% ignored)\n";
|
||||
for(auto& i : opcall) {
|
||||
u64 rate = i.second*100/total;
|
||||
if (!rate) {
|
||||
break;
|
||||
}
|
||||
std::clog << " " << opname[i.first] << " : ";
|
||||
std::clog << i.second << " (" << rate << "%)\n";
|
||||
}
|
||||
std::clog << " total : " << total << '\n';
|
||||
}
|
||||
|
||||
void dbg::step_info() {
|
||||
u32 line = bytecode[ctx.pc].line==0? 0:bytecode[ctx.pc].line-1;
|
||||
u32 begin = (line>>3)==0? 0:((line>>3)<<3);
|
||||
@@ -108,6 +174,11 @@ void dbg::interact() {
|
||||
if (bytecode[ctx.pc].op==op_exit) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do not need interact while doing profiling
|
||||
if (do_profiling) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bytecode[ctx.pc].fidx!=bk_fidx ||
|
||||
bytecode[ctx.pc].line!=bk_line) && // break point
|
||||
@@ -161,75 +232,45 @@ void dbg::interact() {
|
||||
void dbg::run(
|
||||
const codegen& gen,
|
||||
const linker& linker,
|
||||
const std::vector<std::string>& argv) {
|
||||
const std::vector<std::string>& argv,
|
||||
bool profile,
|
||||
bool show_all_prof_result) {
|
||||
verbose = true;
|
||||
fsize = linker.filelist().size();
|
||||
do_profiling = profile || show_all_prof_result;
|
||||
|
||||
const auto& file_list = linker.get_file_list();
|
||||
fsize = file_list.size();
|
||||
init(gen.strs(), gen.nums(), gen.natives(),
|
||||
gen.codes(), gen.globals(), linker.filelist(), argv);
|
||||
u64 count[op_ret+1] = {0};
|
||||
typedef void (dbg::*nafunc)();
|
||||
const nafunc oprs[] = {
|
||||
nullptr, &dbg::o_intg,
|
||||
&dbg::o_intl, &dbg::o_loadg,
|
||||
&dbg::o_loadl, &dbg::o_loadu,
|
||||
&dbg::o_pnum, &dbg::o_pnil,
|
||||
&dbg::o_pstr, &dbg::o_newv,
|
||||
&dbg::o_newh, &dbg::o_newf,
|
||||
&dbg::o_happ, &dbg::o_para,
|
||||
&dbg::o_deft, &dbg::o_dyn,
|
||||
&dbg::o_lnot, &dbg::o_usub,
|
||||
&dbg::o_bnot, &dbg::o_btor,
|
||||
&dbg::o_btxor, &dbg::o_btand,
|
||||
&dbg::o_add, &dbg::o_sub,
|
||||
&dbg::o_mul, &dbg::o_div,
|
||||
&dbg::o_lnk, &dbg::o_addc,
|
||||
&dbg::o_subc, &dbg::o_mulc,
|
||||
&dbg::o_divc, &dbg::o_lnkc,
|
||||
&dbg::o_addeq, &dbg::o_subeq,
|
||||
&dbg::o_muleq, &dbg::o_diveq,
|
||||
&dbg::o_lnkeq, &dbg::o_bandeq,
|
||||
&dbg::o_boreq, &dbg::o_bxoreq,
|
||||
&dbg::o_addeqc, &dbg::o_subeqc,
|
||||
&dbg::o_muleqc, &dbg::o_diveqc,
|
||||
&dbg::o_lnkeqc, &dbg::o_addecp,
|
||||
&dbg::o_subecp, &dbg::o_mulecp,
|
||||
&dbg::o_divecp, &dbg::o_lnkecp,
|
||||
&dbg::o_meq, &dbg::o_eq,
|
||||
&dbg::o_neq, &dbg::o_less,
|
||||
&dbg::o_leq, &dbg::o_grt,
|
||||
&dbg::o_geq, &dbg::o_lessc,
|
||||
&dbg::o_leqc, &dbg::o_grtc,
|
||||
&dbg::o_geqc, &dbg::o_pop,
|
||||
&dbg::o_jmp, &dbg::o_jt,
|
||||
&dbg::o_jf, &dbg::o_cnt,
|
||||
&dbg::o_findex, &dbg::o_feach,
|
||||
&dbg::o_callg, &dbg::o_calll,
|
||||
&dbg::o_upval, &dbg::o_callv,
|
||||
&dbg::o_callvi, &dbg::o_callh,
|
||||
&dbg::o_callfv, &dbg::o_callfh,
|
||||
&dbg::o_callb, &dbg::o_slcbeg,
|
||||
&dbg::o_slcend, &dbg::o_slc,
|
||||
&dbg::o_slc2, &dbg::o_mcallg,
|
||||
&dbg::o_mcalll, &dbg::o_mupval,
|
||||
&dbg::o_mcallv, &dbg::o_mcallh,
|
||||
&dbg::o_ret
|
||||
};
|
||||
gen.codes(), gen.globals(),
|
||||
file_list, argv);
|
||||
data.init(file_list);
|
||||
|
||||
std::vector<u32> code;
|
||||
std::vector<u16> code_file_index;
|
||||
std::vector<u32> code_line;
|
||||
for(auto& i : gen.codes()) {
|
||||
code.push_back(i.op);
|
||||
code_file_index.push_back(i.fidx);
|
||||
code_line.push_back(i.line);
|
||||
imm.push_back(i.num);
|
||||
}
|
||||
while(oprs[code[ctx.pc]]) {
|
||||
while(operand_function[code[ctx.pc]]) {
|
||||
interact();
|
||||
++count[code[ctx.pc]];
|
||||
(this->*oprs[code[ctx.pc]])();
|
||||
data.add_operand_counter(code[ctx.pc]);
|
||||
data.add_code_line_counter(code_file_index[ctx.pc], code_line[ctx.pc]);
|
||||
(this->*operand_function[code[ctx.pc]])();
|
||||
if (ctx.top>=ctx.canary) {
|
||||
die("stack overflow");
|
||||
}
|
||||
++ctx.pc;
|
||||
}
|
||||
|
||||
call_sort(count);
|
||||
data.dump_counter();
|
||||
if (do_profiling) {
|
||||
show_all_prof_result?
|
||||
data.dump_code_line_counter(std::clog):
|
||||
data.dump_this_file_line_counter(std::clog);
|
||||
}
|
||||
ngc.info();
|
||||
ngc.clear();
|
||||
imm.clear();
|
||||
|
||||
Reference in New Issue
Block a user