From a2c4d311e0fa97fed9a58663e89f4568f0e12eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Test=C3=A9?= Date: Fri, 12 Jul 2024 17:12:07 +0200 Subject: [PATCH] chore(bench): benchmark oprf function against all available precisions --- tfhe/benches/integer/bench.rs | 56 +------------------------- tfhe/benches/integer/oprf.rs | 41 ++----------------- tfhe/benches/integer/signed_bench.rs | 60 +--------------------------- tfhe/benches/utilities.rs | 54 +++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 151 deletions(-) diff --git a/tfhe/benches/integer/bench.rs b/tfhe/benches/integer/bench.rs index 3ce93b254c..d7ed71bce1 100644 --- a/tfhe/benches/integer/bench.rs +++ b/tfhe/benches/integer/bench.rs @@ -4,17 +4,14 @@ mod oprf; #[path = "../utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, EnvConfig, OperatorType}; +use crate::utilities::{write_to_json, EnvConfig, OperatorType, ParamsAndNumBlocksIter}; use criterion::{criterion_group, Criterion}; -use itertools::iproduct; use rand::prelude::*; use std::env; -use std::vec::IntoIter; use tfhe::integer::keycache::KEY_CACHE; use tfhe::integer::prelude::*; use tfhe::integer::{IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey, U256}; use tfhe::keycache::NamedParam; -use tfhe::shortint::parameters::*; /// The type used to hold scalar values /// It must be as big as the largest bit size tested @@ -27,57 +24,6 @@ fn gen_random_u256(rng: &mut ThreadRng) -> U256 { tfhe::integer::U256::from((clearlow, clearhigh)) } -/// An iterator that yields a succession of combinations -/// of parameters and a num_block to achieve a certain bit_size ciphertext -/// in radix decomposition -struct ParamsAndNumBlocksIter { - params_and_bit_sizes: - itertools::Product, IntoIter>, -} - -impl Default for ParamsAndNumBlocksIter { - fn default() -> Self { - let env_config = EnvConfig::new(); - - if env_config.is_multi_bit { - #[cfg(feature = "gpu")] - let params = vec![PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS.into()]; - #[cfg(not(feature = "gpu"))] - let params = vec![PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS.into()]; - - let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); - Self { - params_and_bit_sizes, - } - } else { - // FIXME One set of parameter is tested since we want to benchmark only quickest - // operations. - let params = vec![ - PARAM_MESSAGE_2_CARRY_2_KS_PBS.into(), - // PARAM_MESSAGE_3_CARRY_3_KS_PBS.into(), - // PARAM_MESSAGE_4_CARRY_4_KS_PBS.into(), - ]; - - let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); - Self { - params_and_bit_sizes, - } - } - } -} - -impl Iterator for ParamsAndNumBlocksIter { - type Item = (tfhe::shortint::PBSParameters, usize, usize); - - fn next(&mut self) -> Option { - let (param, bit_size) = self.params_and_bit_sizes.next()?; - let num_block = - (bit_size as f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize; - - Some((param, num_block, bit_size)) - } -} - /// Base function to bench a server key function that is a binary operation, input ciphertexts will /// contain non zero carries fn bench_server_key_binary_function_dirty_inputs( diff --git a/tfhe/benches/integer/oprf.rs b/tfhe/benches/integer/oprf.rs index ee969c87cd..7b7aeed156 100644 --- a/tfhe/benches/integer/oprf.rs +++ b/tfhe/benches/integer/oprf.rs @@ -1,42 +1,9 @@ -use crate::utilities::{write_to_json, OperatorType}; +use crate::utilities::{write_to_json, OperatorType, ParamsAndNumBlocksIter}; use concrete_csprng::seeders::Seed; use criterion::{black_box, Criterion}; -use itertools::iproduct; -use std::vec::IntoIter; use tfhe::integer::keycache::KEY_CACHE; use tfhe::integer::IntegerKeyKind; use tfhe::keycache::NamedParam; -use tfhe::shortint::parameters::*; - -/// An iterator that yields a succession of combinations -/// of parameters and a num_block to achieve a certain bit_size ciphertext -/// in radix decomposition -struct ParamsAndNumBlocksIter { - params_and_bit_sizes: itertools::Product, IntoIter>, -} - -impl Default for ParamsAndNumBlocksIter { - fn default() -> Self { - let params = vec![PARAM_MESSAGE_2_CARRY_2_KS_PBS.into()]; - let bit_sizes = vec![64]; - let params_and_bit_sizes = iproduct!(params, bit_sizes); - Self { - params_and_bit_sizes, - } - } -} - -impl Iterator for ParamsAndNumBlocksIter { - type Item = (PBSParameters, u64, u64); - - fn next(&mut self) -> Option { - let (param, bit_size) = self.params_and_bit_sizes.next()?; - let num_block = - (bit_size as f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as u64; - - Some((param, num_block, bit_size)) - } -} pub fn unsigned_oprf(c: &mut Criterion) { let bench_name = "integer::unsigned_oprf"; @@ -44,7 +11,7 @@ pub fn unsigned_oprf(c: &mut Criterion) { let mut bench_group = c.benchmark_group(bench_name); bench_group .sample_size(15) - .measurement_time(std::time::Duration::from_secs(60)); + .measurement_time(std::time::Duration::from_secs(30)); for (param, num_block, bit_size) in ParamsAndNumBlocksIter::default() { let (_, sk) = KEY_CACHE.get_from_params(param, IntegerKeyKind::Radix); @@ -54,8 +21,8 @@ pub fn unsigned_oprf(c: &mut Criterion) { b.iter(|| { _ = black_box(sk.par_generate_oblivious_pseudo_random_unsigned_integer( Seed(0), - bit_size, - num_block, + bit_size as u64, + num_block as u64, )); }) }); diff --git a/tfhe/benches/integer/signed_bench.rs b/tfhe/benches/integer/signed_bench.rs index 68a3ff6396..2f86fb02d4 100644 --- a/tfhe/benches/integer/signed_bench.rs +++ b/tfhe/benches/integer/signed_bench.rs @@ -1,21 +1,14 @@ #[path = "../utilities.rs"] mod utilities; -use crate::utilities::{write_to_json, EnvConfig, OperatorType}; +use crate::utilities::{write_to_json, EnvConfig, OperatorType, ParamsAndNumBlocksIter}; use criterion::{criterion_group, Criterion}; -use itertools::iproduct; use rand::prelude::*; use std::env; -use std::vec::IntoIter; use tfhe::integer::keycache::KEY_CACHE; use tfhe::integer::prelude::*; use tfhe::integer::{IntegerKeyKind, RadixCiphertext, ServerKey, SignedRadixCiphertext, I256}; use tfhe::keycache::NamedParam; -#[cfg(feature = "gpu")] -use tfhe::shortint::parameters::PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS; -use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; -#[cfg(not(feature = "gpu"))] -use tfhe::shortint::parameters::PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS; fn gen_random_i256(rng: &mut ThreadRng) -> I256 { let clearlow = rng.gen::(); @@ -24,57 +17,6 @@ fn gen_random_i256(rng: &mut ThreadRng) -> I256 { tfhe::integer::I256::from((clearlow, clearhigh)) } -/// An iterator that yields a succession of combinations -/// of parameters and a num_block to achieve a certain bit_size ciphertext -/// in radix decomposition -struct ParamsAndNumBlocksIter { - params_and_bit_sizes: - itertools::Product, IntoIter>, -} - -impl Default for ParamsAndNumBlocksIter { - fn default() -> Self { - let env_config = EnvConfig::new(); - - if env_config.is_multi_bit { - #[cfg(feature = "gpu")] - let params = vec![PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS.into()]; - #[cfg(not(feature = "gpu"))] - let params = vec![PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS.into()]; - - let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); - Self { - params_and_bit_sizes, - } - } else { - // FIXME One set of parameter is tested since we want to benchmark only quickest - // operations. - let params = vec![ - PARAM_MESSAGE_2_CARRY_2_KS_PBS.into(), - // PARAM_MESSAGE_3_CARRY_3_KS_PBS.into(), - // PARAM_MESSAGE_4_CARRY_4_KS_PBS.into(), - ]; - - let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); - Self { - params_and_bit_sizes, - } - } - } -} - -impl Iterator for ParamsAndNumBlocksIter { - type Item = (tfhe::shortint::PBSParameters, usize, usize); - - fn next(&mut self) -> Option { - let (param, bit_size) = self.params_and_bit_sizes.next()?; - let num_block = - (bit_size as f64 / param.message_modulus().0.ilog2() as f64).ceil() as usize; - - Some((param, num_block, bit_size)) - } -} - /// Base function to bench a server key function that is a binary operation, input ciphertext will /// contain only zero carries fn bench_server_key_signed_binary_function_clean_inputs( diff --git a/tfhe/benches/utilities.rs b/tfhe/benches/utilities.rs index c2ab4a1e56..52fb5e48ef 100644 --- a/tfhe/benches/utilities.rs +++ b/tfhe/benches/utilities.rs @@ -1,11 +1,18 @@ +use itertools::iproduct; use serde::Serialize; use std::path::PathBuf; +use std::vec::IntoIter; use std::{env, fs}; #[cfg(feature = "boolean")] use tfhe::boolean::parameters::BooleanParameters; use tfhe::core_crypto::prelude::*; #[cfg(feature = "shortint")] use tfhe::shortint::parameters::ShortintKeySwitchingParameters; +#[cfg(feature = "gpu")] +use tfhe::shortint::parameters::PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS; +use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS; +#[cfg(not(feature = "gpu"))] +use tfhe::shortint::parameters::PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS; #[cfg(feature = "shortint")] use tfhe::shortint::PBSParameters; @@ -268,6 +275,53 @@ impl EnvConfig { } } +/// An iterator that yields a succession of combinations +/// of parameters and a num_block to achieve a certain bit_size ciphertext +/// in radix decomposition +pub struct ParamsAndNumBlocksIter { + params_and_bit_sizes: + itertools::Product, IntoIter>, +} + +impl Default for ParamsAndNumBlocksIter { + fn default() -> Self { + let env_config = EnvConfig::new(); + + if env_config.is_multi_bit { + #[cfg(feature = "gpu")] + let params = vec![PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS.into()]; + #[cfg(not(feature = "gpu"))] + let params = vec![PARAM_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_2_KS_PBS.into()]; + + let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); + Self { + params_and_bit_sizes, + } + } else { + // FIXME One set of parameter is tested since we want to benchmark only quickest + // operations. + let params = vec![PARAM_MESSAGE_2_CARRY_2_KS_PBS.into()]; + + let params_and_bit_sizes = iproduct!(params, env_config.bit_sizes()); + Self { + params_and_bit_sizes, + } + } + } +} + +impl Iterator for ParamsAndNumBlocksIter { + type Item = (tfhe::shortint::PBSParameters, usize, usize); + + fn next(&mut self) -> Option { + let (param, bit_size) = self.params_and_bit_sizes.next()?; + let num_block = + (bit_size as f64 / (param.message_modulus().0 as f64).log(2.0)).ceil() as usize; + + Some((param, num_block, bit_size)) + } +} + // Empty main to please clippy. #[allow(dead_code)] pub fn main() {}