fix a bug of line_profiler

This commit is contained in:
blueloveTH 2024-02-17 22:32:30 +08:00
parent 0df619b66f
commit c3b050c77a
9 changed files with 83 additions and 40 deletions

View File

@ -60,7 +60,8 @@ for seq in pipeline:
text += remove_copied_include(f.read()) + '\n' text += remove_copied_include(f.read()) + '\n'
copied.add(j) 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 = \ final_text = \
r'''/* r'''/*
* Copyright (c) 2023 blueloveTH * 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: with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f:
text = f.read() text = f.read()
text = text.replace('#include "pocketpy/pocketpy.h"', '#include "pocketpy.h"') 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) f.write(text)
if sys.platform in ['linux', 'darwin']: if sys.platform in ['linux', 'darwin']:
@ -89,7 +90,7 @@ print("amalgamated/pocketpy.h")
def sync(path): def sync(path):
shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h")) 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") f.write("#include \"pocketpy.h\"\n")
sync("plugins/macos/pocketpy") sync("plugins/macos/pocketpy")

View File

@ -127,4 +127,12 @@ struct Frame {
} }
}; };
struct FrameId{
std::vector<pkpy::Frame>* data;
int index;
FrameId(std::vector<pkpy::Frame>* data, int index) : data(data), index(index) {}
Frame* operator->() const { return &data->operator[](index); }
Frame* get() const { return &data->operator[](index); }
};
}; // namespace pkpy }; // namespace pkpy

View File

@ -13,19 +13,22 @@ struct LineRecord{
bool is_valid() const { return line != -1; } bool is_valid() const { return line != -1; }
}; };
struct LineProfiler{ struct FrameRecord{
FrameId frame;
clock_t prev_time; clock_t prev_time;
LineRecord* prev_record; LineRecord* prev_record;
int prev_line; int prev_line;
};
struct LineProfiler{
// filename -> records // filename -> records
std::map<std::string_view, std::vector<LineRecord>> records; std::map<std::string_view, std::vector<LineRecord>> records;
stack<FrameRecord> frames;
std::set<FuncDecl*> functions; std::set<FuncDecl*> functions;
void begin(); void begin();
void _step(Frame* frame); void _step(FrameId frame);
void _step_end(); void _step_end(FrameId frame);
void end(); void end();
Str stats(); Str stats();
}; };

View File

@ -105,14 +105,6 @@ struct PyTypeInfo{
}; };
struct FrameId{
std::vector<pkpy::Frame>* data;
int index;
FrameId(std::vector<pkpy::Frame>* 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); typedef void(*PrintFunc)(const char*, int);
class VM { class VM {

View File

@ -36,5 +36,6 @@ namespace pkpy{
''' '''
return header 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()) f.write(generate_python_sources())

View File

@ -25,7 +25,8 @@ for line in lines:
ret + ' ' + body + ' {\n' + mock_string + '\n}\n' 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(''' f.write('''
#include "pocketpy_c.h" #include "pocketpy_c.h"

View File

@ -68,7 +68,7 @@ PyObject* VM::_run_top_frame(){
#define CEVAL_STEP_CALLBACK() \ #define CEVAL_STEP_CALLBACK() \
if(_ceval_on_step) _ceval_on_step(this, frame.get(), byte); \ 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; } #define DISPATCH_OP_CALL() { frame = top_frame(); goto __NEXT_FRAME; }
__NEXT_FRAME: __NEXT_FRAME:

View File

@ -15,47 +15,75 @@ static std::string to_string_1f(f64 x){
} }
void LineProfiler::begin(){ void LineProfiler::begin(){
prev_time = 0; frames.clear();
prev_record = nullptr;
prev_line = -1;
records.clear();
} }
void LineProfiler::_step(Frame *frame){ void LineProfiler::_step(FrameId frame){
std::string_view filename = frame->co->src->filename.sv(); std::string_view filename = frame->co->src->filename.sv();
int line = frame->co->lines[frame->_ip]; int line = frame->co->lines[frame->_ip];
// std::string_view function = frame->co->name.sv();
if(prev_record == nullptr){ if(frames.empty()){
prev_time = clock(); frames.push({frame, clock(), nullptr, -1});
}else{ }else{
_step_end(); _step_end(frame);
} }
std::vector<LineRecord>& file_records = records[filename]; std::vector<LineRecord>& file_records = records[filename];
if(file_records.empty()){ if(file_records.empty()){
// initialize file_records
int total_lines = frame->co->src->line_starts.size(); int total_lines = frame->co->src->line_starts.size();
file_records.resize(total_lines + 1); file_records.resize(total_lines + 1);
for(int i=1; i<=total_lines; i++){ for(int i=1; i<=total_lines; i++){
file_records[i].line = 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 now = clock();
clock_t delta = now - prev_time; FrameRecord& top_frame_record = frames.top();
prev_time = now; LineRecord* prev_record = top_frame_record.prev_record;
if(prev_record->line != prev_line){
if(prev_record->line != top_frame_record.prev_line){
prev_record->hits++; 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(){ 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(){ Str LineProfiler::stats(){

View File

@ -1,15 +1,24 @@
from line_profiler import LineProfiler from line_profiler import LineProfiler
def my_func(): def f2(x):
a = 0 a = 0
for i in range(1000000): for i in range(x):
a += i a += i
return a return a
def f1(x):
res = f2(x)
return res
lp = LineProfiler() lp = LineProfiler()
lp.add_function(my_func) lp.add_function(f2)
lp.runcall(my_func)
lp.runcall(f2, 1000000)
lp.print_stats() lp.print_stats()
###############################
lp.add_function(f1)
lp.runcall(f1, 1000000)
lp.print_stats()