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