0

I modified some code I found here on stackoverflow, but I get some weird behaviour. Can anyone see my error?

import atexit
from time import clock

line = "="*10 + ">>>"

def secondsToStr(s):
    return "{0}.{1}ms".format(round(s*1000), round(s*1000000))

##
# @brief Starts a timer. If the program crashes, the end function will be called anyway.
def start():
    atexit.register(stop)
    print(line,"Start time measurement")
    startTime = clock()
    print("new start time:", startTime)

##
# @brief Needs to be called after start(). Prints the time passed since start() was called.
def stop():
    end = clock()
    elapsed = end-startTime
    print(startTime, end)    # Inserted for debugging
    print(line, "Ellapsed time:", secondsToStr(elapsed))
    atexit.unregister(stop)

def now():
    return secondsToStr(clock())

startTime = clock()

The idea is to call start() and stop() to measure the time the program takes in between those two calles. Weirdly, the startTime does not change. Thus every call of stop() gives the past time since the first call of start(). Here is an example output:

==========>>> Start time measurement
new start time: 0.285078
Doing work
0.231932 1.766478
==========>>> Ellapsed time: 1535.1534546ms

==========>>> Start time measurement
new start time: 1.766624
More work
0.231932 1.975752
==========>>> Ellapsed time: 1744.1743820ms

==========>>> Start time measurement
new start time: 1.975821
More work
0.231932 1.976301
==========>>> Ellapsed time: 1744.1744369ms

Why is the startTime never changing? It should get a new value every time start() is called.

Community
  • 1
  • 1
Natjo
  • 2,005
  • 29
  • 75

2 Answers2

1

The reason it doesn't work is because inside start, startTime is a local variable. If you want to update the global variable, you need to tell python that explicitly:

def start():
    global startTime  # tell python to work with `startTime` in the global scope.
    atexit.register(stop)
    print(line,"Start time measurement")
    startTime = clock()
    print("new start time:", startTime)

Note however that 99% of the time, when you use the global statement, there's probably a better alternative. Without knowing your exact use-case, it's hard to give a perfect suggestion. However, I might consider a context manager here:

import contextlib
from time import clock

line = "="*10 + ">>>"

def secondsToStr(s):
    return "{0}.{1}ms".format(round(s*1000), round(s*1000000))

@contextlib.contextmanager
def timer():
    start = clock()
    try:
        yield None
    finally:
        stop = clock()
        print(line, "Ellapsed time:", secondsToStr(elapsed))

You'd use this as follows:

with timer():
    do_something()
    do_something_else()

And after the functions return, you'll get the combined runtime of the two functions printed. As with your original, this will still print if an exception occurs.

mgilson
  • 300,191
  • 65
  • 633
  • 696
-1

On Unix, return the current processor time as a floating point number expressed in seconds. The precision, and in fact the very definition of the meaning of “processor time”, depends on that of the C function of the same name, but in any case, this is the function to use for benchmarking Python or timing algorithms.

This means the time.clock() measured the time from the start of your process. If you want to measure wall time, you can use time.time()

DXM
  • 1,249
  • 1
  • 14
  • 22