diff --git a/amalgamate.py b/amalgamate.py index 865e272b..0dd8dd34 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -60,7 +60,8 @@ for seq in pipeline: text += remove_copied_include(f.read()) + '\n' copied.add(j) -with open("amalgamated/pocketpy.h", "wt", encoding='utf-8') as f: +# use LF line endings instead of CRLF +with open("amalgamated/pocketpy.h", "wt", encoding='utf-8', newline='\n') as f: final_text = \ r'''/* * Copyright (c) 2023 blueloveTH @@ -77,7 +78,7 @@ shutil.copy("src2/main.cpp", "amalgamated/main.cpp") with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f: text = f.read() text = text.replace('#include "pocketpy/pocketpy.h"', '#include "pocketpy.h"') -with open("amalgamated/main.cpp", "wt", encoding='utf-8') as f: +with open("amalgamated/main.cpp", "wt", encoding='utf-8', newline='\n') as f: f.write(text) if sys.platform in ['linux', 'darwin']: @@ -89,7 +90,7 @@ print("amalgamated/pocketpy.h") def sync(path): shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h")) - with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8') as f: + with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8', newline='\n') as f: f.write("#include \"pocketpy.h\"\n") sync("plugins/macos/pocketpy") diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index 4f7c5701..2db27667 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -127,4 +127,12 @@ struct Frame { } }; +struct FrameId{ + std::vector* data; + int index; + FrameId(std::vector* data, int index) : data(data), index(index) {} + Frame* operator->() const { return &data->operator[](index); } + Frame* get() const { return &data->operator[](index); } +}; + }; // namespace pkpy \ No newline at end of file diff --git a/include/pocketpy/profiler.h b/include/pocketpy/profiler.h index c76e4e43..fe2ddb4c 100644 --- a/include/pocketpy/profiler.h +++ b/include/pocketpy/profiler.h @@ -13,19 +13,22 @@ struct LineRecord{ bool is_valid() const { return line != -1; } }; -struct LineProfiler{ +struct FrameRecord{ + FrameId frame; clock_t prev_time; LineRecord* prev_record; int prev_line; +}; +struct LineProfiler{ // filename -> records std::map> records; - + stack frames; std::set functions; void begin(); - void _step(Frame* frame); - void _step_end(); + void _step(FrameId frame); + void _step_end(FrameId frame); void end(); Str stats(); }; diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 9c3691db..654622e2 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -105,14 +105,6 @@ struct PyTypeInfo{ }; -struct FrameId{ - std::vector* data; - int index; - FrameId(std::vector* data, int index) : data(data), index(index) {} - Frame* operator->() const { return &data->operator[](index); } - Frame* get() const { return &data->operator[](index); } -}; - typedef void(*PrintFunc)(const char*, int); class VM { diff --git a/prebuild.py b/prebuild.py index 6d697620..b33391b6 100644 --- a/prebuild.py +++ b/prebuild.py @@ -36,5 +36,6 @@ namespace pkpy{ ''' return header -with open("include/pocketpy/_generated.h", "w", encoding='utf-8') as f: +# use LF line endings instead of CRLF +with open("include/pocketpy/_generated.h", "wt", encoding='utf-8', newline='\n') as f: f.write(generate_python_sources()) diff --git a/scripts/genstub.py b/scripts/genstub.py index 6283d4d4..39237b49 100644 --- a/scripts/genstub.py +++ b/scripts/genstub.py @@ -25,7 +25,8 @@ for line in lines: ret + ' ' + body + ' {\n' + mock_string + '\n}\n' ) -with open('src2/pocketpy_c.c', 'w') as f: +# use LF line endings instead of CRLF +with open('src2/pocketpy_c.c', 'wt', encoding='utf-8', newline='\n') as f: f.write(''' #include "pocketpy_c.h" diff --git a/src/ceval.cpp b/src/ceval.cpp index 973bccaf..9776df50 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -68,7 +68,7 @@ PyObject* VM::_run_top_frame(){ #define CEVAL_STEP_CALLBACK() \ if(_ceval_on_step) _ceval_on_step(this, frame.get(), byte); \ - if(_profiler) _profiler->_step(frame.get()); + if(_profiler) _profiler->_step(frame); #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; } __NEXT_FRAME: diff --git a/src/profiler.cpp b/src/profiler.cpp index d152d88b..3c541fd3 100644 --- a/src/profiler.cpp +++ b/src/profiler.cpp @@ -15,47 +15,75 @@ static std::string to_string_1f(f64 x){ } void LineProfiler::begin(){ - prev_time = 0; - prev_record = nullptr; - prev_line = -1; - records.clear(); + frames.clear(); } -void LineProfiler::_step(Frame *frame){ +void LineProfiler::_step(FrameId frame){ std::string_view filename = frame->co->src->filename.sv(); int line = frame->co->lines[frame->_ip]; - // std::string_view function = frame->co->name.sv(); - if(prev_record == nullptr){ - prev_time = clock(); + if(frames.empty()){ + frames.push({frame, clock(), nullptr, -1}); }else{ - _step_end(); + _step_end(frame); } std::vector& file_records = records[filename]; if(file_records.empty()){ + // initialize file_records int total_lines = frame->co->src->line_starts.size(); file_records.resize(total_lines + 1); for(int i=1; i<=total_lines; i++){ file_records[i].line = i; } } - prev_record = &file_records.at(line); + + frames.top().prev_record = &file_records.at(line); } -void LineProfiler::_step_end(){ +void LineProfiler::_step_end(FrameId frame){ clock_t now = clock(); - clock_t delta = now - prev_time; - prev_time = now; - if(prev_record->line != prev_line){ + FrameRecord& top_frame_record = frames.top(); + LineRecord* prev_record = top_frame_record.prev_record; + + if(prev_record->line != top_frame_record.prev_line){ prev_record->hits++; - prev_line = prev_record->line; + top_frame_record.prev_line = prev_record->line; + } + + int id_delta = frame.index - top_frame_record.frame.index; + PK_ASSERT(id_delta >= -1 && id_delta <= 1); + + if(id_delta == 1){ + frames.push({frame, now, nullptr, -1}); + }else{ + clock_t delta = now - top_frame_record.prev_time; + top_frame_record.prev_time = now; + prev_record->time += delta; + if(id_delta == -1){ + frames.pop(); + prev_record = frames.top().prev_record; + prev_record->time += (now - frames.top().prev_time); + } } - prev_record->time += delta; } void LineProfiler::end(){ - _step_end(); + clock_t now = clock(); + FrameRecord& top_frame_record = frames.top(); + LineRecord* prev_record = top_frame_record.prev_record; + + if(prev_record->line != top_frame_record.prev_line){ + prev_record->hits++; + top_frame_record.prev_line = prev_record->line; + } + + clock_t delta = now - top_frame_record.prev_time; + top_frame_record.prev_time = now; + prev_record->time += delta; + + frames.pop(); + PK_ASSERT(frames.empty()); } Str LineProfiler::stats(){ diff --git a/tests/84_line_profiler.py b/tests/84_line_profiler.py index 7e864940..0d7edd71 100644 --- a/tests/84_line_profiler.py +++ b/tests/84_line_profiler.py @@ -1,15 +1,24 @@ from line_profiler import LineProfiler -def my_func(): +def f2(x): a = 0 - for i in range(1000000): + for i in range(x): a += i return a +def f1(x): + res = f2(x) + return res + lp = LineProfiler() -lp.add_function(my_func) - -lp.runcall(my_func) +lp.add_function(f2) +lp.runcall(f2, 1000000) lp.print_stats() +############################### + +lp.add_function(f1) +lp.runcall(f1, 1000000) +lp.print_stats() +