Skip to content

Commit b0fccae

Browse files
Fragment data structures restructure (#1)
* Move queues into data_structures folder * Move stacks into data_structures folder * Restructure queue benchmarks in benchmark_core directory * Adapt Cargo.toml files for all parts of the framework * Fix build errors for queues * Add entry for output directory in scripts/ * Change run_benchmark script to valid invocations * Change Handle to HandleQueue * Add priority queue data structure * Add is_empty() and min() functions to the PriorityQueue trait * Add benchmarks for priority queue and restructure argument parsing * Add update of software repositories for boost install in workflow * Add ignore tag for compute heavy tests * Add cfg tag test for test modules * Rename queues to fifo_queues * Change argument parsing to a flatter structure with one subcommand
1 parent c709ccf commit b0fccae

168 files changed

Lines changed: 2345 additions & 1340 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
steps:
1818
- uses: actions/checkout@v4
1919
- name: Install Boost
20-
run: sudo apt-get install -y libboost-all-dev
20+
run: sudo apt-get update && sudo apt-get install -y libboost-all-dev
2121
- name: Get submodules
2222
run: git submodule init && git submodule update
2323
- name: Build

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/target
22
/output
3+
/scripts/output
34
Cargo.lock
45
/venv
56
src/cpp-ring-queues-research/benchmarks.sh

.gitmodules

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
[submodule "queues/moodycamel_cpp/cpp_src/concurrentqueue"]
2-
path = queues/moodycamel_cpp/cpp_src/concurrentqueue
1+
[submodule "data_structures/fifo_queues/moodycamel_cpp/cpp_src/concurrentqueue"]
2+
path = data_structures/fifo_queues/moodycamel_cpp/cpp_src/concurrentqueue
33
url = https://github.com/cameron314/concurrentqueue.git

Cargo.toml

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,34 @@
22
resolver = "2"
33
members = [
44
"benchmark_core",
5-
"queues/array_queue",
6-
"queues/atomic_queue",
7-
"queues/basic_queue",
8-
"queues/bbq",
9-
"queues/boost_queue_cpp",
10-
"queues/bounded_concurrent_queue",
11-
"queues/unbounded_concurrent_queue",
12-
"queues/bounded_ringbuffer",
13-
"queues/faaa_queue",
14-
"queues/faaa_queue_cpp",
15-
"queues/lcrq_cpp",
16-
"queues/lcrq",
17-
"queues/lprq_cpp",
18-
"queues/lprq",
19-
"queues/lf_queue",
20-
"queues/lockfree_queue",
21-
"stacks/lockfree_stack",
22-
"queues/moodycamel_cpp",
23-
"queues/ms_queue",
24-
"queues/scc_queue",
25-
"stacks/scc_stack",
26-
"queues/scc2_queue",
27-
"stacks/scc2_stack",
28-
"queues/seg_queue",
29-
"queues/tz_queue_leak",
30-
"queues/tz_queue_hp",
31-
"queues/wf_queue",
5+
"data_structures/fifo_queues/array_queue",
6+
"data_structures/fifo_queues/atomic_queue",
7+
"data_structures/fifo_queues/basic_queue",
8+
"data_structures/fifo_queues/bbq",
9+
"data_structures/fifo_queues/boost_queue_cpp",
10+
"data_structures/fifo_queues/bounded_concurrent_queue",
11+
"data_structures/fifo_queues/unbounded_concurrent_queue",
12+
"data_structures/fifo_queues/bounded_ringbuffer",
13+
"data_structures/fifo_queues/faaa_queue",
14+
"data_structures/fifo_queues/faaa_queue_cpp",
15+
"data_structures/fifo_queues/lcrq_cpp",
16+
"data_structures/fifo_queues/lcrq",
17+
"data_structures/fifo_queues/lprq_cpp",
18+
"data_structures/fifo_queues/lprq",
19+
"data_structures/fifo_queues/lf_queue",
20+
"data_structures/fifo_queues/lockfree_queue",
21+
"data_structures/stacks/lockfree_stack",
22+
"data_structures/fifo_queues/moodycamel_cpp",
23+
"data_structures/fifo_queues/ms_queue",
24+
"data_structures/fifo_queues/scc_queue",
25+
"data_structures/stacks/scc_stack",
26+
"data_structures/fifo_queues/scc2_queue",
27+
"data_structures/stacks/scc2_stack",
28+
"data_structures/fifo_queues/seg_queue",
29+
"data_structures/fifo_queues/tz_queue_leak",
30+
"data_structures/fifo_queues/tz_queue_hp",
31+
"data_structures/fifo_queues/wf_queue",
32+
"data_structures/priority_queues/basic_priority_queue",
3233
]
3334

3435
[workspace.dependencies]

benchmark_core/src/arguments.rs

Lines changed: 161 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,255 @@
11
use clap::{ArgAction, Args as ClapArgs, Parser, Subcommand};
22
use std::fmt::Display;
33

4-
#[derive(Parser, Debug)]
5-
#[command(version, about, long_about = None)]
6-
pub struct Args {
4+
/// General arguments for all benchmarks
5+
#[derive(ClapArgs, Debug, Clone)]
6+
pub struct GeneralArgs {
77
/// Duration of each benchmark
88
#[arg(short, long, default_value_t = 10)]
99
pub time_limit: u64,
10-
/// Attemps to only use on socket. Specific for the developers test environment.
10+
11+
/// Attemps to only use one socket. Specific for the developers test environment.
1112
#[arg(short, long, default_value_t = true, action = ArgAction::SetFalse)]
1213
pub one_socket: bool,
14+
1315
/// How many times the chosen benchmark should be run.
1416
#[arg(short, long, default_value_t = 1)]
1517
pub iterations: u32,
16-
/// Count empty pop operations. Off by default.
17-
#[arg(short, long, default_value_t = false)]
18-
pub empty_pops: bool,
19-
/// Set the size of the bounded queues.
20-
#[arg(short, long, default_value_t = 10000)]
21-
pub queue_size: u32,
18+
2219
/// Set the amount of floating point numbers generated between each operation. Default is 10.
2320
#[arg(short, long, default_value_t = 10)]
2421
pub delay: u64,
22+
2523
/// Set the output path for the result files.
2624
#[arg(long = "path", default_value_t = String::from("./output"))]
2725
pub path_output: String,
28-
/// Choose which benchmark to run.
29-
#[command(subcommand)]
30-
pub benchmark: Benchmarks,
26+
3127
/// If set to true, benchmark will output to stdout instead of to files.
3228
#[arg(long = "write-stdout", default_value_t = false)]
3329
pub write_to_stdout: bool,
34-
/// Prefill the queue with values before running the benchmark.
35-
#[arg(short, long, default_value_t = 0)]
36-
pub prefill_amount: u64,
30+
3731
/// Write benchmark configuration and hardware info to a separate file.
3832
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
3933
pub print_info: bool,
34+
4035
#[cfg(feature = "memory_tracking")]
4136
/// The interval of which memory tracking will update [ms].
4237
#[arg(long, default_value_t = 50)]
4338
pub memory_tracking_interval: u64,
4439
}
4540

46-
/// Possible benchmark types.
41+
/// Arguments for the FIFO Queue benchmark types
42+
#[derive(Parser, Debug)]
43+
#[command(version, about, long_about = None)]
44+
pub struct FifoQueueArgs {
45+
/// Count empty pop operations. Off by default.
46+
#[arg(short, long, default_value_t = false)]
47+
pub empty_pops: bool,
48+
49+
/// Set the size of the bounded queues.
50+
#[arg(short, long, default_value_t = 10000)]
51+
pub queue_size: u32,
52+
53+
/// The runner to use for the benchmark
54+
#[command(subcommand)]
55+
pub benchmark_runner: FifoQueueBenchmarks,
56+
57+
/// Prefill the FIFO Queue with default values before running the benchmark.
58+
#[arg(short, long, default_value_t = 0)]
59+
pub prefill_amount: u64,
60+
61+
/// General arguments agnostic to the FIFO Queue
62+
#[command(flatten)]
63+
pub general_args: GeneralArgs,
64+
}
65+
66+
/// Benchmark runners for FIFO Queues.
4767
#[derive(Subcommand, Debug)]
48-
pub enum Benchmarks {
49-
/// ProdCon throughput test. Decide amount of producers and consumers using flags.
50-
ProdCon(ProdConArgs),
51-
/// A test where each thread performs both consume and produce based on a random floating point
52-
/// value. Spread is decided using the `--spread` flag.
53-
EnqDeq(EnqDeqArgs),
54-
EnqDeqPairs(EnqDeqPairsArgs),
55-
BFS(BFSArgs),
68+
pub enum FifoQueueBenchmarks {
69+
/// A benchmark for measuring throughput using producers and consumers that
70+
/// are each bound to a thread
71+
ProdCon(FifoQueueProdConArgs),
72+
73+
/// A benchmark measuring throughput where a thread will switch between
74+
/// producing and consuming
75+
EnqDeq(FifoQueueEnqDeqArgs),
76+
77+
/// A benchmark measuring throughput where a thread will enqueue an item
78+
/// and then immediately dequeue it
79+
EnqDeqPairs(FifoQueueEnqDeqPairsArgs),
80+
81+
/// Benchmarks how fast the FIFO Queue can complete a breadth-first search
82+
/// on a graph
83+
BFS(FifoQueueBFSArgs),
5684
}
5785

5886
#[derive(ClapArgs, Debug)]
59-
pub struct ProdConArgs {
60-
/// Amount of producers to be used for basic throughput test.
87+
pub struct FifoQueueProdConArgs {
88+
/// Amount of producers to be used
6189
#[arg(short, long, default_value_t = 20)]
6290
pub producers: usize,
63-
/// Amount of consumers to be used for basic throughput test.
91+
92+
/// Amount of consumers to be used
6493
#[arg(short, long, default_value_t = 20)]
6594
pub consumers: usize,
6695
}
96+
6797
#[derive(ClapArgs, Debug)]
68-
pub struct EnqDeqArgs {
98+
pub struct FifoQueueEnqDeqArgs {
6999
/// Set the thread count for the pingpong benchmark.
70100
#[arg(long = "thread-count", default_value_t = 20)]
71101
pub thread_count: usize,
102+
72103
/// Decide the spread of producers/consumers for the pingpong benchmark.
73104
/// Ex. 0.3 means 30% produce 70% consume.
74105
#[arg(long = "spread", default_value_t = 0.5)]
75106
pub spread: f64,
76107
}
108+
77109
#[derive(ClapArgs, Debug)]
78-
pub struct EnqDeqPairsArgs {
110+
pub struct FifoQueueEnqDeqPairsArgs {
79111
/// Set the thread count for the pingpong benchmark.
80112
#[arg(long = "thread-count", default_value_t = 20)]
81113
pub thread_count: usize,
82114
}
115+
83116
#[derive(ClapArgs, Debug)]
84-
pub struct BFSArgs {
117+
pub struct FifoQueueBFSArgs {
85118
#[arg(short, long, default_value_t = 20)]
86119
pub thread_count: usize,
120+
87121
#[arg(short, long)]
88122
pub graph_file: String,
123+
89124
#[arg(short, long, default_value_t = false)]
90125
pub no_verify: bool,
91126
}
127+
128+
/// Arguments for the Priority Queue benchmark types
129+
#[derive(Parser, Debug)]
130+
#[command(version, about, long_about = None)]
131+
pub struct PriorityQueueArgs {
132+
/// Set the size of the bounded queues.
133+
#[arg(short, long, default_value_t = 10000)]
134+
pub queue_size: u32,
135+
136+
/// The runner to use for the benchmark
137+
#[command(subcommand)]
138+
pub benchmark_runner: PriorityQueueBenchmarks,
139+
140+
/// Prefill the FIFO Queue with default values before running the benchmark.
141+
#[arg(short, long, default_value_t = 0)]
142+
pub prefill_amount: u64,
143+
144+
/// General arguments agnostic to the Priority Queue
145+
#[command(flatten)]
146+
pub general_args: GeneralArgs,
147+
}
148+
149+
/// Benchmark runners for priority queues.
150+
#[derive(Subcommand, Debug)]
151+
pub enum PriorityQueueBenchmarks {
152+
/// A benchmark for measuring throughput using producers and consumers that
153+
/// are each bound to a thread
154+
ProdCon(PQProdConArgs),
155+
}
156+
157+
#[derive(ClapArgs, Debug)]
158+
pub struct PQProdConArgs {
159+
/// Amount of producers to be used for basic throughput test.
160+
#[arg(short, long, default_value_t = 20)]
161+
pub producers: usize,
162+
163+
/// Amount of consumers to be used for basic throughput test.
164+
#[arg(short, long, default_value_t = 20)]
165+
pub consumers: usize,
166+
}
167+
92168
/// This is used to write the benchmark type to the output.
93169
/// That is why the arguments are discarded.
94-
impl Display for Benchmarks {
170+
impl Display for FifoQueueBenchmarks {
95171
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96172
match self {
97-
Benchmarks::ProdCon(_) => write!(f, "ProdCon"),
98-
Benchmarks::EnqDeq(_) => write!(f, "EnqDeq"),
99-
Benchmarks::EnqDeqPairs(_) => write!(f, "EnqDeqPairs"),
173+
FifoQueueBenchmarks::ProdCon(_) => write!(f, "ProdCon"),
174+
FifoQueueBenchmarks::EnqDeq(_) => write!(f, "EnqDeq"),
175+
FifoQueueBenchmarks::EnqDeqPairs(_) => write!(f, "EnqDeqPairs"),
100176
// #[cfg(feature = "bfs")]
101-
Benchmarks::BFS(_) => write!(f, "BFS"),
177+
FifoQueueBenchmarks::BFS(_) => write!(f, "BFS"),
102178
}
103179
}
104180
}
181+
182+
/// This is used to write the benchmark type to the output.
183+
/// That is why the arguments are discarded.
184+
impl Display for PriorityQueueBenchmarks {
185+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186+
match self {
187+
PriorityQueueBenchmarks::ProdCon(_) => write!(f, "ProdCon"),
188+
}
189+
}
190+
}
191+
105192
/// This is used in the print_info function.
106-
impl Display for Args {
193+
impl Display for GeneralArgs {
107194
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108195
writeln!(f, "Time limit: {}", self.time_limit)?;
109196
writeln!(f, "One socket?: {}", self.one_socket)?;
110197
writeln!(f, "Iterations: {}", self.iterations)?;
111-
writeln!(f, "Queue size: {}", self.queue_size)?;
112198
writeln!(f, "Delay: {}", self.delay)?;
113199
writeln!(f, "Output path: {}", self.path_output)?;
114-
writeln!(f, "Benchmark: {:?}", self.benchmark)?;
115200
writeln!(f, "Write to stdout: {}", self.write_to_stdout)?;
116-
writeln!(f, "prefill amount: {}", self.prefill_amount)?;
117201
Ok(())
118202
}
119203
}
120204

121205
/// Implemented so that tests are easier to write.
122-
impl Default for Args {
206+
impl Default for GeneralArgs {
123207
fn default() -> Self {
124-
Args {
125-
prefill_amount: 0,
208+
GeneralArgs {
126209
time_limit: 1,
127210
one_socket: true,
128211
iterations: 1,
129-
empty_pops: false,
130-
queue_size: 10000,
131212
delay: 10,
132213
path_output: "".to_string(),
133-
benchmark: Benchmarks::ProdCon(ProdConArgs {
134-
producers: 5,
135-
consumers: 5,
136-
}),
137214
write_to_stdout: true,
138215
print_info: false,
139216
#[cfg(feature = "memory_tracking")]
140217
memory_tracking_interval: 50,
141218
}
142219
}
143220
}
221+
222+
/// Implemented for easier testing
223+
impl Default for FifoQueueArgs {
224+
fn default() -> Self {
225+
FifoQueueArgs {
226+
empty_pops: false,
227+
queue_size: 10000,
228+
benchmark_runner: FifoQueueBenchmarks::ProdCon(
229+
FifoQueueProdConArgs {
230+
producers: 20,
231+
consumers: 20,
232+
},
233+
),
234+
prefill_amount: 1000,
235+
general_args: GeneralArgs::default(),
236+
}
237+
}
238+
}
239+
240+
/// Implemented for easier testing
241+
impl Default for PriorityQueueArgs {
242+
fn default() -> Self {
243+
PriorityQueueArgs {
244+
queue_size: 10000,
245+
benchmark_runner: PriorityQueueBenchmarks::ProdCon(
246+
PQProdConArgs {
247+
producers: 20,
248+
consumers: 20,
249+
},
250+
),
251+
prefill_amount: 1000,
252+
general_args: GeneralArgs::default(),
253+
}
254+
}
255+
}

0 commit comments

Comments
 (0)