fixture API

Luna-Flow/mare_mark/fixture 描述基准测试输入的生命周期:它如何为某个数据集生成、计算指纹、复制、为某个实现做准备并在之后重置,以及这些工作是否计时。运行器调用这些函数;fixture 设计解释了该生命周期。

源码:src/fixture/fixture.mbt。

import {
  "Luna-Flow/mare_mark/model",
  "Luna-Flow/mare_mark/fixture",
}

夹具

Fixture

Fixture 是一类输入的生命周期。

pub struct Fixture[Scale, Input, Prepared] {
  id : String
  version : String
  materialize : (@model.GenerationContext[Scale]) -> Input
  fingerprint : (Input) -> String
  clone_input : (Input) -> Input
  prepare : (Input, String, SampleContext) -> Prepared
  reset : (Prepared, ResetContext) -> Unit
  setup_policy : @model.SetupPolicy
}
字段调用时机用途
materialize每个数据集一次由上下文生成输入
fingerprint每个数据集一次,以及对最小化后的输入在事件中标识该输入
clone_input每次 prepare 之前防止物化后的输入被修改
prepare按准备策略把副本转化为实现实际运行所用的值;接收实现 id
reset准备好的值使用之后释放或恢复它
setup_policyprepare 的运行频率以及是否计时

Fixture::new

Fixture::new 由夹具的全部组成部分构建夹具。

pub fn[Scale, Input, Prepared] Fixture::new(String, String, (@model.GenerationContext[Scale]) -> Input, (Input) -> String, (Input) -> Input, (Input, String, SampleContext) -> Prepared, (Prepared, ResetContext) -> Unit, @model.SetupPolicy) -> Self[Scale, Input, Prepared]

参数顺序与字段顺序一致。

test "a fixture with a workspace" {
  let resets = Ref(0)
  let fixture : @fixture.Fixture[Int, Array[Double], (Array[Double], Array[Double])] = @fixture.Fixture::new(
    "vector",
    "1",
    context => Array::make(context.dataset_key.scale, 1.0),
    xs => "len=" + xs.length().to_string(),
    xs => xs.copy(),
    (xs, _, _) => (xs, Array::make(xs.length(), 0.0)),
    (_, _) => resets.val += 1,
    @model.SetupPolicy::new(
      @model.SetupFrequency::PerBatch,
      @model.SetupTiming::ExcludedFromMeasurement,
      @model.WorkspaceScope::BatchWorkspace,
    ),
  )
  let context = @model.GenerationContext::new(1UL, "s", "axpy", @model.DatasetKey::new(3, 0), fixture.id, fixture.version)
  let input = @fixture.materialize(fixture, context)
  let (x, workspace) = @fixture.prepare(fixture, input, "axpy", @fixture.SampleContext::new(0, "axpy", 0))
  (fixture.reset)((x, workspace), @fixture.ResetContext::new(0, "axpy"))
  inspect(workspace.length(), content="3")
  inspect(resets.val, content="1")
}

Fixture::immutable

Fixture::immutable 为永不修改的输入构建夹具。

pub fn[Scale, Input] Fixture::immutable(String, String, (@model.GenerationContext[Scale]) -> Input, (Input) -> String) -> Self[Scale, Input, Input]

clone_input 和 prepare 原样返回其参数,reset 什么也不做,准备策略为 PerDataset、ExcludedFromMeasurement、DatasetWorkspace。

test "an immutable fixture" {
  let fixture = @fixture.Fixture::immutable("numbers", "1", context => context.dataset_key.scale * 10, (n : Int) => n.to_string())
  inspect(fixture.setup_policy.frequency is PerDataset, content="true")
  let context = @model.GenerationContext::new(0UL, "s", "c", @model.DatasetKey::new(4, 0), "numbers", "1")
  inspect(@fixture.materialize(fixture, context), content="40")
}

materialize

materialize 调用夹具的 materialize 函数。

pub fn[Scale, Input, Prepared] materialize(Fixture[Scale, Input, Prepared], @model.GenerationContext[Scale]) -> Input

prepare

prepare 调用夹具的 prepare 函数。

pub fn[Scale, Input, Prepared] prepare(Fixture[Scale, Input, Prepared], Input, String, SampleContext) -> Prepared

它不会调用 clone_input;运行器在准备之前进行克隆。

上下文

SampleContext

SampleContext 告诉 prepare 它在为哪个样本和哪个实现做准备。

pub struct SampleContext {
  sample_id : Int
  implementation_id : String
  repetition_id : Int
}
pub fn SampleContext::new(Int, String, Int) -> Self

运行器把同一个值同时作为 sample_id 和 repetition_id 传入;负的 id 标记验证、预热、校准和探索性批次(参见 runner 设计)。

ResetContext

ResetContext 告诉 reset 它在重置哪个样本和哪个实现。

pub struct ResetContext {
  sample_id : Int
  implementation_id : String
}
pub fn ResetContext::new(Int, String) -> Self