model API
Luna-Flow/mare_mark/model は mare_mark の共通語彙です。バージョン識別子、データセットと計測のキー、実行プロトコル、環境スナップショット、実行結果、検証の証拠、ランナーが出力するイベントレコード、そして実験とチューニングで使われる判断の型を含みます。依存関係はなく、小さなアクセサと識別情報以外の振る舞いは持ちません。各構造の理由は model の設計にあります。
ソース: src/model/model.mbt、src/model/versioning.mbt。
import {
"Luna-Flow/mare_mark/model",
"Luna-Flow/mare_mark/runner",
}
ほとんどのレコードは読み取り専用フィールドを持つ pub struct で、引数がフィールドの順序に従う new コンストラクタを持ちます。pub(all) と付いた enum は、ユーザーが構築およびパターンマッチできます。
バージョン
ProtocolVersion, ArtifactVersion, SchemaVersion
これらの enum はバージョン付きの契約を命名します。実行プロトコルの語彙(mmkp)、JSONL アーティファクト(mmka)、Plot IR スキーマ(mmks)です。
pub(all) enum ProtocolVersion {
V1
}
pub fn ProtocolVersion::identifier(Self) -> String
pub fn ProtocolVersion::implementation(Self) -> String
pub fn ProtocolVersion::lifecycle(Self) -> VersionLifecycle
pub fn ProtocolVersion::version(Self) -> Int
pub(all) enum ArtifactVersion {
V1
}
pub fn ArtifactVersion::identifier(Self) -> String
pub fn ArtifactVersion::implementation(Self) -> String
pub fn ArtifactVersion::lifecycle(Self) -> VersionLifecycle
pub fn ArtifactVersion::version(Self) -> Int
pub(all) enum SchemaVersion {
V1
}
pub fn SchemaVersion::identifier(Self) -> String
pub fn SchemaVersion::implementation(Self) -> String
pub fn SchemaVersion::lifecycle(Self) -> VersionLifecycle
pub fn SchemaVersion::version(Self) -> Int
implementation は接頭辞、version は番号で、identifier は implementation + "_" + version です。3 つの V1 値はすべて Supported です。
test "version identifiers" {
inspect(@model.ProtocolVersion::V1.identifier(), content="mmkp_1")
inspect(@model.ArtifactVersion::V1.identifier(), content="mmka_1")
inspect(@model.SchemaVersion::V1.identifier(), content="mmks_1")
inspect(@model.SchemaVersion::V1.lifecycle() is Supported, content="true")
}
VersionLifecycle
VersionLifecycle はバージョンがまだ受け付けられるかどうかを示します。
pub(all) enum VersionLifecycle {
Supported
Deprecated
}
データセットとキー
DatasetKey
DatasetKey はケースの 1 つのデータセットを、そのスケールとインデックスで識別します。
pub struct DatasetKey[Scale] {
scale : Scale
dataset_id : Int
}
pub fn[Scale] DatasetKey::new(Scale, Int) -> Self[Scale]
ランナーは、ケースのスケールリストにおけるそのスケールの位置を dataset_id として使います。
MeasurementKey
MeasurementKey は計測された 1 つのバッチを、データセット、反復、ブロックで識別します。
pub struct MeasurementKey {
dataset_id : Int
repetition_id : Int
block_id : Int
}
pub fn MeasurementKey::new(Int, Int, Int) -> Self
キーが等しい 2 つの計測は対応のある計測です。
GenerationContext
GenerationContext は入力ジェネレータが依存してよいもののすべてです。
pub struct GenerationContext[Scale] {
seed : UInt64
suite_id : String
case_id : String
dataset_key : DatasetKey[Scale]
generator_id : String
generator_version : String
}
pub fn[Scale] GenerationContext::new(UInt64, String, String, DatasetKey[Scale], String, String) -> Self[Scale]
これらのフィールドだけを読むジェネレータは再現可能です。ランナーは seed に実行シードを、suite_id に "default" を、ジェネレータ ID とバージョンにフィクスチャの ID とバージョンを設定します。
CaseDescriptor
CaseDescriptor は検証の証拠のために 1 つの操作を記述します。
pub struct CaseDescriptor {
operation : String
operands : Array[String]
context : String
rounding : String
}
pub fn CaseDescriptor::new(String, Array[String], String, String) -> Self
実行プロトコル
RunProtocol
RunProtocol は実行の完全な計測プロトコルです。
pub struct RunProtocol {
experiment_design : ExperimentDesign
warmup_iterations : Int
warmup_time_us : Double?
calibration : CalibrationProtocol
practical_delta_pct : Double
order_policy : OrderPolicy
outlier_policy : OutlierPolicy
validation_coverage : ValidationCoverage
exploratory_samples : Int
confirmatory_samples : Int
}
pub fn RunProtocol::new(ExperimentDesign, Int, Double?, CalibrationProtocol, Double, OrderPolicy, OutlierPolicy, ValidationCoverage, Int, Int) -> Self
ランナーはウォームアップ、キャリブレーション、順序、サンプル数のフィールドに基づいて動作します。その他のフィールドは意図した分析を記録するものです。@runner.validate_protocol が値を検査し、@runner.ProtocolPreset が 3 つの完全なプロトコルを提供します。
CalibrationProtocol
CalibrationProtocol は、計時されるバッチに含まれる反復回数を制御します。
pub struct CalibrationProtocol {
target_batch_time_us : Double
min_batch_iterations : Int
max_batch_iterations : Int
max_sample_time_us : Double
batch_policy : BatchPolicy
}
pub fn CalibrationProtocol::new(Double, Int, Int, Double, BatchPolicy) -> Self
キャリブレーションは、バッチを min_batch_iterations から大きくしていき、target_batch_time_us に達するか、max_batch_iterations に達するか、max_sample_time_us を超えるまで続けます。
プロトコルの enum
pub(all) enum ExperimentDesign {
FixedDatasetRepeatedMeasurements
MultipleDatasetsSingleMeasurement
HierarchicalDatasetsAndRepeats
}
pub(all) enum BatchPolicy {
PerImplementation
SharedBatchSize
}
pub(all) enum OrderPolicy {
BalancedBlocks(UInt64)
FixedOrder
}
pub(all) enum OutlierPolicy {
ReportOnly
TukeyFence
MADTrim
}
pub(all) enum ValidationCoverage {
EveryMeasurement
EveryDataset
ConfirmatoryOnly
}
| enum | 意味 |
|---|---|
ExperimentDesign | 意図したサンプリング構造: 1 つのデータセットの繰り返し計測、多数のデータセットの 1 回ずつの計測、またはその両方 |
BatchPolicy | 各実装を個別にキャリブレーションするか、すべての実装にキャリブレーションされた最小のサイズを与えるか |
OrderPolicy | ブロックごとにシードを使って実装の順序をローテーションするか、宣言された順序を保つか |
OutlierPolicy | 分析用の外れ値の扱い: なし、Tukey のフェンス、または中央値の周り 3 MAD(@stats.filter_outliers を参照) |
ValidationCoverage | 意図した検証の頻度 |
IntervalMode, confirmatory_interval, exploratory_interval
IntervalMode は区間に、そのデータを生成したフェーズのラベルを付けます。
pub enum IntervalMode {
ExploratoryInterval
ConfirmatoryInterval
}
pub fn confirmatory_interval() -> IntervalMode
pub fn exploratory_interval() -> IntervalMode
この enum はパッケージ外からは読み取り専用です。値は 2 つの関数から取得してください。
セットアップポリシー
SetupPolicy は、フィクスチャが入力を準備する頻度と、その作業を計時するかどうかをランナーに伝えます。
pub struct SetupPolicy {
frequency : SetupFrequency
timing : SetupTiming
workspace_scope : WorkspaceScope
}
pub fn SetupPolicy::new(SetupFrequency, SetupTiming, WorkspaceScope) -> Self
pub(all) enum SetupFrequency {
PerRun
PerDataset
PerImplementation
PerSample
PerBatch
PerIteration
}
pub(all) enum SetupTiming {
ExcludedFromMeasurement
IncludedInMeasurement
}
pub(all) enum WorkspaceScope {
RunWorkspace
DatasetWorkspace
ImplementationWorkspace
SampleWorkspace
BatchWorkspace
OperationWorkspace
}
frequency と timing はランナーが計時する対象を変えます(正確な表は runner の設計にあります)。workspace_scope はワークスペースの存続期間を記述するだけで、解釈はされません。
環境
EnvironmentSnapshot
EnvironmentSnapshot は実行が行われた場所を 3 つの部分で記録します。
pub struct EnvironmentSnapshot {
semantic : SemanticEnvironment
performance : PerformanceEnvironment
provenance : ProvenanceEnvironment
}
pub fn EnvironmentSnapshot::new(SemanticEnvironment, PerformanceEnvironment, ProvenanceEnvironment) -> Self
SemanticEnvironment
SemanticEnvironment は、計時だけでなく結果そのものを変えうるものを保持します。
pub struct SemanticEnvironment {
target : ExecutionTarget
toolchain : String
compiler_flags : String
dtype_abi : String
}
pub fn SemanticEnvironment::new(ExecutionTarget, String, String, String) -> Self
PerformanceEnvironment
PerformanceEnvironment は計時を変えるものを保持します。
pub struct PerformanceEnvironment {
runtime : String
cpu : String
gc : String
concurrency : Int
clock : String
device : String
frequency_policy : String
}
pub fn PerformanceEnvironment::new(String, String, String, Int, String, device? : String, frequency_policy? : String) -> Self
device の既定値は "host"、frequency_policy の既定値は "uncontrolled" です。
ProvenanceEnvironment
ProvenanceEnvironment は実行がどこでいつ行われたかを保持します。
pub struct ProvenanceEnvironment {
os : String
hostname : String
timestamp : String
revision : String
run_id : String
}
pub fn ProvenanceEnvironment::new(String, String, String, String, String) -> Self
ExecutionTarget
ExecutionTarget は MoonBit のバックエンドを表します。
pub(all) enum ExecutionTarget {
Native
Js
Wasm
WasmGc
Llvm
Custom(String)
}
pub fn ExecutionTarget::text(Self) -> String
text は "native"、"js"、"wasm"、"wasm-gc"、"llvm"、またはカスタム文字列を返します。
environment_compatible
environment_compatible は、2 つの環境の計時結果を比較してよいかどうかを報告します。
pub fn environment_compatible(EnvironmentSnapshot, EnvironmentSnapshot) -> Bool
semantic と performance のすべてのフィールドが等しいとき真になります。provenance は無視されます。
test "provenance does not matter, the CPU does" {
let semantic = @model.SemanticEnvironment::new(@model.ExecutionTarget::Native, "moonc", "", "f64")
let cpu_a = @model.PerformanceEnvironment::new("native", "cpu-a", "default", 1, "monotonic")
let cpu_b = @model.PerformanceEnvironment::new("native", "cpu-b", "default", 1, "monotonic")
let monday = @model.ProvenanceEnvironment::new("linux", "ci-1", "monday", "abc", "run-1")
let tuesday = @model.ProvenanceEnvironment::new("linux", "ci-2", "tuesday", "def", "run-2")
let a1 = @model.EnvironmentSnapshot::new(semantic, cpu_a, monday)
let a2 = @model.EnvironmentSnapshot::new(semantic, cpu_a, tuesday)
let b = @model.EnvironmentSnapshot::new(semantic, cpu_b, monday)
inspect(@model.environment_compatible(a1, a2), content="true")
inspect(@model.environment_compatible(a1, b), content="false")
}
識別子
protocol_identity
protocol_identity はプロトコルの短いキーを返します。
pub fn protocol_identity(RunProtocol) -> String
キーは mmkp_1:<warmup_iterations>:<confirmatory_samples>:<practical_delta_pct> です。キーに含まれるのはこの 3 つのフィールドだけなので、他の点で異なるプロトコルは同じキーを共有します。
artifact_identity
artifact_identity は、あるプロトコルの下での 1 つのケース、実装、データセットのアーティファクトのキーを返します。
pub fn artifact_identity(String, String, Int, RunProtocol) -> String
キーは mmka_1:<case>:<implementation>:<dataset_id>: の後にプロトコルの識別子が続いたものです。
test "identities" {
let protocol = @runner.ProtocolPreset::Development.validated().protocol
inspect(@model.protocol_identity(protocol), content="mmkp_1:3:10:1")
inspect(@model.artifact_identity("sum", "loop", 2, protocol), content="mmka_1:sum:loop:2:mmkp_1:3:10:1")
}
結果
ExecutionOutcome
ExecutionOutcome は 1 つの操作が生成したものです。
pub(all) enum ExecutionOutcome[Value] {
Value(Value)
Unsupported(String)
ParseFailure(String)
RaisedFlags(Value, Array[String])
Trapped(String, Array[String])
Aborted(Int, String)
Timeout(Int, String)
ExpectedDifference(String)
}
pub fn[Value] ExecutionOutcome::value(Value) -> Self[Value]
pub fn[Value] ExecutionOutcome::raised_flags(Value, Array[String]) -> Self[Value]
pub fn[Value] ExecutionOutcome::kind(Self[Value]) -> String
pub fn[Value] ExecutionOutcome::flags(Self[Value]) -> Array[String]
pub fn[Value] ExecutionOutcome::value_option(Self[Value]) -> Value?
| コンストラクタ | 意味 | kind |
|---|---|---|
Value(v) | 結果の値 | value |
RaisedFlags(v, flags) | ステータスフラグ(例えば IEEE 例外)付きの結果 | raised_flags |
Trapped(trap, flags) | 操作がトラップした | trapped |
Unsupported(reason) | 実装がこの入力をサポートしていない | unsupported |
ExpectedDifference(reason) | 文書化され、受け入れられた差異 | expected_difference |
ParseFailure(reason) | 結果をデコードできなかった | parse_failure |
Aborted(exit_code, stderr) | ワーカープロセスが失敗した | aborted |
Timeout(ms, reason) | ワーカーがタイムアウトを超えた | timeout |
value_option は Value と RaisedFlags の値を返し、それ以外では None を返します。flags は RaisedFlags と Trapped のフラグを返し、それ以外では [] を返します。
test "outcomes" {
let flagged = @model.ExecutionOutcome::raised_flags(1.0, ["inexact"])
inspect(flagged.kind(), content="raised_flags")
debug_inspect(flagged.value_option(), content="Some(1)")
let timeout : @model.ExecutionOutcome[Double] = Timeout(100, "slow")
inspect(timeout.value_option() is None, content="true")
}
OperationResult
OperationResult は、結果と、次の操作のためのコンテキスト、およびキャプチャしたプロセス出力の組です。
pub struct OperationResult[Value, Context] {
outcome : ExecutionOutcome[Value]
next_context : Context?
stdout : String
stderr : String
exit_code : Int?
}
pub fn[Value, Context] OperationResult::new(ExecutionOutcome[Value], Context?, stdout? : String, stderr? : String, exit_code? : Int) -> Self[Value, Context]
pub fn[Value, Context] OperationResult::completed(Value, Context) -> Self[Value, Context]
completed(v, c) は new(Value(v), Some(c)) です。next_context = None で系列が終わります。stdout と stderr の既定値は "" です。
検証
ValidationStatus
ValidationStatus は 1 つのステップに対するオラクルの判定です。
pub(all) enum ValidationStatus {
Valid
Invalid(String)
Skipped(String)
ExpectedDifference(String)
Unsupported(String)
InfrastructureFailure(String)
}
ランナーは Valid を合格、Invalid と InfrastructureFailure を失敗、Unsupported と Skipped を未サポートとして数え、ExpectedDifference は別に数えます。
Validation
Validation は 1 つの検証イベントです。
pub struct Validation {
status : ValidationStatus
oracle_id : String
implementation_id : String
scale_text : String
evidence : ValidationEvidence?
}
pub fn Validation::new(ValidationStatus, String, String, String) -> Self
pub fn Validation::detailed(ValidationStatus, String, String, String, ValidationEvidence) -> Self
new は evidence を空のままにし、detailed はそれを付加します。
ValidationEvidence
ValidationEvidence は、検証された 1 つのステップを理解しリプレイするために必要なすべてです。
pub(all) struct ValidationEvidence {
case_id : String
dataset_id : Int
step_id : Int
operation : String
operands : Array[String]
context : String
rounding : String
expected : String
actual : String
expected_kind : String
actual_kind : String
expected_flags : Array[String]
actual_flags : Array[String]
trap : String
stderr : String
exit_code : Int?
fingerprint : String
implementation_version : String
replay : ReplaySpec
}
これは pub(all) なので、構造体リテラルで構築してください。
ValidationFailure
ValidationFailure は、最小化された入力を伴う失敗した検証です。
pub struct ValidationFailure {
validation : Validation
seed : UInt64
scale_text : String
original_fingerprint : String
minimal_fingerprint : String
shrink_path : Array[String]
minimal_input : String
}
pub fn ValidationFailure::new(Validation, UInt64, String, String, String, Array[String], String) -> Self
ReplaySpec
ReplaySpec は失敗を再現するコマンドです。
pub struct ReplaySpec {
command : String
arguments : Array[String]
timeout_ms : Int
}
pub fn ReplaySpec::new(String, Array[String], timeout_ms? : Int) -> Self
timeout_ms の既定値は 5000 です。mare-mark replay がこれを実行します。
実行イベント
Observation
Observation は計時された 1 つのバッチです。
pub struct Observation {
case_id : String
implementation_id : String
implementation_version : String
dataset_id : Int
repetition_id : Int
block_id : Int
phase : ObservationPhase
raw_elapsed_us : Double
iterations : Int
batch_sink : BatchSinkStatus
setup_timing : SetupTiming
valid : Bool
}
pub fn Observation::new(String, String, String, Int, Int, Int, ObservationPhase, Double, Int, BatchSinkStatus, SetupTiming, Bool) -> Self
raw_elapsed_us はバッチの時間を iterations で割ったもので、単位は 1 操作あたりの µs です。フィルタリングやバッチをまたいだ集約はされていません。repetition_id はフェーズ内のブロックを数え、block_id は両方のフェーズを通してブロックを数えます。
ObservationPhase
pub(all) enum ObservationPhase {
Exploratory
Confirmatory
}
pub fn ObservationPhase::text(Self) -> String
text は "exploratory" または "confirmatory" を返します。
BatchSinkStatus
BatchSinkStatus はバッチが分析用に保持されるかどうかを記録します。
pub(all) enum BatchSinkStatus {
Kept
Discarded(String)
}
pub fn BatchSinkStatus::text(Self) -> String
text は "kept" または "discarded:<reason>" を返します。ランナーは Kept を出力し、レポートは破棄されたバッチを読み飛ばします。
CalibrationEvent
CalibrationEvent は 1 つの実装とデータセットに対して選ばれたバッチサイズを記録します。
pub struct CalibrationEvent {
implementation_id : String
dataset_id : Int
batch_iterations : Int
elapsed_us : Double
target_elapsed_us : Double
retries : Int
}
pub fn CalibrationEvent::new(String, Int, Int, Double, Double, Int) -> Self
elapsed_us は最後のキャリブレーションバッチの時間です。
RunSummary
RunSummary は実行を締めくくります。
pub struct RunSummary {
run_id : String
observation_count : Int
validation_count : Int
calibration_count : Int
complete : Bool
artifact_location : String?
passed_count : Int
failed_count : Int
unsupported_count : Int
expected_difference_count : Int
environment : EnvironmentSnapshot?
}
pub fn RunSummary::new(String, Int, Int, Int, Bool, String?, passed_count? : Int, failed_count? : Int, unsupported_count? : Int, expected_difference_count? : Int, environment? : EnvironmentSnapshot) -> Self
件数の既定値は 0、environment の既定値は None です。
判断とデプロイ
ScaleBoundary
ScaleBoundary は優位な実装が切り替わる位置です。
pub struct ScaleBoundary[Scale] {
below : Scale
at_or_above : Scale
}
pub fn[Scale] ScaleBoundary::new(Scale, Scale) -> Self[Scale]
CrossoverResult
CrossoverResult はスケールにわたるクロスオーバー探索の結果です。
pub enum CrossoverResult[Scale] {
Found(ScaleBoundary[Scale], String, Array[String])
NoCrossover(String, Array[String])
NonMonotonic(Array[String])
Inconclusive(String, Array[String])
}
pub fn[Scale] CrossoverResult::found(ScaleBoundary[Scale], String, Array[String]) -> Self[Scale]
pub fn[Scale] CrossoverResult::no_crossover(String, Array[String]) -> Self[Scale]
pub fn[Scale] CrossoverResult::non_monotonic(Array[String]) -> Self[Scale]
pub fn[Scale] CrossoverResult::inconclusive(String, Array[String]) -> Self[Scale]
文字列はポリシーまたは理由で、配列は証拠(結果の根拠となるラベルや ID)です。この enum はパッケージ外からは読み取り専用なので、4 つの関数で構築してください。@experiment.crossover_from_labels がこれを生成します。
Region
Region はキーの範囲に選択を割り当てます。
pub struct Region[Key, Choice] {
lower : Key?
upper : Key?
choice : Choice
evidence_ids : Array[String]
}
pub fn[Key, Choice] Region::new(Key?, Key?, Choice, Array[String]) -> Self[Key, Choice]
None の境界は開いています。
ParetoPoint
ParetoPoint は 2 つのコストを持つ選択です。
pub struct ParetoPoint[Key, Choice] {
key : Key
choice : Choice
primary : Double
secondary : Double
}
pub fn[Key, Choice] ParetoPoint::new(Key, Choice, Double, Double) -> Self[Key, Choice]
DeploymentPolicy
DeploymentPolicy は、チューニングやクロスオーバーの結果を本番環境でどう使うかを表します。
pub(all) enum DeploymentPolicy[Key, Choice] {
Global(Choice)
Piecewise(Array[Region[Key, Choice]])
Lookup(Array[(Key, Choice)])
Pareto(Array[ParetoPoint[Key, Choice]])
Fallback(Choice, String)
}
| コンストラクタ | 用途 |
|---|---|
Global(c) | どこでも 1 つの選択 |
Piecewise(regions) | キーの範囲ごとの選択。例えばクロスオーバーの下と上 |
Lookup(pairs) | 計測されたキーごとの選択 |
Pareto(points) | 支配されないトレードオフ。選択は呼び出し側に任せます |
Fallback(c, reason) | 証拠が不十分な場合の安全な既定値 |
test "a piecewise policy from a crossover" {
let boundary = @model.ScaleBoundary::new(256, 512)
let policy : @model.DeploymentPolicy[Int, String] = Piecewise([
@model.Region::new(None, Some(boundary.below), "insertion", ["run-1"]),
@model.Region::new(Some(boundary.at_or_above), None, "merge", ["run-1"]),
])
guard policy is Piecewise(regions) else { fail("expected regions") }
inspect(regions[1].choice, content="merge")
}