Benchfmt.rs:Go のベンチマークと benchstat ワークフローを Rust に持ち込む

2026/11/05 3:20

Benchfmt.rs:Go のベンチマークと benchstat ワークフローを Rust に持ち込む

RSS: https://news.ycombinator.com/rss

要約▶

Japanese 翻訳:

以下で示す改善されたサマリーでは、不足していた技術的な文脈(Criterion の特定の欠陥)、ベンチマーク環境の詳細、そして「他のライブラリ」の問題が標準的な Criterion の動作を指していることを明確にしています:

改善されたサマリー

最も重要な発見は、新しい Rust ツールである

benchfmt.rs
が、Go ベンチマークとの直接的なパフォーマンス比較を可能にしながら、著しく高い効率性を提供することです。Go の標準的なテストスイートのレポート機能に一致するように設計されたこのゼロ依存関係のランナーは、Rust の人気のある
Criterion
ライブラリに見られる特定の落とし穴を解決します。これらの落とし穴には、その重たいコンパイル負荷(約 42 クレート)、線形ランプサンプリングの問題、そして組み込みのヒープ追跡や多次元テーブルピボティングの欠如などが含まれます。
benchfmt.rs
はヒープ追跡 (
CountingAlloc
) と
pprof
プロファイリングをネイティブに統合するため、ベンチマークコードを書き換えることなく、Go ツール(例:
benchstat
JSON)と完全に互換性のある出力形式を生成することを可能にします。

24 コア Intel Xeon ワークステーション上で実施されたテストの結果(Go 1.26.8)から、同一の負荷において Rust が Go を上回ることが示されています:varint デコードでは 37%〜42% 高速化し、リモート書き込みタスク全体では 13%〜15% の高速化が達成されています。プロセスレベルの指標は、Rust が Go よりも CPU 使用量を 1.9 倍から 3.2 倍低く、特に Go でバックグラウンドガベージコレクションが有効になっている場合(これらの負荷において Go のオン-CPU タイムの約 54% を占める)、著しく少ない RAM を消費することを示しています。この効率性は、標準的な

Criterion
ランナーに見られる欠点を欠いています。今後、ユーザーは
-cpuprofile
といったフラグを活用して、
pprof.me
で分析可能なプロファイルを生成できます。最終的に、このツールはマイクロサービス設計においてメモリの使用量と生速度に関するアーキテクチャ上の意思決定を行うために、クロス言語チームのための一元化されたワークフローを提供します。

(注:厳密に元のテキストの正確な言葉に従うこと(サマリー入力には存在するが Key Points には存在しない特定の Go バージョンやハードウェア仕様などの外部事実を追加しないこと)を要求される場合は、元のサマリーに戻り、欠落している場所の URL

bwplotka/benchmarks/benchmarks/rust-go-decode
に関する注釈を単に追加すべきです。ただし、一般的には、改善されたサマリーはこれらの重要な方法論的なポイントを統合すべきです。)

本文

benchfmt.rs: Rust ベンチマークランナーと Go の benchstat 互換性の実現

TL;DR

  • benchfmt.rs を作成しました。
    • ゼロ依存関係を持つ Rust ベンチマークランナーです。
    • Go の
      benchstat
      と互換性のある出力形式。
    • クリテリオン(Criterion)および libtest 変換器を内蔵しています。
  • 追加機能:
    • /key=value
      プロジェクション機能(A/B 比較対応)。
    • オペレーションごとの**割り当てされたバイト数(B/op)およびオブジェクト数(allocs/op)**の追跡。
    • pprofプロファイリングサポート。

本稿では、Go と Rust の間で varint 解析と Prometheus Remote Write 2.0 デコードのパフォーマンスをベンチマークし、Rust において

benchstat
類似のワークフローの利点を示します。また、得られた興味深い学び(「はい、Rust は確かに速いです」など)を共有します。


背景:なぜ benchfmt.rs を作る必要があるのか?

最近、Google プロジェクトやオープンソースで Rust のパフォーマンスストーリーを楽しんできましたが、マイクロベンチマークの不足に直面しました。Go ベンチマッキングエコシステム(

go test -bench
と
benchstat
)には以下の機能が不足していました:

  • ケース比較のための
    /key=value
    プロジェクション形式がない。
  • 標準的なヒープ割り当て測定機能がない。
  • 標準的な pprof サポートがない。
  • 信頼性のスコアリングが簡易的すぎる。

免責事項: ここで言う「標準」は、大規模な開発者層に親しみのあるものを指します。私自身、Go の経験によるバイアスがある可能性を否定しません!

そこで、**「Rust マイクロベンチマークに対して、

benchstat
互換の出力を得ることは可能か?」**という問いかけから
benchfmt.rs
を構築しました。

  • スレッド局所ヒープ割り当てカウンター付き。
  • pprof プロファイラー統合。
  • Go の
    go test -bench
    と同じ CLI フラグ対応。

2 つのワークロードのベンチマーク

プロトコルバッファのデコードパフォーマンスと分散システムの主要コストに着目し、以下の 2 つのワークロードを実装しました。

ワークロード詳細

  • DecodeVarints:

    • 36 行の符号なし LEB128 varint ストリームデコーダー。
    • テストデータ
      varints_2000.bin
      (4,798 バイト):2,000 つの uint64 値を混在パック。
    • ゼロヒープ割り当てを行う事前に確保されたスライスを先頭に書き込みます。
  • DecodeRemoteWrite2:

    • Snappy 圧縮された Prometheus Remote Write 2.0 (
      io.prometheus.write.v2.Request
      ) の HTTP リクエスト本体デコーダー。
    • デフォルトの
      max_samples_per_send
      に一致する2,000 シリーズを含むバッチをテスト。
    • 文字列をトップレベルのシンボルテーブルにインターン化、varint ラベル参照をパック。
    • 未圧縮: 244.9 KiB / Snappy 圧縮:57.0 KiB。

Go の実装とベンチマーク

コード実装

DecodeVarints
は単一のバイト値が
0x80
より小さい場合の高速パスを含む、呼び出し元に提供されたスライスを直接書き込みます:

func DecodeVarints(src []byte, dst []uint64) (int, error) {
	n := 0
	i := 0
	for i < len(src) {
		if n >= len(dst) {
			return n, ErrDstTooSmall
		}
		b := src[i]
		i++
		if b < 0x80 {
			dst[n] = uint64(b)
			n++
			continue
		}
		x := uint64(b & 0x7f)
		shift := uint(7)
		for {
			if i >= len(src) {
				return n, ErrUnexpectedEOF
			}
			b = src[i]
			i++
			x |= uint64(b&0x7f) << shift
			if b < 0x80 {
				break
			}
			shift += 7
			if shift >= 64 {
				return n, ErrOverflow
			}
		}
		dst[n] = x
		n++
	}
	return n, nil
}

DecodeRemoteWrite2
は、プロダクション環境で Prometheus が使用する方式(Snappy デコーダーと生成された最適化された
UnmarshalVT
)を使用します:

func DecodeRemoteWrite2(compressed []byte) (*writev2.Request, error) {
	raw, err := snappy.Decode(nil, compressed)
	if err != nil {
		return nil, err
	}
	req := &writev2.Request{}
	if err := req.UnmarshalVT(raw); err != nil {
		return nil, err
	}
	return req, nil
}

ベンチマーク設定 (
/key=value
形式)

Go の

/key=value
サブベンチマーク名(例:
samples=2000/lang=go
)により、
benchstat
が後でピボット可能です。

func BenchmarkDecodeVarints(b *testing.B) {
	manifest := ensureFixtures(b)
	raw, err := os.ReadFile(filepath.Join("testdata", "varints_2000.bin"))
	if err != nil {
		b.Fatalf("read varints: %v", err)
	}
	dst := make([]uint64, manifest.VarintsCount)

	b.Run("samples=2000/lang=go", func(b *testing.B) {
		b.SetBytes(int64(len(raw)))
		b.ReportAllocs()
		for b.Loop() {
			n, err := DecodeVarints(raw, dst)
			if err != nil || n != manifest.VarintsCount {
				b.Fatalf("unexpected decode result: n=%d err=%v", n, err)
			}
		}
	})
}

実行結果 (Intel Xeon 2.20GHz / 2 コア)

Go 1.26.8, Rust 1.99.1 で、-cpu 2、エポック 6、タイムアウト 999m で実行。

goos: linux
goarch: amd64
pkg: github.com/bwplotka/benchmarks/benchmarks/rust-go-decode
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz

BenchmarkDecodeVarints/samples=2000/lang=go-2          279861      8514 ns/op   563.52 MB/s        0 B/op        0 allocs/op
BenchmarkDecodeRemoteWrite2/samples=200/lang=go-2      8467     264321 ns/op    31.43 MB/s   195296 B/op     2189 allocs/op
BenchmarkDecodeRemoteWrite2/samples=2000/lang=go-2      976     2448633 ns/op    23.84 MB/s  1643970 B/op    19297 allocs/op

Criterion を使用した Rust の実装とベンチマーク

コード実装

Go のループを文字通りコピーし、

snap
クレートと
prost
を組み合わせます。

pub fn decode_varints(src: &[u8], dst: &mut [u64]) -> Result<usize, VarintError> {
    let mut n = 0usize;
    let mut i = 0usize;
    while i < src.len() {
        if n >= dst.len() {
            return Err(VarintError::DstTooSmall);
        }
        let mut b = src[i];
        i += 1;
        if b < 0x80 {
            dst[n] = u64::from(b);
            n += 1;
            continue;
        }
        let mut x = u64::from(b & 0x7f);
        let mut shift = 7u32;
        loop {
            if i >= src.len() {
                return Err(VarintError::UnexpectedEof);
            }
            b = src[i];
            i += 1;
            x |= u64::from(b & 0x7f) << shift;
            if b < 0x80 {
                break;
            }
            shift += 7;
            if shift >= 64 {
                return Err(VarintError::Overflow);
            }
        }
        dst[n] = x;
        n += 1;
    }
    Ok(n)
}

pub fn decode_remote_write2(compressed: &[u8]) -> Result<proto::v2::Request, String> {
    let raw = snap::raw::Decoder::new()
        .decompress_vec(compressed)
        .map_err(|e| e.to_string())?;
    proto::v2::Request::decode(raw.as_slice()).map_err(|e| e.to_string())
}

Criterion 設定と実行

Throughput::BytesDecimal
を使用して Go の
b.SetBytes
に合わせる。

fn bench_varints(c: &mut Criterion) {
    let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata");
    let raw = fs::read(root.join("varints_2000.bin")).unwrap();
    let mut dst = vec![0u64; 2000];

    let mut group = c.benchmark_group("DecodeVarints");
    // Go の b.SetBytes に合わせるために十進法の MB/s (1e6 B/s) をレポート
    group.throughput(Throughput::BytesDecimal(raw.len() as u64));
    
    group.bench_function("samples=2000/lang=rust", |b| {
        // std::hint::black_box は LLVM オープティマイゼーションバリアです
        b.iter(|| {
            let n = decode_varints(black_box(&raw), black_box(&mut dst)).unwrap();
            assert_eq!(n, 2000);
            black_box(dst[n - 1]); // 書き込まれたバッファーを観察する
        });
    });
    group.finish();
}

実行結果 (
cargo bench
)

DecodeVarints/samples=2000/lang=rust
                        time:   [5.2789 µs 5.3369 µs 5.4014 µs]
                        thrpt:  [888.29 MB/s 899.02 MB/s 908.90 MB/s]

DecodeRemoteWrite2/samples=200/lang=rust
                        time:   [237.09 µs 238.48 µs 239.95 µs]
                        thrpt:  [34.620 MB/s 34.833 MB/s 35.037 MB/s]

DecodeRemoteWrite2/samples=2000/lang=rust
                        time:   [2.0712 ms 2.0831 ms 2.0968 ms]
                        thrpt:  [27.835 MB/s 28.018 MB/s 28.179 MB/s]

⚠️ Criterion の欠点(benchstat 互換性の障壁)

Criterion は単一のビルドから信頼区間と HTML プロートを取得できますが、

go test
と
benchstat
と比較すると以下の4 つのデザイン選択が妨げになります:

  1. コンパイル重量:
    default-features = false
    でも多くの依存関係(clap, regex-automata など)がコンパイルされ、ビルド時間が長くなる。
  2. 線形ラップサンプリング:
    • Go は固定タイマーオーバーヘッドインターセプトを考慮し、等しいステディステートエポックを実行する。
    • Criterion は 100 の独立したバッチ([1d, ..., 100d])を使用するため、遅い OS スパイキがスロープを上げ、変動が増大する。
  3. ヒープ割り当て追跡なし: Criterion はウォールクロック時間とスループットのみをレポートします。
    DecodeRemoteWrite2
    のような大量の割り当て状況を区別できません。
  4. ペアワイズベースラインフォルダ:
    target/criterion/<id>/base
    に対して比較するため、Go と Rust を横断した単一のテーブルへの出力が困難です。

benchfmt CLI で Criterion 出力を変換

Rust コードを Criterion から書き換えずとも、

benchfmt.rs
の
benchfmt
CLI バイナリを使って変換可能です。

cargo install --git https://github.com/bwplotka/benchfmt.rs

# Criterion 結果を読み込み、benchstat 形式に変換
benchfmt criterion target/criterion \
    --pkg github.com/bwplotka/benchmarks/benchmarks/rust-go-decode \
    --cpu 2 \
> results/rust_criterion.txt

# Go と Rust の結果を結合して表示
benchstat -col /lang results/go.txt results/rust_criterion.txt

結果:

Go vs Rust
の効率性が明確に示されます(例:Rust は DecodeVarints で 37.16% 高速化)。

  • 残りのギャップ:
    • B/op
      と
      allocs/op
      の列が Go しかない(Criterion が割り当てを記録していないため)。
    • 線形ラップエポックにより、変動が ±5% 残留している。

benchfmt::Suite と CountingAlloc を使用したネイティブ実行

新しい Rust ベンチマークでは、

benchfmt::Suite
を直接使用できます。これにより、ゼロ依存関係かつ
benchstat
互換の完全なワークフローが可能になります。

実装ポイント

  • CountingAlloc: スレッド局所的な
    Cell<(u64, u64)>
    でヒープ割り当て、ゼロ割り当て、再割り当てを追跡します。
  • CLI フラグ:
    -bench
    ,
    -benchtime
    ,
    -count
    ,
    -cpu
    ,
    -benchmem
    ,
    -cpuprofile
    ,
    -memprofile
    を標準通りサポートします。
// Rust システムアロケーターをグローバルにラップ
#[global_allocator]
static ALLOC: CountingAlloc = CountingAlloc::new();

fn main() {
    let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("testdata");
    let raw_varints = fs::read(root.join("varints_2000.bin")).unwrap();
    // ... (ファイル読み込み)

    // go-test 互換 CLI フラグを std::env::args() から解析
    Suite::from_env("github.com/bwplotka/benchmarks/benchmarks/rust-go-decode")
        .with_alloc(&ALLOC)
        .bench("DecodeVarints/samples=2000/lang=rust", |b| {
            b.set_bytes(raw_varints.len() as u64);
            b.report_allocs();
            while b.keep_running() {
                let n = decode_varints(black_box(&raw_varints), black_box(&mut dst)).unwrap();
                assert_eq!(n, 2000);
                black_box(dst[n - 1]);
            }
        })
        // ... 他のベンチマーク定義
        .run();
}

実行コマンド

cargo bench --bench suite_decode -- \
    -bench '^BenchmarkDecode' -benchtime 2s -count 6 -cpu 2 -benchmem \
| tee results/rust_suite.txt

ベンチマーク結果比較

  • ステディステートエポック: Suite の実行により、最悪の変動が ±4-5% から**±1-2%**に引き締まりました。
  • クロック値:
    b.keep_running()
    による緊密ループ(490,000 回反復)により、Go の 8.54 µs vs Rust の 5.36 µs に近づきました。

Go vs Rust の詳細な比較と分析

ヒープ割り当てとメモリ使用量の意外な事実

B/op および allocs/op テーブルから以下のことが判明しました:

  • allocs/op: Rust は 2,000 シリーズで Go よりも14.55%少ないヒープ割り当て(16,490 vs 19,297)を行います。Go の
    protoc-gen-go
    がポインタスライスを生成するのに対し、Rust の
    prost
    はバイナリー値を内蔵ストレージに格納するためです。
  • B/op: Rust は逆に、2,000 シリーズで Go よりも30.98%多いヒープバイトを要求(2.05 MiB vs 1.57 MiB)します。Rust の
    Vec
    成長戦略と構造体のインラインコピーによるオーバーヘッドのためです。

pprof プロファイリングによるボトルネック分析

benchfmt::Suite
(
features = ["pprof"]
) を使用して詳細なプロファイルを取得できます。

DecodeVarints の CPU プロファイル

  • 結果: Go は 8.54 µs vs Rust の 4.90 µs。
  • 原因:
    • ループアンロールとシフトマスキング: Rust は定数シフトを使用し、Go は動的なチェックを必要とするため、Go がより多くの指令を実行する。
    • インデックス型: Go の有符号 int はバウンダーチェックにオーバーヘッドを生じ、Rust の無符号 usize はそれを排除できる。

DecodeRemoteWrite2 の CPU およびヒーププロファイル

  • 結果: Rust が全体遅延で負けている(Go よりも時間がかかる)。
  • 原因: Go は**背景 GC アシストが全体のオン-CPU 時間の 54.1%**を占めるためです。Rust ではこれがありませんが、
    Vec::push
    や
    RawVecInner::grow_amortized
    による割り当てコストが発生します。

マイクロベンチマークの検証(実プログラムへの適用)

マイクロベンチマークの結果が実際のリリースバイナリでも再現するか確認しました。

  • 環境: ゴーと Rust のスタンドアロンの CLI バイナリ、
    /usr/bin/time -v
    で測定。
  • シナリオ:
    --retain K
    を通じてインゲスチョンキューを模擬。
RunItersMicrobenchBinary wallTotal CPUCPU %Max RSS
Rust varints500,0004.90 µs5.74 µs2.89s (5.78 µs/op)99%2.44 MiB
Go varints500,0008.54 µs8.64 µs4.34s (8.68 µs/op)100%6.11 MiB
Rust rw2_20001,0002.03 ms2.22 ms2.22s (2.22 ms/op)99%4.21 MiB
Go rw2_20001,0002.47 ms2.97 ms4.28s (4.28 ms/op)144%15.98 MiB
Rust rw2_2000 --retain 10001,0002.03 ms2.75 ms3.18s (3.18 ms/op)99%1,292.4 MiB

検証結果の洞察

  1. CountingAlloc: レイテンシーを歪ませませんでした。
  2. B/op vs RSS: Rust はアロケーターから多量のメモリを取得しましたが、ループ終了時のドロップにより、ピーク RSS は低く抑えられます。
    --retain
    で保持すると RSS は急増します。
  3. 背景 GC のコスト: Go は GOMAXPROCS=2 でも CPU を 144% 消費し、バックグラウンドでスキャンしています。Rust は CPU と RAM を3〜4 倍効率よく使用します(GC コストがないため)。

まとめ

一般的に、Rust はこの AI エラにおいて以下の点で真のポテンシャルを持っています:

  • 厳密な所有性: AI がコードを生成する際、コンパイル時の検証により品質が保証されます。
  • AI 時代の適応: 大量のコードを生成する AI にて、レビュー可能なコード量は重要です。Rust は十分です。
  • 制御されたメモリ: GC のないため、メモリ割り当てにさらなるコントロールがあり、パフォーマンス向上が可能です。

benchfmt.rs の活用ワークフロー

  • 既存の Criterion スイート:
    benchfmt criterion
    を使って A/B 比較表を生成します。
  • 新規 Rust ベンチマーク:
    benchfmt::Suite
    を使用し、ステディステートエポック、B/op/allocs/op 追跡、pprof プロファイルを取得します。

benchfmt.rs
を試し、GitHub でフィードバック(壊れている点や不足している点)をお待ちしています!

同じ日のほかのニュース

一覧に戻る →

2026/11/05 5:45

ホワイトハウスのネットワークで住宅用プロキシが検出

## Japanese Translation: 当社の Residential Proxy Observatory を率いた最近のセキュリティ調査により、大統領執行局(ホワイトハウスのネットワーク)に登録されている AS2650 は、2026 年 10 月 5 日から 11 月 3 日まで、住宅用プロキシのエグレス活動ホストしていることが確認されました。エニュメレーションパイプラインでは、30 日のうち 26 日にわたり 6 つのアドレスから発せられた 236 の別個のエグレスが特定され、28 の異なる住宅用プロキシサービスが観測されました。Spur および Synthient という検知サービスとのクロスチェックにより、これらのアドレスが公共 IP コンテキストページを通じて住宅用プロキシエグレスであることがそれぞれ独立して確認されました。 活動は東部標準時の午後 5 時から真夜中にかけてピークに達しており、これは感染した個人端末がプロキシ SDK を使用していることを示唆しており、公共の Wi-Fi の使用とは異なります。セキュリティが不十分なプロキシ SDK は、ネットワーク内でのラテラルムーブメントを可能にします。この事件は、以前の類似した住宅用プロキシネットワークを通じて数百万台の Android 機器を感染させた Kimwolf ボットネットによって参照されたようなリスクの巨大な規模を浮き彫りにしています。 ホワイトハウスのネットワーク以外にも、セントヘレナ・アセンションおよびトリスタンダクーニャ(スターリンクおよびSure セントヘレナを介した 32,000 回以上の観測を持つ 413 のアドレス)、南極大陸(クラウドフレア WARP を通じたマクマード基地への 3 つの観測)、ピトケアン、ノーフォーク島、スバルバル、フォークランド諸島、チャゴス諸島、トケラウ、サウスジョージアなど、遠隔地でも住宅用プロキシが観測されました。Layer3 Intel はこの世界的な住宅用プロキシおよび匿名化インフラストラクチャを追跡しており、脅威アクターは遠隔または孤立したネットワーク上にあっても隠れる場所がないことを示しています。 侵入を記録するログは当局のために確保されており、関連する機関からの要請により当社の連絡先ページを通じて入手可能です。これらのログは、責任あるアクターの特定と感染の全範囲の評価を可能にします。究極的には、この事件は、個々のエンドポイントが適切にセキュリティ対策されていな場合に、高プロファイルな政府ネットワークも侵入に脆弱であることが示され、全世界でのトラフィックの再方向付けを通じて機密通信のプライバシーとセキュリティに対して直接的な脅威をもたらしていることを実証しています。

2026/11/05 4:50

昆虫はLEDの光に集まってくるわけではない

## Japanese Translation: 白熱灯からLED照明への切り替えは昆虫の引き寄せを劇的に減少させ、昆虫個体数の減少に対する新たな希望を提供しています。昆虫は月光(紫外線(UV)および赤外線波長を含む太陽光の反射光)を利用して航行しますが、人工的な光で紫外線を透過するものには混乱し、上空に向いた姿勢から円を描く飛行や逆さまになるような行動を示します。白熱灯はこの紫外線豊富な光を放出しますが、LED は電気エネルギーのほとんどを可視光(400–700 nm)に変換するため、コバチやヤブカメムシといった飛翔種に対してははるかに魅力的ではありません。 この移行を支える証拠として、2016 年のブリストル大学の研究では白熱灯、省エネ蛍光灯(CFL)、寒色系LED、暖色系LEDを比較し、LED全体が昆虫を引き寄せる数が著しく少ないこと、かつ寒色系と暖色系のLEDの間には有意差がないことを発見しました。具体的には、ハエ目(Diptera)のコバチやクレンカメムシ属(Culicoides)のヤブカメムシがLEDに引き寄せられる個体数が少ないことが確認されました。実例としては、ガイドのロランド・ルム氏によるWINGS バラクロスの旅行で報告された事例があり、家庭では屋外用ダイニング照明を白熱灯からLED に切り替えた後、トカゲの個体群が消失することに気づいたとあります。これは、爬虫類が昆虫という食物源を失ったためです。 夜間の紫外線豊富な人工光は、昆虫個体数の減少の主要な要因の一つと考えられています。このUV曝露を最小限に抑えることで、野生動物の航行への擾乱を軽減し、昆虫媒介疾患に関連するリスクを低減させ、人間の開発と自然の野生生物循環の安全な共存を促進することができます。(記事掲載日:2026 年 11 月 3 日;写真は 2006 年 7 月に撮影されたガソリンスタンド照明に群がる昆虫の様子)

2026/11/05 3:53

Ripple-65B Preview:米国で開示されたオープンウェイトモデルによるエージェント型コーディングにおける最上位性能

## Japanese Translation: このテキストは、先進的な AI モデルの構築において、段階的にトレーニング手法を最適化する方が、強力で生僻な計算資源に依存する蛮力アプローチよりもはるかに効率的であると論じています。この戦略では、単純な規模化よりも反復的な改良を優先することで、TerminalBench 2.1 でトップティアの性能スコア 80.5 を達成しました。これには「ロールアウト」と呼ばれる試行錯誤のステップがわずか 140 万回しか必要であり、先導的だった前技術(Reflection Beam)が要していたものの約 70 分の 1です。この効率性の源は、高価な外部データの購入を排除し、品質フィルタリングとカバレッジ指標を活用した高品質な内部環境に焦点を当てるカスタム synthetic データパイプラインにあります。 技術的には、このアプローチは堅牢な有教師学習用微調整(SFT)チェックポイントから始まり、高品質な長期間視野を持つ合成環境内において、切り捨て重要性サンプリング、スコア中心化、および線形長罰則を含む混合 RL レシピを採用しています。主要な利点はその適応的な性質であり、モデルが改良につれてトレーニング担当者が自動的により困難なタスクを追加することで進捗を維持しつつ資源の浪費を防ぎます。究極的には、この手法は先進的なモデルのトレーニングにおける財務的および計算機的障壁を大幅に低減させ、巨大量のデータクラスターや過剰な計算力への投資を少なくしてでも優越的な結果を得ることを可能にします。