Skip to content
Open
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
18 changes: 18 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.git
.agents
.codex
.deps
.pytest_cache
.venv
__pycache__/
*.pyc
backend/lattigo/
frontend/dacapo/
frontend/log/
input_constants/
input_data/
mlirs_execute/
mlirs_output/
old_backup/
qbps_cache*/
repro_results/
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ qbps_cache*/
frontend/dacapo/
frontend/log/
backend/lattigo/
.venv/
.venv/
.deps/
repro_results/
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM python:3.11-slim

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1

RUN apt-get update && \
apt-get install -y --no-install-recommends \
bash \
build-essential \
ca-certificates \
clang \
cmake \
git \
golang-go \
lld \
ninja-build && \
rm -rf /var/lib/apt/lists/*

WORKDIR /opt/orbit

COPY requirements.txt requirements-dev.txt ./
RUN python -m pip install --upgrade pip && \
python -m pip install -r requirements-dev.txt

ARG USER_ID=1000
ARG GROUP_ID=1000
RUN groupadd --gid "${GROUP_ID}" orbit && \
useradd --uid "${USER_ID}" --gid "${GROUP_ID}" --create-home --shell /bin/bash orbit

COPY . .
RUN chmod +x scripts/reproduce.sh scripts/setup_dependencies.sh && \
chown -R orbit:orbit /opt/orbit

USER orbit

CMD ["./scripts/reproduce.sh", "quick"]
134 changes: 133 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,146 @@ Run the following commands to install them:
pip install -r requirements.txt
```

For `gurobipy`, you have to apply for a Gurobi license. It is free to apply for an unlimited-use Gurobi Optimizer license for academic use.
Orbit uses Gurobi (`gurobipy`) to solve its ILPs. The `gurobipy` wheel ships a bundled size-limited license that is sufficient for every partitioned benchmark, so most runs need no extra setup. Only the `--nopart` configurations build a single large ILP that exceeds the size-limited cap; for those, apply for a free unlimited-use Gurobi Optimizer license for academic use and point `GRB_LICENSE_FILE` at it.

### Frontend and Backend

Orbit uses Dacapo's frontend interface and Lattigo as backend. To evaluate the compiled MLIR files, it is necessary to install the *backend*. As the plaintext files for evaluation are too large (in GBs), it is necessary to install the *frontend* to generate such files. **If you are satisfied with estimated evaluation results, it is NOT necessary to install the frontend and backend.**

Check `frontend/README.md` and `backend/README.md` for installation instructions.

### Docker and reproducibility scripts

The repository ships a `Dockerfile` that provides a self-contained Python
environment for running the checked-in tests and the compilation benchmarks.
It uses Gurobi's bundled size-limited license, so no academic license is
required for the standard (partitioned) benchmarks.

#### 1. Build the image

```bash
docker build \
--build-arg USER_ID="$(id -u)" \
--build-arg GROUP_ID="$(id -g)" \
-t orbit:dev .
```

The `USER_ID`/`GROUP_ID` build args make the in-container `orbit` user match
your host user, so files written to mounted volumes are owned by you. Building
only creates the image; it does not run anything yet.

#### 2. Run the container (auto-runs the quick check)

The image's default command is `./scripts/reproduce.sh quick`, so starting a
container with no extra arguments runs `pytest` plus a smoke compilation of
`mlirs_input/motivation.mlir` with the toy cost model. Mount `repro_results/`
and `mlirs_output/` to keep the logs and compiled MLIR on the host:

```bash
mkdir -p repro_results mlirs_output
docker run --rm \
-v "$PWD/repro_results:/opt/orbit/repro_results" \
-v "$PWD/mlirs_output:/opt/orbit/mlirs_output" \
orbit:dev
```

Results are written under `repro_results/<timestamp>/summary.txt`.

#### 3. Run other modes

Override the default command to run any other `reproduce.sh` mode in the
container, for example:

```bash
docker run --rm \
-v "$PWD/repro_results:/opt/orbit/repro_results" \
-v "$PWD/mlirs_output:/opt/orbit/mlirs_output" \
orbit:dev ./scripts/reproduce.sh compile-base
```

Available modes:

```text
quick pytest + motivation smoke compile (default)
tests pytest only
benchmark-smoke compile mlirs_input/motivation.mlir
compile-base base configuration suite (n=64k, Lm=16, Sw=40)
compile-16k n=16k configuration suite
compile-lm12 Lm=12 configuration suite
compile-sw51 Sw=51 configuration suite
compile-sim-vari simulated-variadic cost-model suite
compile-micro-comppart compression/partitioning micro suite
compile-micro-bypass bypass-handling micro suite
compile-micro-reqbp cross-benchmark QBP-reuse micro suite
compile-all every suite above
```

Set `ORBIT_THREADS` to control the solver thread count (default 2), e.g.
`docker run ... orbit:dev env ORBIT_THREADS=8 ./scripts/reproduce.sh compile-base`.

#### Gurobi license

Orbit solves its ILPs with Gurobi (`gurobipy`). Because Orbit partitions each
problem into small per-partition ILPs, every partitioned benchmark fits within
Gurobi's bundled **size-limited license** and runs without an academic license.
Only the `--nopart` configurations (partitioning disabled) build a single large
ILP that exceeds the size-limited cap and therefore require a full/academic
Gurobi license. To use an academic license, mount your `gurobi.lic` into the
container and point `GRB_LICENSE_FILE` at it:

```bash
docker run --rm \
-v "$HOME/gurobi.lic:/opt/orbit/gurobi.lic:ro" \
-e GRB_LICENSE_FILE=/opt/orbit/gurobi.lic \
-v "$PWD/repro_results:/opt/orbit/repro_results" \
-v "$PWD/mlirs_output:/opt/orbit/mlirs_output" \
orbit:dev ./scripts/reproduce.sh compile-micro-comppart
```

#### Execution (optional)

The container is compile-and-estimate by default. To actually **execute** a
compiled MLIR under FHE you need the Lattigo backend plus data generated by the
Dacapo frontend; neither is baked into the image (the frontend in particular
builds LLVM/MLIR and SEAL from source, so it is large and long-running). The
full chain is:

```bash
# 1. Build the Lattigo backend (network required). Mount the repo so the build
# persists on the host; you only do this once.
docker run --rm -v "$PWD:/opt/orbit" -e HOME=/tmp \
orbit:dev ./scripts/setup_dependencies.sh backend

# 2. Build the Dacapo frontend and generate the execution data. This produces
# input_constants/<bench>_hecate.cst and input_data/<n>k/<model>/<act>/...
# The MLIR inputs in mlirs_input/ are already checked in; this step adds the
# plaintext constants and the CIFAR-10 samples (GBs) that are not committed.
docker run --rm -v "$PWD:/opt/orbit" -e HOME=/tmp \
orbit:dev ./scripts/setup_dependencies.sh frontend
docker run --rm -v "$PWD:/opt/orbit" -e HOME=/tmp -w /opt/orbit/frontend/dacapo \
orbit:dev bash -c '../dacapo_patch/gen_all_mlirs.sh && python3 examples/tests/gen_input_data.py 10'

# 3. Evaluate a compiled benchmark through the backend. The MLIR is compiled on
# demand for the default configuration if it does not already exist.
docker run --rm -v "$PWD:/opt/orbit" -e HOME=/tmp \
-v "$PWD/mlirs_execute:/opt/orbit/mlirs_execute" \
orbit:dev ./scripts/reproduce.sh execute \
--model ResNet --act SiLU --n 64 --Lm 16 --Sw 40 --run 0
```

`execute` accepts `--model --act --n --Lm --Sw` (required) and optional
`--run <id>`, `--cmt <comment>`, `--Csw <scale>`, and `--plain` (plaintext mode).
It fails fast with the exact missing paths if the backend or the
`input_data/`/`input_constants/` files are absent. Results are written under
`mlirs_execute/orbit/<n>/<model>/<act>/`. See `frontend/README.md` and
`backend/README.md` for full details.

If you only need the backend toolchain (e.g. data is already present):

```bash
./scripts/setup_dependencies.sh backend
```

## Usage

### Compilation on one benchmark
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ numpy==1.25.2
matplotlib==3.8.1
more-itertools==8.10.0
joblib==1.5.1
gurobipy==12.0.2
pulp>=2.7.0
gurobipy==12.0.2
89 changes: 89 additions & 0 deletions scripts/gurobi_license_sweep.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Sweep every micro/macro benchmark with the size-limited (non-academic) Gurobi
# license and record which ones fail because a partition exceeds the limit.
#
# Classification (per config):
# PASS run_orbit.py exited 0 (.mlir produced)
# LICENSE_FAIL solver hit the size-limited license error (model too large)
# TIMEOUT did not finish within PER_TASK_TIMEOUT (slow, NOT a license issue)
# ERROR(n) other non-zero exit
set -u

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

OUT="${ORBIT_RESULTS_DIR:-repro_results}/gurobi_sweep"
mkdir -p "$OUT"
RES="$OUT/results.tsv"
: > "$RES"
PER_TASK_TIMEOUT="${PER_TASK_TIMEOUT:-1800}"
TASK_THREADS="${TASK_THREADS:-4}"
PARALLEL="${PARALLEL:-12}"

run() {
local label="$1"; shift
local log="$OUT/${label}.log"
local start end code verdict
start=$(date +%s)
timeout "$PER_TASK_TIMEOUT" python3 scripts/optimizer/orbit/run_orbit.py "$@" \
--threads "$TASK_THREADS" >"$log" 2>&1
code=$?
end=$(date +%s)
if [ "$code" -eq 0 ]; then
verdict="PASS"
elif grep -qiE 'too large for size-limited|size-limited license|exceeds the limit' "$log"; then
verdict="LICENSE_FAIL"
elif [ "$code" -eq 124 ]; then
verdict="TIMEOUT"
else
verdict="ERROR($code)"
fi
printf '%s\t%s\t%ss\n' "$label" "$verdict" "$((end-start))" >> "$RES"
}
export -f run
export OUT RES PER_TASK_TIMEOUT TASK_THREADS ROOT

# Build the full job list: "label -- args..."
jobs_file="$OUT/jobs.txt"
: > "$jobs_file"
emit() { printf '%s\n' "$*" >> "$jobs_file"; }

for m in AlexNet MobileNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "base_${m}_${a} -- --model $m --act $a --n 64 --Lm 16 --Sw 40"
done; done
for m in AlexNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "16k_${m}_${a} -- --model $m --act $a --n 16 --Lm 16 --Sw 40"
done; done
for m in AlexNet MobileNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "lm12_${m}_${a} -- --model $m --act $a --n 64 --Lm 12 --Sw 40"
done; done
for m in AlexNet MobileNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "sw51_${m}_${a} -- --model $m --act $a --n 64 --Lm 16 --Sw 51"
done; done
for m in AlexNet MobileNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "simvari_${m}_${a} -- --model $m --act $a --n 64 --Lm 16 --Sw 40 --sim-vari"
done; done
emit "micro-comppart_comp_part -- --model CompPart --act SiLU --n 64 --Lm 16 --Sw 40"
emit "micro-comppart_comp_nopart -- --model CompPart --act SiLU --n 64 --Lm 16 --Sw 40 --nopart"
emit "micro-comppart_nocomp_part -- --model CompPart --act SiLU --n 64 --Lm 16 --Sw 40 --nocomp"
emit "micro-comppart_nocomp_nopart -- --model CompPart --act SiLU --n 64 --Lm 16 --Sw 40 --nocomp --nopart"
emit "micro-bypass_ResNet_ReLU_64 -- --model ResNet --act ReLU --n 64 --Lm 16 --Sw 40 --nobypass"
emit "micro-bypass_ResNet_SiLU_64 -- --model ResNet --act SiLU --n 64 --Lm 16 --Sw 40 --nobypass"
emit "micro-bypass_ResNet_SiLU_16 -- --model ResNet --act SiLU --n 16 --Lm 16 --Sw 40 --nobypass"
emit "micro-bypass_ResNet_ReLU_16 -- --model ResNet --act ReLU --n 16 --Lm 16 --Sw 40 --nobypass"
for m in AlexNet SqueezeNet VGG16 ResNet; do for a in SiLU ReLU; do
emit "micro-reqbp_${m}_${a} -- --model $m --act $a --n 16 --Lm 16 --Sw 40 --qbp"
done; done

echo "Total jobs: $(wc -l < "$jobs_file"), parallelism: $PARALLEL, threads/task: $TASK_THREADS, timeout: ${PER_TASK_TIMEOUT}s"

# Run in parallel. Each line: "label -- args"
cat "$jobs_file" | xargs -P "$PARALLEL" -I {} bash -c '
line="{}"
label="${line%% -- *}"
args="${line#* -- }"
run "$label" $args
'

echo "=== DONE. $(wc -l < "$RES") results in $RES ==="
sort "$RES"
Loading