Coverage for larch/utils/debugtimer.py: 19%

57 statements  

« prev     ^ index     » next       coverage.py v7.6.0, created at 2024-10-16 21:04 +0000

1#!/usr/bin/env python 

2 

3import time 

4import sys 

5from tabulate import tabulate 

6 

7class DebugTimer(): 

8 ''' 

9 Measure run times for lines of code and summarize results 

10 ''' 

11 def __init__(self, initial_message=None, verbose=False, 

12 with_mod_count=False, precision=3): 

13 self.verbose = verbose 

14 self.precision = precision 

15 self.with_mod_count = with_mod_count 

16 self.clear(initial_message=initial_message) 

17 

18 def clear(self, initial_message=None): 

19 self.data = [] 

20 if initial_message is None: 

21 initial_message = 'DebugTimer' 

22 self.add(f'initial_message {time.ctime()}') 

23 

24 def add(self, msg=None): 

25 if msg is None: 

26 msg = time.ctime() 

27 self.data.append((msg, len(sys.modules), time.perf_counter())) 

28 if self.verbose: 

29 print(msg) 

30 

31 def get_table(self, precision=None, with_mod_count=True, 

32 tablefmt='simple_outline'): 

33 prec = self.precision 

34 if precision is not None: 

35 prec = precision 

36 with_nmod= self.with_mod_count 

37 if with_mod_count is not None: 

38 with_nmod = with_mod_count 

39 m0, n0, t0 = self.data[0] 

40 tprev= t0 

41 header = ['Message','Delta Time', 'Total Time'] 

42 row = [m0, 0, 0] 

43 if with_nmod: 

44 header.append('# Modules') 

45 row.append(n0) 

46 table = [row[:]] 

47 for m, n, t in self.data[1:]: 

48 tt, dt = t-t0, t-tprev 

49 row = [m, dt, tt, n] if with_nmod else [m, dt, tt] 

50 table.append(row[:]) 

51 tprev = t 

52 ffmt = f'.{prec}f' 

53 return tabulate(table, header, floatfmt=ffmt, tablefmt=tablefmt) 

54 

55 def show(self, precision=None, with_mod_count=True, 

56 tablefmt='outline'): 

57 print(self.get_table(precision=precision, 

58 with_mod_count=with_mod_count, 

59 tablefmt=tablefmt)) 

60 

61 

62def debugtimer(initial_message=None, with_mod_count=False, 

63 verbose=False, precision=3): 

64 '''debugtimer returns a DebugTimer object to measure the runtime of 

65 portions of code, and then write a simple report of the results. 

66 

67 Arguments 

68 ------------ 

69 iniitial message: str, optional initial message ['DebugTimer'] 

70 precision: int, precision for timing results [3] 

71 with_mod_count: bool, whether to include number of imported modules [True] 

72 verbose: bool, whether to print() each message when entered [False] 

73 

74 Returns 

75 -------- 

76 DebugTimer object, with methods: 

77 

78 clear(initial_message=None) -- reset Timer 

79 add(message) -- record time, with message 

80 show(tablefmt='simple_outline') -- print timer report 

81 where tableftmt can be any tablefmt for the tabulate module. 

82 

83 Example: 

84 ------- 

85 timer = debugtimer('started timer', precision=4) 

86 result = foo(x=100) 

87 timer.add('ran foo') 

88 bar(result) 

89 timer.add('ran bar') 

90 timer.show(tablefmt='outline') 

91 ''' 

92 return DebugTimer(initial_message=initial_message, 

93 with_mod_count=with_mod_count, 

94 verbose=verbose, precision=precision) 

95 

96 

97if __name__ == '__main__': 

98 dt = debugtimer('test timer') 

99 time.sleep(1.102) 

100 dt.add('slept for 1.102 seconds') 

101 import numpy as np 

102 n = 10_000_000 

103 x = np.arange(n, dtype='float64')/3.0 

104 dt.add(f'created numpy array len={n}') 

105 s = np.sqrt(x) 

106 dt.add('took sqrt') 

107 dt.show(tablefmt='outline')