Skip to content

Commit 2caf697

Browse files
authored
Adding puppeteer benchmarking test between raw duckdb & sequence memory DBM (#26)
* Adding puppeteer based tests * Adding tests * Run tests in CI * Run now * Git clone with large files * Remove unwanted stuff * Remove unwanted stuff * Remove cypress * Run * Increase timeout * Adding raw duckdb runner * Adding test
1 parent 4b7a7cf commit 2caf697

File tree

11 files changed

+1730
-1266
lines changed

11 files changed

+1730
-1266
lines changed

.github/workflows/build-test.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v2
13+
with:
14+
lfs: true
1315
- run: npm install
1416
- run: npx nx run-many --target=build --all --parallel
1517
- run: npx nx run-many --target=test --all --parallel

benchmarking/benchmarking-app/src/app/app.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,32 @@
11
import { Route, BrowserRouter as Router, Routes } from 'react-router-dom';
22
import { MemoryDBMProvider } from './dbm-context/memory-dbm-context';
3+
import { RawDBMProvider } from './dbm-context/raw-dbm-context';
34
import { FileLoader } from './file-loader/file-loader';
45
import { QueryBenchmarking } from './query-benchmarking/query-benchmarking';
56

67
export function App() {
78
return (
89
<Router>
910
<Routes>
11+
<Route
12+
path="/raw-dbm"
13+
element={
14+
<div>
15+
<h1>Raw DuckDB</h1>
16+
<RawDBMProvider>
17+
<FileLoader>
18+
<QueryBenchmarking />
19+
</FileLoader>
20+
</RawDBMProvider>
21+
</div>
22+
}
23+
/>
1024
<Route
1125
path="/memory-dbm"
1226
element={
1327
<div>
28+
<h1>In Memory Sequence DuckDB</h1>
29+
1430
<MemoryDBMProvider>
1531
<FileLoader>
1632
<QueryBenchmarking />
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import axios from 'axios';
2+
import { spawn } from 'child_process';
3+
import * as puppeteer from 'puppeteer';
4+
5+
describe('Benchmarking DBMs', () => {
6+
let page;
7+
let browser;
8+
let appProcess;
9+
10+
beforeAll(async () => {
11+
appProcess = spawn('npx', ['nx', 'serve', 'benchmarking-app'], {
12+
stdio: 'inherit',
13+
});
14+
15+
// Wait for the server to start
16+
let serverStarted = false;
17+
while (!serverStarted) {
18+
try {
19+
const response = await axios.get('http://localhost:4200'); // Replace with your server's URL
20+
if (response.status === 200) {
21+
serverStarted = true;
22+
} else {
23+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second before retrying
24+
}
25+
} catch (error) {
26+
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for 1 second before retrying
27+
}
28+
}
29+
30+
browser = await puppeteer.launch({
31+
headless: 'new',
32+
});
33+
page = await browser.newPage();
34+
}, 30000);
35+
36+
it('Benchmark raw duckdb with memory sequence duckdb', async () => {
37+
await page.goto('http://localhost:4200/raw-dbm');
38+
/**
39+
* wait for total time to be render
40+
*/
41+
await page.waitForSelector('#total_time', { timeout: 120000 });
42+
/**
43+
* Get the total time as number
44+
*/
45+
const totalTimeForRawDB = await page.$eval('#total_time', (el) =>
46+
Number(el.textContent)
47+
);
48+
49+
console.info('totalTimeForRawDB', totalTimeForRawDB);
50+
51+
await page.goto('http://localhost:4200/memory-dbm');
52+
53+
/**
54+
* wait for total time to be render
55+
*/
56+
await page.waitForSelector('#total_time', { timeout: 120000 });
57+
58+
/**
59+
* Get the total time as number
60+
*/
61+
const totalTimeForMemoryDB = await page.$eval('#total_time', (el) =>
62+
Number(el.textContent)
63+
);
64+
65+
console.info('totalTimeForMemoryDB', totalTimeForMemoryDB);
66+
67+
/**
68+
* The total diff between the two DBs should be less than 10%
69+
*/
70+
expect(totalTimeForRawDB).toBeLessThan(totalTimeForMemoryDB * 1.1);
71+
}, 220000);
72+
73+
afterAll(async () => {
74+
await browser.close();
75+
appProcess.kill('SIGTERM');
76+
});
77+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { DBM, FileManagerType, MemoryDBFileManager } from '@devrev/meerkat-dbm';
2+
import React, { useState } from 'react';
3+
import { DBMContext } from '../hooks/dbm-context';
4+
import { useClassicEffect } from '../hooks/use-classic-effect';
5+
import { useAsyncDuckDB } from './use-async-duckdb';
6+
7+
export const RawDBMProvider = ({ children }: { children: JSX.Element }) => {
8+
const fileManagerRef = React.useRef<FileManagerType | null>(null);
9+
const [dbm, setdbm] = useState<DBM | null>(null);
10+
11+
const dbState = useAsyncDuckDB();
12+
13+
useClassicEffect(() => {
14+
if (!dbState) {
15+
return;
16+
}
17+
fileManagerRef.current = new MemoryDBFileManager({
18+
db: dbState,
19+
fetchTableFileBuffers: async (table) => {
20+
return [];
21+
},
22+
});
23+
const dbm = new DBM({
24+
db: dbState,
25+
fileManager: fileManagerRef.current,
26+
});
27+
/**
28+
* Making the queryWithTableNames simply run the queries without sequence which is the default behavior
29+
*/
30+
dbm.queryWithTableNames = async (query, tableNames) => {
31+
return dbm.query(query);
32+
};
33+
setdbm(dbm);
34+
}, [dbState]);
35+
36+
if (!dbm || !fileManagerRef.current) {
37+
return <div>Loading...</div>;
38+
}
39+
40+
return (
41+
<DBMContext.Provider
42+
value={{
43+
dbm,
44+
fileManager: fileManagerRef.current,
45+
}}
46+
>
47+
{children}
48+
</DBMContext.Provider>
49+
);
50+
};

benchmarking/benchmarking-app/src/app/query-benchmarking/query-benchmarking.tsx

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,91 @@ export const QueryBenchmarking = () => {
99
time: number;
1010
}[]
1111
>([]);
12+
const [totalTime, setTotalTime] = useState<number>(0);
1213
const { dbm } = useDBM();
1314

1415
useClassicEffect(() => {
16+
setTotalTime(0);
1517
const testQueries = [
16-
'SELECT * as total_count FROM taxi.parquet ORDER BY bcf LIMIT 100',
1718
'SELECT CAST(COUNT(*) as VARCHAR) as total_count FROM taxi.parquet',
1819
"SELECT * FROM taxi.parquet WHERE originating_base_num='B03404' LIMIT 100",
1920
'SELECT CAST(COUNT(*) as VARCHAR) as total_count FROM taxi.parquet GROUP BY hvfhs_license_num',
21+
'SELECT * as total_count FROM taxi.parquet ORDER BY bcf LIMIT 100',
22+
`
23+
WITH group_by_query AS (
24+
SELECT
25+
hvfhs_license_num,
26+
COUNT(*)
27+
FROM
28+
taxi.parquet
29+
GROUP BY
30+
hvfhs_license_num
31+
),
32+
33+
full_query AS (
34+
SELECT
35+
*
36+
FROM
37+
taxi.parquet
38+
)
39+
40+
SELECT
41+
COUNT(*)
42+
FROM
43+
group_by_query
44+
LEFT JOIN
45+
full_query
46+
ON
47+
group_by_query.hvfhs_license_num = full_query.hvfhs_license_num
48+
LIMIT 1
49+
`,
2050
];
2151

2252
setOutput([]);
23-
53+
const promiseArr = [];
54+
const start = performance.now();
2455
for (let i = 0; i < testQueries.length; i++) {
25-
const start = performance.now();
56+
const eachQueryStart = performance.now();
2657

27-
dbm
58+
const promiseObj = dbm
2859
.queryWithTableNames(testQueries[i], ['taxi.parquet'])
2960
.then((results) => {
3061
const end = performance.now();
31-
const time = end - start;
62+
const time = end - eachQueryStart;
3263
setOutput((prev) => [
3364
...prev,
3465
{ queryName: `Query ${i} ---->`, time },
3566
]);
3667
});
68+
69+
promiseArr.push(promiseObj);
3770
}
71+
Promise.all(promiseArr).then(() => {
72+
const end = performance.now();
73+
const time = end - start;
74+
setTotalTime(time);
75+
});
3876
}, []);
3977

4078
return (
4179
<div>
42-
{output.map((o) => {
80+
{output.map((o, i) => {
4381
return (
44-
<div key={o.queryName}>
82+
<div data-query={`${i}`} key={o.queryName}>
4583
{o.queryName} : {o.time}
4684
</div>
4785
);
4886
})}
87+
{totalTime === 0 && (
88+
<div>
89+
<span>Query Running...</span>
90+
</div>
91+
)}
92+
{totalTime > 0 && (
93+
<div>
94+
Total Time: <span id="total_time">{totalTime}</span>
95+
</div>
96+
)}
4997
</div>
5098
);
5199
};

benchmarking/benchmarking-app/tsconfig.app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"node",
77

88
"@nx/react/typings/cssmodule.d.ts",
9-
"@nx/react/typings/image.d.ts"
9+
"@nx/react/typings/image.d.ts",
10+
"puppeteer"
1011
]
1112
},
1213
"exclude": [

benchmarking/benchmarking-app/tsconfig.spec.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"compilerOptions": {
44
"outDir": "../../dist/out-tsc",
55
"module": "commonjs",
6-
"types": ["jest", "node"]
6+
"types": ["jest", "node", "puppeteer"]
77
},
88
"include": [
99
"jest.config.ts",

examples/meerkat-node-example/tsconfig.app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"compilerOptions": {
44
"outDir": "../../dist/out-tsc",
55
"module": "commonjs",
6-
"types": ["node", "express"]
6+
"types": ["node", "express", "puppeteer"]
77
},
88
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
99
"include": ["src/**/*.ts"]

examples/meerkat-node-example/tsconfig.spec.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"compilerOptions": {
44
"outDir": "../../dist/out-tsc",
55
"module": "commonjs",
6-
"types": ["jest", "node"]
6+
"types": ["jest", "node", "puppeteer"]
77
},
88
"include": [
99
"jest.config.ts",

0 commit comments

Comments
 (0)