Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions atom/compass/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: MIT
"""Compass: a performance simulator for ATOM.

The package is deliberately empty at import time. Every subpackage is imported
by name, so that pulling in one of them costs only what it needs.
"""
53 changes: 53 additions & 0 deletions atom/compass/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2024-2025, Advanced Micro Devices, Inc. All rights reserved.

"""Cost backends: what a simulated step costs, and where that number came from.

The pieces, and the rule each exists to make structural rather than customary:

- `CostBackend` -- `estimate(batch_view) -> StepCost` plus `describe()`. Takes a
projection of the batch, so nothing here imports the engine.
- `StepCost` / `CostTerm` -- a total folded from its parts on every read, with
the parts re-checked on every read, so it cannot drift from them; a breakdown
that cannot be empty; and no subclass that can shadow either.
- `Provenance` / `Species` / `Refusal` -- every number says how it was obtained
and what produced it, with no default that would let one avoid saying.
- `Resolver` / `CostSource` -- sources consulted in a fixed order, with every
refusal on the way down recorded on the answer rather than inferred from it.
- `ProvenanceMix` -- the run-level mixture, and refusals counted by number, by
fraction of steps and by fraction of predicted seconds. A run with nothing in
it has no fractions and says so, rather than reporting a reassuring zero.
"""

from atom.compass.backends.base import CostBackend, Tier
from atom.compass.backends.cost import (
CostTerm,
ProvenanceMix,
StepCost,
fold_seconds,
fold_step,
)
from atom.compass.backends.ladder import (
CostRefused,
CostSource,
Resolution,
Resolver,
)
from atom.compass.backends.provenance import Provenance, Refusal, Species

__all__ = [
"CostBackend",
"CostRefused",
"CostSource",
"CostTerm",
"Provenance",
"ProvenanceMix",
"Refusal",
"Resolution",
"Resolver",
"Species",
"StepCost",
"Tier",
"fold_seconds",
"fold_step",
]
72 changes: 72 additions & 0 deletions atom/compass/backends/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2024-2025, Advanced Micro Devices, Inc. All rights reserved.

"""The interface a cost backend implements.

Two methods. `estimate` prices one step; `describe` says what this backend is,
in a line that goes into the run record so a result can be read a month later.

`batch_view` is a projection of the scheduled batch, prepared by the caller --
plain numbers and sequences, no engine objects. That is the whole reason this
package imports nothing from the rest of ATOM: a backend is then testable on a
machine with no accelerator and no engine, and the fields it depends on are
visible in the projection rather than reachable by attribute from anywhere in
the scheduler. The projection's shape belongs to the caller that builds it, so
it is not named here.

Whoever defines that shape inherits an obligation with it, because the
no-engine-imports property belongs to a package and not to a type. The test
that enforces it reads the files under this package and nothing else: a
projection defined here is covered automatically, and one defined anywhere
else is covered by nobody until its own package's tests assert the same thing
over its own sources. A projection that reaches an engine type for one field
is a projection that can only be built where the engine imports, which defeats
the reason it exists.

`tier` says which cost model was asked, which is a different axis from where
each answer inside it came from. A run can ask for the op-level model and still
receive analytically-computed seconds for a term the campaign never covered;
the tier records the intent and the provenance records what happened.
"""

from __future__ import annotations

import abc
import enum
from typing import Any

from atom.compass.backends.cost import StepCost


class Tier(enum.Enum):
"""Which cost model was asked for."""

ANALYTIC = "0"
COARSE = "a"
OP_LEVEL = "b"

def __str__(self) -> str:
return self.value


class CostBackend(abc.ABC):
"""Turns a projected batch into a duration with its decomposition."""

@property
@abc.abstractmethod
def tier(self) -> Tier:
"""Which cost model this backend is."""

@abc.abstractmethod
def estimate(self, batch_view: Any) -> StepCost:
"""Price one step.

Returns a `StepCost`, which carries its breakdown by construction.
Raises `CostRefused` when nothing can price the step: a backend asked
about something it has no basis for refuses by name and does not
substitute a number, however plausible one would look.
"""

@abc.abstractmethod
def describe(self) -> str:
"""One line naming this backend and what it is answering from."""
Loading