Code Monkey home page Code Monkey logo

rich-bench's Introduction

rich-bench

A little Python benchmarking tool.

Why do I need this?

The builtin timeit module for Python is great, but the typical usage for micro-benchmarks is to run a small script like this:

python -m timeit "a = 1; b = 2; a * b"

The problem with this approach is that the compiled code is a module, so any variables on the top-level are globals. The compiled bytecode is different to the same statements being inside a local scope (e.g. a method or function). They behave and perform very differently in CPython.

richbench encourages you to write benchmarks inside functions to properly simulate the closures and scope of production code.

Installation

Requires Python 3.6+ and can be installed using pip:

pip install richbench

Usage

Write your benchmark functions in a directory and run richbench with that target to get the results:

$ richbench my_benchmarks/

Results are displayed in a table like this:

Example result table

$ richbench --help
usage: richbench [-h] [--profile] [--percentage] [--markdown] [--benchmark [BENCHMARK]] [--repeat REPEAT] [--times TIMES] target [target ...]

positional arguments:
  target

options:
  -h, --help            show this help message and exit
  --profile             Profile the benchmarks and store in .profiles/
  --percentage          Show percentage of improvement instead of multiplier
  --markdown            Prints a markdown friendly table
  --benchmark [BENCHMARK]
                        Run specific benchmark
  --repeat REPEAT       Repeat benchmark this many times
  --times TIMES         Run benchmark this many times

Writing benchmarks

Benchmarks should be in a directory and must have the filename bench_{name}.py.

The last statement in the benchmark file should be a list, called __benchmarks__ with a list of tuples containing:

  1. function a
  2. function b
  3. the name of the benchmark
def sort_seven():
    """Sort a list of seven items"""
    for _ in range(10_000):
        sorted([3,2,4,5,1,5,3])

def sort_three():
    """Sort a list of three items"""
    for _ in range(10_000):
        sorted([3,2,4])

__benchmarks__ = [
    (sort_seven, sort_three, "Sorting 3 items instead of 7")
]

Tips for benchmarking

Inside your benchmark function try to:

  • Run setup commands once
  • Repeat the code you want to benchmark as many times as possible to create a stable benchmark

For micro-benchmarks, this can be achieved by calling 1000 - 100,000 times.

If your benchmark code completes within 0.001s it is likely you will get unstable benchmarks because of the CPU doing other activities. Increase the times the target code is run within the function.

Profiling

By adding the --profile flag to the command line, it will generate a subdirectory .profiles with HTML profile data of your target functions.

rich-bench's People

Contributors

tonybaloney avatar aganders3 avatar

Stargazers

Eric Brown avatar Abbas avatar Piotr Duda avatar Sidafa Conde avatar Romain Dartigues avatar Cesar Marinho avatar Nico Galoppo avatar  avatar Herbert Rusznak avatar Myles avatar Artin Mohammadi avatar  avatar Whiskeybear avatar Hai Zhu avatar Oleksandr Bazna avatar  avatar  avatar Ondřej Míchal avatar Valentin Laurent avatar Igor avatar  avatar Max Halford avatar Camron Flanders avatar Fernando Jorge Mota avatar Uri Laserson avatar Jan Roudaut avatar Pablo Martí Gamboa avatar Frank Wiles avatar Ilya Siamionau avatar Simon avatar Chyld Medford avatar Oli Russell avatar Mateusz Frąk avatar Finley Warman avatar Robert Scheidegger avatar Houssem Nasri avatar  avatar Jorge Massih avatar Salvo avatar Jason Garber avatar Advik avatar Christopher Schröder avatar Sofian Mejjoute avatar Omar MHAIMDAT avatar Paul Sanders avatar Josh Coles avatar  avatar Gary Jarrel avatar Arthur Hamon avatar Abreto avatar Edvard Majakari avatar Sergey Krashevich avatar David Gidwani avatar ~hedy avatar Drew Oldag avatar Lingxi Li avatar Andrew Gazelka avatar Karpushkin Gleb avatar Lionel Tay avatar Bob Green avatar Nicolas Brousse avatar  avatar BethanyG avatar Hugefiver avatar Grigoriy Krasnopolskiy avatar Kyle Rooker avatar Junaid Rahim avatar Kristin Cowalcijk avatar Zev Averbach avatar Mostafa avatar Steven D. avatar Caleb Castleberry avatar Nikolaus Schlemm avatar Alessandro Lucantonio avatar Robert Korzeniec avatar Maciej Wrześniewski avatar Michael Entrup avatar Hei avatar Christophe Nanteuil avatar Jan Tkacik avatar Doronin Evgeniy avatar Eugene Morozov avatar Izabela Kowal avatar Benjamin avatar Christian Ledermann avatar Arcticfox avatar Yoseph Bernandus avatar Tushar Kanhe avatar Berend Klein Haneveld avatar Jacob A Rose avatar This code is... avatar Robbie van Leeuwen avatar Wolf Thomsen avatar  avatar Daniel Bruno avatar Guillaume Gelin avatar Tarcísio Fischer avatar Dorukcan Kişin avatar Vladimir Bolshakov avatar William Jamir Silva avatar

Watchers

 avatar James Cloos avatar  avatar  avatar

rich-bench's Issues

Feature: Benchmarking without a reference?

Reading the documentation made me wonder why the __benchmarks__ entries are tuples with two functions a and b. Apparently this assumes that a benchmark always has to be performed against some kind of reference?

I'm wondering if the framework can be easily adapted to use cases where one doesn't have such a reference function. Say, I just to benchmark sort_three without the kind of arbitrary sort_seven reference.

Is this already supported somehow?

Richbench does not work

I am using Python 3.11 on Arch Linux and found the example work but my other function does not work. Here is my source code:

import logging

logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s')


def _log():
    for _ in range(10_000):
        logging.warning(_)

def _print():
    for _ in range(10_000):
        print(_)

__benchmarks__ = [
    (_log, _print, "Log >< Print"),
    (_print, _log, "Print >< Log")
]

Output:

image

improve rendering of suite.py results

  • fit it to the user's screen (abbreviate benchmark titles)
  • increase number of decimal places to accommodate tiny numbers (currently "**kwargs..." and "slicing with memoryview...")

I'd be happy to submit a PR for these.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.