Coverage for /builds/kinetik161/ase/ase/utils/timing.py: 85.71%
112 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1# Copyright (C) 2003 CAMP
2# Please see the accompanying LICENSE file for further information.
5import functools
6import inspect
7import sys
8import time
11def function_timer(func, *args, **kwargs):
12 out = kwargs.pop('timeout', sys.stdout)
13 t1 = time.time()
14 r = func(*args, **kwargs)
15 t2 = time.time()
16 print(t2 - t1, file=out)
17 return r
20class Timer:
21 """Timer object.
23 Use like this::
25 timer = Timer()
26 timer.start('description')
27 # do something
28 timer.stop()
30 or::
32 with timer('description'):
33 # do something
35 To get a summary call::
37 timer.write()
39 """
41 def __init__(self, print_levels=1000):
42 self.timers = {}
43 self.t0 = time.time()
44 self.running = []
45 self.print_levels = print_levels
47 def print_info(self, calc):
48 """Override to get to write info during calculator's initialize()."""
50 def start(self, name):
51 names = tuple(self.running + [name])
52 self.timers[names] = self.timers.get(names, 0.0) - time.time()
53 self.running.append(name)
55 def stop(self, name=None):
56 if name is None:
57 name = self.running[-1]
58 names = tuple(self.running)
59 running = self.running.pop()
60 if name != running:
61 raise RuntimeError('Must stop timers by stack order. '
62 'Requested stopping of %s but topmost is %s'
63 % (name, running))
64 self.timers[names] += time.time()
65 return names
67 def __call__(self, name):
68 """Context manager for timing a block of code.
70 Example (t is a timer object)::
72 with t('Add two numbers'):
73 x = 2 + 2
75 # same as this:
76 t.start('Add two numbers')
77 x = 2 + 2
78 t.stop()
79 """
80 self.start(name)
81 return self
83 def __enter__(self):
84 pass
86 def __exit__(self, *args):
87 self.stop()
89 def get_time(self, *names):
90 return self.timers[names]
92 def write(self, out=sys.stdout):
93 were_running = list(self.running)
94 while self.running:
95 self.stop()
96 if len(self.timers) == 0:
97 return
99 t0 = time.time()
100 tot = t0 - self.t0
102 n = max([len(names[-1]) + len(names) for names in self.timers]) + 1
103 line = '-' * (n + 26) + '\n'
104 out.write('%-*s incl. excl.\n' % (n, 'Timing:'))
105 out.write(line)
106 tother = tot
108 inclusive = self.timers.copy()
109 exclusive = self.timers.copy()
110 keys = sorted(exclusive.keys())
111 for names in keys:
112 t = exclusive[names]
113 if len(names) > 1:
114 if len(names) < self.print_levels + 1:
115 exclusive[names[:-1]] -= t
116 else:
117 tother -= t
118 exclusive[('Other',)] = tother
119 inclusive[('Other',)] = tother
120 keys.append(('Other',))
121 for names in keys:
122 t = exclusive[names]
123 tinclusive = inclusive[names]
124 r = t / tot
125 p = 100 * r
126 i = int(40 * r + 0.5)
127 if i == 0:
128 bar = '|'
129 else:
130 bar = '|%s|' % ('-' * (i - 1))
131 level = len(names)
132 if level > self.print_levels:
133 continue
134 name = (level - 1) * ' ' + names[-1] + ':'
135 out.write('%-*s%9.3f %9.3f %5.1f%% %s\n' %
136 (n, name, tinclusive, t, p, bar))
137 out.write(line)
138 out.write('%-*s%9.3f %5.1f%%\n\n' % (n + 10, 'Total:', tot, 100.0))
140 for name in were_running:
141 self.start(name)
143 def add(self, timer):
144 for name, t in timer.timers.items():
145 self.timers[name] = self.timers.get(name, 0.0) + t
148class timer:
149 """Decorator for timing a method call.
151 Example::
153 from ase.utils.timing import timer, Timer
155 class A:
156 def __init__(self):
157 self.timer = Timer()
159 @timer('Add two numbers')
160 def add(self, x, y):
161 return x + y
163 """
165 def __init__(self, name):
166 self.name = name
168 def __call__(self, method):
169 if inspect.isgeneratorfunction(method):
170 @functools.wraps(method)
171 def new_method(slf, *args, **kwargs):
172 gen = method(slf, *args, **kwargs)
173 while True:
174 slf.timer.start(self.name)
175 try:
176 x = next(gen)
177 except StopIteration:
178 break
179 finally:
180 slf.timer.stop()
181 yield x
182 else:
183 @functools.wraps(method)
184 def new_method(slf, *args, **kwargs):
185 slf.timer.start(self.name)
186 x = method(slf, *args, **kwargs)
187 try:
188 slf.timer.stop()
189 except IndexError:
190 pass
191 return x
192 return new_method