Skip to content
Draft
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
40 changes: 36 additions & 4 deletions .github/workflows/profile-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ jobs:
# Cases are split across parallel jobs. Merge-base baseline policy lives in
# `scripts/profile_bench_merge_base_policy.py`: mode-name check, optional smoke
# run, then interleaved benchmark only when merge-base can complete every case.
# Each job also compiles only the profile-ci modes its own cases need (via
# `pcs_mode_features`), so the split doubles as the compile-time boundary:
# fp128 dense/tensor root-fold tracking gets its own job each, flat one-hot
# coverage gets one job per field type (fp32/fp64/fp128) since each field
# type pays its own fixed monomorphization cost regardless of mode count,
# and distributed multi-chunk coverage gets a final parallel group.
# `report` then concatenates per-job summaries.
bench:
name: Bench (${{ matrix.group.name }})
runs-on: GitHubRunner-Large-Public
Expand Down Expand Up @@ -76,19 +83,29 @@ jobs:
# recursive flat folds.
group:
- name: 1-fp128-dense
pcs_mode_features: mode-dense-fp128-d64
cases: |
dense_fp128_d64:24:1
- name: 2-fp128-tensor
pcs_mode_features: mode-onehot-fp128-d64-tensor
cases: |
onehot_fp128_d64_tensor:26:1
- name: 3-flat-onehot-suite
- name: 3-flat-fp32-onehot
pcs_mode_features: mode-onehot-fp32-d128
cases: |
onehot_fp32_d128:28:1
- name: 4-flat-fp64-onehot
pcs_mode_features: mode-onehot-fp64-d128
cases: |
onehot_fp64_d128:28:1
- name: 5-flat-fp128-onehot
pcs_mode_features: mode-onehot-fp128-d64
cases: |
onehot_fp128_d64:32:1
onehot_fp128_d64:32:1:recursive
onehot_fp128_d64:30:4
- name: 4-distributed
- name: 6-distributed
pcs_mode_features: mode-onehot-fp128-d64-multi-chunk-w2r2,mode-onehot-fp128-d64-multi-chunk-w4r2,mode-onehot-fp128-d64-multi-chunk-w8r2
cases: |
onehot_fp128_d64_multi_chunk_w2r2:32:1
onehot_fp128_d64_multi_chunk_w4r2:32:1
Expand All @@ -110,6 +127,7 @@ jobs:
echo "AKITA_BENCH_SOURCE_BRANCH=${{ github.head_ref || github.ref_name }}" >> "$GITHUB_ENV"
echo "AKITA_BENCH_BASE_REF=" >> "$GITHUB_ENV"
echo "AKITA_BENCH_MERGE_BASE_SHA=" >> "$GITHUB_ENV"
echo "AKITA_BENCH_PCS_MODE_FEATURES=${{ matrix.group.pcs_mode_features }}" >> "$GITHUB_ENV"

- name: Determine PR benchmark merge base
if: github.event_name == 'pull_request'
Expand Down Expand Up @@ -187,7 +205,20 @@ jobs:
mkdir -p "$RUNNER_TEMP/bench-bins"
(
cd "$RUNNER_TEMP/bench-base" &&
if python3 scripts/cargo_feature_exists.py akita-pcs profile-ci; then
# 3-tier fallback so a merge-base commit that predates this PR's
# per-mode features still builds a usable (if slower) baseline:
# 1) merge-base already has the specific mode features (steady
# state) -> fast, narrow build.
# 2) merge-base has profile-ci but not yet the per-mode split
# (the PR introducing this split) -> slow, full-8-mode build.
# 3) merge-base predates profile-ci entirely -> default-features
# build, same as before this change.
if python3 scripts/cargo_feature_exists.py akita-pcs profile-ci-registry; then
CARGO_TARGET_DIR="$RUNNER_TEMP/bench-base-target" \
cargo build --release --quiet --example profile \
--no-default-features \
--features "parallel,profile-ci-registry,$AKITA_BENCH_PCS_MODE_FEATURES"
elif python3 scripts/cargo_feature_exists.py akita-pcs profile-ci; then
CARGO_TARGET_DIR="$RUNNER_TEMP/bench-base-target" \
cargo build --release --quiet --example profile \
--no-default-features --features parallel,profile-ci
Expand Down Expand Up @@ -220,7 +251,8 @@ jobs:
- name: Build profile binary
run: |
cargo build --release --quiet --example profile \
--no-default-features --features parallel,profile-ci
--no-default-features \
--features "parallel,profile-ci-registry,$AKITA_BENCH_PCS_MODE_FEATURES"

- name: Verify profile-ci linkage isolation
run: ./scripts/check_profile_ci_linkage.sh target/release/examples/profile
Expand Down
35 changes: 29 additions & 6 deletions crates/akita-pcs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,38 @@ parallel = [
]
schedules-default = ["akita-config/schedules-default"]
profile-ci = [
"akita-config/schedules-fp32-d128-onehot",
"akita-config/schedules-fp64-d128-onehot",
"akita-config/schedules-fp128-d64-onehot",
"akita-config/schedules-fp128-d64-onehot-tensor",
"akita-config/schedules-fp128-d64-full",
"akita-config/schedules-fp128-d64-onehot-multi-chunk",
"profile-ci-registry",
"mode-dense-fp128-d64",
"mode-onehot-fp128-d64",
"mode-onehot-fp128-d64-tensor",
"mode-onehot-fp128-d64-multi-chunk-w2r2",
"mode-onehot-fp128-d64-multi-chunk-w4r2",
"mode-onehot-fp128-d64-multi-chunk-w8r2",
"mode-onehot-fp32-d128",
"mode-onehot-fp64-d128",
]
# Selects the CI mode registry in examples/profile/modes.rs (a curated,
# individually-gated subset) instead of the full local-dev registry. CI jobs
# enable this plus only the `mode-*` features their matrix cases exercise, so
# unused generic prover/verifier instantiations are never monomorphized.
profile-ci-registry = []
# Each mirrors one CI profile mode in examples/profile/modes.rs. Forwards to
# the existing akita-config schedule-table feature so the mode's
# `CommitmentConfig::runtime_schedule` has data to look up.
mode-dense-fp128-d64 = ["akita-config/schedules-fp128-d64-full"]
mode-onehot-fp128-d64 = ["akita-config/schedules-fp128-d64-onehot"]
mode-onehot-fp128-d64-tensor = ["akita-config/schedules-fp128-d64-onehot-tensor"]
mode-onehot-fp128-d64-multi-chunk-w2r2 = [
"akita-config/schedules-fp128-d64-onehot-multi-chunk-w2r2",
]
mode-onehot-fp128-d64-multi-chunk-w4r2 = [
"akita-config/schedules-fp128-d64-onehot-multi-chunk-w4r2",
]
mode-onehot-fp128-d64-multi-chunk-w8r2 = [
"akita-config/schedules-fp128-d64-onehot-multi-chunk",
]
mode-onehot-fp32-d128 = ["akita-config/schedules-fp32-d128-onehot"]
mode-onehot-fp64-d128 = ["akita-config/schedules-fp64-d128-onehot"]
disk-persistence = ["akita-setup/disk-persistence"]
logging-transcript = [
"akita-transcript/logging-transcript",
Expand Down
127 changes: 76 additions & 51 deletions crates/akita-pcs/examples/profile/modes.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
// Under `profile-ci-registry`, `profile_modes()` only pushes a mode's wrapper
// function into the registry when that mode's own `mode-*` Cargo feature is
// enabled (see the per-`#[cfg(feature = "mode-*")]` pushes below). CI builds
// each matrix group with only the `mode-*` features its own bench cases need
// (`.github/workflows/profile-bench.yml`'s `pcs_mode_features`), so in any
// given narrow build most of the per-mode wrapper functions here — plus the
// per-field-type dispatch helpers and title/formatting helpers they alone
// call — have zero call sites and are genuinely (and correctly) dead for that
// specific feature combination, while remaining live for others. `-D
// warnings` (set globally in profile-bench.yml) promotes the warn-by-default
// `dead_code` lint to a hard error for exactly this reachability, which is a
// property of the *feature selection*, not of the code being actually
// unused. Allow it file-wide here rather than annotate each of the many
// affected items individually; this file is example-only tooling, not
// library code, and the umbrella `profile-ci` build (which enables every
// `mode-*` feature and therefore populates the registry fully) still exposes
// any items that are dead for reasons unrelated to this feature-gating.
#![allow(dead_code)]

use crate::report::print_layout;
use crate::workload::{onehot_k_for_num_vars, run_batched_onehot, run_dense_for, run_onehot};
use akita_config::proof_optimized::{fp128, fp32, fp64};
Expand Down Expand Up @@ -42,7 +61,7 @@ fn run_dense_mode<const D: usize, Cfg: CommitmentConfig<Field = F, ExtField = F>
run_dense_for::<F, D, Cfg>(label, nv, &layout, Some(&plan));
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_dense_mode_for<FF, const D: usize, Cfg: CommitmentConfig<Field = FF>>(
label: &str,
title: &str,
Expand Down Expand Up @@ -156,48 +175,13 @@ fn run_onehot_mode<const D: usize, Cfg: CommitmentConfig<Field = F, ExtField = F

type ProfileModeRunner = fn(usize, usize);

#[derive(Clone, Copy)]
struct ProfileMode {
name: &'static str,
run: ProfileModeRunner,
}

#[cfg(feature = "profile-ci")]
const PROFILE_CI_MODES: &[ProfileMode] = &[
ProfileMode {
name: "dense_fp128_d64",
run: run_profile_dense_fp128_d64,
},
ProfileMode {
name: "onehot_fp128_d64",
run: run_profile_onehot_fp128_d64,
},
ProfileMode {
name: "onehot_fp128_d64_tensor",
run: run_profile_onehot_fp128_d64_tensor,
},
ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w2r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w2r2,
},
ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w4r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w4r2,
},
ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w8r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w8r2,
},
ProfileMode {
name: "onehot_fp32_d128",
run: run_profile_onehot_fp32_d128,
},
ProfileMode {
name: "onehot_fp64_d128",
run: run_profile_onehot_fp64_d128,
},
];

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
const PROFILE_ALL_MODES: &[ProfileMode] = &[
ProfileMode {
name: "dense_fp128_d64",
Expand Down Expand Up @@ -261,14 +245,55 @@ const PROFILE_ALL_MODES: &[ProfileMode] = &[
},
];

fn profile_modes() -> &'static [ProfileMode] {
#[cfg(feature = "profile-ci")]
fn profile_modes() -> Vec<ProfileMode> {
#[cfg(feature = "profile-ci-registry")]
{
PROFILE_CI_MODES
let mut modes = Vec::new();
#[cfg(feature = "mode-dense-fp128-d64")]
modes.push(ProfileMode {
name: "dense_fp128_d64",
run: run_profile_dense_fp128_d64,
});
#[cfg(feature = "mode-onehot-fp128-d64")]
modes.push(ProfileMode {
name: "onehot_fp128_d64",
run: run_profile_onehot_fp128_d64,
});
#[cfg(feature = "mode-onehot-fp128-d64-tensor")]
modes.push(ProfileMode {
name: "onehot_fp128_d64_tensor",
run: run_profile_onehot_fp128_d64_tensor,
});
#[cfg(feature = "mode-onehot-fp128-d64-multi-chunk-w2r2")]
modes.push(ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w2r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w2r2,
});
#[cfg(feature = "mode-onehot-fp128-d64-multi-chunk-w4r2")]
modes.push(ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w4r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w4r2,
});
#[cfg(feature = "mode-onehot-fp128-d64-multi-chunk-w8r2")]
modes.push(ProfileMode {
name: "onehot_fp128_d64_multi_chunk_w8r2",
run: run_profile_onehot_fp128_d64_multi_chunk_w8r2,
});
#[cfg(feature = "mode-onehot-fp32-d128")]
modes.push(ProfileMode {
name: "onehot_fp32_d128",
run: run_profile_onehot_fp32_d128,
});
#[cfg(feature = "mode-onehot-fp64-d128")]
modes.push(ProfileMode {
name: "onehot_fp64_d128",
run: run_profile_onehot_fp64_d128,
});
modes
}
#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
{
PROFILE_ALL_MODES
PROFILE_ALL_MODES.to_vec()
}
}

Expand Down Expand Up @@ -329,7 +354,7 @@ fn small_field_onehot_title(field_label: &str, d: usize, nv: usize, num_polys: u
}
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn small_field_dense_title(field_label: &str, d: usize) -> String {
let schedule = small_field_schedule_source(d);
format!("=== dense_{field_label}_d{d} ({field_label}, D={d}, {schedule}) ===")
Expand Down Expand Up @@ -414,7 +439,7 @@ fn run_profile_onehot_fp128_d64_tensor(nv: usize, num_polys: usize) {
run_onehot_mode::<{ Cfg::D }, Cfg>("onehot_fp128_d64_tensor", &title, nv, num_polys);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_dense_fp128_d128(nv: usize, num_polys: usize) {
type Cfg = fp128::D128Full;
assert_singleton_mode("dense_fp128_d128", num_polys);
Expand All @@ -428,29 +453,29 @@ fn run_profile_dense_fp128_d128(nv: usize, num_polys: usize) {
);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_onehot_fp128_d128(nv: usize, num_polys: usize) {
type Cfg = fp128::D128OneHot;
let title = fp128_onehot_title(128, nv, num_polys);
run_onehot_mode::<{ Cfg::D }, Cfg>("onehot_fp128_d128", &title, nv, num_polys);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_onehot_fp32_d64(nv: usize, num_polys: usize) {
type Cfg = fp32::D64OneHot;
let title = small_field_onehot_title("fp32", Cfg::D, nv, num_polys);
run_onehot_mode_for::<fp32::Field, { Cfg::D }, Cfg>("onehot_fp32_d64", &title, nv, num_polys);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_dense_fp32_d64(nv: usize, num_polys: usize) {
type Cfg = fp32::D64Full;
assert_singleton_mode("dense_fp32_d64", num_polys);
let title = small_field_dense_title("fp32", Cfg::D);
run_dense_mode_for::<fp32::Field, { Cfg::D }, Cfg>("dense_fp32_d64", &title, nv);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_dense_fp32_d128(nv: usize, num_polys: usize) {
type Cfg = fp32::D128Full;
assert_singleton_mode("dense_fp32_d128", num_polys);
Expand All @@ -464,7 +489,7 @@ fn run_profile_onehot_fp32_d128(nv: usize, num_polys: usize) {
run_onehot_mode_for::<fp32::Field, { Cfg::D }, Cfg>("onehot_fp32_d128", &title, nv, num_polys);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_onehot_fp64_d64(nv: usize, num_polys: usize) {
type Cfg = fp64::D64OneHot;
let title = small_field_onehot_title("fp64", Cfg::D, nv, num_polys);
Expand All @@ -477,7 +502,7 @@ fn run_profile_onehot_fp64_d128(nv: usize, num_polys: usize) {
run_onehot_mode_for::<fp64::Field, { Cfg::D }, Cfg>("onehot_fp64_d128", &title, nv, num_polys);
}

#[cfg(not(feature = "profile-ci"))]
#[cfg(not(feature = "profile-ci-registry"))]
fn run_profile_dense_fp64_d64(nv: usize, num_polys: usize) {
type Cfg = fp64::D64Full;
assert_singleton_mode("dense_fp64_d64", num_polys);
Expand Down
10 changes: 10 additions & 0 deletions crates/akita-pcs/examples/profile/workload.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// See the matching comment in `modes.rs`: under `profile-ci-registry`,
// whether generic pipeline helpers here (e.g. `run_dense_for`, `run_onehot`,
// `run_batched_onehot`) and their small supporting helpers are reachable
// depends entirely on which `mode-*` Cargo features a given build enables,
// since `modes.rs`'s per-mode wrapper functions are their only call sites.
// `-D warnings` promotes that feature-combination-dependent `dead_code` warn
// into a hard error. Allow it file-wide rather than annotate each affected
// item; this is example-only tooling, not library code.
#![allow(dead_code)]

use crate::report::{
emit_proof_tail_report, emit_runtime_schedule_summary, observed_stage3_setup_product_bytes,
print_batched_proof_summary, report_crt_profile, report_setup_sizes, report_timing,
Expand Down
Loading
Loading