Skip to content

Commit 806d2d8

Browse files
committed
Add selective benchmarking and stores the benchmark in a CSV file
1 parent 86cb0d1 commit 806d2d8

File tree

8 files changed

+99
-10
lines changed

8 files changed

+99
-10
lines changed

test_suite/Cargo.lock

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test_suite/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
[dependencies]
77
anyhow = "1.0.89"
88
clap = { version = "4.5.17", features = ["derive"] }
9+
csv = "1.3.0"
910
env_logger = "0.11.5"
1011
itertools = "0.13.0"
1112
log = "0.4.22"

test_suite/bench_result.csv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
acir_opcodes,circuit_size,regex,with_gen_substr
2+
114,17865,email was meant for @[a-z]+,true
3+
59,7808,1=(a|b) (2=(b|c)+ )+d,true

test_suite/regex_db.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2+
"bench_all": false,
23
"database": [
34
{
45
"regex": {
56
"raw": "m(a|b)+-(c|d)+e"
67
},
7-
"with_bench": true,
88
"input_size": 16,
99
"samples_pass": [
1010
"mabab-cdcde",

test_suite/src/bench.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::{fmt::Display, process::Command};
1+
use std::{fmt::Display, path::Path, process::Command};
22

33
use anyhow::Context;
4-
use serde::Deserialize;
4+
use serde::{Deserialize, Serialize};
55
use serde_json::Value;
66

77
use crate::constants;
@@ -16,14 +16,21 @@ pub enum Error {
1616
/// Results of the benchmark.
1717
///
1818
/// This results are extracted using the command `bb gates -b <target>`
19-
#[derive(Deserialize)]
19+
#[derive(Deserialize, Serialize)]
2020
pub struct BenchResult {
2121
/// Number of ACIR opcodes generated by the compiler.
2222
pub acir_opcodes: u32,
2323
/// The number of gates.
2424
pub circuit_size: u32,
2525
/// Number of gates per opcode.
26+
#[serde(skip_serializing)]
2627
pub gates_per_opcode: Vec<u32>,
28+
/// Regex
29+
#[serde(skip_deserializing)]
30+
pub regex: String,
31+
/// Tells if this benchmark was performed using the gen_substr() function.
32+
#[serde(skip_deserializing)]
33+
pub with_gen_substr: bool,
2734
}
2835

2936
impl Display for BenchResult {
@@ -36,6 +43,31 @@ impl Display for BenchResult {
3643
}
3744
}
3845

46+
/// Container for the benchmark results for each test.
47+
#[derive(Serialize, Default)]
48+
pub struct BenchReport(Vec<BenchResult>);
49+
50+
impl BenchReport {
51+
/// Adds a result to the report.
52+
pub fn push_result(&mut self, result: BenchResult) {
53+
self.0.push(result);
54+
}
55+
56+
/// Save the report to a CSV file given by the path.
57+
pub fn save(self, path: &Path) -> anyhow::Result<()> {
58+
let mut writer = csv::Writer::from_path(path)?;
59+
for result in self.0 {
60+
writer.serialize(result)?;
61+
}
62+
Ok(())
63+
}
64+
65+
/// Returns if the report has any benchmark result or not.
66+
pub fn is_empty(&self) -> bool {
67+
self.0.is_empty()
68+
}
69+
}
70+
3971
/// Executes the command to count the gate. This command must be executed after
4072
/// the code is successfully compiled. To count the number of gates, we use the
4173
/// command `bb gates -b <target>`.

test_suite/src/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ pub const DEFAULT_DECOMPOSED_JSON_FILE: &str = "./decomposed.json";
1414
pub const DEFAULT_SUBSTRS_JSON_PATH: &str = "./substrs_transitions.json";
1515
/// Default path of the target folder for the project
1616
pub const DEFAULT_TARJET_JSON_FILE: &str = "./execution_project/target/execution_project.json";
17+
/// Default path for bench report
18+
pub const DEFAULT_BENCH_RESULT_FILE: &str = "./bench_result.csv";

test_suite/src/db.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ use serde::{Deserialize, Serialize};
55
use serde_json::Value;
66

77
/// Database of regular expressions that will be tested.
8-
pub struct RegexDb(Vec<DbEntry>);
8+
#[derive(Deserialize)]
9+
pub struct RegexDb {
10+
// Regex entries in the database
11+
db_entries: Vec<DbEntry>,
12+
// Defines wether we need to benchmark all the entries in the database.
13+
#[serde(default)]
14+
pub bench_all: bool,
15+
}
916

1017
/// Represents each fragment in a decomposed regex.
1118
#[derive(Deserialize, Serialize, Clone)]
@@ -119,13 +126,23 @@ impl RegexDb {
119126
let regex_db: Vec<DbEntry> = serde_json::from_str(&json_value["database"].to_string())
120127
.context("error parsing the database array")?;
121128

129+
// If the field in the "bench_all" is a boolean, take the boolean,
130+
// otherwhise, use false as a default.
131+
let bench_all: bool = match json_value["bench_all"].as_bool() {
132+
Some(flag) => flag,
133+
None => false,
134+
};
135+
122136
let mut regexes = Vec::new();
123137

124138
for db_element in regex_db {
125139
regexes.push(db_element);
126140
}
127141

128-
Ok(Self(regexes))
142+
Ok(Self {
143+
db_entries: regexes,
144+
bench_all,
145+
})
129146
}
130147
}
131148

@@ -134,7 +151,7 @@ impl IntoIterator for RegexDb {
134151
type IntoIter = std::vec::IntoIter<Self::Item>;
135152

136153
fn into_iter(self) -> Self::IntoIter {
137-
self.0.into_iter()
154+
self.db_entries.into_iter()
138155
}
139156
}
140157

test_suite/src/main.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod constants;
55
mod db;
66
mod tester;
77

8-
use bench::execute_count_gate_command;
8+
use bench::{execute_count_gate_command, BenchReport};
99
use code::Code;
1010
use db::RegexDb;
1111
use log::{self, error, info};
@@ -24,6 +24,8 @@ fn main() -> Result<(), Box<dyn Error>> {
2424
err
2525
})?;
2626

27+
let benchmark_all = database.bench_all;
28+
let mut bench_report = BenchReport::default();
2729
for regex_input in database {
2830
info!("testing regex {}", regex_input.regex.complete_regex());
2931
let mut code_read_result = Code::new(&regex_input);
@@ -64,10 +66,14 @@ fn main() -> Result<(), Box<dyn Error>> {
6466
None => error!("error downcasting the anyhow::Error"),
6567
},
6668
}
67-
if regex_input.with_bench {
69+
if regex_input.with_bench || benchmark_all {
6870
match execute_count_gate_command() {
69-
Ok(bench_result) => {
71+
Ok(mut bench_result) => {
7072
info!("benchmark results:\n{}", bench_result);
73+
// Changes the data needed to write the report.
74+
bench_result.regex = regex_input.regex.complete_regex();
75+
bench_result.with_gen_substr = regex_input.gen_substrs;
76+
bench_report.push_result(bench_result);
7177
}
7278
Err(err) => {
7379
error!(
@@ -88,5 +94,11 @@ fn main() -> Result<(), Box<dyn Error>> {
8894
}
8995
}
9096

97+
// Save the bench results.
98+
if !bench_report.is_empty() {
99+
info!("saving benchmark results into CSV");
100+
bench_report.save(Path::new(constants::DEFAULT_BENCH_RESULT_FILE))?;
101+
}
102+
91103
Ok(())
92104
}

0 commit comments

Comments
 (0)