Coverage for python/lsst/pipe/base/timer.py : 38%

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"]
26import functools
27import resource
28import time
29import datetime
31from lsst.log import Log, log
34def logPairs(obj, pairs, logLevel=Log.DEBUG):
35 """Log ``(name, value)`` pairs to ``obj.metadata`` and ``obj.log``
37 Parameters
38 ----------
39 obj : `lsst.pipe.base.Task`-type
40 A `~lsst.pipe.base.Task` or any other object with these two attributes:
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`.
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))
63def logInfo(obj, prefix, logLevel=Log.DEBUG):
64 """Log timer information to ``obj.metadata`` and ``obj.log``.
66 Parameters
67 ----------
68 obj : `lsst.pipe.base.Task`-type
69 A `~lsst.pipe.base.Task` or any other object with these two attributes:
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`.
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`).
82 Notes
83 -----
84 Logged items include:
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.
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 )
116def timeMethod(func):
117 """Decorator to measure duration of a task method.
119 Parameters
120 ----------
121 func
122 The method to wrap.
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.
129 .. warning::
131 This decorator only works with instance methods of Task, or any class
132 with these attributes:
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`.
138 Examples
139 --------
140 To use:
142 .. code-block:: python
144 import lsst.pipe.base as pipeBase
145 class FooTask(pipeBase.Task):
146 pass
148 @pipeBase.timeMethod
149 def run(self, ...): # or any other instance method you want to time
150 pass
151 """
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