Skip to content

Commit c69ab15

Browse files
committed
fix: test proportion of each scenario of TPCC and add more indicators
1 parent 7dedfab commit c69ab15

File tree

3 files changed

+201
-52
lines changed

3 files changed

+201
-52
lines changed

README.md

-12
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,6 @@ let tuples = fnck_sql.run("select * from t1")?;
5757
### TPCC
5858
run `cargo run -p tpcc --release` to run tpcc
5959

60-
- CPU: i9-13900HX
61-
- Memory: 32.0 GB
62-
- SSD: YMTC PC411-1024GB-B
63-
```shell
64-
<90th Percentile RT (MaxRT)>
65-
New-Order : 0.882 (0.947)
66-
Payment : 0.080 (0.095)
67-
Order-Status : 0.235 (0.255)
68-
Delivery : 5.386 (5.658)
69-
Stock-Level : 0.001 (0.002)
70-
```
71-
7260
#### PG Wire Service
7361
run `cargo run --features="net"` to start server
7462
![start](./static/images/start.gif)

tpcc/src/main.rs

+133-40
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::order_stat::OrderStatTest;
55
use crate::payment::PaymentTest;
66
use crate::rt_hist::RtHist;
77
use crate::slev::SlevTest;
8+
use crate::utils::SeqGen;
89
use clap::Parser;
910
use fnck_sql::db::{DBTransaction, DataBaseBuilder};
1011
use fnck_sql::errors::DatabaseError;
@@ -20,8 +21,16 @@ mod order_stat;
2021
mod payment;
2122
mod rt_hist;
2223
mod slev;
24+
mod utils;
2325

2426
pub(crate) const ALLOW_MULTI_WAREHOUSE_TX: bool = true;
27+
pub(crate) const RT_LIMITS: [Duration; 5] = [
28+
Duration::from_millis(500),
29+
Duration::from_millis(500),
30+
Duration::from_millis(500),
31+
Duration::from_secs(8),
32+
Duration::from_secs(2),
33+
];
2534

2635
pub(crate) trait TpccTransaction<S: Storage> {
2736
type Args;
@@ -54,7 +63,7 @@ struct Args {
5463
path: String,
5564
#[clap(long, default_value = "5")]
5665
max_retry: usize,
57-
#[clap(long, default_value = "1080")]
66+
#[clap(long, default_value = "720")]
5867
measure_time: u64,
5968
#[clap(long, default_value = "1")]
6069
num_ware: usize,
@@ -72,6 +81,9 @@ fn main() -> Result<(), TpccError> {
7281
Load::load_ord(&mut rng, &database, args.num_ware)?;
7382

7483
let mut rt_hist = RtHist::new();
84+
let mut success = [0usize; 5];
85+
let mut late = [0usize; 5];
86+
let mut failure = [0usize; 5];
7587
let tests = vec![
7688
Box::new(NewOrdTest) as Box<dyn TpccTest<_>>,
7789
Box::new(PaymentTest),
@@ -81,64 +93,145 @@ fn main() -> Result<(), TpccError> {
8193
];
8294
let tpcc_args = TpccArgs { joins: args.joins };
8395

84-
let tpcc_start = Instant::now();
8596
let duration = Duration::new(args.measure_time, 0);
8697
let mut round_count = 0;
98+
let mut seq_gen = SeqGen::new(10, 10, 1, 1, 1);
99+
let tpcc_start = Instant::now();
87100

88101
while tpcc_start.elapsed() < duration {
89-
for (i, tpcc_test) in tests.iter().enumerate() {
90-
let mut is_succeed = false;
91-
for j in 0..args.max_retry + 1 {
92-
let transaction_start = Instant::now();
93-
let mut tx = database.new_transaction()?;
94-
95-
if let Err(err) =
96-
tpcc_test.do_transaction(&mut rng, &mut tx, args.num_ware, &tpcc_args)
97-
{
98-
eprintln!(
99-
"[{}] Error while doing transaction: {}",
100-
tpcc_test.name(),
101-
err
102-
);
102+
let i = seq_gen.get();
103+
let tpcc_test = &tests[i];
104+
105+
let mut is_succeed = false;
106+
for j in 0..args.max_retry + 1 {
107+
let transaction_start = Instant::now();
108+
let mut tx = database.new_transaction()?;
109+
110+
if let Err(err) = tpcc_test.do_transaction(&mut rng, &mut tx, args.num_ware, &tpcc_args)
111+
{
112+
failure[i] += 1;
113+
eprintln!(
114+
"[{}] Error while doing transaction: {}",
115+
tpcc_test.name(),
116+
err
117+
);
118+
} else {
119+
let rt = transaction_start.elapsed();
120+
rt_hist.hist_inc(i, rt);
121+
is_succeed = true;
122+
123+
if rt <= RT_LIMITS[i] {
124+
success[i] += 1;
103125
} else {
104-
rt_hist.hist_inc(i, transaction_start.elapsed());
105-
is_succeed = true;
106-
break;
107-
}
108-
if j < args.max_retry {
109-
println!("[{}] Retry for the {}th time", tpcc_test.name(), j + 1);
126+
late[i] += 1;
110127
}
128+
break;
111129
}
112-
if !is_succeed {
113-
return Err(TpccError::MaxRetry);
130+
if j < args.max_retry {
131+
println!("[{}] Retry for the {}th time", tpcc_test.name(), j + 1);
114132
}
115133
}
116-
if round_count != 0 && round_count % 4 == 0 {
134+
if !is_succeed {
135+
return Err(TpccError::MaxRetry);
136+
}
137+
if round_count != 0 && round_count % 8 == 0 {
117138
println!(
118-
"============ TPCC CheckPoint {} on round {round_count}: ===============",
119-
round_count / 4
139+
"[TPCC CheckPoint {} on round {round_count}][{}]: 90th Percentile RT: {:.3}",
140+
round_count / 4,
141+
tpcc_test.name(),
142+
rt_hist.hist_ckp(i)
120143
);
121-
for (i, name) in vec![
122-
"New-Order",
123-
"Payment",
124-
"Order-Status",
125-
"Delivery",
126-
"Stock-Level",
127-
]
128-
.into_iter()
129-
.enumerate()
130-
{
131-
println!("{name} 90th Percentile RT: {:.3}", rt_hist.hist_ckp(i));
132-
}
133-
println!("==========================================================");
134144
}
135145
round_count += 1;
136146
}
147+
let actual_tpcc_time = tpcc_start.elapsed();
148+
println!("---------------------------------------------------");
149+
// Raw Results
150+
print_transaction(&success, &late, &failure, |name, success, late, failure| {
151+
println!("|{}| sc: {} lt: {} fl: {}", name, success, late, failure)
152+
});
153+
println!("in {} sec.", actual_tpcc_time.as_secs());
154+
println!("<Constraint Check> (all must be [OK])");
155+
println!("[transaction percentage]");
156+
157+
let mut j = 0.0;
158+
for i in 0..5 {
159+
j += (success[i] + late[i]) as f64;
160+
}
161+
// Payment
162+
let f = ((success[1] + late[1]) as f64 / j) * 100.0;
163+
print!(" Payment: {:.1}% (>=43.0%)", f);
164+
if f >= 43.0 {
165+
println!(" [Ok]");
166+
} else {
167+
println!(" [NG]");
168+
}
169+
// Order-Status
170+
let f = ((success[2] + late[2]) as f64 / j) * 100.0;
171+
print!(" Order-Status: {:.1}% (>=4.0%)", f);
172+
if f >= 4.0 {
173+
println!(" [Ok]");
174+
} else {
175+
println!(" [NG]");
176+
}
177+
// Delivery
178+
let f = ((success[3] + late[3]) as f64 / j) * 100.0;
179+
print!(" Order-Status: {:.1}% (>=4.0%)", f);
180+
if f >= 4.0 {
181+
println!(" [Ok]");
182+
} else {
183+
println!(" [NG]");
184+
}
185+
// Stock-Level
186+
let f = ((success[4] + late[4]) as f64 / j) * 100.0;
187+
print!(" Order-Status: {:.1}% (>=4.0%)", f);
188+
if f >= 4.0 {
189+
println!(" [Ok]");
190+
} else {
191+
println!(" [NG]");
192+
}
193+
println!("[response time (at least 90%% passed)]");
194+
print_transaction(&success, &late, &failure, |name, success, late, _| {
195+
let f = (success as f64 / (success + late) as f64) * 100.0;
196+
print!(" {}: {:.1}", name, f);
197+
if f >= 90.0 {
198+
println!(" [OK]");
199+
} else {
200+
println!(" [NG]");
201+
}
202+
});
203+
print_transaction(&success, &late, &failure, |name, success, late, _| {
204+
println!(" {} Total: {}", name, success + late)
205+
});
206+
println!();
137207
rt_hist.hist_report();
208+
println!("<TpmC>");
209+
let tpmc = (success[0] + late[0]) as f64 / (actual_tpcc_time.as_secs_f64() / 60.0);
210+
println!("{} Tpmc", tpmc);
138211

139212
Ok(())
140213
}
141214

215+
fn print_transaction<F: Fn(&str, usize, usize, usize)>(
216+
success: &[usize],
217+
late: &[usize],
218+
failure: &[usize],
219+
fn_print: F,
220+
) {
221+
for (i, name) in vec![
222+
"New-Order",
223+
"Payment",
224+
"Order-Status",
225+
"Delivery",
226+
"Stock-Level",
227+
]
228+
.into_iter()
229+
.enumerate()
230+
{
231+
fn_print(name, success[i], late[i], failure[i]);
232+
}
233+
}
234+
142235
fn other_ware(rng: &mut ThreadRng, home_ware: usize, num_ware: usize) -> usize {
143236
if num_ware == 1 {
144237
return home_ware;

tpcc/src/utils.rs

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use rand::rngs::ThreadRng;
2+
use rand::Rng;
3+
4+
pub(crate) struct SeqGen {
5+
no: usize,
6+
py: usize,
7+
os: usize,
8+
dl: usize,
9+
sl: usize,
10+
total: usize,
11+
seq: Vec<usize>,
12+
next_num: usize,
13+
rng: ThreadRng,
14+
}
15+
16+
impl SeqGen {
17+
pub(crate) fn new(n: usize, p: usize, o: usize, d: usize, s: usize) -> Self {
18+
let total = n + p + o + d + s;
19+
20+
Self {
21+
no: n,
22+
py: p,
23+
os: o,
24+
dl: d,
25+
sl: s,
26+
total,
27+
seq: vec![0; total],
28+
next_num: 0,
29+
rng: Default::default(),
30+
}
31+
}
32+
33+
pub(crate) fn get(&mut self) -> usize {
34+
if self.next_num >= self.total {
35+
self.shuffle();
36+
self.next_num = 0;
37+
}
38+
let pos = self.next_num;
39+
self.next_num += 1;
40+
self.seq[pos]
41+
}
42+
43+
pub(crate) fn shuffle(&mut self) {
44+
let mut pos = 0;
45+
46+
let mut fn_init = |len, tx| {
47+
for i in 0..len {
48+
self.seq[pos + i] = tx;
49+
}
50+
pos += len;
51+
};
52+
fn_init(self.no, 0);
53+
fn_init(self.py, 1);
54+
fn_init(self.os, 2);
55+
fn_init(self.dl, 3);
56+
fn_init(self.sl, 4);
57+
58+
let mut i = 0;
59+
for j in (0..self.total).rev() {
60+
let rmd = self.rng.gen::<usize>() % (j + 1);
61+
let tmp = self.seq[rmd + i];
62+
self.seq[rmd + i] = self.seq[i];
63+
self.seq[i] = tmp;
64+
65+
i += 1;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)