model のチュートリアル
このチュートリアルでは、共通の型を使ってベンチマークの実行を記述する方法を示します。実行間で比較できる環境スナップショット、記録できるプロトコル、操作が値を持たない理由を示す結果、そして結果から導かれるデプロイポリシーです。どの例も完全なテストです。
クイックスタート
moon add Luna-Flow/mare_mark@0.3.0
import {
"Luna-Flow/mare_mark/model",
}
マシンを記述し、2 つの実行を比較してよいかどうかを検査します:
test "describe two runs" {
let semantic = @model.SemanticEnvironment::new(@model.ExecutionTarget::Native, "moonc 0.10.14", "release", "f64")
let performance = @model.PerformanceEnvironment::new(
"native", "AMD EPYC 7763", "default", 1, "monotonic", frequency_policy="performance",
)
let first = @model.EnvironmentSnapshot::new(
semantic, performance,
@model.ProvenanceEnvironment::new("linux", "ci-7", "2026-10-08T08:00:00Z", "a1b2c3", "nightly-101"),
)
let second = @model.EnvironmentSnapshot::new(
semantic, performance,
@model.ProvenanceEnvironment::new("linux", "ci-3", "2026-10-09T08:00:00Z", "d4e5f6", "nightly-102"),
)
inspect(@model.environment_compatible(first, second), content="true")
}
ホスト、日付、リビジョンの違いは問題になりません。問題になるのは宣言されたハードウェア、ツールチェーン、フラグです。
日常的な作業
結果とともにプロトコルを記録する
test "a protocol and its identity" {
let protocol = @model.RunProtocol::new(
@model.ExperimentDesign::FixedDatasetRepeatedMeasurements,
3,
Some(5000.0),
@model.CalibrationProtocol::new(5000.0, 1, 10000, 250000.0, @model.BatchPolicy::PerImplementation),
1.0,
@model.OrderPolicy::BalancedBlocks(1UL),
@model.OutlierPolicy::ReportOnly,
@model.ValidationCoverage::EveryDataset,
3,
10,
)
inspect(@model.protocol_identity(protocol), content="mmkp_1:3:10:1")
}
識別子は短いキャッシュキーです。プロトコル全体も保存してください。キーが含むのはウォームアップ回数、確認サンプル数、閾値だけです。
正確な結果を返す
入力を扱えない実装は、偽の値を返す代わりにその旨を伝えます:
fn checked_sqrt(x : Double) -> @model.OperationResult[Double, Unit] {
if x < 0.0 {
@model.OperationResult::new(Unsupported("negative input"), Some(()))
} else {
@model.OperationResult::completed(x.sqrt(), ())
}
}
test "unsupported is not wrong" {
let result = checked_sqrt(-4.0)
inspect(result.outcome.kind(), content="unsupported")
inspect(result.outcome.value_option() is None, content="true")
inspect(checked_sqrt(9.0).outcome.value_option() == Some(3.0), content="true")
}
ランナーは Unsupported を失敗とは別に数え、レポートはそれをケイパビリティ行列に記載します。
クロスオーバーをデプロイポリシーに変える
test "piecewise deployment" {
let crossover : @model.CrossoverResult[Int] = @model.CrossoverResult::found(
@model.ScaleBoundary::new(64, 128), "piecewise-confirmed", ["A", "A", "B"],
)
guard crossover is Found(boundary, _, evidence) else { fail("no crossover") }
let policy : @model.DeploymentPolicy[Int, String] = Piecewise([
@model.Region::new(None, Some(boundary.below), "scalar", evidence),
@model.Region::new(Some(boundary.at_or_above), None, "blocked", evidence),
])
guard policy is Piecewise(regions) else { fail("not piecewise") }
inspect(regions.length(), content="2")
}
さらに先へ
- 独自のシンクをテストするには、
Observation、Validation、RunSummaryの値を手で構築します。event のチュートリアルでそうしています。 - 文書化された差異(例えば設計上異なる丸めを行うライブラリ)には
ExpectedDifferenceを使ってください。そうすれば隠されるのではなく数えられます。 - 外部の JSONL を読む前に
ArtifactVersion::V1.identifier()を確認してください。
よくある落とし穴
- 環境を曖昧に記述する。
"cpu"は他のどの"cpu"とも一致してしまいます。モデルと周波数ポリシーを書いてください。 - 実行 ID を
RunSummaryにだけ入れる。 ランナーのrun_idは一意ではありません。ProvenanceEnvironment.run_idを使ってください。 - ランナーがすべてのプロトコルのフィールドに基づいて動作すると期待する。
experiment_design、outlier_policy、validation_coverageには基づいて動作しません。
次のステップ
- model API と model の設計。
- これらの型を実行で使うには runner のチュートリアル。