Hide keyboard shortcuts

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. 

3 

4 

5import inspect 

6import functools 

7import sys 

8import time 

9 

10 

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 

18 

19 

20class Timer: 

21 """Timer object. 

22 

23 Use like this:: 

24 

25 timer = Timer() 

26 timer.start('description') 

27 # do something 

28 timer.stop() 

29 

30 or:: 

31 

32 with timer('description'): 

33 # do something 

34 

35 To get a summary call:: 

36 

37 timer.write() 

38 

39 """ 

40 

41 def __init__(self, print_levels=1000): 

42 self.timers = {} 

43 self.t0 = time.time() 

44 self.running = [] 

45 self.print_levels = print_levels 

46 

47 def print_info(self, calc): 

48 """Override to get to write info during calculator's initialize().""" 

49 pass 

50 

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) 

55 

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 

67 

68 def __call__(self, name): 

69 """Context manager for timing a block of code. 

70 

71 Example (t is a timer object):: 

72 

73 with t('Add two numbers'): 

74 x = 2 + 2 

75 

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 

83 

84 def __enter__(self): 

85 pass 

86 

87 def __exit__(self, *args): 

88 self.stop() 

89 

90 def get_time(self, *names): 

91 return self.timers[names] 

92 

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 

99 

100 t0 = time.time() 

101 tot = t0 - self.t0 

102 

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 

108 

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)) 

140 

141 for name in were_running: 

142 self.start(name) 

143 

144 def add(self, timer): 

145 for name, t in timer.timers.items(): 

146 self.timers[name] = self.timers.get(name, 0.0) + t 

147 

148 

149class timer: 

150 """Decorator for timing a method call. 

151 

152 Example:: 

153 

154 from ase.utils.timing import timer, Timer 

155 

156 class A: 

157 def __init__(self): 

158 self.timer = Timer() 

159 

160 @timer('Add two numbers') 

161 def add(self, x, y): 

162 return x + y 

163 

164 """ 

165 def __init__(self, name): 

166 self.name = name 

167 

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