run-jmh-benchmarks-hetzner
Hetzner CCX33サーバーをプロビジョニングし、プロジェクトをデプロイしてJMHベンチマークを実行し、結果を収集した後、サーバーを削除します。ユーザーがHetznerサーバーでJMHベンチマークの実行を明示的に要求した場合のみ使用してください。一般的なベンチマーク要求やローカルベンチマーク実行では自動実行しません。
description の原文を見る
Provision a Hetzner CCX33 server, deploy the project, run JMH benchmarks, collect results, and destroy the server. Use ONLY when the user explicitly asks to run JMH benchmarks on a Hetzner server. Do NOT trigger for general benchmark requests or local benchmark runs.
SKILL.md 本文
Hetzner で JMH ベンチマークを実行
専用の Hetzner クラウドサーバーをプロビジョニングし、現在の作業ツリーをデプロイして、任意のモジュールから JMH ベンチマークを実行し、結果をダウンロードして、サーバーを停止します。
前提条件
hcloudCLI がインストールされて認証されている (hcloud versionで確認)- SSH キーペアが
~/.ssh/id_ed25519(または~/.ssh/id_rsa) に存在 - ベンチマークモジュールがローカルでコンパイルできる
ワークフロー
ステップ 0: ベンチマークモジュールとパラメーターを決定
ユーザーに確認するか、コンテキストから推測して、どのベンチマークモジュールを実行するかを決定します。プロジェクトに複数の JMH ベンチマークモジュールが含まれることがあります。一般的な例:
jmh-ldbc— LDBC SNB 読み取りクエリベンチマーク(ユーザーが「ベンチマークを実行」と言った場合のデフォルト)- JMH 依存関係を持つ他のモジュール —
pom.xmlでjmh-core依存関係を確認
以下を決定します:
- モジュール名 (
-pl <module>) - JMH 正規表現フィルター (含める/除外するベンチマーク)
- JMH パラメーター (フォーク数、ウォームアップ、測定反復)
デフォルト値(比較実行に適切):
-f 1 -wi 3 -w 5s -i 5 -r 10s
jmh-ldbc の場合:
- 予想実行時間:
-f 1 -wi 3 -w 5s -i 5 -r 10sで約 40 ベンチマーク(20 クエリ x 2 スイート)に対して約 90 分
ステップ 1: サーバーをプロビジョニング
命名規約: サーバーに jmh-bench-<branch>、SSH キーに jmh-bench-key-<branch> を使用します。ここで <branch> は現在の git ブランチ名です(サニタイズ: 小文字、スラッシュをダッシュに置換、合計名を 63 文字以下に切り詰め)。これにより、異なるブランチで複数のベンチマーク実行が同時に実行されるときの競合を回避できます。
# ブランチベースの名前を決定
BRANCH=$(git rev-parse --abbrev-ref HEAD | tr '[:upper:]/' '[:lower:]-' | cut -c1-40)
SERVER_NAME="jmh-bench-${BRANCH}"
KEY_NAME="jmh-bench-key-${BRANCH}"
# ローカル SSH 公開鍵をアップロード
hcloud ssh-key create --name "$KEY_NAME" --public-key-from-file ~/.ssh/id_ed25519.pub
# CCX33 を作成: 8 個の専用 AMD vCPU、32 GB RAM、Falkenstein DC
hcloud server create --name "$SERVER_NAME" --type ccx33 --image ubuntu-24.04 --location fsn1 --ssh-key "$KEY_NAME"
出力から IPv4 アドレスを記録します。SSH を試行する前に、サーバーがブートするまで約 15 秒待ちます。
SSH がホストキーの競合で失敗する場合は、古いキーを削除します:
ssh-keygen -f ~/.ssh/known_hosts -R <IP>
ステップ 2: JDK 21 をインストール
ssh -o StrictHostKeyChecking=no root@<IP> \
'apt-get update -qq && apt-get install -y -qq openjdk-21-jdk-headless git tmux > /dev/null 2>&1 && java -version'
ステップ 3: プロジェクトをデプロイ
ワークツリーのルート(mvnw、pom.xml、core/ などを含むディレクトリ)を rsync で転送します。.git、target、.idea は除外します:
rsync -az --exclude='.git' --exclude='target' --exclude='.idea' <worktree-root>/ root@<IP>:/root/ytdb/
重要: 作業ディレクトリ(例: /workspace/ytdb/ldbc-jmh)は git ワークツリーの場合があります — ルートに mvnw を含む完全なプロジェクトツリーが含まれています。このディレクトリを rsync してください。親ディレクトリ /workspace/ytdb/ ではなく。
次に、サーバー上で git リポジトリを初期化します(Spotless に必要):
ssh root@<IP> 'git config --global --add safe.directory /root/ytdb && \
git config --global user.email "bench@test" && \
git config --global user.name "bench" && \
cd /root/ytdb && git init && git add -A && git commit -m "baseline" --quiet'
ステップ 3b: Hetzner S3 からデータセットをダウンロード(jmh-ldbc のみ — 必須)
LDBC データセットはベンチマーク実行前にあらかじめダウンロードする必要があります。ベンチマークは SURF から自動ダウンロードしなくなりました(SURF 形式は互換性がありません)。Hetzner Object Storage (S3) からダウンロードします:
ssh root@<IP> 'apt-get install -y -qq python3-pip zstd > /dev/null 2>&1 && \
pip install --break-system-packages boto3 -q && \
mkdir -p /root/ytdb/<module>/target/ldbc-dataset/sf0.1 && \
python3 -c "
import boto3, os
s3 = boto3.client(\"s3\",
endpoint_url=os.environ[\"S3_ENDPOINT\"],
aws_access_key_id=os.environ[\"S3_ACCESS_KEY\"],
aws_secret_access_key=os.environ[\"S3_SECRET_KEY\"])
print(\"Downloading dataset from S3...\")
s3.download_file(\"bench-cache\", \"ldbc/ldbc-sf0.1-composite-merged-fk.tar.zst\", \"/tmp/dataset.tar.zst\")
print(\"Downloaded\")
" && \
cd /root/ytdb/<module>/target/ldbc-dataset/sf0.1 && \
zstd -d /tmp/dataset.tar.zst -o /tmp/dataset.tar && \
tar xf /tmp/dataset.tar && \
rm -f /tmp/dataset.tar.zst /tmp/dataset.tar && \
echo "Dataset ready" && ls static/ dynamic/'
重要: 上記のコマンドはリモートサーバー上の環境変数として S3 認証情報を必要とします。SSH 経由で渡します:
ssh root@<IP> "export S3_ENDPOINT='<endpoint>' S3_ACCESS_KEY='<key>' S3_SECRET_KEY='<secret>' && ..."
認証情報は GitHub シークレットとして保存されています: HETZNER_S3_ACCESS_KEY、HETZNER_S3_SECRET_KEY、HETZNER_S3_ENDPOINT。GitHub から取得するか、ユーザーに確認してください。
<module> をベンチマークモジュール(例: jmh-ldbc)に置き換えます。
データセットは LDBC datagen v1.0.0 CsvCompositeMergeForeign 形式(約 19 MB)を使用します。Hetzner Object Storage バケット bench-cache のキー ldbc/ldbc-sf0.1-composite-merged-fk.tar.zst に保存されています。
S3 認証情報が利用できない場合、LDBC datagen Docker イメージを使用してデータセットをローカルで生成し、サーバーに rsync で転送します:
# ローカルマシン上
docker run --rm \
-v "$(pwd)/jmh-ldbc/target/ldbc-dataset/sf0.1:/out" \
ldbc/datagen:latest \
--scale-factor 0.1 --mode raw --format CsvCompositeMergeForeign
# その後、データセットをサーバーに rsync
rsync -az jmh-ldbc/target/ldbc-dataset/ root@<IP>:/root/ytdb/jmh-ldbc/target/ldbc-dataset/
repository.surfsara.nl の SURF リポジトリを使用しないでください — CsvComposite 形式(v0.3.5)を提供しており、ベンチマークローダーが期待する形式と互換性がありません。
ステップ 4: コンパイル
ssh root@<IP> 'cd /root/ytdb && chmod +x mvnw && \
./mvnw -pl <module> -am compile -DskipTests -Dspotless.check.skip=true -q'
<module> をターゲットベンチマークモジュール(例: jmh-ldbc)に置き換えます。
BUILD SUCCESS を待ちます(通常 CCX33 で 60 〜 90 秒)。
ステップ 4b: LDBC データセットをプリロード(jmh-ldbc のみ)
jmh-ldbc の場合重要: LDBC データセットはダウンロードされ、JMH の @Setup(Level.Trial) メソッド内でデータベースにロードされます。これは最初のフォークのウォームアップ反復にデータセットダウンロード + DB 作成時間が含まれることを意味します。マルチスレッドベンチマークでは、スレッドが部分的にロードされたデータベース上でクエリ実行を開始し、非常に不正確な結果(例: 実際のスループットが約 3 ops/s のときに 300+ ops/s)を生成します。
実際のベンチマーク実行前に、常にデータセットをプリロードします:
ssh root@<IP> 'cd /root/ytdb && ./mvnw -pl <module> -am verify -P bench -DskipTests -Dspotless.check.skip=true \
-Djmh.args="ic5_newGroups -f 0 -wi 0 -i 1 -r 1s -t 1" 2>&1 | tail -20'
これは単一のプロセス内反復(-f 0)を実行し、データセットダウンロードと DB 作成をトリガーします。その後のフォーク済み実行は、./target/ldbc-bench-db 既存の DB を見つけてロードをスキップします。
ステップ 3b 経由でデータセットをプリダウンロードした場合: プリロードステップはまだ必要です — CSV ファイルから YouTrackDB データベースを作成します。ただし、データセットファイルが既に target/ldbc-dataset/ に存在するため、ダウンロードフェーズは自動的にスキップされます。
2 つのコードバージョンを比較する場合(A/B テスト): バージョン A の実行後、バージョン B を実行する前にベンチマークデータベースを削除して、古いキャッシュされたデータを回避します:
ssh root@<IP> 'rm -rf /root/ytdb/jmh-ldbc/target/ldbc-bench-db'
データセットファイル(target/ldbc-dataset/)は保持できます — DB のみを再作成する必要があります。
ステップ 5: ベンチマークを実行
重要: 同じサーバー上で複数のベンチマークを同時に実行しないでください。常に 1 つのベンチマーク実行が完了するまで待ってから、次を開始します。
tmux セッションでベンチマークを開始して、SSH 切断後も実行し続けるようにします。
モジュールに bench Maven プロファイルがある場合(jmh-ldbc など):
ssh root@<IP> 'tmux new-session -d -s bench \
"cd /root/ytdb && ./mvnw -pl <module> -am verify -P bench -DskipTests -Dspotless.check.skip=true \
-Djmh.args=\"<jmh-args> -rf json -rff /root/results.json\" \
2>&1 | tee /root/bench.log"'
モジュールが uber-jar を生成する場合:
ssh root@<IP> 'tmux new-session -d -s bench \
"cd /root/ytdb && java -jar <module>/target/benchmarks.jar \
<jmh-args> -rf json -rff /root/results.json \
2>&1 | tee /root/bench.log"'
JMH パラメーターの説明:
-f 1— 1 フォーク(比較実行に十分; 出版向けの結果には-f 3を使用)-wi 3 -w 5s— 3 ウォームアップ反復、各 5 秒-i 5 -r 10s— 5 測定反復、各 10 秒-e <pattern>— 正規表現に一致するベンチマークを除外-rf json -rff /root/results.json— 結果を JSON として保存
ステップ 6: 進捗を監視
定期的に(5 〜 10 分ごと)ポーリングします:
# 完了したベンチマークをカウント
ssh root@<IP> 'grep "^Result" /root/bench.log 2>/dev/null | wc -l'
# 現在のベンチマークを確認
ssh root@<IP> 'tail -5 /root/bench.log'
# 完了したかどうかを確認
ssh root@<IP> 'grep "^# Run complete\|BUILD" /root/bench.log'
ステップ 7: 結果を収集
# Run complete がログに表示されたら:
# JSON 結果をダウンロード
scp root@<IP>:/root/results.json /tmp/claude-code-results.json
# サマリーテーブルを表示
ssh root@<IP> 'grep "^Benchmark\|thrpt\|avgt" /root/bench.log | head -60'
JSON をプロジェクトディレクトリにわかりやすい名前でコピーします:
cp /tmp/claude-code-results.json <module>/<name>-results-ccx33.json
ステップ 8: サーバーを破棄
常にクリーンアップして料金を回避します。ステップ 1 の同じブランチベースの名前を使用します:
hcloud server delete "$SERVER_NAME"
hcloud ssh-key delete "$KEY_NAME"
ステップ 9: 結果を比較
ベースラインデータが存在する場合(例: メモリファイルまたは前の JSON)、以下を含む比較テーブルを表示します:
- ベンチマーク名
- ベースラインスコア
- 新規スコア
- パーセント変化
- 評価(回帰 / ノイズ / 改善)
マルチスレッドベンチマークでは、約 5 〜 7% 以内の変化は通常、測定ノイズです。シングルスレッドベンチマークはより安定しています(約 2 〜 3% のノイズフロア)。
トラブルシューティング
| 問題 | 解決策 |
|---|---|
mvnw: No such file or directory | 間違ったディレクトリを rsync しました。mvnw を含むワークツリーのルートを rsync してください。 |
| SSH ホストキー競合 | ssh-keygen -f ~/.ssh/known_hosts -R <IP> |
detected dubious ownership | git config --global --add safe.directory /root/ytdb |
| JMH がハングするか再起動が必要 | ssh root@<IP> 'rm -f /tmp/jmh.lock' 次に tmux で再実行 |
| コアテストコンパイル失敗 | コンパイルコマンドに -Dmaven.test.skip=true を追加 |
| リアルタイム出力が必要 | tmux + tee を使用(上記のコマンドに既に含まれています) |
| MT ベンチマークで ops/s がワイルドまたは不安定 | データセットがプリロードされていません。最初にステップ 4b を実行してください。最初のフォークはウォームアップ中に DB をロードし、MT スレッドは部分的にロードされたデータを見ます。 |
新規サーバーで apt-get ロック | unattended-upgrades が終わるまで 30 秒待ってから、再試行します。 |
| セットアップ中にデータセットが見つからないエラー | データセットは ステップ 3b(Hetzner S3)経由でプリダウンロードする必要があります。ベンチマークは SURF からの自動ダウンロードを行わなくなりました。 |
注記
- サーバータイプ: CCX33 は 8 個の専用 AMD EPYC vCPU を提供します — 専用(共有ではない)コアは一貫したベンチマーク結果を保証します。より重いベンチマークの場合は、CCX43(16 vCPU)または CCX53(32 vCPU)を検討してください。
- jmh-ldbc Threads.MAX: マルチスレッド LDBC ベンチマークは
@Threads(Threads.MAX)を使用します — 利用可能なプロセッサーごとに 1 スレッド。CCX33 ではこれは 8 スレッドを意味します。 - jmh-ldbc データセットローディング: LDBC データセットはステップ 3b(Hetzner S3)経由でプリダウンロードする必要があります — ベンチマークは SURF から自動ダウンロードしなくなりました。DB 作成は初回実行時に
LdbcBenchmarkState.@Setup(Level.Trial)内で行われます。実際のベンチマーク前に-f 0でプリロード(ステップ 4b を参照)します。DB パスは./target/ldbc-bench-dbです。データセットキャッシュは./target/ldbc-dataset/です。 - ベンチマークを同時に実行しない: 同じサーバー上の複数の JMH プロセスは CPU をめぐって競合し、信頼性の低い数値を生成します。常に一度に 1 つずつ実行します。
- Ubuntu apt ロック(新規サーバー): 新しくプロビジョニングされた Ubuntu 24.04 サーバーは初回ブートで
unattended-upgradesを実行します。apt-get installが「Could not get lock」で失敗した場合は、30 秒待ってから再試行してください。 - メモリファイル: LDBC ベンチマークの場合、各実行後に自動メモリディレクトリの
ldbc-jmh-benchmarks.mdを新しい結果で更新します。 - S3 データセットキャッシュ: LDBC データセットアーカイブ(
ldbc-sf0.1-composite-merged-fk.tar.zst、約 19 MB、datagen v1.0.0 CsvCompositeMergeForeign 形式)は Hetzner Object Storage バケットbench-cacheのldbc/ldbc-sf0.1-composite-merged-fk.tar.zstにキャッシュされています。認証情報は GitHub シークレットHETZNER_S3_ACCESS_KEY/HETZNER_S3_SECRET_KEY/HETZNER_S3_ENDPOINTに保存されています — コードにハードコードしたり、リポジトリにコミットしたりしないでください。 - S3 アクセスなしでデータセット: S3 認証情報が利用できない場合は、LDBC datagen Docker イメージを使用してローカルでデータセットを生成します:
docker run --rm -v "$(pwd)/jmh-ldbc/target/ldbc-dataset/sf0.1:/out" ldbc/datagen:latest --scale-factor 0.1 --mode raw --format CsvCompositeMergeForeign。次に、生成されたデータセットをサーバーに rsync します。詳細はjmh-ldbc/README.mdを参照してください。 - SURF を使用しない: SURF Data Repository(
repository.surfsara.nl)は CsvComposite 形式(v0.3.5)を提供しており、ベンチマークローダーが期待する CsvCompositeMergeForeign カラムレイアウトと互換性がありません。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- majiayu000
- ライセンス
- MIT
- 最終更新
- 2026/5/4
Source: https://github.com/majiayu000/claude-skill-registry / ライセンス: MIT