diff --git a/include/pocketpy/profiler.h b/include/pocketpy/profiler.h index 7231c447..c76e4e43 100644 --- a/include/pocketpy/profiler.h +++ b/include/pocketpy/profiler.h @@ -6,15 +6,11 @@ namespace pkpy { struct LineRecord{ int line; - SourceData* src; - i64 hits; clock_t time; - LineRecord(): line(-1), src(nullptr), hits(0), time(0) {} - - std::string_view line_content() const; - bool is_valid() const { return src != nullptr; } + LineRecord(): line(-1), hits(0), time(0) {} + bool is_valid() const { return line != -1; } }; struct LineProfiler{ @@ -25,6 +21,8 @@ struct LineProfiler{ // filename -> records std::map> records; + std::set functions; + void begin(); void _step(Frame* frame); void _step_end(); diff --git a/src/modules.cpp b/src/modules.cpp index 194b8434..acb08f17 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -262,7 +262,10 @@ struct LineProfilerW{ vm->bind_default_constructor(type); vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args){ - // ... + LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); + vm->check_non_tagged_type(args[1], VM::tp_function); + auto decl = PK_OBJ_GET(Function, args[1]).decl.get(); + self.profiler.functions.insert(decl); return vm->None; }); diff --git a/src/profiler.cpp b/src/profiler.cpp index 569ee7a1..9eb48e6e 100644 --- a/src/profiler.cpp +++ b/src/profiler.cpp @@ -14,11 +14,6 @@ static std::string to_string_1f(f64 x){ return buf; } -std::string_view LineRecord::line_content() const { - auto [_0, _1] = src->_get_line(line); - return std::string_view(_0, _1-_0); -} - void LineProfiler::begin(){ prev_time = 0; prev_record = nullptr; @@ -43,7 +38,6 @@ void LineProfiler::_step(Frame *frame){ file_records.resize(total_lines + 1); for(int i=1; i<=total_lines; i++){ file_records[i].line = i; - file_records[i].src = frame->co->src.get(); } } prev_record = &file_records.at(line); @@ -66,25 +60,33 @@ void LineProfiler::end(){ Str LineProfiler::stats(){ SStream ss; - for(auto& [filename, file_records] : records){ + for(FuncDecl* decl: functions){ + int start_line = decl->code->start_line; + int end_line = decl->code->end_line; + if(start_line == -1 || end_line == -1) continue; + std::string_view filename = decl->code->src->filename.sv(); + std::vector& file_records = records[filename]; + if(file_records.empty()) continue; clock_t total_time = 0; - for(auto& record: file_records){ - if(record.is_valid()) total_time += record.time; + for(int line = start_line; line <= end_line; line++){ + total_time += file_records.at(line).time; } ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n"; ss << "File: " << filename << "\n"; - // ss << "Function: " << "" << "at line " << -1 << "\n"; + ss << "Function: " << decl->code->name << " at line " << start_line << "\n"; ss << "Line # Hits Time Per Hit % Time Line Contents\n"; ss << "==============================================================\n"; - for(int line = 1; line < file_records.size(); line++){ - LineRecord& record = file_records[line]; - if(!record.is_valid() || record.hits == 0) continue; + for(int line = start_line; line <= end_line; line++){ + const LineRecord& record = file_records.at(line); + if(!record.is_valid()) continue; ss << left_pad(std::to_string(line), 6); ss << left_pad(std::to_string(record.hits), 10); - ss << left_pad(std::to_string(record.time), 13); + ss << left_pad(std::to_string(record.time / CLOCKS_PER_SEC), 13); ss << left_pad(std::to_string(record.time / record.hits), 9); ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9); - ss << " " << record.line_content() << "\n"; + // line_content + auto [_0, _1] = decl->code->src->_get_line(line); + ss << " " << std::string_view(_0, _1-_0) << "\n"; } ss << "\n"; }