|
30 | 30 | #ifndef CPP2_COMMON_H
|
31 | 31 | #define CPP2_COMMON_H
|
32 | 32 |
|
33 |
| -#include <string> |
34 |
| -#include <string_view> |
35 |
| -#include <vector> |
36 |
| -#include <cstdint> |
37 |
| -#include <cctype> |
| 33 | +#include <algorithm> |
38 | 34 | #include <cassert>
|
39 |
| -#include <iomanip> |
| 35 | +#include <cctype> |
| 36 | +#include <chrono> |
40 | 37 | #include <compare>
|
41 |
| -#include <algorithm> |
| 38 | +#include <cstdint> |
| 39 | +#include <iomanip> |
| 40 | +#include <map> |
| 41 | +#include <string> |
| 42 | +#include <string_view> |
42 | 43 | #include <unordered_map>
|
| 44 | +#include <vector> |
43 | 45 |
|
44 | 46 | namespace cpp2 {
|
45 | 47 |
|
@@ -971,6 +973,14 @@ struct error_entry
|
971 | 973 | //-----------------------------------------------------------------------
|
972 | 974 | //
|
973 | 975 |
|
| 976 | +//----------------------------------------------------------------------- |
| 977 | +// |
| 978 | +// stackinstr: builds debug information to find causes of large stacks |
| 979 | +// |
| 980 | +// Useful if we need to optimize deep recursion to use less stack |
| 981 | +// |
| 982 | +//----------------------------------------------------------------------- |
| 983 | +// |
974 | 984 | class stackinstr
|
975 | 985 | {
|
976 | 986 | struct entry
|
@@ -1045,6 +1055,137 @@ std::vector<stackinstr::entry> stackinstr::largest;
|
1045 | 1055 | #define STACKINSTR stackinstr::guard _s_guard{ __func__, __FILE__, __LINE__, reinterpret_cast<char*>(&_s_guard) };
|
1046 | 1056 |
|
1047 | 1057 |
|
| 1058 | +//----------------------------------------------------------------------- |
| 1059 | +// |
| 1060 | +// timer: a little profiling timer to measure time spent in |
| 1061 | +// specific sections of code |
| 1062 | +// |
| 1063 | +// This is a tool for cppfront developers to measure the run-time of |
| 1064 | +// specific parts of cppfront code. |
| 1065 | +// |
| 1066 | +// Do still use a profiler too. But once you know where to measure, |
| 1067 | +// this has some advantages: |
| 1068 | +// |
| 1069 | +// - Precise: It's easy to accurately measure specific parts of |
| 1070 | +// code across the run of the program, not relying on sampling to |
| 1071 | +// representatively hit those regions |
| 1072 | +// |
| 1073 | +// - Flexible: You can have as many timers as you want, each with |
| 1074 | +// a clearly readable name, including nested timers (see example |
| 1075 | +// below) |
| 1076 | +// |
| 1077 | +// - Portable: It's part of cppfront itself, no separate tool needed |
| 1078 | +// |
| 1079 | +// - Integrated: Reports are printed automatically by -verbose |
| 1080 | +// |
| 1081 | +// Usage guide |
| 1082 | +// ----------- |
| 1083 | +// |
| 1084 | +// To measure the total time spent in a specific section of code, create |
| 1085 | +// a scope_timer guard object in that scope and give it a readable |
| 1086 | +// string name that will remind you what it's measuring. |
| 1087 | +// |
| 1088 | +// Example: Today I wanted to measure how long get_declaration_of is |
| 1089 | +// taking. So add this line at the start of that function's body: |
| 1090 | +// |
| 1091 | +// auto guard = scope_timer("get_declaration_of"); |
| 1092 | +// |
| 1093 | +// Recompile cppfront, then run with -verbose: |
| 1094 | +// |
| 1095 | +// cppfront pure2-last-use.cpp2 -p -verb |
| 1096 | +// |
| 1097 | +// Sample output: |
| 1098 | +// |
| 1099 | +// pure2-last-use.cpp2... ok (all Cpp2, passes safety checks) |
| 1100 | +// Cpp1 0 lines |
| 1101 | +// Cpp2 1,050 lines (100%) |
| 1102 | +// Time 1,629 ms |
| 1103 | +// 1,120 ms in get_declaration_of |
| 1104 | +// |
| 1105 | +// The first "Time:" is the total run time of the compiland. It is then |
| 1106 | +// followed by any active scope_timer names, in alphabetical order |
| 1107 | +// (you can choose names so that related timers appear together). |
| 1108 | +// |
| 1109 | +// Here, this one function is taking most of the total runtime. It |
| 1110 | +// consists of two major loops, one run before the other, so we can |
| 1111 | +// measure the cost of each part, using names that will be |
| 1112 | +// reported together and in understandable order with -verbose: |
| 1113 | +// |
| 1114 | +// - The function's first loop is to find a starting point, so |
| 1115 | +// enclose that in { } with a scope_timer: |
| 1116 | +// |
| 1117 | +// { |
| 1118 | +// auto guard = scope_timer("get_declaration_of step 1, initial find loop"); |
| 1119 | +// /* the code I want to measure */ |
| 1120 | +// } |
| 1121 | +// |
| 1122 | +// - Immediately after that, install a second timer to measure the |
| 1123 | +// second loop which covers the entire rest of the function body: |
| 1124 | +// |
| 1125 | +// auto guard2 = scope_timer("get_declaration_of step 2, rest of lookup"); |
| 1126 | +// /* followed by the rest of the function's body */ |
| 1127 | +// |
| 1128 | +// - And, since it's easy, throw in a third timer to measure one |
| 1129 | +// sub-part of the step 2 loop... right before the 'move this' |
| 1130 | +// branch we can add this to measure the time spent in oly that |
| 1131 | +// trailing 1/3 of each loop iteration (starting and stopping the |
| 1132 | +// timer at those points in each loop iteration to measure just |
| 1133 | +// the sum of all those loop fragments): |
| 1134 | +// |
| 1135 | +// auto guard = scope_timer("get_declaration_of step 2b, 'move this' branch"); |
| 1136 | +// |
| 1137 | +// Recompile cppfront and run again with -verbose... sample output: |
| 1138 | +// |
| 1139 | +// pure2-last-use.cpp2... ok (all Cpp2, passes safety checks) |
| 1140 | +// Cpp1 0 lines |
| 1141 | +// Cpp2 1,050 lines (100%) |
| 1142 | +// Time 1,471 ms |
| 1143 | +// 1,139 ms in get_declaration_of |
| 1144 | +// 540 ms in get_declaration_of step 1, initial find loop |
| 1145 | +// 567 ms in get_declaration_of step 2, rest of lookup |
| 1146 | +// 148 ms in get_declaration_of step 2b, 'move this' branch |
| 1147 | +// |
| 1148 | +//----------------------------------------------------------------------- |
| 1149 | +// |
| 1150 | +class timer |
| 1151 | +{ |
| 1152 | + using clock = std::chrono::high_resolution_clock; |
| 1153 | + |
| 1154 | + bool running = false; |
| 1155 | + std::chrono::time_point<clock> start_tm = clock::now(); |
| 1156 | + std::chrono::duration<double> duration = {}; |
| 1157 | + |
| 1158 | +public: |
| 1159 | + auto start() { |
| 1160 | + testing.enforce( !running ); |
| 1161 | + running = true; |
| 1162 | + start_tm = clock::now(); |
| 1163 | + } |
| 1164 | + |
| 1165 | + auto stop() { |
| 1166 | + testing.enforce( running ); |
| 1167 | + running = false; |
| 1168 | + duration += clock::now() - start_tm; |
| 1169 | + } |
| 1170 | + |
| 1171 | + void reset() { |
| 1172 | + duration = {}; |
| 1173 | + } |
| 1174 | + |
| 1175 | + auto elapsed() const { |
| 1176 | + testing.enforce( !running ); |
| 1177 | + return std::chrono::duration_cast<std::chrono::milliseconds>(duration); |
| 1178 | + } |
| 1179 | +}; |
| 1180 | + |
| 1181 | +static std::map<std::string, timer> timers; // global named timers |
| 1182 | + |
| 1183 | +auto scope_timer(std::string const& name) { |
| 1184 | + timers[name].start(); |
| 1185 | + return finally( [=]{ timers[name].stop(); } ); |
| 1186 | +} |
| 1187 | + |
| 1188 | + |
1048 | 1189 | }
|
1049 | 1190 |
|
1050 | 1191 | #endif
|
0 commit comments