Last Updated on October 3, 2023
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.
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.perf_counter() function will return a value from a high-performance counter.
Return the value (in fractional seconds) of a performance counter, i.e. a clock with the highest available resolution to measure a short duration.
— time — Time access and conversions
The difference between the two calls to the time.perf_counter() function can provide a high-precision estimate of the execution time of a block of code.
Unlike the time.time() function, the time.perf_counter() function is not subject to updates, such as daylight saving and synchronizing the system clock with a time server. This makes the time.perf_counter() function is a reliable approach to benchmarking Python code.
We can call the time.perf_counter() 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.perf_counter() # call benchmark code task() # record end time time_end = time.perf_counter() |
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.perf_counter() 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 loops using all CPUs, download your 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 = perf_counter() # stop the timer def stop(self): self.time_end = perf_counter() # 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 += perf_counter() - 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 = perf_counter() # stop the timer def stop(self): self.sum_duration += perf_counter() - 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 perf_counter # custom stopwatch timer class class StopwatchTimer(object): # start the timer def start(self): self.time_start = perf_counter() # stop the timer def stop(self): self.time_end = perf_counter() # 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.
Free Python Benchmarking Course
Get FREE access to my 7-day email course on Python Benchmarking.
Discover benchmarking with the time.perf_counter() function, how to develop a benchmarking helper function and context manager and how to use the timeit API and command line.
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 perf_counter # 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 = perf_counter() # stop the timer def stop(self): self.sum_duration += perf_counter() - 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 |
Overwhelmed 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
- Python Benchmarking, Jason Brownlee (my book!)
Also, the following Python books have chapters on benchmarking that may be helpful:
- Python Cookbook, 2013. (sections 9.1, 9.10, 9.22, 13.13, and 14.13)
- High Performance Python, 2020. (chapter 2)
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.
Elena says
Thank you for the tutorial, Jason!
Useful and to the point as always.
Jason Brownlee says
Thank you, I’m happy it helped!