Wie man Benchmarks in CI mit Bencher verfolgt


Die meisten Benchmark-Ergebnisse sind flüchtig. Sie verschwinden, sobald Ihr Terminal seine Scrollback-Grenze erreicht. Einige Benchmark-Frameworks erlauben es Ihnen, Ergebnisse zu zwischenspeichern, aber die meisten tun dies nur lokal. Bencher ermöglicht es Ihnen, Ihre Benchmarks sowohl von lokalen als auch von CI-Läufen zu verfolgen und die Ergebnisse zu vergleichen, während Sie weiterhin Ihr bevorzugtes Benchmark-Framework verwenden.

Es gibt drei beliebte Methoden, um Benchmark-Ergebnisse beim Continuous Benchmarking zu vergleichen, also beim Benchmarking in der CI:

  • Statistisches Continuous Benchmarking
    1. Verfolgen Sie die Benchmark-Ergebnisse im Laufe der Zeit, um eine Basislinie zu erstellen
    2. Verwenden Sie diese Basislinie zusammen mit Statistischen Schwellenwerten, um eine statistische Grenze zu erstellen
    3. Vergleichen Sie die neuen Ergebnisse mit dieser statistischen Grenze, um Leistungsregressionen zu erkennen
  • Relatives Continuous Benchmarking
    1. Führen Sie die Benchmarks für den aktuellen Basisliniencode aus
    2. Wechseln Sie zur neuen Version des Codes
    3. Verwenden Sie Prozentuale Schwellenwerte, um eine Grenze für den Basisliniencode zu erstellen
    4. Führen Sie die Benchmarks für die neue Version des Codes aus
    5. Vergleichen Sie die Ergebnisse der neuen Version des Codes mit den Ergebnissen des Basisliniencodes, um Leistungsregressionen zu erkennen
  • Change Point Detection
    1. Führen Sie gelegentlich die Benchmarks für neue Versionen des Codes aus
    2. Verwenden Sie einen Change-Point-Detection-Algorithmus, um Leistungsregressionen zu erkennen
    3. Führen Sie eine Bisektion durch, um den Commit zu finden, der die Leistungsregression eingeführt hat

Statistisches Kontinuierliches Benchmarking

Anknüpfend an die Tutorials Schnellstart und Docker Selbstgehostet, fügen wir statistisches kontinuierliches Benchmarking zu unserem Save Walter White Projekt hinzu.

🐰 Stellen Sie sicher, dass Sie einen API-Token erstellt und als die Umgebungsvariable BENCHER_API_TOKEN gesetzt haben, bevor Sie fortfahren!

Nun sind wir bereit, unsere Benchmarks in CI auszuführen. Da jede CI-Umgebung ein wenig anders ist, soll das folgende Beispiel eher veranschaulichend als praktisch sein. Für spezifischere Beispiele siehe Kontinuierliches Benchmarking in GitHub Actions und Kontinuierliches Benchmarking in GitLab CI/CD.

Zuerst müssen wir eine historische Basis für unseren main Branch erstellen und pflegen, indem wir jede Änderung in CI benchmarken:

  1. Verwenden Sie den bencher run CLI-Unterbefehl, um Ihre Benchmarks für den main Branch auszuführen. Siehe den bencher run CLI-Unterbefehl für eine vollständige Übersicht. (z.B.: bencher run)
  2. Setzen Sie die --project Option auf den Projektslug. Siehe die --project Dokumentation für mehr Details. (z.B.: --project save-walter-white-1234abcd)
  3. Setzen Sie die --branch Option auf den Basis-Branch-Namen. Siehe die --branch Dokumentation für eine vollständige Übersicht. (z.B.: --branch main)
  4. Setzen Sie die --testbed Option auf den Namen des CI-Runner Testbeds. Siehe die --testbed Dokumentation für mehr Details. (z.B.: --testbed ci-runner)
  5. Setzen Sie den Schwellenwert für den main Branch, das ci-runner Testbed und das latency Maß:
    1. Setzen Sie die --threshold-measure Option auf das eingebaute latency Maß, das von bencher mock generiert wird. Siehe die --threshold-measure Dokumentation für mehr Details. (z.B.: --threshold-measure latency)
    2. Setzen Sie die --threshold-test Option auf einen Student’s t-Test (t_test). Siehe die --threshold-test Dokumentation für eine vollständige Übersicht. (z.B.: --threshold-test t_test)
    3. Setzen Sie die --threshold-max-sample-size Option auf die maximale Stichprobengröße von 64. Siehe die --threshold-max-sample-size Dokumentation für mehr Details. (z.B.: --threshold-max-sample-size 64)
    4. Setzen Sie die --threshold-upper-boundary Option auf die obere Grenze von 0.99. Siehe die --threshold-upper-boundary Dokumentation für mehr Details. (z.B.: --threshold-upper-boundary 0.99)
    5. Setzen Sie das --thresholds-reset Flag, sodass nur der angegebene Schwellenwert aktiv ist. Siehe die --thresholds-reset Dokumentation für eine vollständige Übersicht. (z.B.: --thresholds-reset)
  6. Setzen Sie das --err Flag, um den Befehl fehlschlagen zu lassen, wenn ein Alarm generiert wird. Siehe die --err Dokumentation für eine vollständige Übersicht. (z.B.: --err)
  7. Setzen Sie die --adapter Option auf Bencher Metric Format JSON (json), das von bencher mock generiert wird. Siehe Benchmark-Harness-Adapter für eine vollständige Übersicht. (z.B.: --adapter json)
  8. Geben Sie die Benchmark-Befehlsargumente an. Siehe Benchmark-Befehl für eine vollständige Übersicht. (z.B.: bencher mock)

Das erste Mal, wenn dieser Befehl in CI ausgeführt wird, erstellt er den main Branch, falls dieser noch nicht existiert. Der neue main wird nicht über einen Startpunkt oder vorhandene Daten verfügen. Ein Schwellenwert wird für den main Branch, das ci-runner Testbed und das latency Maß erstellt. Bei nachfolgenden Ausführungen werden dem main Branch neue Daten hinzugefügt. Der angegebene Schwellenwert wird dann verwendet, um Leistungsregressionen zu erkennen.

Jetzt sind wir bereit, Leistungsregressionen in CI zu erkennen. So würden wir die Leistung eines neuen Feature-Branchs in CI verfolgen, passend benannt feature-branch:

  1. Verwenden Sie den bencher run CLI-Unterbefehl, um Ihre Benchmarks für den feature-branch Branch auszuführen. Siehe den bencher run CLI-Unterbefehl für eine vollständige Übersicht. (z.B.: bencher run)
  2. Setzen Sie die --project Option auf den Projektslug. Siehe die --project Dokumentation für mehr Details. (z.B.: --project save-walter-white-1234abcd)
  3. Setzen Sie die --branch Option auf den Feature-Branch-Namen. Siehe die --branch Dokumentation für eine vollständige Übersicht. (z.B.: --branch feature-branch)
  4. Setzen Sie den Startpunkt für den feature-branch Branch:
    1. Setzen Sie die --start-point Option auf den Startpunkt des Feature-Branches. Siehe die --start-point Dokumentation für eine vollständige Übersicht. (z.B.: --start-point main)
    2. Setzen Sie die --start-point-hash Option auf den Git-Hash des Startpunkts des Feature-Branches. Siehe die --start-point-hash Dokumentation für eine vollständige Übersicht. (z.B.: --start-point-hash 32ae...dd8b)
    3. Setzen Sie das --start-point-clone-thresholds Flag, um die Schwellenwerte vom Startpunkt zu klonen. Siehe die --start-point-clone-thresholds Dokumentation für eine vollständige Übersicht. (z.B.: --start-point-clone-thresholds)
    4. Setzen Sie das --start-point-reset Flag, um den Branch immer auf den Startpunkt zurückzusetzen. Dies verhindert das Abdriften von Benchmark-Daten. Siehe die --start-point-reset Dokumentation für eine vollständige Übersicht. (z.B.: --start-point-reset)
  5. Setzen Sie die --testbed Option auf den Namen des Testbeds. Siehe die --tested Dokumentation für mehr Details. (z.B.: --testbed ci-runner)
  6. Setzen Sie das --err Flag, um den Befehl fehlschlagen zu lassen, wenn ein Alarm generiert wird. Siehe die --err Dokumentation für eine vollständige Übersicht. (z.B.: --err)
  7. Setzen Sie die --adapter Option auf Bencher Metric Format JSON (json), das von bencher mock generiert wird. Siehe Benchmark-Harness-Adapter für eine vollständige Übersicht. (z.B.: --adapter json)
  8. Geben Sie die Benchmark-Befehlsargumente an. Siehe Benchmark-Befehl für eine vollständige Übersicht. (z.B.: bencher mock)

Das erste Mal, wenn dieser Befehl in CI ausgeführt wird, wird Bencher den feature-branch Branch erstellen, da er noch nicht existiert. Der neue feature-branch wird den main Branch bei Hash 32aea434d751648726097ed3ac760b57107edd8b als seinen Startpunkt verwenden. Das bedeutet, dass feature-branch eine Kopie aller Daten und Schwellenwerte vom main Branch haben wird, um die Ergebnisse von bencher mock damit zu vergleichen. Bei allen nachfolgenden Ausführungen wird Bencher den feature-branch Branch auf den Startpunkt zurücksetzen und die Daten und Schwellenwerte des main Branch verwenden, um Leistungsregressionen zu erkennen.

Relative Continuous Benchmarking

Anknüpfend an unsere bisherigen Fortschritte in den Quick Start und Docker Self-Hosted Tutorials, fügen wir Relatives Continuous Benchmarking zu unserem Save Walter White Projekt hinzu.

🐰 Stellen Sie sicher, dass Sie einen API-Token erstellt und als BENCHER_API_TOKEN Umgebungsvariable gesetzt haben bevor Sie fortfahren!

Relatives Continuous Benchmarking führt einen direkten Vergleich zwischen zwei Versionen Ihres Codes durch. Dies kann nützlich sein, wenn man mit lauten CI/CD-Umgebungen zu tun hat, bei denen die verfügbaren Ressourcen zwischen den Läufen stark variieren können. In diesem Beispiel werden wir die Ergebnisse vom Laufen im main Branch mit den Ergebnissen aus einem feature Branch, treffend als feature-branch benannt, vergleichen. Da jede CI-Umgebung ein wenig anders ist, soll dieses Beispiel mehr veranschaulichend als praktisch sein. Für spezifischere Beispiele, siehe Continuous Benchmarking in GitHub Actions und Continuous Benchmarking in GitLab CI/CD.

Zuerst müssen wir den main Branch mit git in CI auschecken:

Terminal window
git checkout main

Dann müssen wir unsere Benchmarks im main Branch in CI ausführen:

Terminal window
bencher run \
--project save-walter-white-1234abcd \
--branch main \
--start-point-reset \
--testbed ci-runner \
--adapter json \
bencher mock
  1. Verwenden Sie den bencher run CLI-Unterbefehl, um Ihre main Branch Benchmarks auszuführen. Siehe den bencher run CLI-Unterbefehl für eine vollständige Übersicht. (z.B.: bencher run)
  2. Setzen Sie die --project Option auf das Projektslug. Siehe die --project Dokus für weitere Details. (z.B.: --project save-walter-white-1234abcd)
  3. Setzen Sie die --branch Option auf den Basisbranch-Namen. Siehe die --branch Dokus für eine vollständige Übersicht. (z.B.: --branch main)
  4. Setzen Sie das --start-point-reset Flag, um den Basisbranch immer zurückzusetzen. Dies stellt sicher, dass alle Benchmark-Daten vom aktuellen CI-Runner stammen. Siehe die --start-point-reset Dokus für eine vollständige Übersicht. (z.B.: --start-point-reset)
  5. Setzen Sie die --testbed Option auf den Namen des CI-Runner-Testbeds. Siehe die --testbed Dokus für weitere Details. (z.B.: --testbed ci-runner)
  6. Setzen Sie die --adapter Option auf Bencher Metric Format JSON (json), das von bencher mock generiert wird. Siehe benchmark harness adapters für eine vollständige Übersicht. (z.B.: --adapter json)
  7. Geben Sie die Argumente des Benchmark-Befehls an. Siehe benchmark command für eine vollständige Übersicht. (z.B.: bencher mock)

Beim ersten Mal, wenn dieser Befehl in CI ausgeführt wird, wird der main Branch erstellt, da er noch nicht existiert. Der neue main wird nicht über einen Startpunkt, vorhandene Daten oder Thresholds verfügen. Bei nachfolgenden Läufen wird der alte main Head ersetzt und ein neuer main Head wird erstellt, ohne einen Startpunkt, vorhandene Daten oder Thresholds.

Als nächstes müssen wir den feature-branch Branch mit git in CI auschecken:

Terminal window
git checkout feature-branch

Schließlich sind wir bereit, unsere feature-branch Benchmarks in CI auszuführen:

Terminal window
bencher run \
--project save-walter-white-1234abcd \
--branch feature-branch \
--start-point main \
--start-point-reset \
--testbed ci-runner \
--threshold-measure latency \
--threshold-test percentage \
--threshold-upper-boundary 0.25 \
--thresholds-reset \
--err \
--adapter json \
bencher mock
  1. Verwenden Sie den bencher run CLI-Unterbefehl, um Ihre feature-branch Benchmarks auszuführen. Siehe den bencher run CLI-Unterbefehl für eine vollständige Übersicht. (z.B.: bencher run)
  2. Setzen Sie die --project Option auf das Projektslug. Siehe die --project Dokus für weitere Details. (z.B.: --project save-walter-white-1234abcd)
  3. Setzen Sie die --branch Option auf den Featurebranch-Namen. Siehe die --branch Dokus für eine vollständige Übersicht. (z.B.: --branch feature-branch)
  4. Setzen Sie den Startpunkt für den feature-branch Branch:
    1. Setzen Sie die --start-point Option auf den Startpunkt des Featurebranches. Siehe die --start-point Dokus für eine vollständige Übersicht. (z.B.: --start-point main)
    2. Setzen Sie das --start-point-reset Flag, um den Branch immer auf den Startpunkt zurückzusetzen. Dabei werden nur die neuesten relativen Benchmark-Ergebnisse verwendet. Siehe die --start-point-reset Dokus für eine vollständige Übersicht. (z.B.: --start-point-reset)
  5. Setzen Sie die --testbed Option auf den Namen des CI-Runner-Testbeds. Siehe die --testbed Dokus für weitere Details. (z.B.: --testbed ci-runner)
  6. Setzen Sie die Schwelle für den feature-branch Branch, ci-runner Testbed und latency Measure:
    1. Setzen Sie die --threshold-measure Option auf das eingebaute latency Measure, das von bencher mock generiert wird. Siehe die --threshold-measure Dokus für weitere Details. (z.B.: --threshold-measure latency)
    2. Setzen Sie die --threshold-test Option auf einen einfachen Prozentsatz (percentage). Siehe die --threshold-test Dokus für eine vollständige Übersicht. (z.B.: --threshold-test percentage)
    3. Setzen Sie die --threshold-upper-boundary Option auf die Obergrenze von 0.25. Siehe die --threshold-upper-boundary Dokus für weitere Details. (z.B.: --threshold-upper-boundary 0.25)
    4. Setzen Sie das --thresholds-reset Flag, so dass nur die angegebene Schwelle aktiv ist. Siehe die --thresholds-reset Dokus für eine vollständige Übersicht. (z.B.: --thresholds-reset)
  7. Setzen Sie das --err Flag, um den Befehl zu beenden, falls ein Alert erzeugt wird. Siehe die --err Dokus für eine vollständige Übersicht. (z.B.: --err)
  8. Setzen Sie die --adapter Option auf Bencher Metric Format JSON (json), das von bencher mock generiert wird. Siehe benchmark harness adapters für eine vollständige Übersicht. (z.B.: --adapter json)
  9. Geben Sie die Argumente des Benchmark-Befehls an. Siehe benchmark command für eine vollständige Übersicht. (z.B.: bencher mock)

Jedes Mal, wenn dieser Befehl in CI ausgeführt wird, vergleicht er die Ergebnisse des feature-branch nur mit den neuesten Ergebnissen aus main. Die angegebene Schwelle wird dann verwendet, um Leistungsregressionen zu erkennen.

Change Point Detection

Change Point Detection verwendet einen Change Point Algorithmus, um ein großes Fenster aktueller Ergebnisse auszuwerten. Dies ermöglicht es dem Algorithmus, Ausreißer als Rauschen zu ignorieren und weniger Fehlalarme zu erzeugen. Obwohl Change Point Detection als [kontinuierliches Benchmarking][continuous benchmarking] betrachtet wird, erlaubt es nicht, Leistungsregressionen in CI zu erkennen. Das heißt, Sie können eine Leistungsregression nicht erkennen, bevor ein Feature-Branch zusammengeführt wird. Dies wird manchmal als “Out-of-Band”-Erkennung bezeichnet.

Zum Beispiel, wenn Sie einen Benchmark bench_my_critical_path haben, und dieser hatte folgende historische Latenzen: 5 ms, 6 ms, 5 ms, 5ms, 7ms.

Wenn das nächste Benchmark-Ergebnis 11 ms wäre, dann würden ein Schwellenwert für Statistisches Kontinuierliches Benchmarking und der Change Point Detection Algorithmus die Dinge sehr unterschiedlich interpretieren. Der Schwellenwert würde wahrscheinlich überschritten und ein Alarm würde generiert werden. Wenn dieser Benchmark-Lauf mit einem Pull-Request verbunden wäre, würde das Build wahrscheinlich aufgrund dieses Alarms fehlschlagen. Der Change Point Algorithmus würde jedoch noch nichts unternehmen. Wenn beim nächsten Lauf die Werte wieder auf 5 ms fallen würden, würde wahrscheinlich kein Alarm generiert werden. Umgekehrt, wenn der nächste Lauf oder zwei 10 ms und 12 ms ergeben würden, würde der Change Point Algorithmus erst dann einen Alarm auslösen.

Haben Sie Interesse an der Verwendung von Change Point Detection mit Bencher? Falls ja, hinterlassen Sie bitte einen Kommentar im Tracking Issue oder kontaktieren Sie uns direkt.



🐰 Glückwunsch! Sie haben gelernt, wie man Benchmarks in CI mit Bencher verfolgt! 🎉


Bencher zu GitHub Actions hinzufügen ➡

Bencher zu GitLab CI/CD hinzufügen ➡

🤖 Dieses Dokument wurde automatisch von OpenAI GPT-4 generiert. Es ist möglicherweise nicht korrekt und kann Fehler enthalten. Wenn Sie Fehler finden, öffnen Sie bitte ein Problem auf GitHub.


Published: Fri, October 27, 2023 at 8:40:00 AM UTC | Last Updated: Mon, November 11, 2024 at 7:45:00 AM UTC