Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
profiling.cpp
Go to the documentation of this file.
1
14#include <cassert>
15#include <chrono>
16#include <cstdio>
17#include <ctime>
18#include <list>
19#include <stdexcept>
20#include <vector>
21
25
26#ifndef NO_PROCPS
27#include <proc/readproc.h>
28#endif
29
30namespace libff {
31
32long long get_nsec_time()
33{
34 auto timepoint = std::chrono::high_resolution_clock::now();
35 return std::chrono::duration_cast<std::chrono::nanoseconds>(timepoint.time_since_epoch()).count();
36}
37
38/* Return total CPU time consumsed by all threads of the process, in nanoseconds. */
40{
41#if _MSC_VER
42 return 0;
43#else
44 ::timespec ts;
45 if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) )
46 throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed");
47 // If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef .
48 //TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__?
49 return ts.tv_sec * 1000000000ll + ts.tv_nsec;
50#endif
51}
52
55
57{
58 printf("Reset time counters for profiling\n");
59
62}
63
64std::map<std::string, size_t> invocation_counts;
65std::map<std::string, long long> enter_times;
66std::map<std::string, long long> last_times;
67std::map<std::string, long long> cumulative_times;
68//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map
69std::map<std::string, long long> enter_cpu_times;
70std::map<std::string, long long> last_cpu_times;
71std::map<std::pair<std::string, std::string>, long long> op_counts;
72std::map<std::pair<std::string, std::string>, long long> cumulative_op_counts; // ((msg, data_point), value)
73 // TODO: Convert op_counts and cumulative_op_counts from pair to structs
74size_t indentation = 0;
75
76std::vector<std::string> block_names;
77
78std::list<std::pair<std::string, long long*> > op_data_points = {
79#ifdef PROFILE_OP_COUNTS
80 std::make_pair("Fradd", &Fr<default_ec_pp>::add_cnt),
81 std::make_pair("Frsub", &Fr<default_ec_pp>::sub_cnt),
82 std::make_pair("Frmul", &Fr<default_ec_pp>::mul_cnt),
83 std::make_pair("Frinv", &Fr<default_ec_pp>::inv_cnt),
84 std::make_pair("Fqadd", &Fq<default_ec_pp>::add_cnt),
85 std::make_pair("Fqsub", &Fq<default_ec_pp>::sub_cnt),
86 std::make_pair("Fqmul", &Fq<default_ec_pp>::mul_cnt),
87 std::make_pair("Fqinv", &Fq<default_ec_pp>::inv_cnt),
88 std::make_pair("G1add", &G1<default_ec_pp>::add_cnt),
89 std::make_pair("G1dbl", &G1<default_ec_pp>::dbl_cnt),
90 std::make_pair("G2add", &G2<default_ec_pp>::add_cnt),
91 std::make_pair("G2dbl", &G2<default_ec_pp>::dbl_cnt)
92#endif
93};
94
97
99{
100 invocation_counts.clear();
101 last_times.clear();
102 last_cpu_times.clear();
103 cumulative_times.clear();
104}
105
106void print_cumulative_time_entry(const std::string &key, const long long factor)
107{
108 const double total_ms = (cumulative_times.at(key) * 1e-6);
109 const size_t cnt = invocation_counts.at(key);
110 const double avg_ms = total_ms / cnt;
111 printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor);
112}
113
114void print_cumulative_times(const long long factor)
115{
116 printf("Dumping times:\n");
117 for (auto& kv : cumulative_times)
118 {
119 print_cumulative_time_entry(kv.first, factor);
120 }
121}
122
123void print_cumulative_op_counts(const bool only_fq)
124{
125#ifdef PROFILE_OP_COUNTS
126 printf("Dumping operation counts:\n");
127 for (auto& msg : invocation_counts)
128 {
129 printf(" %-45s: ", msg.first.c_str());
130 bool first = true;
131 for (auto& data_point : op_data_points)
132 {
133 if (only_fq && data_point.first.compare(0, 2, "Fq") != 0)
134 {
135 continue;
136 }
137
138 if (!first)
139 {
140 printf(", ");
141 }
142 printf("%-5s = %7.0f (%3zu)",
143 data_point.first.c_str(),
144 1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second,
145 msg.second);
146 first = false;
147 }
148 printf("\n");
149 }
150#else
151 UNUSED(only_fq);
152#endif
153}
154
155void print_op_profiling(const std::string &msg)
156{
157#ifdef PROFILE_OP_COUNTS
158 printf("\n");
159 print_indent();
160
161 printf("(opcounts) = (");
162 bool first = true;
163 for (std::pair<std::string, long long*> p : op_data_points)
164 {
165 if (!first)
166 {
167 printf(", ");
168 }
169
170 printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]);
171 first = false;
172 }
173 printf(")");
174#else
175 UNUSED(msg);
176#endif
177}
178
179static void print_times_from_last_and_start(long long now, long long last,
180 long long cpu_now, long long cpu_last)
181{
182 long long time_from_start = now - start_time;
183 long long time_from_last = now - last;
184
185 long long cpu_time_from_start = cpu_now - start_cpu_time;
186 long long cpu_time_from_last = cpu_now - cpu_last;
187
188 if (time_from_last != 0) {
189 double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last;
190 printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last);
191 } else {
192 printf("[ ]");
193 }
194 if (time_from_start != 0) {
195 double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start;
196 printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start);
197 }
198}
199
200void print_time(const char* msg)
201{
203 {
204 return;
205 }
206
207 long long now = get_nsec_time();
208 long long cpu_now = get_nsec_cpu_time();
209
210 printf("%-35s\t", msg);
211 print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time);
212#ifdef PROFILE_OP_COUNTS
214#endif
215 printf("\n");
216
217 fflush(stdout);
218 last_time = now;
219 last_cpu_time = cpu_now;
220}
221
222void print_header(const char *msg)
223{
224 printf("\n================================================================================\n");
225 printf("%s\n", msg);
226 printf("================================================================================\n\n");
227}
228
230{
231 for (size_t i = 0; i < indentation; ++i)
232 {
233 printf(" ");
234 }
235}
236
237void op_profiling_enter(const std::string &msg)
238{
239 for (std::pair<std::string, long long*> p : op_data_points)
240 {
241 op_counts[std::make_pair(msg, p.first)] = *(p.second);
242 }
243}
244
245void enter_block(const std::string &msg, const bool indent)
246{
248 {
249 return;
250 }
251
252 block_names.emplace_back(msg);
253 long long t = get_nsec_time();
254 enter_times[msg] = t;
255 long long cpu_t = get_nsec_cpu_time();
256 enter_cpu_times[msg] = cpu_t;
257
259 {
260 return;
261 }
262
263#ifdef MULTICORE
264#pragma omp critical
265#endif
266 {
268
269 print_indent();
270 printf("(enter) %-35s\t", msg.c_str());
271 print_times_from_last_and_start(t, t, cpu_t, cpu_t);
272 printf("\n");
273 fflush(stdout);
274
275 if (indent)
276 {
277 ++indentation;
278 }
279 }
280}
281
282void leave_block(const std::string &msg, const bool indent)
283{
285 {
286 return;
287 }
288
289#ifndef MULTICORE
290 assert(*(--block_names.end()) == msg);
291#endif
292 block_names.pop_back();
293
294 ++invocation_counts[msg];
295
296 long long t = get_nsec_time();
297 last_times[msg] = (t - enter_times[msg]);
298 cumulative_times[msg] += (t - enter_times[msg]);
299
300 long long cpu_t = get_nsec_cpu_time();
301 last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]);
302
303#ifdef PROFILE_OP_COUNTS
304 for (std::pair<std::string, long long*> p : op_data_points)
305 {
306 cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)];
307 }
308#endif
309
311 {
312 return;
313 }
314
315#ifdef MULTICORE
316#pragma omp critical
317#endif
318 {
319 if (indent)
320 {
321 --indentation;
322 }
323
324 print_indent();
325 printf("(leave) %-35s\t", msg.c_str());
326 print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]);
328 printf("\n");
329 fflush(stdout);
330 }
331}
332
333void print_mem(const std::string &s)
334{
335#ifndef NO_PROCPS
336 struct proc_t usage;
337 look_up_our_self(&usage);
338 if (s.empty())
339 {
340 printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20);
341 }
342 else
343 {
344 printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20);
345 }
346#else
347 printf("* Memory profiling not supported in NO_PROCPS mode\n");
348#endif
349}
350
352{
353#ifdef __GNUC__
354 printf("g++ version: %s\n", __VERSION__);
355 printf("Compiled on %s %s\n", __DATE__, __TIME__);
356#endif
357#ifdef STATIC
358 printf("STATIC: yes\n");
359#else
360 printf("STATIC: no\n");
361#endif
362#ifdef MULTICORE
363 printf("MULTICORE: yes\n");
364#else
365 printf("MULTICORE: no\n");
366#endif
367#ifdef DEBUG
368 printf("DEBUG: yes\n");
369#else
370 printf("DEBUG: no\n");
371#endif
372#ifdef PROFILE_OP_COUNTS
373 printf("PROFILE_OP_COUNTS: yes\n");
374#else
375 printf("PROFILE_OP_COUNTS: no\n");
376#endif
377#ifdef _GLIBCXX_DEBUG
378 printf("_GLIBCXX_DEBUG: yes\n");
379#else
380 printf("_GLIBCXX_DEBUG: no\n");
381#endif
382}
383
384} // libff
const mie::Vuint & p
Definition bn.cpp:27
LOGGING_API void printf(Category category, const char *format,...)
Definition Logging.cpp:30
typename EC_ppT::Fq_type Fq
void clear_profiling_counters()
Definition profiling.cpp:98
std::map< std::string, size_t > invocation_counts
Definition profiling.cpp:64
typename EC_ppT::G1_type G1
long long last_cpu_time
Definition profiling.cpp:54
std::map< std::string, long long > last_cpu_times
Definition profiling.cpp:70
void print_mem(const std::string &s)
long long start_cpu_time
Definition profiling.cpp:54
std::map< std::string, long long > cumulative_times
Definition profiling.cpp:67
void start_profiling()
Definition profiling.cpp:56
typename EC_ppT::Fp_type Fr
std::map< std::pair< std::string, std::string >, long long > cumulative_op_counts
Definition profiling.cpp:72
void print_cumulative_op_counts(const bool only_fq)
long long last_time
Definition profiling.cpp:53
void print_time(const char *msg)
std::vector< std::string > block_names
Definition profiling.cpp:76
std::map< std::string, long long > enter_times
Definition profiling.cpp:65
void print_header(const char *msg)
void enter_block(const std::string &msg, const bool indent)
void print_cumulative_time_entry(const std::string &key, const long long factor)
void print_op_profiling(const std::string &msg)
long long get_nsec_time()
Definition profiling.cpp:32
void op_profiling_enter(const std::string &msg)
bool inhibit_profiling_info
Definition profiling.cpp:95
std::map< std::pair< std::string, std::string >, long long > op_counts
Definition profiling.cpp:71
std::list< std::pair< std::string, long long * > > op_data_points
Definition profiling.cpp:78
void print_cumulative_times(const long long factor)
std::map< std::string, long long > last_times
Definition profiling.cpp:66
bool inhibit_profiling_counters
Definition profiling.cpp:96
void leave_block(const std::string &msg, const bool indent)
void print_compilation_info()
long long get_nsec_cpu_time()
Definition profiling.cpp:39
std::map< std::string, long long > enter_cpu_times
Definition profiling.cpp:69
size_t indentation
Definition profiling.cpp:74
long long start_time
Definition profiling.cpp:53
void print_indent()
char * s
#define UNUSED(x)