Cómo medir el rendimiento del código C++ con Google Benchmark

Everett Pompeii

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 C++

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 1 al 100 (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:

#include <iostream>
int main()
{
for (int i = 1; i <= 100; i++)
{
if ((i % 15) == 0)
std::cout << "FizzBuzz\n";
else if ((i % 3) == 0)
std::cout << "Fizz\n";
else if ((i % 5) == 0)
std::cout << "Buzz\n";
else
std::cout << i << "\n";
}
return 0;
}
  • Itera desde 1 hasta 100, incrementando después de cada iteración.
  • Para cada número, calcula el módulo (resto después de la división).
  • Si el resto es 0, entonces el número es un múltiplo del factor dado:
    • Si el resto es 0 para 15, entonces imprime FizzBuzz.
    • Si el resto es 0 para 3, entonces imprime Fizz.
    • Si el resto es 0 para 5, entonces imprime Buzz.
  • De lo contrario, solo imprime el número.

Siga paso a paso

Para seguir este tutorial paso a paso, necesitará instalar git, instalar cmake, y instalar la Colección de Compiladores de GNU (GCC) g++.

🐰 El código fuente de este post está disponible en GitHub.

Cree un archivo C++ llamado game.cpp, y establezca su contenido a la implementación de FizzBuzz anterior.

Utilice g++ para construir un ejecutable llamado game y luego ejecútelo. La salida debería verse como:

$ g++ -std=c++11 game.cpp -o game && ./game
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
97
98
Fizz
Buzz

🐰 ¡Boom! ¡Estás dominando la entrevista de codificación!

Antes de avanzar más, 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.

Pruebas de rendimiento en C++

Las dos opciones populares para pruebas de rendimiento en C++ son: Google Benchmark y Catch2.

Google Benchmark es una biblioteca de benchmarking robusta y versátil para C++ que permite a los desarrolladores medir el rendimiento de su código con alta precisión. Uno de sus beneficios clave es su facilidad de integración en proyectos existentes, especialmente aquellos que ya utilizan GoogleTest. Google Benchmark proporciona métricas de rendimiento detalladas, incluyendo la capacidad de medir el tiempo de CPU, el tiempo de reloj y el uso de memoria. Soporta una amplia gama de escenarios de benchmarking, desde pruebas de funciones simples hasta pruebas complejas y parametrizadas.

Catch2 es un marco de pruebas moderno, solo de cabecera, para C++ que simplifica el proceso de escribir y ejecutar pruebas. Uno de sus beneficios primarios es su facilidad de uso, con una sintaxis que es tanto intuitiva como expresiva, permitiendo a los desarrolladores escribir pruebas de manera rápida y clara. Catch2 soporta una amplia gama de tipos de pruebas, incluyendo pruebas unitarias, pruebas de integración, pruebas en estilo de desarrollo guiado por comportamiento (BDD) y características básicas de micro-benchmarking.

Both are support by Bencher. Entonces, ¿por qué elegir Google Benchmark? Google Benchmark se integra perfectamente con GoogleTest, que es el estándar de facto para pruebas unitarias en el ecosistema de C++. Sugiero usar Google Benchmark para evaluar la latencia de tu código, especialmente si ya estás utilizando GoogleTest. Es decir, Google 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 función main de nuestro programa. Los entornos de prueba de rendimiento no pueden evaluar la función main. Para lograr esto, necesitamos hacer algunos cambios.

Vamos a refactorizar nuestra lógica de FizzBuzz en un par de funciones dentro de un nuevo archivo llamado play_game.cpp:

play_game.cpp
#include <iostream>
#include <string>
std::string fizz_buzz(int n) {
if (n % 15 == 0) {
return "FizzBuzz";
} else if (n % 3 == 0) {
return "Fizz";
} else if (n % 5 == 0) {
return "Buzz";
} else {
return std::to_string(n);
}
}
void play_game(int n, bool should_print) {
std::string result = fizz_buzz(n);
if (should_print) {
std::cout << result << std::endl;
}
}
  • fizz_buzz: Toma un número entero n y realiza la lógica de Fizz, Buzz, FizzBuzz o número, devolviendo el resultado como una cadena.
  • play_game: Toma un número entero n, llama a fizz_buzz con ese número, y si should_print es true, imprime el resultado.

Ahora, vamos a crear un archivo de encabezado llamado play_game.h y agregarle la declaración de la función play_game:

play_game.h
#ifndef GAME_H
#define GAME_H
#include <string>
void play_game(int n, bool should_print);
#endif // GAME_H

Luego actualiza la función main en game.cpp para usar la definición de la función play_game desde el archivo de encabezado:

game.cpp
#include "play_game.h"
int main()
{
for (int i = 1; i <= 100; i++)
{
play_game(i, true);
}
}

La función main 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.

Benchmarking FizzBuzz

Para evaluar el rendimiento de nuestro código, primero necesitamos instalar Google Benchmark.

Clona la biblioteca:

$ git clone https://github.com/google/benchmark.git

Entra en el directorio recién clonado:

$ cd benchmark

Usa cmake para crear un directorio de compilación para colocar la salida de la compilación:

$ cmake -E make_directory "build"

Usa cmake para generar archivos del sistema de compilación y descargar cualquier dependencia:

$ cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../

Finalmente, compila la biblioteca:

$ cmake --build "build" --config Release

Regresa al directorio principal:

cd ..

Ahora creemos un nuevo archivo llamado benchmark_game.cpp:

benchmark_game.cpp
#include "play_game.h"
#include <benchmark/benchmark.h>
#include <iostream>
static void BENCHMARK_game(benchmark::State &state)
{
for (auto _ : state)
{
for (int i = 1; i <= 100; i++)
{
play_game(i, false);
}
}
}
BENCHMARK(BENCHMARK_game);
BENCHMARK_MAIN();
  • Importa las definiciones de funciones de play_game.h.
  • Importa el encabezado de la biblioteca benchmark de Google.
  • Crea una función llamada BENCHMARK_game que tome una referencia a benchmark::State.
  • Itera sobre el objeto benchmark::State.
  • Para cada iteración, itera de 1 a 100 inclusivamente.
    • Llama a play_game con el número actual y should_print configurado a false.
  • Pasa la función BENCHMARK_game al ejecutor BENCHMARK.
  • Ejecuta el benchmark con BENCHMARK_MAIN.

Ahora estamos listos para evaluar el rendimiento de nuestro código:

$ g++ -std=c++11 -isystem benchmark/include -Lbenchmark/build/src -lbenchmark -lpthread play_game.cpp benchmark_game.cpp -o benchmark_game && ./benchmark_game
2023-10-16T14:00:00-04:00
Running ./benchmark_game
Run on (8 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x8)
Load Average: 5.55, 4.62, 4.69
---------------------------------------------------------
Benchmark Time CPU Iterations
---------------------------------------------------------
BENCHMARK_game 1698 ns 1688 ns 419979

🐰 ¡Vamos a darle ritmo a nuestra primera métrica de benchmark!

Finalmente, podemos descansar nuestras cansadas cabezas de desarrolladores… Es broma, ¡nuestros usuarios quieren una nueva característica!

Escribe FizzBuzzFibonacci en C++

Nuestros Indicadores Clave de Rendimiento (KPI) están bajos, por lo que nuestro Gerente de Producto (PM) quiere que agreguemos una nueva característica. Después de mucho brainstorming y muchas entrevistas con usuarios, se decide que el buen viejo 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 1 al 100 (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:

play_game.cpp
bool is_fibonacci_number(int n)
{
for (int i = 0; i <= n; ++i)
{
int previous = 0, current = 1;
while (current < i)
{
int next = previous + current;
previous = current;
current = next;
}
if (current == n)
{
return true;
}
}
return false;
}
  • Crea una función llamada is_fibonacci_number que tome un entero y devuelva un booleano.
  • Itera para todos los números desde 0 hasta nuestro número dado n inclusive.
  • Inicializa nuestra secuencia de Fibonacci comenzando con 0 y 1 como los números previous y current respectivamente.
  • Itera mientras el número current sea menor que la iteración actual i.
  • Suma el número previous y el número current para obtener el número next.
  • Actualiza el número previous al número current.
  • Actualiza el número current al número next.
  • Una vez que current sea mayor o igual al número dado n, saldremos del bucle.
  • Verifica si el número current es igual al número dado n y, si es así, devuelve true.
  • De lo contrario, devuelve false.

Ahora necesitaremos actualizar nuestra función fizz_buzz:

play_game.cpp
std::string fizz_buzz_fibonacci(int n)
{
if (is_fibonacci_number(n))
{
return "Fibonacci";
}
else if (n % 15 == 0)
{
return "FizzBuzz";
}
else if (n % 3 == 0)
{
return "Fizz";
}
else if (n % 5 == 0)
{
return "Buzz";
}
else
{
return std::to_string(n);
}
}
  • Renombra la función fizz_buzz a fizz_buzz_fibonacci para hacerla más descriptiva.
  • Llama a nuestra función auxiliar is_fibonacci_number.
  • Si el resultado de is_fibonacci_number es true, entonces devuelve Fibonacci.
  • Si el resultado de is_fibonacci_number es false, entonces realiza la misma lógica de Fizz, Buzz, FizzBuzz o el número devolviendo el resultado.

Dado que renombramos fizz_buzz a fizz_buzz_fibonacci, también necesitamos actualizar nuestra función play_game:

play_game.cpp
void play_game(int n, bool should_print) {
std::string result = fizz_buzz_fibonacci(n);
if (should_print) {
std::cout << result << std::endl;
}
}

Tanto nuestra función main como la función BENCHMARK_game pueden permanecer exactamente iguales.

Evaluación de rendimiento de FizzBuzzFibonacci

Ahora podemos volver a ejecutar nuestra evaluación de rendimiento:

$ g++ -std=c++11 -isystem benchmark/include -Lbenchmark/build/src -lbenchmark -lpthread play_game.cpp benchmark_game.cpp -o benchmark_game && ./benchmark_game
2023-10-16T15:00:00-04:00
Running ./benchmark_game
Run on (8 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x8)
Load Average: 4.34, 5.75, 4.71
---------------------------------------------------------
Benchmark Time CPU Iterations
---------------------------------------------------------
BENCHMARK_game 56190 ns 56054 ns 12280

Volviendo a revisar nuestro historial del terminal, podemos hacer una comparación visual entre el rendimiento de nuestros juegos FizzBuzz y FizzBuzzFibonacci: 1698 ns vs 56190 ns. Tus números serán un poco diferentes a los míos. Sin embargo, es probable que la diferencia entre los dos juegos esté en el rango de 50 veces. ¡Eso me parece bien! Especialmente por añadir una característica que suena tan elegante como Fibonacci a nuestro juego. ¡A los niños les encantará!

Expandir FizzBuzzFibonacci en C++

¡Nuestro juego es un éxito! A los niños realmente les encanta jugar a FizzBuzzFibonacci. ¡Tanto que ha llegado la noticia de que los ejecutivos quieren una secuela! ¡Pero este es el mundo moderno, necesitamos Ingresos Recurrentes Anuales (ARR) no compras únicas! La nueva visión para nuestro juego es que sea abierto, ya no más viviendo entre los límites de 1 y 100 (incluso si son inclusivos). ¡No, estamos en nuevos horizontes!

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 desde la línea de comandos. Actualice la función main para que se vea así:

game.cpp
#include "play_game.h"
#include <iostream>
#include <cstdlib>
int main(int argc, char *argv[])
{
if (argc > 1 && std::isdigit(argv[1][0]))
{
int i = std::atoi(argv[1]);
play_game(i, true);
}
else
{
std::cout << "Please, enter a positive integer to play..." << std::endl;
}
return 0;
}
  • Actualice la función main para tomar argc y argv.
  • Obtenga el primer argumento pasado a nuestro juego y verifique si es un dígito.
    • Si es así, analice el primer argumento como un entero, i.
    • Juegue nuestro juego con el nuevo entero analizado i.
  • Si la conversión falla o no se pasa ningún argumento, por defecto solicitar una entrada válida.

¡Ahora podemos jugar nuestro juego con cualquier número! Recompile nuestro ejecutable game y ejecute el ejecutable seguido de un entero para jugar nuestro juego:

$ g++ -std=c++11 game.cpp play_game.cpp -o game
$ ./game 9
Fizz
$ ./game 10
Buzz
$ ./game 13
Fibonacci

Y si omitimos o proporcionamos un número inválido:

$ ./game
Please, enter a positive integer to play...
$ ./game bad
Please, enter a positive integer to play...

¡Vaya, eso fue una prueba exhaustiva! La integración continua pasa. Nuestros jefes están encantados. ¡Vamos a lanzarlo! 🚀

El Fin


SpongeBob SquarePants Tres Semanas Después
Meme de Esto está Bien

🐰 … ¿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:

benchmark_game.cpp
static void BENCHMARK_game_100(benchmark::State &state)
{
for (auto _ : state)
{
play_game(100, false);
}
}
static void BENCHMARK_game_1_000_000(benchmark::State &state)
{
for (auto _ : state)
{
play_game(1000000, false);
}
}
BENCHMARK(BENCHMARK_game_100);
BENCHMARK(BENCHMARK_game_1_000_000);
  • Un micro-benchmark BENCHMARK_game_100 para jugar el juego con el número cien (100)
  • Un micro-benchmark BENCHMARK_game_1_000_000 para jugar el juego con el número un millón (1_000_000)

Cuando lo ejecuté, obtuve esto:

$ g++ -std=c++11 -isystem benchmark/include -Lbenchmark/build/src -lbenchmark -lpthread play_game.cpp benchmark_game.cpp -o benchmark_game && ./benchmark_game
2023-11-04T03:00:00-04:00
Running ./benchmark_game
Run on (8 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x8)
Load Average: 4.98, 5.75, 4.96
-------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------
BENCHMARK_game 75547 ns 59280 ns 12560
BENCHMARK_game_100 1249 ns 1243 ns 564689

Espéralo… espéralo…

BENCHMARK_game_1_000_000 110879642 ns 43628118 ns 17

¿Qué! 1,249 ns x 10,000 debería ser 12,490,000 ns no 110,879,642 ns 🤯 Aunque mi código de secuencia de Fibonacci es funcionalmente correcto, debe haber un error de rendimiento en alguna parte.

Corrige FizzBuzzFibonacci en C++

Echemos otro vistazo a esa función is_fibonacci_number:

play_game.cpp
bool is_fibonacci_number(int n)
{
for (int i = 0; i <= n; ++i)
{
int previous = 0, current = 1;
while (current < i)
{
int next = previous + current;
previous = current;
current = next;
}
if (current == n)
{
return true;
}
}
return false;
}

Ahora que estoy pensando en el rendimiento, me doy cuenta de que tengo un bucle innecesario y extra. Podemos deshacernos completamente del bucle for (int i = 0; i <= n; ++i) y solo comparar el valor current con el número dado (n) 🤦

play_game.cpp
bool is_fibonacci_number(int n)
{
int previous = 0, current = 1;
while (current < n)
{
int next = previous + current;
previous = current;
current = next;
}
return current == n;
}
  • Actualiza nuestra función is_fibonacci_number.
  • Inicializa nuestra secuencia de Fibonacci comenzando con 0 y 1 como los números previous y current respectivamente.
  • Itera mientras el número current sea menor que el número dado n.
  • Suma el número previous y el current para obtener el número next.
  • Actualiza el número previous al número current.
  • Actualiza el número current al número next.
  • Una vez que current sea mayor o igual al número dado n, saldremos del bucle.
  • Verifica si el número current es igual al número dado n y devuelve ese resultado.

Ahora volvamos a ejecutar esos benchmarks y veamos cómo nos fue:

$ g++ -std=c++11 -isystem benchmark/include -Lbenchmark/build/src -lbenchmark -lpthread play_game.cpp benchmark_game.cpp -o benchmark_game && ./benchmark_game
2023-11-04T05:00:00-04:00
Running ./benchmark_game
Run on (8 X 24 MHz CPU s)
CPU Caches:
L1 Data 64 KiB
L1 Instruction 128 KiB
L2 Unified 4096 KiB (x8)
Load Average: 4.69, 5.02, 4.78
-------------------------------------------------------------------
Benchmark Time CPU Iterations
-------------------------------------------------------------------
BENCHMARK_game 2914 ns 2913 ns 242382
BENCHMARK_game_100 34.4 ns 34.3 ns 20322076
BENCHMARK_game_1_000_000 61.6 ns 61.6 ns 11346874

¡Oh, wow! Nuestro benchmark BENCHMARK_game ha vuelto a donde estaba para el FizzBuzz original. Desearía poder recordar exactamente cuál era ese puntaje. Sin embargo, han pasado tres semanas. El historial de mi terminal no llega tan lejos, y Google Benchmark no almacena sus resultados. ¡Pero creo que está cerca!

El benchmark BENCHMARK_game_100 ha bajado casi 50 veces a 34.4 ns. ¡Y el benchmark BENCHMARK_game_1_000_000 ha bajado más de 1,500,000 veces! 110,879,642 ns a 61.6 ns!

🐰 Al menos encontramos este error de rendimiento antes de que llegara a producción… oh, cierto. No importa…

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.

$ g++ -std=c++11 -isystem benchmark/include -Lbenchmark/build/src -lbenchmark -lpthread play_game.cpp benchmark_game.cpp -o benchmark_game
$ bencher run --adapter cpp_google "./benchmark_game --benchmark_format=json"
{
"context": {
"date": "2023-10-16T16:00:00-04:00",
"host_name": "bencher",
"executable": "./benchmark_game",
"num_cpus": 8,
"mhz_per_cpu": 24,
"cpu_scaling_enabled": false,
...
View results:
- BENCHMARK_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
- BENCHMARK_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
- BENCHMARK_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=true

Usando 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

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 bencher simplemente 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.

🤖 Este documento fue generado automáticamente por OpenAI GPT-4. Puede que no sea exacto y contenga errores. Si encuentra algún error, abra un problema en GitHub.