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 logging 

28import resource 

29import time 

30import datetime 

31 

32 

33def logPairs(obj, pairs, logLevel=logging.DEBUG, metadata=None, logger=None): 

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

35 

36 Parameters 

37 ---------- 

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

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

40 

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

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

43 - ``log`` an instance of `logging.Logger` or subclass. 

44 

45 If `None`, at least one of ``metadata`` or ``logger`` should be passed 

46 or this function will do nothing. 

47 

48 pairs : sequence 

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

50 logLevel : `int, optional 

51 Log level (an `logging` level constant, such as `logging.DEBUG`). 

52 metadata : `lsst.daf.base.PropertyList`, optional 

53 Metadata object to write entries to. Ignored if `None`. 

54 logger : `logging.Logger` 

55 Log object to write entries to. Ignored if `None`. 

56 """ 

57 if obj is not None: 

58 if metadata is None: 

59 metadata = obj.metadata 

60 if logger is None: 

61 logger = obj.log 

62 strList = [] 

63 for name, value in pairs: 

64 if metadata is not None: 

65 try: 

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

67 # sequence is int-sized 

68 metadata.addLongLong(name, value) 

69 except TypeError: 

70 metadata.add(name, value) 

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

72 if logger is not None: 

73 logging.getLogger("timer." + logger.name).log(logLevel, "; ".join(strList)) 

74 

75 

76def logInfo(obj, prefix, logLevel=logging.DEBUG, metadata=None, logger=None): 

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

78 

79 Parameters 

80 ---------- 

81 obj : `lsst.pipe.base.Task`-type or `None` 

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

83 

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

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

86 - ``log`` an instance of `logging.Logger` or subclass. 

87 

88 If `None`, at least one of ``metadata`` or ``logger`` should be passed 

89 or this function will do nothing. 

90 

91 prefix 

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

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

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

95 logLevel : optional 

96 Log level (an `logging` level constant, such as `logging.DEBUG`). 

97 metadata : `lsst.daf.base.PropertyList`, optional 

98 Metadata object to write entries to, overriding ``obj.metadata``. 

99 logger : `logging.Logger` 

100 Log object to write entries to, overriding ``obj.log``. 

101 

102 Notes 

103 ----- 

104 Logged items include: 

105 

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

107 timestamps). 

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

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

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

111 

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

113 processes are excluded. 

114 """ 

115 cpuTime = time.process_time() 

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

117 res = resource.getrusage(resource.RUSAGE_SELF) 

118 if metadata is None and obj is not None: 

119 metadata = obj.metadata 

120 if metadata is not None: 

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

122 logPairs(obj=obj, 

123 pairs=[ 

124 (prefix + "CpuTime", cpuTime), 

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

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

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

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

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

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

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

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

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

134 ], 

135 logLevel=logLevel, 

136 metadata=metadata, 

137 logger=logger) 

138 

139 

140def timeMethod(func): 

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

142 

143 Parameters 

144 ---------- 

145 func 

146 The method to wrap. 

147 

148 Notes 

149 ----- 

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

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

152 

153 .. warning:: 

154 

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

156 with these attributes: 

157 

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

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

160 - ``log``: an instance of `logging.Logger` or subclass. 

161 

162 Examples 

163 -------- 

164 To use: 

165 

166 .. code-block:: python 

167 

168 import lsst.pipe.base as pipeBase 

169 class FooTask(pipeBase.Task): 

170 pass 

171 

172 @pipeBase.timeMethod 

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

174 pass 

175 """ 

176 

177 @functools.wraps(func) 

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

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

180 try: 

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

182 finally: 

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

184 return res 

185 return wrapper