1

I want to implement a timer to measure how long a block of code takes to run. I then want to do this across an entire application containing multiple modules (40+) across multiple directories (4+).

My timer is created with two functions that are within a class with a structure like this:

 class SubClass(Class1)
    def getStartTime(self):
         start = time.time()
         return start

    def logTiming(self, classstring, start):
        fin = time.time() - start
        logging.getLogger('perf_log_handler').info((classstring + ' sec').format(round(fin,3)))

The first function gets the start time, and the second function calculates the time for the block to run and then logs it to a logger.

This code is in a module that we'll call module1.py.

In practice, generically, it will be implemented as such:

 class SubSubClass(SubClass)
     def Some_Process
        stim = super().getStartTime()
        code..............................
        ...
        ...
        ... 
        ...
        super().logTiming("The Process took: {}", stim)
        return Result_Of_Process

This code resides in a module called module2.py and already works and successfully logs. My problem is that when structured like this, I can seemingly only use the timer inside code that is under the umbrella of SubClass, where it is defined (my application fails to render and I get a "can't find page" error in my browser). But I want to use this code everywhere in all the application modules, globally. Whether the module is within another directory, whether some blocks of code are within other classes and subclasses inside other modules, everywhere.

What is the easiest, most efficient way to create this timing instrument so that I can use it anywhere in my application? I understand I may have to define it completely differently. I am very new to all of this, so any help is appreciated.

AdamC
  • 71
  • 1
  • 7
  • 1
    I don't understand what you mean by " I can seemingly only use the timer inside code that is under the umbrella of SubClass, where it is defined". – Daniel Roseman Aug 10 '18 at 22:37
  • Also note, there is no reason to use super() either time there; just call `self.getStartTime()` and `self.logTiming()`. – Daniel Roseman Aug 10 '18 at 22:39
  • @DanielRoseman I tried to use this code in another module, with code that didn't have a class, and my application would not work. It didn't spit out any errors, so I can't figure out exactly what wasn't working, but my application just simply wouldn't render and I got a "can't find page" result in my browser. – AdamC Aug 10 '18 at 22:49
  • Your use of inheritance here makes no sense to me. A timer mixin might make sense, but why is your timer code in some subclass of some unrelated class? this makes it *less reusable* – juanpa.arrivillaga Aug 10 '18 at 23:25
  • @juanpa.arrivillaga The short answer is because "this is where I was told to put it." My question is specifically how to make it more reusable. This is with full understanding that my current setup might be less reusable. – AdamC Aug 10 '18 at 23:44

2 Answers2

0

OPTION 1) You should define another module, for example, "mytimer.py" fully dedicated to the timer:

import time

class MyTimer():
    def __init__(self):
        self.start = time.time()

    def log(self):
        now = time.time()
        return now - self.start

And then, from any line of your code, for example, in module2.py:

from mytimer import MyTimer

class SomeClass()
    def Some_Function
        t = MyTimer()
        ....
        t.log()
        return ...

OPTION 2) You could also use a simple function instead of a class:

import time

def mytimer(start=None, tag=""):
    if start is None:
        start = time.time()

    now = time.time()
    delay = float(now - start)

    print "%(tag)s %(delay).2f seconds." % {'tag': tag, 'delay': delay}

    return now

And then, in your code:

from mytimer import mytimer

class SomeClass()
    def Some_Function
        t = mytimer(tag='BREAK0')
        ....
        t = mytimer(start=t, tag='BREAK1')
        ....
        t = mytimer(start=t, tag='BREAK2')
        ....
        t = mytimer(start=t, tag='BREAK3')
        return ...
nandoquintana
  • 400
  • 3
  • 14
0

I am not quite sure what you are looking for, but once upon a time I used a decorator for a similar type of problem.

The snippet below is the closest I can remember to what I implemented at that time. Hopefully it is useful to you.

Brief explanation

  1. The timed is a 'decorator' that wraps methods in the python object and times the method.
  2. The class contains a log that is updated by the wrapper as the @timed methods are called.

Note that if you want to make the @property act as a "class property" you can draw inspiration from this post.

from time import sleep, time

# -----------------
# Define Decorators
# ------------------
def timed(wrapped):
    def wrapper(self, *arg, **kwargs):
        start = time()
        res = wrapped(self, *arg, **kwargs)
        stop = time()
        self.log = {'method': wrapped.__name__, 'called': start, 'elapsed': stop - start}
        return res
    return wrapper

# -----------------
# Define Classes
# ------------------    
class Test(object):

    __log = []

    @property
    def log(self):
        return self.__log

    @log.setter
    def log(self, kwargs):
        self.__log.append(kwargs)

    @timed
    def test(self):
        print("Running timed method")
        sleep(2)

    @timed
    def test2(self, a, b=2):
        print("Running another timed method")
        sleep(2)
        return a+b

# ::::::::::::::::::
if __name__ == '__main__':
    t = Test()
    res = t.test()
    res = t.test2(1)
    print(t.log)
Sigve Karolius
  • 1,356
  • 10
  • 26