mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-04-28 03:01:21 -04:00
Compare commits
2 Commits
jb/doc/upd
...
ts/bench/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47e75759c9 | ||
|
|
96d230cf6f |
@@ -36,12 +36,12 @@ pub fn bench_fhe_type_op<FheType, Op>(
|
||||
let inputs = op.setup_inputs(client_key, &mut rng);
|
||||
|
||||
let bench_type = get_bench_type();
|
||||
let benchmark_spec = BenchmarkSpec::new_hlapi(
|
||||
let benchmark_spec = BenchmarkSpec::new_hlapi_ops(
|
||||
hlapi_op,
|
||||
¶m_name,
|
||||
&operand_type,
|
||||
Some(type_name),
|
||||
bench_type,
|
||||
*bench_type,
|
||||
bench_backend_from_cfg(),
|
||||
);
|
||||
let bench_id = benchmark_spec.to_string();
|
||||
|
||||
@@ -5,12 +5,12 @@ use benchmark::params_aliases::{
|
||||
BENCH_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
BENCH_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
};
|
||||
use benchmark::utilities::{bench_backend_from_cfg, write_to_json, OperatorType};
|
||||
#[cfg(feature = "gpu")]
|
||||
use benchmark::utilities::{configure_gpu, get_param_type, ParamType};
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkType};
|
||||
use criterion::measurement::WallTime;
|
||||
use criterion::{BenchmarkGroup, Criterion, Throughput};
|
||||
use benchmark_spec::tfhe::hlapi::dex::{Dex, DexFlavor};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkMetric, BenchmarkSpec, BenchmarkType, OperandType};
|
||||
use criterion::{Criterion, Throughput};
|
||||
use rand::prelude::*;
|
||||
use rand::thread_rng;
|
||||
use rayon::prelude::*;
|
||||
@@ -220,21 +220,15 @@ where
|
||||
|
||||
#[cfg(feature = "pbs-stats")]
|
||||
mod pbs_stats {
|
||||
use super::*;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
use benchmark_spec::TestResult;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn print_swap_request_update_dex_balance_pbs_counts<FheType, F>(
|
||||
client_key: &ClientKey,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_request_update_dex_balance_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -258,29 +252,24 @@ mod pbs_stats {
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let test_name = if cfg!(feature = "gpu") {
|
||||
format!("hlapi::cuda::dex::pbs_count::swap_request_update_dex_balance::{fn_name}::{params_name}::{type_name}")
|
||||
} else {
|
||||
format!(
|
||||
"hlapi::dex::pbs_count::swap_request_update_dex_balance::{fn_name}::{params_name}::{type_name}"
|
||||
)
|
||||
};
|
||||
let test_name = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::PbsCount,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
let results_file = Path::new("dex_swap_request_update_dex_balance_pbs_count.csv");
|
||||
if !results_file.exists() {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result =
|
||||
TestResult::new("dex_swap_request_update_dex_balance_pbs_count.csv");
|
||||
|
||||
write_result(&mut file, &test_name, count as usize);
|
||||
benchmark_test_result.write_result(&test_name.to_string(), count as usize);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
write_to_json::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
params_name,
|
||||
"pbs-count",
|
||||
&OperatorType::Atomic,
|
||||
0,
|
||||
@@ -290,6 +279,7 @@ mod pbs_stats {
|
||||
pub fn print_swap_request_finalize_pbs_counts<FheType, F>(
|
||||
client_key: &ClientKey,
|
||||
type_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_request_finalize_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -313,29 +303,23 @@ mod pbs_stats {
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let test_name = if cfg!(feature = "gpu") {
|
||||
format!(
|
||||
"hlapi::cuda::dex::pbs_count::swap_request_finalize::{params_name}::{type_name}"
|
||||
)
|
||||
} else {
|
||||
format!("hlapi::dex::pbs_count::swap_request_finalize::{params_name}::{type_name}")
|
||||
};
|
||||
let test_name = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::PbsCount,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
let results_file = Path::new("dex_swap_request_finalize_pbs_count.csv");
|
||||
if !results_file.exists() {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::new("dex_swap_request_finalize_pbs_count.csv");
|
||||
|
||||
write_result(&mut file, &test_name, count as usize);
|
||||
benchmark_test_result.write_result(&test_name.to_string(), count as usize);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
write_to_json::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
params_name,
|
||||
"pbs-count",
|
||||
&OperatorType::Atomic,
|
||||
0,
|
||||
@@ -345,6 +329,7 @@ mod pbs_stats {
|
||||
pub fn print_swap_claim_prepare_pbs_counts<FheType, F>(
|
||||
client_key: &ClientKey,
|
||||
type_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_claim_prepare_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -378,27 +363,23 @@ mod pbs_stats {
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let test_name = if cfg!(feature = "gpu") {
|
||||
format!("hlapi::cuda::pbs_count::dex::swap_claim_prepare::{params_name}::{type_name}")
|
||||
} else {
|
||||
format!("hlapi::dex::pbs_count::swap_claim_prepare::{params_name}::{type_name}")
|
||||
};
|
||||
let test_name = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::PbsCount,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
let results_file = Path::new("dex_swap_claim_prepare_pbs_count.csv");
|
||||
if !results_file.exists() {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::new("dex_swap_claim_prepare_pbs_count.csv");
|
||||
|
||||
write_result(&mut file, &test_name, count as usize);
|
||||
benchmark_test_result.write_result(&test_name.to_string(), count as usize);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
write_to_json::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
params_name,
|
||||
"pbs-count",
|
||||
&OperatorType::Atomic,
|
||||
0,
|
||||
@@ -408,7 +389,7 @@ mod pbs_stats {
|
||||
pub fn print_swap_claim_update_dex_balance_pbs_counts<FheType, F>(
|
||||
client_key: &ClientKey,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_claim_update_dex_balance_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -438,27 +419,24 @@ mod pbs_stats {
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let test_name = if cfg!(feature = "gpu") {
|
||||
format!("hlapi::cuda::pbs_count::dex::swap_claim_update_dex_balance::{fn_name}::{params_name}::{type_name}")
|
||||
} else {
|
||||
format!("hlapi::dex::pbs_count::swap_claim_update_dex_balance::{fn_name}::{params_name}::{type_name}")
|
||||
};
|
||||
let test_name = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::PbsCount,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
let results_file = Path::new("dex_swap_claim_update_dex_balance_pbs_count.csv");
|
||||
if !results_file.exists() {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result =
|
||||
TestResult::new("dex_swap_claim_update_dex_balance_pbs_count.csv");
|
||||
|
||||
write_result(&mut file, &test_name, count as usize);
|
||||
benchmark_test_result.write_result(&test_name.to_string(), count as usize);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
write_to_json::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
params_name,
|
||||
"pbs-count",
|
||||
&OperatorType::Atomic,
|
||||
0,
|
||||
@@ -468,11 +446,10 @@ mod pbs_stats {
|
||||
}
|
||||
|
||||
fn bench_swap_request_latency<FheType, F1, F2>(
|
||||
c: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_request_update_dex_balance_func: F1,
|
||||
swap_request_finalize_func: F2,
|
||||
) where
|
||||
@@ -486,8 +463,19 @@ fn bench_swap_request_latency<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let bench_id = format!("{bench_name}::{fn_name}::{type_name}");
|
||||
c.bench_function(&bench_id, |b| {
|
||||
let mut c = c.benchmark_group(type_name);
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Latency,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
c.bench_function(bench_spec.to_string(), |b| {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let from_balance_0 = FheType::encrypt(rng.gen::<u64>(), client_key);
|
||||
@@ -525,10 +513,9 @@ fn bench_swap_request_latency<FheType, F1, F2>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
params_name,
|
||||
"dex-swap-request",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -538,11 +525,10 @@ fn bench_swap_request_latency<FheType, F1, F2>(
|
||||
|
||||
#[cfg(not(feature = "gpu"))]
|
||||
fn bench_swap_request_throughput<FheType, F1, F2>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_request_update_dex_balance_func: F1,
|
||||
swap_request_finalize_func: F2,
|
||||
) where
|
||||
@@ -555,12 +541,22 @@ fn bench_swap_request_throughput<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
|
||||
for num_elems in [10, 50, 100] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let from_balances_0 = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -641,10 +637,9 @@ fn bench_swap_request_throughput<FheType, F1, F2>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"dex-swap-request",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -654,11 +649,10 @@ fn bench_swap_request_throughput<FheType, F1, F2>(
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
fn cuda_bench_swap_request_throughput<FheType, F1, F2>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_request_update_dex_balance_func: F1,
|
||||
swap_request_finalize_func: F2,
|
||||
) where
|
||||
@@ -678,12 +672,20 @@ fn cuda_bench_swap_request_throughput<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
|
||||
for num_elems in [5 * num_gpus, 10 * num_gpus, 20 * num_gpus] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let from_balances_0 = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -853,10 +855,9 @@ fn cuda_bench_swap_request_throughput<FheType, F1, F2>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"dex-swap-request",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -866,11 +867,10 @@ fn cuda_bench_swap_request_throughput<FheType, F1, F2>(
|
||||
}
|
||||
|
||||
fn bench_swap_claim_latency<FheType, F1, F2>(
|
||||
c: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_claim_prepare_func: F1,
|
||||
swap_claim_update_dex_balance_func: F2,
|
||||
) where
|
||||
@@ -884,8 +884,19 @@ fn bench_swap_claim_latency<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let bench_id = format!("{bench_name}::{fn_name}::{params_name}::{type_name}");
|
||||
c.bench_function(&bench_id, |b| {
|
||||
let mut c = c.benchmark_group(type_name);
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Latency,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
c.bench_function(bench_spec.to_string(), |b| {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let pending_0_in = FheType::encrypt(rng.gen::<u64>(), client_key);
|
||||
@@ -929,10 +940,9 @@ fn bench_swap_claim_latency<FheType, F1, F2>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"dex-swap-claim",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -942,11 +952,10 @@ fn bench_swap_claim_latency<FheType, F1, F2>(
|
||||
|
||||
#[cfg(not(feature = "gpu"))]
|
||||
fn bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_claim_prepare_func: F1,
|
||||
swap_claim_update_dex_balance_func: F2,
|
||||
) where
|
||||
@@ -959,12 +968,22 @@ fn bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
|
||||
for num_elems in [2, 6, 10] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let pending_0_in = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -1063,10 +1082,9 @@ fn bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"dex-swap-claim",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -1076,11 +1094,10 @@ fn bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
}
|
||||
#[cfg(feature = "gpu")]
|
||||
fn cuda_bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Dex,
|
||||
swap_claim_prepare_func: F1,
|
||||
swap_claim_update_dex_balance_func: F2,
|
||||
) where
|
||||
@@ -1100,12 +1117,20 @@ fn cuda_bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
|
||||
for num_elems in [num_gpus, 2 * num_gpus] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_dex(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let pending_0_in = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -1270,10 +1295,9 @@ fn cuda_bench_swap_claim_throughput<FheType, F1, F2>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"dex-swap-claim",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -1306,8 +1330,6 @@ fn main() {
|
||||
|
||||
let mut c = Criterion::default().sample_size(10).configure_from_args();
|
||||
|
||||
let bench_name = "hlapi::dex";
|
||||
|
||||
// FheUint64 PBS counts
|
||||
// We don't run multiple times since every input is encrypted
|
||||
// PBS count is always the same
|
||||
@@ -1316,120 +1338,109 @@ fn main() {
|
||||
print_swap_request_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_swap_request_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
print_swap_request_finalize_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Dex::SwapRequest(DexFlavor::Finalize),
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
print_swap_claim_prepare_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Dex::SwapClaim(DexFlavor::Prepare),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
);
|
||||
print_swap_claim_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_swap_claim_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
}
|
||||
|
||||
match get_bench_type() {
|
||||
BenchmarkType::Latency => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_swap_request_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_request_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
BenchmarkType::Throughput => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_swap_request_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_request_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1449,8 +1460,6 @@ fn main() {
|
||||
|
||||
let mut c = Criterion::default().sample_size(10).configure_from_args();
|
||||
|
||||
let bench_name = "hlapi::cuda::dex";
|
||||
|
||||
// FheUint64 PBS counts
|
||||
// We don't run multiple times since every input is encrypted
|
||||
// PBS count is always the same
|
||||
@@ -1459,121 +1468,110 @@ fn main() {
|
||||
print_swap_request_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_swap_request_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
print_swap_request_finalize_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Dex::SwapRequest(DexFlavor::Finalize),
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
print_swap_claim_prepare_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Dex::SwapClaim(DexFlavor::Prepare),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
);
|
||||
print_swap_claim_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_swap_claim_update_dex_balance_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
}
|
||||
|
||||
match get_bench_type() {
|
||||
BenchmarkType::Latency => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_swap_request_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_request_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_swap_claim_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
BenchmarkType::Throughput => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
cuda_bench_swap_request_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::whitepaper",
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
swap_request_update_dex_balance_whitepaper::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
cuda_bench_swap_request_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_request::no_cmux",
|
||||
Dex::SwapRequest(DexFlavor::NoCmux),
|
||||
swap_request_update_dex_balance_no_cmux::<FheUint64>,
|
||||
swap_request_finalize::<FheUint64>,
|
||||
);
|
||||
cuda_bench_swap_claim_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::whitepaper",
|
||||
Dex::SwapClaim(DexFlavor::Whitepaper),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_whitepaper::<FheUint64>,
|
||||
);
|
||||
cuda_bench_swap_claim_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"swap_claim::no_cmux",
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
swap_claim_prepare::<FheUint64, FheUint128>,
|
||||
swap_claim_update_dex_balance_no_cmux::<FheUint64>,
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use benchmark::utilities::{bench_backend_from_cfg, write_to_json, OperatorType};
|
||||
#[cfg(feature = "gpu")]
|
||||
use benchmark::utilities::{configure_gpu, get_param_type, ParamType};
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkType};
|
||||
use criterion::measurement::WallTime;
|
||||
use criterion::{BenchmarkGroup, Criterion, Throughput};
|
||||
use benchmark_spec::tfhe::hlapi::erc7984::{Erc7984, TransferFlavor};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkMetric, BenchmarkSpec, BenchmarkType, OperandType};
|
||||
use criterion::{Criterion, Throughput};
|
||||
use rand::prelude::*;
|
||||
use rand::thread_rng;
|
||||
#[cfg(not(feature = "hpu"))]
|
||||
@@ -286,21 +286,14 @@ where
|
||||
|
||||
#[cfg(all(feature = "pbs-stats", not(feature = "hpu")))]
|
||||
mod pbs_stats {
|
||||
use super::*;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use benchmark_spec::TestResult;
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
use super::*;
|
||||
|
||||
pub fn print_transfer_pbs_counts<FheType, F>(
|
||||
client_key: &ClientKey,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -324,27 +317,23 @@ mod pbs_stats {
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let test_name = if cfg!(feature = "gpu") {
|
||||
format!("hlapi::cuda::erc7984::pbs_count::{fn_name}::{params_name}::{type_name}")
|
||||
} else {
|
||||
format!("hlapi::erc7984::pbs_count::{fn_name}::{params_name}::{type_name}")
|
||||
};
|
||||
let test_name = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::PbsCount,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
|
||||
let results_file = Path::new("erc7984_pbs_count.csv");
|
||||
if !results_file.exists() {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
}
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::new("erc7984_pbs_count.csv");
|
||||
|
||||
write_result(&mut file, &test_name, count as usize);
|
||||
benchmark_test_result.write_result(&test_name.to_string(), count as usize);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
write_to_json::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
params_name,
|
||||
"pbs-count",
|
||||
&OperatorType::Atomic,
|
||||
0,
|
||||
@@ -354,11 +343,10 @@ mod pbs_stats {
|
||||
}
|
||||
|
||||
fn bench_transfer_latency<FheType, F>(
|
||||
c: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -371,7 +359,18 @@ fn bench_transfer_latency<FheType, F>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let bench_id = format!("{bench_name}::{fn_name}::{params_name}::{type_name}");
|
||||
let mut c = c.benchmark_group(type_name);
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Latency,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
let bench_id = bench_spec.to_string();
|
||||
c.bench_function(&bench_id, |b| {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@@ -388,10 +387,9 @@ fn bench_transfer_latency<FheType, F>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
params_name,
|
||||
"erc7984-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -401,11 +399,10 @@ fn bench_transfer_latency<FheType, F>(
|
||||
|
||||
#[cfg(feature = "hpu")]
|
||||
fn bench_transfer_latency_simd<FheType, F>(
|
||||
c: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey>,
|
||||
@@ -423,9 +420,18 @@ fn bench_transfer_latency_simd<FheType, F>(
|
||||
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
let mut c = c.benchmark_group(type_name);
|
||||
|
||||
let bench_id = format!("{bench_name}::{fn_name}::{params_name}::{type_name}");
|
||||
c.bench_function(&bench_id, |b| {
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
None,
|
||||
);
|
||||
c.bench_function(bench_spec.to_string(), |b| {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let mut from_amounts: Vec<FheType> = vec![];
|
||||
@@ -449,10 +455,9 @@ fn bench_transfer_latency_simd<FheType, F>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
params_name,
|
||||
"erc7984-simd-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -462,11 +467,10 @@ fn bench_transfer_latency_simd<FheType, F>(
|
||||
|
||||
#[cfg(not(any(feature = "gpu", feature = "hpu")))]
|
||||
fn bench_transfer_throughput<FheType, F>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey> + Send + Sync,
|
||||
@@ -477,11 +481,20 @@ fn bench_transfer_throughput<FheType, F>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
|
||||
for num_elems in [10, 100, 500] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
let bench_id = bench_spec.to_string();
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
let from_amounts = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
@@ -503,10 +516,9 @@ fn bench_transfer_throughput<FheType, F>(
|
||||
})
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"erc7984-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -517,11 +529,10 @@ fn bench_transfer_throughput<FheType, F>(
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
fn cuda_bench_transfer_throughput<FheType, F>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
c: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey> + Send + Sync,
|
||||
@@ -542,11 +553,19 @@ fn cuda_bench_transfer_throughput<FheType, F>(
|
||||
// and is a multiple of the number of streams per GPU to avoid a bigger batch on one stream
|
||||
let num_elems = 300 * num_gpus;
|
||||
|
||||
let mut group = c.benchmark_group(type_name);
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let from_amounts = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -593,10 +612,9 @@ fn cuda_bench_transfer_throughput<FheType, F>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"erc7984-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -606,11 +624,10 @@ fn cuda_bench_transfer_throughput<FheType, F>(
|
||||
|
||||
#[cfg(feature = "hpu")]
|
||||
fn hpu_bench_transfer_throughput<FheType, F>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
group: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey> + Send + Sync,
|
||||
@@ -622,12 +639,19 @@ fn hpu_bench_transfer_throughput<FheType, F>(
|
||||
let params = client_key.computation_parameters();
|
||||
let params_name = params.name();
|
||||
|
||||
let mut group = group.benchmark_group(type_name);
|
||||
for num_elems in [10, 100] {
|
||||
group.throughput(Throughput::Elements(num_elems));
|
||||
let bench_id = format!(
|
||||
"{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{num_elems}_elems"
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let from_amounts = (0..num_elems)
|
||||
.map(|_| FheType::encrypt(rng.gen::<u64>(), client_key))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -657,10 +681,9 @@ fn hpu_bench_transfer_throughput<FheType, F>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"erc7984-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
@@ -671,11 +694,10 @@ fn hpu_bench_transfer_throughput<FheType, F>(
|
||||
|
||||
#[cfg(feature = "hpu")]
|
||||
fn hpu_bench_transfer_throughput_simd<FheType, F>(
|
||||
group: &mut BenchmarkGroup<'_, WallTime>,
|
||||
group: &mut Criterion,
|
||||
client_key: &ClientKey,
|
||||
bench_name: &str,
|
||||
type_name: &str,
|
||||
fn_name: &str,
|
||||
fn_name: Erc7984,
|
||||
transfer_func: F,
|
||||
) where
|
||||
FheType: FheEncrypt<u64, ClientKey> + Send + Sync,
|
||||
@@ -698,9 +720,16 @@ fn hpu_bench_transfer_throughput_simd<FheType, F>(
|
||||
for num_elems in [2, 8] {
|
||||
let real_num_elems = num_elems * (hpu_simd_n as u64);
|
||||
group.throughput(Throughput::Elements(real_num_elems));
|
||||
let bench_id =
|
||||
format!("{bench_name}::throughput::{fn_name}::{params_name}::{type_name}::{real_num_elems}_elems");
|
||||
group.bench_with_input(&bench_id, &num_elems, |b, &num_elems| {
|
||||
let bench_spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
fn_name,
|
||||
¶ms_name,
|
||||
&OperandType::CipherText,
|
||||
Some(type_name),
|
||||
BenchmarkMetric::Throughput,
|
||||
bench_backend_from_cfg(),
|
||||
Some(real_num_elems.try_into().unwrap()),
|
||||
);
|
||||
group.bench_with_input(bench_spec.to_string(), &num_elems, |b, &num_elems| {
|
||||
let from_amounts = (0..num_elems)
|
||||
.map(|_| {
|
||||
(0..hpu_simd_n)
|
||||
@@ -742,11 +771,10 @@ fn hpu_bench_transfer_throughput_simd<FheType, F>(
|
||||
});
|
||||
});
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&bench_id,
|
||||
write_to_json::<u64, _>(
|
||||
&bench_spec,
|
||||
params,
|
||||
¶ms_name,
|
||||
"erc7984-simd-ransfer",
|
||||
"erc7984-simd-transfer",
|
||||
&OperatorType::Atomic,
|
||||
64,
|
||||
vec![],
|
||||
@@ -769,8 +797,6 @@ fn main() {
|
||||
|
||||
let mut c = Criterion::default().sample_size(10).configure_from_args();
|
||||
|
||||
let bench_name = "hlapi::erc7984";
|
||||
|
||||
// FheUint64 PBS counts
|
||||
// We don't run multiple times since every input is encrypted
|
||||
// PBS count is always the same
|
||||
@@ -780,99 +806,90 @@ fn main() {
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
par_transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
par_transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
par_transfer_overflow::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(&cks, "FheUint64", "safe", par_transfer_safe::<FheUint64>);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
par_transfer_safe::<FheUint64>,
|
||||
);
|
||||
}
|
||||
|
||||
match get_bench_type() {
|
||||
BenchmarkType::Latency => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
par_transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
par_transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
par_transfer_overflow::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::safe",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
par_transfer_safe::<FheUint64>,
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
BenchmarkType::Throughput => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
par_transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
par_transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
par_transfer_overflow::<FheUint64>,
|
||||
);
|
||||
bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::safe",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
par_transfer_safe::<FheUint64>,
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -896,8 +913,6 @@ fn main() {
|
||||
|
||||
let mut c = Criterion::default().sample_size(10).configure_from_args();
|
||||
|
||||
let bench_name = "hlapi::cuda::erc7984";
|
||||
|
||||
// FheUint64 PBS counts
|
||||
// We don't run multiple times since every input is encrypted
|
||||
// PBS count is always the same
|
||||
@@ -907,98 +922,90 @@ fn main() {
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
par_transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
par_transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
par_transfer_overflow::<FheUint64>,
|
||||
);
|
||||
print_transfer_pbs_counts(&cks, "FheUint64", "safe", par_transfer_safe::<FheUint64>);
|
||||
print_transfer_pbs_counts(
|
||||
&cks,
|
||||
"FheUint64",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
par_transfer_safe::<FheUint64>,
|
||||
);
|
||||
}
|
||||
|
||||
match get_bench_type() {
|
||||
BenchmarkType::Latency => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
par_transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
par_transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
par_transfer_overflow::<FheUint64>,
|
||||
);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::safe",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
par_transfer_safe::<FheUint64>,
|
||||
);
|
||||
|
||||
group.finish();
|
||||
}
|
||||
|
||||
BenchmarkType::Throughput => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
cuda_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
cuda_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::no_cmux",
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
transfer_no_cmux::<FheUint64>,
|
||||
);
|
||||
cuda_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::overflow",
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
transfer_overflow::<FheUint64>,
|
||||
);
|
||||
cuda_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::safe",
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
transfer_safe::<FheUint64>,
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1027,69 +1034,57 @@ fn main() {
|
||||
|
||||
let mut c = Criterion::default().sample_size(10).configure_from_args();
|
||||
|
||||
let bench_name = "hlapi::hpu::erc7984";
|
||||
|
||||
match get_bench_type() {
|
||||
BenchmarkType::Latency => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
// Erc7984 optimized instruction only available on Hpu
|
||||
bench_transfer_latency(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::hpu_optim",
|
||||
Erc7984::Transfer(TransferFlavor::HpuOptim),
|
||||
transfer_hpu::<FheUint64>,
|
||||
);
|
||||
// Erc7984 SIMD instruction only available on Hpu
|
||||
bench_transfer_latency_simd(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::hpu_simd",
|
||||
Erc7984::Transfer(TransferFlavor::HpuSimd),
|
||||
transfer_hpu_simd::<FheUint64>,
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
|
||||
BenchmarkType::Throughput => {
|
||||
let mut group = c.benchmark_group(bench_name);
|
||||
hpu_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::whitepaper",
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
transfer_whitepaper::<FheUint64>,
|
||||
);
|
||||
// Erc7984 optimized instruction only available on Hpu
|
||||
hpu_bench_transfer_throughput(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::hpu_optim",
|
||||
Erc7984::Transfer(TransferFlavor::HpuOptim),
|
||||
transfer_hpu::<FheUint64>,
|
||||
);
|
||||
// Erc7984 SIMD instruction only available on Hpu
|
||||
hpu_bench_transfer_throughput_simd(
|
||||
&mut group,
|
||||
&mut c,
|
||||
&cks,
|
||||
bench_name,
|
||||
"FheUint64",
|
||||
"transfer::hpu_simd",
|
||||
Erc7984::Transfer(TransferFlavor::HpuSimd),
|
||||
transfer_hpu_simd::<FheUint64>,
|
||||
);
|
||||
group.finish();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use benchmark::params_aliases::*;
|
||||
use benchmark::utilities::{throughput_num_threads, write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkType};
|
||||
use benchmark_spec::{get_bench_type, BenchmarkType, TestResult};
|
||||
use criterion::{criterion_group, Criterion, Throughput};
|
||||
use rand::prelude::*;
|
||||
use rayon::prelude::*;
|
||||
use std::env;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tfhe::core_crypto::prelude::LweCiphertextCount;
|
||||
use tfhe::integer::key_switching_key::KeySwitchingKey;
|
||||
@@ -61,12 +59,6 @@ fn compute_load_config() -> Vec<ZkComputeLoad> {
|
||||
conf
|
||||
}
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
fn zk_throughput_num_elements() -> u64 {
|
||||
// Zk verify uses pools of 32 threads for a single verification
|
||||
let pool_size = 32;
|
||||
@@ -217,11 +209,7 @@ fn cpu_pke_zk_verify(c: &mut Criterion, results_file: &Path) {
|
||||
.sample_size(15)
|
||||
.measurement_time(std::time::Duration::from_secs(60));
|
||||
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
for (param_pke, param_casting, param_fhe) in [(
|
||||
BENCH_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
|
||||
@@ -271,7 +259,8 @@ fn cpu_pke_zk_verify(c: &mut Criterion, results_file: &Path) {
|
||||
let test_name =
|
||||
format!("zk::crs_sizes::{param_name}::{bits}_bits_packed_ZK{zk_vers:?}");
|
||||
|
||||
write_result(&mut file, &test_name, crs_data.len());
|
||||
benchmark_test_result.write_result(&test_name, crs_data.len());
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
shortint_params,
|
||||
@@ -321,11 +310,9 @@ fn cpu_pke_zk_verify(c: &mut Criterion, results_file: &Path) {
|
||||
"zk::proven_list_size::{param_name}::{bits}_bits_packed_{crs_size}_bits_crs_{zk_load}_ZK{zk_vers:?}"
|
||||
);
|
||||
|
||||
write_result(
|
||||
&mut file,
|
||||
&test_name,
|
||||
proven_ciphertext_list_serialized.len(),
|
||||
);
|
||||
benchmark_test_result
|
||||
.write_result(&test_name, proven_ciphertext_list_serialized.len());
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
shortint_params,
|
||||
@@ -342,7 +329,8 @@ fn cpu_pke_zk_verify(c: &mut Criterion, results_file: &Path) {
|
||||
let test_name =
|
||||
format!("zk::proof_sizes::{param_name}::{bits}_bits_packed_{crs_size}_bits_crs_{zk_load}_ZK{zk_vers:?}");
|
||||
|
||||
write_result(&mut file, &test_name, proof_size);
|
||||
benchmark_test_result.write_result(&test_name, proof_size);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
shortint_params,
|
||||
@@ -522,11 +510,7 @@ mod cuda {
|
||||
.sample_size(15)
|
||||
.measurement_time(std::time::Duration::from_secs(60));
|
||||
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let (param_pke, param_ksk, param_fhe): (
|
||||
CompactPublicKeyEncryptionParameters,
|
||||
@@ -590,7 +574,7 @@ mod cuda {
|
||||
let test_name =
|
||||
format!("zk::crs_sizes::{param_name}::{bits}_bits_packed_ZK{zk_vers:?}");
|
||||
|
||||
write_result(&mut file, &test_name, crs_data.len());
|
||||
benchmark_test_result.write_result(&test_name, crs_data.len());
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
param_fhe,
|
||||
@@ -660,11 +644,8 @@ mod cuda {
|
||||
"zk::proven_list_size::{param_name}::{bits}_bits_packed_{crs_size}_bits_crs_{zk_load}_ZK{zk_vers:?}"
|
||||
);
|
||||
|
||||
write_result(
|
||||
&mut file,
|
||||
&test_name,
|
||||
proven_ciphertext_list_serialized.len(),
|
||||
);
|
||||
benchmark_test_result
|
||||
.write_result(&test_name, proven_ciphertext_list_serialized.len());
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
param_fhe,
|
||||
@@ -681,7 +662,7 @@ mod cuda {
|
||||
let test_name =
|
||||
format!("zk::proof_sizes::{param_name}::{bits}_bits_packed_{crs_size}_bits_crs_{zk_load}_ZK{zk_vers:?}");
|
||||
|
||||
write_result(&mut file, &test_name, proof_size);
|
||||
benchmark_test_result.write_result(&test_name, proof_size);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
param_fhe,
|
||||
|
||||
@@ -1,26 +1,16 @@
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use benchmark_spec::TestResult;
|
||||
use std::path::Path;
|
||||
use tfhe::boolean::parameters::{DEFAULT_PARAMETERS, PARAMETERS_ERROR_PROB_2_POW_MINUS_165};
|
||||
use tfhe::boolean::{client_key, server_key};
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
fn client_server_key_sizes(results_file: &Path) {
|
||||
let boolean_params_vec = [
|
||||
(DEFAULT_PARAMETERS, "DEFAULT_PARAMETERS"),
|
||||
(PARAMETERS_ERROR_PROB_2_POW_MINUS_165, "TFHE_LIB_PARAMETERS"),
|
||||
];
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
@@ -38,7 +28,7 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
let ksk_size = sks.key_switching_key_size_bytes();
|
||||
let test_name = format!("boolean_key_sizes_{params_name}_ksk");
|
||||
|
||||
write_result(&mut file, &test_name, ksk_size);
|
||||
benchmark_test_result.write_result(&test_name, ksk_size);
|
||||
write_to_json_unchecked::<u32, _>(
|
||||
&test_name,
|
||||
*params,
|
||||
@@ -58,7 +48,7 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
let bsk_size = sks.bootstrapping_key_size_bytes();
|
||||
let test_name = format!("boolean_key_sizes_{params_name}_bsk");
|
||||
|
||||
write_result(&mut file, &test_name, bsk_size);
|
||||
benchmark_test_result.write_result(&test_name, bsk_size);
|
||||
write_to_json_unchecked::<u32, _>(
|
||||
&test_name,
|
||||
*params,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use benchmark::params::{get_classical_tuniform_groups, get_multi_bit_tuniform_groups};
|
||||
use benchmark::params_aliases::*;
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::TestResult;
|
||||
use rand::Rng;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tfhe::integer::U256;
|
||||
use tfhe::keycache::NamedParam;
|
||||
@@ -15,22 +14,10 @@ use tfhe::{
|
||||
CompressedSquashedNoiseCiphertextList, ConfigBuilder, FheUint64,
|
||||
};
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
pub fn ct_sizes(results_file: &Path) {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
@@ -87,7 +74,7 @@ pub fn ct_sizes(results_file: &Path) {
|
||||
let params_record = param_fhe;
|
||||
|
||||
let mut write_and_record_result = |res: usize, test_name: &str, display_name: &str| {
|
||||
write_result(&mut file, test_name, res);
|
||||
benchmark_test_result.write_result(test_name, res);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
test_name,
|
||||
params_record,
|
||||
@@ -174,13 +161,7 @@ pub fn cpk_and_cctl_sizes(results_file: &Path) {
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
@@ -205,7 +186,7 @@ pub fn cpk_and_cctl_sizes(results_file: &Path) {
|
||||
let cpk_size = bincode::serialize(&public_key).unwrap().len();
|
||||
|
||||
println!("PK size: {cpk_size} bytes");
|
||||
write_result(&mut file, &test_name, cpk_size);
|
||||
benchmark_test_result.write_result(&test_name, cpk_size);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
@@ -227,7 +208,7 @@ pub fn cpk_and_cctl_sizes(results_file: &Path) {
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {cctl_size} bytes");
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
benchmark_test_result.write_result(&test_name, cctl_size);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
@@ -273,7 +254,7 @@ pub fn cpk_and_cctl_sizes(results_file: &Path) {
|
||||
|
||||
println!("Compact CT list for {NB_CTXT} CTs: {cctl_size} bytes");
|
||||
|
||||
write_result(&mut file, &test_name, cctl_size);
|
||||
benchmark_test_result.write_result(&test_name, cctl_size);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use benchmark::params::get_classical_tuniform_groups;
|
||||
use benchmark::params_aliases::*;
|
||||
use benchmark::utilities::{write_to_json_unchecked, CryptoParametersRecord, OperatorType};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use benchmark_spec::TestResult;
|
||||
use std::path::Path;
|
||||
use tfhe::keycache::NamedParam;
|
||||
use tfhe::shortint::atomic_pattern::compressed::CompressedAtomicPatternServerKey;
|
||||
@@ -18,12 +17,6 @@ use tfhe::shortint::{
|
||||
CompressedServerKey, PBSParameters, ServerKey,
|
||||
};
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
fn client_server_key_sizes(results_file: &Path) {
|
||||
let shortint_params_vec: Vec<PBSParameters> = vec![
|
||||
BENCH_PARAM_MESSAGE_1_CARRY_1_KS_PBS_TUNIFORM_2M128.into(),
|
||||
@@ -59,11 +52,8 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
BENCH_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_3_CARRY_3_KS_PBS_TUNIFORM_2M128.into(),
|
||||
BENCH_PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_4_CARRY_4_KS_PBS_TUNIFORM_2M128.into(),
|
||||
];
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
@@ -83,7 +73,8 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
let ksk_size = sks.key_switching_key_size_bytes();
|
||||
let test_name = format!("shortint_key_sizes_{}_ksk", params.name());
|
||||
|
||||
write_result(&mut file, &test_name, ksk_size);
|
||||
benchmark_test_result.write_result(&test_name, ksk_size);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
@@ -103,7 +94,8 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
let bsk_size = sks.bootstrapping_key_size_bytes();
|
||||
let test_name = format!("shortint_key_sizes_{}_bsk", params.name());
|
||||
|
||||
write_result(&mut file, &test_name, bsk_size);
|
||||
benchmark_test_result.write_result(&test_name, bsk_size);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
@@ -124,7 +116,8 @@ fn client_server_key_sizes(results_file: &Path) {
|
||||
let bsk_compressed_size = sks_compressed.bootstrapping_key_size_bytes();
|
||||
let test_name = format!("shortint_key_sizes_{}_bsk_compressed", params.name());
|
||||
|
||||
write_result(&mut file, &test_name, bsk_compressed_size);
|
||||
benchmark_test_result.write_result(&test_name, bsk_compressed_size);
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
params,
|
||||
@@ -152,12 +145,12 @@ fn measure_serialized_size<T: serde::Serialize, P: Into<CryptoParametersRecord<u
|
||||
param_name: &str,
|
||||
test_name_suffix: &str,
|
||||
display_name: &str,
|
||||
file: &mut File,
|
||||
file: &mut TestResult,
|
||||
) {
|
||||
let serialized = bincode::serialize(to_serialize).unwrap();
|
||||
let size = serialized.len();
|
||||
let test_name = format!("shortint_key_sizes_{param_name}_{test_name_suffix}");
|
||||
write_result(file, &test_name, size);
|
||||
file.write_result(&test_name, size);
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
&test_name,
|
||||
param.clone(),
|
||||
@@ -172,11 +165,7 @@ fn measure_serialized_size<T: serde::Serialize, P: Into<CryptoParametersRecord<u
|
||||
}
|
||||
|
||||
fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
println!("Measuring shortint key sizes:");
|
||||
|
||||
@@ -200,7 +189,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"ksk",
|
||||
"KSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&ap.bootstrapping_key,
|
||||
@@ -208,7 +197,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"bsk",
|
||||
"BSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
AtomicPatternServerKey::KeySwitch32(ap) => {
|
||||
@@ -218,7 +207,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"ksk",
|
||||
"KSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&ap.bootstrapping_key,
|
||||
@@ -226,7 +215,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"bsk",
|
||||
"BSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
AtomicPatternServerKey::Dynamic(_) => panic!("Dynamic atomic pattern not supported"),
|
||||
@@ -240,7 +229,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"ksk_compressed",
|
||||
"KSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&comp_ap.bootstrapping_key(),
|
||||
@@ -248,7 +237,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"bsk_compressed",
|
||||
"BSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
CompressedAtomicPatternServerKey::KeySwitch32(comp_ap) => {
|
||||
@@ -258,7 +247,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"ksk_compressed",
|
||||
"KSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&comp_ap.bootstrapping_key(),
|
||||
@@ -266,7 +255,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_fhe_name,
|
||||
"bsk_compressed",
|
||||
"BSK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -278,14 +267,21 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
let compressed_pk = CompressedCompactPublicKey::new(&compact_private_key);
|
||||
let pk = compressed_pk.decompress();
|
||||
|
||||
measure_serialized_size(&pk, pke_param, ¶m_pke_name, "cpk", "CPK", &mut file);
|
||||
measure_serialized_size(
|
||||
&pk,
|
||||
pke_param,
|
||||
¶m_pke_name,
|
||||
"cpk",
|
||||
"CPK",
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&compressed_pk,
|
||||
pke_param,
|
||||
¶m_pke_name,
|
||||
"cpk_compressed",
|
||||
"CPK",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
|
||||
let casting_param = dedicated_pke_params.ksk_params;
|
||||
@@ -303,7 +299,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_casting_name,
|
||||
"casting_key",
|
||||
"CastKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&compressed_casting_key.into_raw_parts().0,
|
||||
@@ -311,7 +307,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_casting_name,
|
||||
"casting_key_compressed",
|
||||
"CastKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -329,7 +325,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_compression_name,
|
||||
"compression_key",
|
||||
"CompressionKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&decompression_key,
|
||||
@@ -337,7 +333,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_compression_name,
|
||||
"decompression_key",
|
||||
"CompressionKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
|
||||
let (compressed_compression_key, compressed_decompression_key) =
|
||||
@@ -349,7 +345,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_compression_name,
|
||||
"compressed_compression_key",
|
||||
"CompressedCompressionKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
measure_serialized_size(
|
||||
&compressed_decompression_key,
|
||||
@@ -357,7 +353,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
¶m_compression_name,
|
||||
"compressed_decompression_key",
|
||||
"CompressedCompressionKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -373,7 +369,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
&noise_squashing_param.name(),
|
||||
"noise_squashing_key",
|
||||
"NoiseSquashingKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
if let Some(noise_squashing_comp_param) =
|
||||
meta_noise_squashing_param.compression_parameters
|
||||
@@ -392,7 +388,7 @@ fn tuniform_key_set_sizes(results_file: &Path) {
|
||||
&noise_squashing_comp_param.name(),
|
||||
"noise_squashing_compression_key",
|
||||
"NoiseSquashingCompressionKey",
|
||||
&mut file,
|
||||
&mut benchmark_test_result,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use benchmark::utilities::{write_to_json_unchecked, OperatorType};
|
||||
use benchmark_spec::TestResult;
|
||||
use clap::Parser;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tfhe::keycache::NamedParam;
|
||||
use tfhe::shortint::keycache::get_shortint_parameter_set_from_name;
|
||||
@@ -29,18 +28,8 @@ fn params_from_name(name: &str) -> ClassicPBSParameters {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_result(file: &mut File, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
|
||||
pub fn parse_wasm_benchmarks(results_file: &Path, raw_results_file: &Path) {
|
||||
File::create(results_file).expect("create results file failed");
|
||||
let mut file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(results_file)
|
||||
.expect("cannot open parsed results file");
|
||||
let mut benchmark_test_result = TestResult::from_path(results_file);
|
||||
|
||||
let operator = OperatorType::Atomic;
|
||||
|
||||
@@ -60,10 +49,10 @@ pub fn parse_wasm_benchmarks(results_file: &Path, raw_results_file: &Path) {
|
||||
let params: PBSParameters = params_from_name(name_parts[1]).into();
|
||||
println!("{name_parts:?}");
|
||||
if full_name.contains("_size") {
|
||||
write_result(&mut file, &prefixed_full_name, *val as usize);
|
||||
benchmark_test_result.write_result(&prefixed_full_name, *val as usize);
|
||||
} else {
|
||||
let value_in_ns = (val * 1_000_000_f32) as usize;
|
||||
write_result(&mut file, &prefixed_full_name, value_in_ns);
|
||||
benchmark_test_result.write_result(&prefixed_full_name, value_in_ns);
|
||||
}
|
||||
|
||||
write_to_json_unchecked::<u64, _>(
|
||||
|
||||
@@ -29,7 +29,7 @@ Learn the basics of TFHE-rs, set it up, and make it run with ease.
|
||||
|
||||
Start building with TFHE-rs by exploring its core features, discovering essential guides, and learning more with user-friendly tutorials.
|
||||
|
||||
<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>FHE Computations</strong></td><td>Run FHE computation on encrypted data.</td><td><ul><li><a href="fhe-computation/types/">Types </a></li><li><a href="fhe-computation/operations/">Operations</a></li></ul></td><td><a href=".gitbook/assets/bronze-gradient.png">bronze-gradient.png</a></td></tr><tr><td><strong>Configuration</strong></td><td>Advanced configuration for better performance.</td><td><ul><li><a href="configuration/rust-configuration.md">Advanced Rust </a></li><li><a href="configuration/gpu-acceleration/run-on-gpu.md">GPU acceleration</a></li><li><a href="configuration/hpu-acceleration/run-on-hpu.md">HPU acceleration</a></li></ul></td><td><a href=".gitbook/assets/yellow-gradient.png">yellow-gradient.png</a></td></tr><tr><td><strong>Integration</strong></td><td>Use TFHE-rs in different contexts or platforms.</td><td><ul><li><a href="integration/c-api.md">C API</a></li><li><a href="integration/js-on-wasm-api.md">JS on WASM API</a></li></ul></td><td><a href=".gitbook/assets/orange-gradient.png">orange-gradient.png</a></td></tr></tbody></table>
|
||||
<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>FHE Computations</strong></td><td>Run FHE computation on encrypted data.</td><td><ul><li><a href="fhe-computation/types/">Types </a></li><li><a href="fhe-computation/operations/">Operations</a></li></ul></td><td><a href=".gitbook/assets/bronze-gradient.png">bronze-gradient.png</a></td></tr><tr><td><strong>Configuration</strong></td><td>Advanced configuration for better performance.</td><td><ul><li><a href="configuration/rust-configuration.md">Advanced Rust </a></li><li><a href="configuration/gpu-acceleration/run-on-gpu.md">GPU acceleration</a></li><li><a href="configuration/hpu-acceleration/run-on-hpu.md">HPU acceleration</a></li></ul></td><td><a href=".gitbook/assets/yellow-gradient.png">yellow-gradient.png</a></td></tr><tr><td><strong>Integration</strong></td><td>Use TFHE-rs in different contexts or platforms..</td><td><ul><li><a href="integration/c-api.md">C API</a></li><li><a href="integration/js-on-wasm-api.md">JS on WASM API</a></li></ul></td><td><a href=".gitbook/assets/orange-gradient.png">orange-gradient.png</a></td></tr></tbody></table>
|
||||
|
||||
## Explore more
|
||||
|
||||
@@ -42,7 +42,7 @@ Explore step-by-step guides that walk you through real-world uses of TFHE-rs.&#x
|
||||
* [Homomorphic parity bit](tutorials/parity-bit.md): Learn how to implement a parity bit calculation over encrypted data
|
||||
* [Homomorphic case changing on ASCII string](tutorials/ascii-fhe-string.md): See how to process string data securely by changing cases while keeping the data encrypted.
|
||||
* [SHA256 with Boolean API](tutorials/sha256-bool.md): Delve into a more complex example: implementing the SHA256 hash function entirely on encrypted boolean values.
|
||||
* [All tutorials](tutorials/see-all-tutorials.md): A complete list of all available tutorials in one place.
|
||||
* [All tutorials](tutorials/see-all-tutorials.md): A complete list of all available tutorials in one place.tutorials: A complete list of all available tutorials in one place.
|
||||
|
||||
### References & Explanations
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ To reproduce TFHE-rs GPU benchmarks, see [this dedicated page](../../getting-sta
|
||||
|
||||
## GPU TFHE-rs features
|
||||
|
||||
By default, the GPU backend uses specific cryptographic parameters. When calling the [`tfhe::ConfigBuilder::default()`](https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default) function, the cryptographic parameters for PBS will be:
|
||||
By default, the GPU backend uses specific cryptographic parameters. When calling the [`tfhe::ConfigBuilder::default()`](https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default) function, the cryptographic for PBS will be:
|
||||
- PBS parameters: [`PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS`](https://docs.rs/tfhe/latest/tfhe/shortint/parameters/aliases/constant.PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS.html)
|
||||
|
||||
These PBS parameters are accompanied by the following compression parameters:
|
||||
@@ -62,7 +62,7 @@ The key differences between the CPU API and the GPU API are:
|
||||
|
||||
To compile and execute GPU TFHE-rs programs, make sure your system has the following software installed.
|
||||
|
||||
* CUDA version >= 10
|
||||
* Cuda version >= 10
|
||||
* Compute Capability >= 3.0
|
||||
* [gcc](https://gcc.gnu.org/) >= 8.0 - check this [page](https://gist.github.com/ax3l/9489132) for more details about nvcc/gcc compatible versions
|
||||
* [cmake](https://cmake.org/) >= 3.24
|
||||
|
||||
@@ -5,7 +5,7 @@ This document explains the mechanism and steps to generate an oblivious encrypte
|
||||
The goal is to give to the server the possibility to generate a random value, which will be obtained in an encrypted format and will remain unknown to the server.
|
||||
|
||||
The main method for this is `FheUint::generate_oblivious_pseudo_random_custom_range` which returns an integer in the given range.
|
||||
Currently the range can only be in the form `[0, excluded_upper_bound)` with any `excluded_upper_bound` in `[1, 2^64)`
|
||||
Currently the range can only be in the form `[0, excluded_upper_bound[` with any `excluded_upper_bound` in `[1, 2^64[`
|
||||
It follows a distribution close to the uniform.
|
||||
|
||||
This function guarantees the norm-1 distance (defined as ∆(P,Q) := 1/2 Sum[ω∈Ω] |P(ω) − Q(ω)|)
|
||||
@@ -20,11 +20,11 @@ If the range is a power of 2, the distribution is uniform (for any `max_distance
|
||||
|
||||
|
||||
For powers of 2 specifically there are two methods on `FheUint` and `FheInt` (based on [this article](https://eprint.iacr.org/2024/665)):
|
||||
- `generate_oblivious_pseudo_random` which return an integer taken uniformly in the full integer range (`[0; 2^N[` for a `FheUintN` and `[-2^(N-1); 2^(N-1))` for a `FheIntN`).
|
||||
- `generate_oblivious_pseudo_random` which return an integer taken uniformly in the full integer range (`[0; 2^N[` for a `FheUintN` and `[-2^(N-1); 2^(N-1)[` for a `FheIntN`).
|
||||
- `generate_oblivious_pseudo_random_bounded` which return an integer taken uniformly in `[0; 2^random_bits_count[`. For a `FheUintN`, we must have `random_bits_count <= N`. For a `FheIntN`, we must have `random_bits_count <= N - 1`.
|
||||
|
||||
|
||||
These methods take a seed `Seed` as input, which could be any `u128` value.
|
||||
These method functions take a seed `Seed` as input, which could be any `u128` value.
|
||||
They rely on the use of the usual server key.
|
||||
The output is reproducible, i.e., the function is deterministic from the inputs: assuming the same hardware, seed and server key, this function outputs the same random encrypted value.
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ pub fn main() {
|
||||
|
||||
// FheInt16 case
|
||||
let clear: i16 = -42;
|
||||
let enc = FheInt16::encrypt(clear, &cks);
|
||||
let enc = FheInt10::encrypt(clear, &cks);
|
||||
let bitand = &enc & &enc;
|
||||
let squashed = bitand.squash_noise().unwrap();
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ These operations might be slower than their non-overflow-detecting equivalent, s
|
||||
|
||||
Here's the list of operations supported along with their symbol:
|
||||
|
||||
| name | symbol | type |
|
||||
| ------------------------------------------------------- | ----------------- | ------ |
|
||||
| [Add](https://doc.rust-lang.org/std/ops/trait.Add.html) | `overflowing_add` | Binary |
|
||||
| [Sub](https://doc.rust-lang.org/std/ops/trait.Sub.html) | `overflowing_sub` | Binary |
|
||||
| [Mul](https://doc.rust-lang.org/std/ops/trait.Mul.html) | `overflowing_mul` | Binary |
|
||||
| name | symbol | type |
|
||||
| ------------------------------------------------------- | -------------- | ------ |
|
||||
| [Add](https://doc.rust-lang.org/std/ops/trait.Add.html) | `overflow_add` | Binary |
|
||||
| [Sub](https://doc.rust-lang.org/std/ops/trait.Sub.html) | `overflow_sub` | Binary |
|
||||
| [Mul](https://doc.rust-lang.org/std/ops/trait.Mul.html) | `overflow_mul` | Binary |
|
||||
|
||||
The usage of these operations is similar to the standard ones. The key difference is in the decryption process, as shown in following example:
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Ciphertext Re-Randomization
|
||||
|
||||
This document explains the ciphertext re-randomization feature in TFHE-rs, designed to protect FHE computations against attacks under the sIND-CPA^D security model (`s` stands for strong), described in the paper [Drifting Towards Better Error Probabilities in Fully Homomorphic Encryption Schemes](https://eprint.iacr.org/2024/1718).
|
||||
In the paper [Drifting Towards Better Error Probabilities in Fully Homomorphic Encryption Schemes](https://eprint.iacr.org/2024/1718), Bernard et al. introduced the sIND-CPA^D security model (`s` stands for strong here).
|
||||
|
||||
This document explains the ciphertext re-randomization feature in TFHE-rs, designed to protect FHE computations against attacks under the sIND-CPA^D security model.
|
||||
|
||||
To be secure under that model, **TFHE-rs** provides a re-randomization primitive that allows users to re-randomize ciphertexts before they are used as inputs to a predefined FHE program `F`. In this context, `F` should be understood as any FHE computation that must remain secure under the sIND-CPA^D model. All encrypted inputs to `F` must be re-randomized prior to execution.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This document describes how to use trivial encryption in **TFHE-rs** to initiali
|
||||
|
||||
Sometimes, the server side needs to initialize a value. For example, when computing the sum of a list of ciphertexts, you typically initialize the `sum` variable to `0`.
|
||||
|
||||
Instead of asking the client to send an actual encrypted zero, the server can use a trivial encryption. A trivial encryption creates a ciphertext that contains the desired value but isn't securely encrypted - essentially anyone with any key can decrypt it.
|
||||
Instead of asking the client to send an actual encrypted zero, the server can use a trivial encryption. A trivial encryption creates a ciphertext that contains the desired value but isn't securely encrypted - essentially anyone, any key can decrypt it.
|
||||
|
||||
```rust
|
||||
use tfhe::prelude::*;
|
||||
|
||||
@@ -5,7 +5,7 @@ easily upgrade a ciphertext that is under older parameters to newer parameters.
|
||||
|
||||
It is different and complementary to the data versioning feature, as the
|
||||
data versioning feature allows loading ciphertexts generated
|
||||
with a previous TFHE-rs version if the ciphertext structure changed.
|
||||
with a previous TFHE-rs version if the ciphertext structurally changed.
|
||||
|
||||
|
||||
The `UpgradeKeyChain` first needs to know about possible parameters, for that,
|
||||
|
||||
@@ -25,14 +25,14 @@ fn main() {
|
||||
```
|
||||
|
||||
{% hint style="info" %}
|
||||
These default parameters may be updated in future releases of **TFHE-rs**, potentially causing incompatibilities between versions. For production systems, it is therefore recommended to specify a fixed parameter set.
|
||||
These default parameters may be updated with in future releases of **TFHE-rs**, potentially causing incompatibilities between versions. For production systems, it is therefore recommended to specify a fixed parameter set.
|
||||
{% endhint %}
|
||||
|
||||
## Parameters versioning and naming scheme
|
||||
|
||||
Parameter sets are versioned for backward compatibility. This means that each set of parameters can be tied to a specific version of **TFHE-rs**, so that they remain unchanged and compatible after an upgrade.
|
||||
|
||||
All parameter sets are stored as variables inside the `tfhe::shortint::parameters` module, with submodules named after the versions of **TFHE-rs** in which these parameters were added. For example, parameters added in **TFHE-rs** v1.0 can be found inside `tfhe::shortint::parameters::v1_0`.
|
||||
All parameter sets are stored as variables inside the `tfhe::shortint::parameters` module, with submodules named after the versions of **TFHE-rs** in which these parameters where added. For example, parameters added in **TFHE-rs** v1.0 can be found inside `tfhe::shortint::parameters::v1_0`.
|
||||
|
||||
The naming convention of these parameters indicates their capabilities. Taking `tfhe::parameters::v1_0::V1_0_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128` as an example:
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Compressing ciphertexts after some homomorphic computation
|
||||
### Compression ciphertexts after some homomorphic computation
|
||||
|
||||
You can compress ciphertexts at any time, even after performing multiple homomorphic operations.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This document explains the `serialization` and `deserialization` features that a
|
||||
|
||||
## Safe serialization/deserialization
|
||||
|
||||
When dealing with sensitive types, it's important to implement safe serialization and safe deserialization functions to prevent runtime errors and enhance security. **TFHE-rs** provides easy to use functions for this purpose, such as `safe_serialize`, `safe_deserialize` and `safe_deserialize_conformant`.
|
||||
When dealing with sensitive types, it's important to implement safe serialization and safe deserialization functions to prevent runtime errors and enhance security. **TFHE-rs** provide easy to use functions for this purpose, such as `safe_serialize`, `safe_deserialize` and `safe_deserialize_conformant`.
|
||||
|
||||
Here is a basic example on how to use it:
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
a *= &b; // Clear equivalent computations: 15 * 27 mod 256 = 149
|
||||
b = &b + &c; // Clear equivalent computations: 27 + 43 mod 256 = 70
|
||||
b -= 76u8; // Clear equivalent computations: 70 - 76 mod 256 = 250
|
||||
d -= 13i8; // Clear equivalent computations: -87 - 13 = -100 in [-128, 127]
|
||||
d -= 13i8; // Clear equivalent computations: -87 - 13 = 100 in [-128, 128[
|
||||
|
||||
let dec_a: u8 = a.decrypt(&keys);
|
||||
let dec_b: u8 = b.decrypt(&keys);
|
||||
|
||||
@@ -15,8 +15,8 @@ Supported operations:
|
||||
| [Not Equal](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `ne` | Binary |
|
||||
| [Greater Than](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `gt` | Binary |
|
||||
| [Greater or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `ge` | Binary |
|
||||
| [Less Than](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
|
||||
| [Less Than or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
|
||||
| [Lower](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
|
||||
| [Lower or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
|
||||
|
||||
The following example shows how to perform comparison operations:
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ This document details the string operations supported by **TFHE-rs**.
|
||||
| [find](https://doc.rust-lang.org/stable/std/primitive.str.html#method.find) |find | FheAsciiString | FheAsciiString or ClearString |
|
||||
| [rfind](https://doc.rust-lang.org/stable/std/primitive.str.html#method.rfind) |rfind | FheAsciiString | FheAsciiString or ClearString |
|
||||
| [strip_prefix](https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_prefix) |strip_prefix | FheAsciiString | FheAsciiString or ClearString |
|
||||
| [strip_suffix](https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix) |strip_suffix | FheAsciiString | FheAsciiString or ClearString |
|
||||
| [strip_suffix](https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix) |strip_suffix | FheAsciiString | FheAsci---iString or ClearString |
|
||||
| [concat](https://doc.rust-lang.org/stable/std/primitive.str.html#method.concat) |concat | FheAsciiString | FheAsciiString |
|
||||
| [repeat](https://doc.rust-lang.org/stable/std/primitive.str.html#method.repeat) |repeat | FheAsciiString | u16 or u32 or i32 or usize or (FheUint16, u16) |
|
||||
| [trim_end](https://doc.rust-lang.org/stable/std/primitive.str.html#method.trim_end) |trim_end | FheAsciiString | |
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This document details the ternary operations supported by **TFHE-rs**.
|
||||
|
||||
The ternary conditional operator executes conditional instructions in the form `if cond { choice_if_true } else { choice_if_false }`.
|
||||
The ternary conditional operator execute conditional instructions in the form `if cond { choice_if_true } else { choice_if_false }`.
|
||||
|
||||
| name | symbol | type |
|
||||
| ---------------- | -------- | ------- |
|
||||
|
||||
@@ -54,7 +54,7 @@ a: Ok(1234), b: Ok(4567), c: Ok(89101112)
|
||||
a * b = Ok(5635678)
|
||||
```
|
||||
|
||||
If any input to `mul_all` is not a trivial ciphertext, the computations will be done 100% in FHE, and the program will output:
|
||||
If any input to `mul_all` is not a trivial ciphertexts, the computations will be done 100% in FHE, and the program will output:
|
||||
|
||||
```console
|
||||
a: Err(NotTrivialCiphertextError), b: Err(NotTrivialCiphertextError), c: Err(NotTrivialCiphertextError)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This document describes the array types provided by the High-level API.
|
||||
|
||||
These new encrypted types allow you to easily perform array and tensor operations on encrypted data, taking care of the iteration and shape logic for you.
|
||||
This new encrypted types allow you to easily perform array and tensor operations on encrypted data, taking care of the iteration and shape logic for you.
|
||||
|
||||
It also implements efficient algorithms in some cases, like summing elements of an array.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This document explains the FheAsciiString type for handling encrypted strings in TFHE-rs.
|
||||
|
||||
TFHE-rs has support for ASCII strings with the type FheAsciiString.
|
||||
TFHE-rs has supports for ASCII strings with the type FheAsciiString.
|
||||
You can enable this feature using the flag: --features=strings
|
||||
|
||||
{% hint style="warning" %}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
TFHE is a Fully Homomorphic Encryption (FHE) scheme based on Learning With Errors (LWE), which is a secure cryptographic primitive against even quantum computers. The **TFHE-rs** library implements Zama’s variant of TFHE.
|
||||
|
||||
### Homomorphic Encryption Basics
|
||||
#### Homomorphic Encryption Basics
|
||||
|
||||
The basic elements of cryptography:
|
||||
|
||||
@@ -30,7 +30,7 @@ FHE allows to compute on ciphertexts without revealing the content of the messag
|
||||
* **Homomorphic addition:** $$E[x] + E[y] = E[x + y]$$
|
||||
* **Homomorphic multiplication:** $$E[x] * E[y] = E[x * y]$$
|
||||
|
||||
### Zama's variant of TFHE
|
||||
## Zama's variant of TFHE
|
||||
|
||||
Zama's variant of TFHE is a fully homomorphic scheme that takes fixed-precision numbers as messages. It implements all homomorphic operations needed, such as addition and function evaluation via Programmable Bootstrapping.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ By default, **TFHE-rs** makes the assumption that hardware AES features are enab
|
||||
- x86_64: sse2, aesni
|
||||
- aarch64: aes, neon
|
||||
|
||||
To add support for older CPUs, import **TFHE-rs** with the `software-prng` feature in your `Cargo.toml`:
|
||||
To add support for older CPU, import **TFHE-rs** with the `software-prng` feature in your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "~1.6.0", features = ["boolean", "shortint", "integer", "software-prng"] }
|
||||
|
||||
@@ -104,11 +104,11 @@ fn main() {
|
||||
let a = FheUint8::encrypt(clear_a, &client_key);
|
||||
let b = FheUint8::encrypt(clear_b, &client_key);
|
||||
|
||||
// Server-side
|
||||
//Server-side
|
||||
set_server_key(server_key);
|
||||
let result = a + b;
|
||||
|
||||
// Client-side
|
||||
//Client-side
|
||||
let decrypted_result: u8 = result.decrypt(&client_key);
|
||||
|
||||
let clear_result = clear_a + clear_b;
|
||||
|
||||
@@ -103,7 +103,7 @@ params_lwe = LWE.Parameters(n=879, q=2**64, Xs=ND.Binary, Xe=ND.TUniform(46))
|
||||
LWE.estimate(params_lwe, deny_list=("arora-gb", "bkw"))
|
||||
```
|
||||
|
||||
The output corresponds to a selection of attack costs (`usvp`, `bdd`, etc), each with running time `rop`. The security level is the `log2` of the smallest `rop` value (in this case `dual_hybrid` with `2^134.8`). Therefore, the security level of this parameter set is ~134 bits. The same technique can be applied to the GLWE parameters by replacing the LWE dimension `879` by `k*N = 4*512`, i.e. `n=2048` and `Xe=ND.TUniform(46)` by `Xe = ND.TUniform(17)`, that is:
|
||||
The output corresponds to a selection of attack costs (`usvp`, `bdd`, etc), each with running time `rop`. The security level is the `log2` of the smallest `rop` value (in this case `dual_hybrid` with `2^134.8`). Therefore, the security level of this parameter set is ~134 bits. The same technique can be applied to the GLWE parameters by replacing the LWE dimension `879` by `k*N = 512*4`, i.e. `n=2048` and `Xe=ND.TUniform(46)` by `Xe = ND.TUniform(17)`, that is:
|
||||
|
||||
```
|
||||
from estimator import *
|
||||
@@ -124,6 +124,6 @@ The parameter sets for the x86 CPU backend with a $$p_{error} \le 2^{-128}$$ are
|
||||
|
||||
|
||||
|
||||
## Classical public key encryption
|
||||
## Classical public key encryption.
|
||||
|
||||
In classical public key encryption, the public key contains a given number of ciphertexts all encrypting the value 0. By setting the number of encryptions to 0 in the public key at $$m = \lceil (n+1) \log(q) \rceil + \lambda$$, where $$n$$ is the LWE dimension, $$q$$ is the ciphertext modulus, and $$\lambda$$ is the number of security bits. This construction is secure due to the leftover hash lemma, which relates to the impossibility of breaking the underlying multiple subset sum problem. This guarantees both a high-density subset sum and an exponentially large number of possible associated random vectors per LWE sample $$(a,b)$$.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This document describes the C bindings to the **TFHE-rs** high-level primitives for creating Fully Homomorphic Encryption (FHE) programs.
|
||||
|
||||
## Setting up TFHE-rs C API for C programming
|
||||
## Setting up TFHE-rs C API for C programming.
|
||||
|
||||
You can build **TFHE-rs** C API using the following command:
|
||||
|
||||
@@ -19,7 +19,7 @@ Locate files in the right path:
|
||||
* The `tfhe-c-api-dynamic-buffer.h` header
|
||||
* The static (.a) and dynamic (.so) libraries
|
||||
|
||||
Ensure your build system links the C or C++ program against **TFHE-rs** C API binaries and the dynamic buffer library.
|
||||
Ensure your build system configures the C or C++ program links against **TFHE-rs** C API binaries and the dynamic buffer library.
|
||||
|
||||
The following is a minimal `CMakeLists.txt` configuration example:
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This library makes it possible to execute **homomorphic operations over encrypte
|
||||
|
||||
The server, however, has to know the circuit to be evaluated. At the end of the computation, the server returns the encryption of the result to the user. Then the user can decrypt it with the `secret key`.
|
||||
|
||||
## General method to write a homomorphic circuit program
|
||||
## General method to write an homomorphic circuit program
|
||||
|
||||
The overall process to write an homomorphic program is the same for all types. The basic steps for using the TFHE-rs library are the following:
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ fn check_parity_bit_validity(
|
||||
) -> bool
|
||||
```
|
||||
|
||||
To make it generic, the first step is:
|
||||
To make it generic, the first steps is:
|
||||
|
||||
```Rust
|
||||
fn compute_parity_bit<BoolType>(
|
||||
|
||||
@@ -378,7 +378,7 @@ impl CompressedXofKeySet {
|
||||
}
|
||||
|
||||
/// Decompress the KeySet
|
||||
pub fn decompress(self) -> crate::Result<XofKeySet> {
|
||||
pub fn decompress(&self) -> crate::Result<XofKeySet> {
|
||||
let tag = self.compressed_server_key.tag.clone();
|
||||
let (mut public_key, expanded_server_key) = self.expand();
|
||||
// Server key tag is the source of truth; sync public key
|
||||
|
||||
@@ -6,10 +6,47 @@ mod traits;
|
||||
pub use backend::Backend;
|
||||
pub use bench_crate::BenchCrate;
|
||||
use serde::Serialize;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::{env, fmt};
|
||||
pub use tfhe::hlapi::HlapiBench;
|
||||
pub use tfhe::{HlIntegerOp, TfheLayer};
|
||||
|
||||
use crate::tfhe::hlapi::dex::Dex;
|
||||
use crate::tfhe::hlapi::erc7984::Erc7984;
|
||||
|
||||
pub struct TestResult {
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl TestResult {
|
||||
pub fn new(file_name: &str) -> Self {
|
||||
let file_path = Path::new(file_name);
|
||||
Self::from_path(file_path)
|
||||
}
|
||||
|
||||
pub fn from_path(path: &Path) -> Self {
|
||||
if !path.exists() {
|
||||
if let Some(parent) = path.parent() {
|
||||
std::fs::create_dir_all(parent).expect("cannot create parent dirs");
|
||||
}
|
||||
File::create(path).expect("cannot create result file");
|
||||
}
|
||||
let file = OpenOptions::new()
|
||||
.append(true)
|
||||
.open(path)
|
||||
.expect("cannot open result file");
|
||||
Self { file }
|
||||
}
|
||||
|
||||
pub fn write_result(&mut self, name: &str, value: usize) {
|
||||
let line = format!("{name},{value}\n");
|
||||
let error_message = format!("cannot write {name} result into file");
|
||||
self.file.write_all(line.as_bytes()).expect(&error_message);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub enum OperandType {
|
||||
CipherText,
|
||||
@@ -22,14 +59,36 @@ impl OperandType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
/// Benchmark type driven by the `__TFHE_RS_BENCH_TYPE` environment variable.
|
||||
///
|
||||
/// Only `Latency` and `Throughput` can come from the environment; `PbsCount`
|
||||
/// is hard-coded at specific call sites.
|
||||
#[derive(Clone, Copy, Serialize)]
|
||||
pub enum BenchmarkType {
|
||||
Latency,
|
||||
Throughput,
|
||||
}
|
||||
|
||||
/// The metric being recorded by a benchmark, used in [`BenchmarkSpec`].
|
||||
#[derive(Clone, Copy, Serialize)]
|
||||
pub enum BenchmarkMetric {
|
||||
Latency,
|
||||
Throughput,
|
||||
PbsCount,
|
||||
}
|
||||
|
||||
impl From<BenchmarkType> for BenchmarkMetric {
|
||||
fn from(ct: BenchmarkType) -> Self {
|
||||
match ct {
|
||||
BenchmarkType::Latency => BenchmarkMetric::Latency,
|
||||
BenchmarkType::Throughput => BenchmarkMetric::Throughput,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BenchmarkType {
|
||||
pub fn from_env() -> Result<Self, String> {
|
||||
/// Retrieves the benchmark type from the environment variable `__TFHE_RS_BENCH_TYPE`.
|
||||
fn from_env() -> Result<Self, String> {
|
||||
let raw_value = env::var("__TFHE_RS_BENCH_TYPE").unwrap_or("latency".to_string());
|
||||
match raw_value.to_lowercase().as_str() {
|
||||
"latency" => Ok(BenchmarkType::Latency),
|
||||
@@ -39,6 +98,9 @@ impl BenchmarkType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the benchmark type from the environment variable `__TFHE_RS_BENCH_TYPE`.
|
||||
///
|
||||
/// Returns only `Latency` or `Throughput` — never `PbsCount`.
|
||||
pub fn get_bench_type() -> &'static BenchmarkType {
|
||||
use std::sync::OnceLock;
|
||||
static BENCH_TYPE: OnceLock<BenchmarkType> = OnceLock::new();
|
||||
@@ -48,7 +110,7 @@ pub fn get_bench_type() -> &'static BenchmarkType {
|
||||
/// Enforces the naming convention for benchmark IDs.
|
||||
///
|
||||
/// ```text
|
||||
/// {crate}::{layer}::{bench}::{op}(::{backend})?(::throughput)?::{param}(::scalar)?(::{type})?
|
||||
/// {crate}::{layer}::{bench}::{op}(::{backend})?(::{benchmark_type})?::{param}(::scalar)?(::{type})?(::{num_elements}_elements)?
|
||||
/// ```
|
||||
///
|
||||
/// `param_name` and `type_name` are kept as `&str` because their values
|
||||
@@ -60,7 +122,8 @@ pub struct BenchmarkSpec<'a> {
|
||||
pub param_name: &'a str,
|
||||
pub operand_type: &'a OperandType,
|
||||
pub type_name: Option<&'a str>,
|
||||
pub bench_type: &'a BenchmarkType,
|
||||
pub bench_type: BenchmarkMetric,
|
||||
pub num_elements: Option<usize>,
|
||||
}
|
||||
|
||||
impl<'a> BenchmarkSpec<'a> {
|
||||
@@ -70,7 +133,8 @@ impl<'a> BenchmarkSpec<'a> {
|
||||
param_name: &'a str,
|
||||
operand_type: &'a OperandType,
|
||||
type_name: Option<&'a str>,
|
||||
bench_type: &'a BenchmarkType,
|
||||
bench_type: impl Into<BenchmarkMetric>,
|
||||
num_elements: Option<usize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bench_crate,
|
||||
@@ -78,16 +142,17 @@ impl<'a> BenchmarkSpec<'a> {
|
||||
param_name,
|
||||
operand_type,
|
||||
type_name,
|
||||
bench_type,
|
||||
bench_type: bench_type.into(),
|
||||
num_elements,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_hlapi(
|
||||
pub fn new_hlapi_ops(
|
||||
hlapi_op: HlIntegerOp,
|
||||
param_name: &'a str,
|
||||
operand_type: &'a OperandType,
|
||||
type_name: Option<&'a str>,
|
||||
bench_type: &'a BenchmarkType,
|
||||
bench_type: impl Into<BenchmarkMetric>,
|
||||
backend: Backend,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -96,7 +161,47 @@ impl<'a> BenchmarkSpec<'a> {
|
||||
param_name,
|
||||
operand_type,
|
||||
type_name,
|
||||
bench_type,
|
||||
bench_type: bench_type.into(),
|
||||
num_elements: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_hlapi_erc7984(
|
||||
hlapi_erc7984_op: Erc7984,
|
||||
param_name: &'a str,
|
||||
operand_type: &'a OperandType,
|
||||
type_name: Option<&'a str>,
|
||||
bench_type: impl Into<BenchmarkMetric>,
|
||||
backend: Backend,
|
||||
num_elements: Option<usize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bench_crate: BenchCrate::Tfhe(TfheLayer::Hlapi(HlapiBench::Erc7984(hlapi_erc7984_op))),
|
||||
backend,
|
||||
param_name,
|
||||
operand_type,
|
||||
type_name,
|
||||
bench_type: bench_type.into(),
|
||||
num_elements,
|
||||
}
|
||||
}
|
||||
pub fn new_hlapi_dex(
|
||||
hlapi_dex: Dex,
|
||||
param_name: &'a str,
|
||||
operand_type: &'a OperandType,
|
||||
type_name: Option<&'a str>,
|
||||
bench_type: impl Into<BenchmarkMetric>,
|
||||
backend: Backend,
|
||||
num_elements: Option<usize>,
|
||||
) -> Self {
|
||||
Self {
|
||||
bench_crate: BenchCrate::Tfhe(TfheLayer::Hlapi(HlapiBench::Dex(hlapi_dex))),
|
||||
backend,
|
||||
param_name,
|
||||
operand_type,
|
||||
type_name,
|
||||
bench_type: bench_type.into(),
|
||||
num_elements,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,8 +212,10 @@ impl fmt::Display for BenchmarkSpec<'_> {
|
||||
if !matches!(self.backend, Backend::Cpu) {
|
||||
write!(f, "::{}", self.backend)?;
|
||||
}
|
||||
if matches!(self.bench_type, BenchmarkType::Throughput) {
|
||||
write!(f, "::throughput")?;
|
||||
match self.bench_type {
|
||||
BenchmarkMetric::Throughput => write!(f, "::throughput")?,
|
||||
BenchmarkMetric::PbsCount => write!(f, "::pbs_count")?,
|
||||
BenchmarkMetric::Latency => {}
|
||||
}
|
||||
write!(f, "::{}", self.param_name)?;
|
||||
if self.operand_type.is_scalar() {
|
||||
@@ -117,6 +224,9 @@ impl fmt::Display for BenchmarkSpec<'_> {
|
||||
if let Some(type_name) = self.type_name {
|
||||
write!(f, "::{type_name}")?;
|
||||
}
|
||||
if let Some(num_elements) = self.num_elements {
|
||||
write!(f, "::{num_elements}_elements")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -133,7 +243,8 @@ mod tests {
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint64"),
|
||||
&BenchmarkType::Latency,
|
||||
BenchmarkMetric::Latency,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
@@ -149,7 +260,8 @@ mod tests {
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint128"),
|
||||
&BenchmarkType::Latency,
|
||||
BenchmarkMetric::Latency,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
@@ -165,7 +277,8 @@ mod tests {
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint64"),
|
||||
&BenchmarkType::Throughput,
|
||||
BenchmarkMetric::Throughput,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
@@ -181,7 +294,8 @@ mod tests {
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::PlainText,
|
||||
Some("FheUint64"),
|
||||
&BenchmarkType::Latency,
|
||||
BenchmarkMetric::Latency,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
@@ -197,11 +311,164 @@ mod tests {
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
&BenchmarkType::Latency,
|
||||
BenchmarkMetric::Latency,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::ops::neg::PARAM_MESSAGE_2_CARRY_2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_erc7984_with_num_elements() {
|
||||
use crate::tfhe::hlapi::erc7984::TransferFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
Erc7984::Transfer(TransferFlavor::Whitepaper),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
BenchmarkMetric::Latency,
|
||||
Backend::Cpu,
|
||||
Some(10),
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::erc7984::transfer::whitepaper::PARAM_MESSAGE_2_CARRY_2::10_elements"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_erc7984_without_num_elements() {
|
||||
use crate::tfhe::hlapi::erc7984::TransferFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
Erc7984::Transfer(TransferFlavor::NoCmux),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
BenchmarkMetric::Latency,
|
||||
Backend::Cpu,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::erc7984::transfer::no_cmux::PARAM_MESSAGE_2_CARRY_2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_erc7984_num_elements_with_backend() {
|
||||
use crate::tfhe::hlapi::erc7984::TransferFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
Erc7984::Transfer(TransferFlavor::Overflow),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
BenchmarkMetric::Latency,
|
||||
Backend::Cuda,
|
||||
Some(5),
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::erc7984::transfer::overflow::cuda::PARAM_MESSAGE_2_CARRY_2::5_elements"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_erc7984_num_elements_with_throughput() {
|
||||
use crate::tfhe::hlapi::erc7984::TransferFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
BenchmarkMetric::Throughput,
|
||||
Backend::Cpu,
|
||||
Some(20),
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::erc7984::transfer::safe::throughput::PARAM_MESSAGE_2_CARRY_2::20_elements"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_erc7984_with_pbs_count() {
|
||||
use crate::tfhe::hlapi::erc7984::TransferFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_erc7984(
|
||||
Erc7984::Transfer(TransferFlavor::Safe),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
None,
|
||||
BenchmarkMetric::PbsCount,
|
||||
Backend::Cpu,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::erc7984::transfer::safe::pbs_count::PARAM_MESSAGE_2_CARRY_2"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_dex_swap_request_latency() {
|
||||
use crate::tfhe::hlapi::dex::DexFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_dex(
|
||||
Dex::SwapRequest(DexFlavor::Whitepaper),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint64"),
|
||||
BenchmarkMetric::Latency,
|
||||
Backend::Cpu,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::dex::swap_request::whitepaper::PARAM_MESSAGE_2_CARRY_2::FheUint64"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_dex_swap_claim_throughput_with_elements() {
|
||||
use crate::tfhe::hlapi::dex::DexFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_dex(
|
||||
Dex::SwapClaim(DexFlavor::NoCmux),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint64"),
|
||||
BenchmarkMetric::Throughput,
|
||||
Backend::Cuda,
|
||||
Some(10),
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::dex::swap_claim::no_cmux::cuda::throughput::PARAM_MESSAGE_2_CARRY_2::FheUint64::10_elements"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hlapi_dex_with_pbs_count() {
|
||||
use crate::tfhe::hlapi::dex::DexFlavor;
|
||||
|
||||
let spec = BenchmarkSpec::new_hlapi_dex(
|
||||
Dex::SwapRequest(DexFlavor::Finalize),
|
||||
"PARAM_MESSAGE_2_CARRY_2",
|
||||
&OperandType::CipherText,
|
||||
Some("FheUint64"),
|
||||
BenchmarkMetric::PbsCount,
|
||||
Backend::Cpu,
|
||||
None,
|
||||
);
|
||||
assert_eq!(
|
||||
spec.to_string(),
|
||||
"tfhe::hlapi::dex::swap_request::finalize::pbs_count::PARAM_MESSAGE_2_CARRY_2::FheUint64"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
37
utils/benchmark_spec/src/tfhe/hlapi/dex.rs
Normal file
37
utils/benchmark_spec/src/tfhe/hlapi/dex.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use core::fmt;
|
||||
|
||||
use strum::Display;
|
||||
|
||||
use crate::traits::SpecFmt;
|
||||
|
||||
/// DEX (decentralized exchange) benchmark operations for the HLAPI layer.
|
||||
#[derive(Clone, Copy, Display)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Dex {
|
||||
SwapRequest(DexFlavor),
|
||||
SwapClaim(DexFlavor),
|
||||
}
|
||||
|
||||
impl Dex {
|
||||
fn op(&self) -> &dyn fmt::Display {
|
||||
match self {
|
||||
Dex::SwapRequest(op) => op,
|
||||
Dex::SwapClaim(op) => op,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecFmt for Dex {
|
||||
fn fmt_spec(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "::{}::{}", self, self.op())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Display)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum DexFlavor {
|
||||
Whitepaper,
|
||||
NoCmux,
|
||||
Prepare,
|
||||
Finalize,
|
||||
}
|
||||
37
utils/benchmark_spec/src/tfhe/hlapi/erc7984.rs
Normal file
37
utils/benchmark_spec/src/tfhe/hlapi/erc7984.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use core::fmt;
|
||||
|
||||
use strum::Display;
|
||||
|
||||
use crate::traits::SpecFmt;
|
||||
|
||||
/// ERC-7984 token transfer benchmark operations for the HLAPI layer.
|
||||
#[derive(Clone, Copy, Display)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum Erc7984 {
|
||||
Transfer(TransferFlavor),
|
||||
}
|
||||
|
||||
impl Erc7984 {
|
||||
fn op(&self) -> &dyn fmt::Display {
|
||||
match self {
|
||||
Erc7984::Transfer(op) => op,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecFmt for Erc7984 {
|
||||
fn fmt_spec(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "::{}::{}", self, self.op())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Display)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum TransferFlavor {
|
||||
Whitepaper,
|
||||
NoCmux,
|
||||
Overflow,
|
||||
Safe,
|
||||
HpuOptim,
|
||||
HpuSimd,
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
pub mod dex;
|
||||
pub mod erc7984;
|
||||
|
||||
use dex::Dex;
|
||||
use erc7984::Erc7984;
|
||||
use std::fmt;
|
||||
use strum::Display;
|
||||
|
||||
@@ -17,18 +22,23 @@ pub use super::hl_integer_op::HlIntegerOp;
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum HlapiBench {
|
||||
Ops(HlIntegerOp),
|
||||
Erc7984(Erc7984),
|
||||
Dex(Dex),
|
||||
}
|
||||
|
||||
impl HlapiBench {
|
||||
fn op(&self) -> &dyn fmt::Display {
|
||||
fn op(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
HlapiBench::Ops(op) => op,
|
||||
HlapiBench::Ops(op) => write!(f, "::{op}"),
|
||||
HlapiBench::Erc7984(op) => op.fmt_spec(f),
|
||||
HlapiBench::Dex(op) => op.fmt_spec(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecFmt for HlapiBench {
|
||||
fn fmt_spec(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "::{}::{}", self, self.op())
|
||||
write!(f, "::{}", self)?;
|
||||
self.op(f)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user