跳到内容
DispatchAtlas
搜索

领域契约

dispatchatlas.core 是内层包边界。它使用不可变、且仅依赖标准库的对象,使基准、求解器、 实验、分析与文档共享同一套调度词汇。

🗂️ 调度模型

问题以 ProblemSpecTaskSpecResourceSpecDependencyObjectiveConstraint 表示。候选调度使用 AssignmentScheduleObjectiveValueScheduleResult

验证是显式的:

from dispatchatlas.core import (
    Duration,
    Objective,
    ObjectiveSense,
    ProblemId,
    ProblemSpec,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    ResourceSpec,
    TaskId,
    TaskSpec,
    validate_problem,
)
 
cpu = ResourceId("cpu")
 
problem = ProblemSpec(
    id=ProblemId("smoke"),
    tasks=(
        TaskSpec(
            TaskId("task-a"),
            Duration(1.0),
            demands=(ResourceRequirement(cpu, ResourceAmount(1.0)),),
        ),
    ),
    resources=(ResourceSpec(cpu, ResourceAmount(1.0)),),
    objectives=(Objective("makespan", ObjectiveSense.MINIMIZE),),
)
 
validated = validate_problem(problem)

validate_problem 返回一个带验证戳记与机器可读报告的 ValidatedProblemvalidate_schedule 检查任务覆盖、资源容量、时序边界与依赖关系。

🔗 多资源共分配

一个任务可以同时要求多个资源。TaskSpec.demands 是一个 ResourceRequirement 的元组, 调度构造器将任务跨其要求的每一个资源进行共分配,并在任务的整个持续期内将它们一并 持有。因此候选调度将每次放置记录为 Assignment.resource_ids——一个元组,而非单个 资源——而 validate_schedule 确认两个在时间上重叠的任务绝不共享某个资源。

资源冲突图是调度的杠杆:需求集合相交的两个任务必须串行化,而集合互不相交的两个任务 并发运行。

from dispatchatlas.core import ResourceAmount, ResourceId, ResourceRequirement
 
# A task that co-allocates a compute node and an accelerator simultaneously.
demands = (
    ResourceRequirement(ResourceId("edge-0"), ResourceAmount(1.0)),
    ResourceRequirement(ResourceId("gpu-1"), ResourceAmount(1.0)),
)

accelerator-coschedulingdistributed-transactionfpga-partitioning 连续体族行使这一杠杆——前者以 固定的计算加加速器的持有,后者以对数据分片的可变基数锁集合。可运行的 examples/inspect_coallocation.py 对两者都进行调度,并展示资源互不相交的任务并行运行、而共享资源的任务串行化。

🧩 可塑执行

一个任务可以在若干模式之一中运行。TaskSpec.modes 是一个 TaskMode 的元组——每个是 一个 (demands, duration) 对,其中更宽的模式(要求更多资源者)运行得更短,即可塑加速。 当设置了 modes 时任务即为可塑的:调度构造器按任务、依据哪些资源空闲,挑选最早完成的 模式,因此调度顺序决定每个任务主张多少并行度。刚性任务保持 modes 未设置(默认值),其 顶层 durationdemands 即为其单一模式,精确求解后端将其作为保守参考来调度。 validate_schedule 确认每次放置匹配一个已声明的模式,且可塑执行与不精确 (mandatory_duration)执行互斥——一个任务要么选择其并行度,要么舍弃可选工作,而非 两者兼有。

from dispatchatlas.core import (
    Duration,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    TaskMode,
)
 
# Two ways to run one job: wide-and-fast on two workers, or narrow-and-slow on one.
modes = (
    TaskMode(
        demands=(
            ResourceRequirement(ResourceId("worker-0"), ResourceAmount(1.0)),
            ResourceRequirement(ResourceId("worker-1"), ResourceAmount(1.0)),
        ),
        duration=Duration(1.0),
    ),
    TaskMode(
        demands=(ResourceRequirement(ResourceId("worker-0"), ResourceAmount(1.0)),),
        duration=Duration(1.8),
    ),
)

elastic-serverless-autoscale 连续体族行使这一杠杆:每次函数调用可以扩展到从一个小型 共享突发池中取用的一个、两个或四个工作者,因此调度顺序决定哪些调用主张稀缺的宽-且-快 模式、哪些以窄模式运行——一种延迟对资源成本的权衡。

🛰️ 团组共调度

共享 TaskSpec.gang_id 的任务构成一个团组,其工作者必须全部在不同资源上同时启动—— 一种全有或全无的共启动,正如一个同步分布式训练或 MPI 作业需要其工作者一起运行。串行 构造器在每个工作者的资源都空闲的最早时刻原子地放置整个团组,即便某个工作者本可单独 更早启动;validate_schedule 拒绝其工作者不共启动的团组 (schedule.feasibility.gang_cosched)。团组工作者是刚性的(非可塑),因为团组以固定 宽度共启动;独立任务保持 gang_id 未设置。

from dispatchatlas.core import (
    Duration,
    ResourceAmount,
    ResourceId,
    ResourceRequirement,
    TaskId,
    TaskSpec,
)
 
# Two workers of one training job that must launch together on distinct accelerators.
gang = "train-job-0"
workers = tuple(
    TaskSpec(
        id=TaskId(f"worker-{index}"),
        duration=Duration(2.0),
        demands=(ResourceRequirement(ResourceId(f"acc-{index}"), ResourceAmount(1.0)),),
        gang_id=gang,
    )
    for index in range(2)
)

distributed-training-gang 连续体族行使这一杠杆:两到四个工作者的团组复用一个共享 加速器池,且作业随时间到达,因此一个作业在足够的加速器同时空闲之前无法开始,而调度 顺序决定哪个作业首先获取其完整的工作者集合。

⚖️ 多租户公平共享

任务携带一个可选的 TaskSpec.tenant_id,标注其所属租户,用于多租户公平共享核算。 dominant-resource-share 目标(ObjectiveKind.DOMINANT_RESOURCE_SHARE,依据 Ghodsi 等人的支配资源公平性)评分各租户的支配份额平衡得多均匀:每个租户的支配份额是其任务所 占用的某资源总容量-时间在各资源间的最大比例,而该目标是服务最多与最少的租户之间的离散 程度——对于支配份额相等(公平)的调度为 0.0,当某租户垄断其支配资源时更高。该目标为 最小化取向,在无租户实例上返回 DEFERREDtenant_id 与团组、可塑、不精确执行正交—— 一个租户的任务可以是其中任何一种;无租户任务保持 tenant_id 未设置。

杠杆在于放置,而非调度顺序:一个租户的总资源占用由其工作负载固定,因此其任务落在哪些 资源上才是平衡或扭曲支配份额的所在。可运行的 examples/multi_tenant_fairshare_study.py 在一个三节点池上对一个重租户与一个轻租户的公平(分散)放置对垄断放置进行评分,使该杠杆 显式可见。

⏱️ 硬截止与软截止

一个任务可以携带一个完成 TaskSpec.deadline,而 TaskSpec.deadline_kind 分类如何判定 一次错失。默认值 ConstraintKind.HARD 使错失的截止成为可行性违反:validate_schedule 抛出一个阻塞性的 schedule.feasibility.deadline 问题,调度报告为不可行。 ConstraintKind.SOFT 使同一错失仅成为延迟惩罚——调度保持可行,同时超额累计到 lateness 目标(ObjectiveKind.LATENESS),因此一个软实时任务因迟到而受罚,却不致使调度不可行。 当 deadline 未设置时该种类无效。

对截止的两种解读相互独立:硬截止界定可行区域,而软截止塑造目标曲面,任务可以使用任一。 可运行的 examples/infeasibility_study.py 端到端走过硬截止情形——一个过约束实例被报告为不可行,以及当不存在可行调度时的 最小不可行顺序。

💰 成本模型

成本感知调度由 CostModel 描述,这是一个独立的不可变产物,通过其标识符与某个问题 关联。将成本层置于 ProblemSpec 之外,使一个问题及其成本数据能独立地版本化与序列化。 一个成本模型捆绑五个可选契约:

  • ExecutionTimeMatrix——用于 R||Cmax 族的非相关机处理时间(p_ij)。该矩阵是 稀疏的:一个缺失的 (task, machine) 对意味着该任务不能在那里运行,且查询它会抛出 错误,而非默认为零。
  • CompatibilityMask——一个显式的任务-到-机器资格集合,与执行矩阵分开维护,使资格 与制表时间可以分歧。
  • SetupMatrix——序列相关的准备时间,按机器上的任务-到-任务或类型-到-类型转换索引。
  • LoadModel——一条负载相关的执行曲线,通过在严格递增的断点之间进行分段线性或阶梯 插值,将负载水平映射到时长乘数。
  • CommunicationModel——稀疏图上的跨资源通信惩罚;同机通信免费,未列出的跨机对回退 到一个声明的默认惩罚。
from dispatchatlas.core import (
    CostModel,
    ProblemId,
    ResourceId,
    TaskId,
    execution_matrix_from_iterable,
)
 
cost_model = CostModel(
    problem_id=ProblemId("smoke"),
    execution_matrix=execution_matrix_from_iterable(
        [(TaskId("task-a"), ResourceId("cpu"), 1.0)]
    ),
)

🎯 目标与归约

目标族在 OBJECTIVE_FAMILY 中命名,它记录每个目标的正典取向与单位:makespan、能量、 成本、碳、延迟、迟到、公平性、支配资源份额(服务最多与最少的租户的支配资源份额之间的 离散程度——多租户公平共享)、可靠性、安全性、鲁棒性、准备,不精确奖励(在部分可执行 任务的强制部分之外完成的可选计算),以及加权复合。测得结果由 VectorObjectiveValue 承载,它持有一个或多个 ObjectiveValue 条目(按名称排序)加上一个显式的 ObjectiveReduction 与一个披露标签。加权和与 Chebyshev 归约将向量标量化;非标量化归约 (NONELEXICOGRAPHIC)在 scalarize() 上抛出错误,以便调用方显式处理排序。

可行性报告

build_feasibility_report 将一份调度验证报告转化为对审阅者可见的 FeasibilityReport: 硬违反成为逐行的 InfeasibleRow 记录,而被违反的具名软约束累计加权的 SoftConstraintPenalty 条目。软违反绝不会把 feasible 翻转为 False

📐 目标评估、约束与前沿

目标-与-约束层逐一计算每个具名目标,因此无一被折叠进通用捆绑。evaluate_objective 直接从调度导出 makespan、迟到、负载公平性(Jain 指数),以及——对于带租户标注的实例—— 支配资源份额公平性,从附带的执行时间矩阵导出成本、从附带的准备矩阵导出序列相关的准备 时间,并将计算出的各成分归约为一个加权复合。需要核心未携带之模型的目标(能量、碳、 延迟、可靠性、安全性、鲁棒性)返回一个状态为 DEFERRED 且带具名理由的 ObjectiveEvaluation,而非捏造的值。MultiObjectiveOutcome 将标量值、向量目标与可行性 报告通过一次确定性的序列化往返进行承载。

约束核算将具名的服务水平(SLA)约束作为一等约束加入,兼具一条硬违反路径(一种不可行性) 与一条软惩罚路径(一种与违反成比例的加权惩罚)。ConstraintViolationSummary 聚合硬 违反、软惩罚、SLA 结果与修复诊断;它在硬规则违反或硬 SLA 违反任一情形下报告不可行。

Pareto 辅助器提取非支配前沿,并报告依据 Riquelme、Von Lücken & Barán (2015) 选定的四个 具名质量指标:超体积(主要指标)、IGD+(一个弱-Pareto-相容的收敛指标)、加性 epsilon-指标,以及散布(多样性指标)。每个指标都可单独计算。frontier_data 构建带 非支配标志的前沿就绪记录,供分析与门户渲染。

鲁棒性被量化为一个可度量的目标,而非一个姿态标签:evaluate_robustness 在一个显式 声明的扰动集合上聚合某一目标的值,或作为最坏情形值,或作为最坏尾部的条件风险价值 (CVaR)。扰动集合与聚合两者都记录于结果之上。

⚠️ 局限

核心内核定义成本、目标与约束的契约,以及评估它们的目标-与-约束层;它不进行优化。 需要核心未携带之模型的目标(能量、碳、延迟、可靠性、安全性与鲁棒性)被报告为延迟并附 具名理由,而非被估算。LoadModel 仅评估其自身声明的曲线,而 ObjectiveDefinition 承载元数据而非一个评估器。

🌱 出处与种子

生成的产物携带 ProvenanceArtifactHashSourceReferenceEnvironmentStamp 与 可选的 SeedLineage 记录。种子流由稳定坐标导出:

from dispatchatlas.core import derive_seed
 
seed = derive_seed(42, "benchmark.smoke", 0)

相同的根种子、命名空间与索引始终产生相同的导出种子。

📦 序列化

核心对象通过正典的 JSON 兼容映射与 ArtifactEnvelope 包装器进行序列化。包装器将载荷 绑定到内容哈希,并将该哈希复制回出处。

🔌 协议

外层包依赖核心定义的协议:

  • BenchmarkProvider
  • Solver
  • ExperimentRunner
  • ResultRepository
  • DisclosurePolicy
  • AnalysisExporter

这些协议使包导入保持向内定向,同时允许具体的基准、求解器、实验与分析包在之后进行组合。