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'
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")

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

View File

@ -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<std::string_view, std::vector<LineRecord>> records;
stack<FrameRecord> frames;
std::set<FuncDecl*> functions;
void begin();
void _step(Frame* frame);
void _step_end();
void _step(FrameId frame);
void _step_end(FrameId frame);
void end();
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);
class VM {

View File

@ -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())

View File

@ -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"

View File

@ -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:

View File

@ -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<LineRecord>& 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);
}
}
}
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(){

View File

@ -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()