linera_views/test_utils/
performance.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::time::{Duration, Instant};
5
6use crate::{
7    batch::Batch,
8    store::{KeyValueStore, TestKeyValueStore},
9    test_utils::{add_prefix, get_random_key_values_with_small_keys},
10};
11
12// We generate about 2000 keys of length 11 with a key of length 10000
13// The keys are of the form 0,x_1, ..., x_n with 0 <= x_i < 4 and n=10.
14
15/// A value to use for the keys
16const PREFIX: &[u8] = &[0];
17
18/// A value to use for the keys
19const PREFIX_SEARCH: &[u8] = &[0, 0];
20
21/// The number of keys
22const NUM_ENTRIES: usize = 200;
23
24/// The number of inserted keys
25const NUM_INSERT: usize = 70;
26
27/// The length of the keys
28const LEN_KEY: usize = 10;
29
30/// The length of the values
31const LEN_VALUE: usize = 10000;
32
33async fn clear_store<S: KeyValueStore>(store: &S) {
34    let mut batch = Batch::new();
35    batch.delete_key_prefix(PREFIX.to_vec());
36    store.write_batch(batch).await.unwrap();
37}
38
39/// Benchmarks the `contains_key` operation.
40pub async fn contains_key<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
41where
42    F: Fn(bool) -> bool,
43{
44    let store = S::new_test_store().await.unwrap();
45    let mut total_time = Duration::ZERO;
46    for _ in 0..iterations {
47        let key_values = add_prefix(
48            PREFIX,
49            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
50        );
51        let mut batch = Batch::new();
52        for key_value in &key_values[..NUM_INSERT] {
53            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
54        }
55        store.write_batch(batch).await.unwrap();
56
57        let measurement = Instant::now();
58        for key_value in &key_values {
59            f(store.contains_key(&key_value.0).await.unwrap());
60        }
61        total_time += measurement.elapsed();
62
63        clear_store(&store).await;
64    }
65
66    total_time
67}
68
69/// Benchmarks the `contains_keys` operation.
70pub async fn contains_keys<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
71where
72    F: Fn(Vec<bool>) -> Vec<bool>,
73{
74    let store = S::new_test_store().await.unwrap();
75    let mut total_time = Duration::ZERO;
76    for _ in 0..iterations {
77        let key_values = add_prefix(
78            PREFIX,
79            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
80        );
81        let mut batch = Batch::new();
82        for key_value in &key_values[..NUM_INSERT] {
83            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
84        }
85        store.write_batch(batch).await.unwrap();
86        let keys = key_values
87            .into_iter()
88            .map(|(key, _)| key)
89            .collect::<Vec<_>>();
90
91        let measurement = Instant::now();
92        f(store.contains_keys(keys).await.unwrap());
93        total_time += measurement.elapsed();
94
95        clear_store(&store).await;
96    }
97
98    total_time
99}
100
101/// Benchmarks the `find_keys_by_prefix` operation.
102pub async fn find_keys_by_prefix<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
103where
104    F: Fn(S::Keys) -> S::Keys,
105{
106    let store = S::new_test_store().await.unwrap();
107    let mut total_time = Duration::ZERO;
108    for _ in 0..iterations {
109        let key_values = add_prefix(
110            PREFIX,
111            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
112        );
113        let mut batch = Batch::new();
114        for key_value in &key_values {
115            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
116        }
117        store.write_batch(batch).await.unwrap();
118
119        let measurement = Instant::now();
120        f(store.find_keys_by_prefix(PREFIX_SEARCH).await.unwrap());
121        total_time += measurement.elapsed();
122
123        clear_store(&store).await;
124    }
125
126    total_time
127}
128
129/// Benchmarks the `find_keys_by_prefix` operation.
130pub async fn find_key_values_by_prefix<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
131where
132    F: Fn(S::KeyValues) -> S::KeyValues,
133{
134    let store = S::new_test_store().await.unwrap();
135    let mut total_time = Duration::ZERO;
136    for _ in 0..iterations {
137        let key_values = add_prefix(
138            PREFIX,
139            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
140        );
141        let mut batch = Batch::new();
142        for key_value in &key_values {
143            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
144        }
145        store.write_batch(batch).await.unwrap();
146
147        let measurement = Instant::now();
148        f(store
149            .find_key_values_by_prefix(PREFIX_SEARCH)
150            .await
151            .unwrap());
152        total_time += measurement.elapsed();
153
154        clear_store(&store).await;
155    }
156
157    total_time
158}
159
160/// Benchmarks the `read_value_bytes` operation.
161pub async fn read_value_bytes<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
162where
163    F: Fn(Option<Vec<u8>>) -> Option<Vec<u8>>,
164{
165    let store = S::new_test_store().await.unwrap();
166    let mut total_time = Duration::ZERO;
167    for _ in 0..iterations {
168        let key_values = add_prefix(
169            PREFIX,
170            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
171        );
172        let mut batch = Batch::new();
173        for key_value in &key_values {
174            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
175        }
176        store.write_batch(batch).await.unwrap();
177
178        let measurement = Instant::now();
179        for (key, _) in &key_values {
180            f(store.read_value_bytes(key).await.unwrap());
181        }
182        total_time += measurement.elapsed();
183
184        clear_store(&store).await;
185    }
186
187    total_time
188}
189
190/// Benchmarks the `read_multi_values_bytes` operation.
191pub async fn read_multi_values_bytes<S: TestKeyValueStore, F>(iterations: u64, f: F) -> Duration
192where
193    F: Fn(Vec<Option<Vec<u8>>>) -> Vec<Option<Vec<u8>>>,
194{
195    let store = S::new_test_store().await.unwrap();
196    let mut total_time = Duration::ZERO;
197    for _ in 0..iterations {
198        let key_values = add_prefix(
199            PREFIX,
200            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
201        );
202        let mut batch = Batch::new();
203        for key_value in &key_values {
204            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
205        }
206        store.write_batch(batch).await.unwrap();
207        let keys = key_values
208            .into_iter()
209            .map(|(key, _)| key)
210            .collect::<Vec<_>>();
211
212        let measurement = Instant::now();
213        f(store.read_multi_values_bytes(keys).await.unwrap());
214        total_time += measurement.elapsed();
215
216        clear_store(&store).await;
217    }
218
219    total_time
220}
221
222/// Benchmarks the `write_batch` operation.
223pub async fn write_batch<S: TestKeyValueStore>(iterations: u64) -> Duration {
224    let store = S::new_test_store().await.unwrap();
225    let mut total_time = Duration::ZERO;
226    for _ in 0..iterations {
227        let key_values = add_prefix(
228            PREFIX,
229            get_random_key_values_with_small_keys(NUM_ENTRIES, LEN_KEY, LEN_VALUE),
230        );
231        let mut batch = Batch::new();
232        for key_value in &key_values {
233            batch.put_key_value_bytes(key_value.0.clone(), key_value.1.clone());
234        }
235
236        let measurement = Instant::now();
237        store.write_batch(batch).await.unwrap();
238        total_time += measurement.elapsed();
239
240        clear_store(&store).await;
241    }
242
243    total_time
244}