Skip to main content

Archx

An event-based cost-modeling framework for computer-system design-space exploration, built around the A-Graph abstraction.

Overview

Archx computes arbitrary hardware metrics for an architecture running a workload. It does this by:

  1. building a directed graph (the A-Graph) of events and hardware modules connected by subevent edges,
  2. populating each hardware module with costs queried from a pluggable hardware interface (the CACTI7 memory model, CMOS synthesis CSVs, ...),
  3. running user-supplied Python performance models that set per-edge call counts, and
  4. aggregating metrics up the graph to answer queries such as "total energy of a GEMM on this accelerator".

The graph engine is implemented in Rust and exposed to Python as archx._core; everything else is Python.

Archx models across the system stack, separating into four levels. Each level is described by one of the four inputs to a run, detailed under Configuration.

level what it describes input
Application a workload (LLM, signal processing, error correction, ...), defined with parameters to sweep through multiple configurations workload (-w)
Software an event graph decomposing the application into architecture events, each with an isolated Python performance model that translates the workload configuration into per-subevent call counts event (-e)
Architecture the micro-architecture blocks that build the overall architecture, at any granularity architecture (-a)
Circuit the physical costs of each module: area, power, energy, cycle count, runtime, or any user-defined quantity, supplied per module by a hardware interface metric (-m)

For the package layout, the seven pipeline stages, and how caching works, see ARCHITECTURE.md.

Requirements

  • Anaconda to manage the environment.
  • The Rust toolchain for a source installation only, to compile the Rust extension via Maturin. Installing from PyPI needs no Rust.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"   # add cargo/rustc to PATH in the current shell
rustc --version             # verify

Installation

Both methods provide the archx CLI command and the import archx Python module.

Option 1: conda + pip install from PyPI (recommended)

Installs all dependencies via conda and the Archx package from PyPI.

conda env create -f environment.yaml   # edit `name: archx` to rename
conda activate archx
pip install archx

Option 2: source installation (developer mode)

Editable install from source: live code changes are reflected without reinstalling.

git clone https://github.com/UnaryLab/archx.git && cd archx
conda env create -f environment.yaml   # edit `name: archx` to rename
conda activate archx
pip install -e . --no-deps             # editable install; Rust extension is compiled here

After editing any Rust source under src/archx/rust-core/, rerun pip install -e . --no-deps to recompile; Python changes are live without reinstalling.

Validate

archx -h
python -c "import archx"

Quick start

Run one design and query a metric from the result.

archx -r <run_dir> \
      -a arch.yaml -m metric.yaml -w workload.yaml -e event.yaml \
      -c <run_dir>/graph.json \
      [-t] [-s] [-d] [-l DEBUG] [-p <dir>]
  • -c is the checkpoint the populated A-Graph is saved to (must end in .json).
  • -t mirrors the log to the terminal (a logfile is always written into the run dir).
  • -s also dumps the parsed architecture/metric/workload/event dicts as YAML into the run dir.
  • -d deletes the run dir first if it exists.
  • -p adds a directory to sys.path so performance models can import local helpers.

Load the checkpoint and aggregate any metric at any event:

from archx.event import load_event_graph
from archx.metric import create_metric_dict, aggregate_event_metric

event_graph = load_event_graph('<run_dir>/graph.json')
metric_dict = create_metric_dict('metric.yaml')

result = aggregate_event_metric(event_graph=event_graph, metric_dict=metric_dict,
                                metric='dynamic_energy', workload='gemm', event='gemm')
# -> OrderedDict({'value': ..., 'unit': 'nJ'})

aggregate_tag_metric aggregates over all modules sharing an architecture tag, and query_module_metric reads a single module's raw metrics.

For runnable designs with all four inputs written out, see examples/README.md.

Reproducing results

Design-space sweeps

A Python description file defining a description(path) function, built on archx.programming which uses OR-Tools CP-SAT to enumerate valid configurations under constraints, drives batch exploration:

archx -r <run_dir> -compile description.py        # generate configurations.csv
archx -r <run_dir> -extract configurations.csv    # csv -> runs.txt
archx -r <run_dir> -f configurations.csv          # Tkinter GUI to filter -> runs.txt
archx -r <run_dir> -x runs.txt                    # execute all runs in parallel

-compile ... -full chains all of the above in one command (add -ff to insert the GUI filter step). -x fans the runs out across all CPU cores; failing runs are collected in failed_runs.txt.

Writing a description file

A description file builds the same four inputs as a single run, but programmatically, and declares which parameters to sweep. Any list-valued instance or query entry, and any workload parameter added with sweep=True, becomes a sweep axis; constraints prune invalid combinations before anything is written to disk.

from archx.programming.graph.agraph import AGraph


def description(path):
    agraph = AGraph(path=path)
    architecture = agraph.architecture
    event = agraph.event
    metric = agraph.metric
    workload = agraph.workload

    # Architecture: list values become sweep axes.
    architecture.add_attributes(technology=[45], frequency=400, interface='csv_cmos')
    pe = architecture.add_module(name='pe', instance=[[16, 16], [32, 32], [64, 64]], tag=['onchip', 'compute'], query={'class': 'mac'})
    sram = architecture.add_module(name='sram', instance=[1], tag=['memory'], query={'interface': 'cacti7', 'class': 'sram', 'bank': [32, 64, 128], 'width': 16, 'depth': [512, 1024, 2048]})

    # Events: the A-Graph structure, same as the event YAML.
    event.add_event(name='gemm', subevent=['mac_array', 'sram_rd', 'sram_wr'], performance='performance.py')
    event.add_event(name='mac_array', subevent=['pe'], performance='performance.py')
    event.add_event(name='sram_rd', subevent=['sram'], performance='performance.py')
    event.add_event(name='sram_wr', subevent=['sram'], performance='performance.py')

    # Metrics.
    metric.add_metric(name='area', unit='mm^2', aggregation='module')
    metric.add_metric(name='dynamic_energy', unit='nJ', aggregation='summation')
    metric.add_metric(name='runtime', unit='ms', aggregation='specified')

    # Workloads: sweep=True parameters become sweep axes.
    gemm = workload.add_configuration(name='gemm')
    gemm.add_parameter(parameter_name='m', parameter_value=[256, 512, 1024], sweep=True)
    gemm.add_parameter(parameter_name='k', parameter_value=512)
    gemm.add_parameter(parameter_name='n', parameter_value=512)

    # Constraints prune the cross product of all axes.
    # direct_constraint: the listed parameters sweep together by index
    # (the i-th PE shape only pairs with the i-th bank count).
    agraph.direct_constraint([pe['instance'], sram['query']['bank']])
    # conditional_constraint: keep only combinations whose actual values
    # satisfy an arbitrary condition (here: SRAM capacity capped at 4 Mib).
    agraph.conditional_constraint(a=sram['query']['bank'], b=sram['query']['depth'], condition=lambda bank, depth: bank * depth * 16 <= 2**22)

    agraph.generate()
    return agraph

The handles returned by add_module index into the swept parameters (pe['instance'], sram['query']['bank']); passing a list of names (e.g. name=['isram', 'wsram']) creates several identically-parameterized modules, indexed as srams['wsram']['query']['bank']. agraph.generate() solves the constraint model and writes the per-configuration YAML files (architecture/, workload/, event/, metric/) plus configurations.csv into the run directory; -extract then turns the CSV into one archx command line per configuration in runs.txt.

For a complete real-world description (multi-module arrays, partition and multi-variable conditional constraints), see zoo/chiplet4ai/llama/description.py.

Batch runs

bash src/archx/bin/run_archx.sh runs.txt

Tests

pytest

tests/test_numerical_equivalence.py pins the Rust aggregation engine against hand-derived values. Tests touching SRAM run CACTI7, which ships a binary per host as cacti-<system>-<machine> and is built from source when the matching one is absent.

Configuration

A run is described by four YAML files plus one or more Python performance models.

Architecture (-a)

The hardware: a flattened set of named modules. attribute holds global defaults (technology, frequency, default interface) that are merged into each module's query; the query dict is what gets sent to the hardware interface to price the module. Modules can path: to other architecture YAML files for hierarchical descriptions, carry tag: lists for group queries, and instance: lists for arrays of identical units.

architecture:
  attribute:
    technology: 45        # nm
    frequency: 400        # MHz
    interface: csv_cmos   # default hardware interface
  module:
    mac_array:
      path: mac_array.architecture.yaml   # include another file
    sram:
      tag: [memory, onchip]
      query:
        interface: cacti7
        class: sram
        bank: 32
        width: 64          # bits
        depth: 1024

Metric (-m)

The metrics to compute. Each metric declares a unit and an aggregation mode:

mode meaning typical metrics
module sum once over distinct modules area, leakage power
summation sum scaled by per-edge call counts (default) dynamic energy
specified taken directly from a performance-model output cycle count, runtime
metric:
  area:
    unit: mm^2
    aggregation: module
  dynamic_energy:
    unit: nJ                # aggregation defaults to summation
  runtime:
    unit: ms
    aggregation: specified

Workload (-w)

One workload per file: a name and a configuration dict of knobs the performance models read. A file may instead path: to another workload file, which is followed recursively.

workload:
  name: llama_3_70b
  configuration:
    batch_size: 32
    dim: 8192
    layers: 80

Event (-e)

The A-Graph structure: each event lists its subevents (other events, or leaf hardware modules from the architecture) and the Python file holding its performance model.

event:
  gemm:
    subevent: [mac_array, sram_rd, sram_wr]
    performance: performance/example.performance.py
  sram_rd:
    subevent: [sram]
    performance: performance/example.performance.py

Performance models

For each event, a Python function with the same name as the event:

def gemm(architecture_dict, workload_dict=None):
    cfg = workload_dict['configuration']
    macs = cfg['m'] * cfg['k'] * cfg['n']
    return OrderedDict({
        'subevent': OrderedDict({
            'mac_array': OrderedDict({'count': macs / array_size}),
            'sram_rd':   OrderedDict({'count': reads}),
        }),
    })

It receives the parsed architecture and workload dicts and returns, per subevent, the call count (and optionally an operation such as read/write for multi-operation modules like SRAM). It may also return specified metrics directly (e.g. {'cycle_count': {'value': 1., 'unit': 'cycles'}}). See examples/mac_1_cycle/input/performance/example.performance.py for a complete model.

Hardware interfaces

Interfaces are the pluggable cost models that price each module, under src/archx/interface/:

interface costs
cacti7 SRAM/DRAM area, power, and energy via the CACTI7 memory model (bundled C++ source, one binary per host)
csv_cmos logic modules at 45 nm and 7 nm, interpolated from CMOS synthesis and place-and-route CSVs
csv_cmos_32nm the same lookup over a 32 nm library
csv_cmos_asplos_2026_ae the same lookup over a second 45 nm library
chiplet_cmos CMOS CSV costs for chiplet-based designs
csv_sc stochastic-computing modules
csv_h200 measured H200 power and runtime per GPU kernel
csv_riscv per-stage RISC-V energy

A module selects one with the interface: key in its query, or inherits the architecture's global attribute. Register, unregister, or copy an interface with:

archx -ireg  -iname <name> -idir <dir>   # register a new hardware interface
archx -iureg -iname <name>               # unregister
archx -icopy -iname <name> -idir <dir>   # copy an installed interface out

See src/archx/interface/README.md for the query contract and how to add your own.

Citation

Not yet published.

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

archx-0.1.1.tar.gz (1.7 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

archx-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.4 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

archx-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (3.4 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

archx-0.1.1-cp310-abi3-macosx_11_0_arm64.whl (3.3 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

archx-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl (3.3 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file archx-0.1.1.tar.gz.

File metadata

  • Download URL: archx-0.1.1.tar.gz
  • Upload date:
  • Size: 1.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for archx-0.1.1.tar.gz
Algorithm Hash digest
SHA256 289149e7f3d1734cd657bddf1bca2bc6e92209a85f1ae31655cb15796cf9113e
MD5 1f38f3cc50b9fe0a3a776e8e39cf0670
BLAKE2b-256 08da5cc9342ef80ace4e9341352af44b87cf8fb815bc5a9eec491b9d28034550

See more details on using hashes here.

Provenance

The following attestation bundles were made for archx-0.1.1.tar.gz:

Publisher: publish.yaml on UnaryLab/archx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file archx-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for archx-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3efff1b85917bc66e72e8370473ca295c70d7e7fa1f584b0d266471a934ffc5c
MD5 887e9fe8100366a12f55bb009c7b2a9c
BLAKE2b-256 aef647f1cfee69575142162446b1b4e27cdd9ac22eea611b3ba2c0dd0d9ceeee

See more details on using hashes here.

Provenance

The following attestation bundles were made for archx-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yaml on UnaryLab/archx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file archx-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for archx-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c266093829b260f1062a193b266c2c0d1f35ac3525ae43abc8cdad61ab72fe2b
MD5 517b7b63b488012e16d09f06e4d10b7a
BLAKE2b-256 0c1285a9d61278f366257876f25b0f3f9257cb602db4ee214e85f2c97b3c295e

See more details on using hashes here.

Provenance

The following attestation bundles were made for archx-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yaml on UnaryLab/archx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file archx-0.1.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for archx-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9596619f8c185e56dbc0dcab306f992f86d3ee1a09be1cf38ce3c61d1768eba4
MD5 5b8c6cca9ece1b1e6a0fea6e7b711a87
BLAKE2b-256 17ea39cc224e2eb9658e1d1d424695d5439016ddb59c53587221f1cbce80df21

See more details on using hashes here.

Provenance

The following attestation bundles were made for archx-0.1.1-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yaml on UnaryLab/archx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file archx-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for archx-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 682b928aa39d73dccdeed9a6574ab22f66424f3296cea86561795703107da50a
MD5 70745610f60594ae5fb2010cec223397
BLAKE2b-256 40173fb1599f98dd7c5f97e0211422a5784dc2099b21a888f105f6ff1bfff19e

See more details on using hashes here.

Provenance

The following attestation bundles were made for archx-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yaml on UnaryLab/archx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page