Comment faire du benchmarking de code C++ avec Google Benchmark

Everett Pompeii

Everett Pompeii


Qu’est-ce que le Benchmarking ?

Le benchmarking est la pratique consistant à tester les performances de votre code pour voir à quelle vitesse (latence) ou combien (débit) de travail il peut effectuer. Cette étape souvent négligée dans le développement logiciel est cruciale pour créer et maintenir un code rapide et performant. Le benchmarking fournit les métriques nécessaires aux développeurs pour comprendre comment leur code se comporte sous diverses charges de travail et conditions. Pour les mêmes raisons que vous écrivez des tests unitaires et d’intégration pour éviter les régressions de fonctionnalités, vous devriez écrire des benchmarks pour éviter les régressions de performances. Les bugs de performance sont des bugs !

Écrire FizzBuzz en C++

Pour écrire des benchmarks, nous avons besoin de code source à évaluer. Pour commencer, nous allons écrire un programme très simple, FizzBuzz.

Les règles pour FizzBuzz sont les suivantes :

Écrivez un programme qui imprime les entiers de 1 à 100 (inclus) :

  • Pour les multiples de trois, imprimez Fizz
  • Pour les multiples de cinq, imprimez Buzz
  • Pour les multiples de trois et de cinq, imprimez FizzBuzz
  • Pour tous les autres, imprimez le numéro

Il existe de nombreuses façons d’écrire FizzBuzz. Nous allons donc choisir ma préférée :

#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;
}
  • Itérer de 1 à 100, avec une incrémentation après chaque itération.
  • Pour chaque nombre, calculer le module (reste après la division).
  • Si le reste est 0, alors le nombre est un multiple du facteur donné :
    • Si le reste est 0 pour 15, alors afficher FizzBuzz.
    • Si le reste est 0 pour 3, alors afficher Fizz.
    • Si le reste est 0 pour 5, alors afficher Buzz.
  • Sinon, simplement afficher le nombre.

Suivez le guide étape par étape

Pour suivre ce tutoriel étape par étape, vous devrez installer git, installer cmake, et installer la GNU Compiler Collection (GCC) g++.

🐰 Le code source pour cet article est disponible sur GitHub.

Créez un fichier C++ nommé game.cpp, et définissez son contenu avec l’implémentation FizzBuzz ci-dessus.

Utilisez g++ pour construire un exécutable nommé game, puis exécutez-le. La sortie devrait ressembler à :

$ 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 ! Vous êtes en train de réussir votre entretien de programmation !

Avant d’aller plus loin, il est important de discuter des différences entre le micro-benchmarking et le macro-benchmarking.

Micro-Benchmarking vs Macro-Benchmarking

Il existe deux grandes catégories de benchmarks logiciels : les micro-benchmarks et les macro-benchmarks. Les micro-benchmarks fonctionnent à un niveau similaire aux tests unitaires. Par exemple, un benchmark pour une fonction qui détermine Fizz, Buzz, ou FizzBuzz pour un seul nombre serait un micro-benchmark. Les macro-benchmarks fonctionnent à un niveau similaire aux tests d’intégration. Par exemple, un benchmark pour une fonction qui joue l’ensemble du jeu de FizzBuzz, de 1 à 100, serait un macro-benchmark.

Généralement, il est préférable de tester au niveau le plus bas d’abstraction possible. Dans le cas des benchmarks, cela les rend à la fois plus faciles à maintenir, et cela aide à réduire le bruit dans les mesures. Cependant, tout comme avoir des tests de bout en bout peut être très utile pour vérifier la cohérence de l’ensemble du système tel que prévu, avoir des macro-benchmarks peut être très utile pour s’assurer que les chemins critiques à travers votre logiciel restent performants.

Benchmarking en C++

Les deux options populaires pour le benchmarking en C++ sont : Google Benchmark et Catch2.

Google Benchmark est une bibliothèque de benchmarking robuste et polyvalente pour C++ qui permet aux développeurs de mesurer la performance de leur code avec une grande précision. L’un de ses principaux avantages est sa facilité d’intégration dans des projets existants, en particulier ceux qui utilisent déjà GoogleTest. Google Benchmark fournit des métriques de performance détaillées, y compris la capacité de mesurer le temps CPU, le temps d’horloge, et l’utilisation de la mémoire. Il supporte un large éventail de scénarios de benchmarking, allant de simples benchmarks de fonctions à des tests complexes et paramétrés.

Catch2 est un cadre de test moderne, basé uniquement sur des en-têtes, qui simplifie le processus d’écriture et d’exécution des tests. L’un de ses principaux avantages est sa facilité d’utilisation, avec une syntaxe à la fois intuitive et expressive, permettant aux développeurs d’écrire des tests rapidement et clairement. Catch2 supporte une large gamme de types de tests, y compris les tests unitaires, les tests d’intégration, les tests de style développement dirigé par le comportement (BDD), et des fonctionnalités de micro-benchmarking basiques.

Both are support by Bencher. So why choose Google Benchmark? Google Benchmark s’intègre parfaitement avec GoogleTest, qui est le standard de facto pour les frameworks de tests unitaires dans l’écosystème C++. Je suggérerais d’utiliser Google Benchmark pour tester la latence de votre code, surtout si vous utilisez déjà GoogleTest. C’est-à-dire que Google Benchmark est excellent pour mesurer le temps d’horloge.

Refactorisation de FizzBuzz

Afin de tester notre application FizzBuzz, nous devons découpler notre logique de la fonction main de notre programme. Les environnements de test de performance ne peuvent pas évaluer la fonction main. Pour ce faire, nous devons apporter quelques modifications.

Refactorisons notre logique FizzBuzz dans quelques fonctions à l’intérieur d’un nouveau fichier nommé 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 : Prend un entier n et effectue la logique réelle de Fizz, Buzz, FizzBuzz ou du chiffre, renvoyant le résultat sous forme de chaîne.
  • play_game : Prend un entier n, appelle fizz_buzz avec ce nombre, et si should_print est true, imprime le résultat.

Maintenant, créons un fichier d’en-tête nommé play_game.h et ajoutons la déclaration de la fonction play_game à celui-ci :

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

Ensuite, mettez à jour la fonction main dans game.cpp pour utiliser la définition de la fonction play_game depuis le fichier d’en-tête :

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

La fonction main de notre programme itère à travers les nombres de 1 à 100 inclus et appelle play_game pour chaque nombre, avec should_print défini sur true.

Benchmarking FizzBuzz

Pour évaluer les performances de notre code, nous devons d’abord installer Google Benchmark.

Clonez la bibliothèque :

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

Accédez au répertoire nouvellement cloné :

$ cd benchmark

Utilisez cmake pour créer un répertoire de build afin d’y placer le résultat de la construction :

$ cmake -E make_directory "build"

Utilisez cmake pour générer les fichiers du système de build et télécharger toutes les dépendances :

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

Enfin, construisez la bibliothèque :

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

Revenez au répertoire parent :

cd ..

Créons maintenant un nouveau fichier nommé 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();
  • Importez les définitions de fonction depuis play_game.h.
  • Importez l’en-tête de la bibliothèque benchmark de Google.
  • Créez une fonction nommée BENCHMARK_game qui prend en argument une référence à benchmark::State.
  • Itérez sur l’objet benchmark::State.
  • Pour chaque itération, itérez de 1 à 100 inclusivement.
    • Appelez play_game avec le numéro actuel et should_print défini sur false.
  • Passez la fonction BENCHMARK_game au runner BENCHMARK.
  • Exécutez le benchmark avec BENCHMARK_MAIN.

Nous sommes maintenant prêts à évaluer les performances de notre code :

$ 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

🐰 Laitue tourner la betterave ! Nous avons nos premiers métriques de benchmark !

Enfin, nous pouvons reposer nos têtes de développeurs fatiguées… Je rigole, nos utilisateurs veulent une nouvelle fonctionnalité !

Écrire FizzBuzzFibonacci en C++

Nos indicateurs clés de performance (KPI) sont en baisse, donc notre chef de produit (PM) souhaite que nous ajoutions une nouvelle fonctionnalité. Après de nombreux brainstormings et des interviews d’utilisateurs, il est décidé que le bon vieux FizzBuzz ne suffit plus. Les enfants de nos jours veulent un nouveau jeu, FizzBuzzFibonacci.

Les règles du FizzBuzzFibonacci sont les suivantes :

Écrivez un programme qui imprime les entiers de 1 à 100 (inclus) :

  • Pour les multiples de trois, imprimez Fizz
  • Pour les multiples de cinq, imprimez Buzz
  • Pour les multiples de trois et cinq, imprimez FizzBuzz
  • Pour les nombres qui font partie de la séquence de Fibonacci, imprimez uniquement Fibonacci
  • Pour tous les autres, imprimez le nombre

La séquence de Fibonacci est une séquence dans laquelle chaque nombre est la somme des deux précédents. Par exemple, en commençant par 0 et 1, le prochain nombre dans la séquence de Fibonacci serait 1. Suivi par : 2, 3, 5, 8 et ainsi de suite. Les nombres qui font partie de la séquence de Fibonacci sont connus sous le nom de nombres de Fibonacci. Nous allons donc devoir écrire une fonction qui détecte les nombres de Fibonacci.

Il y a plusieurs façons de générer la séquence de Fibonacci et plusieurs façons de détecter un nombre de Fibonacci. Nous allons donc choisir ma méthode préférée :

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;
}
  • Créez une fonction nommée is_fibonacci_number qui prend un entier en entrée et retourne un booléen.
  • Itérez pour tous les nombres de 0 jusqu’à notre nombre donné n inclus.
  • Initialisez notre séquence de Fibonacci en commençant par 0 et 1 comme nombres previous (précédent) et current (actuel) respectivement.
  • Itérez tant que le nombre current est inférieur à l’itération courante i.
  • Ajoutez le nombre previous et current pour obtenir le nombre next.
  • Mettez à jour le nombre previous à current.
  • Mettez à jour le nombre current à next.
  • Une fois que current est supérieur ou égal au nombre donné n, nous sortirons de la boucle.
  • Vérifiez si le nombre current est égal au nombre donné n et si oui, retournez true.
  • Sinon, retournez false.

Nous devons maintenant mettre à jour notre fonction 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);
}
}
  • Renommez la fonction fizz_buzz en fizz_buzz_fibonacci pour la rendre plus descriptive.
  • Appelez notre fonction auxiliaire is_fibonacci_number.
  • Si le résultat de is_fibonacci_number est true, alors retournez Fibonacci.
  • Si le résultat de is_fibonacci_number est false, alors effectuez la même logique Fizz, Buzz, FizzBuzz, ou nombre en retournant le résultat.

Comme nous avons renommé fizz_buzz en fizz_buzz_fibonacci, nous devons également mettre à jour notre fonction 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;
}
}

Tant notre fonction main que la fonction BENCHMARK_game peuvent rester exactement les mêmes.

Benchmarking FizzBuzzFibonacci

Nous pouvons maintenant relancer notre benchmark :

$ 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

En parcourant l’historique de notre terminal, nous pouvons faire une comparaison visuelle entre les performances de nos jeux FizzBuzz et FizzBuzzFibonacci : 1698 ns vs 56190 ns. Vos chiffres seront un peu différents des miens. Cependant, la différence entre les deux jeux est probablement dans la gamme de 50x. Cela me semble bien ! Surtout pour ajouter une fonctionnalité aussi impressionnante que Fibonacci à notre jeu. Les enfants vont adorer !

Étendre FizzBuzzFibonacci en C++

Notre jeu est un succès ! Les enfants adorent effectivement jouer à FizzBuzzFibonacci. À tel point que la direction a entendu parler de cela et souhaite une suite. Mais c’est le monde moderne, nous avons besoin de revenus récurrents annuels (ARR) et non d’achats uniques ! La nouvelle vision pour notre jeu est qu’il soit ouvert, plus de limites entre 1 et 100 (même si elles sont inclusives). Non, nous explorons de nouveaux horizons !

Les règles pour Open World FizzBuzzFibonacci sont les suivantes :

Écrivez un programme qui prend en entrée n’importe quel nombre entier positif et affiche :

  • Pour les multiples de trois, affichez Fizz
  • Pour les multiples de cinq, affichez Buzz
  • Pour les multiples à la fois de trois et de cinq, affichez FizzBuzz
  • Pour les nombres qui font partie de la séquence de Fibonacci, affichez uniquement Fibonacci
  • Pour tous les autres, affichez le nombre

Pour que notre jeu fonctionne avec n’importe quel nombre, nous devrons accepter un argument en ligne de commande. Mettez à jour la fonction main pour qu’elle ressemble à ceci :

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;
}
  • Mettez à jour la fonction main pour prendre en compte argc et argv.
  • Obtenez le premier argument passé à notre jeu et vérifiez s’il s’agit d’un chiffre.
    • Si c’est le cas, analysez le premier argument comme un entier, i.
    • Jouez à notre jeu avec l’entier i nouvellement analysé.
  • Si l’analyse échoue ou qu’aucun argument n’est passé, passez par défaut à une demande d’entrée valide.

Maintenant, nous pouvons jouer à notre jeu avec n’importe quel nombre ! Recompilez notre exécutable game puis exécutez l’exécutable suivi d’un entier pour jouer à notre jeu :

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

Et si nous omettons ou fournissons un nombre invalide :

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

Wow, ce fut un test exhaustif ! L’intégration continue passe avec succès. Nos patrons sont ravis. Expédions-le ! 🚀

La fin


SpongeBob SquarePants Trois semaines plus tard
Meme C'est bien

🐰 … la fin de votre carrière peut-être ?


Rien que pour rire! Tout est en feu! 🔥

Au début, tout semblait aller bien. Et puis à 02h07 du matin le samedi, mon bip a sonné :

📟 Votre jeu est en feu! 🔥

Après me être précipité hors du lit, j’ai essayé de comprendre ce qui se passait. J’ai essayé de rechercher dans les journaux, mais c’était difficile parce que tout continuait de s’effondrer. Finalement, j’ai trouvé le problème. Les enfants ! Ils adorent notre jeu tellement, qu’ils jouaient jusqu’à un million! Dans un éclair de génie, j’ai ajouté deux nouveaux points de référence :

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 pour jouer le jeu avec le nombre cent (100)
  • Un micro-benchmark BENCHMARK_game_1_000_000 pour jouer le jeu avec le nombre un million (1_000_000)

Quand je l’ai exécuté, j’ai obtenu ceci :

$ 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

Attendez… attendez…

BENCHMARK_game_1_000_000 110879642 ns 43628118 ns 17

Quoi ! 1,249 ns x 10,000 devrait être 12,490,000 ns et non 110,879,642 ns 🤯 Même si mon code de séquence de Fibonacci était fonctionnellement correct, il doit y avoir un bug de performance quelque part.

Corriger FizzBuzzFibonacci en C++

Jetons un autre coup d’œil à cette fonction 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;
}

Maintenant que je pense à la performance, je réalise que j’ai une boucle supplémentaire inutile. Nous pouvons complètement supprimer la boucle for (int i = 0; i <= n; ++i) et juste comparer la valeur current au nombre donné (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;
}
  • Mettez à jour notre fonction is_fibonacci_number.
  • Initialisez notre séquence de Fibonacci en commençant par 0 et 1 comme nombres previous et current respectivement.
  • Itérez tant que le nombre current est inférieur au nombre donné n.
  • Ajoutez le nombre previous et current pour obtenir le nombre next.
  • Mettez à jour le nombre previous avec le nombre current.
  • Mettez à jour le nombre current avec le nombre next.
  • Une fois que current est supérieur ou égal au nombre donné n, nous sortirons de la boucle.
  • Vérifiez si le nombre current est égal au nombre donné n et retournez ce résultat.

Maintenant, relançons ces benchmarks et voyons comment nous avons fait :

$ 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 ! Notre benchmark BENCHMARK_game est redescendu à peu près au niveau où il était pour le FizzBuzz original. J’aimerais pouvoir me souvenir exactement de ce score. Ça fait trois semaines. Mon historique de terminal ne va pas aussi loin, et Google Benchmark ne garde pas les résultats. Mais je pense que c’est proche !

Le benchmark BENCHMARK_game_100 a diminué de près de 50 fois pour atteindre 34.4 ns. Et le benchmark BENCHMARK_game_1_000_000 a diminué de plus de 1,500,000x ! De 110,879,642 ns à 61.6 ns !

🐰 Au moins, nous avons détecté ce bug de performance avant qu’il n’arrive en production… oh, d’accord. Peu importe…

Détection des régressions de performances dans l’intégration continue (CI)

Les dirigeants n’étaient pas contents du torrent de critiques négatives que notre jeu a reçu à cause de mon petit bug de performance. Ils m’ont dit de ne pas laisser cela se reproduire, et quand j’ai demandé comment, ils m’ont juste dit de ne pas le refaire. Comment suis-je censé gérer cela‽

Heureusement, j’ai trouvé cet outil open source génial appelé Bencher. Il y a un niveau gratuit super généreux, donc je peux simplement utiliser Bencher Cloud pour mes projets personnels. Et au travail où tout doit être dans notre cloud privé, j’ai commencé à utiliser Bencher Self-Hosted.

Bencher a des adaptateurs intégrés, il est donc facile de l’intégrer dans CI. Après avoir suivi le guide de démarrage rapide, je suis en mesure d’exécuter mes benchmarks et de les suivre avec 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

En utilisant cet astucieux appareil de voyage dans le temps qu’un gentil lapin m’a donné, j’ai pu revenir en arrière et revivre ce qui se serait passé si nous utilisions Bencher depuis le début. Vous pouvez voir où nous avons d’abord poussé l’implémentation buggée de FizzBuzzFibonacci. J’ai immédiatement obtenu des échecs dans CI en commentaire sur ma demande de tirage. Ce même jour, j’ai corrigé le bug de performance, en supprimant cette boucle inutile et supplémentaire. Pas de feux. Juste des utilisateurs heureux.

Bencher: Benchmarking Continu

🐰 Bencher

Bencher est une suite d’outils de benchmarking continu. Avez-vous déjà eu une régression de performance qui a impacté vos utilisateurs ? Bencher aurait pu empêcher cela de se produire. Bencher vous permet de détecter et de prévenir les régressions de performance avant qu’elles n’arrivent en production.

  • Exécuter: Exécutez vos benchmarks localement ou en CI en utilisant vos outils de benchmarking préférés. La CLI bencher enveloppe simplement votre harnais de benchmarking existant et stocke ses résultats.
  • Suivre: Suivez les résultats de vos benchmarks au fil du temps. Surveillez, interrogez et graphiquez les résultats à l’aide de la console web Bencher en fonction de la branche source, du banc d’essai et de la mesure.
  • Détecter: Détectez les régressions de performances en CI. Bencher utilise des analyses de pointe et personnalisables pour détecter les régressions de performances avant qu’elles n’arrivent en production.

Pour les mêmes raisons que les tests unitaires sont exécutés en CI pour prévenir les régressions de fonctionnalités, les benchmarks devraient être exécutés en CI avec Bencher pour prévenir les régressions de performance. Les bugs de performance sont des bugs !

Commencez à détecter les régressions de performances en CI — essayez Bencher Cloud gratuitement.

🤖 Ce document a été automatiquement généré par OpenAI GPT-4. Il peut ne pas être précis et peut contenir des erreurs. Si vous trouvez des erreurs, veuillez ouvrir une issue sur GitHub.