lsst.pipe.base  13.0-12-gaf0c0ec+8
timer.py
Go to the documentation of this file.
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 from __future__ import absolute_import, division
25 import functools
26 import resource
27 import time
28 import datetime
29 
30 from lsst.log import Log, log
31 
32 __all__ = ["logInfo", "timeMethod"]
33 
34 
35 def logPairs(obj, pairs, logLevel=Log.DEBUG):
36  """!Log (name, value) pairs to obj.metadata and obj.log
37 
38  @param obj a \ref task.Task "Task", or any other object with these two attributes:
39  * metadata an instance of lsst.daf.base.PropertyList (or other object with add(name, value) method)
40  * log an instance of lsst.log.Log
41  @param pairs a collection of (name, value) pairs
42  @param logLevel log level (an lsst.log level constant, such as lsst.log.Log.DEBUG)
43  """
44  strList = []
45  for name, value in pairs:
46  try:
47  obj.metadata.add(name, value)
48  except Exception as e:
49  obj.log.fatal("%s.metadata.add(name=%r, value=%r) failed with error=%s",
50  type(obj).__name__, name, value, e)
51  strList.append("%s=%s" % (name, value))
52  log(obj.log.getName(), logLevel, "; ".join(strList))
53 
54 
55 def logInfo(obj, prefix, logLevel=Log.DEBUG):
56  """!Log timer information to obj.metadata and obj.log
57 
58  @param obj a \ref task.Task "Task", or any other object with these two attributes:
59  * metadata an instance of lsst.daf.base.PropertyList (or other object with add(name, value) method)
60  * log an instance of lsst.log.Log
61  @param prefix name prefix, the resulting entries are <prefix>CpuTime, etc.
62  For example timeMethod uses prefix = <methodName>Start
63  when the method begins and prefix = <methodName>End when the method ends.
64  @param logLevel log level (an lsst.log level, constant such as lsst.log.Log.DEBUG)
65 
66 
67  Logged items include:
68  * Utc: UTC date in ISO format (only in metadata since log entries have timestamps)
69  * CpuTime: CPU time (seconds)
70  * MaxRss: maximum resident set size
71  All logged resource information is only for the current process; child processes are excluded
72  """
73  cpuTime = time.clock()
74  utcStr = datetime.datetime.utcnow().isoformat()
75  res = resource.getrusage(resource.RUSAGE_SELF)
76  obj.metadata.add(name=prefix + "Utc", value=utcStr) # log messages already have timestamps
77  logPairs(obj=obj,
78  pairs=[
79  (prefix + "CpuTime", cpuTime),
80  (prefix + "UserTime", res.ru_utime),
81  (prefix + "SystemTime", res.ru_stime),
82  (prefix + "MaxResidentSetSize", int(res.ru_maxrss)),
83  (prefix + "MinorPageFaults", int(res.ru_minflt)),
84  (prefix + "MajorPageFaults", int(res.ru_majflt)),
85  (prefix + "BlockInputs", int(res.ru_inblock)),
86  (prefix + "BlockOutputs", int(res.ru_oublock)),
87  (prefix + "VoluntaryContextSwitches", int(res.ru_nvcsw)),
88  (prefix + "InvoluntaryContextSwitches", int(res.ru_nivcsw)),
89  ],
90  logLevel=logLevel,
91  )
92 
93 
94 def timeMethod(func):
95  """!Decorator to measure duration of a task method
96 
97  Writes various measures of time and possibly memory usage to the task's metadata;
98  all items are prefixed with the function name.
99 
100  To use:
101  \code
102  import lsst.pipe.base as pipeBase
103  class FooTask(pipeBase.Task):
104  ...
105 
106  @pipeBase.timeMethod
107  def run(self, ...): # or any other instance method you want to time
108  ...
109  \endcode
110 
111  @param func the method to wrap
112 
113  @warning This decorator only works with instance methods of Task, or any class with these attributes:
114  * metadata: an instance of lsst.daf.base.PropertyList (or other object with add(name, value) method)
115  * log: an instance of lsst.log.Log
116  """
117  @functools.wraps(func)
118  def wrapper(self, *args, **keyArgs):
119  logInfo(obj=self, prefix=func.__name__ + "Start")
120  try:
121  res = func(self, *args, **keyArgs)
122  finally:
123  logInfo(obj=self, prefix=func.__name__ + "End")
124  return res
125  return wrapper
def logInfo(obj, prefix, logLevel=Log.DEBUG)
Log timer information to obj.metadata and obj.log.
Definition: timer.py:55
def logPairs(obj, pairs, logLevel=Log.DEBUG)
Log (name, value) pairs to obj.metadata and obj.log.
Definition: timer.py:35
def timeMethod(func)
Decorator to measure duration of a task method.
Definition: timer.py:94