plan 教程

本教程展示如何把数据并行操作描述为 Plan,按 v1 子集检查它,以及在计划被拒绝时阅读原因。计划是普通数据,因此这个包可以在所有目标上使用。

快速开始

导入该包,以及用于策略的 shared:

import {
  "Luna-Flow/luna_thread/plan",
  "Luna-Flow/luna_thread/shared",
}

构建一个作用于八个 Int 值的映射计划并验证它:

test "plan quick start" {
  let plan = @plan.map("double", @plan.i32_type(), 8)
  inspect(@plan.is_runnable(plan), content="true")
  inspect(plan.label(), content="double")
}

日常任务

为计划指定策略

默认策略使用一个工作线程,块大小为一。用 make_execution_policy 构建一个并行策略,并把它传给构建函数:

test "policy" {
  let policy = @shared.make_execution_policy(worker_count=4, chunk_size=16).unwrap()
  let plan = @plan.map_reduce("sum", @plan.i64_type(), 64, @plan.sum_reduction(), policy~)
  assert_eq(plan.policy().worker_count, 4)
  assert_true(@plan.has_sum_reduction(plan))
  assert_true(@plan.is_runnable(plan))
}

阅读计划被拒绝的原因

validate 一次返回所有问题,因此你可以把它们一起报告:

test "issues" {
  let policy = @shared.make_execution_policy(worker_count=8, chunk_size=8).unwrap()
  let plan = @plan.reduce("tiny", @plan.f32_type(), 4, @plan.custom_reduction("xor"), policy~)
  let issues = @plan.validate(plan)
  assert_true(issues.any(@plan.is_unsupported_value_type))
  assert_true(issues.any(@plan.is_chunk_size_too_large))
  assert_true(issues.any(@plan.is_unsupported_reduction_kernel))
  assert_eq(issues.length(), 4)
}

第四个问题是 WorkerCountExceedsInput:四个元素却有八个工作线程。

手工构建不寻常的计划

Plan::new 会保存你给它的任何东西,借此可以测试各种验证规则,例如扫描的顺序要求:

test "relaxed scan" {
  let plan = @plan.Plan::new(
    "prefix",
    @plan.scan_plan_kind(),
    @plan.DataDomain::new(@plan.i32_type(), 8),
    ordering=@shared.relaxed_order(),
  )
  let issues = @plan.validate(plan)
  assert_true(issues.any(@plan.is_unsupported_ordering))
  assert_true(issues.any(@plan.is_scan_requires_stable_ordering))
}

查看计划

访问器返回各个字段,种类谓词则省去了一次模式匹配:

test "inspect" {
  let plan = @plan.scan("prefix", @plan.i64_type(), 32)
  assert_true(@plan.is_scan(plan))
  assert_eq(plan.reduction(), None)
  assert_true(plan.ordering() is @shared.PreserveInputOrder)
  assert_eq(plan.domain().input_length(), 32)
}

进阶

计划通过 backend/native 变得可执行:它的 map_request_from_plan、reduce_request_from_plan 和 scan_request_from_plan 把有效计划转换为带类型的请求;也可以通过工作流:@workflow.compute_node 把计划嵌入任务图,@workflow.validate 把计划的问题报告为 InvalidComputePlan。库代码应基于 Plan 和 ValidationIssue 而不是门面来编写,这样它可以在所有目标上构建。

常见陷阱

  • is_runnable 不检查原生内核所要求的“每块一个工作线程”(w≥⌈n/c⌉w \ge \lceil n / c \rceil)。
  • reduce 和 scan 总是保持输入顺序;要尝试其他顺序,请使用 Plan::new。
  • 扫描计划没有内核;原生扫描总是前缀和。
  • 枚举类型在包外是只读的:构建值时请写 @plan.i32_type(),而不是 @plan.I32。对 @plan.I32 做模式匹配是可以的。

下一步

plan API 列出了 validate 的每条规则。plan 设计解释了每种计划计算什么,以及为什么扫描需要有序的输入。workflow 教程把计划放进任务图。