1use rusqlite::{Connection, Result};
2use std::time::Instant;
3
4#[unsafe(no_mangle)]
5unsafe extern "C" fn __dlapi_close() -> i32 { return 0; }
6#[unsafe(no_mangle)]
7unsafe extern "C" fn __dlapi_error() -> i32 { return 0; }
8#[unsafe(no_mangle)]
9unsafe extern "C" fn __dlapi_open() -> i32 { return 0; }
10#[unsafe(no_mangle)]
11unsafe extern "C" fn __dlapi_resolve() -> i32 { return 0; }
12#[unsafe(no_mangle)]
13unsafe extern "C" fn __dlapi_reverse() -> i32 { return 0; }
14
15const NUM_INSERTS: usize = 100000;
16
17fn benchmark_transient_sqlite() -> Result<(Connection, std::time::Duration)> {
18 println!("Benchmarking transient SQLite in-memory database...");
19
20 let conn = Connection::open_in_memory()?;
21
22 conn.execute(
24 "CREATE TABLE test_table (
25 id INTEGER,
26 name TEXT,
27 value INTEGER,
28 data BLOB
29 )",
30 [],
31 )?;
32
33 let start = Instant::now();
34
35 conn.execute("BEGIN TRANSACTION", [])?;
36 for i in 0..NUM_INSERTS {
37 conn.execute(
38 "INSERT INTO test_table (id, name, value, data) VALUES (?1, ?2, ?3, ?4)",
39 [
40 &i,
41 &format!("name_{}", i) as &dyn rusqlite::ToSql,
42 &(i * 2),
43 &vec![0u8; 100] as &dyn rusqlite::ToSql,
44 ],
45 )?;
46 }
47 conn.execute("COMMIT", [])?;
48
49 let duration = start.elapsed();
50 println!("Standard SQLite: Inserted {} records in {:?}", NUM_INSERTS, duration);
51
52 Ok((conn, duration))
53}
54
55fn query_transient_sqlite(conn: &Connection) -> Result<std::time::Duration> {
56 println!("Querying transient SQLite in-memory database...");
57
58 let start = Instant::now();
59
60 let mut stmt = conn.prepare("SELECT COUNT(*) FROM test_table")?;
64 let count: i64 = stmt.query_row([], |row| row.get(0))?;
65 println!(" Total records: {}", count);
66
67 let mut stmt = conn.prepare("SELECT id, name, value FROM test_table WHERE id BETWEEN ? AND ?")?;
69 let rows = stmt.query_map([&100, &110], |row| {
70 Ok((
71 row.get::<_, i64>(0)?,
72 row.get::<_, String>(1)?,
73 row.get::<_, i64>(2)?,
74 ))
75 })?;
76
77 let mut selected_count = 0;
78 for row in rows {
79 let _record = row?;
80 selected_count += 1;
81 }
82 println!(" Selected records (ID 100-110): {}", selected_count);
83
84 let mut stmt = conn.prepare("SELECT AVG(value), MAX(value), MIN(value) FROM test_table")?;
86 let (avg, max, min): (f64, i64, i64) = stmt.query_row([], |row| {
87 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
88 })?;
89 println!(" Value stats - Avg: {:.2}, Max: {}, Min: {}", avg, max, min);
90
91 let duration = start.elapsed();
92 println!("Standard SQLite queries completed in {:?}", duration);
93
94 Ok(duration)
95}
96
97#[allow(dead_code)]
98fn benchmark_file_sqlite() -> Result<(Connection, std::time::Duration)> {
99 println!("Benchmarking SQLite file database...");
100
101 let _ = std::fs::remove_file("benchmark_test.db");
103
104 let conn = Connection::open("benchmark_test.db")?;
105
106 conn.execute(
108 "CREATE TABLE test_table (
109 id INTEGER,
110 name TEXT,
111 value INTEGER,
112 data BLOB
113 )",
114 [],
115 )?;
116
117 let start = Instant::now();
118
119 conn.execute("BEGIN TRANSACTION", [])?;
120 for i in 0..NUM_INSERTS {
121 conn.execute(
122 "INSERT INTO test_table (id, name, value, data) VALUES (?1, ?2, ?3, ?4)",
123 [
124 &i,
125 &format!("name_{}", i) as &dyn rusqlite::ToSql,
126 &(i * 2),
127 &vec![0u8; 100] as &dyn rusqlite::ToSql,
128 ],
129 )?;
130 }
131 conn.execute("COMMIT", [])?;
132
133 let duration = start.elapsed();
134 println!("File SQLite: Inserted {} records in {:?}", NUM_INSERTS, duration);
135
136 Ok((conn, duration))
137}
138
139#[allow(dead_code)]
140fn query_file_sqlite(conn: &Connection) -> Result<std::time::Duration> {
141 println!("Querying SQLite file database...");
142
143 let start = Instant::now();
144
145 let mut stmt = conn.prepare("SELECT COUNT(*) FROM test_table")?;
149 let count: i64 = stmt.query_row([], |row| row.get(0))?;
150 println!(" Total records: {}", count);
151
152 let mut stmt = conn.prepare("SELECT id, name, value FROM test_table WHERE id BETWEEN ? AND ?")?;
154 let rows = stmt.query_map([&100, &110], |row| {
155 Ok((
156 row.get::<_, i64>(0)?,
157 row.get::<_, String>(1)?,
158 row.get::<_, i64>(2)?,
159 ))
160 })?;
161
162 let mut selected_count = 0;
163 for row in rows {
164 let _record = row?;
165 selected_count += 1;
166 }
167 println!(" Selected records (ID 100-110): {}", selected_count);
168
169 let mut stmt = conn.prepare("SELECT AVG(value), MAX(value), MIN(value) FROM test_table")?;
171 let (avg, max, min): (f64, i64, i64) = stmt.query_row([], |row| {
172 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
173 })?;
174 println!(" Value stats - Avg: {:.2}, Max: {}, Min: {}", avg, max, min);
175
176 let duration = start.elapsed();
177 println!("File SQLite queries completed in {:?}", duration);
178
179 Ok(duration)
180}
181
182fn benchmark_transient_vtab() -> Result<(Connection, std::time::Duration)> {
183 println!("Benchmarking Twizzler transient virtual table...");
184
185 let conn = Connection::open_in_memory()?;
186 conn.setup_twz_vtab();
187
188 conn.execute(
190 "CREATE VIRTUAL TABLE test_table USING twz_transient_vtab(
191 id INTEGER,
192 name TEXT,
193 value INTEGER,
194 data BLOB
195 )",
196 [],
197 )?;
198
199 let start = Instant::now();
200
201 for i in 0..NUM_INSERTS {
202 conn.execute(
203 "INSERT INTO test_table (id, name, value, data) VALUES (?1, ?2, ?3, ?4)",
204 [
205 &i,
206 &format!("name_{}", i) as &dyn rusqlite::ToSql,
207 &(i * 2),
208 &vec![0u8; 100] as &dyn rusqlite::ToSql,
209 ],
210 )?;
211 }
212
213 let duration = start.elapsed();
214 println!("Transient VTab: Inserted {} records in {:?}", NUM_INSERTS, duration);
215
216 Ok((conn, duration))
217}
218
219fn query_transient_vtab(conn: &Connection) -> Result<std::time::Duration> {
220 println!("Querying Twizzler transient virtual table...");
221
222 let start = Instant::now();
223
224 let mut stmt = conn.prepare("SELECT COUNT(*) FROM test_table")?;
228 let count: i64 = stmt.query_row([], |row| row.get(0))?;
229 println!(" Total records: {}", count);
230
231 let mut stmt = conn.prepare("SELECT id, name, value FROM test_table WHERE id BETWEEN ? AND ?")?;
233 let rows = stmt.query_map([&100, &110], |row| {
234 Ok((
235 row.get::<_, i64>(0)?,
236 row.get::<_, String>(1)?,
237 row.get::<_, i64>(2)?,
238 ))
239 })?;
240
241 let mut selected_count = 0;
242 for row in rows {
243 let _record = row?;
244 selected_count += 1;
245 }
246 println!(" Selected records (ID 100-110): {}", selected_count);
247
248 let mut stmt = conn.prepare("SELECT AVG(value), MAX(value), MIN(value) FROM test_table")?;
250 let (avg, max, min): (f64, i64, i64) = stmt.query_row([], |row| {
251 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
252 })?;
253 println!(" Value stats - Avg: {:.2}, Max: {}, Min: {}", avg, max, min);
254
255 let duration = start.elapsed();
256 println!("Transient VTab queries completed in {:?}", duration);
257
258 Ok(duration)
259}
260
261fn benchmark_persistent_vtab() -> Result<(Connection, std::time::Duration)> {
262 println!("Benchmarking Twizzler persistent virtual table...");
263
264 let conn = Connection::open_in_memory()?;
265 conn.setup_twz_vtab();
266
267 conn.execute(
269 "CREATE VIRTUAL TABLE test_table USING twz_persistent_vtab(
270 id INTEGER,
271 name TEXT,
272 value INTEGER,
273 data BLOB
274 )",
275 [],
276 )?;
277
278 let start = Instant::now();
279
280 conn.execute("BEGIN TRANSACTION", [])?;
281
282 for i in 0..NUM_INSERTS {
283 conn.execute(
284 "INSERT INTO test_table (id, name, value, data) VALUES (?1, ?2, ?3, ?4)",
285 [
286 &i,
287 &format!("name_{}", i) as &dyn rusqlite::ToSql,
288 &(i * 2),
289 &vec![0u8; 100] as &dyn rusqlite::ToSql,
290 ],
291 )?;
292 }
293
294 conn.execute("COMMIT", [])?;
295
296 let duration = start.elapsed();
297 println!("Persistent VTab: Inserted {} records in {:?}", NUM_INSERTS, duration);
298
299 Ok((conn, duration))
300}
301
302fn query_persistent_vtab(conn: &Connection) -> Result<std::time::Duration> {
303 println!("Querying Twizzler persistent virtual table...");
304
305 let start = Instant::now();
306
307 let mut stmt = conn.prepare("SELECT COUNT(*) FROM test_table")?;
311 let count: i64 = stmt.query_row([], |row| row.get(0))?;
312 println!(" Total records: {}", count);
313
314 let mut stmt = conn.prepare("SELECT id, name, value FROM test_table WHERE id BETWEEN ? AND ?")?;
316 let rows = stmt.query_map([&100, &110], |row| {
317 Ok((
318 row.get::<_, i64>(0)?,
319 row.get::<_, String>(1)?,
320 row.get::<_, i64>(2)?,
321 ))
322 })?;
323
324 let mut selected_count = 0;
325 for row in rows {
326 let _record = row?;
327 selected_count += 1;
328 }
329 println!(" Selected records (ID 100-110): {}", selected_count);
330
331 let mut stmt = conn.prepare("SELECT AVG(value), MAX(value), MIN(value) FROM test_table")?;
333 let (avg, max, min): (f64, i64, i64) = stmt.query_row([], |row| {
334 Ok((row.get(0)?, row.get(1)?, row.get(2)?))
335 })?;
336 println!(" Value stats - Avg: {:.2}, Max: {}, Min: {}", avg, max, min);
337
338 let duration = start.elapsed();
339 println!("Persistent VTab queries completed in {:?}", duration);
340
341 Ok(duration)
342}
343
344#[allow(dead_code)]
345fn benchmark_file_persistence() -> Result<std::time::Duration> {
346 println!("Benchmarking SQLite persistent storage for opening and querying existing data...");
347 let start = Instant::now();
348 let conn = Connection::open("benchmark_test.db")?;
349
350 let _ = query_file_sqlite(&conn)?;
351 let duration = start.elapsed();
352 println!("Reopened and queried existing SQLite file database in {:?}", duration);
353 Ok(duration)
354}
355
356fn benchmark_persistent_vtab_persistence() -> Result<std::time::Duration> {
357 println!("Benchmarking Twizzler persistent virtual table for opening and querying existing data...");
358 let start = Instant::now();
359 let conn = Connection::open_in_memory()?;
360 conn.setup_twz_vtab();
361
362 conn.execute(
364 "CREATE VIRTUAL TABLE test_table USING twz_persistent_vtab(
365 id INTEGER,
366 name TEXT,
367 value INTEGER,
368 data BLOB
369 )",
370 [],
371 )?;
372
373 let _ = query_persistent_vtab(&conn)?;
374 let duration = start.elapsed();
375 println!("Reopened and queried existing Twizzler persistent virtual table in {:?}", duration);
376 Ok(duration)
377}
378
379fn run_bench() -> Result<()> {
380 println!("\n=== Batch Insert Performance Comparison ===");
381
382 let (sqlite_conn, sqlite_duration) = benchmark_transient_sqlite()?;
384
385 let (transient_conn, transient_duration) = benchmark_transient_vtab()?;
390
391 let (persistent_conn, persistent_duration) = benchmark_persistent_vtab()?;
393
394 println!("\n=== Performance Summary ===");
396 println!("Number of inserts: {}", NUM_INSERTS);
397 println!("Standard SQLite: {:?}", sqlite_duration);
398 println!("Transient VTab: {:?}", transient_duration);
400 println!("Persistent VTab: {:?}", persistent_duration);
401
402 println!("\nThroughput (records/second):");
403 println!("Standard SQLite: {:.0}", NUM_INSERTS as f64 / sqlite_duration.as_secs_f64());
404 println!("Transient VTab: {:.0}", NUM_INSERTS as f64 / transient_duration.as_secs_f64());
406 println!("Persistent VTab: {:.0}", NUM_INSERTS as f64 / persistent_duration.as_secs_f64());
407
408 println!("\n=== Query Performance Comparison ===");
409
410 let sqlite_query_duration = query_transient_sqlite(&sqlite_conn)?;
411 let transient_query_duration = query_transient_vtab(&transient_conn)?;
413 let persistent_query_duration = query_persistent_vtab(&persistent_conn)?;
414
415 println!("\n=== Query Performance Summary ===");
416 println!("Standard SQLite: {:?}", sqlite_query_duration);
417 println!("Transient VTab: {:?}", transient_query_duration);
419 println!("Persistent VTab: {:?}", persistent_query_duration);
420
421 drop(persistent_conn);
424
425 let persistent_vtab_persistence_duration = benchmark_persistent_vtab_persistence()?;
427
428 println!("\n=== Persistence Performance Summary ===");
429 println!("Reopen & Query Persistent VTab: {:?}", persistent_vtab_persistence_duration);
431
432 Ok(())
433}
434
435fn cleanup() -> Result<()> {
436 let mut nh = naming::dynamic_naming_factory().unwrap();
440 let _ = nh.remove("/data/vtab-test_table");
441
442 Ok(())
443}
444
445fn main() -> Result<()> {
446 println!("SQLite Performance Benchmark");
447 println!("Testing with {} records\n", NUM_INSERTS);
448
449 run_bench()?;
450
451 cleanup()?;
452
453 Ok(())
454}