Coverage for pySDC/core/timings.py: 100%
96 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
1import time
2from pySDC.core.hooks import Hooks
5class Timings(Hooks):
6 """
7 Abstract base class for hooks timing the setup, run, predictor, steps, iterations, sweeps and communication.
9 Attributes:
10 __t0_setup (float): private variable to get starting time of setup
11 __t0_run (float): private variable to get starting time of the run
12 __t0_predict (float): private variable to get starting time of the predictor
13 __t0_step (float): private variable to get starting time of the step
14 __t0_iteration (float): private variable to get starting time of the iteration
15 __t0_sweep (float): private variable to get starting time of the sweep
16 __t0_comm (list): private variable to get starting time of the communication
17 __t1_run (float): private variable to get end time of the run
18 __t1_predict (float): private variable to get end time of the predictor
19 __t1_step (float): private variable to get end time of the step
20 __t1_iteration (float): private variable to get end time of the iteration
21 __t1_sweep (float): private variable to get end time of the sweep
22 __t1_setup (float): private variable to get end time of setup
23 __t1_comm (list): private variable to hold timing of the communication (!)
24 """
26 prefix = ''
28 def _compute_time_elapsed(self, event_after, event_before):
29 raise NotImplementedError
31 def _get_event(self):
32 raise NotImplementedError
34 def __init__(self):
35 """Start with all start and end times unset."""
36 super().__init__()
37 self.__t0_setup = None
38 self.__t0_run = None
39 self.__t0_predict = None
40 self.__t0_step = None
41 self.__t0_iteration = None
42 self.__t0_sweep = None
43 self.__t0_comm = []
44 self.__t1_run = None
45 self.__t1_predict = None
46 self.__t1_step = None
47 self.__t1_iteration = None
48 self.__t1_sweep = None
49 self.__t1_setup = None
50 self.__t1_comm = []
52 def pre_setup(self, step, level_number):
53 """
54 Default routine called before setup starts
56 Args:
57 step (pySDC.Step.step): the current step
58 level_number (int): the current level number
59 """
60 super().pre_setup(step, level_number)
61 self.__t0_setup = self._get_event()
63 def pre_run(self, step, level_number):
64 """
65 Default routine called before time-loop starts
67 Args:
68 step (pySDC.Step.step): the current step
69 level_number (int): the current level number
70 """
71 super().pre_run(step, level_number)
72 self.__t0_run = self._get_event()
74 def pre_predict(self, step, level_number):
75 """
76 Default routine called before predictor starts
78 Args:
79 step (pySDC.Step.step): the current step
80 level_number (int): the current level number
81 """
82 super().pre_predict(step, level_number)
83 self.__t0_predict = self._get_event()
85 def pre_step(self, step, level_number):
86 """
87 Hook called before each step
89 Args:
90 step (pySDC.Step.step): the current step
91 level_number (int): the current level number
92 """
93 super().pre_step(step, level_number)
94 self.__t0_step = self._get_event()
96 def pre_iteration(self, step, level_number):
97 """
98 Default routine called before iteration starts
100 Args:
101 step (pySDC.Step.step): the current step
102 level_number (int): the current level number
103 """
104 super().pre_iteration(step, level_number)
105 self.__t0_iteration = self._get_event()
107 def pre_sweep(self, step, level_number):
108 """
109 Default routine called before sweep starts
111 Args:
112 step (pySDC.Step.step): the current step
113 level_number (int): the current level number
114 """
115 super().pre_sweep(step, level_number)
116 self.__t0_sweep = self._get_event()
118 def pre_comm(self, step, level_number):
119 """
120 Default routine called before communication starts
122 Args:
123 step (pySDC.Step.step): the current step
124 level_number (int): the current level number
125 """
126 super().pre_comm(step, level_number)
127 if len(self.__t0_comm) >= level_number + 1:
128 self.__t0_comm[level_number] = self._get_event()
129 else:
130 while len(self.__t0_comm) < level_number:
131 self.__t0_comm.append(None)
132 self.__t0_comm.append(self._get_event())
133 while len(self.__t1_comm) <= level_number:
134 self.__t1_comm.append(0.0)
135 assert len(self.__t0_comm) == level_number + 1
136 assert len(self.__t1_comm) == level_number + 1
138 def post_comm(self, step, level_number, add_to_stats=False):
139 """
140 Default routine called after each communication
142 Args:
143 step (pySDC.Step.step): the current step
144 level_number (int): the current level number
145 add_to_stats (bool): set if result should go to stats object
146 """
147 super().post_comm(step, level_number)
148 assert len(self.__t1_comm) >= level_number + 1
149 self.__t1_comm[level_number] += self._compute_time_elapsed(self._get_event(), self.__t0_comm[level_number])
151 if add_to_stats:
152 L = step.levels[level_number]
154 self.add_to_stats(
155 process=step.status.slot,
156 process_sweeper=L.sweep.rank,
157 time=L.time,
158 level=L.level_index,
159 iter=step.status.iter,
160 sweep=L.status.sweep,
161 type=f'{self.prefix}timing_comm',
162 value=self.__t1_comm[level_number],
163 )
164 self.__t1_comm[level_number] = 0.0
166 def post_sweep(self, step, level_number):
167 """
168 Default routine called after each sweep
170 Args:
171 step (pySDC.Step.step): the current step
172 level_number (int): the current level number
173 """
174 super().post_sweep(step, level_number)
175 self.__t1_sweep = self._get_event()
177 L = step.levels[level_number]
179 self.add_to_stats(
180 process=step.status.slot,
181 process_sweeper=L.sweep.rank,
182 time=L.time,
183 level=L.level_index,
184 iter=step.status.iter,
185 sweep=L.status.sweep,
186 type=f'{self.prefix}timing_sweep',
187 value=self._compute_time_elapsed(self.__t1_sweep, self.__t0_sweep),
188 )
190 def post_iteration(self, step, level_number):
191 """
192 Default routine called after each iteration
194 Args:
195 step (pySDC.Step.step): the current step
196 level_number (int): the current level number
197 """
198 super().post_iteration(step, level_number)
199 self.__t1_iteration = self._get_event()
201 L = step.levels[level_number]
203 self.add_to_stats(
204 process=step.status.slot,
205 process_sweeper=L.sweep.rank,
206 time=L.time,
207 level=L.level_index,
208 iter=step.status.iter,
209 sweep=L.status.sweep,
210 type=f'{self.prefix}timing_iteration',
211 value=self._compute_time_elapsed(self.__t1_iteration, self.__t0_iteration),
212 )
214 def post_step(self, step, level_number):
215 """
216 Default routine called after each step or block
218 Args:
219 step (pySDC.Step.step): the current step
220 level_number (int): the current level number
221 """
222 super().post_step(step, level_number)
223 self.__t1_step = self._get_event()
225 L = step.levels[level_number]
227 self.add_to_stats(
228 process=step.status.slot,
229 process_sweeper=L.sweep.rank,
230 time=L.time,
231 level=L.level_index,
232 iter=step.status.iter,
233 sweep=L.status.sweep,
234 type=f'{self.prefix}timing_step',
235 value=self._compute_time_elapsed(self.__t1_step, self.__t0_step),
236 )
238 def post_predict(self, step, level_number):
239 """
240 Default routine called after each predictor
242 Args:
243 step (pySDC.Step.step): the current step
244 level_number (int): the current level number
245 """
246 super().post_predict(step, level_number)
247 self.__t1_predict = self._get_event()
249 L = step.levels[level_number]
251 self.add_to_stats(
252 process=step.status.slot,
253 process_sweeper=L.sweep.rank,
254 time=L.time,
255 level=L.level_index,
256 iter=step.status.iter,
257 sweep=L.status.sweep,
258 type=f'{self.prefix}timing_predictor',
259 value=self._compute_time_elapsed(self.__t1_predict, self.__t0_predict),
260 )
262 def post_run(self, step, level_number):
263 """
264 Default routine called after each run
266 Args:
267 step (pySDC.Step.step): the current step
268 level_number (int): the current level number
269 """
270 super().post_run(step, level_number)
271 self.__t1_run = self._get_event()
272 t_run = self._compute_time_elapsed(self.__t1_run, self.__t0_run)
274 L = step.levels[level_number]
276 self.add_to_stats(
277 process=step.status.slot,
278 process_sweeper=L.sweep.rank,
279 time=L.time,
280 level=L.level_index,
281 iter=step.status.iter,
282 sweep=L.status.sweep,
283 type=f'{self.prefix}timing_run',
284 value=t_run,
285 )
286 if step.status.first:
287 self.logger.info(f'Finished run after {t_run:.2e}s')
289 def post_setup(self, step, level_number):
290 """
291 Default routine called after setup
293 Args:
294 step (pySDC.Step.step): the current step
295 level_number (int): the current level number
296 """
297 super().post_setup(step, level_number)
298 self.__t1_setup = self._get_event()
300 self.add_to_stats(
301 process=-1,
302 process_sweeper=-1,
303 time=-1,
304 level=-1,
305 iter=-1,
306 sweep=-1,
307 type=f'{self.prefix}timing_setup',
308 value=self._compute_time_elapsed(self.__t1_setup, self.__t0_setup),
309 )
312class CPUTimings(Timings):
313 """
314 Hook for recording CPU timings of important operations during a pySDC run.
315 """
317 def _compute_time_elapsed(self, event_after, event_before):
318 return event_after - event_before
320 def _get_event(self):
321 return time.perf_counter()