Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# Copyright (C) 2003 CAMP
2# Please see the accompanying LICENSE file for further information.
5import inspect
6import functools
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()."""
49 pass
51 def start(self, name):
52 names = tuple(self.running + [name])
53 self.timers[names] = self.timers.get(names, 0.0) - time.time()
54 self.running.append(name)
56 def stop(self, name=None):
57 if name is None:
58 name = self.running[-1]
59 names = tuple(self.running)
60 running = self.running.pop()
61 if name != running:
62 raise RuntimeError('Must stop timers by stack order. '
63 'Requested stopping of %s but topmost is %s'
64 % (name, running))
65 self.timers[names] += time.time()
66 return names
68 def __call__(self, name):
69 """Context manager for timing a block of code.
71 Example (t is a timer object)::
73 with t('Add two numbers'):
74 x = 2 + 2
76 # same as this:
77 t.start('Add two numbers')
78 x = 2 + 2
79 t.stop()
80 """
81 self.start(name)
82 return self
84 def __enter__(self):
85 pass
87 def __exit__(self, *args):
88 self.stop()
90 def get_time(self, *names):
91 return self.timers[names]
93 def write(self, out=sys.stdout):
94 were_running = list(self.running)
95 while self.running:
96 self.stop()
97 if len(self.timers) == 0:
98 return
100 t0 = time.time()
101 tot = t0 - self.t0
103 n = max([len(names[-1]) + len(names) for names in self.timers]) + 1
104 line = '-' * (n + 26) + '\n'
105 out.write('%-*s incl. excl.\n' % (n, 'Timing:'))
106 out.write(line)
107 tother = tot
109 inclusive = self.timers.copy()
110 exclusive = self.timers.copy()
111 keys = sorted(exclusive.keys())
112 for names in keys:
113 t = exclusive[names]
114 if len(names) > 1:
115 if len(names) < self.print_levels + 1:
116 exclusive[names[:-1]] -= t
117 else:
118 tother -= t
119 exclusive[('Other',)] = tother
120 inclusive[('Other',)] = tother
121 keys.append(('Other',))
122 for names in keys:
123 t = exclusive[names]
124 tinclusive = inclusive[names]
125 r = t / tot
126 p = 100 * r
127 i = int(40 * r + 0.5)
128 if i == 0:
129 bar = '|'
130 else:
131 bar = '|%s|' % ('-' * (i - 1))
132 level = len(names)
133 if level > self.print_levels:
134 continue
135 name = (level - 1) * ' ' + names[-1] + ':'
136 out.write('%-*s%9.3f %9.3f %5.1f%% %s\n' %
137 (n, name, tinclusive, t, p, bar))
138 out.write(line)
139 out.write('%-*s%9.3f %5.1f%%\n\n' % (n + 10, 'Total:', tot, 100.0))
141 for name in were_running:
142 self.start(name)
144 def add(self, timer):
145 for name, t in timer.timers.items():
146 self.timers[name] = self.timers.get(name, 0.0) + t
149class timer:
150 """Decorator for timing a method call.
152 Example::
154 from ase.utils.timing import timer, Timer
156 class A:
157 def __init__(self):
158 self.timer = Timer()
160 @timer('Add two numbers')
161 def add(self, x, y):
162 return x + y
164 """
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