Skip to content

Commit 6f43d47

Browse files
author
jialan
committed
feat: support custom params when run benchmark test method
1 parent c9f8ba2 commit 6f43d47

File tree

8 files changed

+89
-35
lines changed

8 files changed

+89
-35
lines changed
File renamed without changes.
File renamed without changes.

Diff for: benchmark/data/hive/params.json

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"create": {
3+
"validate": ["$sql"],
4+
"getAllTokens": ["$sql"],
5+
"getAllEntities": ["$sql", { "lineNumber": 8, "column": 1 }]
6+
},
7+
"select": {
8+
"validate": ["$sql"],
9+
"getAllTokens": ["$sql"],
10+
"getAllEntities": ["$sql", { "lineNumber": 8, "column": 1 }]
11+
}
12+
}
File renamed without changes.
File renamed without changes.

Diff for: benchmark/run.ts

+43-15
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,51 @@
11
import path from 'path';
22
import argsParser from 'yargs-parser';
33
import fs from 'fs';
4-
import SqlBenchmark, { languageNameMap } from './sqlBenchmark';
4+
import SqlBenchmark, { languageNameMap, languages } from './sqlBenchmark';
5+
import type { Language } from './sqlBenchmark';
56
import inquirer from 'inquirer';
67
import chalk from 'chalk';
78
import { Table } from 'console-table-printer';
89

9-
const languages: string[] = fs.readdirSync(path.resolve(__dirname, '../src/grammar'));
1010
const argv = argsParser(process.argv.slice(2));
1111
const isChooseAll = argv.lang === 'all';
1212

1313
type TestFile = {
1414
/** Benchmark Name */
1515
name: string;
16-
/** Test sql path */
17-
path: string;
16+
/** Test sql name */
17+
sqlFileName: string;
1818
/** Test run times */
1919
loopTimes?: number;
2020
/** Test method name of parser */
2121
testTypes: string[];
2222
/** Exclude languages */
23-
excludes?: string[];
23+
excludes?: Language[];
2424
/** Include languages */
25-
includes?: string[];
25+
includes?: Language[];
2626
};
2727

2828
const testFiles: TestFile[] = [
2929
{
3030
name: 'Query Collection (100 Rows)',
31-
path: 'select.sql',
31+
sqlFileName: 'select.sql',
3232
loopTimes: 3,
3333
testTypes: ['validate', 'getAllTokens'],
34-
excludes: ['pgsql', 'mysql'],
34+
excludes: ['plsql', 'postgresql'],
35+
},
36+
{
37+
name: 'Select All Entities',
38+
sqlFileName: 'select.sql',
39+
loopTimes: 1,
40+
testTypes: ['getAllEntities'],
41+
includes: ['hive'],
3542
},
3643
{
3744
name: 'Create Table (100 Rows)',
38-
path: 'create.sql',
45+
sqlFileName: 'create.sql',
3946
loopTimes: 3,
40-
testTypes: ['validate'],
41-
excludes: ['pgsql', 'mysql'],
47+
testTypes: ['validate', 'getAllTokens'],
48+
excludes: ['plsql', 'postgresql'],
4249
},
4350
];
4451

@@ -50,6 +57,18 @@ const readSql = (fileName: string, lang: string) => {
5057
return fs.readFileSync(sqlPath, 'utf-8');
5158
};
5259

60+
const readParams = (lang: string) => {
61+
const paramsPath = path.join(__dirname, `./data/${lang}/params.json`);
62+
if (!fs.existsSync(paramsPath)) return null;
63+
return fs.readFileSync(paramsPath, 'utf-8');
64+
};
65+
66+
const getParams = (originalParams: any, sqlFileName: string, methodType: string): any[] => {
67+
if (!originalParams) return ['$sql'];
68+
const fileName = sqlFileName.substring(0, sqlFileName.lastIndexOf('.sql') + 1);
69+
return originalParams[fileName]?.[methodType] || ['$sql'];
70+
};
71+
5372
const askForSaveResult = () => {
5473
inquirer
5574
.prompt([
@@ -125,13 +144,22 @@ const printSummaryReport = () => {
125144
table.printTable();
126145
};
127146

128-
const benchmark = (lang: string) => {
147+
const benchmark = (lang: Language) => {
129148
const sqlBenchmark = new SqlBenchmark(lang);
149+
const originalParams = readParams(lang);
150+
130151
testFiles.forEach((testInfo) => {
131-
const { name, path, testTypes, loopTimes, excludes, includes } = testInfo;
152+
const { name, sqlFileName, testTypes, loopTimes, excludes, includes } = testInfo;
132153
if (excludes?.includes(lang) || (includes?.length && !includes.includes(lang))) return;
133-
const sql = readSql(path, lang);
134-
testTypes.forEach((type) => sqlBenchmark.run(type, name, sql, loopTimes));
154+
const sql = readSql(sqlFileName, lang);
155+
const sqlRows = sql.split('\n').length;
156+
testTypes.forEach((type) => {
157+
const params = getParams(originalParams, sqlFileName, type);
158+
const sqlParamIndex = params.findIndex((param) => param === '$sql');
159+
// replace with real sql text
160+
if (sqlParamIndex !== -1) params.splice(sqlParamIndex, 1, sql);
161+
sqlBenchmark.run(type, name, params, sqlRows, loopTimes);
162+
});
135163
});
136164
sqlBenchmark.printResults();
137165
benchmarkResults.push(sqlBenchmark);

Diff for: benchmark/sqlBenchmark.ts

+28-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import path from 'path';
22
import { MarkdownWritter } from './markdownWritter';
33
import envinfo from 'envinfo';
44
import { Table } from 'console-table-printer';
5-
import BasicParser from '../src/parser/common/basicParser';
5+
import { BasicSQL } from '../src/parser/common/basicSQL';
66
import fs from 'fs';
77

88
export type BenchmarkResult = {
@@ -38,25 +38,32 @@ const tableColumns = [
3838
},
3939
{
4040
name: 'loopTimes',
41-
title: 'Loop',
41+
title: 'Loops',
4242
},
4343
{
4444
name: 'type',
4545
title: 'Type',
4646
},
4747
];
4848

49+
/**
50+
* Key is sql directory name, value is module export name.
51+
*/
4952
export const languageNameMap = {
5053
hive: 'HiveSQL',
5154
mysql: 'MySQL',
5255
plsql: 'PLSQL',
53-
flinksql: 'FlinkSQL',
56+
flink: 'FlinkSQL',
5457
spark: 'SparkSQL',
55-
pgsql: 'PostgresSQL',
56-
trinosql: 'TrinoSQL',
58+
postgresql: 'PostgreSQL',
59+
trino: 'TrinoSQL',
5760
impala: 'ImpalaSQL',
5861
};
5962

63+
export type Language = keyof typeof languageNameMap;
64+
65+
export const languages = Object.keys(languageNameMap) as Language[];
66+
6067
class SqlBenchmark {
6168
constructor(language: string) {
6269
this.language = language;
@@ -81,11 +88,11 @@ class SqlBenchmark {
8188
*
8289
* Due to the presence of ATN cache in antlr4, we will clear the module cache to ensure that each parser is brand new and with no cache.
8390
*/
84-
getSqlParser(): BasicParser {
91+
getSqlParser(): BasicSQL {
8592
const caches = Object.keys(require.cache);
8693
const cacheModules = [
87-
path.join(__dirname, `../src/parser/${this.language}.ts`),
8894
path.join(__dirname, `../src/parser/common/`),
95+
path.join(__dirname, `../src/parser/${this.language}/`),
8996
path.join(__dirname, `../src/lib/${this.language}/`),
9097
path.normalize(require.resolve('antlr4ng')),
9198
];
@@ -94,28 +101,34 @@ class SqlBenchmark {
94101
cacheModules.some((cacheModuleName) => moduleName.includes(cacheModuleName))
95102
)
96103
.forEach((moduleName) => delete require.cache[moduleName]);
97-
const Parser = require(path.join(__dirname, `../src/parser/${this.language}.ts`)).default;
104+
const Parser = require(path.join(__dirname, `../src/parser/${this.language}/index.ts`))[
105+
languageNameMap[this.language]
106+
];
98107
return new Parser();
99108
}
100109

101110
/**
102111
* @param type Which parser method you want to run
103112
* @param name Benchmark name
104-
* @param sql SQL string
113+
* @param params Parser method parameters
114+
* @param params Rows count of sql
105115
* @param loopTimes Loop times, default run 3 times
106116
*/
107-
run(type: string, name: string, sql: string, loopTimes: number = this._DEFAULT_LOOP_TIMES) {
117+
run(
118+
type: string,
119+
name: string,
120+
params: any[],
121+
sqlRows: number,
122+
loopTimes: number = this._DEFAULT_LOOP_TIMES
123+
) {
108124
const costTimes: number[] = [];
109125
const lastResult =
110126
this._lastResultsCache?.find((item) => item.type === type && item.name === name) ?? {};
111-
const rows = sql.split('\n').length;
112-
113127
for (let i = 0; i < loopTimes; i++) {
114128
const parser = this.getSqlParser();
115129
if (!parser[type] || typeof parser[type] !== 'function') return;
116-
117130
const startTime = performance.now();
118-
parser[type](sql);
131+
parser[type](...params);
119132
const costTime = performance.now() - startTime;
120133

121134
costTimes.push(Math.round(costTime));
@@ -128,7 +141,7 @@ class SqlBenchmark {
128141
lastCostTime: lastResult['avgTime'],
129142
costTimes,
130143
loopTimes,
131-
rows,
144+
rows: sqlRows,
132145
type,
133146
};
134147

Diff for: scripts/benchmark.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ const argv = require('yargs-parser')(process.argv.slice(2));
55
const inquirer = require('inquirer');
66
const chalk = require('chalk');
77

8-
const outputPath = path.resolve(__dirname, '../src/grammar');
9-
10-
const languageEntries = fs.readdirSync(outputPath);
8+
const outputPath = path.resolve(__dirname, '../src/lib');
9+
const languages = fs.readdirSync(outputPath).filter((item) => {
10+
return fs.statSync(path.join(outputPath, item)).isDirectory();
11+
});
1112

1213
const cmd = 'tsx';
1314

@@ -28,7 +29,7 @@ function prompt() {
2829
type: 'list',
2930
name: 'language',
3031
message: 'Which language you want to run benchmark (or all languages)',
31-
choices: ['All Languages', ...languageEntries],
32+
choices: ['All Languages', ...languages],
3233
loop: true,
3334
},
3435
])
@@ -39,7 +40,7 @@ function prompt() {
3940

4041
function main() {
4142
if (argv.lang) {
42-
const supportedLanguage = languageEntries.some((language) => language === argv.lang);
43+
const supportedLanguage = languages.some((language) => language === argv.lang);
4344
if (supportedLanguage || argv.lang === 'All Languages') {
4445
runBenchmark(argv.lang);
4546
} else {

0 commit comments

Comments
 (0)