Cómo realizar benchmarks en código Python con pytest-benchmark
 Everett Pompeii
¿Qué es la Evaluación Comparativa?
La evaluación comparativa es la práctica de probar el rendimiento de tu código para ver qué tan rápido (latencia) o cuánto (rendimiento) trabajo puede hacer. Este paso, a menudo pasado por alto en el desarrollo de software, es crucial para crear y mantener un código rápido y de alto rendimiento. La evaluación comparativa proporciona las métricas necesarias para que los desarrolladores comprendan cómo se comporta su código bajo diversas cargas de trabajo y condiciones. Por las mismas razones por las cuales escribes pruebas unitarias y de integración para prevenir regresiones de características, debes escribir evaluaciones comparativas para prevenir regresiones de rendimiento. ¡Los errores de rendimiento son errores!
Escribe FizzBuzz en Python
Para escribir evaluaciones comparativas, necesitamos algún código fuente para comparar. Para empezar, vamos a escribir un programa muy simple, FizzBuzz.
Las reglas para FizzBuzz son las siguientes:
Escribe un programa que imprima los números enteros del
1al100(incluyendo ambos):
- Para múltiplos de tres, imprime
 Fizz- Para múltiplos de cinco, imprime
 Buzz- Para múltiplos de ambos, tres y cinco, imprime
 FizzBuzz- Para todos los demás, imprime el número
 
Hay muchas formas de escribir FizzBuzz. Así que vamos a elegir mi favorita:
for i in range(1, 101):    if n % 15 == 0:        print("FizzBuzz")    elif n % 3 == 0:        print("Fizz")    elif n % 5 == 0:        print("Buzz")    else:        print(i)- Itera desde 
1hasta100, utilizando un rango de101. - Para cada número, calcula el módulo (resto después de la división) tanto para 
3como para5. - Si el resto es 
0, entonces el número es un múltiplo del factor dado.- Si el resto es 
0para15, entonces imprimeFizzBuzz. - Si el resto es 
0para3, entonces imprimeFizz. - Si el resto es 
0para5, entonces imprimeBuzz. 
 - Si el resto es 
 - De lo contrario, simplemente imprime el número.
 
Sigue el Paso a Paso
Para seguir este tutorial paso a paso, necesitarás instalar Python e instalar pipenv.
🐰 El código fuente de este post está disponible en GitHub.
Crea un archivo de Python llamado game.py,
y establece su contenido con la implementación de FizzBuzz anterior.
Luego ejecuta python game.py.
La salida debería verse como:
$ python game.py12Fizz4BuzzFizz78FizzBuzz11Fizz1314FizzBuzz...9798FizzBuzz🐰 ¡Boom! ¡Estás rompiendo la entrevista de codificación!
Antes de continuar, es importante discutir las diferencias entre micro-benchmarking y macro-benchmarking.
Micro-Benchmarking vs Macro-Benchmarking
Existen dos categorías principales de benchmarks de software: micro-benchmarks y macro-benchmarks.
Los micro-benchmarks operan a un nivel similar a las pruebas unitarias.
Por ejemplo, un benchmark para una función que determina Fizz, Buzz, o FizzBuzz para un único número sería un micro-benchmark.
Los macro-benchmarks operan a un nivel similar a las pruebas de integración.
Por ejemplo, un benchmark para una función que juega el juego completo de FizzBuzz, desde 1 hasta 100, sería un macro-benchmark.
Generalmente, es mejor probar al nivel más bajo de abstracción posible. En el caso de los benchmarks, esto los hace más fáciles de mantener, y ayuda a reducir la cantidad de ruido en las mediciones. Sin embargo, al igual que tener algunas pruebas de extremo a extremo puede ser muy útil para verificar la cordura todo el sistema se junta como se esperaba, tener macro-benchmarks puede ser muy útil para asegurarse de que los caminos críticos a través de su software se mantienen con buen rendimiento.
Benchmarking en Python
Las dos opciones populares para benchmarking en Python son: pytest-benchmark y airspeed velocity (asv)
pytest-benchmark es una herramienta de benchmarking poderosa
integrada con el popular marco de pruebas pytest.
Permite a los desarrolladores medir y comparar el rendimiento de su código ejecutando benchmarks junto a sus pruebas unitarias.
Los usuarios pueden comparar fácilmente sus resultados de benchmark localmente
y exportar sus resultados en varios formatos, como JSON.
airspeed velocity (asv) es otra herramienta de benchmarking avanzada en el ecosistema de Python.
Uno de los beneficios clave de asv es su capacidad para generar informes HTML detallados e interactivos,
lo que facilita la visualización de tendencias de rendimiento e identificación de regresiones.
Además, asv soporta Benchmarking Continuo Relativo de forma nativa.
Ambos son soportados por Bencher.
Entonces, ¿por qué elegir pytest-benchmark?
pytest-benchmark se integra perfectamente con pytest,
que es el estándar de facto para pruebas unitarias en el ecosistema de Python.
Recomendaría usar pytest-benchmark para hacer benchmarking de la latencia de tu código,
especialmente si ya estás usando pytest.
Es decir, pytest-benchmark es ideal para medir el tiempo de reloj de pared.
Refactorizar FizzBuzz
Para probar nuestra aplicación FizzBuzz, necesitamos desacoplar nuestra lógica de la ejecución principal de nuestro programa. Los bancos de pruebas no pueden evaluar la ejecución principal. Para hacer esto, necesitamos realizar algunos cambios.
Vamos a refactorizar nuestra lógica FizzBuzz en un par de funciones:
def play_game(n, should_print):    result = fizz_buzz(n)    if should_print:        print(result)    return result
def fizz_buzz(n):    if n % 15 == 0:       return "FizzBuzz"    elif n % 3 == 0:        return "Fizz"    elif n % 5 == 0:        return "Buzz"    else:        return str(n)play_game: Recibe un número enteron, llama afizz_buzzcon ese número, y sishould_printesTrue, imprime el resultado.fizz_buzz: Recibe un número enterony realiza la lógica real deFizz,Buzz,FizzBuzzo número, devolviendo el resultado como una cadena.
Luego, actualiza la ejecución principal para que se vea así:
for i in range(1, 101):    play_game(i, True)La ejecución principal de nuestro programa itera a través de los números del 1 al 100 inclusive y llama a play_game para cada número, con should_print configurado en True.
Evaluando el Rendimiento de FizzBuzz
Para evaluar el rendimiento de nuestro código, necesitamos crear una función de prueba que ejecute nuestra evaluación. Al final de game.py añade el siguiente código:
def test_game(benchmark):    def run_game():        for i in range(1, 101):            play_game(i, False)    benchmark(run_game)- Crea una función llamada 
test_gameque acepte unbenchmarkdepytest-benchmarkcomo fixture. - Crea una función 
run_gameque itere de1a100inclusive.- Para cada número, llama a 
play_game, conshould_printconfigurado enFalse. 
 - Para cada número, llama a 
 - Pasa la función 
run_gameal ejecutorbenchmark. 
Ahora necesitamos configurar nuestro proyecto para ejecutar nuestras evaluaciones.
Crea un nuevo entorno virtual con pipenv:
$ pipenv shell
Creating a Pipfile for this project...Launching subshell in virtual environment... source /usr/bencher/.local/share/virtualenvs/test-xnizGmtA/bin/activateInstala pytest-benchmark dentro de ese nuevo entorno pipenv:
$ pipenv install pytest-benchmarkCreating a Pipfile for this project...Installing pytest-benchmark...Resolving pytest-benchmark...Added pytest-benchmark to Pipfile's [packages] ...✔ Installation SucceededPipfile.lock not found, creating...Locking [packages] dependencies...Building requirements...Resolving dependencies...✔ Success!Locking [dev-packages] dependencies...Updated Pipfile.lock (be953321071292b6175f231c7e2e835a3cd26169a0d52b7b781b344d65e8cce3)!Installing dependencies from Pipfile.lock (e8cce3)...Ahora estamos listos para medir el rendimiento de nuestro código, ejecuta pytest game.py:
$ pytest game.py======================================================= test session starts ========================================================platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)rootdir: /usr/bencher/examples/python/pytest_benchmarkplugins: benchmark-4.0.0collected 1 item
game.py .                                                                                                                    [100%]
------------------------------------------------- benchmark: 1 tests -------------------------------------------------Name (time in us)         Min       Max     Mean  StdDev   Median     IQR   Outliers  OPS (Kops/s)  Rounds  Iterations----------------------------------------------------------------------------------------------------------------------test_game             10.5416  237.7499  10.8307  1.3958  10.7088  0.1248  191;10096       92.3304   57280           1----------------------------------------------------------------------------------------------------------------------
Legend:  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.  OPS: Operations Per Second, computed as 1 / Mean======================================================== 1 passed in 1.68s =========================================================🐰 ¡A zapatear se ha dicho! ¡Tenemos nuestras primeras métricas de evaluación!
Finalmente, podemos descansar nuestras cansadas cabezas de desarrollador… ¡Es broma, nuestros usuarios quieren una nueva característica!
Escribe FizzBuzzFibonacci en Python
Nuestros Indicadores Clave de Rendimiento (KPIs) están bajos, por lo que nuestro Gerente de Producto (PM) quiere que añadamos una nueva funcionalidad. Después de mucho brainstorming y muchas entrevistas con usuarios, se decide que el buen FizzBuzz no es suficiente. Los niños de hoy quieren un nuevo juego, FizzBuzzFibonacci.
Las reglas para FizzBuzzFibonacci son las siguientes:
Escribe un programa que imprima los enteros del
1al100(inclusive):
- Para múltiplos de tres, imprime
 Fizz- Para múltiplos de cinco, imprime
 Buzz- Para múltiplos de tres y cinco, imprime
 FizzBuzz- Para números que sean parte de la secuencia de Fibonacci, solo imprime
 Fibonacci- Para todos los demás, imprime el número
 
La secuencia de Fibonacci es una serie en la que cada número es la suma de los dos números anteriores.
Por ejemplo, comenzando con 0 y 1 el siguiente número en la secuencia de Fibonacci sería 1.
Seguido de: 2, 3, 5, 8 y así sucesivamente.
Los números que forman parte de la secuencia de Fibonacci se conocen como números de Fibonacci. Por lo tanto, tendremos que escribir una función que detecte los números de Fibonacci.
Hay muchas formas de escribir la secuencia de Fibonacci y de igual forma muchas maneras de detectar un número de Fibonacci. Así que elegiremos mi forma favorita:
def is_fibonacci_number(n):    for i in range(n + 1):        previous, current = 0, 1        while current < i:            next_value = previous + current            previous = current            current = next_value        if current == n:            return True    return False- Crea una función llamada 
is_fibonacci_numberque reciba un entero y devuelva un booleano. - Itera para todos los números desde 
0hasta nuestro número dadoninclusive. - Inicializa nuestra secuencia de Fibonacci comenzando con 
0y1como los númerosanterioryactualrespectivamente. - Itera mientras el número 
actualsea menor que la iteración actuali. - Suma los números 
anterioryactualpara obtener el númeronext_value. - Actualiza el número 
anterioral númeroactual. - Actualiza el número 
actualal númeronext_value. - Una vez que 
actualsea mayor o igual al número dadon, saldremos del bucle. - Verifica si el número 
actuales igual al número dadony si es así, devuelveTrue. - De lo contrario, devuelve 
False. 
Ahora necesitaremos actualizar nuestra función fizz_buzz:
def fizz_buzz_fibonacci(n):    if is_fibonacci_number(n):        return "Fibonacci"    elif n % 15 == 0:        return "FizzBuzz"    elif n % 3 == 0:        return "Fizz"    elif n % 5 == 0:        return "Buzz"    else:        return str(n)- Renombra la función 
fizz_buzzafizz_buzz_fibonaccipara que sea más descriptiva. - Llama a nuestra función auxiliar 
is_fibonacci_number. - Si el resultado de 
is_fibonacci_numberesTrueentonces devuelveFibonacci. - Si el resultado de 
is_fibonacci_numberesFalseentonces realiza la misma lógica deFizz,Buzz,FizzBuzz, o número devolviendo el resultado. 
Debido a que renombramos fizz_buzz a fizz_buzz_fibonacci, también necesitamos actualizar nuestra función play_game:
def play_game(n, should_print):    result = fizz_buzz_fibonacci(n)    if should_print:        print(result)    return resultTanto nuestra ejecución principal como la función test_game pueden permanecer exactamente iguales.
Evaluación comparativa de FizzBuzzFibonacci
Ahora podemos volver a ejecutar nuestro benchmark:
$ pytest game.py======================================================= test session starts ========================================================platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)rootdir: /usr/bencher/examples/python/pytest_benchmarkplugins: benchmark-4.0.0collected 1 item
game.py .                                                                                                                    [100%]
--------------------------------------------------- benchmark: 1 tests --------------------------------------------------Name (time in us)          Min       Max      Mean   StdDev    Median     IQR  Outliers  OPS (Kops/s)  Rounds  Iterations-------------------------------------------------------------------------------------------------------------------------test_game             726.9592  848.2919  735.5682  13.4925  731.4999  4.7078   146;192        1.3595    1299           1-------------------------------------------------------------------------------------------------------------------------
Legend:  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.  OPS: Operations Per Second, computed as 1 / Mean======================================================== 1 passed in 1.97s =========================================================Revisando nuestro historial de terminal,
podemos hacer una comparación visual entre el rendimiento de nuestros juegos FizzBuzz y FizzBuzzFibonacci: 10.8307 us vs 735.5682 us.
Tus números serán un poco diferentes a los míos.
Sin embargo, la diferencia entre los dos juegos probablemente esté en el rango de 50x.
¡Eso me parece bien! Especialmente al agregar una característica que suena tan elegante como Fibonacci a nuestro juego.
¡A los niños les encantará!
Expandir FizzBuzzFibonacci en Python
¡Nuestro juego es un éxito! De verdad, a los niños les encanta jugar FizzBuzzFibonacci.
¡Tanto que ha llegado la noticia de los ejecutivos de que quieren una secuela!
Pero este es el mundo moderno, ¡necesitamos ingresos recurrentes anuales (ARR) y no compras únicas!
La nueva visión para nuestro juego es que sea abierto, ya no vivir entre los límites de 1 y 100 (incluso si es inclusivo).
¡No, vamos hacia nuevas fronteras!
Las reglas para Open World FizzBuzzFibonacci son las siguientes:
Escribe un programa que tome cualquier número entero positivo e imprima:
- Para múltiplos de tres, imprime
 Fizz- Para múltiplos de cinco, imprime
 Buzz- Para múltiplos de tres y cinco, imprime
 FizzBuzz- Para números que son parte de la secuencia Fibonacci, sólo imprime
 Fibonacci- Para todos los demás, imprime el número
 
Para que nuestro juego funcione con cualquier número, necesitaremos aceptar un argumento de línea de comandos. Actualiza la ejecución principal para que se vea así:
import sys
args = sys.argvif len(args) > 1 and args[1].isdigit():    i = int(args[1])    play_game(i, True)else:    print("Please, enter a positive integer to play...")- Importar el paquete 
sys. - Recoger todos los argumentos (
args) pasados a nuestro juego desde la línea de comandos. - Obtener el primer argumento pasado a nuestro juego y verificar si es un dígito.
- Si es así, analiza el primer argumento como un entero, 
i. - Juega nuestro juego con el nuevo entero analizado 
i. 
 - Si es así, analiza el primer argumento como un entero, 
 - Si el análisis falla o no se pasa ningún argumento, por defecto solicitar una entrada válida.
 
¡Ahora podemos jugar a nuestro juego con cualquier número!
Ejecuta python game.py seguido de un número entero para jugar a nuestro juego:
$ python game.py 9Fizz$ python game.py 10Buzz$ python game.py 13FibonacciY si omitimos o proporcionamos un número no válido:
$ python game.pyPlease, enter a positive integer to play...$ python game.py badPlease, enter a positive integer to play...¡Vaya, eso fue una prueba exhaustiva! La integración continua pasa. Nuestros jefes están emocionados. ¡Enviémoslo! 🚀
El Fin


🐰 … ¿el fin de tu carrera tal vez?
¡Solo bromeaba! ¡Todo está en llamas! 🔥
Bueno, al principio todo parecía ir bien. Y luego a las 02:07 AM del sábado, mi buscapersonas sonó:
📟 ¡Tu juego está en llamas! 🔥
Después de salir de la cama a la carrera, traté de averiguar qué estaba pasando. Intenté buscar en los registros, pero eso fue difícil porque todo seguía fallando. Finalmente, encontré el problema. ¡Los niños! Les encantaba tanto nuestro juego, que lo estaban jugando hasta llegar al millón! En un destello de genialidad, agregué dos nuevos benchmarks:
def test_game_100(benchmark):    def run_game():        play_game(100, False)    benchmark(run_game)
def test_game_1_000_000(benchmark):    def run_game():        play_game(1_000_000, False)    benchmark(run_game)- Un micro-benchmark 
test_game_100para jugar el juego con el número cien (100) - Un micro-benchmark 
test_game_1_000_000para jugar el juego con el número un millón (1_000_000) 
Cuando lo ejecuté, obtuve esto:
$ pytest game.py======================================================= test session starts ========================================================platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)rootdir: /usr/bencher/examples/python/pytest_benchmarkplugins: benchmark-4.0.0collected 3 items
game.py ...                                                                                                                  [100%]Espera… espera…
-------------------------------------------------------------------------------------------------- benchmark: 3 tests --------------------------------------------------------------------------------------------------Name (time in us)                Min                     Max                    Mean                StdDev                  Median                    IQR            Outliers          OPS            Rounds  Iterations------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------test_game_100                15.4166 (1.0)          112.8749 (1.0)           15.8470 (1.0)          1.1725 (1.0)           15.6672 (1.0)           0.1672 (1.0)     1276;7201  63,103.3078 (1.0)       58970           1test_game                   727.0002 (47.16)      1,074.3327 (9.52)         754.3231 (47.60)       33.2047 (28.32)        748.9999 (47.81)        33.7283 (201.76)     134;54   1,325.6918 (0.02)       1319           1test_game_1_000_000     565,232.3328 (>1000.0)  579,829.1252 (>1000.0)  571,684.6334 (>1000.0)  6,365.1577 (>1000.0)  568,294.3747 (>1000.0)  10,454.0113 (>1000.0)       2;0       1.7492 (0.00)          5           1------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Legend:  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.  OPS: Operations Per Second, computed as 1 / Mean======================================================== 3 passed in 7.01s =========================================================¿Qué! 15.8470 us x 1,000 debería ser 15,847.0 us no 571,684.6334 us 🤯
Aunque obtuve mi código de la secuencia de Fibonacci funcionalmente correcto, debo tener un error de rendimiento en algún lugar.
Corregir FizzBuzzFibonacci en Python
Echemos un vistazo de nuevo a esa función is_fibonacci_number:
def is_fibonacci_number(n):    for i in range(n + 1):        previous, current = 0, 1        while current < i:            next_value = previous + current            previous = current            current = next_value        if current == n:            return True    return FalseAhora que estoy pensando en el rendimiento, me doy cuenta de que tengo un bucle adicional innecesario. Podemos deshacernos completamente del bucle for i in range(n + 1): y simplemente comparar el valor current con el número dado (n) 🤦
def is_fibonacci_number(n):    previous, current = 0, 1    while current < n:        next_value = previous + current        previous = current        current = next_value    return current == n- Actualiza nuestra función 
is_fibonacci_number. - Inicia nuestra secuencia de Fibonacci comenzando con 
0y1como los númerospreviousycurrentrespectivamente. - Itera mientras el número 
currentsea menor que el número dadon. - Suma los números 
previousycurrentpara obtener el númeronext_value. - Actualiza el número 
previousal númerocurrent. - Actualiza el número 
currental númeronext_value. - Una vez que 
currentsea mayor o igual al número dadon, saldremos del bucle. - Verifica si el número 
currentes igual al número dadony devuelve ese resultado. 
Ahora vamos a ejecutar nuevamente esos benchmarks y ver cómo lo hicimos:
$ pytest game.py======================================================= test session starts ========================================================platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)rootdir: /usr/bencher/examples/python/pytest_benchmarkplugins: benchmark-4.0.0collected 3 items
game.py ...                                                                                                                  [100%]
------------------------------------------------------------------------------------------------ benchmark: 3 tests ------------------------------------------------------------------------------------------------Name (time in ns)               Min                     Max                   Mean                StdDev                 Median                 IQR             Outliers  OPS (Kops/s)            Rounds  Iterations--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------test_game_100              309.8685 (1.0)       40,197.8614 (2.38)        322.0815 (1.0)        101.7570 (1.0)         320.2877 (1.0)        5.1805 (1.0)      321;12616    3,104.8046 (1.0)      195120          16test_game_1_000_000        724.9881 (2.34)      16,912.4920 (1.0)         753.1445 (2.34)       121.0458 (1.19)        741.7053 (2.32)      12.4797 (2.41)     656;13698    1,327.7664 (0.43)     123073          10test_game               26,958.9946 (87.00)    129,667.1107 (7.67)     27,448.7719 (85.22)    1,555.0003 (15.28)    27,291.9424 (85.21)    165.7754 (32.00)     479;2372       36.4315 (0.01)      25918           1--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Legend:  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.  OPS: Operations Per Second, computed as 1 / Mean======================================================== 3 passed in 3.99s =========================================================¡Oh, wow! Nuestro benchmark test_game ha vuelto a estar cerca de donde estaba para el FizzBuzz original.
Desearía poder recordar exactamente cuál era ese puntaje. Pero han pasado tres semanas.
Mi historial de terminal no retrocede tanto.
Y pytest-benchmark solo almacena sus resultados cuando se lo pedimos.
¡Pero creo que está cerca!
El benchmark test_game_100 ha bajado casi 50x a 322.0815 ns.
¡Y el benchmark test_game_1_000_000 ha bajado más de 500,000x! 571,684,633.4 ns a 753.1445 ns!
🐰 Al menos atrapamos este error de rendimiento antes de que llegara a producción… oh, cierto. Olvídalo…
Detectar Retrocesos de Rendimiento en CI
Los ejecutivos no estaban contentos con la avalancha de críticas negativas que recibió nuestro juego debido a mi pequeño error de rendimiento. Me dijeron que no dejara que volviera a ocurrir, y cuando les pregunté cómo, simplemente me dijeron que no volviera a hacerlo. ¡¿Cómo se supone que debería manejar eso‽
Afortunadamente, he encontrado esta increíble herramienta de código abierto llamada Bencher. Hay un nivel gratuito súper generoso, así que puedo usar Bencher Cloud para mis proyectos personales. Y en el trabajo, donde todo debe estar en nuestra nube privada, he comenzado a usar Bencher Self-Hosted.
Bencher tiene adaptadores incorporados, por lo que es fácil de integrar en CI. Después de seguir la guía de inicio rápido, ya puedo ejecutar mis referencias y seguir su progreso con Bencher.
$ bencher run --adapter python_pytest --file results.json "pytest --benchmark-json results.json game.py"======================================================= test session starts ========================================================platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)rootdir: /usr/bencher/examples/python/pytest_benchmarkplugins: benchmark-4.0.0collected 3 items
game.py ...
...
View results:- test_game (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=077449e5-5b45-4c00-bdfb-3a277413180d&start_time=1697224006000&end_time=1699816009000&upper_boundary=true- test_game_100 (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=96508869-4fa2-44ac-8e60-b635b83a17b7&start_time=1697224006000&end_time=1699816009000&upper_boundary=true- test_game_1_000_000 (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=ff014217-4570-42ea-8813-6ed0284500a4&start_time=1697224006000&end_time=1699816009000&upper_boundary=trueUsando este práctico dispositivo de viaje en el tiempo que un amable conejo me dio, pude retroceder en el tiempo y reproducir lo que habría sucedido si hubiéramos estado utilizando Bencher todo el tiempo. Puedes ver dónde publicamos por primera vez la implementación defectuosa de FizzBuzzFibonacci. Inmediatamente recibí fallas en CI como un comentario en mi solicitud de extracción. Ese mismo día, arreglé el error de rendimiento, eliminando ese bucle extra innecesario. No hubo incendios. Solo usuarios contentos.
Bencher: Benchmarking continuo
Bencher es un conjunto de herramientas de benchmarking continuo. ¿Alguna vez has tenido un impacto de regresión de rendimiento en tus usuarios? Bencher podría haber evitado que eso sucediera. Bencher te permite detectar y prevenir las regresiones de rendimiento antes de que lleguen a producción.
- Ejecutar: Ejecute sus benchmarks localmente o en CI usando sus herramientas de benchmarking favoritas. La CLI 
benchersimplemente envuelve su arnés de benchmarks existente y almacena sus resultados. - Seguir: Sigue los resultados de tus benchmarks con el tiempo. Monitoriza, realiza consultas y representa gráficamente los resultados utilizando la consola web de Bencher basándose en la rama de origen, el banco de pruebas y la medida.
 - Capturar: Captura las regresiones de rendimiento en CI. Bencher utiliza analíticas de vanguardia y personalizables para detectar regresiones de rendimiento antes de que lleguen a producción.
 
Por las mismas razones que las pruebas unitarias se ejecutan en CI para prevenir regresiones funcionales, los benchmarks deberían ejecutarse en CI con Bencher para prevenir regresiones de rendimiento. ¡Los errores de rendimiento son errores!
Empiece a capturar regresiones de rendimiento en CI — prueba Bencher Cloud gratis.