feat(cpp): option to have a stateless cache

This commit is contained in:
rudy
2022-11-15 16:16:01 +01:00
committed by rudy-6-4
parent f80c657849
commit d0654c0fa7
15 changed files with 111 additions and 71 deletions

View File

@@ -43,7 +43,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
complexity_model: &CpuComplexity::default(),
};
let cache = decomposition::cache(security_level, processing_unit, None);
let cache = decomposition::cache(security_level, processing_unit, None, true);
let solutions: Vec<_> = log_norm2s
.clone()

View File

@@ -43,7 +43,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
complexity_model: &CpuComplexity::default(),
};
let cache = decomposition::cache(security_level, processing_unit, None);
let cache = decomposition::cache(security_level, processing_unit, None, true);
let solutions: Vec<_> = precisions
.clone()

View File

@@ -10,6 +10,7 @@ use concrete_optimizer::optimization::dag::solo_key::optimize_generic::{
Encoding, Solution as DagSolution,
};
use concrete_optimizer::optimization::decomposition;
use concrete_optimizer::utils::cache::persistent::default_cache_dir;
fn no_solution() -> ffi::Solution {
ffi::Solution {
@@ -25,6 +26,21 @@ fn no_dag_solution() -> ffi::DagSolution {
}
}
fn caches_from(options: ffi::Options) -> decomposition::PersistDecompCaches {
if !options.cache_on_disk {
println!("optimizer: Using stateless cache.");
let cache_dir = default_cache_dir();
println!("optimizer: To clear the cache, remove directory {cache_dir}");
}
let processing_unit = processing_unit(options);
decomposition::cache(
options.security_level,
processing_unit,
Some(ProcessingUnit::Cpu.complexity_model()),
options.cache_on_disk,
)
}
fn optimize_bootstrap(precision: u64, noise_factor: f64, options: ffi::Options) -> ffi::Solution {
let processing_unit = processing_unit(options);
@@ -45,11 +61,7 @@ fn optimize_bootstrap(precision: u64, noise_factor: f64, options: ffi::Options)
config,
noise_factor,
&search_space,
&decomposition::cache(
options.security_level,
processing_unit,
Some(ProcessingUnit::Cpu.complexity_model()),
),
&caches_from(options),
);
result
.best_solution
@@ -232,11 +244,7 @@ impl OperationDag {
&self.0,
config,
&search_space,
&decomposition::cache(
options.security_level,
processing_unit,
Some(ProcessingUnit::Cpu.complexity_model()),
),
&caches_from(options),
);
result
.best_solution
@@ -253,11 +261,7 @@ impl OperationDag {
};
let search_space = SearchSpace::default(processing_unit);
let cache = decomposition::cache(
options.security_level,
processing_unit,
Some(ProcessingUnit::Cpu.complexity_model()),
);
let encoding = options.encoding.into();
let result = concrete_optimizer::optimization::dag::solo_key::optimize_generic::optimize(
&self.0,
@@ -265,7 +269,7 @@ impl OperationDag {
&search_space,
encoding,
options.default_log_norm2_woppbs,
&cache,
&caches_from(options),
);
result.map_or_else(no_dag_solution, |solution| solution.into())
}
@@ -430,6 +434,7 @@ mod ffi {
pub default_log_norm2_woppbs: f64,
pub use_gpu_constraints: bool,
pub encoding: Encoding,
pub cache_on_disk: bool,
}
}

View File

@@ -1064,6 +1064,7 @@ struct Options final {
double default_log_norm2_woppbs;
bool use_gpu_constraints;
::concrete_optimizer::Encoding encoding;
bool cache_on_disk;
using IsRelocatable = ::std::true_type;
};

View File

@@ -1045,6 +1045,7 @@ struct Options final {
double default_log_norm2_woppbs;
bool use_gpu_constraints;
::concrete_optimizer::Encoding encoding;
bool cache_on_disk;
using IsRelocatable = ::std::true_type;
};

View File

@@ -23,7 +23,8 @@ concrete_optimizer::Options default_options() {
.maximum_acceptable_error_probability = P_ERROR,
.default_log_norm2_woppbs = WOP_FALLBACK_LOG_NORM,
.use_gpu_constraints = false,
.encoding = concrete_optimizer::Encoding::Auto
.encoding = concrete_optimizer::Encoding::Auto,
.cache_on_disk = true,
};
}

View File

@@ -392,7 +392,7 @@ mod tests {
static SHARED_CACHES: Lazy<PersistDecompCaches> = Lazy::new(|| {
let processing_unit = config::ProcessingUnit::Cpu;
decomposition::cache(128, processing_unit, None)
decomposition::cache(128, processing_unit, None, true)
});
fn optimize(dag: &unparametrized::OperationDag) -> OptimizationState {

View File

@@ -8,7 +8,7 @@ use crate::computing_cost::complexity_model::ComplexityModel;
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
use crate::parameters::{BrDecompositionParameters, GlweParameters, LweDimension, PbsParameters};
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
use crate::utils::cache::persistent::PersistentCacheHashMap;
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
use crate::{config, security};
use super::common::{MacroParam, VERSION};
@@ -115,18 +115,12 @@ pub fn cache(
processing_unit: config::ProcessingUnit,
complexity_model: Arc<dyn ComplexityModel>,
) -> PersistDecompCache {
let max_log2_base = processing_unit.max_br_base_log();
let cache_dir: String = default_cache_dir();
let ciphertext_modulus_log = 64;
let tmp: String = std::env::temp_dir()
.to_str()
.expect("Invalid tmp dir")
.into();
let hardware = processing_unit.br_to_string();
let path = format!("{cache_dir}/br-decomp-{hardware}-64-{security_level}");
let path = format!("{tmp}/optimizer/cache/br-decomp-{hardware}-64-{security_level}");
let max_log2_base = processing_unit.max_br_base_log();
let function = move |(glwe_params, internal_dim): MacroParam| {
pareto_quantities(
complexity_model.as_ref(),
@@ -137,5 +131,5 @@ pub fn cache(
max_log2_base,
)
};
PersistentCacheHashMap::new(&path, VERSION, function)
PersistentCacheHashMap::new_no_read(&path, VERSION, function)
}

View File

@@ -8,7 +8,7 @@ use crate::config;
use crate::noise_estimator::operators::atomic_pattern::variance_cmux;
use crate::parameters::{BrDecompositionParameters, CmuxParameters, GlweParameters};
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
use crate::utils::cache::persistent::PersistentCacheHashMap;
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
use crate::utils::square;
use super::common::VERSION;
@@ -97,15 +97,11 @@ pub fn cache(
processing_unit: config::ProcessingUnit,
complexity_model: Arc<dyn ComplexityModel>,
) -> PersistDecompCache {
let cache_dir: String = default_cache_dir();
let ciphertext_modulus_log = 64;
let tmp: String = std::env::temp_dir()
.to_str()
.expect("Invalid tmp dir")
.into();
let hardware = processing_unit.br_to_string();
let path = format!(
"{tmp}/optimizer/cache/cb-decomp-{hardware}-{ciphertext_modulus_log}-{security_level}"
);
let path =
format!("{cache_dir}/cb-decomp-{hardware}-{ciphertext_modulus_log}-{security_level}");
let function = move |glwe_params| {
pareto_quantities(
complexity_model.as_ref(),
@@ -113,5 +109,5 @@ pub fn cache(
glwe_params,
)
};
PersistentCacheHashMap::new(&path, VERSION, function)
PersistentCacheHashMap::new_no_read(&path, VERSION, function)
}

View File

@@ -11,7 +11,7 @@ use crate::parameters::{
GlweParameters, KeyswitchParameters, KsDecompositionParameters, LweDimension,
};
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
use crate::utils::cache::persistent::PersistentCacheHashMap;
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
use super::common::{MacroParam, VERSION};
@@ -118,15 +118,10 @@ pub fn cache(
processing_unit: config::ProcessingUnit,
complexity_model: Arc<dyn ComplexityModel>,
) -> PersistDecompCache {
let cache_dir: String = default_cache_dir();
let ciphertext_modulus_log = 64;
let tmp: String = std::env::temp_dir()
.to_str()
.expect("Invalid tmp dir")
.into();
let hardware = processing_unit.ks_to_string();
let path = format!("{tmp}/optimizer/cache/ks-decomp-{hardware}-64-{security_level}");
let path = format!("{cache_dir}/ks-decomp-{hardware}-64-{security_level}");
let function = move |(glwe_params, internal_dim): MacroParam| {
pareto_quantities(
@@ -137,5 +132,5 @@ pub fn cache(
glwe_params,
)
};
PersistentCacheHashMap::new(&path, VERSION, function)
PersistentCacheHashMap::new_no_read(&path, VERSION, function)
}

View File

@@ -16,6 +16,7 @@ pub struct PersistDecompCaches {
pub br: blind_rotate::PersistDecompCache,
pub pp: pp_switch::PersistDecompCache,
pub cb: circuit_bootstrap::PersistDecompCache,
pub cache_on_disk: bool,
}
pub struct DecompCaches {
@@ -29,8 +30,14 @@ pub fn cache(
security_level: u64,
processing_unit: config::ProcessingUnit,
complexity_model: Option<Arc<dyn ComplexityModel>>,
cache_on_disk: bool,
) -> PersistDecompCaches {
PersistDecompCaches::new(security_level, processing_unit, complexity_model)
PersistDecompCaches::new(
security_level,
processing_unit,
complexity_model,
cache_on_disk,
)
}
impl PersistDecompCaches {
@@ -38,18 +45,30 @@ impl PersistDecompCaches {
security_level: u64,
processing_unit: config::ProcessingUnit,
complexity_model: Option<Arc<dyn ComplexityModel>>,
cache_on_disk: bool,
) -> Self {
let complexity_model =
complexity_model.unwrap_or_else(|| processing_unit.complexity_model());
Self {
let res = Self {
ks: keyswitch::cache(security_level, processing_unit, complexity_model.clone()),
br: blind_rotate::cache(security_level, processing_unit, complexity_model.clone()),
pp: pp_switch::cache(security_level, processing_unit, complexity_model.clone()),
cb: circuit_bootstrap::cache(security_level, processing_unit, complexity_model.clone()),
cache_on_disk,
};
if cache_on_disk {
res.ks.read();
res.br.read();
res.pp.read();
res.cb.read();
}
res
}
pub fn backport(&self, cache: DecompCaches) {
if !self.cache_on_disk {
return;
}
self.ks.backport(cache.keyswitch);
self.br.backport(cache.blind_rotate);
self.pp.backport(cache.pp_switch);

View File

@@ -11,7 +11,7 @@ use crate::parameters::{
KsDecompositionParameters, LweDimension,
};
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
use crate::utils::cache::persistent::PersistentCacheHashMap;
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
use crate::{config, security};
use super::blind_rotate;
@@ -90,15 +90,12 @@ pub fn cache(
processing_unit: config::ProcessingUnit,
complexity_model: Arc<dyn ComplexityModel>,
) -> PersistDecompCache {
let max_log2_base = processing_unit.max_br_base_log();
let cache_dir: String = default_cache_dir();
let ciphertext_modulus_log = 64;
let tmp: String = std::env::temp_dir()
.to_str()
.expect("Invalid tmp dir")
.into();
let hardware = processing_unit.br_to_string();
let path = format!("{tmp}/optimizer/cache/bc-decomp-{hardware}-64-{security_level}");
let path = format!("{cache_dir}/bc-decomp-{hardware}-64-{security_level}");
let max_log2_base = processing_unit.max_br_base_log();
let function = move |(glwe_params, internal_dim): MacroParam| {
let br = blind_rotate::pareto_quantities(
complexity_model.as_ref(),
@@ -117,5 +114,5 @@ pub fn cache(
&br,
)
};
PersistentCacheHashMap::new(&path, VERSION, function)
PersistentCacheHashMap::new_no_read(&path, VERSION, function)
}

View File

@@ -50,18 +50,18 @@ where
version: u64,
function: impl 'static + Send + Sync + Fn(ROC::K) -> ROC::V,
) -> Self {
let t0 = Instant::now();
let content = Self::read_from_disk(path, version).unwrap_or_default();
if SHOW_DISK_ACCESS {
println!(
"PersistentCache: {}, reading time {} msec, {} entries",
path,
t0.elapsed().as_millis(),
content.len()
);
}
let cache = Self::new_no_read(path, version, function);
cache.read();
cache
}
pub fn new_no_read(
path: &str,
version: u64,
function: impl 'static + Send + Sync + Fn(ROC::K) -> ROC::V,
) -> Self {
let path = path.into();
let content = RwLock::new(Arc::new(content));
let content = RwLock::new(Arc::new(ROC::default()));
let content_changed = AtomicBool::new(false);
Self {
path,
@@ -72,6 +72,21 @@ where
}
}
pub fn read(&self) {
let t0 = Instant::now();
let content = Self::read_from_disk(&self.path, self.version).unwrap_or_default();
if SHOW_DISK_ACCESS {
println!(
"PersistentCache: {}, reading time {} msec, {} entries",
self.path,
t0.elapsed().as_millis(),
content.len()
);
}
self.update_with(|_| content);
self.content_changed.store(false, Ordering::Relaxed);
}
pub fn cache(&self) -> ephemeral::Cache<ROC> {
let initial_content = self.content.read().unwrap().clone();
ephemeral::Cache::<ROC>::new(initial_content, self.function.clone())
@@ -269,6 +284,13 @@ where
pub type PersistentCacheHashMap<K, V> = PersistentCache<Map<K, V>>;
pub fn default_cache_dir() -> String {
let mut cache_dir = std::env::temp_dir();
cache_dir.push("optimizer");
cache_dir.push("cache");
cache_dir.to_str().expect("Invalid tmp dir").into()
}
#[cfg(test)]
mod tests {
use super::super::ephemeral::CacheHashMap;

View File

@@ -17,6 +17,7 @@ fn pbs_benchmark(c: &mut Criterion) {
no_parallelize: true,
wop_pbs: false,
simulate_dag: true,
cache_on_disk: true,
};
c.bench_function("PBS table generation", |b| {
@@ -40,6 +41,7 @@ fn wop_pbs_benchmark(c: &mut Criterion) {
no_parallelize: true,
wop_pbs: true,
simulate_dag: false,
cache_on_disk: true,
};
c.bench_function("WoP-PBS table generation", |b| {

View File

@@ -36,6 +36,7 @@ pub const MAX_LWE_DIM: u64 = DEFAUT_DOMAINS.free_glwe.glwe_dimension.end - 1;
/// Find parameters for classical PBS and new WoP-PBS
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[allow(clippy::struct_excessive_bools)]
pub struct Args {
#[clap(long, default_value_t = 1, help = "1..16")]
pub min_precision: u64,
@@ -82,6 +83,9 @@ pub struct Args {
#[clap(long)]
pub simulate_dag: bool,
#[clap(long, default_value_t = true)]
pub cache_on_disk: bool,
}
pub fn all_results(args: &Args) -> Vec<Vec<Option<Solution>>> {
@@ -89,6 +93,7 @@ pub fn all_results(args: &Args) -> Vec<Vec<Option<Solution>>> {
let sum_size = args.sum_size;
let maximum_acceptable_error_probability = args.p_error;
let security_level = args.security_level;
let cache_on_disk = args.cache_on_disk;
let search_space = SearchSpace {
glwe_log_polynomial_sizes: (args.min_log_poly_size..=args.max_log_poly_size).collect(),
@@ -110,7 +115,7 @@ pub fn all_results(args: &Args) -> Vec<Vec<Option<Solution>>> {
complexity_model: &CpuComplexity::default(),
};
let cache = decomposition::cache(config.security_level, processing_unit, None);
let cache = decomposition::cache(security_level, processing_unit, None, cache_on_disk);
precisions_iter
.map(|precision| {
@@ -272,6 +277,7 @@ mod tests {
no_parallelize: false,
wop_pbs: false,
simulate_dag,
cache_on_disk: true,
};
let mut actual_output = Vec::<u8>::new();
@@ -313,6 +319,7 @@ mod tests {
no_parallelize: false,
wop_pbs: true,
simulate_dag: false,
cache_on_disk: true,
};
let mut actual_output = Vec::<u8>::new();