Theseus
Compressible flow solver
Loading...
Searching...
No Matches
timer.hpp
Go to the documentation of this file.
1// Copyright (c) 2025-2026 Board of Trustees of the University of Illinois
2//
3// This file is part of Theseus.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6#pragma once
7#include <chrono>
8#include <cstdio>
9#include <mpi.h>
10#ifdef TIMER_SYNC_DEVICE
11#include "mfem.hpp"
12#endif
13#include <algorithm>
14#include <chrono>
15#include <cstdint>
16#include <iomanip>
17#include <iostream>
18
19namespace Theseus
20{
22 {
23 public:
24#ifdef ENABLE_TIMERS
25#ifndef TIMER_SYNC_DEVICE
26 explicit ScopedTimer(const char *name)
27 : name_(name),
28 start_(clock::now())
29 {}
30#else
31 explicit ScopedTimer(const char *name)
32 : name_(name)
33 {
34 MFEM_DEVICE_SYNC;
35 // mfem::Device::Sync();
36 start_ = clock::now();
37 }
38#endif
39
41 {
42#ifdef TIMER_SYNC_DEVICE
43 MFEM_DEVICE_SYNC;
44 // mfem::Device::Sync();
45#endif
46 auto end = clock::now();
47 double local_ms = std::chrono::duration<double, std::milli>(end - start_).count();
48 double global_ms = local_ms;
49 int rank = 0;
50 int nranks = 1;
51 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
52 MPI_Comm_size(MPI_COMM_WORLD, &nranks);
53#ifdef TIMER_BARRIER
54 MPI_Barrier(MPI_COMM_WORLD);
55 end = clock::now();
56 if(rank == 0)
57 MPI_Reduce(MPI_IN_PLACE,&global_ms, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);
58 else
59 MPI_Reduce(&global_ms, NULL, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);
60#endif
61#ifdef TIMER_OUTPUT_ALLRANKS
62 if(nranks > 1 && rank > 0)
63 std::printf("[TIMER(%d)] %s : %.6f ms\n", rank, name_, local_ms);
64#endif
65 if(rank == 0 ){
66 std::printf("[TIMER(%d)] %s : %.6f ms\n", rank, name_, local_ms);
67#ifdef TIMER_BARRIER
68 if(nranks > 1)
69 std::printf("[TIMER(all)] %s : %.6f ms\n", name_, global_ms);
70#endif
71 }
72 }
73#else
74 explicit ScopedTimer(const char *name)
75 : name_(name),
76 start_() {}
78#endif
79 private:
80 using clock = std::chrono::steady_clock;
81 const char *name_;
82 clock::time_point start_;
83 };
84
85
87 {
88 public:
89 using clock = std::chrono::steady_clock;
90
91 explicit TimestepTimer(MPI_Comm comm = MPI_COMM_WORLD)
92 : comm_(comm)
93 {
94 MPI_Comm_rank(comm_, &rank_);
95 MPI_Comm_size(comm_, &nranks_);
96 }
97
98 void Start()
99 {
100 Sync();
101 start_ = clock::now();
102 running_ = true;
103 }
104
105 void Stop()
106 {
107 if (!running_)
108 {
109 return;
110 }
111
112 Sync();
113 const auto stop = clock::now();
114
115 const double elapsed_ms =
116 std::chrono::duration<double, std::milli>(stop - start_).count();
117
118 total_ms_ += elapsed_ms;
119 min_ms_ = std::min(min_ms_, elapsed_ms);
120 max_ms_ = std::max(max_ms_, elapsed_ms);
121 ++count_;
122
123 running_ = false;
124 }
125
126 void Reset()
127 {
128 count_ = 0;
129 total_ms_ = 0.0;
130 min_ms_ = std::numeric_limits<double>::max();
131 max_ms_ = 0.0;
132 running_ = false;
133 }
134
135 std::uint64_t Count() const
136 {
137 return count_;
138 }
139
140 double Total() const
141 {
142 return total_ms_;
143 }
144
145 double Min() const
146 {
147 return count_ > 0 ? min_ms_ : 0.0;
148 }
149
150 double Max() const
151 {
152 return count_ > 0 ? max_ms_ : 0.0;
153 }
154
155 double Mean() const
156 {
157 return count_ > 0 ? total_ms_ / static_cast<double>(count_) : 0.0;
158 }
159
160 void Finalize(std::ostream &os = std::cout) const
161 {
162 //
163 // Local statistics.
164 //
165 const double local_total = Total();
166 const double local_min = Min();
167 const double local_max = Max();
168 const double local_mean = Mean();
169
170 const unsigned long long local_count =
171 static_cast<unsigned long long>(count_);
172
173 //
174 // Count statistics across ranks.
175 //
176 unsigned long long count_min = 0;
177 unsigned long long count_max = 0;
178 unsigned long long count_sum = 0;
179
180 MPI_Reduce(&local_count, &count_min, 1,
181 MPI_UNSIGNED_LONG_LONG, MPI_MIN, 0, comm_);
182
183 MPI_Reduce(&local_count, &count_max, 1,
184 MPI_UNSIGNED_LONG_LONG, MPI_MAX, 0, comm_);
185
186 MPI_Reduce(&local_count, &count_sum, 1,
187 MPI_UNSIGNED_LONG_LONG, MPI_SUM, 0, comm_);
188
189 //
190 // For each local statistic, collect min/max/sum across ranks.
191 //
192 double total_min = 0.0;
193 double total_max = 0.0;
194 double total_sum = 0.0;
195
196 double step_min_min = 0.0;
197 double step_min_max = 0.0;
198 double step_min_sum = 0.0;
199
200 double step_max_min = 0.0;
201 double step_max_max = 0.0;
202 double step_max_sum = 0.0;
203
204 double mean_min = 0.0;
205 double mean_max = 0.0;
206 double mean_sum = 0.0;
207
208 ReduceMinMaxSum(local_total,
209 total_min, total_max, total_sum);
210
211 ReduceMinMaxSum(local_min,
212 step_min_min, step_min_max, step_min_sum);
213
214 ReduceMinMaxSum(local_max,
215 step_max_min, step_max_max, step_max_sum);
216
217 ReduceMinMaxSum(local_mean,
218 mean_min, mean_max, mean_sum);
219
220 if (rank_ != 0)
221 {
222 return;
223 }
224
225 const double inv_nranks = 1.0 / static_cast<double>(nranks_);
226
227 const double count_mean =
228 static_cast<double>(count_sum) * inv_nranks;
229
230 const double total_mean =
231 total_sum * inv_nranks;
232
233 const double step_min_mean =
234 step_min_sum * inv_nranks;
235
236 const double step_max_mean =
237 step_max_sum * inv_nranks;
238
239 const double mean_mean =
240 mean_sum * inv_nranks;
241
242 auto old_flags = os.flags();
243 auto old_precision = os.precision();
244 os << std::fixed << std::setprecision(3);
245 os << "\n"
246 << "========================================================================\n"
247 << "Theseus timestep performance\n"
248 << "========================================================================\n"
249 << "MPI ranks : " << nranks_ << "\n"
250 << "\n"
251 << "Per-rank timestep statistics\n"
252 << " min"
253 << " mean"
254 << " max\n"
255 << " Timed steps : "
256 << std::setw(12) << count_min
257 << std::setw(14) << count_mean
258 << std::setw(14) << count_max << "\n"
259 << " Total time (ms) : "
260 << std::setw(12) << total_min
261 << std::setw(14) << total_mean
262 << std::setw(14) << total_max << "\n"
263 << " Min step (ms) : "
264 << std::setw(12) << step_min_min
265 << std::setw(14) << step_min_mean
266 << std::setw(14) << step_min_max << "\n"
267 << " Mean step (ms) : "
268 << std::setw(12) << mean_min
269 << std::setw(14) << mean_mean
270 << std::setw(14) << mean_max << "\n"
271 << " Max step (ms) : "
272 << std::setw(12) << step_max_min
273 << std::setw(14) << step_max_mean
274 << std::setw(14) << step_max_max << "\n"
275 << "\n"
276 << "Critical-rank performance\n"
277 << " Mean timestep : " << mean_max << " ms\n";
278
279 if (mean_max > 0.0)
280 {
281 os << " Timesteps/sec : "
282 << 1000.0 / mean_max << "\n";
283 }
284
285#ifdef TIMER_SYNC_DEVICE
286 os << " Device sync : enabled\n";
287#else
288 os << " Device sync : disabled\n";
289#endif
290
291#ifdef TIMER_BARRIER
292 os << " MPI barrier : enabled\n";
293#else
294 os << " MPI barrier : disabled\n";
295#endif
296
297 os << "========================================================================\n";
298 os.flags(old_flags);
299 os.precision(old_precision);
300 }
301
302 private:
303 void Sync() const
304 {
305#ifdef TIMER_BARRIER
306 MPI_Barrier(comm_);
307#endif
308
309#ifdef TIMER_SYNC_DEVICE
310 MFEM_DEVICE_SYNC;
311#endif
312 }
313
314 void ReduceMinMaxSum(double local,
315 double &minimum,
316 double &maximum,
317 double &sum) const
318 {
319 MPI_Reduce(&local, &minimum, 1,
320 MPI_DOUBLE, MPI_MIN, 0, comm_);
321
322 MPI_Reduce(&local, &maximum, 1,
323 MPI_DOUBLE, MPI_MAX, 0, comm_);
324
325 MPI_Reduce(&local, &sum, 1,
326 MPI_DOUBLE, MPI_SUM, 0, comm_);
327 }
328
329 MPI_Comm comm_ = MPI_COMM_WORLD;
330 int rank_ = 0;
331 int nranks_ = 1;
332
333 clock::time_point start_;
334
335 std::uint64_t count_ = 0;
336 double total_ms_ = 0.0;
337 double min_ms_ = std::numeric_limits<double>::max();
338 double max_ms_ = 0.0;
339
340 bool running_ = false;
341 };
342}
Definition timer.hpp:22
ScopedTimer(const char *name)
Definition timer.hpp:74
~ScopedTimer()
Definition timer.hpp:77
Definition timer.hpp:87
std::uint64_t Count() const
Definition timer.hpp:135
std::chrono::steady_clock clock
Definition timer.hpp:89
double Max() const
Definition timer.hpp:150
double Min() const
Definition timer.hpp:145
double Total() const
Definition timer.hpp:140
void Finalize(std::ostream &os=std::cout) const
Definition timer.hpp:160
void Reset()
Definition timer.hpp:126
TimestepTimer(MPI_Comm comm=MPI_COMM_WORLD)
Definition timer.hpp:91
void Stop()
Definition timer.hpp:105
void Start()
Definition timer.hpp:98
double Mean() const
Definition timer.hpp:155
Definition AxisymmetricGeometry.hpp:15