Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/cubejs-backend-native/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ index.node
**/node_modules
**/.DS_Store
npm-debug.log
benchmarks/result.txt
test/__pycache__/
112 changes: 112 additions & 0 deletions packages/cubejs-backend-native/benchmarks/fixtures/config-async.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from cube import config, file_repository

config.schema_path = "models"
config.pg_sql_port = 5555
config.telemetry = False


@config
async def query_rewrite(query, ctx):
# Removed print statements for benchmarking
return query


@config
async def check_auth(req, authorization):
# Removed print statements for benchmarking
return {
"security_context": {"sub": "1234567890", "iat": 1516239022, "user_id": 42},
"ignoredField": "should not be visible",
}


@config('extend_context')
async def extend_context(req):
# Removed print statements for benchmarking
if "securityContext" not in req:
return {
"security_context": {
"error": "missing",
}
}

req["securityContext"]["extended_by_config"] = True

return {
"security_context": req["securityContext"],
}


@config
async def repository_factory(ctx):
# Removed print statements for benchmarking
return file_repository(ctx["securityContext"]["schemaPath"])


@config
async def context_to_api_scopes():
# Removed print statements for benchmarking
return ["meta", "data", "jobs"]


@config
async def scheduled_refresh_time_zones(ctx):
# Removed print statements for benchmarking
return ["Europe/Kyiv", "Antarctica/Troll", "Australia/Sydney"]


@config
async def scheduled_refresh_contexts(ctx):
# Removed print statements for benchmarking
return [
{
"securityContext": {
"appid": 'test1', "u": { "prop1": "value1" }
}
},
{
"securityContext": {
"appid": 'test2', "u": { "prop1": "value2" }
}
},
{
"securityContext": {
"appid": 'test3', "u": { "prop1": "value3" }
}
},
]


@config
async def schema_version(ctx):
# Removed print statements for benchmarking
return "1"


@config
async def pre_aggregations_schema(ctx):
# Removed print statements for benchmarking
return "schema"


@config
async def logger(msg, params):
# Removed print statements for benchmarking
pass


@config
async def context_to_roles(ctx):
# Removed print statements for benchmarking
return [
"admin",
]


@config
async def context_to_groups(ctx):
# Removed print statements for benchmarking
return [
"dev",
"analytics",
]
112 changes: 112 additions & 0 deletions packages/cubejs-backend-native/benchmarks/fixtures/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from cube import config, file_repository

config.schema_path = "models"
config.pg_sql_port = 5555
config.telemetry = False


@config
def query_rewrite(query, ctx):
# Removed print statements for benchmarking
return query


@config
def check_auth(req, authorization):
# Removed print statements for benchmarking
return {
"security_context": {"sub": "1234567890", "iat": 1516239022, "user_id": 42},
"ignoredField": "should not be visible",
}


@config('extend_context')
def extend_context(req):
# Removed print statements for benchmarking
if "securityContext" not in req:
return {
"security_context": {
"error": "missing",
}
}

req["securityContext"]["extended_by_config"] = True

return {
"security_context": req["securityContext"],
}


@config
def repository_factory(ctx):
# Removed print statements for benchmarking
return file_repository(ctx["securityContext"]["schemaPath"])


@config
def context_to_api_scopes():
# Removed print statements for benchmarking
return ["meta", "data", "jobs"]


@config
def scheduled_refresh_time_zones(ctx):
# Removed print statements for benchmarking
return ["Europe/Kyiv", "Antarctica/Troll", "Australia/Sydney"]


@config
def scheduled_refresh_contexts(ctx):
# Removed print statements for benchmarking
return [
{
"securityContext": {
"appid": 'test1', "u": { "prop1": "value1" }
}
},
{
"securityContext": {
"appid": 'test2', "u": { "prop1": "value2" }
}
},
{
"securityContext": {
"appid": 'test3', "u": { "prop1": "value3" }
}
},
]


@config
def schema_version(ctx):
# Removed print statements for benchmarking
return "1"


@config
def pre_aggregations_schema(ctx):
# Removed print statements for benchmarking
return "schema"


@config
def logger(msg, params):
# Removed print statements for benchmarking
pass


@config
def context_to_roles(ctx):
# Removed print statements for benchmarking
return [
"admin",
]


@config
def context_to_groups(ctx):
# Removed print statements for benchmarking
return [
"dev",
"analytics",
]
122 changes: 122 additions & 0 deletions packages/cubejs-backend-native/benchmarks/python-config.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import fs from 'fs/promises';
import path from 'path';
import { benchmarkSuite } from 'jest-bench';

import * as native from '../js';
import { PyConfiguration } from '../js';

async function loadConfigurationFile(fileName: string): Promise<PyConfiguration> {
const fullFileName = path.join(process.cwd(), 'benchmarks', 'fixtures', fileName);
const content = await fs.readFile(fullFileName, 'utf8');

return native.pythonLoadConfig(content, {
fileName: fullFileName
});
}

// Global variables to hold loaded configs and test data
let configPy: PyConfiguration;
let configAsyncPy: PyConfiguration;
let configContent: string;
let configAsyncContent: string;

describe('Python Configuration Loading', () => {
beforeAll(async () => {
// Load file contents once for all benchmarks
const configPath = path.join(process.cwd(), 'benchmarks', 'fixtures', 'config.py');
const configAsyncPath = path.join(process.cwd(), 'benchmarks', 'fixtures', 'config-async.py');
const oldConfigPath = path.join(process.cwd(), 'test', 'old-config.py');

[configContent, configAsyncContent] = await Promise.all([
fs.readFile(configPath, 'utf8'),
fs.readFile(configAsyncPath, 'utf8'),
]);

// Pre-load configurations for function benchmarks
configPy = await loadConfigurationFile('config.py');
configAsyncPy = await loadConfigurationFile('config-async.py');
});

benchmarkSuite('Config Loading', {
'Load config.py': async () => {
const fullFileName = path.join(process.cwd(), 'benchmarks', 'fixtures', 'config.py');
await native.pythonLoadConfig(configContent, { fileName: fullFileName });
},

'Load config-async.py': async () => {
const fullFileName = path.join(process.cwd(), 'benchmarks', 'fixtures', 'config-async.py');
await native.pythonLoadConfig(configAsyncContent, { fileName: fullFileName });
}
});

benchmarkSuite('Data Conversion Performance', {
'Small payload (3 fields)': async () => {
const smallPayload = { simple_string: 'test', number: 42, boolean: true };
await configPy.queryRewrite!(smallPayload, {});
},

'Medium payload (100 users)': async () => {
const mediumPayload = {
users: Array.from({ length: 100 }, (_, i) => ({
id: i, name: `User ${i}`, active: i % 2 === 0
}))
};
await configPy.queryRewrite!(mediumPayload, {});
},

'Large payload (1000 items)': async () => {
const largePayload = {
data: Array.from({ length: 1000 }, (_, i) => ({
id: i, value: `Value ${i}`, nested: { prop: i * 2 }
}))
};
await configPy.queryRewrite!(largePayload, {});
}
});

benchmarkSuite('Function Execution', {
'checkAuth - sync version (sequential)': async () => {
await configPy.checkAuth!({ requestId: 'sync-bench' }, 'SYNC_TOKEN');
},

// It should help to identify any potential issues with GIL
'checkAuth - sync version (parallel 50x)': async () => {
await Promise.all(
Array.from({ length: 50 }, () => configPy.checkAuth!({ requestId: 'sync-bench' }, 'SYNC_TOKEN'))
);
},

'checkAuth - async version (sequential)': async () => {
await configAsyncPy.checkAuth!({ requestId: 'async-bench' }, 'ASYNC_TOKEN');
},

// It should help to identify any potential issues with GIL
'checkAuth - async version (parallel 50x)': async () => {
await Promise.all(
Array.from({ length: 50 }, () => configAsyncPy.checkAuth!({ requestId: 'async-bench' }, 'ASYNC_TOKEN'))
);
},

'extendContext - sync version': async () => {
await configPy.extendContext!({
securityContext: { sub: '1234567890', iat: 1516239022, user_id: 42 }
});
},

'extendContext - async version (sequential)': async () => {
await configAsyncPy.extendContext!({
securityContext: { sub: '1234567890', iat: 1516239022, user_id: 42 }
});
},

'queryRewrite - sync version': async () => {
const testQuery = { str: 'string', int_number: 1, bool_true: true };
await configPy.queryRewrite!(testQuery, {});
},

'queryRewrite - async version (sequential)': async () => {
const testQuery = { str: 'string', int_number: 1, bool_true: true };
await configAsyncPy.queryRewrite!(testQuery, {});
},
});
});
22 changes: 22 additions & 0 deletions packages/cubejs-backend-native/jest-bench.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const base = require('../../jest.base.config');

/** @type {import('jest').Config} */
module.exports = {
...base,
rootDir: '.',
testEnvironment: 'jest-bench/environment',
testEnvironmentOptions: {
testEnvironment: 'node',
testEnvironmentOptions: {}
},
// Include default reporter for error reporting alongside jest-bench reporter
reporters: ['default', 'jest-bench/reporter'],
// Pick up *.bench.ts files
testRegex: '\\.bench\\.(ts|tsx|js)$',
roots: [
'<rootDir>/dist/benchmarks/'
],
snapshotResolver: '<rootDir>/test/snapshotResolver.js',
// Coverage is not needed for benchmarks
collectCoverage: false
};
2 changes: 2 additions & 0 deletions packages/cubejs-backend-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"unit": "jest --forceExit",
"test:unit": "yarn run unit",
"test:cargo": "cargo test",
"bench": "jest --config jest-bench.config.js --forceExit",
"lint": "eslint test/ js/ --ext .ts",
"lint:fix": "eslint --fix test/ js/ --ext .ts"
},
Expand All @@ -39,6 +40,7 @@
"@types/node": "^20",
"cargo-cp-artifact": "^0.1.9",
"jest": "^29",
"jest-bench": "^29",
"pg": "^8.11.3",
"typescript": "~5.2.2",
"uuid": "^8.3.2"
Expand Down
Loading
Loading