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

大多数记录是带有只读字段和 new 构造函数的 pub struct,构造函数参数顺序与字段顺序一致。标记为 pub(all) 的枚举可由用户构建和匹配。

版本

ProtocolVersion, ArtifactVersion, SchemaVersion

这些枚举为带版本的契约命名:运行协议词汇(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。三个 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 标识用例的一个数据集:它的规模和索引。

pub struct DatasetKey[Scale] {
  scale : Scale
  dataset_id : Int
}
pub fn[Scale] DatasetKey::new(Scale, Int) -> Self[Scale]

运行器把该规模在用例规模列表中的位置用作 dataset_id。

MeasurementKey

MeasurementKey 标识一个被测量的批次:数据集、重复和区组。

pub struct MeasurementKey {
  dataset_id : Int
  repetition_id : Int
  block_id : Int
}
pub fn MeasurementKey::new(Int, Int, Int) -> Self

键相等的两次测量即为成对测量。

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,用 "default" 填充 suite_id,并用夹具的 id 和版本填充生成器 id 和版本。

CaseDescriptor

CaseDescriptor 为验证证据描述一个操作。

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 提供三套完整的协议。

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。

协议枚举

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
}
枚举含义
ExperimentDesign预期的抽样结构:对一个数据集重复测量、对多个数据集各测量一次,或两者兼有
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

该枚举在包外是只读的;请通过这两个函数获取其值。

准备策略

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 分三部分记录一次运行发生的环境。

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 报告两个环境下的计时能否相互比较。

pub fn environment_compatible(EnvironmentSnapshot, EnvironmentSnapshot) -> Bool

当每个语义字段和性能字段都相等时它为真;来源信息被忽略。

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>。只有这三个字段参与其中;在其他方面不同的协议共享同一个键。

artifact_identity

artifact_identity 返回某个协议下某个用例、实现和数据集的产物键。

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 是一次操作产生的结果。

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 是判定器对某一步给出的判定结果。

pub(all) enum ValidationStatus {
  Valid
  Invalid(String)
  Skipped(String)
  ExpectedDifference(String)
  Unsupported(String)
  InfrastructureFailure(String)
}

运行器把 Valid 计为通过,把 Invalid 和 InfrastructureFailure 计为失败,把 Unsupported 和 Skipped 计为不支持,ExpectedDifference 则单独计数。

Validation

Validation 是一个验证事件。

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 包含理解并重放某个已验证步骤所需的一切。

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 是一个计时批次。

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,单位为每次操作的 µ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 记录为某个实现和数据集选定的批次大小。

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)。该枚举在包外是只读的;请用这四个函数构建它。@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 是一个带有两种代价的选择。

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)处处使用同一个选择
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")
}