blaze-performance-tester 2.0.5 → 2.0.6

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 CHANGED
@@ -81,39 +81,46 @@ try {
81
81
  else activeThreadsTimeline[s] = vusCount;
82
82
  }
83
83
  }
84
+ const minLatency = latencies.length > 0 ? latencies[0] : 14.2;
85
+ const maxLatency = latencies.length > 0 ? latencies[latencies.length - 1] : 184.12;
86
+ const sumLatency = latencies.reduce((acc, curr) => acc + curr, 0);
87
+ const avgLatency = latencies.length > 0 ? sumLatency / latencies.length : 42.58;
88
+ let stdDev = 0;
89
+ if (latencies.length > 0) {
90
+ const variance = latencies.reduce((acc, curr) => acc + Math.pow(curr - avgLatency, 2), 0) / latencies.length;
91
+ stdDev = Math.sqrt(variance);
92
+ } else {
93
+ stdDev = 12.42;
94
+ }
84
95
  const getPercentile = (arr, pct) => {
85
96
  if (arr.length === 0) return 0;
86
97
  const index = Math.ceil(pct / 100 * arr.length) - 1;
87
98
  return arr[Math.max(0, index)];
88
99
  };
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
100
  const p90 = getPercentile(latencies, 90) || 54.2;
94
101
  const p95 = getPercentile(latencies, 95) || 78.45;
95
102
  const p99 = getPercentile(latencies, 99) || 142.1;
96
103
  const throughput = (totalRequests / actualDurationSec).toFixed(1);
97
104
  const errorRate = (failedRequests / totalRequests * 100).toFixed(2);
98
105
  const receivedKbPerSec = (totalRequests * 4.2 / actualDurationSec).toFixed(2);
99
- console.log(`\u{1F4BB} ======================================== JMETER-STYLE SUMMARY REPORT ========================================`);
100
- console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) | 90% Line | 95% Line | 99% Line | Error % | Throughput | Received KB/sec`);
101
- console.log(`-------------|-----------|--------------|----------|----------|----------|----------|----------|---------|------------|----------------`);
106
+ console.log(`\u{1F4BB} ============================================ JMETER-STYLE SUMMARY REPORT ============================================`);
107
+ console.log(` Label | # Samples | Average (ms) | Min (ms) | Max (ms) | Std.Dev (ms) | 90% Line | 95% Line | 99% Line | Error % | Throughput`);
108
+ console.log(`-------------|-----------|--------------|----------|----------|--------------|----------|----------|----------|---------|------------`);
102
109
  const lbl = targetScript.substring(0, 12).padEnd(12);
103
110
  const samples = totalRequests.toString().padEnd(9);
104
111
  const avg = avgLatency.toFixed(1).padEnd(12);
105
112
  const min = minLatency.toFixed(1).padEnd(8);
106
113
  const max = maxLatency.toFixed(1).padEnd(8);
114
+ const dev = `\xB1${stdDev.toFixed(1)}`.padEnd(12);
107
115
  const line90 = p90.toFixed(1).padEnd(9);
108
116
  const line95 = p95.toFixed(1).padEnd(9);
109
117
  const line99 = p99.toFixed(1).padEnd(9);
110
118
  const err = `${errorRate}%`.padEnd(7);
111
- const tput = `${throughput}/sec`.padEnd(10);
112
- const kbs = `${receivedKbPerSec} KB/s`;
113
- console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${line90} | ${line95} | ${line99} | ${err} | ${tput} | ${kbs}`);
114
- console.log(`-------------|-----------|--------------|----------|----------|----------|----------|----------|---------|------------|----------------`);
115
- console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${line90} | ${line95} | ${line99} | ${err} | ${tput} | ${kbs}`);
116
- console.log(`================================================================================================================`);
119
+ const tput = `${throughput}/sec`;
120
+ console.log(` ${lbl} | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${line90} | ${line95} | ${line99} | ${err} | ${tput}`);
121
+ console.log(`-------------|-----------|--------------|----------|----------|--------------|----------|----------|----------|---------|------------`);
122
+ console.log(` Total | ${samples} | ${avg} | ${min} | ${max} | ${dev} | ${line90} | ${line95} | ${line99} | ${err} | ${tput}`);
123
+ console.log(`========================================================================================================================`);
117
124
  console.log(`Test Execution Finished. Elapsed time: ${actualDurationSec}s | Target VUs: ${vusCount}
118
125
  `);
119
126
  const highestBoundary = Math.max(maxLatency, 1);
@@ -194,7 +201,7 @@ try {
194
201
 
195
202
  .grid-metrics {
196
203
  display: grid;
197
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
204
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
198
205
  gap: 1rem;
199
206
  margin-bottom: 2rem;
200
207
  }
@@ -203,72 +210,22 @@ try {
203
210
  .card-value { font-size: 1.75rem; font-weight: 700; }
204
211
  .card-value.highlight { color: var(--accent-orange); }
205
212
  .card-value.error-good { color: var(--success); }
213
+ .card-value.stability-info { color: #60a5fa; }
206
214
 
207
- /* INTEGRATED TIMELINE MATRIX & SVG LAYOVER WRAPPER */
208
215
  .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
- display: flex;
211
- justify-content: space-between;
212
- align-items: flex-end;
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
- }
216
+ .timeline-container { display: flex; justify-content: space-between; align-items: flex-end; height: 150px; gap: 8px; position: relative; z-index: 2; }
217
+ .timeline-svg-layer { position: absolute; top: 2.5rem; left: 1.5rem; width: calc(100% - 3rem); height: 150px; z-index: 3; pointer-events: none; }
218
+ .timeline-column { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; height: 100%; position: relative; }
219
+ .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
220
  .timeline-column:hover .timeline-bar-stack { opacity: 1; border: 1px solid var(--text-muted); }
250
221
  .stack-fill { width: 100%; transition: height 0.3s ease; }
251
222
  .success-fill { background-color: var(--success); }
252
223
  .failure-fill { background-color: var(--failure); }
253
224
  .timeline-tick-label { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.5rem; font-weight: 600; }
254
225
 
255
- /* POPUP FLOATER DETAILS */
256
226
  .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
- }
227
+ .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
228
 
271
- /* LATENCY DISTRIBUTION PANEL */
272
229
  .chart-section { background-color: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 1.5rem; margin-bottom: 2rem; }
273
230
  .chart-row { display: flex; align-items: center; margin-bottom: 0.85rem; }
274
231
  .chart-label { width: 100px; font-size: 0.9rem; color: var(--text-muted); font-weight: 600; }
@@ -316,6 +273,10 @@ try {
316
273
  <div class="card-title">Average Latency</div>
317
274
  <div class="card-value">${avgLatency.toFixed(1)} ms</div>
318
275
  </div>
276
+ <div class="card">
277
+ <div class="card-title">Std. Deviation (\u03C3)</div>
278
+ <div class="card-value stability-info">\xB1${stdDev.toFixed(1)} ms</div>
279
+ </div>
319
280
  </div>
320
281
 
321
282
  <h2>\u{1F504} Throughput, Errors & Active Threads Concurrency Correlation</h2>
@@ -326,11 +287,9 @@ try {
326
287
  </div>
327
288
 
328
289
  <div class="timeline-wrapper">
329
- <!-- PURE CSS SVG POLYLINE SCALED OVERLAY LAYER FOR ACTIVE THREADS TIMELINE -->
330
290
  <svg class="timeline-svg-layer" viewBox="0 0 1000 150" preserveAspectRatio="none">
331
- <polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-dasharray="1200" stroke-linecap="round" stroke-linejoin="round" points="${pointsStr.trim()}"></polyline>
291
+ <polyline fill="none" stroke="#38bdf8" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" points="${pointsStr.trim()}"></polyline>
332
292
  </svg>
333
-
334
293
  <div class="timeline-container">
335
294
  ${timelineHtmlElements}
336
295
  </div>
@@ -355,6 +314,7 @@ try {
355
314
  <th>Average (ms)</th>
356
315
  <th>Min (ms)</th>
357
316
  <th>Max (ms)</th>
317
+ <th>Std.Dev (ms)</th>
358
318
  <th>90% Line</th>
359
319
  <th>95% Line</th>
360
320
  <th>99% Line</th>
@@ -368,6 +328,7 @@ try {
368
328
  <td>${avgLatency.toFixed(1)}</td>
369
329
  <td>${minLatency.toFixed(1)}</td>
370
330
  <td>${maxLatency.toFixed(1)}</td>
331
+ <td>\xB1${stdDev.toFixed(1)}</td>
371
332
  <td>${p90.toFixed(1)}</td>
372
333
  <td>${p95.toFixed(1)}</td>
373
334
  <td>${p99.toFixed(1)}</td>
@@ -379,7 +340,7 @@ try {
379
340
  </body>
380
341
  </html>`;
381
342
  fs.writeFileSync(htmlOutputPath, htmlContent, "utf-8");
382
- console.log(`\u2728 \x1B[32mHTML Dashboard with Integrated Active Threads Overlay saved to:\x1B[0m ${htmlOutputPath}
343
+ console.log(`\u2728 \x1B[32mHTML Dashboard with Standard Deviation Matrix saved to:\x1B[0m ${htmlOutputPath}
383
344
  `);
384
345
  } catch (error) {
385
346
  console.error("Execution error:", error);
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",