| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Here are some recent and important revisions. 👉 Complete list of results.
Key: 📄: table, 📈: time plot, 🧠: memory plot
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-08-23 | python/6fcac09401e336b25833 | 6fcac09 (NOGIL) | 1.132x ↑ 📄📈 |
1.093x ↓ 📄📈 |
1.105x ↓ 📄📈 |
1.135x ↓ 📄📈🧠 |
| 2025-08-23 | python/6fcac09401e336b25833 | 6fcac09 (JIT) | 1.297x ↑ 📄📈 |
1.024x ↑ 📄📈 |
1.018x ↑ 📄📈 |
1.011x ↓ 📄📈🧠 |
| 2025-08-23 | python/6fcac09401e336b25833 | 6fcac09 | 1.313x ↑ 📄📈 |
1.036x ↑ 📄📈 |
1.029x ↑ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-05-24 | python/2fd09b011031f3c00c34 | 2fd09b0 (TAILCALL) | ||||
| 2025-05-18 | python/009e7b36981fd07f7cca | 009e7b3 (TAILCALL) | ||||
| 2025-05-10 | python/1a87b6e9ae6da255f304 | 1a87b6e (TAILCALL) |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-07-02 | python/fa43a1e0f8caf00a1589 | fa43a1e (JIT) | 1.422x ↑ 📄📈 |
1.093x ↑ 📄📈 |
1.024x ↑ 📄📈 |
|
| 2025-07-02 | brandtbucher/jit_up_6_12 | ebec717 (JIT) | 1.424x ↑ 📄📈 |
1.094x ↑ 📄📈 |
1.025x ↑ 📄📈 |
1.001x ↑ 📄📈🧠 |
| 2025-07-02 | brandtbucher/jit_up_6_6 | 6c99b17 (JIT) | 1.421x ↑ 📄📈 |
1.092x ↑ 📄📈 |
1.023x ↑ 📄📈 |
1.000x ↓ 📄📈🧠 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-06-30 | python/75f40595e555e7d016cf | 75f4059 (TAILCALL) | ||||
| 2025-06-21 | python/b14986c91464b06e9016 | b14986c (TAILCALL) | ||||
| 2025-06-17 | python/fba5dded6df3c2b19435 | fba5dde (TAILCALL) |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (NOGIL) | 1.207x ↑ 📄📈 |
1.048x ↓ 📄📈 |
1.048x ↓ 📄📈 |
1.107x ↓ 📄📈🧠 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (JIT) | 1.354x ↑ 📄📈 |
1.056x ↑ 📄📈 |
1.060x ↑ 📄📈 |
1.003x ↓ 📄📈🧠 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f | 1.359x ↑ 📄📈 |
1.061x ↑ 📄📈 |
1.063x ↑ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-07-08 | brandtbucher/jit_targets | 997a858 (JIT) | 1.003x ↓ 📄📈🧠 |
|||
| 2025-07-07 | python/0240ef4705d835e27beb | 0240ef4 (JIT) | ||||
| 2025-06-28 | brandtbucher/jit_oz | 6448067 (JIT) | 1.015x ↓ 📄📈🧠 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (NOGIL) | 1.204x ↑ 📄📈 |
1.040x ↑ 📄📈 |
1.022x ↓ 📄📈 |
1.076x ↓ 📄📈 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (JIT) | 1.366x ↑ 📄📈 |
1.169x ↑ 📄📈 |
1.120x ↑ 📄📈 |
1.058x ↑ 📄📈 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f | 1.287x ↑ 📄📈 |
1.102x ↑ 📄📈 |
1.059x ↑ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (TAILCALL) | ||||
| 2025-10-25 | python/421a475c87771d46752c | 421a475 (TAILCALL) | ||||
| 2025-10-19 | python/bedaea05987738c4c6b9 | bedaea0 (TAILCALL) |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (NOGIL) | 1.353x ↑ 📄📈 |
1.387x ↑ 📄📈 |
1.173x ↑ 📄📈 |
1.089x ↓ 📄📈 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (JIT) | 1.531x ↑ 📄📈 |
1.556x ↑ 📄📈 |
1.342x ↑ 📄📈 |
1.043x ↑ 📄📈 |
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f | 1.467x ↑ 📄📈 |
1.490x ↑ 📄📈 |
1.288x ↑ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-11-01 | python/2f60b8f02fe7cb83dd58 | 2f60b8f (TAILCALL) | ||||
| 2025-10-25 | python/421a475c87771d46752c | 421a475 (TAILCALL) | ||||
| 2025-10-19 | python/bedaea05987738c4c6b9 | bedaea0 (TAILCALL) |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-05-24 | python/2fd09b011031f3c00c34 | 2fd09b0 (NOGIL) | 1.052x ↑ 📄📈 |
1.085x ↑ 📄📈 |
1.067x ↓ 📄📈 |
|
| 2025-05-10 | python/1a87b6e9ae6da255f304 | 1a87b6e (NOGIL) | 1.013x ↑ 📄📈 |
1.046x ↑ 📄📈 |
1.101x ↓ 📄📈 |
1.123x ↓ 📄📈 |
| 2025-05-10 | python/1a87b6e9ae6da255f304 | 1a87b6e (JIT) | 1.069x ↑ 📄📈 |
1.090x ↑ 📄📈 |
1.036x ↓ 📄📈 |
1.061x ↓ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-03-08 | python/a3990df6121880e8c678 | a3990df (TAILCALL) | ||||
| 2025-03-06 | Fidget-Spinner/clang_hot | 37fb620 (TAILCALL) | ||||
| 2025-03-01 | python/c9932a9ec8a3077933a8 | c9932a9 (TAILCALL) |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-08-30 | python/d3d94e0ed715829d9bf9 | d3d94e0 (NOGIL) | 1.278x ↑ 📄📈 |
1.026x ↑ 📄📈 |
1.028x ↑ 📄📈 |
1.026x ↓ 📄📈🧠 |
| 2025-08-30 | python/d3d94e0ed715829d9bf9 | d3d94e0 (JIT) | 1.344x ↑ 📄📈 |
1.062x ↑ 📄📈 |
1.064x ↑ 📄📈 |
1.010x ↑ 📄📈🧠 |
| 2025-08-30 | python/d3d94e0ed715829d9bf9 | d3d94e0 | 1.331x ↑ 📄📈 |
1.051x ↑ 📄📈 |
1.054x ↑ 📄📈 |
| date | fork/ref | hash/flags | vs. 3.10.4: | vs. 3.12.0: | vs. 3.13.0: | vs. base: |
|---|---|---|---|---|---|---|
| 2025-08-30 | python/d3d94e0ed715829d9bf9 | d3d94e0 (TAILCALL) | ||||
| 2025-08-23 | python/6fcac09401e336b25833 | 6fcac09 (TAILCALL) | ||||
| 2025-08-16 | python/3663b2ad54c9e15775a6 | 3663b2a (TAILCALL) |
* indicates that the exact same versions of pyperformance was not used.
For the results above, the "faster/slower" result is a geometric mean of each of the benchmarks.
Below are longitudinal timing results. There are also 🧠 longitudinal memory results.
The results have a resolution of 0.001 (0.1%).
This is a CHANGELOG of how any derived data has changed:
Visit the 🔒 benchmark action and click the "Run Workflow" button.
The available parameters are:
To watch the progress of the benchmark, select it from the 🔒 benchmark action page. It may be canceled from there as well. To show only your benchmark workflows, select your GitHub ID from the "Actor" dropdown.
When the benchmarking is complete, the results are published to this repository and will appear in the master table. Each set of benchmarks will have:
The most convenient way to get results locally is to clone this repo and git pull from it.
To automate benchmarking runs, it may be more convenient to use the GitHub CLI. Once you have gh installed and configured, you can run benchmarks by cloning this repository and then from inside it:
$ gh workflow run benchmark.yml -f fork=me -f ref=my_branchAny of the parameters described above are available at the commandline using the -f key=value syntax.
To collect Linux perf sampling profile data for a benchmarking run, run the _benchmark action and check the perf checkbox.
The results will be available as "artifacts" on the run page after the run -- they are not committed directly to the repository.
The python -m bench_runner profiling_plot command can be used to turn the raw perf results into tables and graphs.
If the default comparisons generated by this tool aren't sufficient, you can check out the repo and use the same infrastructure to generate any arbitrary comparison.
Check out a local copy of this repo:
$ git clone https://github.com/faster-cpython/benchmarking-publicCreate a new virtual environment, activate it and install the dependencies into it:
$ cd benchmarking-public
$ python -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txtRun bench_runner's compare tool:
usage:
Generate a set of comparisons between arbitrary commits. The commits
must already exist in the dataset.
[-h] --output-dir OUTPUT_DIR [--type {1:n,n:n}] commit [commit ...]
positional arguments:
commit Commits to compare. Must be a git commit hash prefix. May optionally have a friendly name
after a comma, e.g. c0ffee,main. If ends with a "T", use the Tier 2 run for that commit. If
ends with a "J", use the JIT run for that commit. If ends with a "N", use the NOGIL run for
that commit.
options:
-h, --help show this help message and exit
--output-dir OUTPUT_DIR
Directory to output results to.
--type {1:n,n:n} Compare the first commit to all others, or do the full product of all commits
For example:
$ python -m bench_runner compare e418fc3,default e418fc3J,jit --output comparison --type 1:nThe infrastructure to make all of this work is the bench_runner project. Look there for more detailed developer docs.
The easiest way to reproduce what is here is to use the bench_runner project library directly, but if you want to run parts of it in a different context or better understand how the numbers are calculated, this section describes some of the things that the benchmarking infrastructure does.
These results combine benchmarks that live in the pyperformance and pyston/python-macrobenchmarks projects, so running the default set from pyperformance will definitely produce different results. To combine these benchmarks in the same run, clone both repos side-by-side in the same directory and use a manifest file to combine them. This file should be passed to pyperformance run:
pyperformance run --manifest benchmarks.manifest
Benchmarks and stats collection can happen in three different configurations. Here "configuration" may be a combination of both build-time and run-time flags:
Information about the configuration of the run is in the README.md at the root of each run directory. The directory name will also include PYTHON_UOPS for Tier 2, JIT for JIT, NOGIL for free-threading and CLANG for tail calling.
To reduce the number of unknown variables when comparing results, runs are always compared against runs of the same configuration. Be aware that sometimes the base commit on main may predate the configuration becoming available, for example, before the JIT compiler was merged into main. (Exception to this rule are the weekly benchmarks of upstream main, there Tier 2, JIT, NOGIL and CLANG configurations are compared against default configurations of the same commit, but that isn't relevant for the common case of testing a pull request).
An additional sharp edge is that, by default, pyperformance does not pass environment variables to the child process that actually does the work. Therefore for a Tier 2 configuration, the --inherit-environ=PYTHON_UOPS flag must be passed to pyperformance run when running benchmarks.
For detailed information, see how configurations affect build time flags in the Github Actions configuration..
Timing benchmarks are notoriously noisy. There are a few techniques to reduce this:
pystats are a set of counters in CPython that measure things like the number of times each bytecode instruction is executed. (Detailed documentation of all of the counters should be added to CPython in the future).
Checking the pystats box will generate pystats results automatically.
Collecting pystats requires a special build of CPython with pystats enabled: (./configure --enable-pystats).
pystats must also be enabled at runtime, either using the -Xpystats command line argument or sys._stats_on(). pyperformance/pyperf handles this step automatically when running on a pystats-enabled build. Stats collection is enabled during actual benchmarking code, and disabled while running the "benchmarking harness" code in pyperf itself. pyperf has the concept of "warmup" runs, which allow things like cache lines to warmup before actually timing benchmarks. While they aren't included in the timing benchmarks, these warmup runs are included in pystats collection since often Tier 2/JIT traces are created during warmup, and we don't want the stats to appear as if the traces ran but were not created.
Any statistics collected are then dumped at exit to the /tmp/py_stats directory with a random filename. Lastly, the Tools/scripts/summarize_stats.py script (in the CPython repo) is used to read all of the files from /tmp/py_stats and produce a human-readable markdown summary and a JSON file with aggregate data. Because of this design, it is imperative that:
For more information, see the actual code to collect pystats.
Hierarchical performance testing (HPT) is a method introduced in this paper:
T. Chen, Y. Chen, Q. Guo, O. Temam, Y. Wu and W. Hu, "Statistical performance comparisons of computers," IEEE International Symposium on High-Performance Comp Architecture, New Orleans, LA, USA, 2012, pp. 1-12, doi: 10.1109/HPCA.2012.6169043.
From the abstract:
In traditional performance comparisons, the impact of performance variability is usually ignored (i.e., the means of performance measurements are compared regardless of the variability), or in the few cases where it is factored in using parametric confidence techniques, the confidence is either erroneously computed based on the distribution of performance measurements (with the implicit assumption that it obeys the normal law), instead of the distribution of sample mean of performance measurements, or too few measurements are considered for the distribution of sample mean to be normal. … We propose a non-parametric Hierarchical Performance Testing (HPT) framework for performance comparison, which is significantly more practical than standard parametric techniques because it does not require to collect a large number of measurements in order to achieve a normal distribution of the sample mean.
For each result, we compute a reliability score, as well as the estimated speedup at the 90th, 95th and 99th percentile.
The inclusion of HPT scores is considered experimental as we learn about their usefulness for decision-making.
| Back | FazBrowse Home | New Git URL |