# 8.3. Micro-benchmarking¶

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil -- Donald Knuth

## 8.3.1. Evaluation¶

• Fresh start of Python process

• Clean memory before start

• Same data

• Same start conditions, CPU load, RAM usage, iostat

• Do not measure how long Python wakes up

• Check what you measure

## 8.3.2. Timeit - Programmatic use¶

• timeit

Code 8.40. Timeit simple statement
from timeit import timeit

setup = """name = 'José Jiménez'"""
stmt = """result = f'My name... {name}'"""

duration = timeit(stmt, setup, number=10000)

print(duration)
# 0.0005737080000000061

Code 8.41. Timeit multiple statements with setup code
from timeit import timeit

setup = """
firstname = 'José'
lastname = 'Jiménez'
"""

TEST = dict()
TEST[0] = 'name = f"{firstname} {lastname}"'
TEST[1] = 'name = "{0} {1}".format(firstname, lastname)'
TEST[2] = 'name = firstname + " " + lastname'
TEST[3] = 'name = " ".join([firstname, lastname])'

for stmt in TEST.values():
duration = timeit(stmt, setup, number=10000)
print(f'{duration:.5}\t{stmt}')

# 0.00071559    name = f"{firstname} {lastname}"
# 0.0026514     name = "{0} {1}".format(firstname, lastname)
# 0.001015      name = firstname + " " + lastname
# 0.0013494     name = " ".join([firstname, lastname])

Code 8.42. Timeit with globals()
from timeit import timeit

def factorial(n: int) -> int:
if n == 0:
return 1
else:
return n * factorial(n-1)

duration = timeit(
stmt='factorial(500); factorial(400); factorial(450)',
globals=globals(),
number=10000,
)

duration = round(duration, 6)

print(f'factorial time: {duration} seconds')
# factorial time: 2.845382 seconds


## 8.3.3. Timeit - Console use¶

Code 8.43. Timeit
python3 -m timeit -n100000 -r100 --setup='name="Jose Jimenez"' 'output = f"My name... {name}"'
# 100000 loops, best of 100: 55.9 nsec per loop

python3 -m timeit -n100000 -r100 --setup='name="Jose Jimenez"' 'output = "My name... {name}".format(name=name)'
# 100000 loops, best of 100: 327 nsec per loop

python3 -m timeit -n100000 -r100 --setup='name="Jose Jimenez"' 'output = "My name... %s" % name'
# 100000 loops, best of 100: 124 nsec per loop

-n N, --number=N
how many times to execute 'statement'

-r N, --repeat=N
how many times to repeat the timer (default 5)

-s S, --setup=S
statement to be executed once initially (default pass)

-p, --process
measure process time, not wallclock time, using time.process_time() instead of time.perf_counter(), which is the default

-u, --unit=U
specify a time unit for timer output; can select nsec, usec, msec, or sec

-v, --verbose
print raw timing results; repeat for more digits precision

-h, --help
print a short usage message and exit


## 8.3.4. PyPerformance¶

• pip install pyperformance

• pyperformance run -b django_template - run django template benchmark

$python3.10 -m venv venv-py310$ venv-py310/bin/pip install pyperformance
$venv-py310/bin/pyperformance run -b django_template  $ python3.11 -m venv venv-py311
$venv-py311/bin/pip install pyperformance$ venv-py311/bin/pyperformance run -b django_template