My progress so far with building a Python performance testing framework
Whats are best practices and tools for profiling and performance testing python code? - Stack Overflow
Proper way to automatically test performance in Python (for all developers)? - Stack Overflow
How can I time a code segment for testing performance with Pythons timeit? - Stack Overflow
Videos
I have always wanted to give back to the Python community by creating something useful for others to use and help make Python an even better programming language.
That is why last year I started work on my very first open-source project called QuickPotato. Now taking a moment to look back at my project and see how it has grown so far makes me contend and motivated to continue to make it better and more useful.
So what have I built? Well, I have to build a Python performance testing framework to make it easier to create automated performance tests for your Python code.
Allowing you to do the following awesome things to aid you in creating more performant Python code:
-
Automatically profile your code when a test is executed.
-
Regression test your code to verify that a change did not impact performance.
-
Make sure that your code adheres to your standards by setting performance boundaries.
-
Directly start analyzing the performance bottleneck by generating helpful visualizations.
-
Decide where your start profiling your code by setting a performance breakpoint in the form of a decorator.
The past half-year (almost) I have introduced the following visuals to help debug performance bottlenecks:
Flame graphs
A flame graph showing how much CPU is being burnedHeatmaps
a heatmap showing the hot parts of your codeA CSV exporter
A CSV export of the profiled classA Plotly bar chart
A python bar chart showing the performance of a classI will continue to work on making this project bigger and better and hopefully one day it could help somebody out with troubleshooting some pesky performance problems :).
What do you guys think about my little framework?
If you wanna check out the project or bookmark it by giving it a star on GitHub you can find a link down below to the repo:
https://github.com/JoeyHendricks/QuickPotato
Check out funkload - it's a way of running your unit tests as either functional or load tests to gauge how well your site is performing.
Another interesting project which can be used in conjunction with funkload is codespeed. This is an internal dashboard that measures the "speed" of your codebase for every commit you make to your code, presenting graphs with trends over time. This assumes you have a number of automatic benchmarks you can run - but it could be a useful way to have an authoritative account of performance over time. The best use of codespeed I've seen so far is the speed.pypy.org site.
As to your requirement for determinism - perhaps the best approach to that is to use statistics to your advantage? Automatically run the test N times, produce the min, max, average and standard deviation of all your runs? Check out this article on benchmarking for some pointers on this.
I want the test to be DETERMINISTIC - regardless of what is happening on the machine running the tests, I want multiple runs of the test to return the same results.
Fail. More or less by definition this is utterly impossible in a multi-processing system with multiple users.
Either rethink this requirement or find a new environment in which to run tests that doesn't involve any of the modern multi-processing operating systems.
Further, your running web application is not deterministic, so imposing some kind of "deterministic" performance testing doesn't help much.
When we did time-critical processing (in radar, where "real time" actually meant real time) we did not attempt deterministic testing. We did code inspections and ran simple performance tests that involved simple averages and maximums.
Use cProfile to instrument the interpreter to ignore "outside noise". I'm not sure I know how to read the pstats structure yet, but I'm sure it is doable.
The Stats object created by the profiler is what you're looking for.
http://docs.python.org/library/profile.html#the-stats-class
Focus on 'pcalls', primitive call count, in the profile statistics and you'll have something that's approximately deterministic.
You can use time.time() or time.clock() before and after the block you want to time.
import time
t0 = time.time()
code_block
t1 = time.time()
total = t1-t0
This method is not as exact as timeit (it does not average several runs) but it is straightforward.
time.time() (in Windows and Linux) and time.clock() (in Linux) are not precise enough for fast functions because they return the time in an integer number of seconds (you'll get total = 0 for short durations). In this case or if you want to average the time elapsed by several runs, you have to manually call the function multiple times (As I think you already do in you example code and timeit does this automatically when you set its number argument)
import time
def myfast():
code
n = 10000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()
total_n = t1-t0
In Windows, time.clock() has higher precision because it returns the time in microseconds whereas time.time() returns the time in seconds. So choose whichever makes sense for your situation.
If you are profiling your code and can use IPython, it has the magic function %timeit.
%%timeit operates on cells.
In [2]: %timeit cos(3.14)
10000000 loops, best of 3: 160 ns per loop
In [3]: %%timeit
...: cos(3.14)
...: x = 2 + 3
...:
10000000 loops, best of 3: 196 ns per loop