Coverage for pySDC/core/timings.py: 100%
96 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-25 20:28 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-25 20:28 +0000
1import time
2from pySDC.core.hooks import Hooks
5class Timings(Hooks):
6 """
7 Abstract base class for recoding timings
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 super().__init__()
36 self.__t0_setup = None
37 self.__t0_run = None
38 self.__t0_predict = None
39 self.__t0_step = None
40 self.__t0_iteration = None
41 self.__t0_sweep = None
42 self.__t0_comm = []
43 self.__t1_run = None
44 self.__t1_predict = None
45 self.__t1_step = None
46 self.__t1_iteration = None
47 self.__t1_sweep = None
48 self.__t1_setup = None
49 self.__t1_comm = []
51 def pre_setup(self, step, level_number):
52 """
53 Default routine called before setup starts
55 Args:
56 step (pySDC.Step.step): the current step
57 level_number (int): the current level number
58 """
59 super().pre_setup(step, level_number)
60 self.__t0_setup = self._get_event()
62 def pre_run(self, step, level_number):
63 """
64 Default routine called before time-loop starts
66 Args:
67 step (pySDC.Step.step): the current step
68 level_number (int): the current level number
69 """
70 super().pre_run(step, level_number)
71 self.__t0_run = self._get_event()
73 def pre_predict(self, step, level_number):
74 """
75 Default routine called before predictor starts
77 Args:
78 step (pySDC.Step.step): the current step
79 level_number (int): the current level number
80 """
81 super().pre_predict(step, level_number)
82 self.__t0_predict = self._get_event()
84 def pre_step(self, step, level_number):
85 """
86 Hook called before each step
88 Args:
89 step (pySDC.Step.step): the current step
90 level_number (int): the current level number
91 """
92 super().pre_step(step, level_number)
93 self.__t0_step = self._get_event()
95 def pre_iteration(self, step, level_number):
96 """
97 Default routine called before iteration starts
99 Args:
100 step (pySDC.Step.step): the current step
101 level_number (int): the current level number
102 """
103 super().pre_iteration(step, level_number)
104 self.__t0_iteration = self._get_event()
106 def pre_sweep(self, step, level_number):
107 """
108 Default routine called before sweep starts
110 Args:
111 step (pySDC.Step.step): the current step
112 level_number (int): the current level number
113 """
114 super().pre_sweep(step, level_number)
115 self.__t0_sweep = self._get_event()
117 def pre_comm(self, step, level_number):
118 """
119 Default routine called before communication starts
121 Args:
122 step (pySDC.Step.step): the current step
123 level_number (int): the current level number
124 """
125 super().pre_comm(step, level_number)
126 if len(self.__t0_comm) >= level_number + 1:
127 self.__t0_comm[level_number] = self._get_event()
128 else:
129 while len(self.__t0_comm) < level_number:
130 self.__t0_comm.append(None)
131 self.__t0_comm.append(self._get_event())
132 while len(self.__t1_comm) <= level_number:
133 self.__t1_comm.append(0.0)
134 assert len(self.__t0_comm) == level_number + 1
135 assert len(self.__t1_comm) == level_number + 1
137 def post_comm(self, step, level_number, add_to_stats=False):
138 """
139 Default routine called after each communication
141 Args:
142 step (pySDC.Step.step): the current step
143 level_number (int): the current level number
144 add_to_stats (bool): set if result should go to stats object
145 """
146 super().post_comm(step, level_number)
147 assert len(self.__t1_comm) >= level_number + 1
148 self.__t1_comm[level_number] += self._compute_time_elapsed(self._get_event(), self.__t0_comm[level_number])
150 if add_to_stats:
151 L = step.levels[level_number]
153 self.add_to_stats(
154 process=step.status.slot,
155 process_sweeper=L.sweep.rank,
156 time=L.time,
157 level=L.level_index,
158 iter=step.status.iter,
159 sweep=L.status.sweep,
160 type=f'{self.prefix}timing_comm',
161 value=self.__t1_comm[level_number],
162 )
163 self.__t1_comm[level_number] = 0.0
165 def post_sweep(self, step, level_number):
166 """
167 Default routine called after each sweep
169 Args:
170 step (pySDC.Step.step): the current step
171 level_number (int): the current level number
172 """
173 super().post_sweep(step, level_number)
174 self.__t1_sweep = self._get_event()
176 L = step.levels[level_number]
178 self.add_to_stats(
179 process=step.status.slot,
180 process_sweeper=L.sweep.rank,
181 time=L.time,
182 level=L.level_index,
183 iter=step.status.iter,
184 sweep=L.status.sweep,
185 type=f'{self.prefix}timing_sweep',
186 value=self._compute_time_elapsed(self.__t1_sweep, self.__t0_sweep),
187 )
189 def post_iteration(self, step, level_number):
190 """
191 Default routine called after each iteration
193 Args:
194 step (pySDC.Step.step): the current step
195 level_number (int): the current level number
196 """
197 super().post_iteration(step, level_number)
198 self.__t1_iteration = self._get_event()
200 L = step.levels[level_number]
202 self.add_to_stats(
203 process=step.status.slot,
204 process_sweeper=L.sweep.rank,
205 time=L.time,
206 level=L.level_index,
207 iter=step.status.iter,
208 sweep=L.status.sweep,
209 type=f'{self.prefix}timing_iteration',
210 value=self._compute_time_elapsed(self.__t1_iteration, self.__t0_iteration),
211 )
213 def post_step(self, step, level_number):
214 """
215 Default routine called after each step or block
217 Args:
218 step (pySDC.Step.step): the current step
219 level_number (int): the current level number
220 """
221 super().post_step(step, level_number)
222 self.__t1_step = self._get_event()
224 L = step.levels[level_number]
226 self.add_to_stats(
227 process=step.status.slot,
228 process_sweeper=L.sweep.rank,
229 time=L.time,
230 level=L.level_index,
231 iter=step.status.iter,
232 sweep=L.status.sweep,
233 type=f'{self.prefix}timing_step',
234 value=self._compute_time_elapsed(self.__t1_step, self.__t0_step),
235 )
237 def post_predict(self, step, level_number):
238 """
239 Default routine called after each predictor
241 Args:
242 step (pySDC.Step.step): the current step
243 level_number (int): the current level number
244 """
245 super().post_predict(step, level_number)
246 self.__t1_predict = self._get_event()
248 L = step.levels[level_number]
250 self.add_to_stats(
251 process=step.status.slot,
252 process_sweeper=L.sweep.rank,
253 time=L.time,
254 level=L.level_index,
255 iter=step.status.iter,
256 sweep=L.status.sweep,
257 type=f'{self.prefix}timing_predictor',
258 value=self._compute_time_elapsed(self.__t1_predict, self.__t0_predict),
259 )
261 def post_run(self, step, level_number):
262 """
263 Default routine called after each run
265 Args:
266 step (pySDC.Step.step): the current step
267 level_number (int): the current level number
268 """
269 super().post_run(step, level_number)
270 self.__t1_run = self._get_event()
271 t_run = self._compute_time_elapsed(self.__t1_run, self.__t0_run)
273 L = step.levels[level_number]
275 self.add_to_stats(
276 process=step.status.slot,
277 process_sweeper=L.sweep.rank,
278 time=L.time,
279 level=L.level_index,
280 iter=step.status.iter,
281 sweep=L.status.sweep,
282 type=f'{self.prefix}timing_run',
283 value=t_run,
284 )
285 if step.status.first:
286 self.logger.info(f'Finished run after {t_run:.2e}s')
288 def post_setup(self, step, level_number):
289 """
290 Default routine called after setup
292 Args:
293 step (pySDC.Step.step): the current step
294 level_number (int): the current level number
295 """
296 super().post_setup(step, level_number)
297 self.__t1_setup = self._get_event()
299 self.add_to_stats(
300 process=-1,
301 process_sweeper=-1,
302 time=-1,
303 level=-1,
304 iter=-1,
305 sweep=-1,
306 type=f'{self.prefix}timing_setup',
307 value=self._compute_time_elapsed(self.__t1_setup, self.__t0_setup),
308 )
311class CPUTimings(Timings):
312 """
313 Hook for recording CPU timings of important operations during a pySDC run.
314 """
316 def _compute_time_elapsed(self, event_after, event_before):
317 return event_after - event_before
319 def _get_event(self):
320 return time.perf_counter()