Skip to content

Commit a235a5a

Browse files
committed
Collect empirical constraints
1 parent bee4c27 commit a235a5a

File tree

6 files changed

+412
-0
lines changed

6 files changed

+412
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use std::collections::BTreeMap;
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
/// "Constraints" that were inferred from execution statistics.
6+
#[derive(Serialize, Deserialize, Clone, Default)]
7+
pub struct EmpiricalConstraints {
8+
/// For each program counter, the range constraints for each column.
9+
/// The range might not hold in 100% of cases.
10+
pub column_ranges_by_pc: BTreeMap<u32, Vec<(u32, u32)>>,
11+
/// For each basic block (identified by its starting PC), the equivalence classes of columns.
12+
/// Each equivalence class is a list of (instruction index in block, column index).
13+
pub equivalence_classes_by_block: BTreeMap<u64, Vec<Vec<(usize, usize)>>>,
14+
}
15+
16+
/// Debug information mapping AIR ids to program counters and column names.
17+
#[derive(Serialize, Deserialize)]
18+
pub struct DebugInfo {
19+
/// Mapping from program counter to AIR id.
20+
pub air_id_by_pc: BTreeMap<u32, usize>,
21+
/// Mapping from AIR id to column names.
22+
pub column_names_by_air_id: BTreeMap<usize, Vec<String>>,
23+
}
24+
25+
#[derive(Serialize, Deserialize)]
26+
pub struct EmpiricalConstraintsJson {
27+
pub empirical_constraints: EmpiricalConstraints,
28+
pub debug_info: DebugInfo,
29+
}

autoprecompiles/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub mod adapter;
2626
pub mod blocks;
2727
pub mod bus_map;
2828
pub mod constraint_optimizer;
29+
pub mod empirical_constraints;
2930
pub mod evaluation;
3031
pub mod execution_profile;
3132
pub mod expression;
@@ -53,6 +54,8 @@ pub struct PowdrConfig {
5354
pub degree_bound: DegreeBound,
5455
/// The path to the APC candidates dir, if any.
5556
pub apc_candidates_dir_path: Option<PathBuf>,
57+
/// Whether to use optimistic precompiles.
58+
pub optimistic_precompiles: bool,
5659
}
5760

5861
impl PowdrConfig {
@@ -62,13 +65,19 @@ impl PowdrConfig {
6265
skip_autoprecompiles,
6366
degree_bound,
6467
apc_candidates_dir_path: None,
68+
optimistic_precompiles: false,
6569
}
6670
}
6771

6872
pub fn with_apc_candidates_dir<P: AsRef<Path>>(mut self, path: P) -> Self {
6973
self.apc_candidates_dir_path = Some(path.as_ref().to_path_buf());
7074
self
7175
}
76+
77+
pub fn with_optimistic_precompiles(mut self, optimistic: bool) -> Self {
78+
self.optimistic_precompiles = optimistic;
79+
self
80+
}
7281
}
7382

7483
#[derive(Debug, Clone, PartialEq, Hash, Eq, Serialize, Deserialize)]

cli-openvm/src/main.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ use metrics_tracing_context::{MetricsLayer, TracingContextLayer};
33
use metrics_util::{debugging::DebuggingRecorder, layers::Layer};
44
use openvm_sdk::StdIn;
55
use openvm_stark_sdk::bench::serialize_metric_snapshot;
6+
use powdr_autoprecompiles::empirical_constraints::EmpiricalConstraintsJson;
67
use powdr_autoprecompiles::pgo::{pgo_config, PgoType};
8+
use powdr_autoprecompiles::PowdrConfig;
79
use powdr_openvm::{compile_openvm, default_powdr_openvm_config, CompiledProgram, GuestOptions};
10+
use powdr_openvm::{detect_empirical_constraints, OriginalCompiledProgram};
811

912
#[cfg(feature = "metrics")]
1013
use openvm_stark_sdk::metrics_tracing::TimingMetricsLayer;
@@ -46,6 +49,12 @@ enum Commands {
4649
/// When `--pgo-mode cell`, the directory to persist all APC candidates + a metrics summary
4750
#[arg(long)]
4851
apc_candidates_dir: Option<PathBuf>,
52+
53+
/// If active, generates "optimistic" precompiles. Optimistic precompiles are smaller in size
54+
/// but may fail at runtime if the assumptions they make are violated.
55+
#[arg(long)]
56+
#[arg(default_value_t = false)]
57+
optimistic_precompiles: bool,
4958
},
5059

5160
Execute {
@@ -73,6 +82,12 @@ enum Commands {
7382
/// When `--pgo-mode cell`, the directory to persist all APC candidates + a metrics summary
7483
#[arg(long)]
7584
apc_candidates_dir: Option<PathBuf>,
85+
86+
/// If active, generates "optimistic" precompiles. Optimistic precompiles are smaller in size
87+
/// but may fail at runtime if the assumptions they make are violated.
88+
#[arg(long)]
89+
#[arg(default_value_t = false)]
90+
optimistic_precompiles: bool,
7691
},
7792

7893
Prove {
@@ -108,6 +123,12 @@ enum Commands {
108123
/// When `--pgo-mode cell`, the directory to persist all APC candidates + a metrics summary
109124
#[arg(long)]
110125
apc_candidates_dir: Option<PathBuf>,
126+
127+
/// If active, generates "optimistic" precompiles. Optimistic precompiles are smaller in size
128+
/// but may fail at runtime if the assumptions they make are violated.
129+
#[arg(long)]
130+
#[arg(default_value_t = false)]
131+
optimistic_precompiles: bool,
111132
},
112133
}
113134

@@ -135,15 +156,20 @@ fn run_command(command: Commands) {
135156
max_columns,
136157
input,
137158
apc_candidates_dir,
159+
optimistic_precompiles,
138160
} => {
139161
let mut powdr_config = default_powdr_openvm_config(autoprecompiles as u64, skip as u64);
140162
if let Some(apc_candidates_dir) = apc_candidates_dir {
141163
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
142164
}
165+
if optimistic_precompiles {
166+
powdr_config = powdr_config.with_optimistic_precompiles(true);
167+
}
143168
let guest_program = compile_openvm(&guest, guest_opts.clone()).unwrap();
144169
let execution_profile =
145170
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
146171

172+
maybe_compute_empirical_constraints(&guest_program, &powdr_config, stdin_from(input));
147173
let pgo_config = pgo_config(pgo, max_columns, execution_profile);
148174
let program =
149175
powdr_openvm::compile_exe(guest_program, powdr_config, pgo_config).unwrap();
@@ -159,12 +185,17 @@ fn run_command(command: Commands) {
159185
input,
160186
metrics,
161187
apc_candidates_dir,
188+
optimistic_precompiles,
162189
} => {
163190
let mut powdr_config = default_powdr_openvm_config(autoprecompiles as u64, skip as u64);
164191
if let Some(apc_candidates_dir) = apc_candidates_dir {
165192
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
166193
}
194+
if optimistic_precompiles {
195+
powdr_config = powdr_config.with_optimistic_precompiles(true);
196+
}
167197
let guest_program = compile_openvm(&guest, guest_opts.clone()).unwrap();
198+
maybe_compute_empirical_constraints(&guest_program, &powdr_config, stdin_from(input));
168199
let execution_profile =
169200
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
170201
let pgo_config = pgo_config(pgo, max_columns, execution_profile);
@@ -194,12 +225,17 @@ fn run_command(command: Commands) {
194225
input,
195226
metrics,
196227
apc_candidates_dir,
228+
optimistic_precompiles,
197229
} => {
198230
let mut powdr_config = default_powdr_openvm_config(autoprecompiles as u64, skip as u64);
199231
if let Some(apc_candidates_dir) = apc_candidates_dir {
200232
powdr_config = powdr_config.with_apc_candidates_dir(apc_candidates_dir);
201233
}
234+
if optimistic_precompiles {
235+
powdr_config = powdr_config.with_optimistic_precompiles(true);
236+
}
202237
let guest_program = compile_openvm(&guest, guest_opts).unwrap();
238+
maybe_compute_empirical_constraints(&guest_program, &powdr_config, stdin_from(input));
203239

204240
let execution_profile =
205241
powdr_openvm::execution_profile_from_guest(&guest_program, stdin_from(input));
@@ -261,3 +297,33 @@ pub fn run_with_metric_collection_to_file<R>(file: std::fs::File, f: impl FnOnce
261297
.unwrap();
262298
res
263299
}
300+
301+
fn maybe_compute_empirical_constraints(
302+
guest_program: &OriginalCompiledProgram,
303+
powdr_config: &PowdrConfig,
304+
stdin: StdIn,
305+
) {
306+
if !powdr_config.optimistic_precompiles {
307+
return;
308+
}
309+
310+
tracing::warn!(
311+
"Optimistic precompiles are not implemented yet. Computing empirical constraints..."
312+
);
313+
314+
let (empirical_constraints, debug_info) =
315+
detect_empirical_constraints(&guest_program, powdr_config.degree_bound, stdin);
316+
317+
if let Some(path) = &powdr_config.apc_candidates_dir_path {
318+
tracing::info!(
319+
"Saving empirical constraints debug info to {}/empirical_constraints.json",
320+
path.display()
321+
);
322+
let export = EmpiricalConstraintsJson {
323+
empirical_constraints: empirical_constraints.clone(),
324+
debug_info,
325+
};
326+
let json = serde_json::to_string_pretty(&export).unwrap();
327+
std::fs::write(path.join("empirical_constraints.json"), json).unwrap();
328+
}
329+
}

0 commit comments

Comments
 (0)