profiler.cpp 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #include "pocketpy/profiler.h"
  2. namespace pkpy{
  3. static std::string left_pad(std::string s, int width){
  4. int n = width - s.size();
  5. if(n <= 0) return s;
  6. return std::string(n, ' ') + s;
  7. }
  8. static std::string to_string_1f(f64 x){
  9. char buf[32];
  10. snprintf(buf, 32, "%.1f", x);
  11. return buf;
  12. }
  13. std::string_view LineRecord::line_content() const {
  14. auto [_0, _1] = src->_get_line(line);
  15. return std::string_view(_0, _1-_0);
  16. }
  17. void LineProfiler::begin(){
  18. prev_time = 0;
  19. prev_record = nullptr;
  20. prev_line = -1;
  21. records.clear();
  22. }
  23. void LineProfiler::_step(Frame *frame){
  24. std::string_view filename = frame->co->src->filename.sv();
  25. int line = frame->co->lines[frame->_ip];
  26. // std::string_view function = frame->co->name.sv();
  27. if(prev_record == nullptr){
  28. prev_time = clock();
  29. }else{
  30. _step_end();
  31. }
  32. std::vector<LineRecord>& file_records = records[filename];
  33. if(file_records.empty()) file_records.resize(frame->co->src->line_starts.size() + 10);
  34. prev_record = &file_records[line];
  35. if(!prev_record->is_valid()){
  36. prev_record->line = line;
  37. prev_record->src = frame->co->src.get();
  38. }
  39. }
  40. void LineProfiler::_step_end(){
  41. clock_t now = clock();
  42. clock_t delta = now - prev_time;
  43. prev_time = now;
  44. if(prev_record->line != prev_line){
  45. prev_record->hits++;
  46. prev_line = prev_record->line;
  47. }
  48. prev_record->time += delta;
  49. }
  50. void LineProfiler::end(){
  51. _step_end();
  52. }
  53. Str LineProfiler::stats(){
  54. SStream ss;
  55. for(auto& [filename, file_records] : records){
  56. clock_t total_time = 0;
  57. for(auto& record: file_records){
  58. if(record.is_valid()) total_time += record.time;
  59. }
  60. ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
  61. ss << "File: " << filename << "\n";
  62. // ss << "Function: " << "<?>" << "at line " << -1 << "\n";
  63. ss << "Line # Hits Time Per Hit % Time Line Contents\n";
  64. ss << "==============================================================\n";
  65. for(int line = 1; line < file_records.size(); line++){
  66. LineRecord& record = file_records[line];
  67. if(!record.is_valid()) continue;
  68. ss << left_pad(std::to_string(line), 6);
  69. ss << left_pad(std::to_string(record.hits), 10);
  70. ss << left_pad(std::to_string(record.time), 13);
  71. ss << left_pad(std::to_string(record.time / record.hits), 9);
  72. ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
  73. ss << " " << record.line_content() << "\n";
  74. }
  75. ss << "\n";
  76. }
  77. return ss.str();
  78. }
  79. } // namespace pkpy