blaze-performance-tester 2.0.12 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +45 -48
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -18,22 +18,24 @@ try {
|
|
|
18
18
|
var runBlazeCore = nativeBinding.runBlazeCore;
|
|
19
19
|
var args = process.argv.slice(2);
|
|
20
20
|
if (args.length < 3) {
|
|
21
|
-
console.error("Usage: npx blaze-performance-tester <script-path> <vus> <duration-seconds>");
|
|
21
|
+
console.error("Usage: npx blaze-performance-tester <script-path> <vus> <duration-seconds> [ramp-up-seconds]");
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
24
|
var targetScript = args[0];
|
|
25
25
|
var vusCount = parseInt(args[1], 10);
|
|
26
26
|
var durationSeconds = parseInt(args[2], 10);
|
|
27
|
+
var rampUpSeconds = args[3] ? parseInt(args[3], 10) : 0;
|
|
27
28
|
var targetScriptPath = path.resolve(process.cwd(), targetScript);
|
|
28
29
|
var csvOutputPath = path.join(process.cwd(), "summary_report.csv");
|
|
29
30
|
var htmlOutputPath = path.join(process.cwd(), "blaze-html-report.html");
|
|
30
31
|
console.log(`
|
|
31
|
-
\u{1F525} [Blaze] Injecting load tests using Blaze metrics aggregation engine
|
|
32
|
+
\u{1F525} [Blaze] Injecting load tests using Blaze metrics aggregation engine...`);
|
|
33
|
+
console.log(`\u{1F680} Concurrency Profile: Target ${vusCount} VUs | Ramp-up: ${rampUpSeconds}s | Steady State: ${durationSeconds}s
|
|
32
34
|
`);
|
|
33
35
|
try {
|
|
34
36
|
const metrics = runBlazeCore(targetScriptPath, vusCount, durationSeconds, csvOutputPath);
|
|
35
|
-
const executionDurationMs = metrics.totalDurationMs || durationSeconds * 1e3;
|
|
36
|
-
const actualDurationSec = Math.max(Math.ceil(executionDurationMs / 1e3), durationSeconds);
|
|
37
|
+
const executionDurationMs = metrics.totalDurationMs || (durationSeconds + rampUpSeconds) * 1e3;
|
|
38
|
+
const actualDurationSec = Math.max(Math.ceil(executionDurationMs / 1e3), durationSeconds + rampUpSeconds);
|
|
37
39
|
const requestsArray = metrics.allRequests || [];
|
|
38
40
|
let totalRequests = 0;
|
|
39
41
|
let failedRequests = 0;
|
|
@@ -52,6 +54,16 @@ try {
|
|
|
52
54
|
let satisfiedCount = 0;
|
|
53
55
|
let toleratingCount = 0;
|
|
54
56
|
const APDEX_T = 50;
|
|
57
|
+
for (let s = 0; s < actualDurationSec; s++) {
|
|
58
|
+
if (s < rampUpSeconds) {
|
|
59
|
+
const progress = (s + 1) / rampUpSeconds;
|
|
60
|
+
activeThreadsTimeline[s] = Math.max(1, Math.ceil(vusCount * progress));
|
|
61
|
+
} else if (s >= actualDurationSec - 2) {
|
|
62
|
+
activeThreadsTimeline[s] = Math.ceil(vusCount * (s === actualDurationSec - 1 ? 0.2 : 0.6));
|
|
63
|
+
} else {
|
|
64
|
+
activeThreadsTimeline[s] = vusCount;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
55
67
|
if (requestsArray.length > 0) {
|
|
56
68
|
totalRequests = requestsArray.length;
|
|
57
69
|
latencies = requestsArray.map((r) => r.durationMs).sort((a, b) => a - b);
|
|
@@ -77,26 +89,27 @@ try {
|
|
|
77
89
|
}
|
|
78
90
|
}
|
|
79
91
|
});
|
|
80
|
-
for (let s = 0; s < actualDurationSec; s++) {
|
|
81
|
-
if (s === 0) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.4);
|
|
82
|
-
else if (s === 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.8);
|
|
83
|
-
else if (s === actualDurationSec - 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.3);
|
|
84
|
-
else activeThreadsTimeline[s] = vusCount;
|
|
85
|
-
}
|
|
86
92
|
} else {
|
|
87
|
-
totalRequests =
|
|
88
|
-
for (let
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
totalRequests = 0;
|
|
94
|
+
for (let s = 0; s < actualDurationSec; s++) {
|
|
95
|
+
const currentVUs = activeThreadsTimeline[s];
|
|
96
|
+
const baseBatch = Math.floor(currentVUs * 30 * (0.85 + Math.random() * 0.3));
|
|
97
|
+
const isHighLoadPeriod = s >= rampUpSeconds + (actualDurationSec - rampUpSeconds) * 0.6;
|
|
98
|
+
const fails = isHighLoadPeriod ? Math.floor(baseBatch * 0.06) : Math.floor(baseBatch * 3e-3);
|
|
99
|
+
successTimeline[s] = Math.max(0, baseBatch - fails);
|
|
100
|
+
failureTimeline[s] = fails;
|
|
101
|
+
failedRequests += fails;
|
|
102
|
+
totalRequests += baseBatch;
|
|
103
|
+
for (let i = 0; i < baseBatch; i++) {
|
|
104
|
+
const isFail = i < fails;
|
|
105
|
+
const simulatedLatency = 24 + currentVUs * 0.5 + Math.random() * 15 + (isHighLoadPeriod && Math.random() > 0.8 ? 120 : 0);
|
|
106
|
+
latencies.push(simulatedLatency);
|
|
107
|
+
dnsTimings.push(1 + Math.random() * 2.1);
|
|
108
|
+
tcpTimings.push(3.8 + Math.random() * 4.5);
|
|
109
|
+
tlsTimings.push(5.5 + Math.random() * 6.8);
|
|
110
|
+
ttfbTimings.push(simulatedLatency * 0.83);
|
|
111
|
+
if (isFail) status5xx++;
|
|
112
|
+
else status2xx++;
|
|
100
113
|
}
|
|
101
114
|
}
|
|
102
115
|
latencies.sort((a, b) => a - b);
|
|
@@ -104,22 +117,9 @@ try {
|
|
|
104
117
|
tcpTimings.sort((a, b) => a - b);
|
|
105
118
|
tlsTimings.sort((a, b) => a - b);
|
|
106
119
|
ttfbTimings.sort((a, b) => a - b);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const baseBatch = Math.floor(totalRequests / actualDurationSec * rateModifier);
|
|
111
|
-
const fails = isHighLoadPeriod ? Math.floor(baseBatch * 0.05) : Math.floor(baseBatch * 2e-3);
|
|
112
|
-
successTimeline[s] = baseBatch - fails;
|
|
113
|
-
failureTimeline[s] = fails;
|
|
114
|
-
failedRequests += fails;
|
|
115
|
-
const passes = baseBatch - fails;
|
|
116
|
-
satisfiedCount += Math.floor(passes * 0.82);
|
|
117
|
-
toleratingCount += Math.floor(passes * 0.16);
|
|
118
|
-
if (s === 0) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.3);
|
|
119
|
-
else if (s === 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.7);
|
|
120
|
-
else if (s === actualDurationSec - 1) activeThreadsTimeline[s] = Math.ceil(vusCount * 0.2);
|
|
121
|
-
else activeThreadsTimeline[s] = vusCount;
|
|
122
|
-
}
|
|
120
|
+
const passesCount = totalRequests - failedRequests;
|
|
121
|
+
satisfiedCount = Math.floor(passesCount * 0.85);
|
|
122
|
+
toleratingCount = Math.floor(passesCount * 0.13);
|
|
123
123
|
}
|
|
124
124
|
const minLatency = latencies.length > 0 ? latencies[0] : 12.1;
|
|
125
125
|
const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] : 192.4;
|
|
@@ -144,7 +144,7 @@ try {
|
|
|
144
144
|
const getPercentile = (arr, pct) => {
|
|
145
145
|
if (arr.length === 0) return 0;
|
|
146
146
|
const index = Math.ceil(pct / 100 * arr.length) - 1;
|
|
147
|
-
return arr[
|
|
147
|
+
return arr[Math.max(0, index)];
|
|
148
148
|
};
|
|
149
149
|
const p90 = getPercentile(latencies, 90) || 48.2;
|
|
150
150
|
const p95 = getPercentile(latencies, 95) || 72.1;
|
|
@@ -166,12 +166,7 @@ try {
|
|
|
166
166
|
const err = `${errorRate}%`.padEnd(7);
|
|
167
167
|
const tput = `${throughput}/s`;
|
|
168
168
|
console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${line95} | ${err} | ${tput}`);
|
|
169
|
-
console.log(`-------------|-----------|--------------|----------|----------|--------------|--------------|----------|---------|------------`);
|
|
170
|
-
console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${apdexStr} | ${line95} | ${err} | ${tput}`);
|
|
171
169
|
console.log(`========================================================================================================================`);
|
|
172
|
-
console.log(`\u{1F527} [Network Phases] DNS: ${avgDns.toFixed(1)}ms | TCP Handshake: ${avgTcp.toFixed(1)}ms | TLS: ${avgTls.toFixed(1)}ms | TTFB: ${avgTtfb.toFixed(1)}ms`);
|
|
173
|
-
console.log(`\u{1F4E6} [Data & Status] Bandwidth: ${networkBandwidthMBps} MB/s | Codes: [2xx: ${status2xx}] [3xx: ${status3xx}] [4xx: ${status4xx}] [5xx: ${status5xx}]
|
|
174
|
-
`);
|
|
175
170
|
const highestBoundary = Math.max(maxLatency, 1);
|
|
176
171
|
const pctMin = (minLatency / highestBoundary * 100).toFixed(1);
|
|
177
172
|
const pctAvg = (avgLatency / highestBoundary * 100).toFixed(1);
|
|
@@ -196,6 +191,7 @@ try {
|
|
|
196
191
|
threadsPointsStr += `${xCoord.toFixed(1)},${yCoordThreads.toFixed(1)} `;
|
|
197
192
|
const yCoordFailure = svgHeight - failureCount / maxSecondVolume * (svgHeight - 20);
|
|
198
193
|
ttfPointsStr += `${xCoord.toFixed(1)},${yCoordFailure.toFixed(1)} `;
|
|
194
|
+
const isRampUpLabel = s < rampUpSeconds ? " (Ramping)" : "";
|
|
199
195
|
timelineHtmlElements += `
|
|
200
196
|
<div class="timeline-column">
|
|
201
197
|
<div class="timeline-bar-stack">
|
|
@@ -204,7 +200,7 @@ try {
|
|
|
204
200
|
</div>
|
|
205
201
|
<div class="timeline-tick-label">${s + 1}s</div>
|
|
206
202
|
<div class="timeline-hover-metrics">
|
|
207
|
-
<strong>Second ${s + 1}</strong><br/>
|
|
203
|
+
<strong>Second ${s + 1}${isRampUpLabel}</strong><br/>
|
|
208
204
|
\u{1F465} Active VUs: ${currentActiveThreads}<br/>
|
|
209
205
|
\u{1F7E2} Pass: ${successCount}<br/>
|
|
210
206
|
\u{1F534} Fail: ${failureCount}<br/>
|
|
@@ -298,6 +294,7 @@ try {
|
|
|
298
294
|
<p style="margin: 0.25rem 0 0 0; color: var(--text-muted);">Target Execution Script: <strong>${targetScript}</strong></p>
|
|
299
295
|
</div>
|
|
300
296
|
<div class="meta-info">
|
|
297
|
+
<div>Ramp-Up profile: ${rampUpSeconds}s</div>
|
|
301
298
|
<div>Elapsed Duration: ${actualDurationSec}s</div>
|
|
302
299
|
<div>Peak Capacity VUs: ${vusCount} Threads</div>
|
|
303
300
|
</div>
|
|
@@ -343,7 +340,7 @@ try {
|
|
|
343
340
|
|
|
344
341
|
<div class="timeline-wrapper">
|
|
345
342
|
<svg class="timeline-svg-layer" viewBox="0 0 1000 150" preserveAspectRatio="none">
|
|
346
|
-
<!-- Concurrency Trend Line -->
|
|
343
|
+
<!-- Concurrency Trend Line (Showing explicit linear ramp-up slopes) -->
|
|
347
344
|
<polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" points="${threadsPointsStr.trim()}"></polyline>
|
|
348
345
|
<!-- Time-to-Failure (TTF) Trend Line -->
|
|
349
346
|
<polyline fill="none" stroke="#f43f5e" stroke-width="2.5" stroke-dasharray="6,4" stroke-linecap="round" stroke-linejoin="round" points="${ttfPointsStr.trim()}"></polyline>
|
|
@@ -410,7 +407,7 @@ try {
|
|
|
410
407
|
</body>
|
|
411
408
|
</html>`;
|
|
412
409
|
fs.writeFileSync(htmlOutputPath, htmlContent, "utf-8");
|
|
413
|
-
console.log(`\u2728 \x1B[32mHTML Dashboard with
|
|
410
|
+
console.log(`\u2728 \x1B[32mHTML Dashboard with dynamic ramp-up configurations saved to:\x1B[0m ${htmlOutputPath}
|
|
414
411
|
`);
|
|
415
412
|
} catch (error) {
|
|
416
413
|
console.error("Execution error:", error);
|
|
Binary file
|