Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8840a5e
Add density model, format occupancy, and workload density support
fisherxue Feb 18, 2026
7acc86a
Add sparse frontend spec parsing, occupancy, and access counts
fisherxue Feb 18, 2026
a1b991a
Add SAF pipeline, propagation, and compute classification
fisherxue Feb 19, 2026
9114fd0
Integrate sparse adjustment pipeline with model evaluation
fisherxue Feb 19, 2026
ef3f495
Add sparse energy model with per-rank format metadata
fisherxue Feb 19, 2026
dcebf91
Add sparse latency model, density sweep, energy fixes, and first-k op…
fisherxue Feb 20, 2026
baf2b6b
Add EyerissV2 PE-level reproduction (Fig 12) within 0.6%
fisherxue Feb 21, 2026
7914299
Add Eyeriss v1 spatial model reproduction (Table 7)
fisherxue Feb 21, 2026
b933c67
Add Fig 13 DSTC reproduction, Fig 15 STC configs, and position-space …
fisherxue Feb 22, 2026
f140ae9
Rerun all 6 reproduction notebooks with fresh outputs
fisherxue Feb 22, 2026
0497533
Refactor sparse_adjustment.py and _compute_sparse_latency for readabi…
fisherxue Feb 23, 2026
6bb4c11
Add 'plotting' to __all__ in __init__.py
tanner-andrulis Feb 20, 2026
35dd51e
Update __all__ to include 'roofline' and remove 'plotting'
tanner-andrulis Feb 20, 2026
a78a32e
Fix "Above" resolving to empty set
tanner-andrulis Feb 20, 2026
d8eb886
Run Black
tanner-andrulis Feb 21, 2026
1cb86b7
GPT3 with KV cache
tanner-andrulis Feb 22, 2026
dbb0b00
Clean up tests: replace fig1-only regressions with 6-architecture rep…
fisherxue Feb 23, 2026
3723876
Clean up internal comments and expand user-facing parameter documenta…
fisherxue Feb 23, 2026
7dd6370
Fix 12 code review issues in sparse pipeline
fisherxue Feb 23, 2026
138db9a
Refactor sparse.py frontend: trim docstrings, add input validation, m…
fisherxue Feb 23, 2026
fe06089
Refactor: move halo/stride reuse into Reservation mechanism
fisherxue Feb 23, 2026
8baeecc
Inline sparse config into arch YAML: add framework support
fisherxue Feb 23, 2026
b2dbbb9
Migrate test configs to inline sparse, remove separate sparse YAML files
fisherxue Feb 23, 2026
b6fca6f
Update reproduction notebooks for inline sparse config
fisherxue Feb 23, 2026
7ded12d
Refactor: consolidate temporal-reuse and SAF-update helpers
fisherxue Feb 25, 2026
2aa1a20
Sparsity support, temporal reuse fix, and updated notebook takeaways
fisherxue Feb 26, 2026
d074d69
Validate compute-level tiling and add temporal reuse test
fisherxue Feb 26, 2026
6931b59
Refactor apply_sparse_adjustments into 5 pipeline phases
fisherxue Feb 26, 2026
9c26ea2
Use uneven mapping in temporal reuse test
fisherxue Feb 26, 2026
e2befa7
Refactor temporal reuse: fold fill/drain into regular actions with po…
fisherxue Mar 1, 2026
c8382cf
Remove _apply_temporal_reuse_corrections post-processing step
fisherxue Mar 1, 2026
2f88a78
Add temporal reuse tracking for weight fills at shared_glb
fisherxue Mar 2, 2026
aaee16e
Document conv3-5 cycle 13/12 discrepancy with Sparseloop reference
fisherxue Mar 3, 2026
8f09793
Fix EvalableList/EvalableDict type resolution for Optional fields
fisherxue Mar 3, 2026
ecba8d8
Add is_self_conditioned property to ActionOptimization
fisherxue Mar 3, 2026
9d56526
Add tile_shape and parent fill/write tracking to BuffetStats
fisherxue Mar 3, 2026
fcd7cb2
Re-run sparseloop reproduction notebooks with latest changes
fisherxue Mar 3, 2026
48e6e59
infra readme
rengzhengcodes Mar 3, 2026
c67663d
building everything for all platforms script
rengzhengcodes Mar 3, 2026
2c8508b
all-infra should work
rengzhengcodes Mar 3, 2026
173e904
fixed misdefined extra infra
rengzhengcodes Mar 3, 2026
5d01d33
pushes all infra
rengzhengcodes Mar 3, 2026
8e3ad6e
fixed latest amend
rengzhengcodes Mar 3, 2026
06764e1
Pass gated/skipped compute counts through latency path
fisherxue Mar 3, 2026
df776bd
Add mapping validation to evaluate_mapping
fisherxue Mar 3, 2026
4144a56
fix arch specs for sparsity
fisherxue Mar 5, 2026
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
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*

# Update certificates (needed for downloading)
RUN apt-get upgrade -y ca-certificates && \
update-ca-certificates && \
rm -rf /var/lib/apt/lists/*
RUN apt-get upgrade -y ca-certificates \
&& update-ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*

WORKDIR /home/build
COPY Makefile ./
Expand Down
66 changes: 60 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
DOCKER_EXE ?= docker
DOCKER_NAME ?= accelforge
DOCKER_BUILD ?= ${DOCKER_EXE} buildx build --load
DOCKER_BUILD ?= ${DOCKER_EXE} buildx build --load --pull

VERSION := 0.1.3
VERSION := 0.1.4

USER := timeloopaccelergy
REPO := accelforge
INFRA_REPO := accelforge-extra

NAME := ${USER}/${REPO}
TAG := $$(git log -1 --pretty=%h)
Expand All @@ -14,6 +15,10 @@ IMG := ${NAME}:${TAG}
ALTTAG := latest
ALTIMG := ${NAME}:${ALTTAG}

INFRA_NAME := ${USER}/${INFRA_REPO}
INFRA_IMG := ${INFRA_NAME}:${TAG}
INFRA_ALTIMG := ${INFRA_NAME}:${ALTTAG}

# Install hwcomponents packages from PyPI for Docker builds.
.PHONY: install-hwcomponents
install-hwcomponents:
Expand All @@ -32,6 +37,12 @@ build-amd64:
-t ${IMG}-amd64 \
-t ${ALTIMG}-amd64 .

build-extra-amd64:
${DOCKER_BUILD} ${BUILD_FLAGS} --platform linux/amd64 \
-f infrastructure/Dockerfile \
-t ${INFRA_IMG}-amd64 \
-t ${INFRA_ALTIMG}-amd64 .

build-arm64:
${DOCKER_BUILD} ${BUILD_FLAGS} --platform linux/arm64 \
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
Expand All @@ -40,29 +51,72 @@ build-arm64:
-t ${IMG}-arm64 \
-t ${ALTIMG}-arm64 .

build-extra-arm64:
${DOCKER_BUILD} ${BUILD_FLAGS} --platform linux/arm64 \
-f infrastructure/Dockerfile \
-t ${INFRA_IMG}-arm64 \
-t ${INFRA_ALTIMG}-arm64 .

# Push docker image
push-amd64:
@echo "Pushing ${NAME}:${ALTTAG}-amd64"
#Push Amd64 version
"${DOCKER_EXE}" push ${NAME}:${ALTTAG}-amd64
#Combine Amd64 version into multi-architecture docker image.
"${DOCKER_EXE}" manifest rm ${NAME}:${ALTTAG} || true
"${DOCKER_EXE}" manifest create \
${NAME}:${ALTTAG} \
--amend ${NAME}:${ALTTAG}-amd64 \
--amend ${NAME}:${ALTTAG}-arm64
${NAME}:${ALTTAG}-amd64 \
${NAME}:${ALTTAG}-arm64
"${DOCKER_EXE}" manifest push ${NAME}:${ALTTAG}
@echo "Pushing ${INFRA_NAME}:${ALTTAG}-amd64"


push-extra-amd64:
@echo "Pushing ${INFRA_NAME}:${ALTTAG}-amd64"
"${DOCKER_EXE}" push ${INFRA_NAME}:${ALTTAG}-amd64
#Combine Amd64 infrastructure version into multi-architecture docker image.
"${DOCKER_EXE}" manifest rm ${INFRA_NAME}:${ALTTAG} || true
"${DOCKER_EXE}" manifest create \
${INFRA_NAME}:${ALTTAG} \
${INFRA_NAME}:${ALTTAG}-amd64 \
${INFRA_NAME}:${ALTTAG}-arm64
"${DOCKER_EXE}" manifest push ${INFRA_NAME}:${ALTTAG}

push-arm64:
@echo "Pushing ${NAME}:${ALTTAG}-arm64"
#Push Arm64 version
"${DOCKER_EXE}" push ${NAME}:${ALTTAG}-arm64
#Combine Arm64 version into multi-architecture docker image.
"${DOCKER_EXE}" manifest rm ${NAME}:${ALTTAG} || true
"${DOCKER_EXE}" manifest create \
${NAME}:${ALTTAG} \
--amend ${NAME}:${ALTTAG}-amd64 \
--amend ${NAME}:${ALTTAG}-arm64
${NAME}:${ALTTAG}-amd64 \
${NAME}:${ALTTAG}-arm64
"${DOCKER_EXE}" manifest push ${NAME}:${ALTTAG}

push-extra-arm64:
@echo "Pushing ${INFRA_NAME}:${ALTTAG}-arm64"
#Push Arm64 infrastructure version
"${DOCKER_EXE}" push ${INFRA_NAME}:${ALTTAG}-arm64
#Combine Arm64 infrastructure version into multi-architecture docker image.
"${DOCKER_EXE}" manifest rm ${INFRA_NAME}:${ALTTAG} || true
"${DOCKER_EXE}" manifest create \
${INFRA_NAME}:${ALTTAG} \
${INFRA_NAME}:${ALTTAG}-amd64 \
${INFRA_NAME}:${ALTTAG}-arm64
"${DOCKER_EXE}" manifest push ${INFRA_NAME}:${ALTTAG}

all-infra:
make build-arm64
make build-amd64
make push-arm64
make push-amd64
make build-extra-arm64
make build-extra-amd64
make push-extra-arm64
make push-extra-amd64

run-docker:
docker-compose up

Expand Down
17 changes: 17 additions & 0 deletions accelforge/frontend/arch/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
from accelforge.util._eval_expressions import eval_expression
from accelforge.util._setexpressions import InvertibleSet, eval_set_expression
from accelforge.frontend.renames import TensorName
from accelforge.frontend.sparse import (
RepresentationFormat,
ActionOptimization,
ComputeOptimization,
)
from accelforge.frontend.arch.constraints import Comparison
from accelforge.frontend.arch.structure import ArchNode, Branch, Leaf
from accelforge.frontend.arch.spatialable import Spatial, Spatialable
Expand Down Expand Up @@ -893,6 +898,14 @@ class TensorHolder(Component, Leaf):
value for the bits_per_action of all actions of this component.
"""

representation_format: EvalableList[RepresentationFormat] = EvalableList()
"""Compressed representation formats for tensors at this storage level.
Inline alternative to specifying in a separate sparse_optimizations file."""

action_optimization: EvalableList[ActionOptimization] = EvalableList()
"""Storage action optimizations (gating/skipping) at this level.
Inline alternative to specifying in a separate sparse_optimizations file."""

def model_post_init(self, __context__=None) -> None:
self._update_actions(MEMORY_ACTIONS)

Expand Down Expand Up @@ -999,6 +1012,10 @@ class Compute(Component, Leaf):
actions: EvalableList[Action] = COMPUTE_ACTIONS
""" The actions that this `Compute` can perform. """

compute_optimization: EvalableList[ComputeOptimization] = EvalableList()
"""Compute-level optimizations (gating/skipping at the MAC).
Inline alternative to specifying in a separate sparse_optimizations file."""

def model_post_init(self, __context__=None) -> None:
self._update_actions(COMPUTE_ACTIONS)

Expand Down
191 changes: 191 additions & 0 deletions accelforge/frontend/sparse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
"""Sparse optimization specification for AccelForge."""

from typing import Literal, Optional

from pydantic import Field

from accelforge.util._basetypes import EvalableModel, EvalableList


class RankFormat(EvalableModel):
"""Per-rank format specification for explicit (expert) format definitions."""

format: str
""" Format primitive name: UOP, CP, B, or RLE. """

metadata_word_bits: Optional[int] = None
""" Bits per metadata word. None = auto-derived from format primitive. """

payload_word_bits: Optional[int] = None
""" Bits per payload word. None = auto-derived from dimension size. """

flattened_rank_ids: Optional[list[list[str]]] = None
""" Dimension names flattened into this rank, e.g. [["C", "R"]]. """

def model_post_init(self, __context__=None) -> None:
if self.format.upper() not in ("UOP", "CP", "B", "RLE"):
raise ValueError(
f"Unknown format primitive {self.format!r}. "
f"Expected one of: UOP, CP, B, RLE"
)


class RepresentationFormat(EvalableModel):
"""Per-tensor compressed format at a storage level.

Specify ``format`` as one of: csr, coo, bitmask, rle.
"""

_VALID_FORMATS = {"csr", "coo", "bitmask", "b", "rle"}

name: str
""" Tensor name (must match a tensor in the workload). """

format: Optional[str] = None
""" User-friendly format name (csr, coo, bitmask, rle), auto-expanded to per-rank primitives. """

ranks: Optional[EvalableList[RankFormat]] = Field(None, exclude=True)
""" Explicit per-rank format specification (internal), outer-to-inner. """

metadata_word_bits: Optional[int] = None
""" Default bits per metadata word for auto-expanded ranks. None = auto-derived per rank. """

metadata_storage_width: Optional[int] = None
""" Physical SRAM width in bits for metadata packing. None = fall back to arch. """

uop_payload_word_bits: Optional[int] = None
""" Override payload_word_bits for auto-expanded UOP ranks. None = auto-derived. """

def has_explicit_ranks(self) -> bool:
"""True if explicit per-rank formats were provided (internal)."""
return self.ranks is not None

def model_post_init(self, __context__=None) -> None:
if self.format is not None and self.format.lower() not in self._VALID_FORMATS:
raise ValueError(
f"Unknown format {self.format!r}. "
f"Expected one of: csr, coo, bitmask, rle"
)

def get_rank_formats(self, num_ranks: Optional[int] = None) -> list[RankFormat]:
"""Return per-rank formats, auto-expanding from ``format`` if needed."""
if self.ranks is not None:
return list(self.ranks)
if self.format is None:
return []
if num_ranks is None:
raise ValueError(
f"num_ranks required to auto-expand format {self.format!r} "
f"for tensor {self.name}"
)
from accelforge.model.sparse_formats import expand_format

primitives = expand_format(self.format, num_ranks)
result = []
for p in primitives:
if p.upper() == "UOP" and self.uop_payload_word_bits is not None:
result.append(RankFormat(format=p, payload_word_bits=self.uop_payload_word_bits))
else:
result.append(RankFormat(format=p))
return result


class ActionOptimization(EvalableModel):
"""Storage action optimization at a memory level."""

kind: Literal["gating", "skipping", "position_skipping"]
""" Optimization type: gating (filter after access), skipping (skip access), or position_skipping (self-conditioned skip). """

target: str
""" Tensor whose read accesses are reduced. """

condition_on: list[str]
""" Tensors whose sparsity determines the filtering probability. Empty for position_skipping. """

def model_post_init(self, __context__=None) -> None:
if self.kind == "position_skipping" and self.condition_on:
raise ValueError(
f"position_skipping requires condition_on=[], "
f"got {self.condition_on!r}"
)

@property
def is_self_conditioned(self) -> bool:
"""True when the optimization is position-skipping (self-conditioned)."""
return self.kind == "position_skipping" and not self.condition_on


class ComputeOptimization(EvalableModel):
"""Compute-level optimization (gating or skipping at the MAC)."""

kind: Literal["gating", "skipping"]
""" Optimization type: gating (discard result) or skipping (skip entirely). """

target: str
""" Target tensor or operation name (e.g., Z, GEMM). """

condition_on: list[str]
""" Operand tensors for compute classification. """


class SparseTarget(EvalableModel):
"""Sparse optimization configuration for one hardware component."""

target: str
""" Component name from arch YAML (e.g., DRAM, Buffer, Reg, MAC). """

representation_format: EvalableList[RepresentationFormat] = EvalableList()
""" Compressed formats for tensors at this level. """

action_optimization: EvalableList[ActionOptimization] = EvalableList()
""" Storage action filtering optimizations at this level. """

compute_optimization: EvalableList[ComputeOptimization] = EvalableList()
""" Compute-level optimizations (only meaningful on Compute nodes). """


class SparseOptimizations(EvalableModel):
"""Top-level sparse optimizations specification."""

targets: EvalableList[SparseTarget] = EvalableList()
""" Per-component sparse optimization configurations. """

def get_targets_for(self, component_name: str) -> list[SparseTarget]:
"""Return all SparseTarget entries matching a component name."""
return [t for t in self.targets if t.target == component_name]

def get_formats_for(
self, component_name: str, tensor_name: str
) -> list[RepresentationFormat]:
"""Return all RepresentationFormat entries for a (component, tensor) pair."""
results = []
for t in self.get_targets_for(component_name):
for rf in t.representation_format:
if rf.name == tensor_name:
results.append(rf)
return results

def get_action_optimizations_for(
self, component_name: str
) -> list[ActionOptimization]:
"""Return all ActionOptimization entries for a component."""
results = []
for t in self.get_targets_for(component_name):
results.extend(t.action_optimization)
return results

def get_compute_optimizations_for(
self, component_name: str
) -> list[ComputeOptimization]:
"""Return all ComputeOptimization entries for a component."""
results = []
for t in self.get_targets_for(component_name):
results.extend(t.compute_optimization)
return results

def has_format(self, component_name: str, tensor_name: str) -> bool:
"""True if the tensor has a compressed format at the component."""
return any(
rf.format is not None or rf.has_explicit_ranks()
for rf in self.get_formats_for(component_name, tensor_name)
)
Loading