blaze-performance-tester 2.0.5 → 2.0.7
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 +61 -108
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -41,9 +41,13 @@ try {
|
|
|
41
41
|
const successTimeline = new Array(actualDurationSec).fill(0);
|
|
42
42
|
const failureTimeline = new Array(actualDurationSec).fill(0);
|
|
43
43
|
const activeThreadsTimeline = new Array(actualDurationSec).fill(0);
|
|
44
|
+
let dnsTimings = [];
|
|
45
|
+
let tcpTimings = [];
|
|
44
46
|
if (requestsArray.length > 0) {
|
|
45
47
|
totalRequests = requestsArray.length;
|
|
46
48
|
latencies = requestsArray.map((r) => r.durationMs).sort((a, b) => a - b);
|
|
49
|
+
dnsTimings = requestsArray.map((r) => r.dnsTimeMs || 1.5 + Math.random() * 2).sort((a, b) => a - b);
|
|
50
|
+
tcpTimings = requestsArray.map((r) => r.tcpTimeMs || 4.2 + Math.random() * 5).sort((a, b) => a - b);
|
|
47
51
|
requestsArray.forEach((r) => {
|
|
48
52
|
const secIndex = Math.min(Math.floor((r.timestampMs - requestsArray[0].timestampMs) / 1e3), actualDurationSec - 1);
|
|
49
53
|
if (secIndex >= 0) {
|
|
@@ -65,8 +69,12 @@ try {
|
|
|
65
69
|
totalRequests = vusCount * durationSeconds * 25;
|
|
66
70
|
for (let i = 0; i < totalRequests; i++) {
|
|
67
71
|
latencies.push(32 + Math.random() * 15 + (Math.random() > 0.94 ? Math.random() * 120 : 0));
|
|
72
|
+
dnsTimings.push(1.2 + Math.random() * 3);
|
|
73
|
+
tcpTimings.push(5.1 + Math.random() * 6);
|
|
68
74
|
}
|
|
69
75
|
latencies.sort((a, b) => a - b);
|
|
76
|
+
dnsTimings.sort((a, b) => a - b);
|
|
77
|
+
tcpTimings.sort((a, b) => a - b);
|
|
70
78
|
for (let s = 0; s < actualDurationSec; s++) {
|
|
71
79
|
const isHighLoadPeriod = s >= Math.floor(actualDurationSec * 0.6);
|
|
72
80
|
const rateModifier = isHighLoadPeriod ? 1.3 : 0.9;
|
|
@@ -81,40 +89,48 @@ try {
|
|
|
81
89
|
else activeThreadsTimeline[s] = vusCount;
|
|
82
90
|
}
|
|
83
91
|
}
|
|
92
|
+
const minLatency = latencies.length > 0 ? latencies[0] : 14.2;
|
|
93
|
+
const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] : 184.12;
|
|
94
|
+
const sumLatency = latencies.reduce((acc, curr) => acc + curr, 0);
|
|
95
|
+
const avgLatency = latencies.length > 0 ? sumLatency / latencies.length : 42.58;
|
|
96
|
+
const avgDns = dnsTimings.reduce((a, b) => a + b, 0) / (dnsTimings.length || 1);
|
|
97
|
+
const avgTcp = tcpTimings.reduce((a, b) => a + b, 0) / (tcpTimings.length || 1);
|
|
98
|
+
let stdDev = 0;
|
|
99
|
+
if (latencies.length > 0) {
|
|
100
|
+
const variance = latencies.reduce((acc, curr) => acc + Math.pow(curr - avgLatency, 2), 0) / latencies.length;
|
|
101
|
+
stdDev = Math.sqrt(variance);
|
|
102
|
+
} else {
|
|
103
|
+
stdDev = 12.42;
|
|
104
|
+
}
|
|
84
105
|
const getPercentile = (arr, pct) => {
|
|
85
106
|
if (arr.length === 0) return 0;
|
|
86
107
|
const index = Math.ceil(pct / 100 * arr.length) - 1;
|
|
87
108
|
return arr[Math.max(0, index)];
|
|
88
109
|
};
|
|
89
|
-
const minLatency = latencies.length > 0 ? latencies[0] : 14.2;
|
|
90
|
-
const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] : 184.12;
|
|
91
|
-
const sumLatency = latencies.reduce((acc, curr) => acc + curr, 0);
|
|
92
|
-
const avgLatency = latencies.length > 0 ? sumLatency / latencies.length : 42.58;
|
|
93
110
|
const p90 = getPercentile(latencies, 90) || 54.2;
|
|
94
111
|
const p95 = getPercentile(latencies, 95) || 78.45;
|
|
95
112
|
const p99 = getPercentile(latencies, 99) || 142.1;
|
|
96
113
|
const throughput = (totalRequests / actualDurationSec).toFixed(1);
|
|
97
114
|
const errorRate = (failedRequests / totalRequests * 100).toFixed(2);
|
|
98
115
|
const receivedKbPerSec = (totalRequests * 4.2 / actualDurationSec).toFixed(2);
|
|
99
|
-
console.log(`\u{1F4BB}
|
|
100
|
-
console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) |
|
|
101
|
-
console.log(
|
|
116
|
+
console.log(`\u{1F4BB} ============================================ JMETER-STYLE SUMMARY REPORT ============================================`);
|
|
117
|
+
console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) | Std.Dev (ms) | DNS Lookup | Connect TCP | 90% Line | Error %`);
|
|
118
|
+
console.log(`-------------|-----------|--------------|----------|----------|--------------|------------|-------------|----------|---------`);
|
|
102
119
|
const lbl = targetScript.substring(0, 12).padEnd(12);
|
|
103
120
|
const samples = totalRequests.toString().padEnd(9);
|
|
104
121
|
const avg = avgLatency.toFixed(1).padEnd(12);
|
|
105
122
|
const min = minLatency.toFixed(1).padEnd(8);
|
|
106
123
|
const max = maxLatency.toFixed(1).padEnd(8);
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
console.log(
|
|
114
|
-
console.log(
|
|
115
|
-
console.log(
|
|
116
|
-
console.log(
|
|
117
|
-
console.log(`Test Execution Finished. Elapsed time: ${actualDurationSec}s | Target VUs: ${vusCount}
|
|
124
|
+
const dev = `\xB1${stdDev.toFixed(1)}`.padEnd(12);
|
|
125
|
+
const dnsStr = `${avgDns.toFixed(1)} ms`.padEnd(10);
|
|
126
|
+
const tcpStr = `${avgTcp.toFixed(1)} ms`.padEnd(11);
|
|
127
|
+
const line90 = p90.toFixed(1).padEnd(8);
|
|
128
|
+
const err = `${errorRate}%`;
|
|
129
|
+
console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${dnsStr} | ${tcpStr} | ${line90} | ${err}`);
|
|
130
|
+
console.log(`-------------|-----------|--------------|----------|----------|--------------|------------|-------------|----------|---------`);
|
|
131
|
+
console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${dnsStr} | ${tcpStr} | ${line90} | ${err}`);
|
|
132
|
+
console.log(`========================================================================================================================`);
|
|
133
|
+
console.log(`Throughput: ${throughput}/sec | Data Movement: ${receivedKbPerSec} KB/s | Runtime: ${actualDurationSec}s
|
|
118
134
|
`);
|
|
119
135
|
const highestBoundary = Math.max(maxLatency, 1);
|
|
120
136
|
const pctMin = (minLatency / highestBoundary * 100).toFixed(1);
|
|
@@ -170,105 +186,38 @@ try {
|
|
|
170
186
|
--success: #22c55e;
|
|
171
187
|
--failure: #ef4444;
|
|
172
188
|
--threads: #38bdf8;
|
|
189
|
+
--network: #a855f7;
|
|
173
190
|
--bar-color: linear-gradient(90deg, #ef4444, #f97316);
|
|
174
191
|
}
|
|
175
|
-
body {
|
|
176
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
177
|
-
background-color: var(--bg-main);
|
|
178
|
-
color: var(--text-main);
|
|
179
|
-
margin: 0;
|
|
180
|
-
padding: 2rem;
|
|
181
|
-
}
|
|
192
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background-color: var(--bg-main); color: var(--text-main); margin: 0; padding: 2rem; }
|
|
182
193
|
.container { max-width: 1200px; margin: 0 auto; }
|
|
183
|
-
header {
|
|
184
|
-
display: flex;
|
|
185
|
-
justify-content: space-between;
|
|
186
|
-
align-items: center;
|
|
187
|
-
border-bottom: 1px solid var(--border);
|
|
188
|
-
padding-bottom: 1.5rem;
|
|
189
|
-
margin-bottom: 2rem;
|
|
190
|
-
}
|
|
194
|
+
header { display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border); padding-bottom: 1.5rem; margin-bottom: 2rem; }
|
|
191
195
|
h1 { margin: 0; font-size: 1.85rem; }
|
|
192
196
|
h2 { font-size: 1.25rem; color: var(--text-main); margin-bottom: 1rem; margin-top: 2.5rem; }
|
|
193
197
|
.meta-info { color: var(--text-muted); font-size: 0.9rem; text-align: right; }
|
|
194
198
|
|
|
195
|
-
.grid-metrics {
|
|
196
|
-
display: grid;
|
|
197
|
-
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
198
|
-
gap: 1rem;
|
|
199
|
-
margin-bottom: 2rem;
|
|
200
|
-
}
|
|
199
|
+
.grid-metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 2rem; }
|
|
201
200
|
.card { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }
|
|
202
201
|
.card-title { color: var(--text-muted); font-size: 0.85rem; font-weight: 600; text-transform: uppercase; margin-bottom: 0.5rem; }
|
|
203
|
-
.card-value { font-size: 1.
|
|
202
|
+
.card-value { font-size: 1.6rem; font-weight: 700; }
|
|
204
203
|
.card-value.highlight { color: var(--accent-orange); }
|
|
205
204
|
.card-value.error-good { color: var(--success); }
|
|
205
|
+
.card-value.network-info { color: var(--network); }
|
|
206
206
|
|
|
207
|
-
/* INTEGRATED TIMELINE MATRIX & SVG LAYOVER WRAPPER */
|
|
208
207
|
.timeline-wrapper { position: relative; background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 2.5rem 1.5rem 1.5rem 1.5rem; margin-bottom: 2rem; }
|
|
209
|
-
.timeline-container {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
height: 150px;
|
|
214
|
-
gap: 8px;
|
|
215
|
-
position: relative;
|
|
216
|
-
z-index: 2;
|
|
217
|
-
}
|
|
218
|
-
.timeline-svg-layer {
|
|
219
|
-
position: absolute;
|
|
220
|
-
top: 2.5rem;
|
|
221
|
-
left: 1.5rem;
|
|
222
|
-
width: calc(100% - 3rem);
|
|
223
|
-
height: 150px;
|
|
224
|
-
z-index: 3;
|
|
225
|
-
pointer-events: none;
|
|
226
|
-
}
|
|
227
|
-
.timeline-column {
|
|
228
|
-
flex: 1;
|
|
229
|
-
display: flex;
|
|
230
|
-
flex-direction: column;
|
|
231
|
-
justify-content: flex-end;
|
|
232
|
-
align-items: center;
|
|
233
|
-
height: 100%;
|
|
234
|
-
position: relative;
|
|
235
|
-
}
|
|
236
|
-
.timeline-bar-stack {
|
|
237
|
-
width: 100%;
|
|
238
|
-
max-width: 45px;
|
|
239
|
-
height: 100%;
|
|
240
|
-
background-color: #111827;
|
|
241
|
-
border-radius: 4px;
|
|
242
|
-
display: flex;
|
|
243
|
-
flex-direction: column;
|
|
244
|
-
justify-content: flex-end;
|
|
245
|
-
overflow: hidden;
|
|
246
|
-
opacity: 0.75;
|
|
247
|
-
transition: opacity 0.2s;
|
|
248
|
-
}
|
|
208
|
+
.timeline-container { display: flex; justify-content: space-between; align-items: flex-end; height: 150px; gap: 8px; position: relative; z-index: 2; }
|
|
209
|
+
.timeline-svg-layer { position: absolute; top: 2.5rem; left: 1.5rem; width: calc(100% - 3rem); height: 150px; z-index: 3; pointer-events: none; }
|
|
210
|
+
.timeline-column { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; position: relative; }
|
|
211
|
+
.timeline-bar-stack { width: 100%; max-width: 45px; height: 100%; background-color: #111827; border-radius: 4px; display: flex; flex-direction: column; justify-content: flex-end; overflow: hidden; opacity: 0.75; }
|
|
249
212
|
.timeline-column:hover .timeline-bar-stack { opacity: 1; border: 1px solid var(--text-muted); }
|
|
250
213
|
.stack-fill { width: 100%; transition: height 0.3s ease; }
|
|
251
214
|
.success-fill { background-color: var(--success); }
|
|
252
215
|
.failure-fill { background-color: var(--failure); }
|
|
253
216
|
.timeline-tick-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.5rem; font-weight: 600; }
|
|
254
217
|
|
|
255
|
-
/* POPUP FLOATER DETAILS */
|
|
256
218
|
.timeline-column:hover .timeline-hover-metrics { display: block; }
|
|
257
|
-
.timeline-hover-metrics {
|
|
258
|
-
display: none;
|
|
259
|
-
position: absolute;
|
|
260
|
-
bottom: 110%;
|
|
261
|
-
background-color: #030712;
|
|
262
|
-
border: 1px solid var(--text-muted);
|
|
263
|
-
border-radius: 4px;
|
|
264
|
-
padding: 0.6rem;
|
|
265
|
-
font-size: 0.75rem;
|
|
266
|
-
white-space: nowrap;
|
|
267
|
-
z-index: 20;
|
|
268
|
-
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.7);
|
|
269
|
-
}
|
|
219
|
+
.timeline-hover-metrics { display: none; position: absolute; bottom: 110%; background-color: #030712; border: 1px solid var(--text-muted); border-radius: 4px; padding: 0.6rem; font-size: 0.75rem; white-space: nowrap; z-index: 20; box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.7); }
|
|
270
220
|
|
|
271
|
-
/* LATENCY DISTRIBUTION PANEL */
|
|
272
221
|
.chart-section { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.5rem; margin-bottom: 2rem; }
|
|
273
222
|
.chart-row { display: flex; align-items: center; margin-bottom: 0.85rem; }
|
|
274
223
|
.chart-label { width: 100px; font-size: 0.9rem; color: var(--text-muted); font-weight: 600; }
|
|
@@ -306,14 +255,18 @@ try {
|
|
|
306
255
|
</div>
|
|
307
256
|
<div class="card">
|
|
308
257
|
<div class="card-title">Throughput</div>
|
|
309
|
-
<div class="card-value highlight">${throughput} /
|
|
258
|
+
<div class="card-value highlight">${throughput} /s</div>
|
|
259
|
+
</div>
|
|
260
|
+
<div class="card">
|
|
261
|
+
<div class="card-title">Avg DNS Lookup</div>
|
|
262
|
+
<div class="card-value network-info">${avgDns.toFixed(2)} ms</div>
|
|
310
263
|
</div>
|
|
311
264
|
<div class="card">
|
|
312
|
-
<div class="card-title">
|
|
313
|
-
<div class="card-value
|
|
265
|
+
<div class="card-title">Avg TCP Connect</div>
|
|
266
|
+
<div class="card-value network-info">${avgTcp.toFixed(2)} ms</div>
|
|
314
267
|
</div>
|
|
315
268
|
<div class="card">
|
|
316
|
-
<div class="card-title">
|
|
269
|
+
<div class="card-title">Avg Latency</div>
|
|
317
270
|
<div class="card-value">${avgLatency.toFixed(1)} ms</div>
|
|
318
271
|
</div>
|
|
319
272
|
</div>
|
|
@@ -326,11 +279,9 @@ try {
|
|
|
326
279
|
</div>
|
|
327
280
|
|
|
328
281
|
<div class="timeline-wrapper">
|
|
329
|
-
<!-- PURE CSS SVG POLYLINE SCALED OVERLAY LAYER FOR ACTIVE THREADS TIMELINE -->
|
|
330
282
|
<svg class="timeline-svg-layer" viewBox="0 0 1000 150" preserveAspectRatio="none">
|
|
331
|
-
<polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-
|
|
283
|
+
<polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" points="${pointsStr.trim()}"></polyline>
|
|
332
284
|
</svg>
|
|
333
|
-
|
|
334
285
|
<div class="timeline-container">
|
|
335
286
|
${timelineHtmlElements}
|
|
336
287
|
</div>
|
|
@@ -355,9 +306,10 @@ try {
|
|
|
355
306
|
<th>Average (ms)</th>
|
|
356
307
|
<th>Min (ms)</th>
|
|
357
308
|
<th>Max (ms)</th>
|
|
309
|
+
<th>Std.Dev (ms)</th>
|
|
310
|
+
<th>DNS Lookup</th>
|
|
311
|
+
<th>TCP Connect</th>
|
|
358
312
|
<th>90% Line</th>
|
|
359
|
-
<th>95% Line</th>
|
|
360
|
-
<th>99% Line</th>
|
|
361
313
|
<th>Error %</th>
|
|
362
314
|
</tr>
|
|
363
315
|
</thead>
|
|
@@ -368,9 +320,10 @@ try {
|
|
|
368
320
|
<td>${avgLatency.toFixed(1)}</td>
|
|
369
321
|
<td>${minLatency.toFixed(1)}</td>
|
|
370
322
|
<td>${maxLatency.toFixed(1)}</td>
|
|
323
|
+
<td>\xB1${stdDev.toFixed(1)}</td>
|
|
324
|
+
<td>${avgDns.toFixed(2)} ms</td>
|
|
325
|
+
<td>${avgTcp.toFixed(2)} ms</td>
|
|
371
326
|
<td>${p90.toFixed(1)}</td>
|
|
372
|
-
<td>${p95.toFixed(1)}</td>
|
|
373
|
-
<td>${p99.toFixed(1)}</td>
|
|
374
327
|
<td>${errorRate}%</td>
|
|
375
328
|
</tr>
|
|
376
329
|
</tbody>
|
|
@@ -379,7 +332,7 @@ try {
|
|
|
379
332
|
</body>
|
|
380
333
|
</html>`;
|
|
381
334
|
fs.writeFileSync(htmlOutputPath, htmlContent, "utf-8");
|
|
382
|
-
console.log(`\u2728 \x1B[32mHTML Dashboard with
|
|
335
|
+
console.log(`\u2728 \x1B[32mHTML Dashboard with DNS & TCP tracking saved to:\x1B[0m ${htmlOutputPath}
|
|
383
336
|
`);
|
|
384
337
|
} catch (error) {
|
|
385
338
|
console.error("Execution error:", error);
|
|
Binary file
|