Skip to content

Rework the random functions to reduce allocations #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 4, 2021
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
30 changes: 28 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ rand = "0.8.3"
fastrand = "1"
num_cpus = "1.0"
rusqlite = "0.25.3"
tinystr = "0.4.10"
3 changes: 1 addition & 2 deletions src/bin/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
//!
//! next: basic_async.rs

use fast_sqlite3_inserts as common;
use rusqlite::{params, Connection};

mod common;

fn faker(mut conn: Connection, count: i64) {
let tx = conn.transaction().unwrap();
for _ in 0..count {
Expand Down
4 changes: 2 additions & 2 deletions src/bin/basic_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::str::FromStr;
use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqliteSynchronous};
use sqlx::{ConnectOptions, Connection, Executor, SqliteConnection, Statement};

mod common;
use fast_sqlite3_inserts as common;

async fn faker(mut conn: SqliteConnection, count: i64) -> Result<(), sqlx::Error> {
let mut tx = conn.begin().await?;
Expand All @@ -29,7 +29,7 @@ async fn faker(mut conn: SqliteConnection, count: i64) -> Result<(), sqlx::Error
let area_code = common::get_random_area_code();
stmt_with_area
.query()
.bind(area_code)
.bind(area_code.as_str())
.bind(age)
.bind(is_active)
.execute(&mut tx)
Expand Down
5 changes: 3 additions & 2 deletions src/bin/basic_batched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@

use rusqlite::{Connection, ToSql, Transaction};

mod common;
use crate::common::AreaCode;
use fast_sqlite3_inserts as common;

fn faker_wrapper(mut conn: Connection, count: i64) {
let tx = conn.transaction().unwrap();
Expand Down Expand Up @@ -53,7 +54,7 @@ fn faker(tx: &Transaction, count: i64) {
let mut param_values: Vec<_> = Vec::new();
if with_area {
// lets prepare the batch
let mut vector = Vec::<(String, i8, i8)>::new();
let mut vector = Vec::<(AreaCode, i8, i8)>::new();
for _ in 0..min_batch_size {
let area_code = common::get_random_area_code();
vector.push((area_code, age, is_active));
Expand Down
4 changes: 2 additions & 2 deletions src/bin/basic_batched_wp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use rusqlite::Connection;

mod common;
use fast_sqlite3_inserts as common;

fn faker(mut conn: Connection, count: i64) {
let tx = conn.transaction().unwrap();
Expand All @@ -23,7 +23,7 @@ fn faker(mut conn: Connection, count: i64) {
for _ in 0..min_batch_size {
if with_area {
let area_code = common::get_random_area_code();
let params = format!(" (NULL, {}, {}, {}),", area_code, age, is_active);
let params = format!(" (NULL, {}, {}, {}),", area_code.as_str(), age, is_active);
stmt.push_str(&params);
} else {
let params = format!(" (NULL, NULL, {}, {}),", age, is_active);
Expand Down
2 changes: 1 addition & 1 deletion src/bin/basic_prep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use rusqlite::{params, Connection, Transaction};

mod common;
use fast_sqlite3_inserts as common;

fn faker_wrapper(mut conn: Connection, count: i64) {
let tx = conn.transaction().unwrap();
Expand Down
15 changes: 6 additions & 9 deletions src/bin/busy.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,27 @@
//! busy loop
//!
//! This code does not really do anything, just runs two for loops. It has no SQL code. The idea was to measure how much
//! This code does not really do anything, just runs two for loops. It has no SQL code. The idea was to measure how much
//! time rust spending just to run a for loop, generating data.
//!
//! next: threaded_busy.rs

mod common;
use crate::common::AreaCode;
use fast_sqlite3_inserts as common;

fn faker(count: i64) {
let min_batch_size = 1_000_000;
for _ in 0..(count / min_batch_size) {
let with_area = common::get_random_bool();
let mut current_batch = Vec::<(String, i8, i8)>::new();
let mut current_batch = Vec::<(Option<AreaCode>, i8, i8)>::new();
for _ in 0..min_batch_size {
if with_area {
current_batch.push((
common::get_random_area_code(),
Some(common::get_random_area_code()),
common::get_random_age(),
common::get_random_active(),
));
} else {
current_batch.push((
"".parse().unwrap(),
common::get_random_age(),
common::get_random_active(),
));
current_batch.push((None, common::get_random_age(), common::get_random_active()));
}
}
}
Expand Down
18 changes: 0 additions & 18 deletions src/bin/common.rs

This file was deleted.

7 changes: 4 additions & 3 deletions src/bin/threaded_batched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread;

mod common;
use crate::common::AreaCode;
use fast_sqlite3_inserts as common;

static MIN_BATCH_SIZE: i64 = 50;

enum ParamValues {
WithArea(Vec<(String, i8, i8)>),
WithArea(Vec<(AreaCode, i8, i8)>),
WithoutArea(Vec<(i8, i8)>),
}

Expand Down Expand Up @@ -93,7 +94,7 @@ fn producer(tx: Sender<ParamValues>, count: i64) {
let mut param_values: Vec<_> = Vec::new();
if with_area {
// lets prepare the batch
let mut vector = Vec::<(String, i8, i8)>::new();
let mut vector = Vec::<(AreaCode, i8, i8)>::new();
for _ in 0..MIN_BATCH_SIZE {
let area_code = common::get_random_area_code();
vector.push((area_code, age, is_active));
Expand Down
15 changes: 6 additions & 9 deletions src/bin/threaded_busy.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
//! busy loop but threaded.
//!
//! This code does not really do anything, just runs two for loops. It has no SQL code. The idea was to measure how much
//! This code does not really do anything, just runs two for loops. It has no SQL code. The idea was to measure how much
//! time rust spending just to run a for loop, generating data. This builds upon busy.rs and uses multiple threads.
//!
//! previous: busy.rs

use std::thread;
extern crate num_cpus;

mod common;
use crate::common::AreaCode;
use fast_sqlite3_inserts as common;

fn faker(count: i64) {
let min_batch_size = 1_000_000;
for _ in 0..(count / min_batch_size) {
let with_area = common::get_random_bool();
let mut current_batch = Vec::<(String, i8, i8)>::new();
let mut current_batch = Vec::<(Option<AreaCode>, i8, i8)>::new();
for _ in 0..min_batch_size {
if with_area {
current_batch.push((
common::get_random_area_code(),
Some(common::get_random_area_code()),
common::get_random_age(),
common::get_random_active(),
));
} else {
current_batch.push((
"".parse().unwrap(),
common::get_random_age(),
common::get_random_active(),
));
current_batch.push((None, common::get_random_age(), common::get_random_active()));
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/bin/threaded_str_batched.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread;

mod common;
use fast_sqlite3_inserts as common;

fn consumer(rx: Receiver<String>) {
let mut conn = Connection::open("threaded_str_batched.db").unwrap();
Expand Down Expand Up @@ -49,7 +49,7 @@ fn producer(tx: Sender<String>, count: i64) {
for _ in 0..min_batch_size {
if with_area {
let area_code = common::get_random_area_code();
let params = format!(" (NULL, {}, {}, {}),", area_code, age, is_active);
let params = format!(" (NULL, {}, {}, {}),", area_code.as_str(), age, is_active);
stmt.push_str(&params);
} else {
let params = format!(" (NULL, NULL, {}, {}),", age, is_active);
Expand Down
61 changes: 61 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use rusqlite::{types::ToSqlOutput, ToSql};
use tinystr::TinyStr8;

pub fn get_random_age() -> i8 {
[5, 10, 15][fastrand::usize(0..3)]
}

pub fn get_random_active() -> i8 {
fastrand::bool().into()
}

pub fn get_random_bool() -> bool {
fastrand::bool()
}

pub fn get_random_area_code() -> AreaCode {
let n = fastrand::u32(0..=999_999);
let buffer = format_6digits_number(n);
TinyStr8::from_bytes(&buffer).map(AreaCode).unwrap()
}

/// Formats a number that is between 0 and 999_999,
/// the number will be padded with `0`s.
pub fn format_6digits_number(mut n: u32) -> [u8; 6] {
let mut buffer = [b'0'; 6];
let mut i = buffer.len() - 1;
while i < buffer.len() {
buffer[i] = (n % 10) as u8 + b'0';
n = n / 10;
i = i.wrapping_sub(1);
}
buffer
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn formatting() {
for n in 0..=999_999 {
let output = format_6digits_number(n);
let expected = format!("{:06}", n);
assert_eq!(output, expected.as_bytes());
}
}
}

pub struct AreaCode(TinyStr8);

impl AreaCode {
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}

impl ToSql for AreaCode {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
Ok(ToSqlOutput::from(self.0.as_str()))
}
}