Skip to content

Commit 253eb58

Browse files
SK-2375 update the perf code
1 parent 13ec048 commit 253eb58

14 files changed

Lines changed: 1926 additions & 37 deletions

File tree

load-testing/echo-server/EchoServer.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public static void main(String[] args) throws IOException {
5656
server.createContext("/v2/tokens/detokenize", new DetokenizeHandler());
5757
server.createContext("/metrics", new MetricsHandler());
5858
server.createContext("/health", new HealthHandler());
59-
server.setExecutor(Executors.newFixedThreadPool(200));
59+
// int echoThreads = defaultWaitMs > 0 ? 500 : 100;
60+
server.setExecutor(Executors.newFixedThreadPool(10));
6061
server.start();
6162

6263
System.out.printf("[EchoServer-v3] port=%d wait=%dms error_rate=%d%%%n",
@@ -104,6 +105,8 @@ public void handle(HttpExchange ex) throws IOException {
104105
.append("\"httpCode\":200}");
105106
}
106107
sb.append("]}");
108+
// add logs here
109+
System.out.println("Insert call received with record count: " + count);
107110
sendJson(ex, 200, sb.toString());
108111

109112
} catch (InterruptedException e) {

load-testing/k6/insert-fixed.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* K6 Fixed-Iteration Load Test: skyflow.vault().bulkInsert() [v3 SDK]
3+
*
4+
* Runs exactly TOTAL_REQUESTS iterations across all VUs, then stops.
5+
* RPS = total_requests / total_time_taken (no ramp-up/ramp-down noise)
6+
*
7+
* Run:
8+
* k6 run load-testing/k6/insert-fixed.js
9+
* k6 run --env TOTAL_REQUESTS=100000 --env VUS=200 load-testing/k6/insert-fixed.js
10+
*
11+
* Env vars:
12+
* WRAPPER_URL default: http://localhost:8080
13+
* VUS virtual users default: 100
14+
* TOTAL_REQUESTS total SDK calls default: 100000
15+
* NUM_RECORDS records per call default: 1
16+
* TABLE vault table default: load_test_table
17+
*/
18+
19+
import http from 'k6/http';
20+
import { check } from 'k6';
21+
import { Rate, Trend } from 'k6/metrics';
22+
23+
const BASE_URL = __ENV.WRAPPER_URL || 'http://localhost:8080';
24+
const VUS = parseInt(__ENV.VUS || '100');
25+
const TOTAL_REQUESTS = parseInt(__ENV.TOTAL_REQUESTS || '100000');
26+
const NUM_RECORDS = parseInt(__ENV.NUM_RECORDS || '1');
27+
const TABLE = __ENV.TABLE || 'load_test_table';
28+
29+
const errorRate = new Rate('insert_errors');
30+
const sdkDuration = new Trend('insert_sdk_duration_ms', true);
31+
32+
export const options = {
33+
vus: VUS,
34+
iterations: TOTAL_REQUESTS, // k6 stops exactly after this many calls
35+
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(50)', 'p(90)', 'p(95)', 'p(99)'],
36+
};
37+
38+
export default function () {
39+
const res = http.post(
40+
`${BASE_URL}/insert`,
41+
JSON.stringify({ table: TABLE, num_records: NUM_RECORDS }),
42+
{ headers: { 'Content-Type': 'application/json' } }
43+
);
44+
45+
const ok = check(res, {
46+
'status 200': (r) => r.status === 200,
47+
});
48+
49+
errorRate.add(!ok);
50+
sdkDuration.add(res.timings.duration);
51+
}
52+
53+
export function setup() {
54+
http.post(`${BASE_URL}/reset`); // clear counters so RPS is correct for this run
55+
}
56+
57+
export function teardown() {
58+
const res = http.get(`${BASE_URL}/metrics`);
59+
if (res.status === 200) console.log('[WrapperMetrics]', res.body);
60+
}
61+
62+
export function handleSummary(data) {
63+
const reqs = data.metrics['http_reqs'];
64+
const dur = data.metrics['http_req_duration'];
65+
const failed = data.metrics['http_req_failed'];
66+
const sdkDur = data.metrics['insert_sdk_duration_ms'];
67+
68+
const totalReqs = reqs?.values?.count ?? 0;
69+
const testDurationMs = data?.state?.testRunDurationMs ?? 0;
70+
const testDurationSec = (testDurationMs / 1000).toFixed(3);
71+
72+
// RPS = total_requests / total_time_taken (what the user asked for)
73+
const rpsRaw = totalReqs > 0 && testDurationMs > 0
74+
? totalReqs / (testDurationMs / 1000)
75+
: 0;
76+
const rps = rpsRaw.toFixed(2);
77+
78+
// k6's own rate (same formula, shown for cross-check)
79+
const k6RateRaw = reqs?.values?.rate ?? 0;
80+
const k6Rate = k6RateRaw.toFixed(2);
81+
82+
// Delta between the two — should be <5% if both are correct.
83+
// Divergence happens because testRunDurationMs includes teardown() time.
84+
const delta = Math.abs(rpsRaw - k6RateRaw);
85+
const deltaPct = k6RateRaw > 0 ? ((delta / k6RateRaw) * 100).toFixed(1) : '0.0';
86+
const match = parseFloat(deltaPct) < 5 ? 'OK (within 5%)' : 'WARN (>5% gap — check teardown latency)';
87+
88+
const p50 = (dur?.values?.['p(50)'] ?? 0).toFixed(1);
89+
const p95 = (dur?.values?.['p(95)'] ?? 0).toFixed(1);
90+
const p99 = (dur?.values?.['p(99)'] ?? 0).toFixed(1);
91+
const avgMs = (dur?.values?.avg ?? 0).toFixed(1);
92+
const minMs = (dur?.values?.min ?? 0).toFixed(1);
93+
const maxMs = (dur?.values?.max ?? 0).toFixed(1);
94+
const errRate = ((failed?.values?.rate ?? 0) * 100).toFixed(2);
95+
const sdkP50 = (sdkDur?.values?.['p(50)'] ?? 0).toFixed(1);
96+
const sdkP95 = (sdkDur?.values?.['p(95)'] ?? 0).toFixed(1);
97+
const sdkP99 = (sdkDur?.values?.['p(99)'] ?? 0).toFixed(1);
98+
99+
const summary = `
100+
╔══════════════════════════════════════════════════╗
101+
║ FIXED-ITERATION INSERT SUMMARY ║
102+
╠══════════════════════════════════════════════════╣
103+
║ Config ║
104+
║ VUs : ${String(VUS).padStart(24)}
105+
║ Target requests : ${String(TOTAL_REQUESTS).padStart(24)}
106+
║ Completed : ${String(totalReqs).padStart(24)}
107+
║ Test duration : ${(testDurationSec + 's').padStart(24)}
108+
╠══════════════════════════════════════════════════╣
109+
║ Throughput ║
110+
║ RPS (total/time) : ${String(rps).padStart(24)}
111+
║ RPS (k6 rate) : ${String(k6Rate).padStart(24)}
112+
║ Delta : ${(delta.toFixed(2) + ' (' + deltaPct + '%)').padStart(24)}
113+
║ Verdict : ${String(match).padStart(24)}
114+
║ Error rate : ${(errRate + '%').padStart(24)}
115+
╠══════════════════════════════════════════════════╣
116+
║ HTTP round-trip latency (ms) ║
117+
║ min : ${String(minMs).padStart(24)}
118+
║ avg : ${String(avgMs).padStart(24)}
119+
║ p50 : ${String(p50).padStart(24)}
120+
║ p95 : ${String(p95).padStart(24)}
121+
║ p99 : ${String(p99).padStart(24)}
122+
║ max : ${String(maxMs).padStart(24)}
123+
╠══════════════════════════════════════════════════╣
124+
║ SDK duration (ms) ║
125+
║ p50 : ${String(sdkP50).padStart(24)}
126+
║ p95 : ${String(sdkP95).padStart(24)}
127+
║ p99 : ${String(sdkP99).padStart(24)}
128+
╚══════════════════════════════════════════════════╝
129+
`;
130+
console.log(summary);
131+
return { stdout: summary };
132+
}

load-testing/k6/insert.js

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { Rate, Trend } from 'k6/metrics';
2121

2222
const BASE_URL = __ENV.WRAPPER_URL || 'http://localhost:8080';
2323
const VUS = parseInt(__ENV.VUS || '50');
24-
const DURATION = parseInt(__ENV.DURATION || '120');
24+
const DURATION = Math.max(61, parseInt(__ENV.DURATION || '120')); // must be > 60 (30s ramp-up + 30s ramp-down)
2525
const NUM_RECORDS = parseInt(__ENV.NUM_RECORDS || '1');
2626
const TABLE = __ENV.TABLE || 'load_test_table';
2727

@@ -40,6 +40,7 @@ export const options = {
4040
'insert_errors': ['rate<0.01'],
4141
'insert_sdk_duration_ms': ['p(95)<400'],
4242
},
43+
summaryTrendStats: ['avg', 'min', 'med', 'max', 'p(50)', 'p(90)', 'p(95)', 'p(99)'],
4344
};
4445

4546
export default function () {
@@ -63,7 +64,68 @@ export default function () {
6364
sdkDuration.add(res.timings.duration);
6465
}
6566

66-
export function teardown() {
67-
const res = http.get(`${BASE_URL}/metrics`);
68-
if (res.status === 200) console.log('[WrapperMetrics]', res.body);
67+
// setup() runs once before any VU starts.
68+
// Resets WrapperServer counters and records the exact start time.
69+
// Return value is passed as `data` into teardown().
70+
export function setup() {
71+
http.post(`${BASE_URL}/reset`);
72+
return { startTimeMs: Date.now() };
73+
}
74+
75+
// teardown(data) runs once after all VUs finish.
76+
// data.startTimeMs = timestamp from setup() — no ramp-up/teardown noise.
77+
// RPS = total completed requests / (now - startTimeMs)
78+
export function teardown(data) {
79+
const endTimeMs = Date.now();
80+
const elapsedSec = (endTimeMs - data.startTimeMs) / 1000;
81+
82+
const metricsRes = http.get(`${BASE_URL}/metrics`);
83+
if (metricsRes.status !== 200) {
84+
console.log('[teardown] Could not fetch metrics');
85+
return;
86+
}
87+
88+
const m = JSON.parse(metricsRes.body);
89+
const totalReqs = m.insert.total;
90+
const rps = (totalReqs / elapsedSec).toFixed(2);
91+
92+
console.log('[WrapperMetrics]', metricsRes.body);
93+
console.log(`[RPS] total=${totalReqs} elapsed=${elapsedSec.toFixed(1)}s rps=${rps}`);
94+
}
95+
96+
export function handleSummary(data) {
97+
const reqs = data.metrics['http_reqs'];
98+
const dur = data.metrics['http_req_duration'];
99+
const failed = data.metrics['http_req_failed'];
100+
const sdkDur = data.metrics['insert_sdk_duration_ms'];
101+
102+
const totalReqs = reqs?.values?.count ?? 0;
103+
const k6Rps = (reqs?.values?.rate ?? 0).toFixed(2);
104+
const p50 = (dur?.values?.['p(50)'] ?? 0).toFixed(1);
105+
const p95 = (dur?.values?.['p(95)'] ?? 0).toFixed(1);
106+
const p99 = (dur?.values?.['p(99)'] ?? 0).toFixed(1);
107+
const avgMs = (dur?.values?.avg ?? 0).toFixed(1);
108+
const errRate = ((failed?.values?.rate ?? 0) * 100).toFixed(2);
109+
const sdkP95 = (sdkDur?.values?.['p(95)'] ?? 0).toFixed(1);
110+
111+
const summary = `
112+
╔══════════════════════════════════════════╗
113+
║ K6 INSERT SUMMARY ║
114+
╠══════════════════════════════════════════╣
115+
║ Total requests : ${String(totalReqs).padStart(20)}
116+
║ RPS (k6 rate) : ${String(k6Rps).padStart(20)}
117+
║ Error rate : ${(errRate + '%').padStart(20)}
118+
╠══════════════════════════════════════════╣
119+
║ HTTP latency (ms) ║
120+
║ avg : ${String(avgMs).padStart(20)}
121+
║ p50 : ${String(p50).padStart(20)}
122+
║ p95 : ${String(p95).padStart(20)}
123+
║ p99 : ${String(p99).padStart(20)}
124+
╠══════════════════════════════════════════╣
125+
║ SDK duration p95 (ms) ║
126+
║ p95 : ${String(sdkP95).padStart(20)}
127+
╚══════════════════════════════════════════╝
128+
`;
129+
console.log(summary);
130+
return { stdout: summary };
69131
}

0 commit comments

Comments
 (0)