HILA
Loading...
Searching...
No Matches
timing.cpp
1
2#include <time.h>
3#include <chrono>
4
5#include "defs.h"
6
7//////////////////////////////////////////////////////////////////
8// Time related routines (runtime - timing - timelimit)
9// Check timing.h for details
10//////////////////////////////////////////////////////////////////
11
12#include "com_mpi.h"
13
14namespace hila {
15
16// This stores the start time of the program
17static double start_time = -1.0;
18
19/////////////////////////////////////////////////////////////////
20/// Timer routines - for high-resolution event timing
21/////////////////////////////////////////////////////////////////
22
23// store all timers in use
24std::vector<timer *> timer_list = {};
25
26// initialize timer to this timepoint
27void timer::init(const char *tag) {
28 if (tag != nullptr)
29 label = tag;
30 reset();
31 // Store it on 1st use!
32}
33
34// remove the timer also from the list
35void timer::remove() {
36 for (auto it = timer_list.begin(); it != timer_list.end(); ++it) {
37 if (*it == this) {
38 timer_list.erase(it);
39 return;
40 }
41 }
42}
43
44void timer::reset() {
45 t_start = t_total = 0.0;
46 count = 0;
47 is_on = is_error = false;
48}
49
50void timer::error() {
51 if (!is_error) {
52 hila::out0 << " **** Timer '" << label
53 << "' error, unbalanced start/stop. Removing from statistics\n";
54 }
55 is_error = true;
56}
57
58double timer::start() {
59 if (is_on)
60 error();
61 is_on = true;
62
63 // Move storing the timer ptr here, because if timer is initialized
64 // in the global scope the timer_list is possibly initialized later!
65 if (count == 0) {
66 timer_list.push_back(this);
67 }
68
69#ifdef GPU_SYNCHRONIZE_TIMERS
70 gpuStreamSynchronize(0);
71#endif
72
73 t_start = hila::gettime();
74 return t_start;
75}
76
77double timer::stop() {
78 if (!is_on)
79 error();
80 is_on = false;
81
82#ifdef GPU_SYNCHRONIZE_TIMERS
83 gpuStreamSynchronize(0);
84#endif
85
86 double e = hila::gettime();
87 t_total += (e - t_start);
88 count++;
89 return e;
90}
91
92timer_value timer::value() {
93 timer_value r;
94 r.time = t_total;
95 r.count = count;
96 return r;
97}
98
99void timer::report(bool print_not_timed) {
100 if (hila::myrank() == 0) {
101 char line[202];
102
103 // time used during the counter activity
104 double ttime = gettime();
105 if (count > 0 && !is_error) {
106 if (t_total / count > 0.1) {
107 std::snprintf(line, 200, "%-20s: %14.3f %14ld %10.3f s %8.4f\n", label.c_str(),
108 t_total, (long)count, t_total / count, t_total / ttime);
109 } else if (t_total / count > 1e-4) {
110 std::snprintf(line, 200, "%-20s: %14.3f %14ld %10.3f ms %8.4f\n", label.c_str(),
111 t_total, (long)count, 1e3 * t_total / count, t_total / ttime);
112 } else {
113 std::snprintf(line, 200, "%-20s: %14.3f %14ld %10.3f μs %8.4f\n", label.c_str(),
114 t_total, (long)count, 1e6 * t_total / count, t_total / ttime);
115 }
116 hila::out << line;
117 } else if (!is_error && print_not_timed) {
118 std::snprintf(line, 200, "%-20s: no timed calls made\n", label.c_str());
119 hila::out << line;
120 } else if (is_error) {
121 std::snprintf(line, 200, "%-20s: error:unbalanced start/stop\n", label.c_str());
122 hila::out << line;
123 }
124 }
125}
126
127void report_timers() {
128 if (hila::myrank() == 0) {
129 if (timer_list.size() > 0) {
130
131#if defined(CUDA) || defined(HIP)
132#if defined(GPU_SYNCHRONIZE_TIMERS)
133 hila::out << "TIMERS: synchronized to GPU kernel execution (GPU_SYNCHRONIZE_TIMERS "
134 "defined)\n";
135#else
136 hila::out << "TIMERS: GPU_SYNCHRONIZE_TIMERS not defined, fine-grained timing "
137 "likely to be incorrect\n";
138#endif
139#endif
140
141 hila::out << "TIMER REPORT: total(sec) calls "
142 "time/call fraction\n";
143 hila::out << "------------------------------------------------------------"
144 "---------------\n";
145
146 for (auto tp : timer_list) {
147 tp->report();
148 }
149
150 hila::out << "------------------------------------------------------------"
151 "---------------\n";
152 } else {
153 hila::out << "No timers defined\n";
154 }
155 }
156}
157
158/////////////////////////////////////////////////////////////////
159/// Use clock_gettime() to get the accurate time
160/// (alternative: use gettimeofday() or MPI_Wtime())
161/// gettime returns the time in secs since program start
162
163double gettime() {
164 struct timespec tp;
165
166 if (start_time == -1.0)
167 inittime();
168
169 clock_gettime(CLOCK_MONOTONIC, &tp);
170 return (((double)tp.tv_sec - start_time) + 1.0e-9 * (double)tp.tv_nsec);
171}
172
173void inittime() {
174 if (start_time == -1.0) {
175 start_time = 0.0;
176 start_time = gettime();
177 }
178}
179
180//////////////////////////////////////////////////////////////////
181/// Routines for checking remaining cpu-time
182/// time_to_exit() is called periodically on a point where exit can be done.
183/// It uses the max of the time intervals for the estimate for one further round.
184/// If not enough time returns true, else false
185///
186
187static double timelimit = 0;
188
189void setup_timelimit(long seconds) {
190 timelimit = (double)seconds;
191}
192
193bool time_to_exit() {
194 static double max_interval = 0.0;
195 static double previous_time = 0.0;
196 bool finish;
197
198 // if no time limit set
199 if (timelimit == 0.0)
200 return false;
201
202 if (hila::myrank() == 0) {
203 double this_time = gettime();
204 if (this_time - previous_time > max_interval)
205 max_interval = this_time - previous_time;
206 previous_time = this_time;
207
208 // Give 5 min margin for the exit - perhaps needed for writing etc.
209 if (timelimit - this_time < max_interval + 5 * 60.0)
210 finish = true;
211 else
212 finish = false;
213
214 hila::out << "TIMECHECK: " << this_time << "s used, " << timelimit - this_time
215 << "s remaining\n";
216 if (finish)
217 hila::out << "CPU TIME LIMIT, EXITING THE PROGRAM\n";
218 }
219 hila::broadcast(finish);
220 return finish;
221}
222
223/*****************************************************
224 * Time stamp
225 */
226
227void timestamp(const char *msg) {
228 if (hila::myrank() == 0) {
229 int p = hila::out0.precision();
230 std::time_t ct = std::time(NULL);
231 if (msg != NULL)
232 hila::out << msg;
233 std::string d = ctime(&ct);
234 d.resize(d.size() - 1); // take away \n at the end
235 hila::out0 << " -- date " << d << " run time " << std::setprecision(4) << hila::gettime()
236 << "s" << std::endl;
237 hila::out0.precision(p);
238 hila::out0.flush();
239 }
240}
241
242void timestamp(const std::string &msg) {
243 hila::timestamp(msg.c_str());
244}
245
246} // namespace hila
This file defines all includes for HILA.
Implement hila::swap for gauge fields.
Definition array.h:981
int myrank()
rank of this node
Definition com_mpi.cpp:235
std::ostream out
this is our default output file stream
std::ostream out0
This writes output only from main process (node 0)
T broadcast(T &var, int rank=0)
Broadcast the value of var to all MPI ranks from rank (default=0).
Definition com_mpi.h:153
double gettime()
Definition timing.cpp:163
std::vector< timer * > timer_list
Timer routines - for high-resolution event timing.
Definition timing.cpp:24