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# 

2# LSST Data Management System 

3# Copyright 2008, 2009, 2010, 2011 LSST Corporation. 

4# 

5# This product includes software developed by the 

6# LSST Project (http://www.lsst.org/). 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

19# the GNU General Public License along with this program. If not, 

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22"""Utilities for measuring execution time. 

23""" 

24__all__ = ["logInfo", "timeMethod"] 

25 

26import functools 

27import resource 

28import time 

29import datetime 

30 

31from lsst.log import Log, log 

32 

33 

34def logPairs(obj, pairs, logLevel=Log.DEBUG): 

35 """Log ``(name, value)`` pairs to ``obj.metadata`` and ``obj.log`` 

36 

37 Parameters 

38 ---------- 

39 obj : `lsst.pipe.base.Task`-type 

40 A `~lsst.pipe.base.Task` or any other object with these two attributes: 

41 

42 - ``metadata`` an instance of `lsst.daf.base.PropertyList`` (or other 

43 object with ``add(name, value)`` method). 

44 - ``log`` an instance of `lsst.log.Log`. 

45 

46 pairs : sequence 

47 A sequence of ``(name, value)`` pairs, with value typically numeric. 

48 logLevel : optional 

49 Log level (an `lsst.log` level constant, such as `lsst.log.Log.DEBUG`). 

50 """ 

51 strList = [] 

52 for name, value in pairs: 

53 try: 

54 # Use LongLong explicitly here in case an early value in the 

55 # sequence is int-sized 

56 obj.metadata.addLongLong(name, value) 

57 except TypeError: 

58 obj.metadata.add(name, value) 

59 strList.append(f"{name}={value}") 

60 log("timer." + obj.log.getName(), logLevel, "; ".join(strList)) 

61 

62 

63def logInfo(obj, prefix, logLevel=Log.DEBUG): 

64 """Log timer information to ``obj.metadata`` and ``obj.log``. 

65 

66 Parameters 

67 ---------- 

68 obj : `lsst.pipe.base.Task`-type 

69 A `~lsst.pipe.base.Task` or any other object with these two attributes: 

70 

71 - ``metadata`` an instance of `lsst.daf.base.PropertyList`` (or other 

72 object with ``add(name, value)`` method). 

73 - ``log`` an instance of `lsst.log.Log`. 

74 

75 prefix 

76 Name prefix, the resulting entries are ``CpuTime``, etc.. For example 

77 timeMethod uses ``prefix = Start`` when the method begins and 

78 ``prefix = End`` when the method ends. 

79 logLevel : optional 

80 Log level (an `lsst.log` level constant, such as `lsst.log.Log.DEBUG`). 

81 

82 Notes 

83 ----- 

84 Logged items include: 

85 

86 - ``Utc``: UTC date in ISO format (only in metadata since log entries have 

87 timestamps). 

88 - ``CpuTime``: System + User CPU time (seconds). This should only be used 

89 in differential measurements; the time reference point is undefined. 

90 - ``MaxRss``: maximum resident set size. 

91 

92 All logged resource information is only for the current process; child 

93 processes are excluded. 

94 """ 

95 cpuTime = time.process_time() 

96 utcStr = datetime.datetime.utcnow().isoformat() 

97 res = resource.getrusage(resource.RUSAGE_SELF) 

98 obj.metadata.add(name=prefix + "Utc", value=utcStr) # log messages already have timestamps 

99 logPairs(obj=obj, 

100 pairs=[ 

101 (prefix + "CpuTime", cpuTime), 

102 (prefix + "UserTime", res.ru_utime), 

103 (prefix + "SystemTime", res.ru_stime), 

104 (prefix + "MaxResidentSetSize", int(res.ru_maxrss)), 

105 (prefix + "MinorPageFaults", int(res.ru_minflt)), 

106 (prefix + "MajorPageFaults", int(res.ru_majflt)), 

107 (prefix + "BlockInputs", int(res.ru_inblock)), 

108 (prefix + "BlockOutputs", int(res.ru_oublock)), 

109 (prefix + "VoluntaryContextSwitches", int(res.ru_nvcsw)), 

110 (prefix + "InvoluntaryContextSwitches", int(res.ru_nivcsw)), 

111 ], 

112 logLevel=logLevel, 

113 ) 

114 

115 

116def timeMethod(func): 

117 """Decorator to measure duration of a task method. 

118 

119 Parameters 

120 ---------- 

121 func 

122 The method to wrap. 

123 

124 Notes 

125 ----- 

126 Writes various measures of time and possibly memory usage to the task's 

127 metadata; all items are prefixed with the function name. 

128 

129 .. warning:: 

130 

131 This decorator only works with instance methods of Task, or any class 

132 with these attributes: 

133 

134 - ``metadata``: an instance of `lsst.daf.base.PropertyList` (or other 

135 object with ``add(name, value)`` method). 

136 - ``log``: an instance of `lsst.log.Log`. 

137 

138 Examples 

139 -------- 

140 To use: 

141 

142 .. code-block:: python 

143 

144 import lsst.pipe.base as pipeBase 

145 class FooTask(pipeBase.Task): 

146 pass 

147 

148 @pipeBase.timeMethod 

149 def run(self, ...): # or any other instance method you want to time 

150 pass 

151 """ 

152 

153 @functools.wraps(func) 

154 def wrapper(self, *args, **keyArgs): 

155 logInfo(obj=self, prefix=func.__name__ + "Start") 

156 try: 

157 res = func(self, *args, **keyArgs) 

158 finally: 

159 logInfo(obj=self, prefix=func.__name__ + "End") 

160 return res 

161 return wrapper