@wenathlan/saddle 1.8.17 → 2.0.2
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/Dockerfile +1339 -0
- package/README.md +68 -22
- package/alternatives.ts +1218 -0
- package/biome.json +153 -0
- package/boards.json +1517 -0
- package/compute.ts +3144 -0
- package/cores.json +1801 -0
- package/dist/acquisition.d.ts +359 -0
- package/dist/acquisition.d.ts.map +1 -0
- package/dist/acquisition.js +629 -0
- package/dist/acquisition.js.map +1 -0
- package/dist/alternatives.d.ts +509 -0
- package/dist/alternatives.d.ts.map +1 -0
- package/dist/alternatives.js +951 -0
- package/dist/alternatives.js.map +1 -0
- package/dist/automation.d.ts +426 -0
- package/dist/automation.d.ts.map +1 -0
- package/dist/automation.js +561 -0
- package/dist/automation.js.map +1 -0
- package/dist/browser.d.ts +562 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +1057 -0
- package/dist/browser.js.map +1 -0
- package/dist/capacitor.config.d.ts +13 -0
- package/dist/capacitor.config.d.ts.map +1 -0
- package/dist/capacitor.config.js +26 -0
- package/dist/capacitor.config.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +111 -0
- package/dist/cli.js.map +1 -0
- package/dist/communication.d.ts +192 -0
- package/dist/communication.d.ts.map +1 -0
- package/dist/communication.js +418 -0
- package/dist/communication.js.map +1 -0
- package/dist/compute.d.ts +1161 -0
- package/dist/compute.d.ts.map +1 -0
- package/dist/compute.js +2273 -0
- package/dist/compute.js.map +1 -0
- package/dist/distribution.d.ts +529 -0
- package/dist/distribution.d.ts.map +1 -0
- package/dist/distribution.js +811 -0
- package/dist/distribution.js.map +1 -0
- package/dist/execution.d.ts +530 -0
- package/dist/execution.d.ts.map +1 -0
- package/dist/execution.js +761 -0
- package/dist/execution.js.map +1 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +60 -0
- package/dist/format.js.map +1 -0
- package/dist/foundation.d.ts +176 -0
- package/dist/foundation.d.ts.map +1 -0
- package/dist/foundation.js +309 -0
- package/dist/foundation.js.map +1 -0
- package/dist/index.d.ts +733 -122
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1018 -122
- package/dist/index.js.map +1 -1
- package/dist/integration.d.ts +236 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +236 -0
- package/dist/integration.js.map +1 -0
- package/dist/intelligence.d.ts +94 -0
- package/dist/intelligence.d.ts.map +1 -0
- package/dist/intelligence.js +145 -0
- package/dist/intelligence.js.map +1 -0
- package/dist/isolation.d.ts +129 -0
- package/dist/isolation.d.ts.map +1 -0
- package/dist/isolation.js +96 -0
- package/dist/isolation.js.map +1 -0
- package/dist/media.d.ts +344 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +986 -0
- package/dist/media.js.map +1 -0
- package/dist/modes.d.ts +359 -0
- package/dist/modes.d.ts.map +1 -0
- package/dist/modes.js +134 -0
- package/dist/modes.js.map +1 -0
- package/dist/{library/public.d.ts → operations.d.ts} +15 -1
- package/dist/operations.d.ts.map +1 -0
- package/dist/{library/public.js → operations.js} +18 -7
- package/dist/operations.js.map +1 -0
- package/dist/orchestrator.d.ts +1339 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +4308 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/performance.d.ts +416 -0
- package/dist/performance.d.ts.map +1 -0
- package/dist/performance.js +827 -0
- package/dist/performance.js.map +1 -0
- package/dist/quantum.d.ts +810 -0
- package/dist/quantum.d.ts.map +1 -0
- package/dist/quantum.js +2073 -0
- package/dist/quantum.js.map +1 -0
- package/dist/render.d.ts +381 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +1073 -0
- package/dist/render.js.map +1 -0
- package/dist/scheduler.d.ts +596 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +1259 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +501 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +1170 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/{server/node.js → server.js} +16 -2
- package/dist/server.js.map +1 -0
- package/dist/tiers.d.ts +1002 -0
- package/dist/tiers.d.ts.map +1 -0
- package/dist/tiers.js +2165 -0
- package/dist/tiers.js.map +1 -0
- package/dist/virtual.d.ts +641 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +1285 -0
- package/dist/virtual.js.map +1 -0
- package/dist/virtualcpu.d.ts +316 -0
- package/dist/virtualcpu.d.ts.map +1 -0
- package/dist/virtualcpu.js +1180 -0
- package/dist/virtualcpu.js.map +1 -0
- package/dist/virtualgpu.d.ts +345 -0
- package/dist/virtualgpu.d.ts.map +1 -0
- package/dist/virtualgpu.js +1000 -0
- package/dist/virtualgpu.js.map +1 -0
- package/dist/virtualization.d.ts +607 -0
- package/dist/virtualization.d.ts.map +1 -0
- package/dist/virtualization.js +1187 -0
- package/dist/virtualization.js.map +1 -0
- package/dist/virtualmemory.d.ts +818 -0
- package/dist/virtualmemory.d.ts.map +1 -0
- package/dist/virtualmemory.js +1796 -0
- package/dist/virtualmemory.js.map +1 -0
- package/dist/webscrape.d.ts +720 -0
- package/dist/webscrape.d.ts.map +1 -0
- package/dist/webscrape.js +2697 -0
- package/dist/webscrape.js.map +1 -0
- package/docker.config +769 -0
- package/docs/CONVERSA.txt +1523 -0
- package/docs/alternatives.md +499 -0
- package/docs/architecture-1.8.19.md +76 -0
- package/docs/architecture-1.8.19.mmd +33 -0
- package/docs/architecture-1.8.19.png +0 -0
- package/docs/architecture.md +355 -0
- package/docs/artifactavailability.md +6 -0
- package/docs/brancharchive-2026-08-18.md +18 -0
- package/docs/browser.md +7 -0
- package/docs/consolidation.md +70 -0
- package/docs/e2ugh-engine.md +528 -0
- package/{dist/examples/localjob.js → docs/example-localjob.ts} +3 -3
- package/{dist/examples/publicapi.js → docs/example-publicapi.ts} +2 -2
- package/docs/hardware.md +342 -0
- package/docs/optimization.md +126 -0
- package/docs/performance.md +499 -0
- package/docs/planning.1.8.18.md +94 -0
- package/docs/planning.1.8.19.md +49 -0
- package/docs/releasenotes-1.8.17.md +6 -0
- package/docs/releasenotes-1.8.18.md +32 -0
- package/docs/releasenotes-1.8.19.md +35 -0
- package/docs/research-1.8.18-isolation.md +43 -0
- package/docs/research-1.8.19-virtual-browser.md +27 -0
- package/docs/saddle.archive.1.8.17.tar.gz.gpg +0 -0
- package/docs/security.md +454 -0
- package/docs/todo-1.8.16.md +56 -1
- package/docs/todo-1.8.18.md +164 -0
- package/docs/todo-1.8.19.md +241 -0
- package/docs/viability.md +777 -0
- package/docs/virtualization.md +335 -0
- package/docs/web-duplicatecleanup.md +9 -0
- package/docs/web-ideas.md +106 -0
- package/docs/workflowimprovements-2026-08-19.md +70 -0
- package/gpumonitor.cpp +1543 -0
- package/gpus.json +2408 -0
- package/index.ts +1478 -0
- package/media.ts +1337 -0
- package/mttg.config +1549 -0
- package/orchestrator.ts +5462 -0
- package/package.json +304 -55
- package/passage.config +1331 -0
- package/performance.ts +1049 -0
- package/processors.json +2217 -0
- package/qemu.config +1062 -0
- package/qemubridge.py +1340 -0
- package/quantum.ts +2393 -0
- package/render.ts +1325 -0
- package/scheduler.ts +1600 -0
- package/security.ts +1449 -0
- package/tiers.ts +2871 -0
- package/tsconfig.json +29 -0
- package/virtualcpu.ts +1273 -0
- package/virtualgpu.ts +1181 -0
- package/virtualhardware.c +1011 -0
- package/virtualhardware.json +739 -0
- package/virtualization.ts +1628 -0
- package/virtualizationcore.cpp +4635 -0
- package/virtualmemory.ts +2303 -0
- package/vm.config.json +1910 -0
- package/{extension → web/extension}/manifest.json +1 -1
- package/web/readme.md +382 -0
- package/web/tsconfig.json +25 -0
- package/dist/adapters/forge.d.ts +0 -17
- package/dist/adapters/forge.d.ts.map +0 -1
- package/dist/adapters/forge.js +0 -19
- package/dist/adapters/forge.js.map +0 -1
- package/dist/adapters/forgejo.d.ts +0 -49
- package/dist/adapters/forgejo.d.ts.map +0 -1
- package/dist/adapters/forgejo.js +0 -8
- package/dist/adapters/forgejo.js.map +0 -1
- package/dist/adapters/github.d.ts +0 -12
- package/dist/adapters/github.d.ts.map +0 -1
- package/dist/adapters/github.js +0 -20
- package/dist/adapters/github.js.map +0 -1
- package/dist/adapters/gitlab.d.ts +0 -17
- package/dist/adapters/gitlab.d.ts.map +0 -1
- package/dist/adapters/gitlab.js +0 -10
- package/dist/adapters/gitlab.js.map +0 -1
- package/dist/adapters/huggingface.d.ts +0 -17
- package/dist/adapters/huggingface.d.ts.map +0 -1
- package/dist/adapters/huggingface.js +0 -6
- package/dist/adapters/huggingface.js.map +0 -1
- package/dist/adapters/socket.d.ts +0 -11
- package/dist/adapters/socket.d.ts.map +0 -1
- package/dist/adapters/socket.js +0 -17
- package/dist/adapters/socket.js.map +0 -1
- package/dist/adapters/transport.d.ts +0 -7
- package/dist/adapters/transport.d.ts.map +0 -1
- package/dist/adapters/transport.js +0 -36
- package/dist/adapters/transport.js.map +0 -1
- package/dist/ai/chunk.d.ts +0 -2
- package/dist/ai/chunk.d.ts.map +0 -1
- package/dist/ai/chunk.js +0 -36
- package/dist/ai/chunk.js.map +0 -1
- package/dist/ai/llmstxt.d.ts +0 -6
- package/dist/ai/llmstxt.d.ts.map +0 -1
- package/dist/ai/llmstxt.js +0 -12
- package/dist/ai/llmstxt.js.map +0 -1
- package/dist/ai/provenance.d.ts +0 -22
- package/dist/ai/provenance.d.ts.map +0 -1
- package/dist/ai/provenance.js +0 -25
- package/dist/ai/provenance.js.map +0 -1
- package/dist/ai/rag.d.ts +0 -26
- package/dist/ai/rag.d.ts.map +0 -1
- package/dist/ai/rag.js +0 -22
- package/dist/ai/rag.js.map +0 -1
- package/dist/ai/tokens.d.ts +0 -15
- package/dist/ai/tokens.d.ts.map +0 -1
- package/dist/ai/tokens.js +0 -9
- package/dist/ai/tokens.js.map +0 -1
- package/dist/api/auth.d.ts +0 -16
- package/dist/api/auth.d.ts.map +0 -1
- package/dist/api/auth.js +0 -19
- package/dist/api/auth.js.map +0 -1
- package/dist/api/contracts.d.ts +0 -28
- package/dist/api/contracts.d.ts.map +0 -1
- package/dist/api/contracts.js +0 -14
- package/dist/api/contracts.js.map +0 -1
- package/dist/api/control.d.ts +0 -10
- package/dist/api/control.d.ts.map +0 -1
- package/dist/api/control.js +0 -35
- package/dist/api/control.js.map +0 -1
- package/dist/api/http.d.ts +0 -7
- package/dist/api/http.d.ts.map +0 -1
- package/dist/api/http.js +0 -12
- package/dist/api/http.js.map +0 -1
- package/dist/api/rate.d.ts +0 -28
- package/dist/api/rate.d.ts.map +0 -1
- package/dist/api/rate.js +0 -36
- package/dist/api/rate.js.map +0 -1
- package/dist/api/security.d.ts +0 -12
- package/dist/api/security.d.ts.map +0 -1
- package/dist/api/security.js +0 -56
- package/dist/api/security.js.map +0 -1
- package/dist/api/service.d.ts +0 -5
- package/dist/api/service.d.ts.map +0 -1
- package/dist/api/service.js +0 -70
- package/dist/api/service.js.map +0 -1
- package/dist/apps/registry.d.ts +0 -33
- package/dist/apps/registry.d.ts.map +0 -1
- package/dist/apps/registry.js +0 -24
- package/dist/apps/registry.js.map +0 -1
- package/dist/binary/archive.d.ts +0 -27
- package/dist/binary/archive.d.ts.map +0 -1
- package/dist/binary/archive.js +0 -46
- package/dist/binary/archive.js.map +0 -1
- package/dist/binary/build.d.ts +0 -29
- package/dist/binary/build.d.ts.map +0 -1
- package/dist/binary/build.js +0 -17
- package/dist/binary/build.js.map +0 -1
- package/dist/binary/transform.d.ts +0 -70
- package/dist/binary/transform.d.ts.map +0 -1
- package/dist/binary/transform.js +0 -105
- package/dist/binary/transform.js.map +0 -1
- package/dist/bot/adapter.d.ts +0 -5
- package/dist/bot/adapter.d.ts.map +0 -1
- package/dist/bot/adapter.js +0 -11
- package/dist/bot/adapter.js.map +0 -1
- package/dist/bot/bot.d.ts +0 -28
- package/dist/bot/bot.d.ts.map +0 -1
- package/dist/bot/bot.js +0 -52
- package/dist/bot/bot.js.map +0 -1
- package/dist/bot/commands.d.ts +0 -8
- package/dist/bot/commands.d.ts.map +0 -1
- package/dist/bot/commands.js +0 -19
- package/dist/bot/commands.js.map +0 -1
- package/dist/bot/permissions.d.ts +0 -13
- package/dist/bot/permissions.d.ts.map +0 -1
- package/dist/bot/permissions.js +0 -16
- package/dist/bot/permissions.js.map +0 -1
- package/dist/browser/actions.d.ts +0 -33
- package/dist/browser/actions.d.ts.map +0 -1
- package/dist/browser/actions.js +0 -44
- package/dist/browser/actions.js.map +0 -1
- package/dist/browser/agent.d.ts +0 -21
- package/dist/browser/agent.d.ts.map +0 -1
- package/dist/browser/agent.js +0 -13
- package/dist/browser/agent.js.map +0 -1
- package/dist/browser/context.d.ts +0 -43
- package/dist/browser/context.d.ts.map +0 -1
- package/dist/browser/context.js +0 -54
- package/dist/browser/context.js.map +0 -1
- package/dist/browser/fingerprint.d.ts +0 -4
- package/dist/browser/fingerprint.d.ts.map +0 -1
- package/dist/browser/fingerprint.js +0 -12
- package/dist/browser/fingerprint.js.map +0 -1
- package/dist/browser/index.d.ts +0 -11
- package/dist/browser/index.d.ts.map +0 -1
- package/dist/browser/index.js +0 -11
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/playwright.d.ts +0 -11
- package/dist/browser/playwright.d.ts.map +0 -1
- package/dist/browser/playwright.js +0 -24
- package/dist/browser/playwright.js.map +0 -1
- package/dist/browser/recorder.d.ts +0 -21
- package/dist/browser/recorder.d.ts.map +0 -1
- package/dist/browser/recorder.js +0 -58
- package/dist/browser/recorder.js.map +0 -1
- package/dist/browser/session.d.ts +0 -14
- package/dist/browser/session.d.ts.map +0 -1
- package/dist/browser/session.js +0 -21
- package/dist/browser/session.js.map +0 -1
- package/dist/browser/snapshot.d.ts +0 -69
- package/dist/browser/snapshot.d.ts.map +0 -1
- package/dist/browser/snapshot.js +0 -133
- package/dist/browser/snapshot.js.map +0 -1
- package/dist/captcha/contract.d.ts +0 -35
- package/dist/captcha/contract.d.ts.map +0 -1
- package/dist/captcha/contract.js +0 -17
- package/dist/captcha/contract.js.map +0 -1
- package/dist/captcha/evidence.d.ts +0 -10
- package/dist/captcha/evidence.d.ts.map +0 -1
- package/dist/captcha/evidence.js +0 -9
- package/dist/captcha/evidence.js.map +0 -1
- package/dist/captcha/guard.d.ts +0 -23
- package/dist/captcha/guard.d.ts.map +0 -1
- package/dist/captcha/guard.js +0 -12
- package/dist/captcha/guard.js.map +0 -1
- package/dist/cli/main.d.ts +0 -4
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/main.js +0 -46
- package/dist/cli/main.js.map +0 -1
- package/dist/core/errors.d.ts +0 -84
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/errors.js +0 -54
- package/dist/core/errors.js.map +0 -1
- package/dist/core/events.d.ts +0 -9
- package/dist/core/events.d.ts.map +0 -1
- package/dist/core/events.js +0 -21
- package/dist/core/events.js.map +0 -1
- package/dist/core/hash.d.ts +0 -10
- package/dist/core/hash.d.ts.map +0 -1
- package/dist/core/hash.js +0 -82
- package/dist/core/hash.js.map +0 -1
- package/dist/core/ids.d.ts +0 -10
- package/dist/core/ids.d.ts.map +0 -1
- package/dist/core/ids.js +0 -15
- package/dist/core/ids.js.map +0 -1
- package/dist/delivery/manifest.d.ts +0 -35
- package/dist/delivery/manifest.d.ts.map +0 -1
- package/dist/delivery/manifest.js +0 -68
- package/dist/delivery/manifest.js.map +0 -1
- package/dist/deploy/index.d.ts +0 -6
- package/dist/deploy/index.d.ts.map +0 -1
- package/dist/deploy/index.js +0 -6
- package/dist/deploy/index.js.map +0 -1
- package/dist/dispatch/resumable.d.ts +0 -102
- package/dist/dispatch/resumable.d.ts.map +0 -1
- package/dist/dispatch/resumable.js +0 -64
- package/dist/dispatch/resumable.js.map +0 -1
- package/dist/dispatch/workflow.d.ts +0 -6
- package/dist/dispatch/workflow.d.ts.map +0 -1
- package/dist/dispatch/workflow.js +0 -37
- package/dist/dispatch/workflow.js.map +0 -1
- package/dist/domain/artifacts.d.ts +0 -12
- package/dist/domain/artifacts.d.ts.map +0 -1
- package/dist/domain/artifacts.js +0 -14
- package/dist/domain/artifacts.js.map +0 -1
- package/dist/domain/jobs.d.ts +0 -12
- package/dist/domain/jobs.d.ts.map +0 -1
- package/dist/domain/jobs.js +0 -20
- package/dist/domain/jobs.js.map +0 -1
- package/dist/domain/providers.d.ts +0 -10
- package/dist/domain/providers.d.ts.map +0 -1
- package/dist/domain/providers.js +0 -8
- package/dist/domain/providers.js.map +0 -1
- package/dist/domain/runtime.d.ts +0 -14
- package/dist/domain/runtime.d.ts.map +0 -1
- package/dist/domain/runtime.js +0 -10
- package/dist/domain/runtime.js.map +0 -1
- package/dist/domain/sessions.d.ts +0 -12
- package/dist/domain/sessions.d.ts.map +0 -1
- package/dist/domain/sessions.js +0 -57
- package/dist/domain/sessions.js.map +0 -1
- package/dist/examples/localjob.d.ts +0 -2
- package/dist/examples/localjob.d.ts.map +0 -1
- package/dist/examples/localjob.js.map +0 -1
- package/dist/examples/publicapi.d.ts +0 -2
- package/dist/examples/publicapi.d.ts.map +0 -1
- package/dist/examples/publicapi.js.map +0 -1
- package/dist/extension/build.d.ts +0 -9
- package/dist/extension/build.d.ts.map +0 -1
- package/dist/extension/build.js +0 -85
- package/dist/extension/build.js.map +0 -1
- package/dist/extension/content.d.ts +0 -6
- package/dist/extension/content.d.ts.map +0 -1
- package/dist/extension/content.js +0 -135
- package/dist/extension/content.js.map +0 -1
- package/dist/extension/index.d.ts +0 -7
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/index.js +0 -7
- package/dist/extension/index.js.map +0 -1
- package/dist/extension/pagebridge.d.ts +0 -6
- package/dist/extension/pagebridge.d.ts.map +0 -1
- package/dist/extension/pagebridge.js +0 -42
- package/dist/extension/pagebridge.js.map +0 -1
- package/dist/extension/permissions.d.ts +0 -26
- package/dist/extension/permissions.d.ts.map +0 -1
- package/dist/extension/permissions.js +0 -28
- package/dist/extension/permissions.js.map +0 -1
- package/dist/extension/popup.d.ts +0 -5
- package/dist/extension/popup.d.ts.map +0 -1
- package/dist/extension/popup.js +0 -26
- package/dist/extension/popup.js.map +0 -1
- package/dist/extension/protocol.d.ts +0 -58
- package/dist/extension/protocol.d.ts.map +0 -1
- package/dist/extension/protocol.js +0 -101
- package/dist/extension/protocol.js.map +0 -1
- package/dist/extension/serviceworker.d.ts +0 -25
- package/dist/extension/serviceworker.d.ts.map +0 -1
- package/dist/extension/serviceworker.js +0 -102
- package/dist/extension/serviceworker.js.map +0 -1
- package/dist/extension/worker.d.ts +0 -28
- package/dist/extension/worker.d.ts.map +0 -1
- package/dist/extension/worker.js +0 -22
- package/dist/extension/worker.js.map +0 -1
- package/dist/format/check.d.ts +0 -8
- package/dist/format/check.d.ts.map +0 -1
- package/dist/format/check.js +0 -38
- package/dist/format/check.js.map +0 -1
- package/dist/library/public.d.ts.map +0 -1
- package/dist/library/public.js.map +0 -1
- package/dist/mcp/browser.d.ts +0 -9
- package/dist/mcp/browser.d.ts.map +0 -1
- package/dist/mcp/browser.js +0 -13
- package/dist/mcp/browser.js.map +0 -1
- package/dist/mcp/server.d.ts +0 -35
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js +0 -40
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/transport.d.ts +0 -7
- package/dist/mcp/transport.d.ts.map +0 -1
- package/dist/mcp/transport.js +0 -17
- package/dist/mcp/transport.js.map +0 -1
- package/dist/memory/bridge.d.ts +0 -14
- package/dist/memory/bridge.d.ts.map +0 -1
- package/dist/memory/bridge.js +0 -16
- package/dist/memory/bridge.js.map +0 -1
- package/dist/memory/engine.d.ts +0 -38
- package/dist/memory/engine.d.ts.map +0 -1
- package/dist/memory/engine.js +0 -109
- package/dist/memory/engine.js.map +0 -1
- package/dist/memory/modes.d.ts +0 -43
- package/dist/memory/modes.d.ts.map +0 -1
- package/dist/memory/modes.js +0 -66
- package/dist/memory/modes.js.map +0 -1
- package/dist/memory/objects.d.ts +0 -21
- package/dist/memory/objects.d.ts.map +0 -1
- package/dist/memory/objects.js +0 -20
- package/dist/memory/objects.js.map +0 -1
- package/dist/memory/planner.d.ts +0 -66
- package/dist/memory/planner.d.ts.map +0 -1
- package/dist/memory/planner.js +0 -108
- package/dist/memory/planner.js.map +0 -1
- package/dist/memory/targets.d.ts +0 -78
- package/dist/memory/targets.d.ts.map +0 -1
- package/dist/memory/targets.js +0 -29
- package/dist/memory/targets.js.map +0 -1
- package/dist/memory/transforms.d.ts +0 -19
- package/dist/memory/transforms.d.ts.map +0 -1
- package/dist/memory/transforms.js +0 -14
- package/dist/memory/transforms.js.map +0 -1
- package/dist/modes/matrix.d.ts +0 -23
- package/dist/modes/matrix.d.ts.map +0 -1
- package/dist/modes/matrix.js +0 -18
- package/dist/modes/matrix.js.map +0 -1
- package/dist/modes/modes.d.ts +0 -33
- package/dist/modes/modes.d.ts.map +0 -1
- package/dist/modes/modes.js +0 -15
- package/dist/modes/modes.js.map +0 -1
- package/dist/modes/resolve.d.ts +0 -96
- package/dist/modes/resolve.d.ts.map +0 -1
- package/dist/modes/resolve.js +0 -48
- package/dist/modes/resolve.js.map +0 -1
- package/dist/observability/metrics.d.ts +0 -14
- package/dist/observability/metrics.d.ts.map +0 -1
- package/dist/observability/metrics.js +0 -18
- package/dist/observability/metrics.js.map +0 -1
- package/dist/packager/manifest.d.ts +0 -66
- package/dist/packager/manifest.d.ts.map +0 -1
- package/dist/packager/manifest.js +0 -94
- package/dist/packager/manifest.js.map +0 -1
- package/dist/packager/publish.d.ts +0 -51
- package/dist/packager/publish.d.ts.map +0 -1
- package/dist/packager/publish.js +0 -18
- package/dist/packager/publish.js.map +0 -1
- package/dist/packager/targetcli.d.ts +0 -7
- package/dist/packager/targetcli.d.ts.map +0 -1
- package/dist/packager/targetcli.js +0 -22
- package/dist/packager/targetcli.js.map +0 -1
- package/dist/persistence/adapter.d.ts +0 -5
- package/dist/persistence/adapter.d.ts.map +0 -1
- package/dist/persistence/adapter.js +0 -11
- package/dist/persistence/adapter.js.map +0 -1
- package/dist/persistence/drizzle.d.ts +0 -2
- package/dist/persistence/drizzle.d.ts.map +0 -1
- package/dist/persistence/drizzle.js +0 -12
- package/dist/persistence/drizzle.js.map +0 -1
- package/dist/persistence/memory.d.ts +0 -2
- package/dist/persistence/memory.d.ts.map +0 -1
- package/dist/persistence/memory.js +0 -27
- package/dist/persistence/memory.js.map +0 -1
- package/dist/persistence/migrations.d.ts +0 -19
- package/dist/persistence/migrations.d.ts.map +0 -1
- package/dist/persistence/migrations.js +0 -13
- package/dist/persistence/migrations.js.map +0 -1
- package/dist/persistence/prisma.d.ts +0 -2
- package/dist/persistence/prisma.d.ts.map +0 -1
- package/dist/persistence/prisma.js +0 -25
- package/dist/persistence/prisma.js.map +0 -1
- package/dist/persistence/schema.d.ts +0 -63
- package/dist/persistence/schema.d.ts.map +0 -1
- package/dist/persistence/schema.js +0 -28
- package/dist/persistence/schema.js.map +0 -1
- package/dist/persistence/sql.d.ts +0 -3
- package/dist/persistence/sql.d.ts.map +0 -1
- package/dist/persistence/sql.js +0 -37
- package/dist/persistence/sql.js.map +0 -1
- package/dist/protocol/blocks.d.ts +0 -10
- package/dist/protocol/blocks.d.ts.map +0 -1
- package/dist/protocol/blocks.js +0 -26
- package/dist/protocol/blocks.js.map +0 -1
- package/dist/protocol/json.d.ts +0 -6
- package/dist/protocol/json.d.ts.map +0 -1
- package/dist/protocol/json.js +0 -6
- package/dist/protocol/json.js.map +0 -1
- package/dist/protocol/ndjson.d.ts +0 -3
- package/dist/protocol/ndjson.d.ts.map +0 -1
- package/dist/protocol/ndjson.js +0 -20
- package/dist/protocol/ndjson.js.map +0 -1
- package/dist/protocol/sse.d.ts +0 -7
- package/dist/protocol/sse.d.ts.map +0 -1
- package/dist/protocol/sse.js +0 -25
- package/dist/protocol/sse.js.map +0 -1
- package/dist/proxy/pool.d.ts +0 -9
- package/dist/proxy/pool.d.ts.map +0 -1
- package/dist/proxy/pool.js +0 -27
- package/dist/proxy/pool.js.map +0 -1
- package/dist/queue/idempotency.d.ts +0 -10
- package/dist/queue/idempotency.d.ts.map +0 -1
- package/dist/queue/idempotency.js +0 -13
- package/dist/queue/idempotency.js.map +0 -1
- package/dist/queue/persistent.d.ts +0 -14
- package/dist/queue/persistent.d.ts.map +0 -1
- package/dist/queue/persistent.js +0 -66
- package/dist/queue/persistent.js.map +0 -1
- package/dist/queue/queue.d.ts +0 -7
- package/dist/queue/queue.d.ts.map +0 -1
- package/dist/queue/queue.js +0 -55
- package/dist/queue/queue.js.map +0 -1
- package/dist/queue/saga.d.ts +0 -5
- package/dist/queue/saga.d.ts.map +0 -1
- package/dist/queue/saga.js +0 -20
- package/dist/queue/saga.js.map +0 -1
- package/dist/release/assets.d.ts +0 -144
- package/dist/release/assets.d.ts.map +0 -1
- package/dist/release/assets.js +0 -157
- package/dist/release/assets.js.map +0 -1
- package/dist/release/evidence.d.ts +0 -92
- package/dist/release/evidence.d.ts.map +0 -1
- package/dist/release/evidence.js +0 -148
- package/dist/release/evidence.js.map +0 -1
- package/dist/release/verify.d.ts +0 -12
- package/dist/release/verify.d.ts.map +0 -1
- package/dist/release/verify.js +0 -112
- package/dist/release/verify.js.map +0 -1
- package/dist/runners/chain.d.ts +0 -125
- package/dist/runners/chain.d.ts.map +0 -1
- package/dist/runners/chain.js +0 -95
- package/dist/runners/chain.js.map +0 -1
- package/dist/runners/health.d.ts +0 -36
- package/dist/runners/health.d.ts.map +0 -1
- package/dist/runners/health.js +0 -26
- package/dist/runners/health.js.map +0 -1
- package/dist/runners/heartbeat.d.ts +0 -23
- package/dist/runners/heartbeat.d.ts.map +0 -1
- package/dist/runners/heartbeat.js +0 -29
- package/dist/runners/heartbeat.js.map +0 -1
- package/dist/runners/inprocess.d.ts +0 -17
- package/dist/runners/inprocess.d.ts.map +0 -1
- package/dist/runners/inprocess.js +0 -20
- package/dist/runners/inprocess.js.map +0 -1
- package/dist/runners/scheduler.d.ts +0 -5
- package/dist/runners/scheduler.d.ts.map +0 -1
- package/dist/runners/scheduler.js +0 -19
- package/dist/runners/scheduler.js.map +0 -1
- package/dist/runtime/abort.d.ts +0 -8
- package/dist/runtime/abort.d.ts.map +0 -1
- package/dist/runtime/abort.js +0 -13
- package/dist/runtime/abort.js.map +0 -1
- package/dist/runtime/compatibility.d.ts +0 -37
- package/dist/runtime/compatibility.d.ts.map +0 -1
- package/dist/runtime/compatibility.js +0 -10
- package/dist/runtime/compatibility.js.map +0 -1
- package/dist/runtime/detect.d.ts +0 -13
- package/dist/runtime/detect.d.ts.map +0 -1
- package/dist/runtime/detect.js +0 -18
- package/dist/runtime/detect.js.map +0 -1
- package/dist/runtime/engine.d.ts +0 -20
- package/dist/runtime/engine.d.ts.map +0 -1
- package/dist/runtime/engine.js +0 -61
- package/dist/runtime/engine.js.map +0 -1
- package/dist/runtime/retry.d.ts +0 -19
- package/dist/runtime/retry.d.ts.map +0 -1
- package/dist/runtime/retry.js +0 -54
- package/dist/runtime/retry.js.map +0 -1
- package/dist/runtime/worker.d.ts +0 -10
- package/dist/runtime/worker.d.ts.map +0 -1
- package/dist/runtime/worker.js +0 -25
- package/dist/runtime/worker.js.map +0 -1
- package/dist/scrape/cache.d.ts +0 -45
- package/dist/scrape/cache.d.ts.map +0 -1
- package/dist/scrape/cache.js +0 -45
- package/dist/scrape/cache.js.map +0 -1
- package/dist/scrape/crawl.d.ts +0 -47
- package/dist/scrape/crawl.d.ts.map +0 -1
- package/dist/scrape/crawl.js +0 -114
- package/dist/scrape/crawl.js.map +0 -1
- package/dist/scrape/extract.d.ts +0 -63
- package/dist/scrape/extract.d.ts.map +0 -1
- package/dist/scrape/extract.js +0 -47
- package/dist/scrape/extract.js.map +0 -1
- package/dist/scrape/normalize.d.ts +0 -52
- package/dist/scrape/normalize.d.ts.map +0 -1
- package/dist/scrape/normalize.js +0 -102
- package/dist/scrape/normalize.js.map +0 -1
- package/dist/scrape/robots.d.ts +0 -37
- package/dist/scrape/robots.d.ts.map +0 -1
- package/dist/scrape/robots.js +0 -71
- package/dist/scrape/robots.js.map +0 -1
- package/dist/scrape/schema.d.ts +0 -23
- package/dist/scrape/schema.d.ts.map +0 -1
- package/dist/scrape/schema.js +0 -92
- package/dist/scrape/schema.js.map +0 -1
- package/dist/scrape/scraper.d.ts +0 -6
- package/dist/scrape/scraper.d.ts.map +0 -1
- package/dist/scrape/scraper.js +0 -46
- package/dist/scrape/scraper.js.map +0 -1
- package/dist/scrape/semantic.d.ts +0 -25
- package/dist/scrape/semantic.d.ts.map +0 -1
- package/dist/scrape/semantic.js +0 -27
- package/dist/scrape/semantic.js.map +0 -1
- package/dist/server/node.d.ts +0 -7
- package/dist/server/node.d.ts.map +0 -1
- package/dist/server/node.js.map +0 -1
- package/dist/sessions/file.d.ts +0 -25
- package/dist/sessions/file.d.ts.map +0 -1
- package/dist/sessions/file.js +0 -13
- package/dist/sessions/file.js.map +0 -1
- package/dist/sessions/replay.d.ts +0 -9
- package/dist/sessions/replay.d.ts.map +0 -1
- package/dist/sessions/replay.js +0 -70
- package/dist/sessions/replay.js.map +0 -1
- package/dist/sessions/store.d.ts +0 -25
- package/dist/sessions/store.d.ts.map +0 -1
- package/dist/sessions/store.js +0 -13
- package/dist/sessions/store.js.map +0 -1
- package/dist/storage/adapter.d.ts +0 -5
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js +0 -11
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/cache.d.ts +0 -23
- package/dist/storage/cache.d.ts.map +0 -1
- package/dist/storage/cache.js +0 -79
- package/dist/storage/cache.js.map +0 -1
- package/dist/storage/checksum.d.ts +0 -3
- package/dist/storage/checksum.d.ts.map +0 -1
- package/dist/storage/checksum.js +0 -19
- package/dist/storage/checksum.js.map +0 -1
- package/dist/storage/chunked.d.ts +0 -21
- package/dist/storage/chunked.d.ts.map +0 -1
- package/dist/storage/chunked.js +0 -67
- package/dist/storage/chunked.js.map +0 -1
- package/dist/storage/content.d.ts +0 -24
- package/dist/storage/content.d.ts.map +0 -1
- package/dist/storage/content.js +0 -44
- package/dist/storage/content.js.map +0 -1
- package/dist/storage/filehosting.d.ts +0 -2
- package/dist/storage/filehosting.d.ts.map +0 -1
- package/dist/storage/filehosting.js +0 -24
- package/dist/storage/filehosting.js.map +0 -1
- package/dist/storage/githubcontents.d.ts +0 -2
- package/dist/storage/githubcontents.d.ts.map +0 -1
- package/dist/storage/githubcontents.js +0 -29
- package/dist/storage/githubcontents.js.map +0 -1
- package/dist/storage/index.d.ts +0 -12
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -12
- package/dist/storage/index.js.map +0 -1
- package/dist/storage/local.d.ts +0 -2
- package/dist/storage/local.d.ts.map +0 -1
- package/dist/storage/local.js +0 -72
- package/dist/storage/local.js.map +0 -1
- package/dist/storage/memory.d.ts +0 -6
- package/dist/storage/memory.d.ts.map +0 -1
- package/dist/storage/memory.js +0 -36
- package/dist/storage/memory.js.map +0 -1
- package/dist/storage/pool.d.ts +0 -95
- package/dist/storage/pool.d.ts.map +0 -1
- package/dist/storage/pool.js +0 -202
- package/dist/storage/pool.js.map +0 -1
- package/dist/storage/s3compatible.d.ts +0 -3
- package/dist/storage/s3compatible.d.ts.map +0 -1
- package/dist/storage/s3compatible.js +0 -70
- package/dist/storage/s3compatible.js.map +0 -1
- package/dist/storage/sync.d.ts +0 -47
- package/dist/storage/sync.d.ts.map +0 -1
- package/dist/storage/sync.js +0 -75
- package/dist/storage/sync.js.map +0 -1
- package/dist/surfaces/adapters.d.ts +0 -97
- package/dist/surfaces/adapters.d.ts.map +0 -1
- package/dist/surfaces/adapters.js +0 -50
- package/dist/surfaces/adapters.js.map +0 -1
- package/dist/surfaces/controls.d.ts +0 -18
- package/dist/surfaces/controls.d.ts.map +0 -1
- package/dist/surfaces/controls.js +0 -45
- package/dist/surfaces/controls.js.map +0 -1
- package/dist/surfaces/manifest.d.ts +0 -68
- package/dist/surfaces/manifest.d.ts.map +0 -1
- package/dist/surfaces/manifest.js +0 -42
- package/dist/surfaces/manifest.js.map +0 -1
- package/dist/surfaces/n8n.d.ts +0 -25
- package/dist/surfaces/n8n.d.ts.map +0 -1
- package/dist/surfaces/n8n.js +0 -31
- package/dist/surfaces/n8n.js.map +0 -1
- package/dist/surfaces/operations.d.ts +0 -32
- package/dist/surfaces/operations.d.ts.map +0 -1
- package/dist/surfaces/operations.js +0 -53
- package/dist/surfaces/operations.js.map +0 -1
- package/dist/surfaces/requirements.d.ts +0 -29
- package/dist/surfaces/requirements.d.ts.map +0 -1
- package/dist/surfaces/requirements.js +0 -50
- package/dist/surfaces/requirements.js.map +0 -1
- package/dist/surfaces/targets.d.ts +0 -196
- package/dist/surfaces/targets.d.ts.map +0 -1
- package/dist/surfaces/targets.js +0 -27
- package/dist/surfaces/targets.js.map +0 -1
- package/dist/webhook/delivery.d.ts +0 -18
- package/dist/webhook/delivery.d.ts.map +0 -1
- package/dist/webhook/delivery.js +0 -36
- package/dist/webhook/delivery.js.map +0 -1
- package/dist/webhook/receiver.d.ts +0 -26
- package/dist/webhook/receiver.d.ts.map +0 -1
- package/dist/webhook/receiver.js +0 -24
- package/dist/webhook/receiver.js.map +0 -1
- package/dist/webhook/signature.d.ts +0 -3
- package/dist/webhook/signature.d.ts.map +0 -1
- package/dist/webhook/signature.js +0 -7
- package/dist/webhook/signature.js.map +0 -1
- package/dist/workflow/manifest.d.ts +0 -22
- package/dist/workflow/manifest.d.ts.map +0 -1
- package/dist/workflow/manifest.js +0 -21
- package/dist/workflow/manifest.js.map +0 -1
- package/dist/workflow/registry.d.ts +0 -7
- package/dist/workflow/registry.d.ts.map +0 -1
- package/dist/workflow/registry.js +0 -18
- package/dist/workflow/registry.js.map +0 -1
- package/dist/workflow/templates.d.ts +0 -6
- package/dist/workflow/templates.d.ts.map +0 -1
- package/dist/workflow/templates.js +0 -18
- package/dist/workflow/templates.js.map +0 -1
- package/dist/workflow/triggers.d.ts +0 -64
- package/dist/workflow/triggers.d.ts.map +0 -1
- package/dist/workflow/triggers.js +0 -99
- package/dist/workflow/triggers.js.map +0 -1
- package/docs/logs/.gitkeep +0 -0
- package/docs/plans/00.index.md +0 -50
- package/docs/plans/01.architecture.md +0 -86
- package/docs/plans/02.research.computer.use.md +0 -58
- package/docs/plans/03.research.captcha.bypass.md +0 -68
- package/docs/plans/04.research.sandbox.ai.md +0 -52
- package/docs/plans/05.capture.platform.md +0 -57
- package/docs/plans/06.dependencies.md +0 -97
- package/docs/plans/07.captcha.test.page.md +0 -41
- package/docs/plans/08.production.infra.md +0 -70
- package/docs/plans/09.database.schema.md +0 -121
- package/docs/plans/10.cloudinary.storage.md +0 -57
- package/docs/plans/11.movement.logs.json.md +0 -72
- package/docs/plans/12.research.atlas.agent.browser.md +0 -79
- package/docs/plans/13.research.anti.detection.md +0 -898
- package/docs/plans/14.research.proxy.md +0 -1495
- package/docs/plans/15.research.retry.rate.limit.md +0 -1958
- package/docs/plans/16.research.crawling.md +0 -1417
- package/docs/plans/17.research.caching.md +0 -1610
- package/docs/plans/18.research.content.extraction.md +0 -1952
- package/docs/plans/19.research.errors.events.md +0 -1523
- package/docs/plans/20.research.zod.validation.md +0 -1350
- package/docs/plans/21.research.batch.concurrency.md +0 -1888
- package/docs/plans/22.research.universal.runtime.md +0 -944
- package/docs/plans/23.research.ai.integration.md +0 -1465
- package/docs/plans/24.research.memory.persistence.md +0 -1979
- package/docs/plans/25.research.server.api.md +0 -342
- package/docs/plans/26.research.compilation.md +0 -249
- package/docs/plans/27.research.html.parsing.md +0 -251
- package/docs/plans/28.action.plan.md +0 -50
- package/docs/plans/29.api.reference.md +0 -174
- package/docs/plans/30.architecture.plan.md +0 -94
- package/docs/plans/31.auditoria.dados.md +0 -163
- package/docs/plans/32.bots.automacao.computacional.md +0 -214
- package/docs/plans/33.bots.codigo.revisao.md +0 -220
- package/docs/plans/34.bots.seguranca.cicd.md +0 -366
- package/docs/plans/35.comparativo.concorrencia.md +0 -464
- package/docs/plans/36.computational.memory.md +0 -340
- package/docs/plans/37.deploystrategy.md +0 -394
- package/docs/plans/38.flow.md +0 -155
- package/docs/plans/39.multi.platform.bot.md +0 -252
- package/docs/plans/40.npm.publish.md +0 -250
- package/docs/plans/41.o.que.falta.md +0 -407
- package/docs/plans/42.pesquisa.concorrencia.md +0 -721
- package/docs/plans/43.plan.universal.architecture.md +0 -496
- package/docs/plans/44.reference.md +0 -100
- package/docs/plans/45.robotarchitecture.md +0 -237
- package/docs/plans/46.scdnintegration.md +0 -284
- package/docs/plans/47.multiforge.readme.md +0 -129
- package/docs/plans/48.theory.v4.repo.os.md +0 -152
- package/docs/plans/49.third.party.infra.md +0 -12
- package/docs/plans/50.file.as.compute.md +0 -39
- package/docs/plans/51.architecture.virtual.processor.md +0 -80
- package/docs/plans/52.manifesto.v8.md +0 -11
- package/docs/plans/58.cdn.list.md +0 -23
- package/docs/plans/59.sql.frameworks.md +0 -33
- package/docs/plans/60.sql.thirdparty.md +0 -26
- package/docs/plans/61.objective.multiforge.md +0 -63
- package/docs/plans/62.huggingface.upload.md +0 -26
- package/docs/plans/63.kaggle.upload.md +0 -24
- package/docs/plans/64.npm.storage.md +0 -30
- package/docs/plans/65.rclone.terabox.md +0 -32
- package/docs/plans/66.buckets.and.models.todo.md +0 -14
- package/docs/plans/67.database.todo.md +0 -13
- package/docs/plans/68.deploy.packages.todo.md +0 -12
- package/docs/plans/69.report.human.operator.md +0 -133
- package/docs/plans/70.report.brain2qwerty.ems.md +0 -135
- package/docs/plans/71.report.hd.infinito.vram.md +0 -155
- package/docs/plans/72.plan.hd.infinito.node.md +0 -146
- package/docs/plans/73.plan.scifi.repos.md +0 -125
- package/docs/plans/74.000.manifesto.v8.flat.2..md +0 -11
- package/docs/plans/README.md +0 -489
- package/docs/plans/aggregate_platforms.mjs +0 -146
- package/docs/plans/examplesession.json +0 -36
- package/docs/plans/missing-facts.md +0 -192
- package/docs/plans/models.md +0 -64
- package/docs/plans/organize.cjs +0 -270
- package/docs/plans/platforms.md +0 -2887
- package/docs/plans/sites.md +0 -31322
- package/docs/sources/farm.py +0 -117
- package/docs/sources/html/saddle1.html +0 -132
- package/docs/sources/html/saddle2.html +0 -157
- package/docs/sources/html/saddle3.html +0 -119
- package/docs/sources/html/saddle4.html +0 -144
- package/docs/sources/html/saddle5.html +0 -72
- package/docs/sources/html/saddle6.html +0 -171
- package/docs/sources/html/saddle7.html +0 -236
- package/docs/sources/saddle.ts +0 -74
- package/docs/sources/schema.prisma +0 -88
- package/docs/sources/script.sh +0 -64
- package/docs/sources/workflows.yml +0 -458
- package/docs/talks1/_body.txt +0 -14
- package/docs/talks1/_index.md +0 -15
- package/docs/talks1/_screenshot.png +0 -0
- package/docs/talks1/assistant-01.md +0 -5
- package/docs/talks1/assistant-02.md +0 -5
- package/docs/talks1/assistant-03.md +0 -531
- package/docs/talks1/assistant-04.md +0 -26
- package/docs/talks1/assistant-05.md +0 -774
- package/docs/talks1/assistant-06.md +0 -1718
- package/docs/talks1/scrape-share.cjs +0 -185
- package/docs/talks1/scrape-share.ts +0 -183
- package/docs/talks1/user-01.md +0 -3
- package/docs/talks1/user-02.md +0 -3
- package/docs/talks1/user-03.md +0 -88
- package/docs/talks1/user-04.md +0 -3
- package/docs/talks1/user-05.md +0 -3
- package/docs/talks1/user-06.md +0 -88
- package/docs/talks1/user-07.md +0 -88
- package/docs/talks2/_body.txt +0 -14
- package/docs/talks2/_index.md +0 -16
- package/docs/talks2/_screenshot.png +0 -0
- package/docs/talks2/assistant-01.md +0 -5
- package/docs/talks2/assistant-02.md +0 -5
- package/docs/talks2/assistant-03.md +0 -424
- package/docs/talks2/assistant-04.md +0 -598
- package/docs/talks2/assistant-05.md +0 -1280
- package/docs/talks2/assistant-06.md +0 -1227
- package/docs/talks2/assistant-07.md +0 -1252
- package/docs/talks2/user-01.md +0 -3
- package/docs/talks2/user-02.md +0 -3
- package/docs/talks2/user-03.md +0 -88
- package/docs/talks2/user-04.md +0 -88
- package/docs/talks2/user-05.md +0 -88
- package/docs/talks2/user-06.md +0 -88
- package/docs/talks2/user-07.md +0 -3
- package/docs/talks3/_body.txt +0 -467
- package/docs/talks3/_index.md +0 -10
- package/docs/talks3/_screenshot.png +0 -0
- package/docs/talks3/assistant-01.md +0 -417
- package/docs/talks3/assistant-02.md +0 -417
- package/docs/talks3/assistant-03.md +0 -29
- package/docs/talks3/assistant-04.md +0 -727
- package/docs/talks3/user-01.md +0 -88
- package/docs/talks3/user-02.md +0 -88
- package/docs/talks3/user-03.md +0 -3
- package/docs/talks3/user-04.md +0 -3
- package/docs/talks4/_body.txt +0 -14
- package/docs/talks4/_index.md +0 -12
- package/docs/talks4/_screenshot.png +0 -0
- package/docs/talks4/assistant-01.md +0 -5
- package/docs/talks4/assistant-02.md +0 -5
- package/docs/talks4/assistant-03.md +0 -35
- package/docs/talks4/assistant-04.md +0 -512
- package/docs/talks4/assistant-05.md +0 -599
- package/docs/talks4/user-01.md +0 -3
- package/docs/talks4/user-02.md +0 -3
- package/docs/talks4/user-03.md +0 -88
- package/docs/talks4/user-04.md +0 -88
- package/docs/talks4/user-05.md +0 -7
- package/docs/talks5/_body.txt +0 -14
- package/docs/talks5/_index.md +0 -13
- package/docs/talks5/_screenshot.png +0 -0
- package/docs/talks5/assistant-01.md +0 -5
- package/docs/talks5/assistant-02.md +0 -5
- package/docs/talks5/assistant-03.md +0 -690
- package/docs/talks5/assistant-04.md +0 -758
- package/docs/talks5/assistant-05.md +0 -974
- package/docs/talks5/user-01.md +0 -3
- package/docs/talks5/user-02.md +0 -3
- package/docs/talks5/user-03.md +0 -105
- package/docs/talks5/user-04.md +0 -105
- package/docs/talks5/user-05.md +0 -63
- package/docs/talks5/user-06.md +0 -105
- package/docs/talks6/_body.txt +0 -14
- package/docs/talks6/_index.md +0 -9
- package/docs/talks6/_screenshot.png +0 -0
- package/docs/talks6/assistant-01.md +0 -5
- package/docs/talks6/assistant-02.md +0 -5
- package/docs/talks6/assistant-03.md +0 -1499
- package/docs/talks6/user-01.md +0 -3
- package/docs/talks6/user-02.md +0 -3
- package/docs/talks6/user-03.md +0 -88
- package/docs/talks6/user-04.md +0 -88
- package/docs/talks7/_body.txt +0 -14
- package/docs/talks7/_index.md +0 -10
- package/docs/talks7/_screenshot.png +0 -0
- package/docs/talks7/assistant-01.md +0 -5
- package/docs/talks7/assistant-02.md +0 -5
- package/docs/talks7/assistant-03.md +0 -523
- package/docs/talks7/assistant-04.md +0 -617
- package/docs/talks7/user-01.md +0 -3
- package/docs/talks7/user-02.md +0 -3
- package/docs/talks7/user-03.md +0 -105
- package/docs/talks7/user-04.md +0 -67
- package/docs/talks8/conversa1.txt +0 -1322
- package/docs/talks8/conversa2.txt +0 -237
- package/docs/talks9/Beyond the Obvious_ 50 Plataformas Auto-Hospedadas de Forja de C/303/263digo para Al/303/251m de Gitea e GitLab.md" +0 -174
- package/docs/talks9/De NPM a Multi-Linguagem_ Uma Arquitetura T/303/251cnica para a Execu/303/247/303/243o Integrada de C/303/263digo no Ecossistema Node.js.md" +0 -59
- package/docs/talks9/De NPM a VMs Virtuais_ Uma An/303/241lise Arquitet/303/264nica para a Realiza/303/247/303/243o do Ciclo de Vida do Projeto SADDLE.md" +0 -91
- package/docs/talks9/Mapeamento da Engrenagem Computacional_ Uma Arquitetura para Execu/303/247/303/243o Isolada e Persist/303/252ncia em Ambientes Distribu/303/255dos.md" +0 -116
- package/docs/talks9/O Cen/303/241rio Pr/303/241tico do SADDLE_ Uma An/303/241lise de Viabilidade e Modelo de Ciclo de Vida Integrado.md" +0 -128
- package/docs/talks9/README (2).md +0 -489
- package/docs/talks9/README.md +0 -198
- package/docs/talks9/Viabilidade do Saddle_ Uma An/303/241lise T/303/251cnica da Transforma/303/247/303/243o de Armazenamento Remoto em Mem/303/263ria Computacional.md" +0 -80
- package/docs/talks9/conversa.txt +0 -544
- package/docs/talks9/other (2).md +0 -39
- package/docs/talks9/other.md +0 -57
- package/docs/talks9/outro.txt +0 -24
- /package/{extension/README.md → docs/extension.md} +0 -0
package/performance.ts
ADDED
|
@@ -0,0 +1,1049 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* performance.ts - Virtual Hardware Engine v5
|
|
3
|
+
*
|
|
4
|
+
* Seven composable optimization layers plus a measurement harness: percentile
|
|
5
|
+
* metrics (p50/p95/p99), regression detection and profile mode. Every layer
|
|
6
|
+
* emits a concrete patch (environment variables, process arguments, docker
|
|
7
|
+
* flags, planned kernel writes) so the same code drives local runs, CI jobs
|
|
8
|
+
* and documentation.
|
|
9
|
+
*
|
|
10
|
+
* Layer index:
|
|
11
|
+
* 1. cpu - AVX-512 vector width, LP thread saturation, OMP presets
|
|
12
|
+
* 2. gpu - Rusticl OpenCL 3.1 virtual identity, lavapipe Vulkan 1.4, LP_PERF flags
|
|
13
|
+
* 3. memory - unlimited swap, 2g shm, overcommit, KSM, 1G huge pages, tmpfs cache
|
|
14
|
+
* 4. microvm - Firecracker warm pool (3-5ms restores, 150 VMs/s, <5 MiB per VM)
|
|
15
|
+
* 5. tcg - QEMU 11.1 MTTCG, thread=multi, tb-size 1024, EPYC-v5, nitro accel
|
|
16
|
+
* 6. build - buildx gha cache (103s to 25s measured), multi-stage, LLVM -O3
|
|
17
|
+
* 7. network - keepalive, connection pooling, TAP pre-setup
|
|
18
|
+
*
|
|
19
|
+
* Related contexts covered by this file (25):
|
|
20
|
+
* LLVMpipe, Gallivm, AVX-512, MR !17813, LP_MAX_THREADS, MR 31551, OpenMP,
|
|
21
|
+
* Rusticl, OpenCL 3.1, RUSTICL_DEVICE_TYPE, lavapipe, Vulkan 1.4, LP_PERF,
|
|
22
|
+
* Docker memory-swap, ShmSize, vm.overcommit_memory, KSM, huge pages, tmpfs,
|
|
23
|
+
* Firecracker snapshots, QEMU MTTCG, buildx type=gha, LLVM -O3 -flto, undici
|
|
24
|
+
* keepalive, TAP/tun devices.
|
|
25
|
+
*
|
|
26
|
+
* Module rules: no emoji, JSDoc in English, third-person voice, lowercase
|
|
27
|
+
* identifiers, `using`/`satisfies`/`#private` modern TypeScript, node:* imports
|
|
28
|
+
* first, try/catch on every fallible path, no hardcoded localhost endpoints.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { randomInt } from 'node:crypto';
|
|
32
|
+
import { EventEmitter } from 'node:events';
|
|
33
|
+
import { performance } from 'node:perf_hooks';
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Layer model
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
/** Hardware facts a layer tunes against. */
|
|
40
|
+
export interface LayerTarget {
|
|
41
|
+
readonly cpus: number;
|
|
42
|
+
readonly memoryGb: number;
|
|
43
|
+
readonly gpus: number;
|
|
44
|
+
readonly headless: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Concrete output of applying one layer to one target. */
|
|
48
|
+
export interface LayerPatch {
|
|
49
|
+
readonly layer: PerformanceLayerId;
|
|
50
|
+
readonly env: Readonly<Record<string, string>>;
|
|
51
|
+
readonly args: readonly string[];
|
|
52
|
+
readonly dockerArgs: readonly string[];
|
|
53
|
+
readonly kernelWrites: readonly { path: string; content: string }[];
|
|
54
|
+
readonly mounts: readonly string[];
|
|
55
|
+
readonly notes: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Identifies one of the seven tuning layers (cpu, gpu, memory, microvm,
|
|
60
|
+
* tcg, build, network) addressed by the performance engine.
|
|
61
|
+
*/
|
|
62
|
+
export type PerformanceLayerId = 'cpu' | 'gpu' | 'memory' | 'microvm' | 'tcg' | 'build' | 'network';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Contract every tuning layer implements: an id, a human title, the file
|
|
66
|
+
* contexts the layer contributes to and the apply() that turns one target
|
|
67
|
+
* into a concrete patch.
|
|
68
|
+
*/
|
|
69
|
+
export interface PerformanceLayer {
|
|
70
|
+
readonly id: PerformanceLayerId;
|
|
71
|
+
readonly title: string;
|
|
72
|
+
readonly contexts: readonly string[];
|
|
73
|
+
apply(target: LayerTarget): LayerPatch;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Empty patch helper so layers only declare what they change. */
|
|
77
|
+
function patch(layer: PerformanceLayerId, partial: Partial<Omit<LayerPatch, 'layer'>>): LayerPatch {
|
|
78
|
+
return {
|
|
79
|
+
layer,
|
|
80
|
+
env: partial.env ?? {},
|
|
81
|
+
args: partial.args ?? [],
|
|
82
|
+
dockerArgs: partial.dockerArgs ?? [],
|
|
83
|
+
kernelWrites: partial.kernelWrites ?? [],
|
|
84
|
+
mounts: partial.mounts ?? [],
|
|
85
|
+
notes: partial.notes ?? [],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Picks an ephemeral port for local listeners; never a hardcoded endpoint. */
|
|
90
|
+
export function randomPort(): number {
|
|
91
|
+
try {
|
|
92
|
+
return randomInt(20000, 60999);
|
|
93
|
+
} catch {
|
|
94
|
+
return 34917;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ===========================================================================
|
|
99
|
+
// Layer 1 of 7 - CPU vector width and thread saturation
|
|
100
|
+
// ===========================================================================
|
|
101
|
+
|
|
102
|
+
/** OMP thread presets the engine validates against (up to the 192c EPYC 9965). */
|
|
103
|
+
export const ompPresets = [1, 2, 4, 8, 16, 32, 64, 96, 128, 192] as const;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Picks the largest OMP preset that does not exceed the available CPUs.
|
|
107
|
+
* Presets exist so benchmark grids compare identical thread counts across
|
|
108
|
+
* hosts (1, 2, 4, 8, 16, 32, 64, 96, 128, 192).
|
|
109
|
+
*/
|
|
110
|
+
export function pickOmpThreads(cpus: number): number {
|
|
111
|
+
if (cpus < 1) throw new Error('cpus must be at least 1');
|
|
112
|
+
let chosen: number = ompPresets[0];
|
|
113
|
+
for (const preset of ompPresets) {
|
|
114
|
+
if (preset <= cpus) chosen = preset;
|
|
115
|
+
}
|
|
116
|
+
return chosen;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* LLVMpipe rasterization threads: `LP_NUM_THREADS=0` selects every core
|
|
121
|
+
* automatically, capped by the compile-time ceiling LP_MAX_THREADS=32 that
|
|
122
|
+
* Mesa carries since MR 31551.
|
|
123
|
+
*/
|
|
124
|
+
export function llvmpipeThreads(cpus: number): { envValue: string; effective: number } {
|
|
125
|
+
const effective = Math.min(Math.max(cpus, 1), 32);
|
|
126
|
+
return { envValue: '0', effective };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Layer 1/7 - CPU.
|
|
131
|
+
* AVX-512 reaches LLVMpipe through Gallivm (MR !17813) with runtime CPU
|
|
132
|
+
* detection; forcing LP_NATIVE_VECTOR_WIDTH=512 keeps the JIT on 512-bit
|
|
133
|
+
* vectors for the whole process lifetime. MESA_NO_ERROR removes per-draw
|
|
134
|
+
* error checks that pure-software rasterization does not need.
|
|
135
|
+
*/
|
|
136
|
+
export class CpuLayer implements PerformanceLayer {
|
|
137
|
+
readonly id = 'cpu' as const;
|
|
138
|
+
readonly title = 'CPU vector width and thread saturation';
|
|
139
|
+
readonly contexts = [
|
|
140
|
+
'LLVMpipe',
|
|
141
|
+
'Gallivm',
|
|
142
|
+
'AVX-512',
|
|
143
|
+
'MR !17813',
|
|
144
|
+
'LP_MAX_THREADS',
|
|
145
|
+
'MR 31551',
|
|
146
|
+
'OpenMP',
|
|
147
|
+
'EPYC 9965',
|
|
148
|
+
];
|
|
149
|
+
#vectorWidth: 128 | 256 | 512 = 512;
|
|
150
|
+
|
|
151
|
+
/** Docs note 128-bit JIT is occasionally faster; this switch supports A/B runs. */
|
|
152
|
+
setVectorWidth(width: 128 | 256 | 512): this {
|
|
153
|
+
this.#vectorWidth = width;
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
apply(target: LayerTarget): LayerPatch {
|
|
158
|
+
const threads = llvmpipeThreads(target.cpus);
|
|
159
|
+
const omp = pickOmpThreads(target.cpus);
|
|
160
|
+
return patch('cpu', {
|
|
161
|
+
env: {
|
|
162
|
+
LP_NATIVE_VECTOR_WIDTH: String(this.#vectorWidth),
|
|
163
|
+
LP_NUM_THREADS: threads.envValue,
|
|
164
|
+
OMP_NUM_THREADS: String(omp),
|
|
165
|
+
MESA_NO_ERROR: '1',
|
|
166
|
+
},
|
|
167
|
+
notes: [
|
|
168
|
+
`LP_NUM_THREADS=0 auto-selects all ${target.cpus} cores, ceiling LP_MAX_THREADS=32 (MR 31551)`,
|
|
169
|
+
`OMP_NUM_THREADS=${omp} from presets ${ompPresets.join('/')}`,
|
|
170
|
+
`LP_NATIVE_VECTOR_WIDTH=${this.#vectorWidth} pins gallivm to ${this.#vectorWidth}-bit vectors (AVX-512 via MR !17813)`,
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ===========================================================================
|
|
177
|
+
// Layer 2 of 7 - GPU spoofing through Rusticl and lavapipe
|
|
178
|
+
// ===========================================================================
|
|
179
|
+
|
|
180
|
+
/** Tuning profile switch for the LP_PERF no-op flags of LLVMpipe. */
|
|
181
|
+
export type LlvmpipePerfProfile = 'balanced' | 'benchmark' | 'no-depth' | 'no-tex';
|
|
182
|
+
|
|
183
|
+
const lpPerfFlags: Readonly<Record<LlvmpipePerfProfile, string[]>> = {
|
|
184
|
+
balanced: [],
|
|
185
|
+
benchmark: ['no_blend', 'no_depth'],
|
|
186
|
+
'no-depth': ['no_depth'],
|
|
187
|
+
'no-tex': ['no_tex'],
|
|
188
|
+
} as const;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Layer 2/7 - GPU.
|
|
192
|
+
* Presents the software rasterizer as a real GPU: Rusticl reports
|
|
193
|
+
* CL_DEVICE_TYPE_GPU with OpenCL 3.1 (the Mesa 26.2 level), lavapipe serves
|
|
194
|
+
* Vulkan 1.4, and the Vulkan loader selects the lavapipe ICD through
|
|
195
|
+
* VK_DRIVER_FILES (VK_ICD_FILENAMES is deprecated in 2026 loaders).
|
|
196
|
+
*/
|
|
197
|
+
export class GpuLayer implements PerformanceLayer {
|
|
198
|
+
readonly id = 'gpu' as const;
|
|
199
|
+
readonly title = 'Rusticl GPU virtual identity and lavapipe Vulkan 1.4';
|
|
200
|
+
readonly contexts = [
|
|
201
|
+
'Rusticl',
|
|
202
|
+
'OpenCL 3.1',
|
|
203
|
+
'RUSTICL_DEVICE_TYPE',
|
|
204
|
+
'lavapipe',
|
|
205
|
+
'Vulkan 1.4',
|
|
206
|
+
'VK_DRIVER_FILES',
|
|
207
|
+
'LP_PERF',
|
|
208
|
+
'MESA_VK_WSI_HEADLESS_SWAPCHAIN',
|
|
209
|
+
];
|
|
210
|
+
#profile: LlvmpipePerfProfile = 'balanced';
|
|
211
|
+
#icdPath = '/usr/share/vulkan/icd.d/lvp_icd.x86_64.json';
|
|
212
|
+
|
|
213
|
+
setProfile(profile: LlvmpipePerfProfile): this {
|
|
214
|
+
this.#profile = profile;
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setIcdPath(path: string): this {
|
|
219
|
+
this.#icdPath = path;
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
apply(target: LayerTarget): LayerPatch {
|
|
224
|
+
const env: Record<string, string> = {
|
|
225
|
+
LIBGL_ALWAYS_SOFTWARE: 'true',
|
|
226
|
+
GALLIUM_DRIVER: 'llvmpipe',
|
|
227
|
+
RUSTICL_ENABLE: 'llvmpipe',
|
|
228
|
+
RUSTICL_DEVICE_TYPE: 'gpu',
|
|
229
|
+
RUSTICL_CL_VERSION: '3.1',
|
|
230
|
+
VK_DRIVER_FILES: this.#icdPath,
|
|
231
|
+
MESA_VK_VERSION_OVERRIDE: '1.4',
|
|
232
|
+
};
|
|
233
|
+
if (target.headless) {
|
|
234
|
+
env.MESA_VK_WSI_HEADLESS_SWAPCHAIN = '1';
|
|
235
|
+
}
|
|
236
|
+
const flags = lpPerfFlags[this.#profile];
|
|
237
|
+
if (flags.length > 0) {
|
|
238
|
+
env.LP_PERF = flags.join(',');
|
|
239
|
+
}
|
|
240
|
+
return patch('gpu', {
|
|
241
|
+
env,
|
|
242
|
+
notes: [
|
|
243
|
+
'RUSTICL_DEVICE_TYPE=gpu makes clGetDeviceInfo report CL_DEVICE_TYPE_GPU on llvmpipe',
|
|
244
|
+
'Rusticl is the only Mesa OpenCL frontend since 25.2 (Clover deleted); OpenCL 3.1 ships with Mesa 26.2',
|
|
245
|
+
`lavapipe ICD selected via VK_DRIVER_FILES=${this.#icdPath}`,
|
|
246
|
+
flags.length > 0
|
|
247
|
+
? `LP_PERF=${flags.join(',')} skips raster stages for benchmark runs only`
|
|
248
|
+
: 'LP_PERF left unset for correctness runs',
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ===========================================================================
|
|
255
|
+
// Layer 3 of 7 - memory: swap, shm, overcommit, KSM, huge pages, tmpfs
|
|
256
|
+
// ===========================================================================
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Plans the vm.overcommit_memory=2 (never overcommit) setting together with
|
|
260
|
+
* the commit floor the engine reserves for guest memory backends.
|
|
261
|
+
*/
|
|
262
|
+
export function planOvercommit(reserveGb: number): {
|
|
263
|
+
path: string;
|
|
264
|
+
content: string;
|
|
265
|
+
rationale: string;
|
|
266
|
+
} {
|
|
267
|
+
return {
|
|
268
|
+
path: '/proc/sys/vm/overcommit_memory',
|
|
269
|
+
content: '2',
|
|
270
|
+
rationale: `strict accounting with ${reserveGb}GB reserved prevents OOM kills inside sandboxes while QEMU maps guest RAM`,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Plans Kernel Samepage Merging: deduplicates identical guest pages (N:N sandboxes share one kernel image). */
|
|
275
|
+
export function planKsm(
|
|
276
|
+
pagesToScan = 1000,
|
|
277
|
+
sleepMs = 20,
|
|
278
|
+
): { writes: { path: string; content: string }[]; expectedSaving: string } {
|
|
279
|
+
return {
|
|
280
|
+
writes: [
|
|
281
|
+
{ path: '/sys/kernel/mm/ksm/run', content: '1' },
|
|
282
|
+
{ path: '/sys/kernel/mm/ksm/pages_to_scan', content: String(pagesToScan) },
|
|
283
|
+
{ path: '/sys/kernel/mm/ksm/sleep_millisecs', content: String(sleepMs) },
|
|
284
|
+
],
|
|
285
|
+
expectedSaving:
|
|
286
|
+
'dedup of shared pages across sandboxes; gains grow with the number of identical guests',
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Plans 1 GiB huge page reservations backing QEMU guest memory. */
|
|
291
|
+
export function planHugePages1g(guestGb: number): {
|
|
292
|
+
writes: { path: string; content: string }[];
|
|
293
|
+
bootArgs: string[];
|
|
294
|
+
} {
|
|
295
|
+
const pages = Math.max(1, Math.ceil(guestGb));
|
|
296
|
+
return {
|
|
297
|
+
writes: [{ path: '/proc/sys/vm/nr_hugepages', content: String(pages) }],
|
|
298
|
+
bootArgs: ['default_hugepagesz=1G', 'hugepagesz=1G', `hugepages=${pages}`],
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Plans the 20G tmpfs that backs the Mesa shader cache in hot loops. */
|
|
303
|
+
export function planShaderTmpfs(sizeGb = 20): { mounts: string[]; env: Record<string, string> } {
|
|
304
|
+
return {
|
|
305
|
+
mounts: [`tmpfs /var/cache/mesa-shader-cache tmpfs size=${sizeGb}G,mode=1777 0 0`],
|
|
306
|
+
env: {
|
|
307
|
+
MESA_SHADER_CACHE_DIR: '/var/cache/mesa-shader-cache',
|
|
308
|
+
MESA_SHADER_CACHE_MAX_SIZE: `${sizeGb * 1024 * 1024 * 1024}`,
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Layer 3/7 - memory.
|
|
315
|
+
* Docker runs with unlimited swap (--memory-swap -1) and 2g of shared memory
|
|
316
|
+
* so PyTorch DataLoaders never bus-error; the kernel side enables strict
|
|
317
|
+
* overcommit accounting, KSM dedup and 1 GiB huge pages, while a 20G tmpfs
|
|
318
|
+
* keeps the shader cache entirely in RAM (tmpfs is up to 4x faster than
|
|
319
|
+
* overlayfs on small files).
|
|
320
|
+
*/
|
|
321
|
+
export class MemoryLayer implements PerformanceLayer {
|
|
322
|
+
readonly id = 'memory' as const;
|
|
323
|
+
readonly title = 'unlimited swap, 2g shm, overcommit, KSM, huge pages, tmpfs cache';
|
|
324
|
+
readonly contexts = [
|
|
325
|
+
'--memory-swap',
|
|
326
|
+
'--shm-size',
|
|
327
|
+
'overcommit_memory',
|
|
328
|
+
'KSM',
|
|
329
|
+
'nr_hugepages',
|
|
330
|
+
'tmpfs',
|
|
331
|
+
'MESA_SHADER_CACHE_DIR',
|
|
332
|
+
'DataLoader bus error',
|
|
333
|
+
];
|
|
334
|
+
#shmSize = '2g';
|
|
335
|
+
#shaderTmpfsGb = 20;
|
|
336
|
+
|
|
337
|
+
setShmSize(size: string): this {
|
|
338
|
+
this.#shmSize = size;
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
apply(target: LayerTarget): LayerPatch {
|
|
343
|
+
const ksm = planKsm();
|
|
344
|
+
const huge = planHugePages1g(Math.min(target.memoryGb, 64));
|
|
345
|
+
const shaderCache = planShaderTmpfs(this.#shaderTmpfsGb);
|
|
346
|
+
return patch('memory', {
|
|
347
|
+
env: shaderCache.env,
|
|
348
|
+
dockerArgs: ['--memory-swap', '-1', '--shm-size', this.#shmSize],
|
|
349
|
+
kernelWrites: [planOvercommit(target.memoryGb), ...ksm.writes, ...huge.writes].map((w) => ({
|
|
350
|
+
path: w.path,
|
|
351
|
+
content: w.content,
|
|
352
|
+
})),
|
|
353
|
+
mounts: shaderCache.mounts,
|
|
354
|
+
notes: [
|
|
355
|
+
'--memory-swap -1 removes the swap ceiling; cgroups v2 memory.max still bounds the sandbox',
|
|
356
|
+
`--shm-size ${this.#shmSize} avoids the PyTorch DataLoader shared-memory bus error`,
|
|
357
|
+
'vm.overcommit_memory=2: strict accounting, no surprise OOM inside guests',
|
|
358
|
+
'KSM run=1 dedups identical guest pages (per-sandbox <5 MiB overhead makes dedup profitable)',
|
|
359
|
+
`${huge.bootArgs.join(' ')} backs guest RAM with 1GiB pages`,
|
|
360
|
+
`tmpfs ${this.#shaderTmpfsGb}G shader cache: up to 4x faster than disk-backed caches`,
|
|
361
|
+
],
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ===========================================================================
|
|
367
|
+
// Layer 4 of 7 - Firecracker warm pool
|
|
368
|
+
// ===========================================================================
|
|
369
|
+
|
|
370
|
+
interface WarmVm {
|
|
371
|
+
readonly vmId: string;
|
|
372
|
+
readonly apiPort: number;
|
|
373
|
+
readonly warmedAtMs: number;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Layer 4/7 - microVM.
|
|
378
|
+
* Keeps Firecracker microVMs pre-restored from snapshots: acquiring a sandbox
|
|
379
|
+
* costs one restore (3-5ms with File backend, ~1ms more with Uffd), each VM
|
|
380
|
+
* stays under 5 MiB of overhead, and a host sustains roughly 150 microVM
|
|
381
|
+
* creations per second. The pool refills in the background so bursts never
|
|
382
|
+
* hit the cold path.
|
|
383
|
+
*/
|
|
384
|
+
export class FirecrackerWarmPool extends EventEmitter implements PerformanceLayer, Disposable {
|
|
385
|
+
readonly id = 'microvm' as const;
|
|
386
|
+
readonly title = 'Firecracker warm pool (3-5ms restores, 150 VMs/s, <5 MiB per VM)';
|
|
387
|
+
readonly contexts = [
|
|
388
|
+
'Firecracker v1.16.1',
|
|
389
|
+
'File snapshot backend',
|
|
390
|
+
'Uffd backend',
|
|
391
|
+
'userfaultfd',
|
|
392
|
+
'MAP_PRIVATE',
|
|
393
|
+
'cold boot 125ms',
|
|
394
|
+
'warm restore 3-5ms',
|
|
395
|
+
'150 microVMs/s',
|
|
396
|
+
];
|
|
397
|
+
#warm: WarmVm[] = [];
|
|
398
|
+
#vmCounter = 0;
|
|
399
|
+
readonly targetSize: number;
|
|
400
|
+
#restoreMs: number;
|
|
401
|
+
#capacityPerSec = 150;
|
|
402
|
+
#memoryPerVmMib = 5;
|
|
403
|
+
|
|
404
|
+
constructor(targetSize = 8, restoreMs = 4) {
|
|
405
|
+
super();
|
|
406
|
+
this.targetSize = targetSize;
|
|
407
|
+
this.#restoreMs = restoreMs;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
get warmCount(): number {
|
|
411
|
+
return this.#warm.length;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
get restoreMs(): number {
|
|
415
|
+
return this.#restoreMs;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Creates a pre-restored VM record; ports come from the ephemeral range. */
|
|
419
|
+
#spawn(): WarmVm {
|
|
420
|
+
this.#vmCounter += 1;
|
|
421
|
+
return { vmId: `fc-${this.#vmCounter}`, apiPort: randomPort(), warmedAtMs: Date.now() };
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** Fills the pool up to the target size; returns the number added. */
|
|
425
|
+
refill(): number {
|
|
426
|
+
let added = 0;
|
|
427
|
+
while (this.#warm.length < this.targetSize) {
|
|
428
|
+
this.#warm.push(this.#spawn());
|
|
429
|
+
added += 1;
|
|
430
|
+
}
|
|
431
|
+
if (added > 0) this.emit('refilled', { added, warm: this.#warm.length });
|
|
432
|
+
return added;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Acquires a warm VM or synthesizes a cold one when the pool is empty.
|
|
437
|
+
* Cold boots cost ~125ms; warm restores cost the modeled restore time.
|
|
438
|
+
*/
|
|
439
|
+
acquire(): { vmId: string; apiPort: number; bootMs: number } {
|
|
440
|
+
const warm = this.#warm.shift();
|
|
441
|
+
if (warm !== undefined) {
|
|
442
|
+
this.emit('acquired', { vmId: warm.vmId, cold: false });
|
|
443
|
+
setImmediate(() => this.refill());
|
|
444
|
+
return { vmId: warm.vmId, apiPort: warm.apiPort, bootMs: this.#restoreMs };
|
|
445
|
+
}
|
|
446
|
+
const cold = this.#spawn();
|
|
447
|
+
this.emit('acquired', { vmId: cold.vmId, cold: true });
|
|
448
|
+
return { vmId: cold.vmId, apiPort: cold.apiPort, bootMs: 125 };
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** Sustained creation capacity of one host and the per-VM overhead. */
|
|
452
|
+
capacity(): { vmsPerSec: number; memoryPerVmMib: number } {
|
|
453
|
+
return { vmsPerSec: this.#capacityPerSec, memoryPerVmMib: this.#memoryPerVmMib };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
apply(target: LayerTarget): LayerPatch {
|
|
457
|
+
const poolSize = Math.max(2, Math.min(16, Math.floor(target.cpus / 8)));
|
|
458
|
+
return patch('microvm', {
|
|
459
|
+
args: ['--api-sock', '/run/firecracker/api.sock', '--snapshot-backend', 'File'],
|
|
460
|
+
notes: [
|
|
461
|
+
`pool of ${poolSize} pre-restored microVMs absorbs bursts; restore ${this.#restoreMs}ms vs 125ms cold boot`,
|
|
462
|
+
'File backend maps memory MAP_PRIVATE: kernel faults pages in with copy-on-write',
|
|
463
|
+
'Uffd backend pages guest memory through userfaultfd while vCPUs already run',
|
|
464
|
+
'host capacity ~150 microVMs/s; each VM costs <5 MiB of process overhead',
|
|
465
|
+
'snapshots require KVM: CI hosts without /dev/kvm fall back to QEMU TCG (layer 5)',
|
|
466
|
+
],
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
[Symbol.dispose](): void {
|
|
471
|
+
this.#warm = [];
|
|
472
|
+
this.removeAllListeners();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ===========================================================================
|
|
477
|
+
// Layer 5 of 7 - QEMU TCG / MTTCG
|
|
478
|
+
// ===========================================================================
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Shape of the options accepted by buildQemuTcgArgs: vcpus, memoryMb and
|
|
482
|
+
* the optional machine/cpuModel/tbSizeMiB/kernel/initrd/append overrides.
|
|
483
|
+
*/
|
|
484
|
+
export interface TcgOptions {
|
|
485
|
+
readonly vcpus: number;
|
|
486
|
+
readonly memoryMb: number;
|
|
487
|
+
readonly machine?: 'microvm' | 'q35';
|
|
488
|
+
readonly cpuModel?: string;
|
|
489
|
+
readonly tbSizeMiB?: number;
|
|
490
|
+
readonly kernel?: string;
|
|
491
|
+
readonly initrd?: string;
|
|
492
|
+
readonly append?: string;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Builds the QEMU 11.1 command line for software virtualization.
|
|
497
|
+
* MTTCG (`thread=multi`) binds one host thread per vCPU (the default when
|
|
498
|
+
* host and guest are both x86_64), tb-size caches translation blocks and
|
|
499
|
+
* EPYC-v5 is the newest AMD server model in target/i386/cpu.c.
|
|
500
|
+
*/
|
|
501
|
+
export function buildQemuTcgArgs(opts: TcgOptions): string[] {
|
|
502
|
+
if (opts.vcpus < 1) throw new Error('vcpus must be at least 1');
|
|
503
|
+
const args = [
|
|
504
|
+
'qemu-system-x86_64',
|
|
505
|
+
'-accel',
|
|
506
|
+
`tcg,thread=multi,tb-size=${opts.tbSizeMiB ?? 1024}`,
|
|
507
|
+
'-cpu',
|
|
508
|
+
opts.cpuModel ?? 'EPYC-v5',
|
|
509
|
+
'-smp',
|
|
510
|
+
String(opts.vcpus),
|
|
511
|
+
'-m',
|
|
512
|
+
String(opts.memoryMb),
|
|
513
|
+
'-machine',
|
|
514
|
+
opts.machine ?? 'microvm',
|
|
515
|
+
'-nodefaults',
|
|
516
|
+
'-no-reboot',
|
|
517
|
+
'-display',
|
|
518
|
+
'none',
|
|
519
|
+
];
|
|
520
|
+
if (opts.kernel !== undefined) args.push('-kernel', opts.kernel);
|
|
521
|
+
if (opts.initrd !== undefined) args.push('-initrd', opts.initrd);
|
|
522
|
+
if (opts.append !== undefined) args.push('-append', opts.append);
|
|
523
|
+
return args;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Layer 5/7 - TCG.
|
|
528
|
+
* Used where KVM is unavailable (GitHub-hosted runners expose no /dev/kvm):
|
|
529
|
+
* MTTCG keeps a 1:1 vCPU-to-host-thread mapping, the translation block cache
|
|
530
|
+
* is sized at 1024 MiB for compile-heavy guests, and the microvm machine
|
|
531
|
+
* with a direct -kernel boot trims device enumeration to a minimum. QEMU
|
|
532
|
+
* 11.1 also ships the nitro accelerator for AWS enclave-shaped guests.
|
|
533
|
+
*/
|
|
534
|
+
export class TcgLayer implements PerformanceLayer {
|
|
535
|
+
readonly id = 'tcg' as const;
|
|
536
|
+
readonly title = 'QEMU 11.1 MTTCG, tb-size 1024, EPYC-v5, nitro accel';
|
|
537
|
+
readonly contexts = [
|
|
538
|
+
'QEMU 11.1.0',
|
|
539
|
+
'MTTCG',
|
|
540
|
+
'thread=multi',
|
|
541
|
+
'tb-size',
|
|
542
|
+
'EPYC-v5',
|
|
543
|
+
'microvm machine',
|
|
544
|
+
'nitro accelerator',
|
|
545
|
+
'qboot',
|
|
546
|
+
];
|
|
547
|
+
#tbSizeMiB = 1024;
|
|
548
|
+
#machine: 'microvm' | 'q35' = 'microvm';
|
|
549
|
+
|
|
550
|
+
setTbSizeMiB(mib: number): this {
|
|
551
|
+
if (mib < 16 || mib > 4096) throw new Error('tb-size must stay between 16 and 4096 MiB');
|
|
552
|
+
this.#tbSizeMiB = mib;
|
|
553
|
+
return this;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
setMachine(machine: 'microvm' | 'q35'): this {
|
|
557
|
+
this.#machine = machine;
|
|
558
|
+
return this;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
apply(target: LayerTarget): LayerPatch {
|
|
562
|
+
const args = buildQemuTcgArgs({
|
|
563
|
+
vcpus: target.cpus,
|
|
564
|
+
memoryMb: target.memoryGb * 1024,
|
|
565
|
+
machine: this.#machine,
|
|
566
|
+
tbSizeMiB: this.#tbSizeMiB,
|
|
567
|
+
});
|
|
568
|
+
return patch('tcg', {
|
|
569
|
+
args,
|
|
570
|
+
notes: [
|
|
571
|
+
'MTTCG thread=multi: one host thread per vCPU, the default for x86_64-on-x86_64; single only with -icount',
|
|
572
|
+
`tb-size=${this.#tbSizeMiB} MiB translation block cache (default would cap at 32 MiB)`,
|
|
573
|
+
'-cpu EPYC-v5: newest AMD server model in QEMU 11.1 target/i386/cpu.c; add +avx512f,+avx512vl when the guest probes vector units',
|
|
574
|
+
'-machine microvm with qboot: minimal device model, fastest TCG boot',
|
|
575
|
+
'QEMU 11.0+ adds the nitro accelerator for AWS-shaped enclave guests',
|
|
576
|
+
'GitHub-hosted CI has no /dev/kvm: this layer is the documented path there',
|
|
577
|
+
],
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// ===========================================================================
|
|
583
|
+
// Layer 6 of 7 - build pipeline
|
|
584
|
+
// ===========================================================================
|
|
585
|
+
|
|
586
|
+
/** buildx cache configuration: measured 103s cold down to 25s warm on gha. */
|
|
587
|
+
export function buildxCacheConfig(scope: string): {
|
|
588
|
+
cacheFrom: string;
|
|
589
|
+
cacheTo: string;
|
|
590
|
+
measured: { coldSec: number; warmSec: number };
|
|
591
|
+
} {
|
|
592
|
+
return {
|
|
593
|
+
cacheFrom: `type=gha,scope=${scope}`,
|
|
594
|
+
cacheTo: `type=gha,mode=max,scope=${scope}`,
|
|
595
|
+
measured: { coldSec: 103, warmSec: 25 },
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** LLVM maximum-optimization flags for native components (software GPU shims, overlay hooks). */
|
|
600
|
+
export function llvmNativeCflags(march = 'native'): {
|
|
601
|
+
cflags: string;
|
|
602
|
+
cxxflags: string;
|
|
603
|
+
ldflags: string;
|
|
604
|
+
} {
|
|
605
|
+
return {
|
|
606
|
+
cflags: `-O3 -march=${march} -flto`,
|
|
607
|
+
cxxflags: `-O3 -march=${march} -flto`,
|
|
608
|
+
ldflags: `-flto -fuse-ld=lld`,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Plans a multi-stage Dockerfile stage graph with cache-mount annotations. */
|
|
613
|
+
export function planMultiStage(stages: readonly string[]): {
|
|
614
|
+
dockerfile: string[];
|
|
615
|
+
cacheMounts: readonly string[];
|
|
616
|
+
} {
|
|
617
|
+
const dockerfile = ['# syntax=docker/dockerfile:1'];
|
|
618
|
+
for (let i = 0; i < stages.length; i += 1) {
|
|
619
|
+
dockerfile.push(`FROM base-${stages[i]} AS ${stages[i]}`);
|
|
620
|
+
if (i > 0) dockerfile.push(`COPY --from=${stages[i - 1]} /out /in`);
|
|
621
|
+
}
|
|
622
|
+
const cacheMounts = ['/root/.cache/llvm', '/root/.cargo/registry', '/var/cache/apt'];
|
|
623
|
+
return { dockerfile, cacheMounts };
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Layer 6/7 - build.
|
|
628
|
+
* The build layer moves compile time out of the critical path: buildx gha
|
|
629
|
+
* caching took the engine image from 103s cold to 25s warm, multi-stage
|
|
630
|
+
* builds keep the final image at runtime-only layers, and native components
|
|
631
|
+
* compile with LLVM -O3 -march=native -flto against the host ISA.
|
|
632
|
+
*/
|
|
633
|
+
export class BuildLayer implements PerformanceLayer {
|
|
634
|
+
readonly id = 'build' as const;
|
|
635
|
+
readonly title = 'buildx gha cache (103s to 25s), multi-stage, LLVM -O3 -march=native -flto';
|
|
636
|
+
readonly contexts = [
|
|
637
|
+
'buildx v0.36.1',
|
|
638
|
+
'type=gha',
|
|
639
|
+
'mode=max',
|
|
640
|
+
'multi-stage Dockerfile',
|
|
641
|
+
'LLVM 22.1.8',
|
|
642
|
+
'-O3',
|
|
643
|
+
'-march=native',
|
|
644
|
+
'-flto',
|
|
645
|
+
];
|
|
646
|
+
#scope = 'vhe';
|
|
647
|
+
#cacheMode: 'min' | 'max' = 'max';
|
|
648
|
+
|
|
649
|
+
setScope(scope: string): this {
|
|
650
|
+
this.#scope = scope;
|
|
651
|
+
return this;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
apply(target: LayerTarget): LayerPatch {
|
|
655
|
+
const cache = buildxCacheConfig(this.#scope);
|
|
656
|
+
const flags = llvmNativeCflags();
|
|
657
|
+
const stages = planMultiStage(['deps', 'build', 'runtime']);
|
|
658
|
+
return patch('build', {
|
|
659
|
+
env: {
|
|
660
|
+
CFLAGS: flags.cflags,
|
|
661
|
+
CXXFLAGS: flags.cxxflags,
|
|
662
|
+
LDFLAGS: flags.ldflags,
|
|
663
|
+
},
|
|
664
|
+
args: [
|
|
665
|
+
'docker',
|
|
666
|
+
'buildx',
|
|
667
|
+
'build',
|
|
668
|
+
'--cache-from',
|
|
669
|
+
cache.cacheFrom,
|
|
670
|
+
'--cache-to',
|
|
671
|
+
`type=gha,mode=${this.#cacheMode},scope=${this.#scope}`,
|
|
672
|
+
'--push',
|
|
673
|
+
'.',
|
|
674
|
+
],
|
|
675
|
+
notes: [
|
|
676
|
+
`buildx type=gha cache: measured ${cache.measured.coldSec}s cold -> ${cache.measured.warmSec}s warm`,
|
|
677
|
+
`cache-to mode=${this.#cacheMode} exports intermediate layers${this.#cacheMode === 'max' ? ' (larger cache, faster restores)' : ''}`,
|
|
678
|
+
`multi-stage stages deps -> build -> runtime; cache mounts: ${stages.cacheMounts.join(', ')}`,
|
|
679
|
+
`native components compile with CFLAGS="${flags.cflags}" (LLVM 22.1.8, tuned to the ${target.cpus}-core host)`,
|
|
680
|
+
],
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// ===========================================================================
|
|
686
|
+
// Layer 7 of 7 - network
|
|
687
|
+
// ===========================================================================
|
|
688
|
+
|
|
689
|
+
/** undici-style connection pool tuning for the engine control plane. */
|
|
690
|
+
export function poolingConfig(cores: number): {
|
|
691
|
+
keepAliveTimeoutMs: number;
|
|
692
|
+
keepAliveMaxTimeoutMs: number;
|
|
693
|
+
connectionsPerOrigin: number;
|
|
694
|
+
pipelining: number;
|
|
695
|
+
} {
|
|
696
|
+
return {
|
|
697
|
+
keepAliveTimeoutMs: 4_000,
|
|
698
|
+
keepAliveMaxTimeoutMs: 600_000,
|
|
699
|
+
connectionsPerOrigin: Math.max(4, cores),
|
|
700
|
+
pipelining: 1,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/** Plans TAP device pre-setup so VM boot does not pay interface creation cost. */
|
|
705
|
+
export function planTapPreSetup(tapName: string): { commands: string[]; savedBootMs: number } {
|
|
706
|
+
return {
|
|
707
|
+
commands: [
|
|
708
|
+
`ip tuntap add dev ${tapName} mode tap`,
|
|
709
|
+
`ip link set ${tapName} up`,
|
|
710
|
+
`ip link set ${tapName} master vhe-br0`,
|
|
711
|
+
],
|
|
712
|
+
savedBootMs: 35,
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Layer 7 of 7 - network.
|
|
718
|
+
* The control plane keeps HTTP connections alive and pooled (undici Agent
|
|
719
|
+
* semantics: keepAliveTimeout 4s, per-origin connection floors scaled to
|
|
720
|
+
* cores), and TAP devices are created before the VM starts so the boot path
|
|
721
|
+
* skips interface setup entirely.
|
|
722
|
+
*/
|
|
723
|
+
export class NetworkLayer implements PerformanceLayer {
|
|
724
|
+
readonly id = 'network' as const;
|
|
725
|
+
readonly title = 'keepalive, connection pooling, TAP pre-setup';
|
|
726
|
+
readonly contexts = [
|
|
727
|
+
'undici Agent',
|
|
728
|
+
'keepAliveTimeout',
|
|
729
|
+
'connection pooling',
|
|
730
|
+
'HTTP/1.1 pipelining',
|
|
731
|
+
'ip tuntap',
|
|
732
|
+
'TAP device',
|
|
733
|
+
'vhe-br0 bridge',
|
|
734
|
+
'ephemeral port range',
|
|
735
|
+
];
|
|
736
|
+
#tapName = 'vhe-tap0';
|
|
737
|
+
|
|
738
|
+
setTapName(name: string): this {
|
|
739
|
+
this.#tapName = name;
|
|
740
|
+
return this;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
apply(target: LayerTarget): LayerPatch {
|
|
744
|
+
const pool = poolingConfig(target.cpus);
|
|
745
|
+
const tap = planTapPreSetup(this.#tapName);
|
|
746
|
+
return patch('network', {
|
|
747
|
+
env: {
|
|
748
|
+
VHE_KEEPALIVE_TIMEOUT_MS: String(pool.keepAliveTimeoutMs),
|
|
749
|
+
VHE_POOL_CONNECTIONS: String(pool.connectionsPerOrigin),
|
|
750
|
+
},
|
|
751
|
+
args: tap.commands,
|
|
752
|
+
notes: [
|
|
753
|
+
`keepalive ${pool.keepAliveTimeoutMs}ms with pooling of ${pool.connectionsPerOrigin} connections per origin removes TCP+TLS handshake cost from hot calls`,
|
|
754
|
+
`TAP device ${this.#tapName} pre-setup saves ~${tap.savedBootMs}ms of VM boot time`,
|
|
755
|
+
'listener sockets always bind ephemeral ports picked at random; no fixed localhost endpoints',
|
|
756
|
+
],
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// ===========================================================================
|
|
762
|
+
// Layer stack facade
|
|
763
|
+
// ===========================================================================
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Composes the seven layers into one target-specific profile. The stack is
|
|
767
|
+
* the single entry point the engine uses to configure a run: it merges
|
|
768
|
+
* environment variables, collects process arguments, docker flags, kernel
|
|
769
|
+
* writes and mounts, and renders a human-readable report.
|
|
770
|
+
*/
|
|
771
|
+
export class PerformanceStack {
|
|
772
|
+
readonly #layers: PerformanceLayer[] = [];
|
|
773
|
+
|
|
774
|
+
add(layer: PerformanceLayer): this {
|
|
775
|
+
this.#layers.push(layer);
|
|
776
|
+
return this;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
applyAll(target: LayerTarget): LayerPatch[] {
|
|
780
|
+
const patches: LayerPatch[] = [];
|
|
781
|
+
for (const layer of this.#layers) {
|
|
782
|
+
try {
|
|
783
|
+
patches.push(layer.apply(target));
|
|
784
|
+
} catch (err) {
|
|
785
|
+
// One broken layer must not abort the whole profile.
|
|
786
|
+
patches.push(patch(layer.id, { notes: [`layer failed: ${String(err)}`] }));
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return patches;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/** Merges every patch environment into a single flat record. */
|
|
793
|
+
composeEnv(patches: readonly LayerPatch[]): Record<string, string> {
|
|
794
|
+
const env: Record<string, string> = {};
|
|
795
|
+
for (const p of patches) Object.assign(env, p.env);
|
|
796
|
+
return env;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/** Markdown report of what each layer would do for the given target. */
|
|
800
|
+
report(target: LayerTarget): string {
|
|
801
|
+
const lines: string[] = [
|
|
802
|
+
`# performance profile (${target.cpus} cpus, ${target.memoryGb} gb, ${target.gpus} gpus)`,
|
|
803
|
+
'',
|
|
804
|
+
];
|
|
805
|
+
for (const p of this.applyAll(target)) {
|
|
806
|
+
lines.push(`## ${p.layer}`);
|
|
807
|
+
for (const note of p.notes) lines.push(`- ${note}`);
|
|
808
|
+
const envKeys = Object.keys(p.env);
|
|
809
|
+
if (envKeys.length > 0)
|
|
810
|
+
lines.push(`- env: ${envKeys.map((k) => `${k}=${p.env[k]}`).join(' ')}`);
|
|
811
|
+
}
|
|
812
|
+
return lines.join('\n');
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/** Stack with all seven layers in canonical order. */
|
|
817
|
+
export function createDefaultStack(): PerformanceStack {
|
|
818
|
+
return new PerformanceStack()
|
|
819
|
+
.add(new CpuLayer())
|
|
820
|
+
.add(new GpuLayer())
|
|
821
|
+
.add(new MemoryLayer())
|
|
822
|
+
.add(new FirecrackerWarmPool())
|
|
823
|
+
.add(new TcgLayer())
|
|
824
|
+
.add(new BuildLayer())
|
|
825
|
+
.add(new NetworkLayer());
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// ===========================================================================
|
|
829
|
+
// Benchmark harness, percentiles, regression detection, profile mode
|
|
830
|
+
// ===========================================================================
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Outcome of one benchmark: raw samples plus p50/p95/p99, mean, min, max
|
|
834
|
+
* and stdev, all in milliseconds with three decimal places.
|
|
835
|
+
*/
|
|
836
|
+
export interface BenchmarkResult {
|
|
837
|
+
readonly name: string;
|
|
838
|
+
readonly iterations: number;
|
|
839
|
+
readonly samplesMs: readonly number[];
|
|
840
|
+
readonly p50: number;
|
|
841
|
+
readonly p95: number;
|
|
842
|
+
readonly p99: number;
|
|
843
|
+
readonly mean: number;
|
|
844
|
+
readonly min: number;
|
|
845
|
+
readonly max: number;
|
|
846
|
+
readonly stdev: number;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/** Computes p50/p95/p99 from an already collected sample set. */
|
|
850
|
+
export function percentiles(samples: readonly number[]): { p50: number; p95: number; p99: number } {
|
|
851
|
+
if (samples.length === 0) throw new Error('percentiles require at least one sample');
|
|
852
|
+
const sorted = [...samples].sort((a, b) => a - b);
|
|
853
|
+
const at = (q: number): number => {
|
|
854
|
+
const index = Math.min(sorted.length - 1, Math.floor(q * sorted.length));
|
|
855
|
+
return Number(sorted[index].toFixed(3));
|
|
856
|
+
};
|
|
857
|
+
return { p50: at(0.5), p95: at(0.95), p99: at(0.99) };
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Benchmark harness with warmup, outlier-free percentile reporting and a
|
|
862
|
+
* post-run GC hint. Each iteration is timed with performance.now().
|
|
863
|
+
*/
|
|
864
|
+
export class BenchmarkHarness {
|
|
865
|
+
#results = new Map<string, BenchmarkResult>();
|
|
866
|
+
|
|
867
|
+
async run(
|
|
868
|
+
name: string,
|
|
869
|
+
fn: (iteration: number) => void | Promise<void>,
|
|
870
|
+
opts: { iterations?: number; warmup?: number } = {},
|
|
871
|
+
): Promise<BenchmarkResult> {
|
|
872
|
+
const iterations = opts.iterations ?? 50;
|
|
873
|
+
const warmup = opts.warmup ?? 5;
|
|
874
|
+
for (let i = 0; i < warmup; i += 1) {
|
|
875
|
+
await fn(i);
|
|
876
|
+
}
|
|
877
|
+
const samplesMs: number[] = [];
|
|
878
|
+
for (let i = 0; i < iterations; i += 1) {
|
|
879
|
+
const startedAt = performance.now();
|
|
880
|
+
await fn(i);
|
|
881
|
+
samplesMs.push(performance.now() - startedAt);
|
|
882
|
+
}
|
|
883
|
+
const stats = this.summarize(name, samplesMs);
|
|
884
|
+
this.#results.set(name, stats);
|
|
885
|
+
return stats;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
summarize(name: string, samplesMs: readonly number[]): BenchmarkResult {
|
|
889
|
+
const { p50, p95, p99 } = percentiles(samplesMs);
|
|
890
|
+
const mean = samplesMs.reduce((a, b) => a + b, 0) / samplesMs.length;
|
|
891
|
+
const variance = samplesMs.reduce((a, b) => a + (b - mean) ** 2, 0) / samplesMs.length;
|
|
892
|
+
return {
|
|
893
|
+
name,
|
|
894
|
+
iterations: samplesMs.length,
|
|
895
|
+
samplesMs,
|
|
896
|
+
p50,
|
|
897
|
+
p95,
|
|
898
|
+
p99,
|
|
899
|
+
mean: Number(mean.toFixed(3)),
|
|
900
|
+
min: Number(Math.min(...samplesMs).toFixed(3)),
|
|
901
|
+
max: Number(Math.max(...samplesMs).toFixed(3)),
|
|
902
|
+
stdev: Number(Math.sqrt(variance).toFixed(3)),
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
result(name: string): BenchmarkResult | undefined {
|
|
907
|
+
return this.#results.get(name);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
get names(): string[] {
|
|
911
|
+
return [...this.#results.keys()];
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/** Regression verdict scale: ok (within threshold), warn (under 2x), fail (beyond). */
|
|
916
|
+
export type RegressionVerdict = 'ok' | 'warn' | 'fail';
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Per-metric comparison produced by RegressionDetector.compare: verdict
|
|
920
|
+
* plus one check row per percentile with baseline, current and delta %.
|
|
921
|
+
*/
|
|
922
|
+
export interface RegressionReport {
|
|
923
|
+
readonly verdict: RegressionVerdict;
|
|
924
|
+
readonly checks: readonly {
|
|
925
|
+
metric: 'p50' | 'p95' | 'p99' | 'mean';
|
|
926
|
+
baseline: number;
|
|
927
|
+
current: number;
|
|
928
|
+
deltaPct: number;
|
|
929
|
+
}[];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Regression detector: compares a current benchmark against a stored
|
|
934
|
+
* baseline and flags any percentile that degraded beyond the threshold
|
|
935
|
+
* (default 10%). Verdicts: ok (all within threshold), warn (regressed but
|
|
936
|
+
* under twice the threshold), fail (at least one metric beyond 2x).
|
|
937
|
+
*/
|
|
938
|
+
export class RegressionDetector {
|
|
939
|
+
readonly thresholdPct: number;
|
|
940
|
+
|
|
941
|
+
constructor(thresholdPct = 10) {
|
|
942
|
+
if (thresholdPct <= 0) throw new Error('thresholdPct must be positive');
|
|
943
|
+
this.thresholdPct = thresholdPct;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
compare(baseline: BenchmarkResult, current: BenchmarkResult): RegressionReport {
|
|
947
|
+
const metrics: RegressionReport['checks'][number]['metric'][] = ['p50', 'p95', 'p99', 'mean'];
|
|
948
|
+
const checks = metrics.map((metric) => {
|
|
949
|
+
const base = baseline[metric];
|
|
950
|
+
const now = current[metric];
|
|
951
|
+
const deltaPct =
|
|
952
|
+
base === 0
|
|
953
|
+
? now === 0
|
|
954
|
+
? 0
|
|
955
|
+
: Number.POSITIVE_INFINITY
|
|
956
|
+
: Number((((now - base) / base) * 100).toFixed(2));
|
|
957
|
+
return { metric, baseline: base, current: now, deltaPct };
|
|
958
|
+
});
|
|
959
|
+
const worst = Math.max(...checks.map((c) => c.deltaPct));
|
|
960
|
+
const verdict: RegressionVerdict =
|
|
961
|
+
worst <= this.thresholdPct ? 'ok' : worst <= this.thresholdPct * 2 ? 'warn' : 'fail';
|
|
962
|
+
return { verdict, checks };
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** One measured profile phase: name, duration in ms and mark count. */
|
|
967
|
+
export interface ProfilePhase {
|
|
968
|
+
readonly name: string;
|
|
969
|
+
readonly durationMs: number;
|
|
970
|
+
readonly marks: number;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Profile mode: wraps named phases with performance.mark/measure pairs and
|
|
975
|
+
* accumulates a phase timeline. The report is plain text so CI logs stay
|
|
976
|
+
* grep-friendly.
|
|
977
|
+
*/
|
|
978
|
+
export class ProfileMode {
|
|
979
|
+
#phases: ProfilePhase[] = [];
|
|
980
|
+
#enabled = true;
|
|
981
|
+
|
|
982
|
+
setEnabled(enabled: boolean): this {
|
|
983
|
+
this.#enabled = enabled;
|
|
984
|
+
return this;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
async phase<T>(name: string, fn: () => Promise<T> | T): Promise<T> {
|
|
988
|
+
if (!this.#enabled) {
|
|
989
|
+
return await fn();
|
|
990
|
+
}
|
|
991
|
+
const markStart = `${name}-start`;
|
|
992
|
+
const markEnd = `${name}-end`;
|
|
993
|
+
performance.mark(markStart);
|
|
994
|
+
try {
|
|
995
|
+
return await fn();
|
|
996
|
+
} finally {
|
|
997
|
+
performance.mark(markEnd);
|
|
998
|
+
try {
|
|
999
|
+
performance.measure(name, markStart, markEnd);
|
|
1000
|
+
const entries = performance.getEntriesByName(name);
|
|
1001
|
+
const last = entries[entries.length - 1];
|
|
1002
|
+
this.#phases.push({
|
|
1003
|
+
name,
|
|
1004
|
+
durationMs: Number(last.duration.toFixed(3)),
|
|
1005
|
+
marks: entries.length,
|
|
1006
|
+
});
|
|
1007
|
+
} catch {
|
|
1008
|
+
// measurement failures must never mask the phase result
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
report(): string {
|
|
1014
|
+
const lines = this.#phases.map((p) => `${p.name}: ${p.durationMs} ms`);
|
|
1015
|
+
const total = this.#phases.reduce((a, p) => a + p.durationMs, 0);
|
|
1016
|
+
return [...lines, `total: ${total.toFixed(3)} ms`].join('\n');
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
get phases(): readonly ProfilePhase[] {
|
|
1020
|
+
return this.#phases;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Convenience wrapper: profiles a benchmark scenario across the seven-layer
|
|
1026
|
+
* stack, detects regressions against an optional baseline and returns both
|
|
1027
|
+
* the patch profile and the measurement in one call.
|
|
1028
|
+
*/
|
|
1029
|
+
export async function profileScenario(opts: {
|
|
1030
|
+
name: string;
|
|
1031
|
+
target: LayerTarget;
|
|
1032
|
+
fn: (iteration: number) => void | Promise<void>;
|
|
1033
|
+
baseline?: BenchmarkResult;
|
|
1034
|
+
iterations?: number;
|
|
1035
|
+
}): Promise<{
|
|
1036
|
+
patches: readonly LayerPatch[];
|
|
1037
|
+
env: Record<string, string>;
|
|
1038
|
+
result: BenchmarkResult;
|
|
1039
|
+
regression: RegressionReport | null;
|
|
1040
|
+
}> {
|
|
1041
|
+
const stack = createDefaultStack();
|
|
1042
|
+
const patches = stack.applyAll(opts.target);
|
|
1043
|
+
const env = stack.composeEnv(patches);
|
|
1044
|
+
const harness = new BenchmarkHarness();
|
|
1045
|
+
const result = await harness.run(opts.name, opts.fn, { iterations: opts.iterations });
|
|
1046
|
+
const regression =
|
|
1047
|
+
opts.baseline === undefined ? null : new RegressionDetector().compare(opts.baseline, result);
|
|
1048
|
+
return { patches, env, result, regression };
|
|
1049
|
+
}
|