You can develop a stopwatch timer class to benchmark the execution time of Python code.
In this tutorial, you will discover how to develop a stopwatch timer class for benchmarking in Python.
Let’s get started.
Table of Contents
Need a Stopwatch Timer Class for Benchmarking
Benchmarking Python code refers to comparing the performance of one program to variations of the program.
Benchmarking is the practice of comparing business processes and performance metrics to industry bests and best practices from other companies. Dimensions typically measured are quality, time and cost.
— Benchmarking, Wikipedia.
Typically, we make changes to the programs, such as adding concurrency, in order to improve the performance of the program on a given system.
Improving performance typically means reducing the run time of the program.
Therefore, when we benchmark programs in Python after adding concurrency, we typically are interested in recording how long a program takes to run.
We can benchmark Python code using the time module.
The time.time() function will return the current time in seconds since January 1st 1970 (called the epoch).
Return the time in seconds since the epoch as a floating point number.
— time — Time access and conversions
We can call this function at the beginning of the code we wish to benchmark, and again at the end of the code we wish to benchmark.
For example:
1 2 3 4 5 6 7 |
... # record start time time_start = time.time() # call benchmark code task() # record end time time_end = time.time() |
The difference between the start and end time is the total duration of the program in seconds.
For example:
1 2 3 4 5 |
... # calculate the duration time_duration = time_end - time_start # report the duration print(f'Took {time_duration:.3f} seconds') |
You can learn more about benchmarking Python code with the time.time() function in the tutorial:
How can we hide all of this code to benchmark with a simple interface?
Can we develop a stopwatch timer class that we can use for ad hoc benchmarking?
Run your loops using all CPUs, download my FREE book to learn how.
How to Develop a Stopwatch Timer Class
We can develop a stopwatch timer class.
Generally, the class provides a method to start the timer, a method to stop the timer, and a method to get the duration that the timer was running.
We will explore two versions of the timer:
- Simple single-use timer.
- Timer that can be resumed.
This idea of developing a stopwatch timer for benchmarking is not new, many examples exist.
For example, a similar approach is described in the Python Cookbook, in section “13.13. Making a Stopwatch Timer“.
Let’s dive in.
Simple Stopwatch Timer
We can develop a simple stopwatch timer.
The timer provides three methods:
- start(): starts the timer, and records the current time.
- stop(): stops the timer, and records the current time.
- duration(): returns the difference between end and start times
And that’s it.
Tying this together, the StopwatchTimer class below implements this.
1 2 3 4 5 6 7 8 9 10 11 |
# custom stopwatch timer class class StopwatchTimer(object): # start the timer def start(self): self.time_start = time() # stop the timer def stop(self): self.time_end = time() # get the duration def duration(self): return self.time_end - self.time_start |
We could change the design slightly to calculate and record the duration when the stop() method is called and then simply return it in the duration method.
I prefer tracking the start and stop times and making them available if needed and computing the duration derived from those recorded details.
To start the timer we create an instance and call the start() method:
1 2 3 4 5 |
... # create the timer timer = StopwatchTimer() # start the timer timer.start() |
To stop the timer, we call the stop() method:
1 2 3 |
... # stop the timer timer.stop() |
Then, if we want to report the duration, we can call the duration() method and print the result:
1 2 3 |
... # report the duration print(timer.duration()) |
The timer could be reused by calling start() and stop() again in the same order. This will overwrite the internal state and stop time attributes correctly.
This timer cannot be resumed again if stopped.
Next, let’s look at how we might update the StopwatchTimer class to add the ability to resume the timer after it has been stopped.
Stopwatch Timer With Resume Support
We can update the stopwatch timer class developed in the previous section to add resume support.
Resume support can be added by updating the stop() method to calculate the duration since start() was called and adding the result to an internal attribute.
For example:
1 2 3 |
# stop the timer def stop(self): self.sum_duration += time() - self.time_start |
This allows each combination of start() and stop() to be accumulated and returned via the call to duration().
We can then add a new method to reset the internal duration accumulation, which must be called in order to reuse the timer.
1 2 3 |
# reset the timer def reset(self): self.sum_duration = 0 |
It is also a good idea to reset the timer the first time in the constructor.
1 2 3 |
# constructor def __init__(self): self.reset() |
And that’s it, tying this together, the ResumeStopwatchTimer class provides a reusable stopwatch timer for benchmarking.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# custom stopwatch timer class that can be resumed class ResumeStopwatchTimer(object): # constructor def __init__(self): self.reset() # start or resume the timer def start(self): self.time_start = time() # stop the timer def stop(self): self.sum_duration += time() - self.time_start # get the duration def duration(self): return self.sum_duration # reset the timer def reset(self): self.sum_duration = 0 |
We can then create the timer and call the start() method to start the timer.
1 2 3 4 5 |
... # create the timer timer = ResumeStopwatchTimer() # start the timer timer.start() |
The timer can then be stopped and started again, then stopped.
1 2 3 4 5 6 7 8 9 |
... # stop the timer timer.stop() # ... # start the timer timer.start() ... # stop the timer timer.stop() |
Finally, we can retrieve and report the overall duration of all start-stop pairs and reset the timer for reuse.
1 2 3 4 5 |
... # report the duration print(timer.duration()) # reset the timer timer.reset() |
Now that we know how to develop a stopwatch timer, let’s look at some worked examples.
Example of Using a Stopwatch Timer
We can explore an example of benchmarking Python code using the simple StopwatchTimer class.
In this case, we will create a list of 100,000,000 squared integers, which should take a few seconds.
This requires first creating the stopwatch and starting the timer.
1 2 3 4 5 |
... # create the timer timer = StopwatchTimer() # start the timer timer.start() |
We can then run our target code.
1 2 3 |
... # create a list of squared numbers result = [i*i for i in range(100000000)] |
Finally, we can stop the timer and report the duration in seconds.
1 2 3 4 5 |
... # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# SuperFastPython.com # example of a custom stopwatch timer class from time import time # custom stopwatch timer class class StopwatchTimer(object): # start the timer def start(self): self.time_start = time() # stop the timer def stop(self): self.time_end = time() # get the duration def duration(self): return self.time_end - self.time_start # create the timer timer = StopwatchTimer() # start the timer timer.start() # create a list of squared numbers result = [i*i for i in range(100000000)] # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') |
Running the example first creates and starts the timer.
The list of squared integers is then created, which takes a moment.
Finally, the timer is stopped and the result is reported.
In this case, we can see that the task took about 5.103 seconds.
This highlights how we can use the simple benchmark timer class.
1 |
Took 5.1031060218811035 seconds |
Next, let’s explore how we might use the stopwatch timer class that can be resumed.
Example of Using a Stopwatch Timer With Resume
We can explore an example of using the stopwatch timer that can be resumed.
In this case, we will first time one target statement, stop the timer, then resume the timer to time a second statement. Finally, we will report the combined duration of both statements.
This involves first creating and starting the ResumeStopwatchTimer, executing the first statement, then stopping the timer and reporting the duration.
1 2 3 4 5 6 7 8 9 10 11 |
... # create the timer timer = ResumeStopwatchTimer() # start the timer timer.start() # create a list of squared numbers result = [i*i for i in range(100000000)] # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') |
We can then resume the timer by calling the start() method, executing the second statement, stopping the timer, and reporting the overall duration of both statements.
1 2 3 4 5 6 7 8 9 |
... # resume the timer timer.start() # do some more work result = [i*i for i in range(100000000)] # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') |
Tying this together, the complete example is listed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# SuperFastPython.com # example of a custom stopwatch timer class with resume support from time import time # custom stopwatch timer class that can be resumed class ResumeStopwatchTimer(object): # constructor def __init__(self): self.reset() # start or resume the timer def start(self): self.time_start = time() # stop the timer def stop(self): self.sum_duration += time() - self.time_start # get the duration def duration(self): return self.sum_duration # reset the timer def reset(self): self.sum_duration = 0 # create the timer timer = ResumeStopwatchTimer() # start the timer timer.start() # create a list of squared numbers result = [i*i for i in range(100000000)] # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') # resume the timer timer.start() # do some more work result = [i*i for i in range(100000000)] # stop the timer timer.stop() # report the duration print(f'Took {timer.duration()} seconds') |
Running the example first creates and starts the timer.
Next, the target code is executed, the timer is stopped and the duration is reported.
In this case, the target code takes about 5.012 seconds to complete.
The timer is then resumed, and the second target statement is executed. The timer is stopped again and the overall duration of the timer is reported.
In this case, the summed duration of the two statements is reported as about 10.841 seconds.
This highlights how we can stop and resume a timer to calculate the overall duration of multiple sections of code.
1 2 |
Took 5.012497186660767 seconds Took 10.84142518043518 seconds |
Overwheled by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Further Reading
This section provides additional resources that you may find helpful.
Books
There are no books dedicated to Python benchmarking.
The following Python books have chapters on benchmarking that may be helpful:
The book Python Cookbook, 2013 has a few sections on benchmarking, such as:
- 9.1. Putting a Wrapper Around a Function
- 9.10. Applying Decorators to Class and Static Methods
- 9.22. Defining Context Managers the Easy Way
- 13.13. Making a Stopwatch Timer
- 14.13. Profiling and Timing Your Program
The book High Performance Python: Practical Performant Programming for Humans has a chapter on benchmarking: Chapter 2: Profiling to Find Bottlenecks, including a section titled "Simple Approaches to Timing—print and a Decorator", and a section titled "Simple Timing Using the Unix time Command".
Benchmarking Guides
- 4 Ways to Benchmark Python Code
- 5 Ways to Measure Execution Time in Python
- Python Benchmark Comparison Metrics
Benchmarking APIs
- time — Time access and conversions
- timeit — Measure execution time of small code snippets
- The Python Profilers
References
Takeaways
You now know how to develop a stopwatch timer class for benchmarking in Python.
Did I make a mistake? See a typo?
I’m a simple humble human. Correct me, please!
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Thank you for the tutorial, Jason!
Useful and to the point as always.
Thank you, I’m happy it helped!