perf/throughput: Replace think time with CPU-bound compute time

Replace the sleep-based --think parameter with a --compute parameter
that uses a busy loop to simulate realistic CPU or GPU bound business
logic (e.g., parsing, data aggregation, or ML inference). The compute
time is now specified in microseconds instead of milliseconds for
finer granularity.
This commit is contained in:
Pekka Enberg
2025-10-01 08:48:02 +03:00
parent 6fd2ad2f5e
commit eeb14b25c6
2 changed files with 46 additions and 18 deletions

View File

@@ -18,11 +18,11 @@ struct Args {
iterations: usize,
#[arg(
long = "think",
long = "compute",
default_value = "0",
help = "Per transaction think time (ms)"
help = "Per transaction compute time (us)"
)]
think: u64,
compute: u64,
}
fn main() -> Result<()> {
@@ -61,7 +61,7 @@ fn main() -> Result<()> {
args.batch_size,
args.iterations,
barrier,
args.think,
args.compute,
)
});
@@ -126,7 +126,7 @@ fn worker_thread(
batch_size: usize,
iterations: usize,
start_barrier: Arc<Barrier>,
think_ms: u64,
compute_usec: u64,
) -> Result<u64> {
let conn = Connection::open(&db_path)?;
@@ -142,14 +142,16 @@ fn worker_thread(
conn.execute("BEGIN", [])?;
let result = perform_compute(thread_id, compute_usec);
std::hint::black_box(result);
for i in 0..batch_size {
let id = thread_id * iterations * batch_size + iteration * batch_size + i;
stmt.execute([&id.to_string(), &format!("data_{id}")])?;
total_inserts += 1;
}
if think_ms > 0 {
thread::sleep(std::time::Duration::from_millis(think_ms));
}
conn.execute("COMMIT", [])?;
}
@@ -166,3 +168,17 @@ fn worker_thread(
Ok(total_inserts)
}
// Busy loop to simulate CPU or GPU bound computation (for example, parsing,
// data aggregation or ML inference).
fn perform_compute(thread_id: usize, usec: u64) -> u64 {
if usec == 0 {
return 0;
}
let start = Instant::now();
let mut sum: u64 = 0;
while start.elapsed().as_micros() < usec as u128 {
sum = sum.wrapping_add(thread_id as u64);
}
sum
}

View File

@@ -35,11 +35,11 @@ struct Args {
mode: TransactionMode,
#[arg(
long = "think",
long = "compute",
default_value = "0",
help = "Per transaction think time (ms)"
help = "Per transaction compute time (us)"
)]
think: u64,
compute: u64,
#[arg(
long = "timeout",
@@ -95,7 +95,7 @@ async fn main() -> Result<()> {
args.iterations,
barrier,
args.mode,
args.think,
args.compute,
timeout,
));
@@ -171,7 +171,6 @@ async fn setup_database(
)
.await?;
println!("Database created at: {db_path}");
Ok(db)
}
@@ -183,7 +182,7 @@ async fn worker_thread(
iterations: usize,
start_barrier: Arc<Barrier>,
mode: TransactionMode,
think_ms: u64,
compute_usec: u64,
timeout: Duration,
) -> Result<u64> {
start_barrier.wait();
@@ -208,6 +207,9 @@ async fn worker_thread(
};
conn.execute(begin_stmt, ()).await?;
let result = perform_compute(thread_id, compute_usec);
std::hint::black_box(result);
for i in 0..batch_size {
let id = thread_id * iterations * batch_size + iteration * batch_size + i;
stmt.execute(turso::params::Params::Positional(vec![
@@ -218,10 +220,6 @@ async fn worker_thread(
total_inserts.fetch_add(1, Ordering::Relaxed);
}
if think_ms > 0 {
tokio::time::sleep(tokio::time::Duration::from_millis(think_ms)).await;
}
conn.execute("COMMIT", ()).await?;
Ok::<_, turso::Error>(())
};
@@ -250,3 +248,17 @@ async fn worker_thread(
Ok(final_inserts)
}
// Busy loop to simulate CPU or GPU bound computation (for example, parsing,
// data aggregation or ML inference).
fn perform_compute(thread_id: usize, usec: u64) -> u64 {
if usec == 0 {
return 0;
}
let start = Instant::now();
let mut sum: u64 = 0;
while start.elapsed().as_micros() < usec as u128 {
sum = sum.wrapping_add(thread_id as u64);
}
sum
}