Source code for lsst.pipe.base.timer

#
# LSST Data Management System
# Copyright 2008, 2009, 2010, 2011 LSST Corporation.
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program.  If not,
# see <http://www.lsstcorp.org/LegalNotices/>.
#
"""Utilities for measuring execution time.
"""
from __future__ import absolute_import, division
import functools
import resource
import time
import datetime

from lsst.log import Log, log

__all__ = ["logInfo", "timeMethod"]


def logPairs(obj, pairs, logLevel=Log.DEBUG):
    """Log ``(name, value)`` pairs to ``obj.metadata`` and ``obj.log``

    Parameters
    ----------
    obj : `lsst.pipe.base.Task`-type
        A `~lsst.pipe.base.Task` or any other object with these two attributes:

        - ``metadata`` an instance of `lsst.daf.base.PropertyList`` (or other object with
          ``add(name, value)`` method).
        - ``log`` an instance of `lsst.log.Log`.

    pairs : sequence
        A sequence of ``(name, value)`` pairs, with value typically numeric.
    logLevel : optional
        Log level (an `lsst.log` level constant, such as `lsst.log.Log.DEBUG`).
    """
    strList = []
    for name, value in pairs:
        try:
            # Use LongLong explicitly here in case an early value in the sequence is int-sized
            obj.metadata.addLongLong(name, value)
        except TypeError as e:
            obj.metadata.add(name, value)
        strList.append("%s=%s" % (name, value))
    log(obj.log.getName(), logLevel, "; ".join(strList))


[docs]def logInfo(obj, prefix, logLevel=Log.DEBUG): """Log timer information to ``obj.metadata`` and ``obj.log``. Parameters ---------- obj : `lsst.pipe.base.Task`-type A `~lsst.pipe.base.Task` or any other object with these two attributes: - ``metadata`` an instance of `lsst.daf.base.PropertyList`` (or other object with ``add(name, value)`` method). - ``log`` an instance of `lsst.log.Log`. prefix Name prefix, the resulting entries are ``CpuTime``, etc.. For example timeMethod uses ``prefix = Start`` when the method begins and ``prefix = End`` when the method ends. logLevel : optional Log level (an `lsst.log` level constant, such as `lsst.log.Log.DEBUG`). Notes ----- Logged items include: - ``Utc``: UTC date in ISO format (only in metadata since log entries have timestamps). - ``CpuTime``: CPU time (seconds). - ``MaxRss``: maximum resident set size. All logged resource information is only for the current process; child processes are excluded. """ cpuTime = time.clock() utcStr = datetime.datetime.utcnow().isoformat() res = resource.getrusage(resource.RUSAGE_SELF) obj.metadata.add(name=prefix + "Utc", value=utcStr) # log messages already have timestamps logPairs(obj=obj, pairs=[ (prefix + "CpuTime", cpuTime), (prefix + "UserTime", res.ru_utime), (prefix + "SystemTime", res.ru_stime), (prefix + "MaxResidentSetSize", int(res.ru_maxrss)), (prefix + "MinorPageFaults", int(res.ru_minflt)), (prefix + "MajorPageFaults", int(res.ru_majflt)), (prefix + "BlockInputs", int(res.ru_inblock)), (prefix + "BlockOutputs", int(res.ru_oublock)), (prefix + "VoluntaryContextSwitches", int(res.ru_nvcsw)), (prefix + "InvoluntaryContextSwitches", int(res.ru_nivcsw)), ], logLevel=logLevel, )
[docs]def timeMethod(func): """Decorator to measure duration of a task method. Parameters ---------- func The method to wrap. Notes ----- Writes various measures of time and possibly memory usage to the task's metadata; all items are prefixed with the function name. .. warning:: This decorator only works with instance methods of Task, or any class with these attributes: - ``metadata``: an instance of `lsst.daf.base.PropertyList` (or other object with ``add(name, value)`` method). - ``log``: an instance of `lsst.log.Log`. Examples -------- To use:: import lsst.pipe.base as pipeBase class FooTask(pipeBase.Task): pass @pipeBase.timeMethod def run(self, ...): # or any other instance method you want to time pass """ @functools.wraps(func) def wrapper(self, *args, **keyArgs): logInfo(obj=self, prefix=func.__name__ + "Start") try: res = func(self, *args, **keyArgs) finally: logInfo(obj=self, prefix=func.__name__ + "End") return res return wrapper