bench の設計

設計目標

floating における性能に関する主張は再現可能でなければならず、ノイズと混同されてはなりません。bench は Maremark フレームワークを、このリポジトリ専用の小さなツールキットに仕立てます。ベンチマークは正しさのオラクルを備えた不変の仕様であり、各実行はその環境とプロトコルを記録し、計時結果はロバストな対応付き統計で集約され、その不確かさはブートストラップ信頼区間として報告されます。計測(計時、JSONL のストリーミング)はコアごとのテストパッケージと tools/benchmark.py で行われます。このパッケージは実験を記述し、そのデータを集約するだけです。

数学的背景

1 つの観測が計測するもの

Maremark はまず実装とデータセットごとにバッチサイズを較正します。プロトコルの最小反復回数 n0n_0 から始めてバッチを計時し、バッチが目標バッチ時間 TT(Development プリセットで 5 ms、RegressionGate で 10 ms)より短く、かつ反復回数の上限に達していない間、次の値で再試行します

nk+1=min⁡(nmax⁡, max⁡(nk+1, ⌈nkT/tk⌉)),n_{k+1} = \min\Bigl(n_{\max},\ \max\bigl(n_k + 1,\ \lceil n_k T / t_k \rceil\bigr)\Bigr),

ここで tkt_k は計測されたバッチ時間です。1 つの観測は nn 回の呼び出しからなる 1 回の計時バッチであり、呼び出しあたりの平均時間 x=tbatch/nx = t_{\text{batch}} / n をマイクロ秒単位で記録します。バッチ内で平均することでクロックの分解能の影響が除かれます。残るバッチ間の変動は、以下の統計で扱います。

ブロックと対応付け

確認フェーズは mm 個のブロックからなります(Development では m=10m = 10、RegressionGate では 2020)。ブロック jj では各実装が 1 回ずつ、KK 個の実装の巡回順 (j+o) mod K(j + o) \bmod K で計測されます。オフセット oo はシードから導かれるため、連続する KK ブロックにわたって各実装が最初に実行される回数は等しくなります。ベースライン BB と候補 CC について、観測はブロック順に並べられ、対応付けられます:

dj=cj−bj,j=1,…,m.d_j = c_j - b_j, \qquad j = 1, \dots, m .

緩やかなドリフト(周波数スケーリング、熱状態、バックグラウンド負荷)は同じブロックの bjb_j と cjc_j に同様に影響し、djd_j では相殺されます。

点推定

med⁡\operatorname{med} を標本中央値として、

Δ%=100⋅med⁡(d)med⁡(b),speedup=med⁡(b)med⁡(b)+med⁡(d).\Delta_{\%} = 100 \cdot \frac{\operatorname{med}(d)}{\operatorname{med}(b)}, \qquad \text{speedup} = \frac{\operatorname{med}(b)}{\operatorname{med}(b) + \operatorname{med}(d)} .

中央値の破綻点は 50 % です。ブロックの半数までが任意に乱されても(プリエンプトされたバッチ、ページフォールトの嵐など)、推定値が任意に動くことはありません。これが bench の集約における外れ値の扱いであり、観測は一切捨てられません。Maremark のプロトコルは外れ値ポリシーも指定します(Development では ReportOnly、RegressionGate では TukeyFence)。これは記録されるプロトコル識別情報の一部ですが、観測はフィルタされずに出力され、このパッケージの集約もフィルタを適用しません。

判定は Δ%\Delta_{\%} を実用上の閾値 δ\delta と比較します。Δ%≤−δ\Delta_{\%} \le -\delta なら Faster、Δ%≥δ\Delta_{\%} \ge \delta なら Slower、それ以外は Equivalent です。δ\delta より小さい差は、どれほど精密に計測されていても無関係とみなされます。

標本分位数

Maremark は線形補間による分位数(Hyndman と Fan の type 711 R. J. Hyndman, Y. Fan, “Sample quantiles in statistical packages”, The American Statistician 50(4), 1996. )を用います。ソート済みの値 s0≤⋯≤sN−1s_0 \le \dots \le s_{N-1} と f∈[0,1]f \in [0, 1] について、h=f(N−1)h = f (N - 1) として

Q(f)=s⌊h⌋+(h−⌊h⌋)(s⌈h⌉−s⌊h⌋),Q(f) = s_{\lfloor h \rfloor} + \bigl(h - \lfloor h \rfloor\bigr) \bigl(s_{\lceil h \rceil} - s_{\lfloor h \rfloor}\bigr),

したがって Q(1/2)Q(1/2) は通常の中央値です(NN が偶数なら中央の 2 値の平均)。

ブートストラップ信頼区間

med⁡(d)\operatorname{med}(d) の不確かさはパーセンタイル・ブートストラップ22 B. Efron, R. J. Tibshirani, An Introduction to the Bootstrap, Chapman & Hall, 1993, chapter 13. で推定します。r=1,…,Rr = 1, \dots, R について:

  1. {1,…,m}\{1, \dots, m\} から復元抽出で一様に mm 個の添字 i1,…,imi_1, \dots, i_m を引く。
  2. 再標本の中央値 θr∗=med⁡(di1,…,dim)\theta^{*}_r = \operatorname{med}(d_{i_1}, \dots, d_{i_m}) を計算する。

θ(1)∗≤⋯≤θ(R)∗\theta^{*}_{(1)} \le \dots \le \theta^{*}_{(R)} とソートします。信頼水準 cc(パーセント)について α=(100−c)/200\alpha = (100 - c) / 200 とします。区間は

[ L,U ]=[ Q∗(α), Q∗(1−α) ],\bigl[\, L, U \,\bigr] = \bigl[\, Q^{*}(\alpha),\ Q^{*}(1 - \alpha) \,\bigr],

ここで Q∗Q^{*} はソート済みブートストラップ中央値の type 7 分位数です。c=95c = 95、R=10 000R = 10\,000 のとき、これは [Q∗(0.025),Q∗(0.975)][Q^{*}(0.025), Q^{*}(0.975)]、すなわちソート済み再標本の位置 249.975249.975 と 9749.0259749.025(0 始まり)での線形補間です。区間は med⁡(d)\operatorname{med}(d) に対するもので、単位はマイクロ秒です(パーセントではありません)。

乱数の添字は、呼び出し側のシードで初期化された xorshift64* 生成器33 S. Vigna, “An experimental exploration of Marsaglia’s xorshift generators, scrambled”, ACM TOMS 42(4), 2016. から得られ(シードが 0 の場合は固定の定数に置き換えられます)、添字は状態を mm で割った余りです。剰余によるバイアスは高々 m/264m / 2^{64} です。シードを固定すれば区間はデータの決定的な関数となるため、解析を再実行すると正確に再現されます。

リグレッションの判定

is_significant_regression は次の両方を要求します

Δ%≥δandL>0:\Delta_{\%} \ge \delta \quad\text{and}\quad L > 0 :

中央値での速度低下が実用上意味のある大きさであり、かつ、中央値の対応差の 95 % 区間が低速側でゼロを含まないこと。第 1 の条件は、小さいが精密に計測された変化を検出してしまうことを防ぎ、第 2 の条件は、大きいがノイズの多い変化を検出してしまうことを防ぎます。

設計上の判断

平均ではなく対応付き中央値

計時の分布は右に裾が長く、ときどき大きな外れ値を含みます。差の平均と tt 区間はそうした外れ値に支配されてしまいます。ブロックで対応付けた差の中央値はロバストで正規性の仮定を必要とせず、ブートストラップは中央値の分散公式なしにその区間を与えます。

用途ごとに固定されたパラメータ

confirmatory_regression は δ=3 %\delta = 3\,\%、R=10 000R = 10\,000、c=95 %c = 95\,\% に固定されているため、呼び出し側がリグレッションゲートを弱めることはできません。paired_hotspot は δ\delta とシードを呼び出し側から受け取り、探索的なホットスポットレポート用に R=2000R = 2000 を用います。信頼水準は 0.95 として渡されますが、Maremark はこの値をパーセントとして解釈するため、報告される区間はブートストラップ分布の中央 0.95 % であり、ほぼブートストラップ中央値の一点になります。スイートはそこから Δ%\Delta_{\%} のみを表示するので、影響はありません。

最小中央値による自動チューニング

tune_dataset は各候補を、有効な確認サンプルの中央値で評価し、中央値が最小のものを返します。完全な同点は候補 id で決着します。スコアは主基準と副基準の両方として @tune.select_best に渡されるため、最速から δ\delta 以内の候補のうち副基準が最小のもの、つまりやはり最速のものが選ばれます。したがって実用上の閾値は選択に影響しません。スケールをまたいだ 2 候補間の交差点は、データセットごとのラベルから Maremark が計算します。

オラクル付きの不変フィクスチャ

immutable_bench は各入力をスケールごとに一度だけ生成し、すべての出力を独立した参照値と照合します。誤った結果を計算する高速な実装は、比較に勝つのではなく実行を失敗させます。

データとしての環境

environment は各実行についてターゲット、プロファイル、データ型ラベルを記録し、外側のツールだけが知る情報(マシン、周波数ポリシー、コミット)を external-metadata として示します。これにより 2 つの成果物を読む人は、その数値が比較可能かどうかを判断できます。パッケージ自体は環境をまたいだ実行の比較は行いません。

正しさ/不変条件

  • 集約の決定性。 観測とシードを固定すれば、paired_hotspot、confirmatory_regression、tune_dataset はどの実行でも同じ値を返します(ブロック id によるソート、シード付き生成器、決定的なタイブレーク)。
  • 対応付け。 サンプルはブロック順に対応付けられます。サンプル数が異なる場合はエラー(MismatchedPairs)であり、黙って切り詰めることはありません。
  • 区間の順序。 Q∗Q^{*} は引数について単調であり、c>0c > 0 に対して α<1−α\alpha < 1 - \alpha であるため、L≤UL \le U が成り立ちます。
  • スケール不変性。 すべてのサンプルに定数 λ>0\lambda > 0 を掛けると med⁡(d)\operatorname{med}(d)、LL、UU は λ\lambda 倍になり、Δ%\Delta_{\%}、判定、評決は変わりません。したがって時間の単位は問題になりません。

却下した代替案

  • 平均化の前に外れ値を捨てる。 どんなフェンスも調整定数を必要とし、サンプルを暗黙に変えてしまいます。中央値を使えばそれは不要です。
  • 2 つのサンプル集合の非対応比較。 BB と CC の計測の間のドリフトが、差にそのまま入り込みます。
  • 正規理論に基づく区間。 計時データにはない対称な誤差を仮定しています。

境界

  • 計時、プロセス制御、ファイル出力は行いません。それらは Maremark のランナーと tools/benchmark.py が担います。
  • 絶対的な性能目標は設けません。閾値は相対的な差に適用されます。
  • 性能の結果が正しさに関する主張を変えることはなく、ベンチマークは native ターゲットでのみ実行されます。

Footnotes

  1. R. J. Hyndman, Y. Fan, “Sample quantiles in statistical packages”, The American Statistician 50(4), 1996. ↩

  2. B. Efron, R. J. Tibshirani, An Introduction to the Bootstrap, Chapman & Hall, 1993, chapter 13. ↩

  3. S. Vigna, “An experimental exploration of Marsaglia’s xorshift generators, scrambled”, ACM TOMS 42(4), 2016. ↩