claude-flow-novice 2.0.3 → 2.0.4
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/src/cli/commands/guidance.js +487 -668
- package/dist/src/cli/commands/index-validate.js +18 -29
- package/dist/src/cli/commands/mcp-troubleshoot.js +230 -282
- package/dist/src/cli/commands/neural-goal-init.js +92 -125
- package/dist/src/cli/commands/swarm-exec.js +317 -393
- package/dist/src/cli/commands/swarm.js +1 -1
- package/dist/src/cli/commands/validate-framework.js +983 -1100
- package/dist/src/cli/commands/validate.js +144 -223
- package/dist/src/cli/simple-commands/__tests__/agent.test.js +265 -277
- package/dist/src/cli/simple-commands/__tests__/memory.test.js +6 -7
- package/dist/src/cli/simple-commands/__tests__/swarm.test.js +373 -356
- package/dist/src/cli/simple-commands/__tests__/task.test.js +6 -7
- package/dist/src/cli/simple-commands/agent.js +157 -193
- package/dist/src/cli/simple-commands/analysis.js +336 -446
- package/dist/src/cli/simple-commands/automation-executor.js +1095 -1339
- package/dist/src/cli/simple-commands/automation.js +481 -469
- package/dist/src/cli/simple-commands/batch-manager.js +261 -313
- package/dist/src/cli/simple-commands/claude-telemetry.js +241 -267
- package/dist/src/cli/simple-commands/claude-track.js +68 -90
- package/dist/src/cli/simple-commands/concurrent-display.js +266 -320
- package/dist/src/cli/simple-commands/config.js +245 -290
- package/dist/src/cli/simple-commands/coordination.js +182 -234
- package/dist/src/cli/simple-commands/enhanced-ui-views.js +812 -615
- package/dist/src/cli/simple-commands/enhanced-webui-complete.js +922 -981
- package/dist/src/cli/simple-commands/fix-hook-variables.js +274 -294
- package/dist/src/cli/simple-commands/github/gh-coordinator.js +378 -457
- package/dist/src/cli/simple-commands/github/github-api.js +535 -574
- package/dist/src/cli/simple-commands/github/init.js +276 -303
- package/dist/src/cli/simple-commands/github.js +222 -247
- package/dist/src/cli/simple-commands/goal.js +51 -63
- package/dist/src/cli/simple-commands/hive-mind/auto-save-middleware.js +208 -278
- package/dist/src/cli/simple-commands/hive-mind/communication.js +601 -696
- package/dist/src/cli/simple-commands/hive-mind/core.js +907 -979
- package/dist/src/cli/simple-commands/hive-mind/db-optimizer.js +406 -655
- package/dist/src/cli/simple-commands/hive-mind/mcp-wrapper.js +1125 -1245
- package/dist/src/cli/simple-commands/hive-mind/memory.js +854 -1090
- package/dist/src/cli/simple-commands/hive-mind/performance-optimizer.js +459 -574
- package/dist/src/cli/simple-commands/hive-mind/performance-test.js +263 -347
- package/dist/src/cli/simple-commands/hive-mind/queen.js +727 -768
- package/dist/src/cli/simple-commands/hive-mind/session-manager.js +745 -1049
- package/dist/src/cli/simple-commands/hive-mind-optimize.js +227 -283
- package/dist/src/cli/simple-commands/hive-mind-wizard.js +174 -217
- package/dist/src/cli/simple-commands/hive-mind.js +1842 -2283
- package/dist/src/cli/simple-commands/hive.js +90 -79
- package/dist/src/cli/simple-commands/hook-safety.js +431 -521
- package/dist/src/cli/simple-commands/hooks/session-start-soul.js +203 -254
- package/dist/src/cli/simple-commands/hooks.js +1064 -1204
- package/dist/src/cli/simple-commands/init/agent-copier.js +294 -319
- package/dist/src/cli/simple-commands/init/batch-init.js +496 -562
- package/dist/src/cli/simple-commands/init/claude-commands/claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-claude-flow-commands.js +13 -19
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-slash-commands.js +61 -88
- package/dist/src/cli/simple-commands/init/claude-commands/optimized-sparc-commands.js +125 -150
- package/dist/src/cli/simple-commands/init/claude-commands/slash-commands.js +42 -49
- package/dist/src/cli/simple-commands/init/claude-commands/sparc-commands.js +43 -61
- package/dist/src/cli/simple-commands/init/copy-revised-templates.js +141 -147
- package/dist/src/cli/simple-commands/init/executable-wrapper.js +31 -44
- package/dist/src/cli/simple-commands/init/gitignore-updater.js +64 -90
- package/dist/src/cli/simple-commands/init/help.js +104 -107
- package/dist/src/cli/simple-commands/init/hive-mind-init.js +509 -528
- package/dist/src/cli/simple-commands/init/index.js +1510 -1759
- package/dist/src/cli/simple-commands/init/performance-monitor.js +234 -317
- package/dist/src/cli/simple-commands/init/rollback/backup-manager.js +441 -504
- package/dist/src/cli/simple-commands/init/rollback/index.js +289 -364
- package/dist/src/cli/simple-commands/init/rollback/recovery-manager.js +652 -728
- package/dist/src/cli/simple-commands/init/rollback/rollback-executor.js +416 -481
- package/dist/src/cli/simple-commands/init/rollback/state-tracker.js +369 -448
- package/dist/src/cli/simple-commands/init/sparc/roo-readme.js +1 -2
- package/dist/src/cli/simple-commands/init/sparc/roomodes-config.js +122 -99
- package/dist/src/cli/simple-commands/init/sparc/workflows.js +32 -37
- package/dist/src/cli/simple-commands/init/sparc-structure.js +55 -62
- package/dist/src/cli/simple-commands/init/template-copier.js +421 -533
- package/dist/src/cli/simple-commands/init/templates/coordination-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/enhanced-templates.js +344 -318
- package/dist/src/cli/simple-commands/init/templates/github-safe-enhanced.js +173 -218
- package/dist/src/cli/simple-commands/init/templates/github-safe.js +65 -75
- package/dist/src/cli/simple-commands/init/templates/memory-bank-md.js +3 -6
- package/dist/src/cli/simple-commands/init/templates/readme-files.js +2 -4
- package/dist/src/cli/simple-commands/init/templates/safe-hook-patterns.js +187 -230
- package/dist/src/cli/simple-commands/init/templates/sparc-modes.js +53 -80
- package/dist/src/cli/simple-commands/init/templates/verification-claude-md.js +101 -85
- package/dist/src/cli/simple-commands/init/validation/config-validator.js +283 -330
- package/dist/src/cli/simple-commands/init/validation/health-checker.js +495 -561
- package/dist/src/cli/simple-commands/init/validation/index.js +302 -358
- package/dist/src/cli/simple-commands/init/validation/mode-validator.js +308 -359
- package/dist/src/cli/simple-commands/init/validation/post-init-validator.js +389 -366
- package/dist/src/cli/simple-commands/init/validation/pre-init-validator.js +270 -268
- package/dist/src/cli/simple-commands/init/validation/test-runner.js +427 -447
- package/dist/src/cli/simple-commands/init.js +1 -2
- package/dist/src/cli/simple-commands/mcp-health.js +131 -158
- package/dist/src/cli/simple-commands/mcp-integration-layer.js +533 -634
- package/dist/src/cli/simple-commands/mcp.js +345 -400
- package/dist/src/cli/simple-commands/memory-consolidation.js +426 -537
- package/dist/src/cli/simple-commands/memory.js +247 -311
- package/dist/src/cli/simple-commands/migrate-hooks.js +39 -46
- package/dist/src/cli/simple-commands/monitor.js +294 -363
- package/dist/src/cli/simple-commands/neural.js +51 -65
- package/dist/src/cli/simple-commands/pair-autofix-only.js +538 -662
- package/dist/src/cli/simple-commands/pair-basic.js +528 -656
- package/dist/src/cli/simple-commands/pair-old.js +430 -543
- package/dist/src/cli/simple-commands/pair-working.js +615 -751
- package/dist/src/cli/simple-commands/pair.js +615 -751
- package/dist/src/cli/simple-commands/performance-hooks.js +83 -111
- package/dist/src/cli/simple-commands/performance-metrics.js +348 -433
- package/dist/src/cli/simple-commands/process-ui-enhanced.js +708 -787
- package/dist/src/cli/simple-commands/process-ui.js +230 -254
- package/dist/src/cli/simple-commands/realtime-update-system.js +525 -611
- package/dist/src/cli/simple-commands/sparc/architecture.js +1704 -1530
- package/dist/src/cli/simple-commands/sparc/commands.js +438 -516
- package/dist/src/cli/simple-commands/sparc/completion.js +1224 -1481
- package/dist/src/cli/simple-commands/sparc/coordinator.js +913 -978
- package/dist/src/cli/simple-commands/sparc/index.js +241 -298
- package/dist/src/cli/simple-commands/sparc/phase-base.js +314 -390
- package/dist/src/cli/simple-commands/sparc/pseudocode.js +965 -869
- package/dist/src/cli/simple-commands/sparc/refinement.js +980 -1273
- package/dist/src/cli/simple-commands/sparc/specification.js +559 -645
- package/dist/src/cli/simple-commands/sparc-modes/architect.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/ask.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/code.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/debug.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/devops.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/docs-writer.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/generic.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/index.js +47 -55
- package/dist/src/cli/simple-commands/sparc-modes/integration.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/mcp.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/monitoring.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/optimization.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/security-review.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/sparc-orchestrator.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/spec-pseudocode.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/supabase-admin.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/swarm.js +101 -87
- package/dist/src/cli/simple-commands/sparc-modes/tdd.js +1 -1
- package/dist/src/cli/simple-commands/sparc-modes/tutorial.js +1 -1
- package/dist/src/cli/simple-commands/sparc.js +465 -493
- package/dist/src/cli/simple-commands/start-ui.js +108 -132
- package/dist/src/cli/simple-commands/start-wrapper.js +240 -268
- package/dist/src/cli/simple-commands/start.js +1 -1
- package/dist/src/cli/simple-commands/status.js +254 -275
- package/dist/src/cli/simple-commands/stream-chain-clean.js +128 -171
- package/dist/src/cli/simple-commands/stream-chain-fixed.js +61 -82
- package/dist/src/cli/simple-commands/stream-chain-real.js +267 -331
- package/dist/src/cli/simple-commands/stream-chain-working.js +211 -263
- package/dist/src/cli/simple-commands/stream-chain.js +260 -318
- package/dist/src/cli/simple-commands/stream-processor.js +290 -315
- package/dist/src/cli/simple-commands/swarm-executor.js +189 -222
- package/dist/src/cli/simple-commands/swarm-metrics-integration.js +208 -300
- package/dist/src/cli/simple-commands/swarm-ui.js +623 -703
- package/dist/src/cli/simple-commands/swarm-webui-integration.js +258 -286
- package/dist/src/cli/simple-commands/swarm.js +887 -1082
- package/dist/src/cli/simple-commands/task.js +161 -206
- package/dist/src/cli/simple-commands/timestamp-fix.js +59 -89
- package/dist/src/cli/simple-commands/token-tracker.js +258 -316
- package/dist/src/cli/simple-commands/tool-execution-framework.js +433 -519
- package/dist/src/cli/simple-commands/train-and-stream.js +275 -331
- package/dist/src/cli/simple-commands/training-pipeline.js +619 -725
- package/dist/src/cli/simple-commands/training.js +170 -227
- package/dist/src/cli/simple-commands/verification-hooks.js +261 -284
- package/dist/src/cli/simple-commands/verification-integration.js +389 -417
- package/dist/src/cli/simple-commands/verification-training-integration.js +486 -606
- package/dist/src/cli/simple-commands/verification.js +493 -513
- package/dist/src/cli/simple-commands/web-server.js +766 -836
- package/dist/src/cli/simple-commands/webui-validator.js +106 -124
- package/dist/src/coordination/event-bus/demo-wasm-integration.js +212 -251
- package/dist/src/coordination/event-bus/qe-event-bus.js +608 -748
- package/dist/src/coordination/event-bus/qe-event-bus.test.js +379 -454
- package/dist/src/coordination/iteration-tracker.js +363 -454
- package/dist/src/enterprise/analytics-manager.js +1135 -0
- package/dist/src/enterprise/audit-manager.js +1115 -0
- package/dist/src/enterprise/cloud-manager.js +891 -0
- package/dist/src/enterprise/deployment-manager.js +966 -0
- package/dist/src/enterprise/index.js +6 -0
- package/dist/src/enterprise/project-manager.js +584 -0
- package/dist/src/enterprise/security-manager.js +991 -0
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/DEPRECATED.js +46 -60
- package/dist/src/mcp/fixes/mcp-error-fixes.js +115 -134
- package/dist/src/mcp/implementations/agent-tracker.js +114 -128
- package/dist/src/mcp/implementations/daa-tools.js +292 -350
- package/dist/src/mcp/implementations/workflow-tools.js +329 -361
- package/dist/src/mcp/mcp-config-manager.js +1183 -1331
- package/dist/src/mcp/mcp-server-novice-simplified.js +11 -17
- package/dist/src/mcp/mcp-server-novice.js +11 -17
- package/dist/src/mcp/mcp-server-sdk.js +11 -17
- package/dist/src/mcp/mcp-server.js +1620 -1484
- package/dist/src/mcp/ruv-swarm-wrapper.js +209 -239
- package/dist/src/memory/advanced-serializer.js +609 -589
- package/dist/src/memory/enhanced-examples.js +220 -305
- package/dist/src/memory/enhanced-memory.js +295 -336
- package/dist/src/memory/enhanced-session-serializer.js +408 -492
- package/dist/src/memory/fallback-memory-system.js +900 -1021
- package/dist/src/memory/fallback-store.js +93 -131
- package/dist/src/memory/high-performance-serialization.js +592 -730
- package/dist/src/memory/in-memory-store.js +161 -213
- package/dist/src/memory/index.js +123 -157
- package/dist/src/memory/lock-free-structures.js +578 -764
- package/dist/src/memory/memory-mapped-persistence.js +585 -766
- package/dist/src/memory/memory-pressure-manager.js +569 -707
- package/dist/src/memory/migration.js +358 -445
- package/dist/src/memory/shared-memory.js +641 -768
- package/dist/src/memory/sqlite-store.js +245 -325
- package/dist/src/memory/sqlite-wrapper.js +122 -151
- package/dist/src/memory/swarm-memory.js +470 -603
- package/dist/src/memory/test-example.js +126 -134
- package/dist/src/memory/ultra-fast-memory-store.js +622 -821
- package/dist/src/memory/unified-memory-manager.js +356 -437
- package/dist/src/migration/index.js +92 -0
- package/dist/src/migration/logger.js +121 -0
- package/dist/src/migration/migration-analyzer.js +268 -0
- package/dist/src/migration/migration-runner.js +522 -0
- package/dist/src/migration/migration-validator.js +285 -0
- package/dist/src/migration/progress-reporter.js +150 -0
- package/dist/src/migration/rollback-manager.js +321 -0
- package/dist/src/migration/tests/migration-system.test.js +7 -0
- package/dist/src/migration/types.js +3 -0
- package/dist/src/swarm/CodeRefactoringSwarm.js +777 -952
- package/dist/src/swarm/__tests__/integration.test.js +227 -0
- package/dist/src/swarm/__tests__/prompt-copier.test.js +344 -0
- package/dist/src/swarm/advanced-orchestrator.js +1095 -0
- package/dist/src/swarm/claude-code-interface.js +961 -0
- package/dist/src/swarm/claude-flow-executor.js +229 -0
- package/dist/src/swarm/consensus-coordinator.js +475 -0
- package/dist/src/swarm/coordinator.js +2993 -0
- package/dist/src/swarm/direct-executor.js +1180 -0
- package/dist/src/swarm/error-recovery/advanced-error-detection.js +691 -0
- package/dist/src/swarm/error-recovery/automated-recovery-workflows.js +998 -0
- package/dist/src/swarm/error-recovery/error-recovery-coordinator.js +1197 -0
- package/dist/src/swarm/error-recovery/recovery-monitoring.js +772 -0
- package/dist/src/swarm/error-recovery/resilience-architecture.js +714 -0
- package/dist/src/swarm/error-recovery/self-healing-mechanisms.js +1319 -0
- package/dist/src/swarm/error-recovery/test-error-recovery-effectiveness.js +808 -0
- package/dist/src/swarm/executor-v2.js +322 -0
- package/dist/src/swarm/executor.js +815 -0
- package/dist/src/swarm/hive-mind-integration.js +703 -0
- package/dist/src/swarm/index.js +41 -0
- package/dist/src/swarm/json-output-aggregator.js +267 -0
- package/dist/src/swarm/large-scale-coordinator.js +542 -0
- package/dist/src/swarm/mcp-integration-wrapper.js +628 -0
- package/dist/src/swarm/memory.js +1117 -0
- package/dist/src/swarm/optimizations/__tests__/optimization.test.js +348 -0
- package/dist/src/swarm/optimizations/async-file-manager.js +285 -0
- package/dist/src/swarm/optimizations/circular-buffer.js +162 -0
- package/dist/src/swarm/optimizations/connection-pool.js +244 -0
- package/dist/src/swarm/optimizations/index.js +28 -0
- package/dist/src/swarm/optimizations/optimized-executor.js +320 -0
- package/dist/src/swarm/optimizations/ttl-map.js +234 -0
- package/dist/src/swarm/prompt-cli.js +200 -0
- package/dist/src/swarm/prompt-copier-enhanced.js +202 -0
- package/dist/src/swarm/prompt-copier.js +381 -0
- package/dist/src/swarm/prompt-manager.js +295 -0
- package/dist/src/swarm/prompt-utils.js +310 -0
- package/dist/src/swarm/result-aggregator.js +718 -0
- package/dist/src/swarm/sparc-executor.js +1568 -0
- package/dist/src/swarm/strategies/auto.js +758 -0
- package/dist/src/swarm/strategies/base.js +128 -0
- package/dist/src/swarm/strategies/research.js +914 -0
- package/dist/src/swarm/strategies/strategy-metrics-patch.js +2 -0
- package/dist/src/swarm/types.js +52 -0
- package/dist/src/swarm/workers/copy-worker.js +56 -0
- package/dist/src/utils/__tests__/github-cli-safety-wrapper.test.js +332 -400
- package/dist/src/utils/github-cli-safe.js +56 -64
- package/dist/src/utils/github-cli-safety-wrapper.js +451 -546
- package/dist/src/utils/npx-isolated-cache.js +104 -119
- package/dist/src/utils/preference-manager.js +622 -652
- package/dist/src/utils/timezone-utils.js +86 -105
- package/dist/src/validators/epic-config-schema.js +214 -0
- package/dist/src/validators/index.js +10 -0
- package/dist/src/validators/swarm-init-validator.js +259 -0
- package/dist/src/validators/todowrite-batching-validator.js +215 -0
- package/dist/src/validators/todowrite-integration.js +187 -0
- package/package.json +2 -2
|
@@ -9,812 +9,626 @@
|
|
|
9
9
|
* - Write operations: <500ns
|
|
10
10
|
* - Zero lock contention
|
|
11
11
|
* - Linear scalability with CPU cores
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
12
|
+
*/ /**
|
|
15
13
|
* Atomic operations wrapper with performance optimizations
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
14
|
+
*/ export class AtomicOperations {
|
|
15
|
+
/**
|
|
19
16
|
* Compare-and-swap with retry logic and backoff
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
17
|
+
*/ static compareAndSwap32(buffer, offset, expected, value) {
|
|
18
|
+
const view = new Uint32Array(buffer);
|
|
19
|
+
const index = offset >> 2;
|
|
20
|
+
return Atomics.compareExchange(view, index, expected, value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
28
23
|
* Compare-and-swap for 64-bit values (using two 32-bit operations)
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
24
|
+
*/ static compareAndSwap64(buffer, offset, expectedLow, expectedHigh, valueLow, valueHigh) {
|
|
25
|
+
const view = new Uint32Array(buffer);
|
|
26
|
+
const lowIndex = offset >> 2;
|
|
27
|
+
const highIndex = lowIndex + 1;
|
|
28
|
+
// Atomic 64-bit CAS requires platform-specific implementation
|
|
29
|
+
// This is a simplified version for demonstration
|
|
30
|
+
while(true){
|
|
31
|
+
const currentLow = Atomics.load(view, lowIndex);
|
|
32
|
+
const currentHigh = Atomics.load(view, highIndex);
|
|
33
|
+
if (currentLow === expectedLow && currentHigh === expectedHigh) {
|
|
34
|
+
const successLow = Atomics.compareExchange(view, lowIndex, expectedLow, valueLow);
|
|
35
|
+
if (successLow === expectedLow) {
|
|
36
|
+
const successHigh = Atomics.compareExchange(view, highIndex, expectedHigh, valueHigh);
|
|
37
|
+
if (successHigh === expectedHigh) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
// Rollback low if high failed
|
|
41
|
+
Atomics.compareExchange(view, lowIndex, valueLow, expectedLow);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Exponential backoff
|
|
45
|
+
this.backoff();
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
60
50
|
* Atomic increment with overflow protection
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
/**
|
|
51
|
+
*/ static atomicIncrement(buffer, offset) {
|
|
52
|
+
const view = new Uint32Array(buffer);
|
|
53
|
+
return Atomics.add(view, offset >> 2, 1);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
68
56
|
* Atomic decrement with underflow protection
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
/**
|
|
57
|
+
*/ static atomicDecrement(buffer, offset) {
|
|
58
|
+
const view = new Uint32Array(buffer);
|
|
59
|
+
return Atomics.sub(view, offset >> 2, 1);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
76
62
|
* Load with acquire memory ordering
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
/**
|
|
63
|
+
*/ static loadAcquire(buffer, offset) {
|
|
64
|
+
const view = new Uint32Array(buffer);
|
|
65
|
+
return Atomics.load(view, offset >> 2);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
84
68
|
* Store with release memory ordering
|
|
85
|
-
*/
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
/**
|
|
69
|
+
*/ static storeRelease(buffer, offset, value) {
|
|
70
|
+
const view = new Uint32Array(buffer);
|
|
71
|
+
return Atomics.store(view, offset >> 2, value);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
92
74
|
* Exponential backoff for contention management
|
|
93
|
-
*/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
/**
|
|
75
|
+
*/ static backoff(attempt = 1) {
|
|
76
|
+
const maxBackoff = Math.min(64, Math.pow(2, attempt));
|
|
77
|
+
for(let i = 0; i < maxBackoff; i++){
|
|
78
|
+
// CPU-friendly spin without yielding
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
102
82
|
* Memory fence for ordering guarantees
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
83
|
+
*/ static memoryFence() {
|
|
84
|
+
// Use Atomics.notify/wait for memory synchronization
|
|
85
|
+
const dummy = new Int32Array(new SharedArrayBuffer(4));
|
|
86
|
+
Atomics.store(dummy, 0, 0);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
111
89
|
/**
|
|
112
90
|
* Lock-free hash table with linear probing and optimistic concurrency
|
|
113
|
-
*/
|
|
114
|
-
|
|
115
|
-
constructor(sharedBuffer, bucketCount = 16384, bucketsOffset = 4096) {
|
|
116
|
-
this.buffer = sharedBuffer;
|
|
117
|
-
this.bucketCount = bucketCount;
|
|
118
|
-
this.bucketSize = 32; // bytes per bucket
|
|
119
|
-
this.bucketsOffset = bucketsOffset;
|
|
120
|
-
this.loadFactor = 0.75; // Resize threshold
|
|
121
|
-
|
|
122
|
-
this.initializeBuckets();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
91
|
+
*/ export class LockFreeHashTable {
|
|
92
|
+
/**
|
|
126
93
|
* Initialize bucket structure in shared memory
|
|
127
|
-
*/
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
94
|
+
*/ initializeBuckets() {
|
|
95
|
+
const view = new Uint32Array(this.buffer);
|
|
96
|
+
const bucketView = view.subarray(this.bucketsOffset >> 2);
|
|
97
|
+
for(let i = 0; i < this.bucketCount; i++){
|
|
98
|
+
const bucketBase = i * (this.bucketSize >> 2);
|
|
99
|
+
bucketView[bucketBase] = 0; // head = null
|
|
100
|
+
bucketView[bucketBase + 1] = 0; // count = 0
|
|
101
|
+
bucketView[bucketBase + 2] = 0; // lock version = 0
|
|
102
|
+
// Reserved space for future use
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
142
106
|
* Lock-free insertion with optimistic concurrency control
|
|
143
|
-
*/
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Exponential backoff before retry
|
|
175
|
-
AtomicOperations.backoff(attempts);
|
|
176
|
-
attempts++;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return false; // Failed after max attempts
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
107
|
+
*/ insert(keyHash, entryOffset) {
|
|
108
|
+
const bucketIndex = keyHash % this.bucketCount;
|
|
109
|
+
const bucketOffset = this.bucketsOffset + bucketIndex * this.bucketSize;
|
|
110
|
+
let attempts = 0;
|
|
111
|
+
const maxAttempts = 16;
|
|
112
|
+
while(attempts < maxAttempts){
|
|
113
|
+
// Read current state
|
|
114
|
+
const currentHead = AtomicOperations.loadAcquire(this.buffer, bucketOffset);
|
|
115
|
+
const lockVersion = AtomicOperations.loadAcquire(this.buffer, bucketOffset + 8);
|
|
116
|
+
// Set next pointer of new entry to current head
|
|
117
|
+
AtomicOperations.storeRelease(this.buffer, entryOffset, currentHead);
|
|
118
|
+
// Attempt atomic update of bucket head
|
|
119
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, bucketOffset, currentHead, entryOffset);
|
|
120
|
+
if (success === currentHead) {
|
|
121
|
+
// Verify no concurrent modification (ABA problem prevention)
|
|
122
|
+
const newLockVersion = AtomicOperations.loadAcquire(this.buffer, bucketOffset + 8);
|
|
123
|
+
if (newLockVersion === lockVersion) {
|
|
124
|
+
// Update count atomically
|
|
125
|
+
AtomicOperations.atomicIncrement(this.buffer, bucketOffset + 4);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Exponential backoff before retry
|
|
130
|
+
AtomicOperations.backoff(attempts);
|
|
131
|
+
attempts++;
|
|
132
|
+
}
|
|
133
|
+
return false; // Failed after max attempts
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
183
136
|
* Lock-free lookup with minimal memory barriers
|
|
184
|
-
*/
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
entryOffset = AtomicOperations.loadAcquire(this.buffer, entryOffset);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return 0; // Not found
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
137
|
+
*/ lookup(keyHash, keyComparator) {
|
|
138
|
+
const bucketIndex = keyHash % this.bucketCount;
|
|
139
|
+
const bucketOffset = this.bucketsOffset + bucketIndex * this.bucketSize;
|
|
140
|
+
let entryOffset = AtomicOperations.loadAcquire(this.buffer, bucketOffset);
|
|
141
|
+
while(entryOffset !== 0){
|
|
142
|
+
const entry = this.getEntryView(entryOffset);
|
|
143
|
+
// Fast hash comparison first
|
|
144
|
+
const entryHash = AtomicOperations.loadAcquire(this.buffer, entryOffset + 4);
|
|
145
|
+
if (entryHash === keyHash && keyComparator(entry)) {
|
|
146
|
+
return entryOffset;
|
|
147
|
+
}
|
|
148
|
+
// Follow chain
|
|
149
|
+
entryOffset = AtomicOperations.loadAcquire(this.buffer, entryOffset);
|
|
150
|
+
}
|
|
151
|
+
return 0; // Not found
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
208
154
|
* Lock-free removal with lazy deletion
|
|
209
|
-
*/
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
prevOffset = currentOffset;
|
|
239
|
-
currentOffset = AtomicOperations.loadAcquire(this.buffer, currentOffset);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return false; // Not found
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
155
|
+
*/ remove(keyHash, keyComparator) {
|
|
156
|
+
const bucketIndex = keyHash % this.bucketCount;
|
|
157
|
+
const bucketOffset = this.bucketsOffset + bucketIndex * this.bucketSize;
|
|
158
|
+
while(true){
|
|
159
|
+
let prevOffset = bucketOffset;
|
|
160
|
+
let currentOffset = AtomicOperations.loadAcquire(this.buffer, bucketOffset);
|
|
161
|
+
while(currentOffset !== 0){
|
|
162
|
+
const entry = this.getEntryView(currentOffset);
|
|
163
|
+
const entryHash = AtomicOperations.loadAcquire(this.buffer, currentOffset + 4);
|
|
164
|
+
if (entryHash === keyHash && keyComparator(entry)) {
|
|
165
|
+
// Mark as deleted (lazy deletion)
|
|
166
|
+
const flags = AtomicOperations.loadAcquire(this.buffer, currentOffset + 24);
|
|
167
|
+
const newFlags = flags | 0x80000000; // Set deleted bit
|
|
168
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, currentOffset + 24, flags, newFlags);
|
|
169
|
+
if (success === flags) {
|
|
170
|
+
// Decrement bucket count
|
|
171
|
+
AtomicOperations.atomicDecrement(this.buffer, bucketOffset + 4);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
prevOffset = currentOffset;
|
|
176
|
+
currentOffset = AtomicOperations.loadAcquire(this.buffer, currentOffset);
|
|
177
|
+
}
|
|
178
|
+
return false; // Not found
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
247
182
|
* Get entry view for fast access
|
|
248
|
-
*/
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
/**
|
|
183
|
+
*/ getEntryView(offset) {
|
|
184
|
+
return {
|
|
185
|
+
offset,
|
|
186
|
+
next: ()=>AtomicOperations.loadAcquire(this.buffer, offset),
|
|
187
|
+
keyHash: ()=>AtomicOperations.loadAcquire(this.buffer, offset + 4),
|
|
188
|
+
keyLength: ()=>new Uint16Array(this.buffer, offset + 8, 1)[0],
|
|
189
|
+
valueLength: ()=>new Uint16Array(this.buffer, offset + 10, 1)[0],
|
|
190
|
+
namespace: ()=>AtomicOperations.loadAcquire(this.buffer, offset + 12),
|
|
191
|
+
timestamp: ()=>AtomicOperations.loadAcquire(this.buffer, offset + 16),
|
|
192
|
+
flags: ()=>AtomicOperations.loadAcquire(this.buffer, offset + 24)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
263
196
|
* Get bucket statistics for load balancing
|
|
264
|
-
*/
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
197
|
+
*/ getBucketStats() {
|
|
198
|
+
const stats = {
|
|
199
|
+
totalEntries: 0,
|
|
200
|
+
maxChainLength: 0,
|
|
201
|
+
emptyBuckets: 0,
|
|
202
|
+
averageChainLength: 0
|
|
203
|
+
};
|
|
204
|
+
for(let i = 0; i < this.bucketCount; i++){
|
|
205
|
+
const bucketOffset = this.bucketsOffset + i * this.bucketSize;
|
|
206
|
+
const count = AtomicOperations.loadAcquire(this.buffer, bucketOffset + 4);
|
|
207
|
+
stats.totalEntries += count;
|
|
208
|
+
stats.maxChainLength = Math.max(stats.maxChainLength, count);
|
|
209
|
+
if (count === 0) stats.emptyBuckets++;
|
|
210
|
+
}
|
|
211
|
+
stats.averageChainLength = stats.totalEntries / (this.bucketCount - stats.emptyBuckets);
|
|
212
|
+
return stats;
|
|
213
|
+
}
|
|
214
|
+
constructor(sharedBuffer, bucketCount = 16384, bucketsOffset = 4096){
|
|
215
|
+
this.buffer = sharedBuffer;
|
|
216
|
+
this.bucketCount = bucketCount;
|
|
217
|
+
this.bucketSize = 32; // bytes per bucket
|
|
218
|
+
this.bucketsOffset = bucketsOffset;
|
|
219
|
+
this.loadFactor = 0.75; // Resize threshold
|
|
220
|
+
this.initializeBuckets();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
287
223
|
/**
|
|
288
224
|
* Lock-free memory pool with segregated free lists
|
|
289
|
-
*/
|
|
290
|
-
|
|
291
|
-
constructor(sharedBuffer, poolOffset, poolSize) {
|
|
292
|
-
this.buffer = sharedBuffer;
|
|
293
|
-
this.poolOffset = poolOffset;
|
|
294
|
-
this.poolSize = poolSize;
|
|
295
|
-
this.chunkSize = 64; // Minimum allocation unit (cache line aligned)
|
|
296
|
-
this.sizeBuckets = 16; // Number of different size classes
|
|
297
|
-
|
|
298
|
-
this.initializeFreeLists();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
225
|
+
*/ export class LockFreeMemoryPool {
|
|
226
|
+
/**
|
|
302
227
|
* Initialize segregated free lists for different allocation sizes
|
|
303
|
-
*/
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
// Last chunk points to null
|
|
328
|
-
AtomicOperations.storeRelease(this.buffer, chunkOffset, 0);
|
|
329
|
-
currentOffset = chunkOffset + chunkSize;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
228
|
+
*/ initializeFreeList() {
|
|
229
|
+
const headerSize = this.sizeBuckets * 8; // 8 bytes per size class (head pointer + count)
|
|
230
|
+
let currentOffset = this.poolOffset + headerSize;
|
|
231
|
+
// Initialize free lists for different size classes
|
|
232
|
+
for(let sizeClass = 0; sizeClass < this.sizeBuckets; sizeClass++){
|
|
233
|
+
const chunkSize = this.chunkSize * (1 << sizeClass); // Power of 2 sizes
|
|
234
|
+
const headerOffset = this.poolOffset + sizeClass * 8;
|
|
235
|
+
// Initialize first chunk as head of free list
|
|
236
|
+
AtomicOperations.storeRelease(this.buffer, headerOffset, currentOffset);
|
|
237
|
+
AtomicOperations.storeRelease(this.buffer, headerOffset + 4, 0); // count
|
|
238
|
+
// Chain all chunks of this size class
|
|
239
|
+
let chunkOffset = currentOffset;
|
|
240
|
+
const chunksInClass = Math.floor(this.poolSize / (this.sizeBuckets * chunkSize));
|
|
241
|
+
for(let i = 0; i < chunksInClass - 1; i++){
|
|
242
|
+
const nextChunk = chunkOffset + chunkSize;
|
|
243
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset, nextChunk);
|
|
244
|
+
chunkOffset = nextChunk;
|
|
245
|
+
}
|
|
246
|
+
// Last chunk points to null
|
|
247
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset, 0);
|
|
248
|
+
currentOffset = chunkOffset + chunkSize;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
334
252
|
* Lock-free allocation using compare-and-swap
|
|
335
|
-
*/
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
// Initialize allocated chunk header
|
|
369
|
-
this.initializeAllocatedChunk(currentHead, alignedSize, sizeClass);
|
|
370
|
-
return currentHead;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
AtomicOperations.backoff(attempts);
|
|
374
|
-
attempts++;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return 0; // Allocation failed
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
253
|
+
*/ allocate(requestedSize) {
|
|
254
|
+
const alignedSize = this.alignSize(requestedSize);
|
|
255
|
+
const sizeClass = this.getSizeClass(alignedSize);
|
|
256
|
+
if (sizeClass >= this.sizeBuckets) {
|
|
257
|
+
return this.allocateLarge(alignedSize);
|
|
258
|
+
}
|
|
259
|
+
const freeListOffset = this.poolOffset + sizeClass * 8;
|
|
260
|
+
let attempts = 0;
|
|
261
|
+
const maxAttempts = 16;
|
|
262
|
+
while(attempts < maxAttempts){
|
|
263
|
+
const currentHead = AtomicOperations.loadAcquire(this.buffer, freeListOffset);
|
|
264
|
+
if (currentHead === 0) {
|
|
265
|
+
// No free chunks in this size class, try larger size class
|
|
266
|
+
return this.allocateFromLargerClass(sizeClass + 1, alignedSize);
|
|
267
|
+
}
|
|
268
|
+
// Read next pointer before attempting CAS
|
|
269
|
+
const nextChunk = AtomicOperations.loadAcquire(this.buffer, currentHead);
|
|
270
|
+
// Attempt to update free list head
|
|
271
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, freeListOffset, currentHead, nextChunk);
|
|
272
|
+
if (success === currentHead) {
|
|
273
|
+
// Update allocation count
|
|
274
|
+
AtomicOperations.atomicDecrement(this.buffer, freeListOffset + 4);
|
|
275
|
+
// Initialize allocated chunk header
|
|
276
|
+
this.initializeAllocatedChunk(currentHead, alignedSize, sizeClass);
|
|
277
|
+
return currentHead;
|
|
278
|
+
}
|
|
279
|
+
AtomicOperations.backoff(attempts);
|
|
280
|
+
attempts++;
|
|
281
|
+
}
|
|
282
|
+
return 0; // Allocation failed
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
381
285
|
* Lock-free deallocation returning chunk to appropriate free list
|
|
382
|
-
*/
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
// Clear chunk header for security
|
|
409
|
-
this.clearChunkHeader(chunkOffset);
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
AtomicOperations.backoff(attempts);
|
|
414
|
-
attempts++;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
286
|
+
*/ deallocate(chunkOffset) {
|
|
287
|
+
if (chunkOffset === 0) return;
|
|
288
|
+
// Read chunk header to determine size class
|
|
289
|
+
const sizeClass = this.getChunkSizeClass(chunkOffset);
|
|
290
|
+
const freeListOffset = this.poolOffset + sizeClass * 8;
|
|
291
|
+
let attempts = 0;
|
|
292
|
+
const maxAttempts = 16;
|
|
293
|
+
while(attempts < maxAttempts){
|
|
294
|
+
const currentHead = AtomicOperations.loadAcquire(this.buffer, freeListOffset);
|
|
295
|
+
// Set next pointer of chunk being freed
|
|
296
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset, currentHead);
|
|
297
|
+
// Attempt to update free list head
|
|
298
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, freeListOffset, currentHead, chunkOffset);
|
|
299
|
+
if (success === currentHead) {
|
|
300
|
+
// Update free count
|
|
301
|
+
AtomicOperations.atomicIncrement(this.buffer, freeListOffset + 4);
|
|
302
|
+
// Clear chunk header for security
|
|
303
|
+
this.clearChunkHeader(chunkOffset);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
AtomicOperations.backoff(attempts);
|
|
307
|
+
attempts++;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
419
311
|
* Align size to chunk boundaries
|
|
420
|
-
*/
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
/**
|
|
312
|
+
*/ alignSize(size) {
|
|
313
|
+
return Math.ceil(size / this.chunkSize) * this.chunkSize;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
426
316
|
* Determine size class for allocation size
|
|
427
|
-
*/
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
/**
|
|
317
|
+
*/ getSizeClass(alignedSize) {
|
|
318
|
+
const chunks = alignedSize / this.chunkSize;
|
|
319
|
+
return Math.floor(Math.log2(chunks));
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
434
322
|
* Allocate from larger size class when smaller classes are exhausted
|
|
435
|
-
*/
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
return chunk;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
323
|
+
*/ allocateFromLargerClass(sizeClass, requestedSize) {
|
|
324
|
+
if (sizeClass >= this.sizeBuckets) {
|
|
325
|
+
return 0; // No larger classes available
|
|
326
|
+
}
|
|
327
|
+
const chunk = this.allocate(this.chunkSize * (1 << sizeClass));
|
|
328
|
+
if (chunk === 0) {
|
|
329
|
+
return this.allocateFromLargerClass(sizeClass + 1, requestedSize);
|
|
330
|
+
}
|
|
331
|
+
// Split chunk if it's significantly larger than requested
|
|
332
|
+
const chunkSize = this.chunkSize * (1 << sizeClass);
|
|
333
|
+
if (chunkSize > requestedSize * 2) {
|
|
334
|
+
this.splitChunk(chunk, requestedSize, chunkSize);
|
|
335
|
+
}
|
|
336
|
+
return chunk;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
456
339
|
* Split large chunk into smaller pieces
|
|
457
|
-
*/
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/**
|
|
340
|
+
*/ splitChunk(chunkOffset, requestedSize, chunkSize) {
|
|
341
|
+
const remainderOffset = chunkOffset + requestedSize;
|
|
342
|
+
const remainderSize = chunkSize - requestedSize;
|
|
343
|
+
if (remainderSize >= this.chunkSize) {
|
|
344
|
+
// Return remainder to appropriate free list
|
|
345
|
+
const remainderSizeClass = this.getSizeClass(remainderSize);
|
|
346
|
+
this.initializeAllocatedChunk(remainderOffset, remainderSize, remainderSizeClass);
|
|
347
|
+
this.deallocate(remainderOffset);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
471
351
|
* Initialize allocated chunk header with metadata
|
|
472
|
-
*/
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
/**
|
|
352
|
+
*/ initializeAllocatedChunk(chunkOffset, size, sizeClass) {
|
|
353
|
+
// Chunk header format: [size: 4 bytes][sizeClass: 4 bytes][reserved: 8 bytes]
|
|
354
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 16, size);
|
|
355
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 12, sizeClass);
|
|
356
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 8, 0); // Reserved
|
|
357
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 4, 0); // Reserved
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
482
360
|
* Get size class from chunk header
|
|
483
|
-
*/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
/**
|
|
361
|
+
*/ getChunkSizeClass(chunkOffset) {
|
|
362
|
+
return AtomicOperations.loadAcquire(this.buffer, chunkOffset - 12);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
489
365
|
* Clear chunk header for security
|
|
490
|
-
*/
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
/**
|
|
366
|
+
*/ clearChunkHeader(chunkOffset) {
|
|
367
|
+
// Clear sensitive data
|
|
368
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 16, 0);
|
|
369
|
+
AtomicOperations.storeRelease(this.buffer, chunkOffset - 12, 0);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
498
372
|
* Get memory pool statistics
|
|
499
|
-
*/
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
373
|
+
*/ getPoolStats() {
|
|
374
|
+
const stats = {
|
|
375
|
+
totalSize: this.poolSize,
|
|
376
|
+
allocatedBytes: 0,
|
|
377
|
+
freeBytes: 0,
|
|
378
|
+
fragmentationRatio: 0,
|
|
379
|
+
sizeClassStats: []
|
|
380
|
+
};
|
|
381
|
+
for(let sizeClass = 0; sizeClass < this.sizeBuckets; sizeClass++){
|
|
382
|
+
const freeListOffset = this.poolOffset + sizeClass * 8;
|
|
383
|
+
const freeCount = AtomicOperations.loadAcquire(this.buffer, freeListOffset + 4);
|
|
384
|
+
const chunkSize = this.chunkSize * (1 << sizeClass);
|
|
385
|
+
stats.sizeClassStats[sizeClass] = {
|
|
386
|
+
chunkSize,
|
|
387
|
+
freeChunks: freeCount,
|
|
388
|
+
freeBytes: freeCount * chunkSize
|
|
389
|
+
};
|
|
390
|
+
stats.freeBytes += freeCount * chunkSize;
|
|
391
|
+
}
|
|
392
|
+
stats.allocatedBytes = stats.totalSize - stats.freeBytes;
|
|
393
|
+
stats.fragmentationRatio = stats.freeBytes / stats.totalSize;
|
|
394
|
+
return stats;
|
|
395
|
+
}
|
|
396
|
+
constructor(sharedBuffer, poolOffset, poolSize){
|
|
397
|
+
this.buffer = sharedBuffer;
|
|
398
|
+
this.poolOffset = poolOffset;
|
|
399
|
+
this.poolSize = poolSize;
|
|
400
|
+
this.chunkSize = 64; // Minimum allocation unit (cache line aligned)
|
|
401
|
+
this.sizeBuckets = 16; // Number of different size classes
|
|
402
|
+
this.initializeFreeLists();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
530
405
|
/**
|
|
531
406
|
* Lock-free ring buffer for high-throughput message passing
|
|
532
|
-
*/
|
|
533
|
-
|
|
534
|
-
constructor(sharedBuffer, ringOffset, ringSize) {
|
|
535
|
-
this.buffer = sharedBuffer;
|
|
536
|
-
this.ringOffset = ringOffset;
|
|
537
|
-
this.ringSize = ringSize;
|
|
538
|
-
this.slotSize = 64; // Each message slot size
|
|
539
|
-
this.slotCount = Math.floor(ringSize / this.slotSize);
|
|
540
|
-
|
|
541
|
-
// Ring buffer control structure
|
|
542
|
-
this.headOffset = ringOffset - 16; // Producer position
|
|
543
|
-
this.tailOffset = ringOffset - 12; // Consumer position
|
|
544
|
-
this.countOffset = ringOffset - 8; // Current count
|
|
545
|
-
this.flagsOffset = ringOffset - 4; // Control flags
|
|
546
|
-
|
|
547
|
-
this.initialize();
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
407
|
+
*/ export class LockFreeRingBuffer {
|
|
408
|
+
/**
|
|
551
409
|
* Initialize ring buffer control structure
|
|
552
|
-
*/
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
/**
|
|
410
|
+
*/ initialize() {
|
|
411
|
+
AtomicOperations.storeRelease(this.buffer, this.headOffset, 0);
|
|
412
|
+
AtomicOperations.storeRelease(this.buffer, this.tailOffset, 0);
|
|
413
|
+
AtomicOperations.storeRelease(this.buffer, this.countOffset, 0);
|
|
414
|
+
AtomicOperations.storeRelease(this.buffer, this.flagsOffset, 0);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
561
417
|
* Lock-free enqueue operation
|
|
562
|
-
*/
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
//
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
// Update count atomically
|
|
594
|
-
AtomicOperations.atomicIncrement(this.buffer, this.countOffset);
|
|
595
|
-
return true;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
AtomicOperations.backoff(attempts);
|
|
599
|
-
attempts++;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
return false; // Failed after max attempts
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
418
|
+
*/ enqueue(messageData) {
|
|
419
|
+
if (messageData.length > this.slotSize - 8) {
|
|
420
|
+
return false; // Message too large
|
|
421
|
+
}
|
|
422
|
+
let attempts = 0;
|
|
423
|
+
const maxAttempts = 100;
|
|
424
|
+
while(attempts < maxAttempts){
|
|
425
|
+
const currentHead = AtomicOperations.loadAcquire(this.buffer, this.headOffset);
|
|
426
|
+
const currentTail = AtomicOperations.loadAcquire(this.buffer, this.tailOffset);
|
|
427
|
+
const currentCount = AtomicOperations.loadAcquire(this.buffer, this.countOffset);
|
|
428
|
+
// Check if buffer is full
|
|
429
|
+
if (currentCount >= this.slotCount) {
|
|
430
|
+
return false; // Buffer full
|
|
431
|
+
}
|
|
432
|
+
const newHead = (currentHead + 1) % this.slotCount;
|
|
433
|
+
const slotOffset = this.ringOffset + currentHead * this.slotSize;
|
|
434
|
+
// Reserve slot by advancing head
|
|
435
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, this.headOffset, currentHead, newHead);
|
|
436
|
+
if (success === currentHead) {
|
|
437
|
+
// Write message to reserved slot
|
|
438
|
+
this.writeMessageToSlot(slotOffset, messageData);
|
|
439
|
+
// Update count atomically
|
|
440
|
+
AtomicOperations.atomicIncrement(this.buffer, this.countOffset);
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
AtomicOperations.backoff(attempts);
|
|
444
|
+
attempts++;
|
|
445
|
+
}
|
|
446
|
+
return false; // Failed after max attempts
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
606
449
|
* Lock-free dequeue operation
|
|
607
|
-
*/
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
AtomicOperations.atomicDecrement(this.buffer, this.countOffset);
|
|
636
|
-
return messageData;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
AtomicOperations.backoff(attempts);
|
|
640
|
-
attempts++;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
return null; // Failed after max attempts
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
450
|
+
*/ dequeue() {
|
|
451
|
+
let attempts = 0;
|
|
452
|
+
const maxAttempts = 100;
|
|
453
|
+
while(attempts < maxAttempts){
|
|
454
|
+
const currentTail = AtomicOperations.loadAcquire(this.buffer, this.tailOffset);
|
|
455
|
+
const currentHead = AtomicOperations.loadAcquire(this.buffer, this.headOffset);
|
|
456
|
+
const currentCount = AtomicOperations.loadAcquire(this.buffer, this.countOffset);
|
|
457
|
+
// Check if buffer is empty
|
|
458
|
+
if (currentCount === 0) {
|
|
459
|
+
return null; // Buffer empty
|
|
460
|
+
}
|
|
461
|
+
const newTail = (currentTail + 1) % this.slotCount;
|
|
462
|
+
const slotOffset = this.ringOffset + currentTail * this.slotSize;
|
|
463
|
+
// Reserve slot by advancing tail
|
|
464
|
+
const success = AtomicOperations.compareAndSwap32(this.buffer, this.tailOffset, currentTail, newTail);
|
|
465
|
+
if (success === currentTail) {
|
|
466
|
+
// Read message from reserved slot
|
|
467
|
+
const messageData = this.readMessageFromSlot(slotOffset);
|
|
468
|
+
// Update count atomically
|
|
469
|
+
AtomicOperations.atomicDecrement(this.buffer, this.countOffset);
|
|
470
|
+
return messageData;
|
|
471
|
+
}
|
|
472
|
+
AtomicOperations.backoff(attempts);
|
|
473
|
+
attempts++;
|
|
474
|
+
}
|
|
475
|
+
return null; // Failed after max attempts
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
647
478
|
* Write message data to ring buffer slot
|
|
648
|
-
*/
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
dataView.set(messageData);
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/**
|
|
479
|
+
*/ writeMessageToSlot(slotOffset, messageData) {
|
|
480
|
+
// Slot format: [length: 4 bytes][timestamp: 4 bytes][data: variable]
|
|
481
|
+
AtomicOperations.storeRelease(this.buffer, slotOffset, messageData.length);
|
|
482
|
+
AtomicOperations.storeRelease(this.buffer, slotOffset + 4, Math.floor(performance.now() * 1000000) & 0xFFFFFFFF);
|
|
483
|
+
// Copy message data
|
|
484
|
+
const dataView = new Uint8Array(this.buffer, slotOffset + 8, messageData.length);
|
|
485
|
+
dataView.set(messageData);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
661
488
|
* Read message data from ring buffer slot
|
|
662
|
-
*/
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
489
|
+
*/ readMessageFromSlot(slotOffset) {
|
|
490
|
+
const length = AtomicOperations.loadAcquire(this.buffer, slotOffset);
|
|
491
|
+
const timestamp = AtomicOperations.loadAcquire(this.buffer, slotOffset + 4);
|
|
492
|
+
const messageData = new Uint8Array(length);
|
|
493
|
+
const dataView = new Uint8Array(this.buffer, slotOffset + 8, length);
|
|
494
|
+
messageData.set(dataView);
|
|
495
|
+
return {
|
|
496
|
+
data: messageData,
|
|
497
|
+
timestamp,
|
|
498
|
+
length
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
679
502
|
* Get ring buffer statistics
|
|
680
|
-
*/
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
503
|
+
*/ getStats() {
|
|
504
|
+
return {
|
|
505
|
+
size: this.slotCount,
|
|
506
|
+
count: AtomicOperations.loadAcquire(this.buffer, this.countOffset),
|
|
507
|
+
head: AtomicOperations.loadAcquire(this.buffer, this.headOffset),
|
|
508
|
+
tail: AtomicOperations.loadAcquire(this.buffer, this.tailOffset),
|
|
509
|
+
utilization: AtomicOperations.loadAcquire(this.buffer, this.countOffset) / this.slotCount
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
constructor(sharedBuffer, ringOffset, ringSize){
|
|
513
|
+
this.buffer = sharedBuffer;
|
|
514
|
+
this.ringOffset = ringOffset;
|
|
515
|
+
this.ringSize = ringSize;
|
|
516
|
+
this.slotSize = 64; // Each message slot size
|
|
517
|
+
this.slotCount = Math.floor(ringSize / this.slotSize);
|
|
518
|
+
// Ring buffer control structure
|
|
519
|
+
this.headOffset = ringOffset - 16; // Producer position
|
|
520
|
+
this.tailOffset = ringOffset - 12; // Consumer position
|
|
521
|
+
this.countOffset = ringOffset - 8; // Current count
|
|
522
|
+
this.flagsOffset = ringOffset - 4; // Control flags
|
|
523
|
+
this.initialize();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
692
526
|
/**
|
|
693
527
|
* Performance benchmarking utilities for lock-free structures
|
|
694
|
-
*/
|
|
695
|
-
|
|
696
|
-
constructor() {
|
|
697
|
-
this.samples = new Array(100000);
|
|
698
|
-
this.sampleIndex = 0;
|
|
699
|
-
this.operationCounts = new Map();
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
/**
|
|
528
|
+
*/ export class LockFreePerformanceBenchmark {
|
|
529
|
+
/**
|
|
703
530
|
* Measure operation with nanosecond precision
|
|
704
|
-
*/
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
/**
|
|
531
|
+
*/ measureOperation(operationName, operation) {
|
|
532
|
+
const start = performance.now() * 1000000; // Convert to nanoseconds
|
|
533
|
+
const result = operation();
|
|
534
|
+
const end = performance.now() * 1000000;
|
|
535
|
+
const duration = end - start;
|
|
536
|
+
this.recordSample(operationName, duration);
|
|
537
|
+
return {
|
|
538
|
+
result,
|
|
539
|
+
duration
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
717
543
|
* Concurrent benchmark with multiple threads
|
|
718
|
-
*/
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const threadResults = await Promise.all(workers);
|
|
746
|
-
return this.analyzeConcurrentResults(threadResults);
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
/**
|
|
544
|
+
*/ async concurrentBenchmark(operationName, operation, threadCount = 4, operationsPerThread = 10000) {
|
|
545
|
+
const workers = [];
|
|
546
|
+
const results = [];
|
|
547
|
+
for(let i = 0; i < threadCount; i++){
|
|
548
|
+
const worker = new Promise((resolve)=>{
|
|
549
|
+
const threadResults = [];
|
|
550
|
+
const startTime = performance.now() * 1000000;
|
|
551
|
+
for(let j = 0; j < operationsPerThread; j++){
|
|
552
|
+
const { duration } = this.measureOperation(operationName, operation);
|
|
553
|
+
threadResults.push(duration);
|
|
554
|
+
}
|
|
555
|
+
const endTime = performance.now() * 1000000;
|
|
556
|
+
resolve({
|
|
557
|
+
threadId: i,
|
|
558
|
+
results: threadResults,
|
|
559
|
+
totalTime: endTime - startTime,
|
|
560
|
+
throughput: operationsPerThread / ((endTime - startTime) / 1000000000)
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
workers.push(worker);
|
|
564
|
+
}
|
|
565
|
+
const threadResults = await Promise.all(workers);
|
|
566
|
+
return this.analyzeConcurrentResults(threadResults);
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
750
569
|
* Record performance sample
|
|
751
|
-
*/
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
/**
|
|
570
|
+
*/ recordSample(operationName, duration) {
|
|
571
|
+
if (!this.operationCounts.has(operationName)) {
|
|
572
|
+
this.operationCounts.set(operationName, []);
|
|
573
|
+
}
|
|
574
|
+
const samples = this.operationCounts.get(operationName);
|
|
575
|
+
samples.push(duration);
|
|
576
|
+
if (samples.length > 10000) {
|
|
577
|
+
samples.shift(); // Keep only recent samples
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
766
581
|
* Analyze concurrent benchmark results
|
|
767
|
-
*/
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
};
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/**
|
|
582
|
+
*/ analyzeConcurrentResults(threadResults) {
|
|
583
|
+
const allDurations = threadResults.flatMap((r)=>r.results);
|
|
584
|
+
allDurations.sort((a, b)=>a - b);
|
|
585
|
+
const totalThroughput = threadResults.reduce((sum, r)=>sum + r.throughput, 0);
|
|
586
|
+
return {
|
|
587
|
+
totalOperations: allDurations.length,
|
|
588
|
+
totalThroughput,
|
|
589
|
+
avgThroughputPerThread: totalThroughput / threadResults.length,
|
|
590
|
+
latencyStats: {
|
|
591
|
+
min: allDurations[0],
|
|
592
|
+
max: allDurations[allDurations.length - 1],
|
|
593
|
+
median: allDurations[Math.floor(allDurations.length / 2)],
|
|
594
|
+
p95: allDurations[Math.floor(allDurations.length * 0.95)],
|
|
595
|
+
p99: allDurations[Math.floor(allDurations.length * 0.99)],
|
|
596
|
+
p999: allDurations[Math.floor(allDurations.length * 0.999)],
|
|
597
|
+
mean: allDurations.reduce((a, b)=>a + b, 0) / allDurations.length
|
|
598
|
+
},
|
|
599
|
+
threadResults
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
792
603
|
* Generate performance report
|
|
793
|
-
*/
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
604
|
+
*/ generateReport() {
|
|
605
|
+
const report = {
|
|
606
|
+
timestamp: Date.now(),
|
|
607
|
+
operations: {}
|
|
608
|
+
};
|
|
609
|
+
for (const [operationName, samples] of this.operationCounts){
|
|
610
|
+
const sortedSamples = [
|
|
611
|
+
...samples
|
|
612
|
+
].sort((a, b)=>a - b);
|
|
613
|
+
report.operations[operationName] = {
|
|
614
|
+
sampleCount: samples.length,
|
|
615
|
+
min: sortedSamples[0],
|
|
616
|
+
max: sortedSamples[sortedSamples.length - 1],
|
|
617
|
+
median: sortedSamples[Math.floor(sortedSamples.length / 2)],
|
|
618
|
+
p95: sortedSamples[Math.floor(sortedSamples.length * 0.95)],
|
|
619
|
+
p99: sortedSamples[Math.floor(sortedSamples.length * 0.99)],
|
|
620
|
+
mean: samples.reduce((a, b)=>a + b, 0) / samples.length,
|
|
621
|
+
targetMet: {
|
|
622
|
+
read: sortedSamples[Math.floor(sortedSamples.length * 0.95)] < 100,
|
|
623
|
+
write: sortedSamples[Math.floor(sortedSamples.length * 0.95)] < 500 // <500ns p95
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
return report;
|
|
628
|
+
}
|
|
629
|
+
constructor(){
|
|
630
|
+
this.samples = new Array(100000);
|
|
631
|
+
this.sampleIndex = 0;
|
|
632
|
+
this.operationCounts = new Map();
|
|
633
|
+
}
|
|
634
|
+
}
|