diff --git a/README.md b/README.md index 69167e0716..e418107406 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ minor version bump. `halo2` currently uses [rayon](https://github.com/rayon-rs/rayon) for parallel computation. The `RAYON_NUM_THREADS` environment variable can be used to set the number of threads. +You can disable `rayon` by disabling the `"multicore"` feature. +Warning! Halo2 will lose access to parallelism if you disable the `"multicore"` feature. +This will significantly degrade performance. + ## License Licensed under either of diff --git a/halo2/Cargo.toml b/halo2/Cargo.toml index 7a6bbaa94f..ba934102b6 100644 --- a/halo2/Cargo.toml +++ b/halo2/Cargo.toml @@ -19,7 +19,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] [dependencies] -halo2_proofs = { version = "0.2", path = "../halo2_proofs" } +halo2_proofs = { version = "0.2", path = "../halo2_proofs", default-features = false } [lib] bench = false diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 58b9ffff72..14e562ff81 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -26,7 +26,7 @@ arrayvec = "0.7.0" bitvec = "1" ff = { version = "0.13", features = ["bits"] } group = "0.13" -halo2_proofs = { version = "0.2", path = "../halo2_proofs" } +halo2_proofs = { version = "0.2", path = "../halo2_proofs", default-features = false } lazy_static = "1" halo2curves = { version = "0.1.0" } proptest = { version = "1.0.0", optional = true } @@ -35,7 +35,7 @@ subtle = "2.3" uint = "0.9.2" # MSRV 1.56.1 # Developer tooling dependencies -plotters = { version = "0.3.0", optional = true } +plotters = { version = "0.3.0", default-features = false, optional = true } [dev-dependencies] criterion = "0.3" @@ -48,7 +48,12 @@ pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 bench = false [features] -dev-graph = ["halo2_proofs/dev-graph", "plotters"] +test-dev-graph = [ + "halo2_proofs/dev-graph", + "plotters", + "plotters/bitmap_backend", + "plotters/bitmap_encoder", +] circuit-params = ["halo2_proofs/circuit-params"] test-dependencies = ["proptest"] unstable = [] diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs index 05ea999053..8d71db8580 100644 --- a/halo2_gadgets/src/ecc.rs +++ b/halo2_gadgets/src/ecc.rs @@ -903,7 +903,7 @@ pub(crate) mod tests { assert_eq!(prover.verify(), Ok(())) } - #[cfg(feature = "dev-graph")] + #[cfg(feature = "test-dev-graph")] #[test] fn print_ecc_chip() { use plotters::prelude::*; diff --git a/halo2_gadgets/src/poseidon/pow5.rs b/halo2_gadgets/src/poseidon/pow5.rs index e8ea7abf69..0fb37994e5 100644 --- a/halo2_gadgets/src/poseidon/pow5.rs +++ b/halo2_gadgets/src/poseidon/pow5.rs @@ -869,7 +869,7 @@ mod tests { } } - #[cfg(feature = "dev-graph")] + #[cfg(feature = "test-dev-graph")] #[test] fn print_poseidon_chip() { use plotters::prelude::*; diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs index 76b8e3476f..4781d82f64 100644 --- a/halo2_gadgets/src/sha256/table16.rs +++ b/halo2_gadgets/src/sha256/table16.rs @@ -450,7 +450,7 @@ trait Table16Assignment { } #[cfg(test)] -#[cfg(feature = "dev-graph")] +#[cfg(feature = "test-dev-graph")] mod tests { use super::super::{Sha256, BLOCK_SIZE}; use super::{message_schedule::msg_schedule_test_input, Table16Chip, Table16Config}; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 543d49f55f..48b929cbeb 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -739,7 +739,7 @@ pub(crate) mod tests { assert_eq!(prover.verify(), Ok(())) } - #[cfg(feature = "dev-graph")] + #[cfg(feature = "test-dev-graph")] #[test] fn print_sinsemilla_chip() { use plotters::prelude::*; diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs index 219a9025af..47e5c953e3 100644 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ b/halo2_gadgets/src/sinsemilla/merkle.rs @@ -382,7 +382,7 @@ pub mod tests { assert_eq!(prover.verify(), Ok(())) } - #[cfg(feature = "dev-graph")] + #[cfg(feature = "test-dev-graph")] #[test] fn print_merkle_chip() { use plotters::prelude::*; diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index fb1ce59eb2..3328f67e6d 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -49,7 +49,6 @@ harness = false [dependencies] backtrace = { version = "0.3", optional = true } -rayon = "1.5.1" ff = "0.13" group = "0.13" halo2curves = { version = "0.1.0" } @@ -58,9 +57,10 @@ tracing = "0.1" blake2b_simd = "1" sha3 = "0.9.1" rand_chacha = "0.3" +maybe-rayon = { version = "0.1.0", default-features = false } # Developer tooling dependencies -plotters = { version = "0.3.0", optional = true } +plotters = { version = "0.3.0", default-features = false, optional = true } tabbycat = { version = "0.1", features = ["attributes"], optional = true } [dev-dependencies] @@ -74,8 +74,14 @@ rand_core = { version = "0.6", default-features = false, features = ["getrandom" getrandom = { version = "0.2", features = ["js"] } [features] -default = ["batch"] +default = ["batch", "multicore"] +multicore = ["maybe-rayon/threads"] dev-graph = ["plotters", "tabbycat"] +test-dev-graph = [ + "dev-graph", + "plotters/bitmap_backend", + "plotters/bitmap_encoder", +] gadget-traces = ["backtrace"] thread-safe-region = [] sanity-checks = [] @@ -87,6 +93,4 @@ bench = false [[example]] name = "circuit-layout" -required-features = ["dev-graph"] - - +required-features = ["test-dev-graph"] diff --git a/halo2_proofs/benches/commit_zk.rs b/halo2_proofs/benches/commit_zk.rs index 3496dbd4be..7555845f8a 100644 --- a/halo2_proofs/benches/commit_zk.rs +++ b/halo2_proofs/benches/commit_zk.rs @@ -4,10 +4,10 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use group::ff::Field; use halo2_proofs::*; use halo2curves::pasta::pallas::Scalar; +use maybe_rayon::{current_num_threads, prelude::*}; use rand_chacha::rand_core::RngCore; use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; -use rayon::{current_num_threads, prelude::*}; fn rand_poly_serial(mut rng: ChaCha20Rng, domain: usize) -> Vec { // Sample a random polynomial of degree n - 1 diff --git a/halo2_proofs/examples/vector-mul.rs b/halo2_proofs/examples/vector-mul.rs index 23dc6d274e..4b971dc97f 100644 --- a/halo2_proofs/examples/vector-mul.rs +++ b/halo2_proofs/examples/vector-mul.rs @@ -180,7 +180,7 @@ impl NumericInstructions for FieldChip { #[cfg(feature = "thread-safe-region")] { - use rayon::prelude::{ + use maybe_rayon::prelude::{ IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator, }; layouter.assign_region( diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index 7366fb7b19..984b102b45 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -262,7 +262,7 @@ pub fn recursive_butterfly_arithmetic>( a[1] -= &t; } else { let (left, right) = a.split_at_mut(n / 2); - rayon::join( + multicore::join( || recursive_butterfly_arithmetic(left, n / 2, twiddle_chunk * 2, twiddles), || recursive_butterfly_arithmetic(right, n / 2, twiddle_chunk * 2, twiddles), ); diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 3bce097920..f8ac33b2e0 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -14,6 +14,10 @@ use ff::FromUniformBytes; use group::Group; use crate::circuit::layouter::SyncDeps; +use crate::multicore::{ + IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, + ParallelSliceMut, +}; use crate::plonk::permutation::keygen::Assembly; use crate::{ circuit, @@ -26,12 +30,6 @@ use crate::{ }, poly::Rotation, }; -use rayon::{ - iter::{ - IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, - }, - slice::ParallelSliceMut, -}; pub mod metadata; use metadata::Column as ColumnMetadata; diff --git a/halo2_proofs/src/multicore.rs b/halo2_proofs/src/multicore.rs index a22eac9e79..0b0839fa18 100644 --- a/halo2_proofs/src/multicore.rs +++ b/halo2_proofs/src/multicore.rs @@ -1,5 +1,74 @@ -//! An interface for dealing with the kinds of parallel computations involved in -//! `halo2`. It's currently just a (very!) thin wrapper around [`rayon`] but may -//! be extended in the future to allow for various parallelism strategies. +#[cfg(all( + feature = "multicore", + target_arch = "wasm32", + not(target_feature = "atomics") +))] +compile_error!( + "The multicore feature flag is not supported on wasm32 architectures without atomics" +); -pub use rayon::{current_num_threads, scope, Scope}; +pub use maybe_rayon::{ + iter::{ + IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, + IntoParallelRefMutIterator, ParallelIterator, + }, + join, scope, + slice::ParallelSliceMut, + Scope, +}; + +#[cfg(feature = "multicore")] +pub use maybe_rayon::current_num_threads; + +#[cfg(not(feature = "multicore"))] +pub fn current_num_threads() -> usize { + 1 +} + +#[cfg(not(feature = "multicore"))] +pub trait IndexedParallelIterator: std::iter::Iterator {} + +pub trait TryFoldAndReduce { + /// Implements `iter.try_fold().try_reduce()` for `rayon::iter::ParallelIterator`, + /// falling back on `Iterator::try_fold` when the `multicore` feature flag is + /// disabled. + /// The `try_fold_and_reduce` function can only be called by a iter with + /// `Result` item type because the `fold_op` must meet the trait + /// bounds of both `try_fold` and `try_reduce` from rayon. + fn try_fold_and_reduce( + self, + identity: impl Fn() -> T + Send + Sync, + fold_op: impl Fn(T, Result) -> Result + Send + Sync, + ) -> Result; +} + +#[cfg(feature = "multicore")] +impl TryFoldAndReduce for I +where + T: Send + Sync, + E: Send + Sync, + I: maybe_rayon::iter::ParallelIterator>, +{ + fn try_fold_and_reduce( + self, + identity: impl Fn() -> T + Send + Sync, + fold_op: impl Fn(T, Result) -> Result + Send + Sync, + ) -> Result { + self.try_fold(&identity, &fold_op) + .try_reduce(&identity, |a, b| fold_op(a, Ok(b))) + } +} + +#[cfg(not(feature = "multicore"))] +impl TryFoldAndReduce for I +where + I: std::iter::Iterator>, +{ + fn try_fold_and_reduce( + mut self, + identity: impl Fn() -> T + Send + Sync, + fold_op: impl Fn(T, Result) -> Result + Send + Sync, + ) -> Result { + self.try_fold(identity(), fold_op) + } +} diff --git a/halo2_proofs/src/plonk/permutation/keygen.rs b/halo2_proofs/src/plonk/permutation/keygen.rs index 819612357e..843e2a9fab 100644 --- a/halo2_proofs/src/plonk/permutation/keygen.rs +++ b/halo2_proofs/src/plonk/permutation/keygen.rs @@ -2,14 +2,14 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use ff::{Field, PrimeField}; use group::Curve; -use rayon::prelude::{ - IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, - IntoParallelRefMutIterator, ParallelIterator, ParallelSliceMut, -}; use super::{Argument, ProvingKey, VerifyingKey}; use crate::{ arithmetic::{parallelize, CurveAffine}, + multicore::{ + IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, + IntoParallelRefMutIterator, ParallelIterator, + }, plonk::{Any, Column, Error}, poly::{ commitment::{Blind, CommitmentScheme, Params}, @@ -133,12 +133,19 @@ impl Assembly { &self.columns } + #[cfg(feature = "multicore")] /// Returns mappings of the copies. pub fn mapping( &self, ) -> impl Iterator + '_> { self.mapping.iter().map(|c| c.par_iter().copied()) } + + #[cfg(not(feature = "multicore"))] + /// Returns mappings of the copies. + pub fn mapping(&self) -> impl Iterator + '_> { + self.mapping.iter().map(|c| c.iter().copied()) + } } #[cfg(feature = "thread-safe-region")] @@ -304,6 +311,7 @@ impl Assembly { &self.columns } + #[cfg(feature = "multicore")] /// Returns mappings of the copies. pub fn mapping( &self, @@ -314,6 +322,12 @@ impl Assembly { .map(move |j| self.mapping_at_idx(i, j)) }) } + + #[cfg(not(feature = "multicore"))] + /// Returns mappings of the copies. + pub fn mapping(&self) -> impl Iterator + '_> { + (0..self.num_cols).map(move |i| (0..self.col_len).map(move |j| self.mapping_at_idx(i, j))) + } } pub(crate) fn build_pk<'params, C: CurveAffine, P: Params<'params, C>>( diff --git a/halo2_proofs/src/plonk/vanishing/prover.rs b/halo2_proofs/src/plonk/vanishing/prover.rs index 30360dea5c..453cb8dc49 100644 --- a/halo2_proofs/src/plonk/vanishing/prover.rs +++ b/halo2_proofs/src/plonk/vanishing/prover.rs @@ -4,11 +4,14 @@ use ff::{Field, PrimeField}; use group::Curve; use rand_chacha::ChaCha20Rng; use rand_core::{RngCore, SeedableRng}; -use rayon::{current_num_threads, prelude::*}; use super::Argument; use crate::{ arithmetic::{eval_polynomial, CurveAffine}, + multicore::{ + current_num_threads, IndexedParallelIterator, IntoParallelIterator, + IntoParallelRefMutIterator, ParallelIterator, ParallelSliceMut, + }, plonk::{ChallengeX, ChallengeY, Error}, poly::{ self, diff --git a/halo2_proofs/src/plonk/verifier/batch.rs b/halo2_proofs/src/plonk/verifier/batch.rs index 04e08be4af..db3800371b 100644 --- a/halo2_proofs/src/plonk/verifier/batch.rs +++ b/halo2_proofs/src/plonk/verifier/batch.rs @@ -4,11 +4,12 @@ use ff::FromUniformBytes; use group::ff::Field; use halo2curves::CurveAffine; use rand_core::{OsRng, RngCore}; -use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use super::{verify_proof, VerificationStrategy}; use crate::{ - multicore, + multicore::{ + IndexedParallelIterator, IntoParallelIterator, ParallelIterator, TryFoldAndReduce, + }, plonk::{Error, VerifyingKey}, poly::{ commitment::{Params, MSM}, @@ -123,11 +124,10 @@ where e }) }) - .try_fold( + .try_fold_and_reduce( || params.empty_msm(), - |msm, res| res.map(|proof_msm| accumulate_msm(msm, proof_msm)), - ) - .try_reduce(|| params.empty_msm(), |a, b| Ok(accumulate_msm(a, b))); + |acc, res| res.map(|proof_msm| accumulate_msm(acc, proof_msm)), + ); match final_msm { Ok(msm) => msm.check(), diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs index d14132fb43..eb0222bd19 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs @@ -1,6 +1,7 @@ mod prover; mod verifier; +use crate::multicore::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use crate::{ arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine}, poly::{query::Query, Coeff, Polynomial}, @@ -8,7 +9,6 @@ use crate::{ }; use ff::Field; pub use prover::ProverSHPLONK; -use rayon::prelude::*; use std::{ collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, marker::PhantomData, diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs index bb50eafe58..ebde585d5e 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs @@ -13,11 +13,11 @@ use crate::poly::Rotation; use crate::poly::{commitment::Params, Coeff, Polynomial}; use crate::transcript::{EncodedChallenge, TranscriptWrite}; +use crate::multicore::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use ff::{Field, PrimeField}; use group::Curve; use halo2curves::pairing::Engine; use rand_core::RngCore; -use rayon::prelude::*; use std::fmt::Debug; use std::io::{self, Write}; use std::marker::PhantomData;