@ruvector/edge-net 0.5.0 → 0.5.1
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/package.json +1 -1
- package/plugins/SECURITY-AUDIT.md +654 -0
- package/plugins/cli.js +43 -3
- package/plugins/implementations/e2e-encryption.js +57 -12
- package/plugins/plugin-loader.js +229 -21
- package/tests/plugin-benchmark.js +1239 -0
|
@@ -0,0 +1,1239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Edge-Net Plugin System Performance Benchmarks
|
|
4
|
+
*
|
|
5
|
+
* Comprehensive benchmarks measuring:
|
|
6
|
+
* - Plugin loading performance (cold/warm/bundle)
|
|
7
|
+
* - Plugin execution throughput
|
|
8
|
+
* - Sandbox overhead
|
|
9
|
+
* - Memory usage patterns
|
|
10
|
+
*
|
|
11
|
+
* Run: node tests/plugin-benchmark.js
|
|
12
|
+
*
|
|
13
|
+
* @module @ruvector/edge-net/tests/plugin-benchmark
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { performance } from 'perf_hooks';
|
|
17
|
+
import { PluginLoader, PluginManager } from '../plugins/plugin-loader.js';
|
|
18
|
+
import { CompressionPlugin } from '../plugins/implementations/compression.js';
|
|
19
|
+
import { E2EEncryptionPlugin } from '../plugins/implementations/e2e-encryption.js';
|
|
20
|
+
import { SwarmIntelligencePlugin } from '../plugins/implementations/swarm-intelligence.js';
|
|
21
|
+
import { FederatedLearningPlugin } from '../plugins/implementations/federated-learning.js';
|
|
22
|
+
import { ReputationStakingPlugin } from '../plugins/implementations/reputation-staking.js';
|
|
23
|
+
import { PLUGIN_CATALOG, PLUGIN_BUNDLES } from '../plugins/plugin-manifest.js';
|
|
24
|
+
|
|
25
|
+
// ============================================
|
|
26
|
+
// BENCHMARK CONFIGURATION
|
|
27
|
+
// ============================================
|
|
28
|
+
|
|
29
|
+
const CONFIG = {
|
|
30
|
+
// Iterations for statistical significance
|
|
31
|
+
warmupIterations: 10,
|
|
32
|
+
benchmarkIterations: 100,
|
|
33
|
+
|
|
34
|
+
// Data sizes for throughput tests
|
|
35
|
+
dataSizes: {
|
|
36
|
+
small: 1024, // 1 KB
|
|
37
|
+
medium: 65536, // 64 KB
|
|
38
|
+
large: 1048576, // 1 MB
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Swarm intelligence settings
|
|
42
|
+
swarm: {
|
|
43
|
+
populationSize: 50,
|
|
44
|
+
dimensions: 10,
|
|
45
|
+
iterations: 100,
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Federated learning settings
|
|
49
|
+
federated: {
|
|
50
|
+
localDataSize: 1000,
|
|
51
|
+
participants: 5,
|
|
52
|
+
epochs: 5,
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Reputation staking settings
|
|
56
|
+
staking: {
|
|
57
|
+
operations: 1000,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// Memory test settings
|
|
61
|
+
memoryOperations: 1000,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ============================================
|
|
65
|
+
// UTILITY FUNCTIONS
|
|
66
|
+
// ============================================
|
|
67
|
+
|
|
68
|
+
function formatBytes(bytes) {
|
|
69
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
70
|
+
if (bytes < 1048576) return `${(bytes / 1024).toFixed(2)} KB`;
|
|
71
|
+
return `${(bytes / 1048576).toFixed(2)} MB`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatNumber(num) {
|
|
75
|
+
if (num >= 1000000) return `${(num / 1000000).toFixed(2)}M`;
|
|
76
|
+
if (num >= 1000) return `${(num / 1000).toFixed(2)}K`;
|
|
77
|
+
return num.toFixed(2);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function generateRandomData(size) {
|
|
81
|
+
const buffer = Buffer.alloc(size);
|
|
82
|
+
for (let i = 0; i < size; i++) {
|
|
83
|
+
buffer[i] = Math.floor(Math.random() * 256);
|
|
84
|
+
}
|
|
85
|
+
return buffer;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function generateCompressibleData(size) {
|
|
89
|
+
// Data with repeating patterns (compresses well)
|
|
90
|
+
const buffer = Buffer.alloc(size);
|
|
91
|
+
const patterns = [0x00, 0xFF, 0xAA, 0x55];
|
|
92
|
+
for (let i = 0; i < size; i++) {
|
|
93
|
+
// Create runs of repeating bytes
|
|
94
|
+
const runLength = Math.floor(Math.random() * 32) + 4;
|
|
95
|
+
const pattern = patterns[Math.floor(Math.random() * patterns.length)];
|
|
96
|
+
for (let j = 0; j < runLength && i + j < size; j++) {
|
|
97
|
+
buffer[i + j] = pattern;
|
|
98
|
+
}
|
|
99
|
+
i += runLength - 1;
|
|
100
|
+
}
|
|
101
|
+
return buffer;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getMemoryUsage() {
|
|
105
|
+
const usage = process.memoryUsage();
|
|
106
|
+
return {
|
|
107
|
+
heapUsed: usage.heapUsed,
|
|
108
|
+
heapTotal: usage.heapTotal,
|
|
109
|
+
external: usage.external,
|
|
110
|
+
rss: usage.rss,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function calculateStats(times) {
|
|
115
|
+
const sorted = [...times].sort((a, b) => a - b);
|
|
116
|
+
const sum = sorted.reduce((a, b) => a + b, 0);
|
|
117
|
+
const mean = sum / sorted.length;
|
|
118
|
+
const variance = sorted.reduce((acc, t) => acc + Math.pow(t - mean, 2), 0) / sorted.length;
|
|
119
|
+
const stdDev = Math.sqrt(variance);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
mean,
|
|
123
|
+
median: sorted[Math.floor(sorted.length / 2)],
|
|
124
|
+
min: sorted[0],
|
|
125
|
+
max: sorted[sorted.length - 1],
|
|
126
|
+
stdDev,
|
|
127
|
+
p95: sorted[Math.floor(sorted.length * 0.95)],
|
|
128
|
+
p99: sorted[Math.floor(sorted.length * 0.99)],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ============================================
|
|
133
|
+
// BENCHMARK RESULTS COLLECTOR
|
|
134
|
+
// ============================================
|
|
135
|
+
|
|
136
|
+
class BenchmarkResults {
|
|
137
|
+
constructor() {
|
|
138
|
+
this.results = new Map();
|
|
139
|
+
this.startTime = Date.now();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
add(category, name, metrics) {
|
|
143
|
+
if (!this.results.has(category)) {
|
|
144
|
+
this.results.set(category, new Map());
|
|
145
|
+
}
|
|
146
|
+
this.results.get(category).set(name, metrics);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
generateReport() {
|
|
150
|
+
const report = {
|
|
151
|
+
timestamp: new Date().toISOString(),
|
|
152
|
+
duration: Date.now() - this.startTime,
|
|
153
|
+
nodeVersion: process.version,
|
|
154
|
+
platform: process.platform,
|
|
155
|
+
arch: process.arch,
|
|
156
|
+
categories: {},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
for (const [category, metrics] of this.results) {
|
|
160
|
+
report.categories[category] = {};
|
|
161
|
+
for (const [name, data] of metrics) {
|
|
162
|
+
report.categories[category][name] = data;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return report;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ============================================
|
|
171
|
+
// PLUGIN LOADING BENCHMARKS
|
|
172
|
+
// ============================================
|
|
173
|
+
|
|
174
|
+
async function benchmarkPluginLoading(results) {
|
|
175
|
+
console.log('\n--- Plugin Loading Performance ---\n');
|
|
176
|
+
|
|
177
|
+
// Cold load time (first load, no cache)
|
|
178
|
+
console.log('Testing cold load times...');
|
|
179
|
+
const coldLoadTimes = {};
|
|
180
|
+
|
|
181
|
+
for (const pluginId of Object.keys(PLUGIN_CATALOG)) {
|
|
182
|
+
PluginManager.reset();
|
|
183
|
+
const loader = PluginManager.getInstance({ verifySignatures: false });
|
|
184
|
+
|
|
185
|
+
global.gc?.(); // Force GC if available
|
|
186
|
+
|
|
187
|
+
const start = performance.now();
|
|
188
|
+
try {
|
|
189
|
+
await loader.load(pluginId);
|
|
190
|
+
coldLoadTimes[pluginId] = performance.now() - start;
|
|
191
|
+
} catch (e) {
|
|
192
|
+
coldLoadTimes[pluginId] = null; // Plugin not loadable
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Filter out null values and calculate stats
|
|
197
|
+
const validColdTimes = Object.values(coldLoadTimes).filter(t => t !== null);
|
|
198
|
+
results.add('Plugin Loading', 'Cold Load Times (ms)', coldLoadTimes);
|
|
199
|
+
results.add('Plugin Loading', 'Cold Load Stats', calculateStats(validColdTimes));
|
|
200
|
+
|
|
201
|
+
// Warm load time (already loaded/cached)
|
|
202
|
+
console.log('Testing warm load times...');
|
|
203
|
+
const warmLoadTimes = {};
|
|
204
|
+
|
|
205
|
+
for (const pluginId of Object.keys(PLUGIN_CATALOG)) {
|
|
206
|
+
const loader = PluginManager.getInstance();
|
|
207
|
+
const times = [];
|
|
208
|
+
|
|
209
|
+
for (let i = 0; i < CONFIG.warmupIterations; i++) {
|
|
210
|
+
const start = performance.now();
|
|
211
|
+
try {
|
|
212
|
+
await loader.load(pluginId); // Should return cached
|
|
213
|
+
times.push(performance.now() - start);
|
|
214
|
+
} catch (e) {
|
|
215
|
+
// Skip
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (times.length > 0) {
|
|
220
|
+
warmLoadTimes[pluginId] = calculateStats(times);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
results.add('Plugin Loading', 'Warm Load Times (ms)', warmLoadTimes);
|
|
225
|
+
|
|
226
|
+
// Bundle load time
|
|
227
|
+
console.log('Testing bundle load times...');
|
|
228
|
+
const bundleLoadTimes = {};
|
|
229
|
+
|
|
230
|
+
for (const bundleName of Object.keys(PLUGIN_BUNDLES)) {
|
|
231
|
+
PluginManager.reset();
|
|
232
|
+
const loader = PluginManager.getInstance({ verifySignatures: false });
|
|
233
|
+
|
|
234
|
+
global.gc?.();
|
|
235
|
+
|
|
236
|
+
const start = performance.now();
|
|
237
|
+
try {
|
|
238
|
+
await loader.loadBundle(bundleName);
|
|
239
|
+
bundleLoadTimes[bundleName] = performance.now() - start;
|
|
240
|
+
} catch (e) {
|
|
241
|
+
bundleLoadTimes[bundleName] = null;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
results.add('Plugin Loading', 'Bundle Load Times (ms)', bundleLoadTimes);
|
|
246
|
+
|
|
247
|
+
// Memory footprint per plugin
|
|
248
|
+
console.log('Measuring plugin memory footprint...');
|
|
249
|
+
const memoryFootprints = {};
|
|
250
|
+
|
|
251
|
+
for (const pluginId of Object.keys(PLUGIN_CATALOG)) {
|
|
252
|
+
PluginManager.reset();
|
|
253
|
+
global.gc?.();
|
|
254
|
+
|
|
255
|
+
const beforeMem = getMemoryUsage();
|
|
256
|
+
const loader = PluginManager.getInstance({ verifySignatures: false });
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
await loader.load(pluginId);
|
|
260
|
+
global.gc?.();
|
|
261
|
+
|
|
262
|
+
const afterMem = getMemoryUsage();
|
|
263
|
+
memoryFootprints[pluginId] = afterMem.heapUsed - beforeMem.heapUsed;
|
|
264
|
+
} catch (e) {
|
|
265
|
+
memoryFootprints[pluginId] = null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
results.add('Plugin Loading', 'Memory Footprint (bytes)', memoryFootprints);
|
|
270
|
+
|
|
271
|
+
console.log(' Cold load avg:', calculateStats(validColdTimes).mean.toFixed(3), 'ms');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ============================================
|
|
275
|
+
// COMPRESSION PLUGIN BENCHMARKS
|
|
276
|
+
// ============================================
|
|
277
|
+
|
|
278
|
+
async function benchmarkCompression(results) {
|
|
279
|
+
console.log('\n--- CompressionPlugin Performance ---\n');
|
|
280
|
+
|
|
281
|
+
const plugin = new CompressionPlugin({ threshold: 0 }); // Disable threshold
|
|
282
|
+
|
|
283
|
+
for (const [sizeName, size] of Object.entries(CONFIG.dataSizes)) {
|
|
284
|
+
console.log(`Testing ${sizeName} data (${formatBytes(size)})...`);
|
|
285
|
+
|
|
286
|
+
// Test with compressible data
|
|
287
|
+
const compressibleData = generateCompressibleData(size);
|
|
288
|
+
const randomData = generateRandomData(size);
|
|
289
|
+
|
|
290
|
+
// Compression throughput (compressible)
|
|
291
|
+
const compressTimes = [];
|
|
292
|
+
const compressedSizes = [];
|
|
293
|
+
|
|
294
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
295
|
+
const start = performance.now();
|
|
296
|
+
const result = plugin.compress(compressibleData);
|
|
297
|
+
compressTimes.push(performance.now() - start);
|
|
298
|
+
compressedSizes.push(result.compressedSize || compressibleData.length);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const compressStats = calculateStats(compressTimes);
|
|
302
|
+
const avgCompressedSize = compressedSizes.reduce((a, b) => a + b, 0) / compressedSizes.length;
|
|
303
|
+
const compressionRatio = avgCompressedSize / size;
|
|
304
|
+
const throughputMBs = (size / 1048576) / (compressStats.mean / 1000);
|
|
305
|
+
|
|
306
|
+
results.add('Compression', `${sizeName} Compress (compressible)`, {
|
|
307
|
+
throughputMBs: throughputMBs.toFixed(2),
|
|
308
|
+
avgTimeMs: compressStats.mean.toFixed(3),
|
|
309
|
+
p95Ms: compressStats.p95.toFixed(3),
|
|
310
|
+
compressionRatio: compressionRatio.toFixed(3),
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Decompression throughput
|
|
314
|
+
const compressedData = plugin.compress(compressibleData);
|
|
315
|
+
const decompressTimes = [];
|
|
316
|
+
|
|
317
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
318
|
+
const start = performance.now();
|
|
319
|
+
plugin.decompress(compressedData.data, compressedData.compressed);
|
|
320
|
+
decompressTimes.push(performance.now() - start);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const decompressStats = calculateStats(decompressTimes);
|
|
324
|
+
const decompressThroughput = (size / 1048576) / (decompressStats.mean / 1000);
|
|
325
|
+
|
|
326
|
+
results.add('Compression', `${sizeName} Decompress`, {
|
|
327
|
+
throughputMBs: decompressThroughput.toFixed(2),
|
|
328
|
+
avgTimeMs: decompressStats.mean.toFixed(3),
|
|
329
|
+
p95Ms: decompressStats.p95.toFixed(3),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// Random data (less compressible)
|
|
333
|
+
const randomCompressTimes = [];
|
|
334
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
335
|
+
const start = performance.now();
|
|
336
|
+
plugin.compress(randomData);
|
|
337
|
+
randomCompressTimes.push(performance.now() - start);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const randomCompressStats = calculateStats(randomCompressTimes);
|
|
341
|
+
results.add('Compression', `${sizeName} Compress (random)`, {
|
|
342
|
+
throughputMBs: ((size / 1048576) / (randomCompressStats.mean / 1000)).toFixed(2),
|
|
343
|
+
avgTimeMs: randomCompressStats.mean.toFixed(3),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
console.log(' Compression benchmarks complete');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ============================================
|
|
351
|
+
// E2E ENCRYPTION PLUGIN BENCHMARKS
|
|
352
|
+
// ============================================
|
|
353
|
+
|
|
354
|
+
async function benchmarkEncryption(results) {
|
|
355
|
+
console.log('\n--- E2EEncryptionPlugin Performance ---\n');
|
|
356
|
+
|
|
357
|
+
const plugin = new E2EEncryptionPlugin({ forwardSecrecy: false });
|
|
358
|
+
await plugin.init();
|
|
359
|
+
|
|
360
|
+
// Setup sessions
|
|
361
|
+
const peers = ['peer1', 'peer2', 'peer3', 'peer4', 'peer5'];
|
|
362
|
+
for (const peer of peers) {
|
|
363
|
+
await plugin.establishSession(peer, 'dummy-public-key');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
for (const [sizeName, size] of Object.entries(CONFIG.dataSizes)) {
|
|
367
|
+
console.log(`Testing ${sizeName} data (${formatBytes(size)})...`);
|
|
368
|
+
|
|
369
|
+
const testData = generateRandomData(size).toString('base64');
|
|
370
|
+
|
|
371
|
+
// Encryption ops/sec
|
|
372
|
+
const encryptTimes = [];
|
|
373
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
374
|
+
const peer = peers[i % peers.length];
|
|
375
|
+
const start = performance.now();
|
|
376
|
+
plugin.encrypt(peer, testData);
|
|
377
|
+
encryptTimes.push(performance.now() - start);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const encryptStats = calculateStats(encryptTimes);
|
|
381
|
+
const encryptOpsPerSec = 1000 / encryptStats.mean;
|
|
382
|
+
|
|
383
|
+
results.add('Encryption', `${sizeName} Encrypt`, {
|
|
384
|
+
opsPerSec: formatNumber(encryptOpsPerSec),
|
|
385
|
+
avgTimeMs: encryptStats.mean.toFixed(3),
|
|
386
|
+
p95Ms: encryptStats.p95.toFixed(3),
|
|
387
|
+
throughputMBs: ((size / 1048576) / (encryptStats.mean / 1000)).toFixed(2),
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Decryption ops/sec
|
|
391
|
+
const encrypted = plugin.encrypt('peer1', testData);
|
|
392
|
+
const decryptTimes = [];
|
|
393
|
+
|
|
394
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
395
|
+
const start = performance.now();
|
|
396
|
+
plugin.decrypt('peer1', encrypted);
|
|
397
|
+
decryptTimes.push(performance.now() - start);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const decryptStats = calculateStats(decryptTimes);
|
|
401
|
+
const decryptOpsPerSec = 1000 / decryptStats.mean;
|
|
402
|
+
|
|
403
|
+
results.add('Encryption', `${sizeName} Decrypt`, {
|
|
404
|
+
opsPerSec: formatNumber(decryptOpsPerSec),
|
|
405
|
+
avgTimeMs: decryptStats.mean.toFixed(3),
|
|
406
|
+
p95Ms: decryptStats.p95.toFixed(3),
|
|
407
|
+
throughputMBs: ((size / 1048576) / (decryptStats.mean / 1000)).toFixed(2),
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Session establishment overhead
|
|
412
|
+
console.log('Testing session establishment...');
|
|
413
|
+
const sessionTimes = [];
|
|
414
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
415
|
+
const start = performance.now();
|
|
416
|
+
await plugin.establishSession(`test-peer-${i}`, 'dummy-key');
|
|
417
|
+
sessionTimes.push(performance.now() - start);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const sessionStats = calculateStats(sessionTimes);
|
|
421
|
+
results.add('Encryption', 'Session Establishment', {
|
|
422
|
+
opsPerSec: formatNumber(1000 / sessionStats.mean),
|
|
423
|
+
avgTimeMs: sessionStats.mean.toFixed(3),
|
|
424
|
+
p95Ms: sessionStats.p95.toFixed(3),
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
await plugin.destroy();
|
|
428
|
+
console.log(' Encryption benchmarks complete');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ============================================
|
|
432
|
+
// SWARM INTELLIGENCE PLUGIN BENCHMARKS
|
|
433
|
+
// ============================================
|
|
434
|
+
|
|
435
|
+
async function benchmarkSwarmIntelligence(results) {
|
|
436
|
+
console.log('\n--- SwarmIntelligencePlugin Performance ---\n');
|
|
437
|
+
|
|
438
|
+
const algorithms = ['pso', 'ga', 'de', 'aco'];
|
|
439
|
+
|
|
440
|
+
for (const algorithm of algorithms) {
|
|
441
|
+
console.log(`Testing ${algorithm.toUpperCase()} algorithm...`);
|
|
442
|
+
|
|
443
|
+
const plugin = new SwarmIntelligencePlugin({
|
|
444
|
+
algorithm,
|
|
445
|
+
populationSize: CONFIG.swarm.populationSize,
|
|
446
|
+
iterations: CONFIG.swarm.iterations,
|
|
447
|
+
dimensions: CONFIG.swarm.dimensions,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Single step performance
|
|
451
|
+
const stepTimes = [];
|
|
452
|
+
const swarm = plugin.createSwarm('bench-swarm', {
|
|
453
|
+
algorithm,
|
|
454
|
+
dimensions: CONFIG.swarm.dimensions,
|
|
455
|
+
fitnessFunction: (pos) => pos.reduce((sum, x) => sum + x * x, 0),
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
459
|
+
const start = performance.now();
|
|
460
|
+
plugin.step('bench-swarm');
|
|
461
|
+
stepTimes.push(performance.now() - start);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const stepStats = calculateStats(stepTimes);
|
|
465
|
+
const iterationsPerSec = 1000 / stepStats.mean;
|
|
466
|
+
|
|
467
|
+
results.add('Swarm Intelligence', `${algorithm.toUpperCase()} Step`, {
|
|
468
|
+
iterationsPerSec: formatNumber(iterationsPerSec),
|
|
469
|
+
avgTimeMs: stepStats.mean.toFixed(3),
|
|
470
|
+
p95Ms: stepStats.p95.toFixed(3),
|
|
471
|
+
populationSize: CONFIG.swarm.populationSize,
|
|
472
|
+
dimensions: CONFIG.swarm.dimensions,
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// Full optimization run
|
|
476
|
+
const optimizeTimes = [];
|
|
477
|
+
for (let i = 0; i < 10; i++) { // Fewer iterations for full optimization
|
|
478
|
+
const newSwarm = plugin.createSwarm(`bench-opt-${i}`, {
|
|
479
|
+
algorithm,
|
|
480
|
+
dimensions: CONFIG.swarm.dimensions,
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
const start = performance.now();
|
|
484
|
+
await plugin.optimize(`bench-opt-${i}`, { iterations: 50 });
|
|
485
|
+
optimizeTimes.push(performance.now() - start);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const optStats = calculateStats(optimizeTimes);
|
|
489
|
+
results.add('Swarm Intelligence', `${algorithm.toUpperCase()} Full Optimization (50 iter)`, {
|
|
490
|
+
avgTimeMs: optStats.mean.toFixed(2),
|
|
491
|
+
p95Ms: optStats.p95.toFixed(2),
|
|
492
|
+
totalIterationsPerSec: formatNumber((50 * 1000) / optStats.mean),
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Particle scaling test
|
|
497
|
+
console.log('Testing particle scaling...');
|
|
498
|
+
const scalingSizes = [10, 50, 100, 200, 500];
|
|
499
|
+
const scalingResults = {};
|
|
500
|
+
|
|
501
|
+
for (const popSize of scalingSizes) {
|
|
502
|
+
const plugin = new SwarmIntelligencePlugin({
|
|
503
|
+
algorithm: 'pso',
|
|
504
|
+
populationSize: popSize,
|
|
505
|
+
dimensions: CONFIG.swarm.dimensions,
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
const swarm = plugin.createSwarm('scale-test');
|
|
509
|
+
const times = [];
|
|
510
|
+
|
|
511
|
+
for (let i = 0; i < 50; i++) {
|
|
512
|
+
const start = performance.now();
|
|
513
|
+
plugin.step('scale-test');
|
|
514
|
+
times.push(performance.now() - start);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const stats = calculateStats(times);
|
|
518
|
+
scalingResults[popSize] = {
|
|
519
|
+
avgTimeMs: stats.mean.toFixed(3),
|
|
520
|
+
iterPerSec: formatNumber(1000 / stats.mean),
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
results.add('Swarm Intelligence', 'PSO Population Scaling', scalingResults);
|
|
525
|
+
console.log(' Swarm intelligence benchmarks complete');
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// ============================================
|
|
529
|
+
// FEDERATED LEARNING PLUGIN BENCHMARKS
|
|
530
|
+
// ============================================
|
|
531
|
+
|
|
532
|
+
async function benchmarkFederatedLearning(results) {
|
|
533
|
+
console.log('\n--- FederatedLearningPlugin Performance ---\n');
|
|
534
|
+
|
|
535
|
+
const plugin = new FederatedLearningPlugin({
|
|
536
|
+
aggregationStrategy: 'fedavg',
|
|
537
|
+
localEpochs: CONFIG.federated.epochs,
|
|
538
|
+
differentialPrivacy: true,
|
|
539
|
+
minParticipants: 1, // Allow single participant for benchmarking
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// Generate test data
|
|
543
|
+
const localData = Array(CONFIG.federated.localDataSize).fill(null).map(() => ({
|
|
544
|
+
features: Array(10).fill(0).map(() => Math.random()),
|
|
545
|
+
label: Math.random() > 0.5 ? 1 : 0,
|
|
546
|
+
}));
|
|
547
|
+
|
|
548
|
+
const globalWeights = Array(10).fill(0).map(() => Math.random());
|
|
549
|
+
|
|
550
|
+
// Local training performance
|
|
551
|
+
console.log('Testing local training...');
|
|
552
|
+
const trainTimes = [];
|
|
553
|
+
|
|
554
|
+
for (let i = 0; i < 50; i++) {
|
|
555
|
+
const roundId = plugin.startRound(`model-${i}`, globalWeights);
|
|
556
|
+
|
|
557
|
+
const start = performance.now();
|
|
558
|
+
await plugin.trainLocal(roundId, localData, {
|
|
559
|
+
participantId: `participant-${i}`,
|
|
560
|
+
epochs: CONFIG.federated.epochs,
|
|
561
|
+
});
|
|
562
|
+
trainTimes.push(performance.now() - start);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const trainStats = calculateStats(trainTimes);
|
|
566
|
+
results.add('Federated Learning', 'Local Training', {
|
|
567
|
+
avgTimeMs: trainStats.mean.toFixed(2),
|
|
568
|
+
p95Ms: trainStats.p95.toFixed(2),
|
|
569
|
+
samplesProcessed: CONFIG.federated.localDataSize,
|
|
570
|
+
epochs: CONFIG.federated.epochs,
|
|
571
|
+
samplesPerSecond: formatNumber((CONFIG.federated.localDataSize * CONFIG.federated.epochs * 1000) / trainStats.mean),
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
// Aggregation performance (FedAvg)
|
|
575
|
+
console.log('Testing aggregation...');
|
|
576
|
+
const aggregationTimes = [];
|
|
577
|
+
|
|
578
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
579
|
+
// Simulate multiple participant updates
|
|
580
|
+
const updates = Array(CONFIG.federated.participants).fill(null).map(() => ({
|
|
581
|
+
update: Array(10).fill(0).map(() => Math.random()),
|
|
582
|
+
dataSize: Math.floor(Math.random() * 1000) + 100,
|
|
583
|
+
}));
|
|
584
|
+
|
|
585
|
+
const start = performance.now();
|
|
586
|
+
plugin._fedAvg(updates);
|
|
587
|
+
aggregationTimes.push(performance.now() - start);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const aggStats = calculateStats(aggregationTimes);
|
|
591
|
+
results.add('Federated Learning', 'FedAvg Aggregation', {
|
|
592
|
+
avgTimeMs: aggStats.mean.toFixed(4),
|
|
593
|
+
p95Ms: aggStats.p95.toFixed(4),
|
|
594
|
+
opsPerSec: formatNumber(1000 / aggStats.mean),
|
|
595
|
+
participants: CONFIG.federated.participants,
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// Differential privacy overhead
|
|
599
|
+
console.log('Testing differential privacy overhead...');
|
|
600
|
+
const dpTimes = [];
|
|
601
|
+
const noDpTimes = [];
|
|
602
|
+
|
|
603
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
604
|
+
const weights = Array(100).fill(0).map(() => Math.random());
|
|
605
|
+
|
|
606
|
+
const start1 = performance.now();
|
|
607
|
+
plugin._addDifferentialPrivacy([...weights]);
|
|
608
|
+
dpTimes.push(performance.now() - start1);
|
|
609
|
+
|
|
610
|
+
// Baseline (no DP)
|
|
611
|
+
const start2 = performance.now();
|
|
612
|
+
const _ = weights.map(w => w); // Just copy
|
|
613
|
+
noDpTimes.push(performance.now() - start2);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const dpStats = calculateStats(dpTimes);
|
|
617
|
+
const noDpStats = calculateStats(noDpTimes);
|
|
618
|
+
results.add('Federated Learning', 'Differential Privacy Overhead', {
|
|
619
|
+
withDpMs: dpStats.mean.toFixed(4),
|
|
620
|
+
withoutDpMs: noDpStats.mean.toFixed(4),
|
|
621
|
+
overheadFactor: (dpStats.mean / noDpStats.mean).toFixed(2),
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
console.log(' Federated learning benchmarks complete');
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// ============================================
|
|
628
|
+
// REPUTATION STAKING PLUGIN BENCHMARKS
|
|
629
|
+
// ============================================
|
|
630
|
+
|
|
631
|
+
async function benchmarkReputationStaking(results) {
|
|
632
|
+
console.log('\n--- ReputationStakingPlugin Performance ---\n');
|
|
633
|
+
|
|
634
|
+
const plugin = new ReputationStakingPlugin();
|
|
635
|
+
|
|
636
|
+
// Mock credit system
|
|
637
|
+
const balances = new Map();
|
|
638
|
+
const creditSystem = {
|
|
639
|
+
getBalance: (nodeId) => balances.get(nodeId) || 0,
|
|
640
|
+
spendCredits: (nodeId, amount) => {
|
|
641
|
+
balances.set(nodeId, (balances.get(nodeId) || 0) - amount);
|
|
642
|
+
},
|
|
643
|
+
earnCredits: (nodeId, amount) => {
|
|
644
|
+
balances.set(nodeId, (balances.get(nodeId) || 0) + amount);
|
|
645
|
+
},
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// Initialize nodes with credits
|
|
649
|
+
for (let i = 0; i < 100; i++) {
|
|
650
|
+
balances.set(`node-${i}`, 10000);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Stake operations
|
|
654
|
+
console.log('Testing stake operations...');
|
|
655
|
+
const stakeTimes = [];
|
|
656
|
+
for (let i = 0; i < CONFIG.staking.operations; i++) {
|
|
657
|
+
const nodeId = `node-${i % 100}`;
|
|
658
|
+
const start = performance.now();
|
|
659
|
+
try {
|
|
660
|
+
plugin.stake(nodeId, 100, creditSystem);
|
|
661
|
+
} catch (e) {
|
|
662
|
+
// Ignore insufficient balance
|
|
663
|
+
}
|
|
664
|
+
stakeTimes.push(performance.now() - start);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const stakeStats = calculateStats(stakeTimes);
|
|
668
|
+
results.add('Reputation Staking', 'Stake Operations', {
|
|
669
|
+
opsPerSec: formatNumber(1000 / stakeStats.mean),
|
|
670
|
+
avgTimeMs: stakeStats.mean.toFixed(4),
|
|
671
|
+
p95Ms: stakeStats.p95.toFixed(4),
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
// Slash operations
|
|
675
|
+
console.log('Testing slash operations...');
|
|
676
|
+
const slashTimes = [];
|
|
677
|
+
for (let i = 0; i < CONFIG.staking.operations; i++) {
|
|
678
|
+
const nodeId = `node-${i % 100}`;
|
|
679
|
+
const start = performance.now();
|
|
680
|
+
plugin.slash(nodeId, 'benchmark-test', 0.5);
|
|
681
|
+
slashTimes.push(performance.now() - start);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const slashStats = calculateStats(slashTimes);
|
|
685
|
+
results.add('Reputation Staking', 'Slash Operations', {
|
|
686
|
+
opsPerSec: formatNumber(1000 / slashStats.mean),
|
|
687
|
+
avgTimeMs: slashStats.mean.toFixed(4),
|
|
688
|
+
p95Ms: slashStats.p95.toFixed(4),
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// Reputation checks
|
|
692
|
+
console.log('Testing reputation lookups...');
|
|
693
|
+
const reputationTimes = [];
|
|
694
|
+
for (let i = 0; i < CONFIG.staking.operations; i++) {
|
|
695
|
+
const nodeId = `node-${i % 100}`;
|
|
696
|
+
const start = performance.now();
|
|
697
|
+
plugin.getReputation(nodeId);
|
|
698
|
+
reputationTimes.push(performance.now() - start);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const repStats = calculateStats(reputationTimes);
|
|
702
|
+
results.add('Reputation Staking', 'Reputation Lookups', {
|
|
703
|
+
opsPerSec: formatNumber(1000 / repStats.mean),
|
|
704
|
+
avgTimeMs: repStats.mean.toFixed(5),
|
|
705
|
+
p95Ms: repStats.p95.toFixed(5),
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
// Leaderboard computation
|
|
709
|
+
console.log('Testing leaderboard computation...');
|
|
710
|
+
const leaderboardTimes = [];
|
|
711
|
+
for (let i = 0; i < 100; i++) {
|
|
712
|
+
const start = performance.now();
|
|
713
|
+
plugin.getLeaderboard(10);
|
|
714
|
+
leaderboardTimes.push(performance.now() - start);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const lbStats = calculateStats(leaderboardTimes);
|
|
718
|
+
results.add('Reputation Staking', 'Leaderboard (top 10)', {
|
|
719
|
+
opsPerSec: formatNumber(1000 / lbStats.mean),
|
|
720
|
+
avgTimeMs: lbStats.mean.toFixed(3),
|
|
721
|
+
p95Ms: lbStats.p95.toFixed(3),
|
|
722
|
+
stakerCount: plugin.stakes.size,
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
// Eligibility checks
|
|
726
|
+
console.log('Testing eligibility checks...');
|
|
727
|
+
const eligibilityTimes = [];
|
|
728
|
+
for (let i = 0; i < CONFIG.staking.operations; i++) {
|
|
729
|
+
const nodeId = `node-${i % 100}`;
|
|
730
|
+
const start = performance.now();
|
|
731
|
+
plugin.isEligible(nodeId, 50, 100);
|
|
732
|
+
eligibilityTimes.push(performance.now() - start);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const eligStats = calculateStats(eligibilityTimes);
|
|
736
|
+
results.add('Reputation Staking', 'Eligibility Checks', {
|
|
737
|
+
opsPerSec: formatNumber(1000 / eligStats.mean),
|
|
738
|
+
avgTimeMs: eligStats.mean.toFixed(5),
|
|
739
|
+
p95Ms: eligStats.p95.toFixed(5),
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
console.log(' Reputation staking benchmarks complete');
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// ============================================
|
|
746
|
+
// SANDBOX OVERHEAD BENCHMARKS
|
|
747
|
+
// ============================================
|
|
748
|
+
|
|
749
|
+
async function benchmarkSandboxOverhead(results) {
|
|
750
|
+
console.log('\n--- Sandbox Overhead ---\n');
|
|
751
|
+
|
|
752
|
+
const loader = new PluginLoader({ verifySignatures: false });
|
|
753
|
+
|
|
754
|
+
// Capability check overhead
|
|
755
|
+
console.log('Testing capability check overhead...');
|
|
756
|
+
const sandbox = loader._createSandbox(['NETWORK_CONNECT', 'CRYPTO_ENCRYPT']);
|
|
757
|
+
|
|
758
|
+
const capCheckTimes = [];
|
|
759
|
+
for (let i = 0; i < CONFIG.benchmarkIterations * 10; i++) {
|
|
760
|
+
const start = performance.now();
|
|
761
|
+
sandbox.hasCapability('NETWORK_CONNECT');
|
|
762
|
+
capCheckTimes.push(performance.now() - start);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const capStats = calculateStats(capCheckTimes);
|
|
766
|
+
results.add('Sandbox Overhead', 'Capability Check', {
|
|
767
|
+
opsPerSec: formatNumber(1000 / capStats.mean),
|
|
768
|
+
avgTimeNs: (capStats.mean * 1000000).toFixed(0),
|
|
769
|
+
p95Ns: (capStats.p95 * 1000000).toFixed(0),
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// API call overhead vs direct
|
|
773
|
+
console.log('Testing API call overhead...');
|
|
774
|
+
|
|
775
|
+
// Direct function call baseline
|
|
776
|
+
const directTimes = [];
|
|
777
|
+
const directFn = (x) => x * 2;
|
|
778
|
+
for (let i = 0; i < CONFIG.benchmarkIterations * 10; i++) {
|
|
779
|
+
const start = performance.now();
|
|
780
|
+
directFn(i);
|
|
781
|
+
directTimes.push(performance.now() - start);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Sandboxed API call
|
|
785
|
+
const api = loader._createPluginAPI({ capabilities: ['CRYPTO_ENCRYPT'] }, sandbox);
|
|
786
|
+
const sandboxedTimes = [];
|
|
787
|
+
for (let i = 0; i < CONFIG.benchmarkIterations * 10; i++) {
|
|
788
|
+
const start = performance.now();
|
|
789
|
+
sandbox.hasCapability('CRYPTO_ENCRYPT');
|
|
790
|
+
// Simulate API work
|
|
791
|
+
const _ = i * 2;
|
|
792
|
+
sandboxedTimes.push(performance.now() - start);
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const directStats = calculateStats(directTimes);
|
|
796
|
+
const sandboxedStats = calculateStats(sandboxedTimes);
|
|
797
|
+
|
|
798
|
+
results.add('Sandbox Overhead', 'Direct vs Sandboxed Call', {
|
|
799
|
+
directAvgNs: (directStats.mean * 1000000).toFixed(0),
|
|
800
|
+
sandboxedAvgNs: (sandboxedStats.mean * 1000000).toFixed(0),
|
|
801
|
+
overheadFactor: (sandboxedStats.mean / directStats.mean).toFixed(2),
|
|
802
|
+
overheadNs: ((sandboxedStats.mean - directStats.mean) * 1000000).toFixed(0),
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
// Capability require (with exception path)
|
|
806
|
+
console.log('Testing capability require overhead...');
|
|
807
|
+
const requireTimes = [];
|
|
808
|
+
for (let i = 0; i < CONFIG.benchmarkIterations * 10; i++) {
|
|
809
|
+
const start = performance.now();
|
|
810
|
+
sandbox.require('NETWORK_CONNECT');
|
|
811
|
+
requireTimes.push(performance.now() - start);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
const requireStats = calculateStats(requireTimes);
|
|
815
|
+
results.add('Sandbox Overhead', 'Capability Require', {
|
|
816
|
+
opsPerSec: formatNumber(1000 / requireStats.mean),
|
|
817
|
+
avgTimeNs: (requireStats.mean * 1000000).toFixed(0),
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
console.log(' Sandbox overhead benchmarks complete');
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// ============================================
|
|
824
|
+
// MEMORY USAGE BENCHMARKS
|
|
825
|
+
// ============================================
|
|
826
|
+
|
|
827
|
+
async function benchmarkMemoryUsage(results) {
|
|
828
|
+
console.log('\n--- Memory Usage ---\n');
|
|
829
|
+
|
|
830
|
+
// Force GC if available
|
|
831
|
+
if (global.gc) {
|
|
832
|
+
global.gc();
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
const baseMemory = getMemoryUsage();
|
|
836
|
+
|
|
837
|
+
// Base memory footprint (no plugins)
|
|
838
|
+
results.add('Memory Usage', 'Base Memory', {
|
|
839
|
+
heapUsed: formatBytes(baseMemory.heapUsed),
|
|
840
|
+
heapTotal: formatBytes(baseMemory.heapTotal),
|
|
841
|
+
rss: formatBytes(baseMemory.rss),
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
// Per-plugin memory cost
|
|
845
|
+
console.log('Measuring per-plugin memory...');
|
|
846
|
+
const pluginMemory = {};
|
|
847
|
+
|
|
848
|
+
const plugins = [
|
|
849
|
+
{ name: 'Compression', factory: () => new CompressionPlugin() },
|
|
850
|
+
{ name: 'E2E Encryption', factory: () => new E2EEncryptionPlugin() },
|
|
851
|
+
{ name: 'Swarm Intelligence', factory: () => new SwarmIntelligencePlugin() },
|
|
852
|
+
{ name: 'Federated Learning', factory: () => new FederatedLearningPlugin() },
|
|
853
|
+
{ name: 'Reputation Staking', factory: () => new ReputationStakingPlugin() },
|
|
854
|
+
];
|
|
855
|
+
|
|
856
|
+
for (const { name, factory } of plugins) {
|
|
857
|
+
global.gc?.();
|
|
858
|
+
const before = getMemoryUsage();
|
|
859
|
+
|
|
860
|
+
const instances = [];
|
|
861
|
+
for (let i = 0; i < 10; i++) {
|
|
862
|
+
instances.push(factory());
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
global.gc?.();
|
|
866
|
+
const after = getMemoryUsage();
|
|
867
|
+
|
|
868
|
+
pluginMemory[name] = {
|
|
869
|
+
perInstance: formatBytes((after.heapUsed - before.heapUsed) / 10),
|
|
870
|
+
perInstanceBytes: Math.floor((after.heapUsed - before.heapUsed) / 10),
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
results.add('Memory Usage', 'Per-Plugin Memory', pluginMemory);
|
|
875
|
+
|
|
876
|
+
// Memory after 1000 operations
|
|
877
|
+
console.log('Measuring memory after sustained operations...');
|
|
878
|
+
|
|
879
|
+
global.gc?.();
|
|
880
|
+
const beforeOps = getMemoryUsage();
|
|
881
|
+
|
|
882
|
+
// Compression operations
|
|
883
|
+
const compression = new CompressionPlugin({ threshold: 0 });
|
|
884
|
+
for (let i = 0; i < CONFIG.memoryOperations; i++) {
|
|
885
|
+
const data = generateCompressibleData(1024);
|
|
886
|
+
const compressed = compression.compress(data);
|
|
887
|
+
compression.decompress(compressed.data, compressed.compressed);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// Encryption operations
|
|
891
|
+
const encryption = new E2EEncryptionPlugin({ forwardSecrecy: false });
|
|
892
|
+
for (let i = 0; i < CONFIG.memoryOperations; i++) {
|
|
893
|
+
await encryption.establishSession(`peer-${i}`, 'key');
|
|
894
|
+
encryption.encrypt(`peer-${i}`, 'test message');
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Swarm operations
|
|
898
|
+
const swarm = new SwarmIntelligencePlugin();
|
|
899
|
+
for (let i = 0; i < Math.min(100, CONFIG.memoryOperations); i++) {
|
|
900
|
+
swarm.createSwarm(`swarm-${i}`);
|
|
901
|
+
for (let j = 0; j < 10; j++) {
|
|
902
|
+
swarm.step(`swarm-${i}`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
global.gc?.();
|
|
907
|
+
const afterOps = getMemoryUsage();
|
|
908
|
+
|
|
909
|
+
results.add('Memory Usage', 'After 1000 Operations', {
|
|
910
|
+
heapGrowth: formatBytes(afterOps.heapUsed - beforeOps.heapUsed),
|
|
911
|
+
heapGrowthBytes: afterOps.heapUsed - beforeOps.heapUsed,
|
|
912
|
+
finalHeap: formatBytes(afterOps.heapUsed),
|
|
913
|
+
operationsPerMB: Math.floor(CONFIG.memoryOperations / ((afterOps.heapUsed - beforeOps.heapUsed) / 1048576)),
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
// Memory pressure test (create and release)
|
|
917
|
+
console.log('Testing memory release...');
|
|
918
|
+
|
|
919
|
+
global.gc?.();
|
|
920
|
+
const beforePressure = getMemoryUsage();
|
|
921
|
+
|
|
922
|
+
// Create many instances
|
|
923
|
+
const instances = [];
|
|
924
|
+
for (let i = 0; i < 100; i++) {
|
|
925
|
+
instances.push(new CompressionPlugin());
|
|
926
|
+
instances.push(new E2EEncryptionPlugin());
|
|
927
|
+
instances.push(new SwarmIntelligencePlugin());
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
global.gc?.();
|
|
931
|
+
const peakMemory = getMemoryUsage();
|
|
932
|
+
|
|
933
|
+
// Release
|
|
934
|
+
instances.length = 0;
|
|
935
|
+
global.gc?.();
|
|
936
|
+
const releasedMemory = getMemoryUsage();
|
|
937
|
+
|
|
938
|
+
results.add('Memory Usage', 'Memory Pressure Test', {
|
|
939
|
+
peakGrowth: formatBytes(peakMemory.heapUsed - beforePressure.heapUsed),
|
|
940
|
+
afterRelease: formatBytes(releasedMemory.heapUsed - beforePressure.heapUsed),
|
|
941
|
+
releaseEfficiency: ((1 - (releasedMemory.heapUsed - beforePressure.heapUsed) /
|
|
942
|
+
(peakMemory.heapUsed - beforePressure.heapUsed)) * 100).toFixed(1) + '%',
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
console.log(' Memory usage benchmarks complete');
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// ============================================
|
|
949
|
+
// BASELINE COMPARISON
|
|
950
|
+
// ============================================
|
|
951
|
+
|
|
952
|
+
async function benchmarkBaseline(results) {
|
|
953
|
+
console.log('\n--- Baseline Comparison (No Plugins) ---\n');
|
|
954
|
+
|
|
955
|
+
// Direct operations without plugin overhead
|
|
956
|
+
|
|
957
|
+
// Raw buffer operations (baseline for compression)
|
|
958
|
+
console.log('Testing raw buffer operations...');
|
|
959
|
+
const rawBufferTimes = [];
|
|
960
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
961
|
+
const data = Buffer.alloc(65536);
|
|
962
|
+
const start = performance.now();
|
|
963
|
+
const copy = Buffer.from(data);
|
|
964
|
+
rawBufferTimes.push(performance.now() - start);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
results.add('Baseline', 'Raw Buffer Copy (64KB)', {
|
|
968
|
+
avgTimeMs: calculateStats(rawBufferTimes).mean.toFixed(4),
|
|
969
|
+
throughputMBs: ((65536 / 1048576) / (calculateStats(rawBufferTimes).mean / 1000)).toFixed(2),
|
|
970
|
+
});
|
|
971
|
+
|
|
972
|
+
// Raw crypto operations (baseline for encryption)
|
|
973
|
+
console.log('Testing raw crypto operations...');
|
|
974
|
+
const { createCipheriv, randomBytes, createHash } = await import('crypto');
|
|
975
|
+
|
|
976
|
+
const cryptoTimes = [];
|
|
977
|
+
const key = randomBytes(32);
|
|
978
|
+
const testData = randomBytes(1024);
|
|
979
|
+
|
|
980
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
981
|
+
const iv = randomBytes(12);
|
|
982
|
+
const start = performance.now();
|
|
983
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
984
|
+
cipher.update(testData);
|
|
985
|
+
cipher.final();
|
|
986
|
+
cipher.getAuthTag();
|
|
987
|
+
cryptoTimes.push(performance.now() - start);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
results.add('Baseline', 'Raw AES-256-GCM (1KB)', {
|
|
991
|
+
avgTimeMs: calculateStats(cryptoTimes).mean.toFixed(4),
|
|
992
|
+
opsPerSec: formatNumber(1000 / calculateStats(cryptoTimes).mean),
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
// Map operations (baseline for staking)
|
|
996
|
+
console.log('Testing raw Map operations...');
|
|
997
|
+
const map = new Map();
|
|
998
|
+
const mapTimes = [];
|
|
999
|
+
|
|
1000
|
+
for (let i = 0; i < CONFIG.staking.operations; i++) {
|
|
1001
|
+
const start = performance.now();
|
|
1002
|
+
map.set(`key-${i}`, { value: i, data: { nested: true } });
|
|
1003
|
+
map.get(`key-${i % (i + 1)}`);
|
|
1004
|
+
mapTimes.push(performance.now() - start);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
results.add('Baseline', 'Raw Map Operations', {
|
|
1008
|
+
avgTimeNs: (calculateStats(mapTimes).mean * 1000000).toFixed(0),
|
|
1009
|
+
opsPerSec: formatNumber(1000 / calculateStats(mapTimes).mean),
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
// Math operations (baseline for swarm)
|
|
1013
|
+
console.log('Testing raw math operations...');
|
|
1014
|
+
const mathTimes = [];
|
|
1015
|
+
const dimensions = CONFIG.swarm.dimensions;
|
|
1016
|
+
const particles = CONFIG.swarm.populationSize;
|
|
1017
|
+
|
|
1018
|
+
for (let i = 0; i < CONFIG.benchmarkIterations; i++) {
|
|
1019
|
+
const start = performance.now();
|
|
1020
|
+
for (let p = 0; p < particles; p++) {
|
|
1021
|
+
let sum = 0;
|
|
1022
|
+
for (let d = 0; d < dimensions; d++) {
|
|
1023
|
+
sum += Math.random() * Math.random() + Math.sqrt(Math.random());
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
mathTimes.push(performance.now() - start);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
results.add('Baseline', 'Raw Math Operations (50 particles x 10 dim)', {
|
|
1030
|
+
avgTimeMs: calculateStats(mathTimes).mean.toFixed(3),
|
|
1031
|
+
opsPerSec: formatNumber(1000 / calculateStats(mathTimes).mean),
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
console.log(' Baseline benchmarks complete');
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// ============================================
|
|
1038
|
+
// REPORT GENERATION
|
|
1039
|
+
// ============================================
|
|
1040
|
+
|
|
1041
|
+
function generateTextReport(report) {
|
|
1042
|
+
const lines = [];
|
|
1043
|
+
|
|
1044
|
+
lines.push('');
|
|
1045
|
+
lines.push('='.repeat(80));
|
|
1046
|
+
lines.push(' EDGE-NET PLUGIN SYSTEM PERFORMANCE BENCHMARKS');
|
|
1047
|
+
lines.push('='.repeat(80));
|
|
1048
|
+
lines.push('');
|
|
1049
|
+
lines.push(`Timestamp: ${report.timestamp}`);
|
|
1050
|
+
lines.push(`Duration: ${(report.duration / 1000).toFixed(2)}s`);
|
|
1051
|
+
lines.push(`Node.js: ${report.nodeVersion}`);
|
|
1052
|
+
lines.push(`Platform: ${report.platform} (${report.arch})`);
|
|
1053
|
+
lines.push('');
|
|
1054
|
+
|
|
1055
|
+
for (const [category, metrics] of Object.entries(report.categories)) {
|
|
1056
|
+
lines.push('-'.repeat(80));
|
|
1057
|
+
lines.push(` ${category}`);
|
|
1058
|
+
lines.push('-'.repeat(80));
|
|
1059
|
+
lines.push('');
|
|
1060
|
+
|
|
1061
|
+
for (const [name, data] of Object.entries(metrics)) {
|
|
1062
|
+
if (typeof data === 'object' && !Array.isArray(data)) {
|
|
1063
|
+
lines.push(` ${name}:`);
|
|
1064
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1065
|
+
if (typeof value === 'object') {
|
|
1066
|
+
lines.push(` ${key}: ${JSON.stringify(value)}`);
|
|
1067
|
+
} else {
|
|
1068
|
+
lines.push(` ${key}: ${value}`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
} else {
|
|
1072
|
+
lines.push(` ${name}: ${JSON.stringify(data)}`);
|
|
1073
|
+
}
|
|
1074
|
+
lines.push('');
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
lines.push('='.repeat(80));
|
|
1079
|
+
lines.push(' SUMMARY & RECOMMENDATIONS');
|
|
1080
|
+
lines.push('='.repeat(80));
|
|
1081
|
+
lines.push('');
|
|
1082
|
+
|
|
1083
|
+
// Extract key metrics for summary
|
|
1084
|
+
const compressionThroughput = report.categories['Compression']?.['medium Compress (compressible)']?.throughputMBs || 'N/A';
|
|
1085
|
+
const encryptionOps = report.categories['Encryption']?.['small Encrypt']?.opsPerSec || 'N/A';
|
|
1086
|
+
const swarmIterSec = report.categories['Swarm Intelligence']?.['PSO Step']?.iterationsPerSec || 'N/A';
|
|
1087
|
+
const stakingOps = report.categories['Reputation Staking']?.['Stake Operations']?.opsPerSec || 'N/A';
|
|
1088
|
+
const sandboxOverhead = report.categories['Sandbox Overhead']?.['Direct vs Sandboxed Call']?.overheadFactor || 'N/A';
|
|
1089
|
+
|
|
1090
|
+
lines.push('Key Performance Metrics:');
|
|
1091
|
+
lines.push(` - Compression throughput: ${compressionThroughput} MB/s`);
|
|
1092
|
+
lines.push(` - Encryption operations: ${encryptionOps} ops/sec`);
|
|
1093
|
+
lines.push(` - Swarm PSO iterations: ${swarmIterSec} iter/sec`);
|
|
1094
|
+
lines.push(` - Staking operations: ${stakingOps} ops/sec`);
|
|
1095
|
+
lines.push(` - Sandbox overhead factor: ${sandboxOverhead}x`);
|
|
1096
|
+
lines.push('');
|
|
1097
|
+
|
|
1098
|
+
lines.push('Optimization Recommendations:');
|
|
1099
|
+
lines.push('');
|
|
1100
|
+
|
|
1101
|
+
// Provide context-aware recommendations
|
|
1102
|
+
const compressionNum = parseFloat(compressionThroughput) || 0;
|
|
1103
|
+
if (compressionNum < 100) {
|
|
1104
|
+
lines.push(' [!] Compression: Consider using native WASM LZ4 for better throughput');
|
|
1105
|
+
} else {
|
|
1106
|
+
lines.push(' [OK] Compression: Throughput is acceptable for most use cases');
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const sandboxNum = parseFloat(sandboxOverhead) || 0;
|
|
1110
|
+
if (sandboxNum > 5) {
|
|
1111
|
+
lines.push(' [!] Sandbox: High overhead detected - consider caching capability checks');
|
|
1112
|
+
} else {
|
|
1113
|
+
lines.push(' [OK] Sandbox: Overhead is within acceptable range');
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
lines.push('');
|
|
1117
|
+
lines.push('For production deployments:');
|
|
1118
|
+
lines.push(' 1. Enable WASM SIMD for compression/encryption acceleration');
|
|
1119
|
+
lines.push(' 2. Use worker threads for swarm intelligence computations');
|
|
1120
|
+
lines.push(' 3. Consider batching staking operations for high-throughput scenarios');
|
|
1121
|
+
lines.push(' 4. Monitor memory usage with --expose-gc for accurate measurements');
|
|
1122
|
+
lines.push('');
|
|
1123
|
+
|
|
1124
|
+
return lines.join('\n');
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function generateSummaryTable(report) {
|
|
1128
|
+
const lines = [];
|
|
1129
|
+
|
|
1130
|
+
lines.push('');
|
|
1131
|
+
lines.push('+' + '-'.repeat(78) + '+');
|
|
1132
|
+
lines.push('|' + ' '.repeat(25) + 'PERFORMANCE SUMMARY TABLE' + ' '.repeat(28) + '|');
|
|
1133
|
+
lines.push('+' + '-'.repeat(78) + '+');
|
|
1134
|
+
lines.push('| Plugin/Operation | Metric | Value | Unit |');
|
|
1135
|
+
lines.push('+' + '-'.repeat(78) + '+');
|
|
1136
|
+
|
|
1137
|
+
const tableRows = [
|
|
1138
|
+
// Compression
|
|
1139
|
+
{ plugin: 'CompressionPlugin', op: 'Compress (64KB)', metric: 'Throughput', value: report.categories['Compression']?.['medium Compress (compressible)']?.throughputMBs || 'N/A', unit: 'MB/s' },
|
|
1140
|
+
{ plugin: 'CompressionPlugin', op: 'Decompress (64KB)', metric: 'Throughput', value: report.categories['Compression']?.['medium Decompress']?.throughputMBs || 'N/A', unit: 'MB/s' },
|
|
1141
|
+
|
|
1142
|
+
// Encryption
|
|
1143
|
+
{ plugin: 'E2EEncryptionPlugin', op: 'Encrypt (1KB)', metric: 'Operations', value: report.categories['Encryption']?.['small Encrypt']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1144
|
+
{ plugin: 'E2EEncryptionPlugin', op: 'Decrypt (1KB)', metric: 'Operations', value: report.categories['Encryption']?.['small Decrypt']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1145
|
+
{ plugin: 'E2EEncryptionPlugin', op: 'Session Setup', metric: 'Operations', value: report.categories['Encryption']?.['Session Establishment']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1146
|
+
|
|
1147
|
+
// Swarm Intelligence
|
|
1148
|
+
{ plugin: 'SwarmIntelligencePlugin', op: 'PSO Step', metric: 'Iterations', value: report.categories['Swarm Intelligence']?.['PSO Step']?.iterationsPerSec || 'N/A', unit: 'iter/sec' },
|
|
1149
|
+
{ plugin: 'SwarmIntelligencePlugin', op: 'GA Step', metric: 'Iterations', value: report.categories['Swarm Intelligence']?.['GA Step']?.iterationsPerSec || 'N/A', unit: 'iter/sec' },
|
|
1150
|
+
{ plugin: 'SwarmIntelligencePlugin', op: 'DE Step', metric: 'Iterations', value: report.categories['Swarm Intelligence']?.['DE Step']?.iterationsPerSec || 'N/A', unit: 'iter/sec' },
|
|
1151
|
+
|
|
1152
|
+
// Federated Learning
|
|
1153
|
+
{ plugin: 'FederatedLearningPlugin', op: 'Local Training', metric: 'Samples', value: report.categories['Federated Learning']?.['Local Training']?.samplesPerSecond || 'N/A', unit: 'samples/s' },
|
|
1154
|
+
{ plugin: 'FederatedLearningPlugin', op: 'FedAvg', metric: 'Aggregations', value: report.categories['Federated Learning']?.['FedAvg Aggregation']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1155
|
+
|
|
1156
|
+
// Reputation Staking
|
|
1157
|
+
{ plugin: 'ReputationStakingPlugin', op: 'Stake', metric: 'Operations', value: report.categories['Reputation Staking']?.['Stake Operations']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1158
|
+
{ plugin: 'ReputationStakingPlugin', op: 'Slash', metric: 'Operations', value: report.categories['Reputation Staking']?.['Slash Operations']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1159
|
+
{ plugin: 'ReputationStakingPlugin', op: 'Reputation Lookup', metric: 'Operations', value: report.categories['Reputation Staking']?.['Reputation Lookups']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1160
|
+
|
|
1161
|
+
// Sandbox
|
|
1162
|
+
{ plugin: 'Sandbox', op: 'Capability Check', metric: 'Operations', value: report.categories['Sandbox Overhead']?.['Capability Check']?.opsPerSec || 'N/A', unit: 'ops/sec' },
|
|
1163
|
+
{ plugin: 'Sandbox', op: 'Overhead Factor', metric: 'Factor', value: report.categories['Sandbox Overhead']?.['Direct vs Sandboxed Call']?.overheadFactor || 'N/A', unit: 'x' },
|
|
1164
|
+
];
|
|
1165
|
+
|
|
1166
|
+
for (const row of tableRows) {
|
|
1167
|
+
const pluginPad = (row.plugin + ' ' + row.op).substring(0, 30).padEnd(30);
|
|
1168
|
+
const metricPad = row.metric.padEnd(20);
|
|
1169
|
+
const valuePad = String(row.value).padEnd(17);
|
|
1170
|
+
const unitPad = row.unit.padEnd(9);
|
|
1171
|
+
lines.push(`| ${pluginPad}| ${metricPad}| ${valuePad}| ${unitPad}|`);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
lines.push('+' + '-'.repeat(78) + '+');
|
|
1175
|
+
lines.push('');
|
|
1176
|
+
|
|
1177
|
+
return lines.join('\n');
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// ============================================
|
|
1181
|
+
// MAIN BENCHMARK RUNNER
|
|
1182
|
+
// ============================================
|
|
1183
|
+
|
|
1184
|
+
async function runBenchmarks() {
|
|
1185
|
+
console.log('');
|
|
1186
|
+
console.log('='.repeat(60));
|
|
1187
|
+
console.log(' Edge-Net Plugin System Performance Benchmarks');
|
|
1188
|
+
console.log('='.repeat(60));
|
|
1189
|
+
console.log('');
|
|
1190
|
+
console.log('Configuration:');
|
|
1191
|
+
console.log(` - Warmup iterations: ${CONFIG.warmupIterations}`);
|
|
1192
|
+
console.log(` - Benchmark iterations: ${CONFIG.benchmarkIterations}`);
|
|
1193
|
+
console.log(` - Data sizes: ${Object.entries(CONFIG.dataSizes).map(([k, v]) => `${k}=${formatBytes(v)}`).join(', ')}`);
|
|
1194
|
+
console.log(` - GC available: ${typeof global.gc === 'function' ? 'Yes' : 'No (run with --expose-gc for accurate memory)'}`);
|
|
1195
|
+
console.log('');
|
|
1196
|
+
|
|
1197
|
+
const results = new BenchmarkResults();
|
|
1198
|
+
|
|
1199
|
+
try {
|
|
1200
|
+
// Run all benchmarks
|
|
1201
|
+
await benchmarkPluginLoading(results);
|
|
1202
|
+
await benchmarkCompression(results);
|
|
1203
|
+
await benchmarkEncryption(results);
|
|
1204
|
+
await benchmarkSwarmIntelligence(results);
|
|
1205
|
+
await benchmarkFederatedLearning(results);
|
|
1206
|
+
await benchmarkReputationStaking(results);
|
|
1207
|
+
await benchmarkSandboxOverhead(results);
|
|
1208
|
+
await benchmarkMemoryUsage(results);
|
|
1209
|
+
await benchmarkBaseline(results);
|
|
1210
|
+
|
|
1211
|
+
// Generate reports
|
|
1212
|
+
const report = results.generateReport();
|
|
1213
|
+
|
|
1214
|
+
console.log(generateSummaryTable(report));
|
|
1215
|
+
console.log(generateTextReport(report));
|
|
1216
|
+
|
|
1217
|
+
// Output JSON for programmatic access
|
|
1218
|
+
console.log('\n--- JSON Output ---\n');
|
|
1219
|
+
console.log(JSON.stringify(report, null, 2));
|
|
1220
|
+
|
|
1221
|
+
return report;
|
|
1222
|
+
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
console.error('\nBenchmark failed:', error);
|
|
1225
|
+
console.error(error.stack);
|
|
1226
|
+
process.exit(1);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// Run if executed directly
|
|
1231
|
+
runBenchmarks().then(() => {
|
|
1232
|
+
console.log('\nBenchmarks completed successfully.');
|
|
1233
|
+
process.exit(0);
|
|
1234
|
+
}).catch((error) => {
|
|
1235
|
+
console.error('Fatal error:', error);
|
|
1236
|
+
process.exit(1);
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
export { runBenchmarks, CONFIG };
|