blaze-performance-tester 3.1.15 → 3.1.17
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 +25 -68
- package/dist/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -147,7 +147,6 @@ function parseArguments(args) {
|
|
|
147
147
|
let maxThreads = 300;
|
|
148
148
|
let maxAllowedLatencyMs = 800;
|
|
149
149
|
let outputHtml = "blaze-dashboard.html";
|
|
150
|
-
let apdexT = 50;
|
|
151
150
|
const threadsIdx = args.indexOf("--threads");
|
|
152
151
|
if (threadsIdx !== -1) threads = parseInt(args[threadsIdx + 1], 10);
|
|
153
152
|
const durationIdx = args.indexOf("--duration");
|
|
@@ -160,8 +159,6 @@ function parseArguments(args) {
|
|
|
160
159
|
if (maxThreadsIdx !== -1) maxThreads = parseInt(args[maxThreadsIdx + 1], 10);
|
|
161
160
|
const outputIdx = args.indexOf("--output");
|
|
162
161
|
if (outputIdx !== -1) outputHtml = args[outputIdx + 1];
|
|
163
|
-
const apdexTIdx = args.indexOf("--apdex-t");
|
|
164
|
-
if (apdexTIdx !== -1) apdexT = parseFloat(args[apdexTIdx + 1]);
|
|
165
162
|
const positionalNums = args.slice(1).filter((arg) => !arg.startsWith("-")).map(Number).filter((n) => !isNaN(n));
|
|
166
163
|
if (positionalNums.length > 0 && threadsIdx === -1 && !isAgentic) threads = positionalNums[0];
|
|
167
164
|
if (positionalNums.length > 1 && durationIdx === -1 && !isAgentic) durationSec = positionalNums[1];
|
|
@@ -192,8 +189,7 @@ function parseArguments(args) {
|
|
|
192
189
|
maxThreads,
|
|
193
190
|
stepSize: 15,
|
|
194
191
|
maxAllowedLatencyMs,
|
|
195
|
-
outputHtml
|
|
196
|
-
apdexT
|
|
192
|
+
outputHtml
|
|
197
193
|
};
|
|
198
194
|
}
|
|
199
195
|
async function runBlazeCoreEngine(config) {
|
|
@@ -211,7 +207,7 @@ async function runBlazeCoreEngine(config) {
|
|
|
211
207
|
}
|
|
212
208
|
const warmUpCutoff = Math.floor(rawRequests.length * 0.1);
|
|
213
209
|
const steadyStateRequests = rawRequests.slice(warmUpCutoff);
|
|
214
|
-
const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec
|
|
210
|
+
const metrics = processMetricsTelemetry(steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests, config.durationSec);
|
|
215
211
|
const rawErrors = rawRequests.filter((r) => r.errorMessage).map((r) => r.errorMessage);
|
|
216
212
|
resolve2({ metrics, rawErrors, rawRequests: steadyStateRequests.length > 0 ? steadyStateRequests : rawRequests });
|
|
217
213
|
}, 1e3);
|
|
@@ -223,7 +219,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
223
219
|
let aggregateErrorLogs = [];
|
|
224
220
|
let lastRawRequests = [];
|
|
225
221
|
let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
|
|
226
|
-
let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: []
|
|
222
|
+
let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [] };
|
|
227
223
|
let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
|
|
228
224
|
let baseStep = config.stepSize;
|
|
229
225
|
let isStable = true;
|
|
@@ -247,9 +243,6 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
247
243
|
globalMetricsAccumulator.ttfb.push(metrics.avgTtfbMs);
|
|
248
244
|
globalMetricsAccumulator.latencies.push(metrics.avgLatencyMs);
|
|
249
245
|
globalMetricsAccumulator.bandwidths.push(metrics.bandwidthMb);
|
|
250
|
-
globalMetricsAccumulator.lcp.push(metrics.lcpMs);
|
|
251
|
-
globalMetricsAccumulator.fid.push(metrics.fidMs);
|
|
252
|
-
globalMetricsAccumulator.cls.push(metrics.clsScore);
|
|
253
246
|
const currentState = {
|
|
254
247
|
threads: currentThreads,
|
|
255
248
|
avgLatency: metrics.avgLatencyMs,
|
|
@@ -258,10 +251,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
258
251
|
apdex: metrics.apdexScore,
|
|
259
252
|
throughput: metrics.requestsPerSecond,
|
|
260
253
|
successRequests: metrics.c2xx + metrics.c3xx,
|
|
261
|
-
failedRequests: metrics.c4xx + metrics.c5xx
|
|
262
|
-
lcp: metrics.lcpMs,
|
|
263
|
-
fid: metrics.fidMs,
|
|
264
|
-
cls: metrics.clsScore
|
|
254
|
+
failedRequests: metrics.c4xx + metrics.c5xx
|
|
265
255
|
};
|
|
266
256
|
printMatrixDashboard(metrics, currentThreads);
|
|
267
257
|
history.push(currentState);
|
|
@@ -315,10 +305,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
315
305
|
tls: mathUtils.mean(globalMetricsAccumulator.tls),
|
|
316
306
|
stdDev: mathUtils.stdDev(globalMetricsAccumulator.latencies, mathUtils.mean(globalMetricsAccumulator.latencies)),
|
|
317
307
|
saturationKneePoint: saturationKneePoint || history[history.length - 1]?.threads || 50,
|
|
318
|
-
vuRampUpVelocity
|
|
319
|
-
lcp: mathUtils.mean(globalMetricsAccumulator.lcp),
|
|
320
|
-
fid: mathUtils.mean(globalMetricsAccumulator.fid),
|
|
321
|
-
cls: mathUtils.mean(globalMetricsAccumulator.cls)
|
|
308
|
+
vuRampUpVelocity
|
|
322
309
|
};
|
|
323
310
|
generateFinalAgentReport(history);
|
|
324
311
|
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
|
|
@@ -335,10 +322,7 @@ async function runStandardStressTest(config) {
|
|
|
335
322
|
apdex: metrics.apdexScore,
|
|
336
323
|
throughput: metrics.requestsPerSecond,
|
|
337
324
|
successRequests: metrics.c2xx + metrics.c3xx,
|
|
338
|
-
failedRequests: metrics.c4xx + metrics.c5xx
|
|
339
|
-
lcp: metrics.lcpMs,
|
|
340
|
-
fid: metrics.fidMs,
|
|
341
|
-
cls: metrics.clsScore
|
|
325
|
+
failedRequests: metrics.c4xx + metrics.c5xx
|
|
342
326
|
}];
|
|
343
327
|
let semanticReport = null;
|
|
344
328
|
if (config.clusterLogs) {
|
|
@@ -357,10 +341,7 @@ async function runStandardStressTest(config) {
|
|
|
357
341
|
tls: metrics.avgTlsMs,
|
|
358
342
|
stdDev: metrics.stdDevMs,
|
|
359
343
|
saturationKneePoint: config.threads,
|
|
360
|
-
vuRampUpVelocity: config.threads / config.durationSec
|
|
361
|
-
lcp: metrics.lcpMs,
|
|
362
|
-
fid: metrics.fidMs,
|
|
363
|
-
cls: metrics.clsScore
|
|
344
|
+
vuRampUpVelocity: config.threads / config.durationSec
|
|
364
345
|
};
|
|
365
346
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
366
347
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
@@ -413,7 +394,7 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
|
|
|
413
394
|
}
|
|
414
395
|
return data.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
415
396
|
}
|
|
416
|
-
function processMetricsTelemetry(requests, durationSec
|
|
397
|
+
function processMetricsTelemetry(requests, durationSec) {
|
|
417
398
|
const totalRequests = requests.length;
|
|
418
399
|
const durations = requests.map((r) => r.durationMs);
|
|
419
400
|
const avgLatencyMs = mathUtils.mean(durations);
|
|
@@ -433,13 +414,11 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
|
|
|
433
414
|
});
|
|
434
415
|
const errorCount = c4xx + c5xx;
|
|
435
416
|
const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
|
|
436
|
-
const
|
|
437
|
-
const
|
|
417
|
+
const T = 50;
|
|
418
|
+
const satisfied = requests.filter((r) => r.durationMs <= T && r.statusCode < 400).length;
|
|
419
|
+
const tolerating = requests.filter((r) => r.durationMs > T && r.durationMs <= T * 4 && r.statusCode < 400).length;
|
|
438
420
|
const apdexScore = totalRequests === 0 ? 0 : (satisfied + tolerating / 2) / totalRequests;
|
|
439
421
|
const bandwidthMb = totalRequests * 1.2 / durationSec / 10;
|
|
440
|
-
const lcpMs = avgTtfbMs * 1.6 + (p95LatencyMs - avgLatencyMs) * 0.4;
|
|
441
|
-
const fidMs = Math.max(1.5, stdDevMs * 0.18 + errorRate * 60);
|
|
442
|
-
const clsScore = Math.min(0.5, errorRate * 0.25 + (avgLatencyMs > 400 ? 0.08 : 0.01));
|
|
443
422
|
return {
|
|
444
423
|
totalRequests,
|
|
445
424
|
requestsPerSecond: totalRequests / durationSec,
|
|
@@ -457,10 +436,7 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
|
|
|
457
436
|
avgTcpMs,
|
|
458
437
|
avgTlsMs,
|
|
459
438
|
avgTtfbMs,
|
|
460
|
-
bandwidthMb
|
|
461
|
-
lcpMs,
|
|
462
|
-
fidMs,
|
|
463
|
-
clsScore
|
|
439
|
+
bandwidthMb
|
|
464
440
|
};
|
|
465
441
|
}
|
|
466
442
|
function printMatrixDashboard(m, threads) {
|
|
@@ -470,8 +446,6 @@ function printMatrixDashboard(m, threads) {
|
|
|
470
446
|
console.log(`-----------------------------------------------------------------------------------------`);
|
|
471
447
|
console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
|
|
472
448
|
console.log(`-----------------------------------------------------------------------------------------`);
|
|
473
|
-
console.log(`| Simulated Web Vitals Equivalent -> LCP: ${m.lcpMs.toFixed(0)}ms | FID: ${m.fidMs.toFixed(1)}ms | CLS: ${m.clsScore.toFixed(3)} |`);
|
|
474
|
-
console.log(`-----------------------------------------------------------------------------------------`);
|
|
475
449
|
}
|
|
476
450
|
function generateFinalAgentReport(history) {
|
|
477
451
|
if (history.length === 0) return;
|
|
@@ -493,7 +467,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
493
467
|
const activeThreadsData = history.map((h) => h.threads);
|
|
494
468
|
const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
|
|
495
469
|
const waveListItems = history.map((h) => {
|
|
496
|
-
return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}
|
|
470
|
+
return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%</div>`;
|
|
497
471
|
}).join("");
|
|
498
472
|
const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
|
|
499
473
|
const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
|
|
@@ -503,12 +477,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
503
477
|
x: Number(((r.timestampMs - firstTimestamp) / 1e3).toFixed(2)),
|
|
504
478
|
y: Number(((r.dnsTimeMs || 0) + (r.tcpTimeMs || 0) + (r.tlsTimeMs || 0) + r.durationMs * 0.3).toFixed(1))
|
|
505
479
|
}));
|
|
506
|
-
const getLcpStatus = (val) => val <= 2500 ? { label: "Good", cls: "green" } : val <= 4e3 ? { label: "Needs Imp.", cls: "orange" } : { label: "Poor", cls: "badge-fail" };
|
|
507
|
-
const getFidStatus = (val) => val <= 100 ? { label: "Good", cls: "green" } : val <= 300 ? { label: "Needs Imp.", cls: "orange" } : { label: "Poor", cls: "badge-fail" };
|
|
508
|
-
const getClsStatus = (val) => val <= 0.1 ? { label: "Good", cls: "green" } : val <= 0.25 ? { label: "Needs Imp.", cls: "orange" } : { label: "Poor", cls: "badge-fail" };
|
|
509
|
-
const lcpStat = getLcpStatus(cards.lcp);
|
|
510
|
-
const fidStat = getFidStatus(cards.fid);
|
|
511
|
-
const clsStat = getClsStatus(cards.cls);
|
|
512
480
|
let logClustersHtml = "";
|
|
513
481
|
if (semanticReport) {
|
|
514
482
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
@@ -635,7 +603,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
635
603
|
h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
|
|
636
604
|
.meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
|
|
637
605
|
|
|
638
|
-
.section-title { font-size: 1.2rem; color: #cbd5e1; font-weight: bold; margin: 2rem 0 1rem 0; padding-bottom: 0.4rem; border-bottom: 1px solid #1e293b; }
|
|
639
606
|
.cards-wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
|
|
640
607
|
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
641
608
|
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
@@ -645,9 +612,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
645
612
|
.card-value.orange { color: #f97316; }
|
|
646
613
|
.card-value.purple { color: #a855f7; }
|
|
647
614
|
.card-value.cyan { color: #38bdf8; }
|
|
648
|
-
.card-subtext { font-size: 0.8rem; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
649
|
-
.card-subtext.green { color: #10b981; }
|
|
650
|
-
.card-subtext.orange { color: #f97316; }
|
|
615
|
+
.card-subtext { font-size: 0.8rem; color: #10b981; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
|
|
651
616
|
|
|
652
617
|
.top-layout-grid { display: grid; grid-template-columns: 1fr 400px; gap: 1.5rem; margin-bottom: 2rem; }
|
|
653
618
|
.verdict-box { background: #0f172a; border: 1px dashed #ea580c; border-radius: 8px; padding: 1.25rem; }
|
|
@@ -688,11 +653,10 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
688
653
|
<div class="meta">Target Script: <code>${config.targetScript}</code></div>
|
|
689
654
|
</div>
|
|
690
655
|
|
|
691
|
-
<div class="section-title">\u{1F4CA} Core Server Metrics & Apdex Verification</div>
|
|
692
656
|
<div class="cards-wrapper">
|
|
693
657
|
<div class="metric-card">
|
|
694
|
-
<div class="card-title">Apdex Score (T:
|
|
695
|
-
<div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext
|
|
658
|
+
<div class="card-title">Apdex Score (T: 50ms)</div>
|
|
659
|
+
<div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
|
|
696
660
|
</div>
|
|
697
661
|
<div class="metric-card">
|
|
698
662
|
<div class="card-title">Throughput</div>
|
|
@@ -711,28 +675,23 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
711
675
|
<div class="card-value cyan">${cards.vuRampUpVelocity.toFixed(1)}<span class="unit">VUs/s</span></div>
|
|
712
676
|
</div>
|
|
713
677
|
<div class="metric-card">
|
|
714
|
-
<div class="card-title">
|
|
715
|
-
<div class="card-value"
|
|
678
|
+
<div class="card-title">DNS Lookup</div>
|
|
679
|
+
<div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
|
|
716
680
|
</div>
|
|
717
|
-
</div>
|
|
718
|
-
|
|
719
|
-
<div class="section-title">\u{1F310} Simulated Browser Core Web Vitals Equivalent</div>
|
|
720
|
-
<div class="cards-wrapper">
|
|
721
681
|
<div class="metric-card">
|
|
722
|
-
<div class="card-title">
|
|
723
|
-
<div class="card-value">${cards.
|
|
682
|
+
<div class="card-title">TCP Connect</div>
|
|
683
|
+
<div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
|
|
724
684
|
</div>
|
|
725
685
|
<div class="metric-card">
|
|
726
|
-
<div class="card-title">
|
|
727
|
-
<div class="card-value">${cards.
|
|
686
|
+
<div class="card-title">TLS Handshake</div>
|
|
687
|
+
<div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
|
|
728
688
|
</div>
|
|
729
689
|
<div class="metric-card">
|
|
730
|
-
<div class="card-title">
|
|
731
|
-
<div class="card-value"
|
|
690
|
+
<div class="card-title">Stability (Std Dev)</div>
|
|
691
|
+
<div class="card-value">±${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
|
|
732
692
|
</div>
|
|
733
693
|
</div>
|
|
734
694
|
|
|
735
|
-
<div class="section-title">\u26A1 Diagnostic Breakdowns</div>
|
|
736
695
|
<div class="top-layout-grid">
|
|
737
696
|
<div class="verdict-box">
|
|
738
697
|
<div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
|
|
@@ -804,7 +763,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
804
763
|
<th>Throughput</th>
|
|
805
764
|
<th>Avg Latency</th>
|
|
806
765
|
<th>P95 Latency</th>
|
|
807
|
-
<th>Simulated LCP</th>
|
|
808
766
|
<th>Error Rate</th>
|
|
809
767
|
<th>Status</th>
|
|
810
768
|
</tr>
|
|
@@ -817,7 +775,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
817
775
|
<td>${h.throughput.toFixed(0)} req/sec</td>
|
|
818
776
|
<td>${h.avgLatency.toFixed(1)} ms</td>
|
|
819
777
|
<td>${h.p95Latency.toFixed(1)} ms</td>
|
|
820
|
-
<td>${h.lcp.toFixed(0)} ms</td>
|
|
821
778
|
<td>${(h.errorRate * 100).toFixed(2)}%</td>
|
|
822
779
|
<td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
|
|
823
780
|
</tr>`;
|
|
@@ -990,6 +947,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
990
947
|
function printUsage() {
|
|
991
948
|
console.log(`Blaze Core Performance Test CLI Engine
|
|
992
949
|
Options:
|
|
993
|
-
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate
|
|
950
|
+
--threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate`);
|
|
994
951
|
}
|
|
995
952
|
main().catch(console.error);
|
|
Binary file
|