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")
}