Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Install Boost
run: sudo apt-get install -y libboost-all-dev
run: sudo apt-get update && sudo apt-get install -y libboost-all-dev
- name: Get submodules
run: git submodule init && git submodule update
- name: Build
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/target
/output
/scripts/output
Cargo.lock
/venv
src/cpp-ring-queues-research/benchmarks.sh
Expand Down
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "queues/moodycamel_cpp/cpp_src/concurrentqueue"]
path = queues/moodycamel_cpp/cpp_src/concurrentqueue
[submodule "data_structures/fifo_queues/moodycamel_cpp/cpp_src/concurrentqueue"]
path = data_structures/fifo_queues/moodycamel_cpp/cpp_src/concurrentqueue
url = https://github.com/cameron314/concurrentqueue.git
55 changes: 28 additions & 27 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@
resolver = "2"
members = [
"benchmark_core",
"queues/array_queue",
"queues/atomic_queue",
"queues/basic_queue",
"queues/bbq",
"queues/boost_queue_cpp",
"queues/bounded_concurrent_queue",
"queues/unbounded_concurrent_queue",
"queues/bounded_ringbuffer",
"queues/faaa_queue",
"queues/faaa_queue_cpp",
"queues/lcrq_cpp",
"queues/lcrq",
"queues/lprq_cpp",
"queues/lprq",
"queues/lf_queue",
"queues/lockfree_queue",
"stacks/lockfree_stack",
"queues/moodycamel_cpp",
"queues/ms_queue",
"queues/scc_queue",
"stacks/scc_stack",
"queues/scc2_queue",
"stacks/scc2_stack",
"queues/seg_queue",
"queues/tz_queue_leak",
"queues/tz_queue_hp",
"queues/wf_queue",
"data_structures/fifo_queues/array_queue",
"data_structures/fifo_queues/atomic_queue",
"data_structures/fifo_queues/basic_queue",
"data_structures/fifo_queues/bbq",
"data_structures/fifo_queues/boost_queue_cpp",
"data_structures/fifo_queues/bounded_concurrent_queue",
"data_structures/fifo_queues/unbounded_concurrent_queue",
"data_structures/fifo_queues/bounded_ringbuffer",
"data_structures/fifo_queues/faaa_queue",
"data_structures/fifo_queues/faaa_queue_cpp",
"data_structures/fifo_queues/lcrq_cpp",
"data_structures/fifo_queues/lcrq",
"data_structures/fifo_queues/lprq_cpp",
"data_structures/fifo_queues/lprq",
"data_structures/fifo_queues/lf_queue",
"data_structures/fifo_queues/lockfree_queue",
"data_structures/stacks/lockfree_stack",
"data_structures/fifo_queues/moodycamel_cpp",
"data_structures/fifo_queues/ms_queue",
"data_structures/fifo_queues/scc_queue",
"data_structures/stacks/scc_stack",
"data_structures/fifo_queues/scc2_queue",
"data_structures/stacks/scc2_stack",
"data_structures/fifo_queues/seg_queue",
"data_structures/fifo_queues/tz_queue_leak",
"data_structures/fifo_queues/tz_queue_hp",
"data_structures/fifo_queues/wf_queue",
"data_structures/priority_queues/basic_priority_queue",
]

[workspace.dependencies]
Expand Down
210 changes: 161 additions & 49 deletions benchmark_core/src/arguments.rs
Original file line number Diff line number Diff line change
@@ -1,143 +1,255 @@
use clap::{ArgAction, Args as ClapArgs, Parser, Subcommand};
use std::fmt::Display;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct Args {
/// General arguments for all benchmarks
#[derive(ClapArgs, Debug, Clone)]
pub struct GeneralArgs {
/// Duration of each benchmark
#[arg(short, long, default_value_t = 10)]
pub time_limit: u64,
/// Attemps to only use on socket. Specific for the developers test environment.

/// Attemps to only use one socket. Specific for the developers test environment.
#[arg(short, long, default_value_t = true, action = ArgAction::SetFalse)]
pub one_socket: bool,

/// How many times the chosen benchmark should be run.
#[arg(short, long, default_value_t = 1)]
pub iterations: u32,
/// Count empty pop operations. Off by default.
#[arg(short, long, default_value_t = false)]
pub empty_pops: bool,
/// Set the size of the bounded queues.
#[arg(short, long, default_value_t = 10000)]
pub queue_size: u32,

/// Set the amount of floating point numbers generated between each operation. Default is 10.
#[arg(short, long, default_value_t = 10)]
pub delay: u64,

/// Set the output path for the result files.
#[arg(long = "path", default_value_t = String::from("./output"))]
pub path_output: String,
/// Choose which benchmark to run.
#[command(subcommand)]
pub benchmark: Benchmarks,

/// If set to true, benchmark will output to stdout instead of to files.
#[arg(long = "write-stdout", default_value_t = false)]
pub write_to_stdout: bool,
/// Prefill the queue with values before running the benchmark.
#[arg(short, long, default_value_t = 0)]
pub prefill_amount: u64,

/// Write benchmark configuration and hardware info to a separate file.
#[arg(long, default_value_t = false, action = ArgAction::SetTrue)]
pub print_info: bool,

#[cfg(feature = "memory_tracking")]
/// The interval of which memory tracking will update [ms].
#[arg(long, default_value_t = 50)]
pub memory_tracking_interval: u64,
}

/// Possible benchmark types.
/// Arguments for the FIFO Queue benchmark types
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct FifoQueueArgs {
/// Count empty pop operations. Off by default.
#[arg(short, long, default_value_t = false)]
pub empty_pops: bool,

/// Set the size of the bounded queues.
#[arg(short, long, default_value_t = 10000)]
pub queue_size: u32,

/// The runner to use for the benchmark
#[command(subcommand)]
pub benchmark_runner: FifoQueueBenchmarks,

/// Prefill the FIFO Queue with default values before running the benchmark.
#[arg(short, long, default_value_t = 0)]
pub prefill_amount: u64,

/// General arguments agnostic to the FIFO Queue
#[command(flatten)]
pub general_args: GeneralArgs,
}

/// Benchmark runners for FIFO Queues.
#[derive(Subcommand, Debug)]
pub enum Benchmarks {
/// ProdCon throughput test. Decide amount of producers and consumers using flags.
ProdCon(ProdConArgs),
/// A test where each thread performs both consume and produce based on a random floating point
/// value. Spread is decided using the `--spread` flag.
EnqDeq(EnqDeqArgs),
EnqDeqPairs(EnqDeqPairsArgs),
BFS(BFSArgs),
pub enum FifoQueueBenchmarks {
/// A benchmark for measuring throughput using producers and consumers that
/// are each bound to a thread
ProdCon(FifoQueueProdConArgs),

/// A benchmark measuring throughput where a thread will switch between
/// producing and consuming
EnqDeq(FifoQueueEnqDeqArgs),

/// A benchmark measuring throughput where a thread will enqueue an item
/// and then immediately dequeue it
EnqDeqPairs(FifoQueueEnqDeqPairsArgs),

/// Benchmarks how fast the FIFO Queue can complete a breadth-first search
/// on a graph
BFS(FifoQueueBFSArgs),
}

#[derive(ClapArgs, Debug)]
pub struct ProdConArgs {
/// Amount of producers to be used for basic throughput test.
pub struct FifoQueueProdConArgs {
/// Amount of producers to be used
#[arg(short, long, default_value_t = 20)]
pub producers: usize,
/// Amount of consumers to be used for basic throughput test.

/// Amount of consumers to be used
#[arg(short, long, default_value_t = 20)]
pub consumers: usize,
}

#[derive(ClapArgs, Debug)]
pub struct EnqDeqArgs {
pub struct FifoQueueEnqDeqArgs {
/// Set the thread count for the pingpong benchmark.
#[arg(long = "thread-count", default_value_t = 20)]
pub thread_count: usize,

/// Decide the spread of producers/consumers for the pingpong benchmark.
/// Ex. 0.3 means 30% produce 70% consume.
#[arg(long = "spread", default_value_t = 0.5)]
pub spread: f64,
}

#[derive(ClapArgs, Debug)]
pub struct EnqDeqPairsArgs {
pub struct FifoQueueEnqDeqPairsArgs {
/// Set the thread count for the pingpong benchmark.
#[arg(long = "thread-count", default_value_t = 20)]
pub thread_count: usize,
}

#[derive(ClapArgs, Debug)]
pub struct BFSArgs {
pub struct FifoQueueBFSArgs {
#[arg(short, long, default_value_t = 20)]
pub thread_count: usize,

#[arg(short, long)]
pub graph_file: String,

#[arg(short, long, default_value_t = false)]
pub no_verify: bool,
}

/// Arguments for the Priority Queue benchmark types
#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct PriorityQueueArgs {
/// Set the size of the bounded queues.
#[arg(short, long, default_value_t = 10000)]
pub queue_size: u32,

/// The runner to use for the benchmark
#[command(subcommand)]
pub benchmark_runner: PriorityQueueBenchmarks,

/// Prefill the FIFO Queue with default values before running the benchmark.
#[arg(short, long, default_value_t = 0)]
pub prefill_amount: u64,

/// General arguments agnostic to the Priority Queue
#[command(flatten)]
pub general_args: GeneralArgs,
}

/// Benchmark runners for priority queues.
#[derive(Subcommand, Debug)]
pub enum PriorityQueueBenchmarks {
/// A benchmark for measuring throughput using producers and consumers that
/// are each bound to a thread
ProdCon(PQProdConArgs),
}

#[derive(ClapArgs, Debug)]
pub struct PQProdConArgs {
/// Amount of producers to be used for basic throughput test.
#[arg(short, long, default_value_t = 20)]
pub producers: usize,

/// Amount of consumers to be used for basic throughput test.
#[arg(short, long, default_value_t = 20)]
pub consumers: usize,
}

/// This is used to write the benchmark type to the output.
/// That is why the arguments are discarded.
impl Display for Benchmarks {
impl Display for FifoQueueBenchmarks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Benchmarks::ProdCon(_) => write!(f, "ProdCon"),
Benchmarks::EnqDeq(_) => write!(f, "EnqDeq"),
Benchmarks::EnqDeqPairs(_) => write!(f, "EnqDeqPairs"),
FifoQueueBenchmarks::ProdCon(_) => write!(f, "ProdCon"),
FifoQueueBenchmarks::EnqDeq(_) => write!(f, "EnqDeq"),
FifoQueueBenchmarks::EnqDeqPairs(_) => write!(f, "EnqDeqPairs"),
// #[cfg(feature = "bfs")]
Benchmarks::BFS(_) => write!(f, "BFS"),
FifoQueueBenchmarks::BFS(_) => write!(f, "BFS"),
}
}
}

/// This is used to write the benchmark type to the output.
/// That is why the arguments are discarded.
impl Display for PriorityQueueBenchmarks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PriorityQueueBenchmarks::ProdCon(_) => write!(f, "ProdCon"),
}
}
}

/// This is used in the print_info function.
impl Display for Args {
impl Display for GeneralArgs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Time limit: {}", self.time_limit)?;
writeln!(f, "One socket?: {}", self.one_socket)?;
writeln!(f, "Iterations: {}", self.iterations)?;
writeln!(f, "Queue size: {}", self.queue_size)?;
writeln!(f, "Delay: {}", self.delay)?;
writeln!(f, "Output path: {}", self.path_output)?;
writeln!(f, "Benchmark: {:?}", self.benchmark)?;
writeln!(f, "Write to stdout: {}", self.write_to_stdout)?;
writeln!(f, "prefill amount: {}", self.prefill_amount)?;
Ok(())
}
}

/// Implemented so that tests are easier to write.
impl Default for Args {
impl Default for GeneralArgs {
fn default() -> Self {
Args {
prefill_amount: 0,
GeneralArgs {
time_limit: 1,
one_socket: true,
iterations: 1,
empty_pops: false,
queue_size: 10000,
delay: 10,
path_output: "".to_string(),
benchmark: Benchmarks::ProdCon(ProdConArgs {
producers: 5,
consumers: 5,
}),
write_to_stdout: true,
print_info: false,
#[cfg(feature = "memory_tracking")]
memory_tracking_interval: 50,
}
}
}

/// Implemented for easier testing
impl Default for FifoQueueArgs {
fn default() -> Self {
FifoQueueArgs {
empty_pops: false,
queue_size: 10000,
benchmark_runner: FifoQueueBenchmarks::ProdCon(
FifoQueueProdConArgs {
producers: 20,
consumers: 20,
},
),
prefill_amount: 1000,
general_args: GeneralArgs::default(),
}
}
}

/// Implemented for easier testing
impl Default for PriorityQueueArgs {
fn default() -> Self {
PriorityQueueArgs {
queue_size: 10000,
benchmark_runner: PriorityQueueBenchmarks::ProdCon(
PQProdConArgs {
producers: 20,
consumers: 20,
},
),
prefill_amount: 1000,
general_args: GeneralArgs::default(),
}
}
}
Loading