> Source: https://www.ymotongpoo.com/works/oteps/otep-5109/


# OTEP-5109: OpenTelemetryベンチマーク集中リポジトリ

プロジェクトが所有する `open-telemetry/benchmarks` リポジトリを新設し、言語横断的なシナリオ定義をホストし、それらを各言語実装のリリース上で実行し、履歴ダッシュボードを公開します。
スコープは意図的に単一のシナリオと、少なくとも2つの言語ハーネスに限定されています。
さらなるシナリオと言語は、この新しいリポジトリの中で段階的に追加できます。

## 動機 {#motivation}

仕様にはすでにパフォーマンスに関連するガイダンスが含まれています。

- [`specification/performance-benchmark.md`](../specification/performance-benchmark.md)
  は、スパンのスループット測定手法、CPUとメモリの測定ガイダンス、そしてレポート形式を定義しています。

このドキュメントはこれまで言語横断的なベンチマークの成果につながっていません。
これはスパンのみを対象としており、メトリクスとログのシグナルより前に書かれたもので、結果として得られる数値がどこで報告され、比較され、時系列で追跡されるかを定めた中央の場所を定義していません。
自身をベンチマークする各言語実装は、それぞれ独自のリポジトリで、独自の手法により、独自の形式でこれを行っています。
パフォーマンスに関しては、[spec compliance matrix](../spec-compliance-matrix.md)に相当するものが存在しません。

プロジェクト自身の[エンジニアリング上の価値観](https://opentelemetry.io/community/mission/)は「高いパフォーマンスはOpenTelemetryの要件である」と述べていますが、それを追跡するプロジェクト全体のメカニズムは存在しません。
[`metrics/api.md`](../specification/metrics/api.md)と[`trace/api.md`](../specification/trace/api.md)はいずれも、SDKが構成されていないときにAPIがno-opであることを要求していますが、プロジェクトにはすべての実装がこの要件を満たしているという共有された証拠がなく、そのパスのコストが時間とともにどのように推移するかについてのリリースをまたいだ可視性もありません。

## 解説 {#explanation}

プロジェクト組織のもとに新しいリポジトリ `open-telemetry/benchmarks` を作成します。
これには以下が含まれます。

1. 任意の言語実装が一貫した方法で実装できるシナリオ定義。
2. 言語固有のハーネス（シナリオごと、言語ごとに1つ）を実行し、結果を公開するGitHub Actionsワークフロー。
3. シナリオごと、言語ごと、リリースごとの結果の履歴記録。
4. リリースをまたいだトレンドを示すGitHub Pagesダッシュボード。

このリポジトリはトレンドの追跡者であり、リグレッション検出のためのCIではありません。
コミットごと、あるいは夜間のリグレッション検出は、各言語実装自身のリポジトリに属する責務であり、そこではメンテナーがケイデンス、しきい値、そして失敗した実行への対応を管理します。
ここで提案されているダッシュボードは、参加している各実装の追跡対象リリースごとに1つのデータポイントを記録します。
その目的はリリースをまたいだ可視性であり、個々の変更をゲーティングすることではありません。

### 初期シナリオ {#the-initial-scenario}

シナリオS1: 安定した属性セットを用いた、API限定でのカウンターのインクリメント。

- OTel APIパッケージのみに依存します。
  SDKパッケージは参照も読み込みもされません。
- このベンチマークは、`Counter` インストゥルメント（`house.energy.consumed`）を、毎回の呼び出しで同じ属性値を用いてタイトループの中で1ずつインクリメントします。
  属性セットは3つの文字列属性を使用します。例えば以下のとおりです。
  - `house.room` = `"living_room"`
  - `house.device` = `"thermostat"`
  - `house.action` = `"set_temperature"`
- シングルスレッド（OSスレッド1つ）です。
  非同期やコルーチンスタイルのコードは、イディオマティックであれば問題ありません。
  マルチスレッドおよび競合を伴うバリアントは、後続のシナリオに委ねられます。
- 実行ごとに報告されるメトリクス。
  - `ns/op`（中央値）。
  - `allocations/op`（操作あたりのヒープ割り当て数）。言語がこれを公開している場合。
    bytes/opは任意です。

S1が最初のシナリオとして選ばれたのは以下の理由からです。

1. 既存の規範的な要件（[API no-op要件](../specification/metrics/noop.md)）を検証するものであり、それを正当化するための新しい仕様上の文言を必要としません。
2. OpenTelemetryの目標は、あらゆるライブラリとフレームワークにおけるネイティブな計装です。
   ライブラリのオーナーが最初に尋ねる質問は「SDKが構成されていないとき、これにどれだけのコストがかかるのか」です。
   no-opのコストが高いと、ライブラリ自体の速度を直接低下させます。
   この質問に対する公開されたリリースごとの回答は、採用における主要な障壁を取り除きます。

### 初期言語 {#initial-languages}

初期のロールアウトでは、少なくとも2つの言語でシナリオS1のハーネスが必要です。
具体的な言語はこのOTEPで固定されません。
最初に貢献したメンテナーがその最低要件を満たすことになり、さらなる言語はそれぞれのOTEPなしで後から追加できます。

## 内部の詳細 {#internal-details}

### リポジトリのレイアウト {#repository-layout}

```text
open-telemetry/benchmarks/
├── README.md
├── scenarios/
│   └── S1-counter-increment-api-only.md
├── harnesses/
│   └── <language>/
├── .github/workflows/
│   └── run-benchmark.yml
└── docs/
```

### 更新のケイデンス {#update-cadence}

各言語ハーネスは、ベンチマーク対象のSDKパッケージのバージョンを、リポジトリにチェックインされた独自のマニフェスト（`csproj`、`Cargo.toml`、`build.gradle`など）にピン留めします。
[Dependabot](https://docs.github.com/en/code-security/dependabot)や[Renovate](https://docs.renovatebot.com/)のようなボットが対応するパッケージレジストリを監視し、追跡対象のSDKが新しいリリースを公開するたびにプルリクエストを開きます。
そのプルリクエストをマージすると、ベアメタルランナー上でベンチマークワークフローがトリガーされ、結果のデータポイントがダッシュボードに追加されます。
クロスリポジトリの権限は必要ありません。
トリガーはすべてbenchmarksリポジトリの内部に存在します。

`workflow_dispatch` は、アドホックな実行（バックフィル、同一SDKを2つのランタイムバージョンで比較する、古くなったデータポイントを再実行するなど）のためのエスケープハッチとして引き続きサポートされます。
リリースがハーネスの使用するAPIを変更する場合、バージョンアップのプルリクエストにはメンテナーの手作業での対応が必要になります。
シナリオが安定したAPIを対象としているため、これは稀であると想定されています。

オンボーディングの際、実装は追跡対象の過去のリリースを少なくとも2つバックフィルする必要があります。
これにより、ダッシュボードは単一のポイントではなくトレンドを伴って開始されます。

### 実行環境 {#execution-environment}

ベンチマークの実行には、OpenTelemetryプロジェクトの既存の共有セルフホスト型ベアメタルランナーを使用します。
これはすでに他のOTelベンチマークワークフローで使用されており、[`open-telemetry/community/docs/how-to-provision-bare-metal-runner.md`](https://github.com/open-telemetry/community/blob/main/docs/how-to-provision-bare-metal-runner.md)に文書化されています。
benchmarksリポジトリは、これを使用する権限を持つリポジトリの集合に追加される必要があり、その手順は[`how-to-use-bare-metal-runner.md`](https://github.com/open-telemetry/community/blob/main/docs/how-to-use-bare-metal-runner.md#request-access)に従います（`open-telemetry/community`でアクセスをリクエストするissueを開きます）。
新しいインフラストラクチャは必要ありません。

各データポイントには環境メタデータ（ランナー、ランタイム、OS、ベンチマークツールのバージョン）が記録され、実装ではなく環境によって引き起こされた変動を特定できるようになります。

### ツールの選択 {#tooling-choice}

[`benchmark-action/github-action-benchmark`](https://github.com/benchmark-action/github-action-benchmark)は有力な選択肢の1つであり、すでに `opentelemetry-rust`、`opentelemetry-java`、`otel-arrow`、およびOpenTelemetry Collectorがベンチマークのトレンドを公開するために使用しています。
このOTEPは特定のツールにコミットするものではありません。
以下の完了基準が求めているのは、特定の実装ではなく、履歴的な結果を伴う公開ダッシュボードです。

### 初期ロールアウトの完了基準 {#exit-criteria-for-the-initial-rollout}

このOTEPで定められた初期ロールアウトは、以下がすべて満たされたときに完了します。

1. `open-telemetry/benchmarks` が、上記のレイアウトと、所有権を定義する `CODEOWNERS` とともに存在します。
   所有権は[`opentelemetry.io`](https://github.com/open-telemetry/opentelemetry.io)と同じモデルに従います。
   言語ごとのハーネスのサブフォルダーは、それぞれ対応する言語実装のアプルーバーが所有し、共有コンテンツ（シナリオ、ワークフロー、トップレベルのドキュメント）はリポジトリのトップレベルのメンテナーが所有します。
2. シナリオS1が、そのドキュメントのみから任意の言語実装が準拠するハーネスを生成できるように文書化されています。
3. 少なくとも2つの言語でS1のハーネスが存在し、マージ済みで実行可能です。
4. ベンチマークワークフローが、少なくとも1つの参加言語の少なくとも1つの追跡対象リリースに対してS1を実行しており、結果のデータポイントがダッシュボードに表示されています。
5. ダッシュボードがGitHub Pages上で公開されて閲覧可能であり、参加している各言語の最新リリースについて少なくとも1つのデータポイントを示しています。

### スコープ外 {#out-of-scope}

以下は、ここで提案されている作業には明確に含まれておらず、レビューにおいてそれと混同されるべきではありません。

- S1以外のシナリオ。
- コミットごと、あるいは夜間のリグレッション検出CI。
  その責務は各言語実装自身のリポジトリに引き続き残ります。
  ここで提案されているダッシュボードは、各実装の追跡対象リリースごとに1つのデータポイントを記録するものであり、個々の変更をゲーティングするためではなく、リリースをまたいだトレンドの可視化を意図しています。
- [`specification/performance-benchmark.md`](../specification/performance-benchmark.md)の置き換え、あるいは非推奨化。
  このドキュメントはそのまま残ります。
  このリポジトリは、それが提供していない中央のレポート場所を提供します。

上記のそれぞれは妥当な後続作業であり、[今後の課題](#future-possibilities)に概略が示されています。

## トレードオフと緩和策 {#trade-offs-and-mitigations}

- 初期の参加言語のみを対象とするダッシュボードは、すべての言語実装を代表するものではありません。
  リポジトリとシナリオのフォーマットは、任意の実装が自身のスケジュールでハーネスを追加できるように設計されるべきです。
  READMEには、ダッシュボードが参加している実装のみを反映しており、ランキングではないことが記載されます。
  ダッシュボードは、横並びの比較ではなく言語ごとに1つのトレンドチャートをプロットし、実装ごとの推移を主要なビューとして維持します。
- S1はメトリクスAPIのみを検証します。
  スパンの作成とログの発行に対する同等のAPI限定シナリオは、妥当な後続作業であり、[今後の課題](#future-possibilities)に列挙されています。

## 先行技術と代替技術 {#prior-art-and-alternatives}

- [`specification/performance-benchmark.md`](../specification/performance-benchmark.md)
  — 中央のレポート場所を持たない既存の手法ドキュメントです。
  このOTEPはその場所を提供します。
- [spec-compliance-matrix](../spec-compliance-matrix.md) — このOTEPがパフォーマンスにおいて相当する、適合性の類似物です。
- [opentelemetry-rust-contrib#548のレビュースレッド](https://github.com/open-telemetry/opentelemetry-rust-contrib/pull/548#discussion_r2850585180)
  — 意味のある処理を行っている「no-opパス」の例であり、リリースをまたいだトレンドビューが明らかにする類の挙動を示しています。

検討された代替案。

- 連合モデル: 各言語のリポジトリが共有シナリオを自身で実行し、結果を中央のダッシュボードにプッシュする、中央のハーネスコードを持たないモデルです。
  N個のリポジトリにまたがって一貫したCI構成を維持することは、すべてを1か所でホストするよりもオーバーヘッドが大きいため、採用されませんでした。

## 未解決の問題 {#open-questions}

- トップレベルのリポジトリの所有権。
  言語ごとのハーネスのサブフォルダーは（`opentelemetry.io`と同様に）その言語実装のアプルーバーが所有します。
  共有コンテンツとリポジトリの所有権については、長期的なオーナー（例えば新しいPerformance SIG、Spec Sponsors、あるいはTC）が選ばれるまでの暫定メンテナーとして、Cijo Thomas（@cijothomas、Microsoft）とMartin Costello（@martincostello、Grafana Labs）が提案されています。

## プロトタイプ {#prototypes}

このOTEPで説明されているモデルの動作するプロトタイプが<https://github.com/cijothomas/otel-benchmarks>で公開されており、ライブダッシュボードは<https://cijothomas.github.io/otel-benchmarks/>にあります。
これは、各言語のネイティブなベンチマークフレームワーク（BenchmarkDotNet、Criterion、JMH）を用いて.NET、Rust、Javaにわたってシナリオ S1 を実行し、統一されたスキーマを通じて結果を公開し、データポイントごとの環境メタデータ（ランナーイメージ、ランタイムバージョン、CPUモデル、カーネルバージョン、ベンチマークフレームワークのバージョン）を記録します。
このプロトタイプは個人アカウントの下でホストされ、共有のGitHubホスト型CIランナー上で実行されており、権威あるパフォーマンス数値を公開することではなく、提案されているモデルのエンドツーエンドの形を実証することのみを意図しています。

## 今後の課題 {#future-possibilities}

以下の項目は意図的にこのOTEPには含まれておらず、妥当な後続作業の非拘束的なスケッチとしてここに列挙されています。

- シナリオを拡張し、追加のシグナル（スパン、ログ）、SDKの高速パスの処理（サンプリング、集計）、そしてマルチスレッドや競合を伴うワークロードをカバーします。
- 初期ロールアウトで貢献された言語を超えて、さらなる言語をオンボードします。
- データ、レイアウト、プロセスが安定した後、公式の[`opentelemetry.io`](https://opentelemetry.io)サイト上でダッシュボードを公開します。
  当初の拠点は、`open-telemetry/benchmarks` リポジトリからホストされるGitHub Pagesサイトのままです。

