Skip to content

Commit

Permalink
Merge pull request #2202 from subspace/proving-benchmark
Browse files Browse the repository at this point in the history
Proving benchmark in subspace-farmer
  • Loading branch information
nazar-pc authored Nov 7, 2023
2 parents ee44e02 + c26f104 commit 1358519
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 38 deletions.
51 changes: 29 additions & 22 deletions crates/subspace-core-primitives/benches/kzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,41 +16,48 @@ fn criterion_benchmark(c: &mut Criterion) {
})
});

c.bench_function("commit", |b| {
{
let polynomial = kzg.poly(&values).unwrap();
b.iter(|| {
kzg.commit(black_box(&polynomial)).unwrap();
})
});

c.bench_function("commit", |b| {
b.iter(|| {
kzg.commit(black_box(&polynomial)).unwrap();
})
});
}

let num_values = values.len();

c.bench_function("create-witness", |b| {
{
let polynomial = kzg.poly(&values).unwrap();

b.iter(|| {
kzg.create_witness(black_box(&polynomial), black_box(num_values), black_box(0))
.unwrap();
})
});
c.bench_function("create-witness", |b| {
b.iter(|| {
kzg.create_witness(black_box(&polynomial), black_box(num_values), black_box(0))
.unwrap();
})
});
}

c.bench_function("verify", |b| {
{
let polynomial = kzg.poly(&values).unwrap();
let commitment = kzg.commit(&polynomial).unwrap();
let index = 0;
let witness = kzg.create_witness(&polynomial, num_values, index).unwrap();
let value = values.first().unwrap();

b.iter(|| {
kzg.verify(
black_box(&commitment),
black_box(num_values),
black_box(index),
black_box(value),
black_box(&witness),
);
})
});
c.bench_function("verify", |b| {
b.iter(|| {
kzg.verify(
black_box(&commitment),
black_box(num_values),
black_box(index),
black_box(value),
black_box(&witness),
);
})
});
}
}

criterion_group!(benches, criterion_benchmark);
Expand Down
182 changes: 175 additions & 7 deletions crates/subspace-farmer/src/bin/subspace-farmer/commands/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,55 @@ use subspace_rpc_primitives::SlotInfo;
/// Arguments for benchmark
#[derive(Debug, Subcommand)]
pub(crate) enum BenchmarkArgs {
/// Audit benchmark
/// Auditing benchmark
Audit {
/// Number of samples to collect for benchmarking purposes
#[arg(long, default_value_t = 10)]
sample_size: usize,
/// Disk farm to audit
///
/// Example:
/// /path/to/directory
disk_farm: PathBuf,
/// Optional filter for benchmarks, must correspond to a part of benchmark name in order for benchmark to run
filter: Option<String>,
},
/// Proving benchmark
Prove {
/// Number of samples to collect for benchmarking purposes
#[arg(long, default_value_t = 10)]
sample_size: usize,
/// Disk farm to prove
///
/// Example:
/// /path/to/directory
disk_farm: PathBuf,
/// Optional filter for benchmarks, must correspond to a part of benchmark name in order for benchmark to run
filter: Option<String>,
/// Limit number of sectors audited to specified number, this limits amount of memory used by benchmark (normal
/// farming process doesn't use this much RAM)
#[arg(long)]
limit_sector_count: Option<usize>,
},
}

pub(crate) fn benchmark(benchmark_args: BenchmarkArgs) -> anyhow::Result<()> {
match benchmark_args {
BenchmarkArgs::Audit {
sample_size,
disk_farm,
filter,
} => audit(sample_size, disk_farm, filter),
BenchmarkArgs::Prove {
sample_size,
} => audit(disk_farm, sample_size),
disk_farm,
filter,
limit_sector_count,
} => prove(sample_size, disk_farm, filter, limit_sector_count),
}
}

fn audit(disk_farm: PathBuf, sample_size: usize) -> anyhow::Result<()> {
fn audit(sample_size: usize, disk_farm: PathBuf, filter: Option<String>) -> anyhow::Result<()> {
let (single_disk_farm_info, disk_farm) = match SingleDiskFarm::collect_summary(disk_farm) {
SingleDiskFarmSummary::Found { info, directory } => (info, directory),
SingleDiskFarmSummary::NotFound { directory } => {
Expand Down Expand Up @@ -72,6 +99,9 @@ fn audit(disk_farm: PathBuf, sample_size: usize) -> anyhow::Result<()> {
.map_err(|error| anyhow::anyhow!("Failed to read sectors metadata: {error}"))?;

let mut criterion = Criterion::default().sample_size(sample_size);
if let Some(filter) = filter {
criterion = criterion.with_filter(filter);
}
{
let mut group = criterion.benchmark_group("audit");
group.throughput(Throughput::Bytes(
Expand All @@ -82,10 +112,9 @@ fn audit(disk_farm: PathBuf, sample_size: usize) -> anyhow::Result<()> {
.read(true)
.open(disk_farm.join(SingleDiskFarm::PLOT_FILE))
.map_err(|error| anyhow::anyhow!("Failed to open plot: {error}"))?;
let plot_audit = PlotAudit::new(&plot);

group.bench_function("plot/single", |b| {
let plot_audit = PlotAudit::new(&plot);

b.iter_batched(
rand::random,
|global_challenge| {
Expand Down Expand Up @@ -116,10 +145,9 @@ fn audit(disk_farm: PathBuf, sample_size: usize) -> anyhow::Result<()> {
{
let plot = RayonFiles::open(&disk_farm.join(SingleDiskFarm::PLOT_FILE))
.map_err(|error| anyhow::anyhow!("Failed to open plot: {error}"))?;
let plot_audit = PlotAudit::new(&plot);

group.bench_function("plot/rayon", |b| {
let plot_audit = PlotAudit::new(&plot);

b.iter_batched(
rand::random,
|global_challenge| {
Expand Down Expand Up @@ -153,3 +181,143 @@ fn audit(disk_farm: PathBuf, sample_size: usize) -> anyhow::Result<()> {

Ok(())
}

fn prove(
sample_size: usize,
disk_farm: PathBuf,
filter: Option<String>,
limit_sector_count: Option<usize>,
) -> anyhow::Result<()> {
let (single_disk_farm_info, disk_farm) = match SingleDiskFarm::collect_summary(disk_farm) {
SingleDiskFarmSummary::Found { info, directory } => (info, directory),
SingleDiskFarmSummary::NotFound { directory } => {
return Err(anyhow!(
"No single disk farm info found, make sure {} is a valid path to the farm and \
process have permissions to access it",
directory.display()
));
}
SingleDiskFarmSummary::Error { directory, error } => {
return Err(anyhow!(
"Failed to open single disk farm info, make sure {} is a valid path to the farm \
and process have permissions to access it: {error}",
directory.display()
));
}
};

let kzg = Kzg::new(embedded_kzg_settings());
let erasure_coding = ErasureCoding::new(
NonZeroUsize::new(Record::NUM_S_BUCKETS.next_power_of_two().ilog2() as usize)
.expect("Not zero; qed"),
)
.map_err(|error| anyhow::anyhow!(error))?;
let table_generator = Mutex::new(PosTable::generator());

let mut sectors_metadata = SingleDiskFarm::read_all_sectors_metadata(&disk_farm)
.map_err(|error| anyhow::anyhow!("Failed to read sectors metadata: {error}"))?;
if let Some(limit_sector_count) = limit_sector_count {
sectors_metadata.truncate(limit_sector_count);
};

let mut criterion = Criterion::default().sample_size(sample_size);
if let Some(filter) = filter {
criterion = criterion.with_filter(filter);
}
{
let mut group = criterion.benchmark_group("prove");
{
let plot = OpenOptions::new()
.read(true)
.open(disk_farm.join(SingleDiskFarm::PLOT_FILE))
.map_err(|error| anyhow::anyhow!("Failed to open plot: {error}"))?;
let plot_audit = PlotAudit::new(&plot);
let options = PlotAuditOptions::<PosTable> {
public_key: single_disk_farm_info.public_key(),
reward_address: single_disk_farm_info.public_key(),
slot_info: SlotInfo {
slot_number: 0,
global_challenge: rand::random(),
// Solution is guaranteed to be found
solution_range: SolutionRange::MAX,
// Solution is guaranteed to be found
voting_solution_range: SolutionRange::MAX,
},
sectors_metadata: &sectors_metadata,
kzg: &kzg,
erasure_coding: &erasure_coding,
maybe_sector_being_modified: None,
table_generator: &table_generator,
};

let mut audit_results = plot_audit.audit(options);

group.bench_function("plot/single", |b| {
b.iter_batched(
|| {
if let Some(result) = audit_results.pop() {
return result;
}

audit_results = plot_audit.audit(options);

audit_results.pop().unwrap()
},
|(_sector_index, mut provable_solutions)| {
while (provable_solutions.next()).is_none() {
// Try to create one solution and exit
}
},
BatchSize::SmallInput,
)
});
}
{
let plot = RayonFiles::open(&disk_farm.join(SingleDiskFarm::PLOT_FILE))
.map_err(|error| anyhow::anyhow!("Failed to open plot: {error}"))?;
let plot_audit = PlotAudit::new(&plot);
let options = PlotAuditOptions::<PosTable> {
public_key: single_disk_farm_info.public_key(),
reward_address: single_disk_farm_info.public_key(),
slot_info: SlotInfo {
slot_number: 0,
global_challenge: rand::random(),
// Solution is guaranteed to be found
solution_range: SolutionRange::MAX,
// Solution is guaranteed to be found
voting_solution_range: SolutionRange::MAX,
},
sectors_metadata: &sectors_metadata,
kzg: &kzg,
erasure_coding: &erasure_coding,
maybe_sector_being_modified: None,
table_generator: &table_generator,
};
let mut audit_results = plot_audit.audit(options);

group.bench_function("plot/rayon", |b| {
b.iter_batched(
|| {
if let Some(result) = audit_results.pop() {
return result;
}

audit_results = plot_audit.audit(options);

audit_results.pop().unwrap()
},
|(_sector_index, mut provable_solutions)| {
while (provable_solutions.next()).is_none() {
// Try to create one solution and exit
}
},
BatchSize::SmallInput,
)
});
}
}

criterion.final_summary();

Ok(())
}
12 changes: 12 additions & 0 deletions crates/subspace-farmer/src/single_disk_farm/farming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ where
}

/// Plot audit options
#[derive(Debug)]
pub struct PlotAuditOptions<'a, PosTable>
where
PosTable: Table,
Expand All @@ -102,6 +103,17 @@ where
pub table_generator: &'a Mutex<PosTable::Generator>,
}

impl<'a, PosTable> Clone for PlotAuditOptions<'a, PosTable>
where
PosTable: Table,
{
fn clone(&self) -> Self {
*self
}
}

impl<'a, PosTable> Copy for PlotAuditOptions<'a, PosTable> where PosTable: Table {}

/// Plot auditing implementation
pub struct PlotAudit<Plot>(Plot)
where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,7 @@ pub struct RayonFiles {

impl ReadAtSync for RayonFiles {
fn read_at(&self, buf: &mut [u8], offset: usize) -> io::Result<()> {
let thread_index = rayon::current_thread_index().ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
"Reads must be called from rayon worker thread",
)
})?;
let thread_index = rayon::current_thread_index().unwrap_or_default();
let file = self.files.get(thread_index).ok_or_else(|| {
io::Error::new(io::ErrorKind::Other, "No files entry for this rayon thread")
})?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ fn criterion_benchmark(c: &mut Criterion) {

let cpu_cores = core_affinity::get_core_ids().expect("Must be able to get CPU cores");
for cpu_core in cpu_cores {
if !core_affinity::set_for_current(cpu_core) {
panic!("Failed to set CPU affinity");
}

c.bench_function(&format!("prove/cpu-{}", cpu_core.id), move |b| {
if !core_affinity::set_for_current(cpu_core) {
panic!("Failed to set CPU affinity");
}
b.iter(|| {
black_box(prove(black_box(seed), black_box(pot_iterations))).unwrap();
})
Expand Down

0 comments on commit 1358519

Please sign in to comment.