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