본문으로 건너뛰기
DispatchAtlas
검색

도메인 계약

dispatchatlas.core는 안쪽 패키지 경계입니다. 불변이며 표준 라이브러리만 사용하는 객체를 써서 벤치마크, 솔버, 실험, 분석, 문서가 하나의 공유 스케줄링 어휘를 소비하도록 합니다.

🗂️ 스케줄링 모델

문제는 ProblemSpec, TaskSpec, ResourceSpec, Dependency, Objective, Constraint로 표현됩니다. 후보 스케줄은 Assignment, Schedule, ObjectiveValue, ScheduleResult를 사용합니다.

검증은 명시적입니다:

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은 검증 스탬프와 기계 판독 가능 보고서를 갖춘 ValidatedProblem을 반환합니다. validate_schedule은 작업 커버리지, 리소스 용량, 타이밍 경계, 의존성을 확인합니다.

🔗 다중 리소스 공동 할당

한 작업은 한 번에 둘 이상의 리소스를 요구할 수 있습니다. TaskSpec.demandsResourceRequirement의 튜플이며, 스케줄 생성자는 작업이 요구하는 모든 리소스에 걸쳐 작업을 공동 할당하고, 작업의 전체 기간 동안 그것들을 함께 보유합니다. 따라서 후보 스케줄은 각 배치를 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-coscheduling, distributed-transactionfpga-partitioning 연속체 패밀리가 이 지렛대를 행사합니다 — 전자는 고정된 연산-플러스-가속기 보유로, 후자는 데이터 샤드에 대한 가변 카디널리티 잠금 집합으로. 실행 가능한 examples/inspect_coallocation.py 는 둘 다 스케줄링하고, 서로소 리소스 작업이 병렬로 실행되는 한편 리소스를 공유하는 작업이 직렬화되는 것을 보여줍니다.

🧩 가소적 실행

한 작업은 여러 모드 중 하나로 실행될 수 있습니다. TaskSpec.modesTaskMode의 튜플이며 — 각각 (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 et al.의 지배적 리소스 공정성에 따름)는 테넌트들의 지배적 몫이 얼마나 고르게 균형 잡혔는지를 채점합니다: 각 테넌트의 지배적 몫은 리소스 전반에서 그 작업들이 점유하는 어떤 리소스의 총 용량-시간의 최대 분율이며, 목표는 가장 많이-가장 적게 서비스된 테넌트 간의 산포입니다 — 지배적-몫이-동등한(공정한) 스케줄에서 0.0, 한 테넌트가 자기 지배적 리소스를 독점하면 더 높습니다. 목표는 최소화 의미이며 테넌트 없는 인스턴스에서 DEFERRED를 반환합니다. tenant_id는 갱· 가소적·부정확 실행에 직교합니다 — 테넌트의 작업은 그 중 어느 것이든 될 수 있습니다. 테넌트 없는 작업은 tenant_id를 미설정으로 둡니다.

지렛대는 스케줄 순서가 아니라 배치입니다: 테넌트의 총 리소스 점유는 그 워크로드로 고정되므로, 그 작업이 어떤 리소스에 안착하는지가 지배적 몫을 균형 잡거나 왜곡하는 것입니다. 실행 가능한 examples/multi_tenant_fairshare_study.py 는 3노드 풀에서 무거운 테넌트와 가벼운 테넌트의 공정한(분산된) 배치 대 독점적 배치를 채점하여 지렛대를 명시합니다.

⏱️ 하드 데드라인과 소프트 데드라인

작업은 완료 TaskSpec.deadline을 가질 수 있고, TaskSpec.deadline_kind는 미스가 어떻게 판정되는지를 분류합니다. 기본값 ConstraintKind.HARD는 놓친 데드라인을 실행 가능성 위반으로 만듭니다: validate_schedule은 차단성 schedule.feasibility.deadline 문제를 일으키고 스케줄은 실행 불가능으로 보고됩니다. ConstraintKind.SOFT는 같은 미스를 지연 페널티로만 만듭니다 — 초과분이 lateness 목표(ObjectiveKind.LATENESS)에 누적되는 동안 스케줄은 실행 가능한 채로 남으므로, 소프트 실시간 작업은 스케줄을 실행 불가능하게 만들지 않으면서 지각으로 벌점을 받습니다. deadline이 미설정일 때 이 종류는 효과가 없습니다.

데드라인의 두 가지 해석은 독립적입니다: 하드 데드라인은 실행 가능 영역을 한정하고, 소프트 데드라인은 목표 표면을 형성하며, 작업은 어느 쪽이든 사용할 수 있습니다. 실행 가능한 examples/infeasibility_study.py 는 하드 데드라인 사례를 처음부터 끝까지 따라갑니다 — 과제약 인스턴스가 실행 불가능으로 보고되고, 실행 가능한 스케줄이 존재하지 않을 때의 최소-실행-불가능 순서를 보여줍니다.

💰 비용 모델

비용 인식 스케줄링은 CostModel—식별자로 문제에 연결된 별도의 불변 산출물—로 기술됩니다. 비용 계층을 ProblemSpec 밖에 두면 문제와 그 비용 데이터가 독립적으로 버전 관리·직렬화될 수 있습니다. 비용 모델은 다섯 개의 선택적 계약을 묶습니다:

  • ExecutionTimeMatrixR||Cmax 패밀리를 위한 비관련-기계 처리 시간(p_ij). 행렬은 희소합니다: 부재한 (task, machine) 쌍은 작업이 거기서 실행될 수 없음을 의미하며, 그것을 조회하면 0을 기본값으로 하는 대신 오류를 일으킵니다.
  • 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에 명명되며, 각 목표의 정전적 의미와 단위를 기록합니다: 메이크스팬, 에너지, 비용, 탄소, 지연, 지각, 공정성, 지배적 리소스 몫 (가장 많이-가장 적게 서비스된 테넌트의 지배적 리소스 몫 간의 산포 — 멀티테넌트 공정 분배), 신뢰성, 보안, 견고성, 셋업, 부정확 보상(부분 실행 가능 작업의 필수 부분을 넘어 완료된 선택적 계산), 그리고 가중 복합. 측정된 결과는 VectorObjectiveValue가 운반하며, 하나 이상의 ObjectiveValue 항목(이름순)에 더해 명시적 ObjectiveReduction과 공개 라벨을 보유합니다. 가중합과 체비쇼프 환원은 벡터를 스칼라화합니다. 비스칼라화 환원 (NONE, LEXICOGRAPHIC)은 scalarize()에서 오류를 일으켜 호출자가 순서를 명시적으로 다루게 합니다.

실행 가능성 보고서

build_feasibility_report는 스케줄 검증 보고서를 리뷰어에게 보이는 FeasibilityReport로 바꿉니다: 하드 위반은 행별 InfeasibleRow 기록이 되고, 명명된 위반 소프트 제약은 가중 SoftConstraintPenalty 항목을 누적합니다. 소프트 위반은 결코 feasibleFalse로 뒤집지 않습니다.

📐 목표 평가, 제약, 프런티어

목표-와-제약 계층은 명명된 각 목표를 개별적으로 계산하므로, 어느 것도 일반 번들로 접히지 않습니다. evaluate_objective는 메이크스팬, 지각, 부하 공정성(Jain 지수), 그리고 — 테넌트 라벨 인스턴스에 대해서는 — 지배적-리소스-몫 공정성을 스케줄에서 직접 도출하고, 비용을 첨부된 실행 시간 행렬에서, 시퀀스 의존 셋업 시간을 첨부된 셋업 행렬에서 도출하며, 계산된 성분을 가중 복합으로 환원합니다. 코어가 운반하지 않는 모델이 필요한 목표(에너지, 탄소, 지연, 신뢰성, 보안, 견고성)는 날조된 값 대신 DEFERRED 상태와 명명된 근거를 가진 ObjectiveEvaluation을 반환합니다. MultiObjectiveOutcome은 스칼라 값, 벡터 목표, 실행 가능성 보고서를 결정적 직렬화 왕복을 통해 운반합니다.

제약 회계는 명명된 서비스 수준(SLA) 제약을, 하드 위반 경로(실행 불가능)와 소프트 페널티 경로(위반에 비례하는 가중 페널티) 둘 다를 가진 일급 제약으로 추가합니다. ConstraintViolationSummary는 하드 위반, 소프트 페널티, SLA 결과, 수리 진단을 집계합니다. 하드 규칙 위반이나 하드 SLA 위반 어느 쪽에서든 실행 불가능을 보고합니다.

Pareto 헬퍼는 비지배 프런트를 추출하고, Riquelme, Von Lücken & Barán (2015)에 따라 선택된 네 개의 명명된 품질 지표를 보고합니다: 하이퍼볼륨(주요 지표), IGD+(약-Pareto-적합 수렴 지표), 가법 엡실론-지표, 그리고 산포(다양성 지표). 각 지표는 개별적으로 계산 가능합니다. frontier_data는 분석과 포털 렌더링을 위해 비지배 플래그를 가진 프런티어 대응 기록을 구축합니다.

견고성은 자세 라벨이 아니라 측정 가능한 목표로 정량화됩니다: evaluate_robustness는 명시적으로 선언된 섭동 집합에 걸쳐 한 목표의 값을, 최악 경우 값으로, 또는 최악 꼬리의 조건부 가치-위험(CVaR)으로 집계합니다. 섭동 집합과 집계 둘 다 결과에 기록됩니다.

⚠️ 한계

코어 커널은 비용·목표·제약 계약과 그것들을 평가하는 목표-와-제약 계층을 정의합니다; 최적화하지 않습니다. 코어가 운반하지 않는 모델이 필요한 목표(에너지, 탄소, 지연, 신뢰성, 보안, 견고성)는 추정되지 않고 명명된 근거와 함께 연기로 보고됩니다. LoadModel은 자신의 선언된 곡선만 평가하고, ObjectiveDefinition은 평가기가 아니라 메타데이터를 운반합니다.

🌱 출처와 시드

생성된 산출물은 Provenance, ArtifactHash, SourceReference, EnvironmentStamp, 선택적 SeedLineage 기록을 운반합니다. 시드 스트림은 안정적 좌표에서 도출됩니다:

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

같은 루트 시드, 네임스페이스, 인덱스는 항상 같은 도출 시드를 생성합니다.

📦 직렬화

코어 객체는 정전적 JSON 호환 매핑과 ArtifactEnvelope 래퍼를 통해 직렬화합니다. 엔벨로프는 페이로드를 콘텐츠 해시에 묶고 그 해시를 출처로 다시 복사합니다.

🔌 프로토콜

바깥 패키지는 코어에 정의된 프로토콜에 의존합니다:

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

이 프로토콜들은 패키지 임포트를 안쪽으로 향하게 유지하면서, 구체적인 벤치마크·솔버· 실험·분석 패키지가 나중에 합성될 수 있게 합니다.