Skip to content

Commit

Permalink
Implement guardrails for Fibonacci benchmark utilities (#995)
Browse files Browse the repository at this point in the history
* centralize fib-related API

* wip compute_coeff

* compute the linear and angular coefficients

* fix structure

---------

Co-authored-by: Gabriel Barreto <[email protected]>
  • Loading branch information
arthurpaulino and gabriel-barrett authored Dec 21, 2023
1 parent 8f8165c commit 6af8086
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 102 deletions.
107 changes: 107 additions & 0 deletions benches/common/fib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Without this, code is considered dead unless used in all benchmark targets
#![allow(dead_code)]

use lurk::{
eval::lang::{Coproc, Lang},
field::LurkField,
lem::{
eval::{eval_step, evaluate_simple},
pointers::Ptr,
store::Store,
},
state::user_sym,
};

pub(crate) fn fib_expr<F: LurkField>(store: &Store<F>) -> Ptr {
let program = r#"
(letrec ((next (lambda (a b) (next b (+ a b))))
(fib (next 0 1)))
(fib))
"#;

store.read_with_default_state(program).unwrap()
}

const LIN_COEF: usize = 7;
const ANG_COEF: usize = 10;

// The env output in the `fib_frame`th frame of the above, infinite Fibonacci computation contains a binding of the
// nth Fibonacci number to `a`.
pub(crate) fn fib_frame(n: usize) -> usize {
LIN_COEF + ANG_COEF * n
}

// Set the limit so the last step will be filled exactly, since Lurk currently only pads terminal/error continuations.
pub(crate) fn fib_limit(n: usize, rc: usize) -> usize {
let frame = fib_frame(n);
rc * (frame / rc + usize::from(frame % rc != 0))
}

fn lurk_fib<F: LurkField>(store: &Store<F>, n: usize) -> Ptr {
let frame_idx = fib_frame(n);
let limit = frame_idx;
let fib_expr = fib_expr(store);

let (output, ..) = evaluate_simple::<F, Coproc<F>>(None, fib_expr, store, limit).unwrap();

let target_env = &output[1];

// The result is the value of the second binding (of `a`), in the target env.
// See relevant excerpt of execution trace below:
//
// INFO lurk::lem::eval: Frame: 7
// Expr: (.lurk.user.next .lurk.user.b (+ .lurk.user.a .lurk.user.b))
// Env: ((.lurk.user.b . 1) (.lurk.user.a . 0) ((.lurk.user.next . <FUNCTION (.lurk.user.a .lurk.user.b) (.lurk.user.next .lurk.user.b (+ .lurk.user.a .lurk.user.b))>)))
// Cont: LetRec{ var: .lurk.user.fib,
// saved_env: (((.lurk.user.next . <FUNCTION (.lurk.user.a .lurk.user.b) (.lurk.user.next .lurk.user.b (+ .lurk.user.a .lurk.user.b))>))),
// body: (.lurk.user.fib), continuation: Outermost }

let (_, rest_bindings) = store.car_cdr(target_env).unwrap();
let (second_binding, _) = store.car_cdr(&rest_bindings).unwrap();
store.car_cdr(&second_binding).unwrap().1
}

// Returns the linear and angular coefficients for the iteration count of fib
fn compute_coeffs<F: LurkField>(store: &Store<F>) -> (usize, usize) {
let mut input = vec![fib_expr(store), store.intern_nil(), store.cont_outermost()];
let lang: Lang<F, Coproc<F>> = Lang::new();
let mut coef_lin = 0;
let coef_ang;
let step_func = eval_step();
let mut iteration = 0;
loop {
if let Some((elts, _)) = store.fetch_list(&input[0]) {
if store.fetch_symbol(&elts[0]) == Some(user_sym("next"))
&& store.fetch_symbol(&elts[1]) == Some(user_sym("b"))
{
if coef_lin == 0 {
// first occurrence of `(next b ...)`
coef_lin = iteration;
} else {
// second occurrence of `(next b ...)`
coef_ang = iteration - coef_lin;
break;
}
}
}
let frame = step_func.call_simple(&input, store, &lang, 0).unwrap();
input = frame.output.clone();
iteration += 1;
}
(coef_lin, coef_ang)
}

pub(crate) fn test_coeffs() {
let store = Store::<pasta_curves::Fq>::default();
assert_eq!(compute_coeffs(&store), (LIN_COEF, ANG_COEF));
}

pub(crate) fn test_fib_io_matches() {
let store = Store::<pasta_curves::Fq>::default();
let fib_9 = store.num_u64(34);
let fib_10 = store.num_u64(55);
let fib_11 = store.num_u64(89);
assert_eq!(fib_9, lurk_fib(&store, 9));
assert_eq!(fib_10, lurk_fib(&store, 10));
assert_eq!(fib_11, lurk_fib(&store, 11));
}
2 changes: 2 additions & 0 deletions benches/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) mod fib;

use camino::Utf8PathBuf;
use lurk::cli::paths::lurk_default_dir;
use lurk::config::lurk_config;
Expand Down
52 changes: 14 additions & 38 deletions benches/fibonacci.rs
Original file line number Diff line number Diff line change
@@ -1,51 +1,29 @@
use std::{cell::RefCell, rc::Rc, sync::Arc, time::Duration};

use anyhow::anyhow;
use criterion::{
black_box, criterion_group, criterion_main, measurement, BatchSize, BenchmarkGroup,
BenchmarkId, Criterion, SamplingMode,
};

use pasta_curves::pallas;
use std::{sync::Arc, time::Duration};

use lurk::{
eval::lang::{Coproc, Lang},
field::LurkField,
lem::{eval::evaluate, multiframe::MultiFrame, pointers::Ptr, store::Store},
lem::{eval::evaluate, multiframe::MultiFrame, store::Store},
proof::nova::NovaProver,
proof::Prover,
public_parameters::{
instance::{Instance, Kind},
public_params,
},
state::State,
};

mod common;
use common::set_bench_config;

fn fib<F: LurkField>(store: &Store<F>, state: Rc<RefCell<State>>, _a: u64) -> Ptr {
let program = r#"
(letrec ((next (lambda (a b) (next b (+ a b))))
(fib (next 0 1)))
(fib))
"#;

store.read(state, program).unwrap()
}

// The env output in the `fib_frame`th frame of the above, infinite Fibonacci computation will contain a binding of the
// nth Fibonacci number to `a`.
// means of computing it.]
fn fib_frame(n: usize) -> usize {
11 + 10 * n
}
use common::{
fib::{fib_expr, fib_frame, fib_limit},
set_bench_config,
};

// Set the limit so the last step will be filled exactly, since Lurk currently only pads terminal/error continuations.
fn fib_limit(n: usize, rc: usize) -> usize {
let frame = fib_frame(n);
rc * (frame / rc + usize::from(frame % rc != 0))
}
use crate::common::fib::{test_coeffs, test_fib_io_matches};

#[derive(Clone, Debug, Copy)]
struct ProveParams {
Expand Down Expand Up @@ -105,7 +83,6 @@ fn noise_threshold_env() -> anyhow::Result<f64> {
fn fibonacci_prove<M: measurement::Measurement>(
prove_params: ProveParams,
c: &mut BenchmarkGroup<'_, M>,
state: &Rc<RefCell<State>>,
) {
let limit = fib_limit(prove_params.fib_n, prove_params.reduction_count);
let lang_pallas = Lang::<pallas::Scalar, Coproc<pallas::Scalar>>::new();
Expand Down Expand Up @@ -133,11 +110,7 @@ fn fibonacci_prove<M: measurement::Measurement>(
|b, prove_params| {
let store = Store::default();

let ptr = fib::<pasta_curves::Fq>(
&store,
state.clone(),
black_box(prove_params.fib_n as u64),
);
let ptr = fib_expr::<pasta_curves::Fq>(&store);
let prover = NovaProver::new(prove_params.reduction_count, lang_rc.clone());

let frames =
Expand All @@ -157,16 +130,19 @@ fn fibonacci_prove<M: measurement::Measurement>(
}

fn fibonacci_benchmark(c: &mut Criterion) {
// Running tests to make sure the constants are correct
test_coeffs();
test_fib_io_matches();

// Uncomment to record the logs. May negatively impact performance
//tracing_subscriber::fmt::init();
set_bench_config();

tracing::debug!("{:?}", lurk::config::LURK_CONFIG);

let reduction_counts = rc_env().unwrap_or_else(|_| vec![100]);
let batch_sizes = [100, 200];

let state = State::init_lurk_state().rccell();

for reduction_count in reduction_counts.iter() {
let mut group: BenchmarkGroup<'_, _> =
c.benchmark_group(format!("LEM Fibonacci Prove - rc = {}", reduction_count));
Expand All @@ -181,7 +157,7 @@ fn fibonacci_benchmark(c: &mut Criterion) {
date: env!("VERGEN_GIT_COMMIT_DATE"),
sha: env!("VERGEN_GIT_SHA"),
};
fibonacci_prove(prove_params, &mut group, &state);
fibonacci_prove(prove_params, &mut group);
}
}
}
Expand Down
64 changes: 0 additions & 64 deletions examples/fibonacci.rs

This file was deleted.

1 comment on commit 6af8086

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Fibonacci GPU benchmark.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
125.78 GB RAM
Workflow run: https://github.com/lurk-lab/lurk-rs/actions/runs/7294014356

Benchmark Results

LEM Fibonacci Prove - rc = 100

fib-ref=8f8165c42e7f385d1b3f9a42dcb4cbaa6656d7a7 fib-ref=6af808640caa7a23bfaae652b1af33470f5e7cb9
num-100 2.37 s (✅ 1.00x) 2.36 s (✅ 1.00x faster)
num-200 4.63 s (✅ 1.00x) 4.61 s (✅ 1.00x faster)

LEM Fibonacci Prove - rc = 600

fib-ref=8f8165c42e7f385d1b3f9a42dcb4cbaa6656d7a7 fib-ref=6af808640caa7a23bfaae652b1af33470f5e7cb9
num-100 1.99 s (✅ 1.00x) 1.99 s (✅ 1.00x faster)
num-200 4.50 s (✅ 1.00x) 4.49 s (✅ 1.00x faster)

Made with criterion-table

Please sign in to comment.