@divmain/jdm-asm 0.2.1 → 0.2.3
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/index.js +2227 -29
- package/dist/index.js.map +1 -1
- package/package.json +8 -2
- package/.github/workflows/ci.yml +0 -53
- package/.oxfmtrc.json +0 -16
- package/.oxlintrc.json +0 -183
- package/AGENTS.md +0 -81
- package/asconfig.json +0 -23
- package/benchmarks/fixtures.ts +0 -111
- package/benchmarks/input-fixtures.ts +0 -80
- package/benchmarks/run.ts +0 -913
- package/benchmarks/worker-pool.ts +0 -223
- package/benchmarks/worker.ts +0 -374
- package/scripts/run-all-tests.ts +0 -220
- package/src/compiler/EXPRESSION_SUBSETS.md +0 -228
- package/src/compiler/asc-compiler.ts +0 -315
- package/src/compiler/ast-types.ts +0 -215
- package/src/compiler/build.ts +0 -56
- package/src/compiler/cache.ts +0 -414
- package/src/compiler/code-generators.ts +0 -211
- package/src/compiler/codegen/index.ts +0 -15
- package/src/compiler/codegen/js-marshal.ts +0 -999
- package/src/compiler/codegen/js-validation.ts +0 -243
- package/src/compiler/codegen.ts +0 -19
- package/src/compiler/compile-time-validation.ts +0 -507
- package/src/compiler/cst-visitor.ts +0 -434
- package/src/compiler/errors.ts +0 -227
- package/src/compiler/expression-parser.ts +0 -536
- package/src/compiler/graph.ts +0 -197
- package/src/compiler/index.ts +0 -199
- package/src/compiler/input-validation.ts +0 -33
- package/src/compiler/marshal-gen.ts +0 -21
- package/src/compiler/nodes/context-resolvers.ts +0 -197
- package/src/compiler/nodes/decision-table.ts +0 -507
- package/src/compiler/nodes/decision.ts +0 -292
- package/src/compiler/nodes/expression-compiler.ts +0 -526
- package/src/compiler/nodes/expression.ts +0 -425
- package/src/compiler/nodes/function.ts +0 -316
- package/src/compiler/nodes/input.ts +0 -60
- package/src/compiler/nodes/switch.ts +0 -547
- package/src/compiler/optimizer.ts +0 -948
- package/src/compiler/orchestrator.ts +0 -352
- package/src/compiler/parser.ts +0 -115
- package/src/compiler/result-selection.ts +0 -161
- package/src/compiler/runtime/index.ts +0 -26
- package/src/compiler/runtime-codegen.ts +0 -211
- package/src/compiler/runtime-validation-codegen.ts +0 -294
- package/src/compiler/runtime.ts +0 -452
- package/src/compiler/schema.ts +0 -245
- package/src/compiler/switch-branch-detection.ts +0 -92
- package/src/compiler/types.ts +0 -136
- package/src/compiler/unary-ast-transforms.ts +0 -148
- package/src/compiler/unary-parser.ts +0 -301
- package/src/compiler/unary-transform.ts +0 -161
- package/src/compiler/utils.ts +0 -27
- package/src/compiler/virtual-fs.ts +0 -90
- package/src/compiler/wasm-instantiate.ts +0 -127
- package/src/index.ts +0 -1
- package/src/runtime/arrays.ts +0 -579
- package/src/runtime/context.ts +0 -189
- package/src/runtime/expressions.ts +0 -1811
- package/src/runtime/index.ts +0 -8
- package/src/runtime/memory.ts +0 -607
- package/src/runtime/strings.ts +0 -260
- package/src/runtime/tables.ts +0 -96
- package/src/runtime/tsconfig.json +0 -4
- package/src/runtime/values.ts +0 -209
- package/test-data/README.md +0 -83
- package/test-data/decision-tables/basic/8k.json +0 -87992
- package/test-data/decision-tables/basic/affiliate-commission-calculator.json +0 -228
- package/test-data/decision-tables/basic/airline-loyalty-points-calculations.json +0 -285
- package/test-data/decision-tables/basic/airline-upgrade-eligibility.json +0 -466
- package/test-data/decision-tables/basic/auto-insurance-premium-calculator.json +0 -412
- package/test-data/decision-tables/basic/booking-personalization-system.json +0 -553
- package/test-data/decision-tables/basic/care-team-assignment-system.json +0 -585
- package/test-data/decision-tables/basic/claim-validation-system.json +0 -307
- package/test-data/decision-tables/basic/clinical-lab-result-interpreter.json +0 -433
- package/test-data/decision-tables/basic/clinical-treatment-protocol.json +0 -474
- package/test-data/decision-tables/basic/credit-limit-adjustment.json +0 -479
- package/test-data/decision-tables/basic/customer-eligibility-engine.json +0 -551
- package/test-data/decision-tables/basic/customer-lifetime-value.json +0 -200
- package/test-data/decision-tables/basic/customer-onboarding-kyc-verification.json +0 -611
- package/test-data/decision-tables/basic/customer-service-escalation.json +0 -191
- package/test-data/decision-tables/basic/decision-table-discounts.json +0 -168
- package/test-data/decision-tables/basic/decision-table-shipping.json +0 -398
- package/test-data/decision-tables/basic/delivery-route-optimizer.json +0 -271
- package/test-data/decision-tables/basic/device-compatibility-checker.json +0 -303
- package/test-data/decision-tables/basic/disaster-relief-fund-allocation.json +0 -296
- package/test-data/decision-tables/basic/dynamic-fx-rate-pricing-system.json +0 -237
- package/test-data/decision-tables/basic/dynamic-marketplace-comission-calculator.json +0 -242
- package/test-data/decision-tables/basic/dynamic-shipping-cost-calculator.json +0 -378
- package/test-data/decision-tables/basic/dynamic-tarrif-engine.json +0 -289
- package/test-data/decision-tables/basic/dynamic-ticket-pricing.json +0 -325
- package/test-data/decision-tables/basic/empty-column-with-space.json +0 -100
- package/test-data/decision-tables/basic/empty-column-without-space.json +0 -100
- package/test-data/decision-tables/basic/environment-compliance-assessment.json +0 -386
- package/test-data/decision-tables/basic/expression-table-map.json +0 -313
- package/test-data/decision-tables/basic/flash-sale-eligibility.json +0 -366
- package/test-data/decision-tables/basic/flight-dispatch-decision-system.json +0 -455
- package/test-data/decision-tables/basic/flight-rebooking-fee-calculator.json +0 -406
- package/test-data/decision-tables/basic/government-assistance.json +0 -299
- package/test-data/decision-tables/basic/grant-funding-distribution.json +0 -307
- package/test-data/decision-tables/basic/hazardous-materials-management-system.json +0 -414
- package/test-data/decision-tables/basic/immigration-eligibility-evaluator.json +0 -765
- package/test-data/decision-tables/basic/import-duties-calculator.json +0 -318
- package/test-data/decision-tables/basic/insurance-agent-commission.json +0 -228
- package/test-data/decision-tables/basic/insurance-coverage-calculator.json +0 -362
- package/test-data/decision-tables/basic/insurance-underwriting-risk.json +0 -321
- package/test-data/decision-tables/basic/international-roaming-policy-manager.json +0 -199
- package/test-data/decision-tables/basic/legacy-plan-management.json +0 -434
- package/test-data/decision-tables/basic/marketplace-listing-verification-system.json +0 -334
- package/test-data/decision-tables/basic/medication-dosage-calculator.json +0 -318
- package/test-data/decision-tables/basic/merch-bags.json +0 -171
- package/test-data/decision-tables/basic/municipal-permit-evaluation-system.json +0 -364
- package/test-data/decision-tables/basic/mvno-partner-enablement.json +0 -313
- package/test-data/decision-tables/basic/partner-revenue-sharing.json +0 -244
- package/test-data/decision-tables/basic/payment-routing-and-fee-calculator.json +0 -475
- package/test-data/decision-tables/basic/policy-discount-calculator.json +0 -307
- package/test-data/decision-tables/basic/policy-eligibility-analyzer.json +0 -299
- package/test-data/decision-tables/basic/product-listing-scoring.json +0 -358
- package/test-data/decision-tables/basic/realtime-fraud-detection.json +0 -235
- package/test-data/decision-tables/basic/regional-compliance-manager.json +0 -278
- package/test-data/decision-tables/basic/returns-and-refund-policy.json +0 -366
- package/test-data/decision-tables/basic/returns-processing-system.json +0 -448
- package/test-data/decision-tables/basic/school-district-resource-allocation.json +0 -282
- package/test-data/decision-tables/basic/seat-map-optimization.json +0 -325
- package/test-data/decision-tables/basic/seller-fee-calculator.json +0 -307
- package/test-data/decision-tables/basic/service-level-agreement-enforcement.json +0 -575
- package/test-data/decision-tables/basic/smart-financial-product-matcher.json +0 -249
- package/test-data/decision-tables/basic/supply-chain-risk.json +0 -316
- package/test-data/decision-tables/basic/table-loop.json +0 -93
- package/test-data/decision-tables/basic/table.json +0 -76
- package/test-data/decision-tables/basic/traffic-violation-penalty-calculator.json +0 -436
- package/test-data/decision-tables/basic/transaction-compliance-classifier.json +0 -525
- package/test-data/decision-tables/basic/vehicle-claims-resolution.json +0 -310
- package/test-data/decision-tables/basic/warehouse-storage-location.json +0 -345
- package/test-data/decision-tables/hit-policy-collect/collect-multiple-matches.json +0 -127
- package/test-data/decision-tables/hit-policy-collect/collect-no-match.json +0 -95
- package/test-data/decision-tables/hit-policy-first/first-match.json +0 -103
- package/test-data/decision-tables/hit-policy-first/no-match.json +0 -95
- package/test-data/decision-tables/hit-policy-output-order/output-order-respected.json +0 -94
- package/test-data/decision-tables/hit-policy-output-order/string-output-order.json +0 -94
- package/test-data/decision-tables/hit-policy-priority/priority-respected.json +0 -86
- package/test-data/decision-tables/hit-policy-rule-order/rule-order-respected.json +0 -94
- package/test-data/decision-tables/hit-policy-unique/all-match-error.json +0 -89
- package/test-data/decision-tables/hit-policy-unique/multiple-match-error.json +0 -89
- package/test-data/decision-tables/hit-policy-unique/no-match.json +0 -88
- package/test-data/decision-tables/hit-policy-unique/unique-match.json +0 -99
- package/test-data/expressions/arithmetic/error-cyclic.json +0 -114
- package/test-data/expressions/arithmetic/error-missing-input.json +0 -54
- package/test-data/expressions/arithmetic/error-missing-output.json +0 -54
- package/test-data/expressions/arithmetic/expression-default.json +0 -93
- package/test-data/expressions/arithmetic/expression-fields.json +0 -94
- package/test-data/expressions/arithmetic/expression-loop.json +0 -94
- package/test-data/expressions/arithmetic/expression-passthrough.json +0 -108
- package/test-data/expressions/arithmetic/expression.json +0 -69
- package/test-data/expressions/arithmetic/nested-request.json +0 -125
- package/test-data/expressions/arithmetic/number-function.json +0 -58
- package/test-data/expressions/arithmetic/test-number-functions.json +0 -68
- package/test-data/expressions/functions/all.json +0 -149
- package/test-data/expressions/functions/avg.json +0 -89
- package/test-data/expressions/functions/filter.json +0 -109
- package/test-data/expressions/functions/flat.json +0 -167
- package/test-data/expressions/functions/map-strings.json +0 -65
- package/test-data/expressions/functions/map.json +0 -73
- package/test-data/expressions/functions/reduce.json +0 -49
- package/test-data/expressions/functions/some.json +0 -175
- package/test-data/expressions/functions/sort-strings.json +0 -97
- package/test-data/expressions/functions/sort.json +0 -97
- package/test-data/expressions/logical/logical-and.json +0 -116
- package/test-data/expressions/logical/logical-complex.json +0 -260
- package/test-data/expressions/logical/logical-not.json +0 -111
- package/test-data/expressions/logical/logical-or.json +0 -123
- package/test-data/expressions/string/string-comparison.json +0 -128
- package/test-data/expressions/string/string-concat.json +0 -106
- package/test-data/expressions/string/string-contains.json +0 -125
- package/test-data/expressions/string/string-endsWith.json +0 -113
- package/test-data/expressions/string/string-indexOf.json +0 -131
- package/test-data/expressions/string/string-join.json +0 -92
- package/test-data/expressions/string/string-lower.json +0 -94
- package/test-data/expressions/string/string-replace.json +0 -130
- package/test-data/expressions/string/string-split.json +0 -101
- package/test-data/expressions/string/string-startsWith.json +0 -113
- package/test-data/expressions/string/string-substring.json +0 -138
- package/test-data/expressions/string/string-trim.json +0 -100
- package/test-data/expressions/string/string-upper.json +0 -94
- package/test-data/other/custom.json +0 -51
- package/test-data/other/customer-input-schema.json +0 -34
- package/test-data/other/customer-output-schema.json +0 -34
- package/test-data/other/passthrough.json +0 -31
- package/test-data/sub-decisions/basic/$nodes-child.json +0 -31
- package/test-data/sub-decisions/basic/$nodes-parent.json +0 -49
- package/test-data/sub-decisions/basic/recursive-table1.json +0 -49
- package/test-data/sub-decisions/basic/recursive-table2.json +0 -49
- package/test-data/sub-decisions/complex-multi/approval-decision.json +0 -31
- package/test-data/sub-decisions/complex-multi/complex-dag.json +0 -175
- package/test-data/sub-decisions/complex-multi/credit-check.json +0 -31
- package/test-data/sub-decisions/complex-multi/customer-segmentation.json +0 -31
- package/test-data/sub-decisions/complex-multi/discount-eligibility.json +0 -31
- package/test-data/sub-decisions/complex-multi/eligibility-check.json +0 -31
- package/test-data/sub-decisions/complex-multi/final-offer.json +0 -31
- package/test-data/sub-decisions/complex-multi/income-verification.json +0 -31
- package/test-data/sub-decisions/complex-multi/linear-chain.json +0 -121
- package/test-data/sub-decisions/complex-multi/pricing-calculation.json +0 -31
- package/test-data/sub-decisions/complex-multi/product-eligibility.json +0 -31
- package/test-data/sub-decisions/complex-multi/risk-assessment.json +0 -31
- package/test-data/sub-decisions/complex-multi/shared-validation.json +0 -31
- package/test-data/sub-decisions/complex-multi/validation.json +0 -31
- package/test-data/sub-decisions/diamond/decision-a.json +0 -31
- package/test-data/sub-decisions/diamond/decision-b.json +0 -31
- package/test-data/sub-decisions/diamond/decision-c.json +0 -31
- package/test-data/sub-decisions/diamond/decision-shared.json +0 -31
- package/test-data/sub-decisions/diamond/diamond-pattern.json +0 -109
- package/test-data/sub-decisions/error-propagation/parent-calls-error.json +0 -44
- package/test-data/sub-decisions/error-propagation/sub-decision-with-error.json +0 -60
- package/test-data/switch-nodes/basic/account-dormancy-management.json +0 -245
- package/test-data/switch-nodes/basic/application-risk-assessment.json +0 -474
- package/test-data/switch-nodes/basic/cellular-data-rollover-system.json +0 -281
- package/test-data/switch-nodes/basic/clinical-pathway-selection.json +0 -454
- package/test-data/switch-nodes/basic/insurance-prior-authorization.json +0 -467
- package/test-data/switch-nodes/basic/last-mile-delivery-assignment.json +0 -373
- package/test-data/switch-nodes/basic/loan-approval.json +0 -469
- package/test-data/switch-nodes/basic/multi-switch.json +0 -498
- package/test-data/switch-nodes/basic/online-checkin-eligibility.json +0 -285
- package/test-data/switch-nodes/basic/order-consolidation-system.json +0 -493
- package/test-data/switch-nodes/basic/seller-approval-workflow.json +0 -383
- package/test-data/switch-nodes/basic/set-fee.json +0 -243
- package/test-data/switch-nodes/basic/shipping-carrier-selector.json +0 -379
- package/test-data/switch-nodes/basic/switch-node.json +0 -167
- package/test-data/switch-nodes/basic/switch-performance-2.json +0 -1307
- package/test-data/switch-nodes/basic/switch-performance.json +0 -691
- package/test-data/switch-nodes/basic/tax-exemption.json +0 -295
- package/test-data/switch-nodes/basic/warehouse-cross-docking.json +0 -313
- package/test-data/switch-nodes/default-cases/switch-with-default.json +0 -134
- package/test-data/zen-reference/$nodes-child.json +0 -69
- package/test-data/zen-reference/$nodes-parent.json +0 -34
- package/test-data/zen-reference/8k.json +0 -87992
- package/test-data/zen-reference/credit-analysis.json +0 -324
- package/test-data/zen-reference/custom.json +0 -51
- package/test-data/zen-reference/customer-input-schema.json +0 -34
- package/test-data/zen-reference/customer-output-schema.json +0 -34
- package/test-data/zen-reference/error-cyclic.json +0 -114
- package/test-data/zen-reference/error-missing-input.json +0 -54
- package/test-data/zen-reference/error-missing-output.json +0 -54
- package/test-data/zen-reference/expression.json +0 -69
- package/test-data/zen-reference/function-v2.json +0 -48
- package/test-data/zen-reference/function.json +0 -46
- package/test-data/zen-reference/graphs/account-dormancy-management.json +0 -245
- package/test-data/zen-reference/graphs/affiliate-commission-calculator.json +0 -228
- package/test-data/zen-reference/graphs/airline-loyalty-points-calculations.json +0 -285
- package/test-data/zen-reference/graphs/airline-upgrade-eligibility.json +0 -466
- package/test-data/zen-reference/graphs/aml.json +0 -537
- package/test-data/zen-reference/graphs/application-risk-assessment.json +0 -474
- package/test-data/zen-reference/graphs/auto-insurance-premium-calculator.json +0 -412
- package/test-data/zen-reference/graphs/booking-personalization-system.json +0 -553
- package/test-data/zen-reference/graphs/care-team-assignment-system.json +0 -585
- package/test-data/zen-reference/graphs/cellular-data-rollover-system.json +0 -281
- package/test-data/zen-reference/graphs/claim-validation-system.json +0 -307
- package/test-data/zen-reference/graphs/clinical-lab-result-interpreter.json +0 -433
- package/test-data/zen-reference/graphs/clinical-pathway-selection.json +0 -454
- package/test-data/zen-reference/graphs/clinical-treatment-protocol.json +0 -474
- package/test-data/zen-reference/graphs/company-analysis.json +0 -390
- package/test-data/zen-reference/graphs/credit-limit-adjustment.json +0 -479
- package/test-data/zen-reference/graphs/customer-eligibility-engine.json +0 -551
- package/test-data/zen-reference/graphs/customer-lifetime-value.json +0 -200
- package/test-data/zen-reference/graphs/customer-onboarding-kyc-verification.json +0 -611
- package/test-data/zen-reference/graphs/customer-service-escalation.json +0 -191
- package/test-data/zen-reference/graphs/decision-table-discounts.json +0 -168
- package/test-data/zen-reference/graphs/decision-table-shipping.json +0 -398
- package/test-data/zen-reference/graphs/delivery-route-optimizer.json +0 -271
- package/test-data/zen-reference/graphs/device-compatibility-checker.json +0 -303
- package/test-data/zen-reference/graphs/disaster-relief-fund-allocation.json +0 -296
- package/test-data/zen-reference/graphs/dynamic-fx-rate-pricing-system.json +0 -237
- package/test-data/zen-reference/graphs/dynamic-marketplace-comission-calculator.json +0 -242
- package/test-data/zen-reference/graphs/dynamic-shipping-cost-calculator.json +0 -378
- package/test-data/zen-reference/graphs/dynamic-tarrif-engine.json +0 -289
- package/test-data/zen-reference/graphs/dynamic-ticket-pricing.json +0 -325
- package/test-data/zen-reference/graphs/empty-column-with-space.json +0 -100
- package/test-data/zen-reference/graphs/empty-column-without-space.json +0 -100
- package/test-data/zen-reference/graphs/environment-compliance-assessment.json +0 -386
- package/test-data/zen-reference/graphs/expression-default.json +0 -93
- package/test-data/zen-reference/graphs/expression-fields.json +0 -94
- package/test-data/zen-reference/graphs/expression-loop.json +0 -94
- package/test-data/zen-reference/graphs/expression-passthrough.json +0 -108
- package/test-data/zen-reference/graphs/expression-table-map.json +0 -313
- package/test-data/zen-reference/graphs/flash-sale-eligibility.json +0 -366
- package/test-data/zen-reference/graphs/flight-dispatch-decision-system.json +0 -455
- package/test-data/zen-reference/graphs/flight-rebooking-fee-calculator.json +0 -406
- package/test-data/zen-reference/graphs/government-assistance.json +0 -299
- package/test-data/zen-reference/graphs/grant-funding-distribution.json +0 -307
- package/test-data/zen-reference/graphs/hazardous-materials-management-system.json +0 -414
- package/test-data/zen-reference/graphs/immigration-eligibility-evaluator.json +0 -765
- package/test-data/zen-reference/graphs/import-duties-calculator.json +0 -318
- package/test-data/zen-reference/graphs/insurance-agent-commission.json +0 -228
- package/test-data/zen-reference/graphs/insurance-breakdown.json +0 -421
- package/test-data/zen-reference/graphs/insurance-coverage-calculator.json +0 -362
- package/test-data/zen-reference/graphs/insurance-prior-authorization.json +0 -467
- package/test-data/zen-reference/graphs/insurance-underwriting-risk.json +0 -321
- package/test-data/zen-reference/graphs/international-roaming-policy-manager.json +0 -199
- package/test-data/zen-reference/graphs/last-mile-delivery-assignment.json +0 -373
- package/test-data/zen-reference/graphs/legacy-plan-management.json +0 -434
- package/test-data/zen-reference/graphs/loan-approval.json +0 -469
- package/test-data/zen-reference/graphs/marketplace-listing-verification-system.json +0 -334
- package/test-data/zen-reference/graphs/medication-dosage-calculator.json +0 -318
- package/test-data/zen-reference/graphs/merch-bags.json +0 -171
- package/test-data/zen-reference/graphs/multi-switch.json +0 -498
- package/test-data/zen-reference/graphs/municipal-permit-evaluation-system.json +0 -364
- package/test-data/zen-reference/graphs/mvno-partner-enablement.json +0 -313
- package/test-data/zen-reference/graphs/nested-request.json +0 -125
- package/test-data/zen-reference/graphs/online-checkin-eligibility.json +0 -285
- package/test-data/zen-reference/graphs/order-consolidation-system.json +0 -493
- package/test-data/zen-reference/graphs/partner-revenue-sharing.json +0 -244
- package/test-data/zen-reference/graphs/payment-routing-and-fee-calculator.json +0 -475
- package/test-data/zen-reference/graphs/policy-discount-calculator.json +0 -307
- package/test-data/zen-reference/graphs/policy-eligibility-analyzer.json +0 -299
- package/test-data/zen-reference/graphs/product-listing-scoring.json +0 -358
- package/test-data/zen-reference/graphs/realtime-fraud-detection.json +0 -235
- package/test-data/zen-reference/graphs/regional-compliance-manager.json +0 -278
- package/test-data/zen-reference/graphs/returns-and-refund-policy.json +0 -366
- package/test-data/zen-reference/graphs/returns-processing-system.json +0 -448
- package/test-data/zen-reference/graphs/school-district-resource-allocation.json +0 -282
- package/test-data/zen-reference/graphs/seat-map-optimization.json +0 -325
- package/test-data/zen-reference/graphs/seller-approval-workflow.json +0 -383
- package/test-data/zen-reference/graphs/seller-fee-calculator.json +0 -307
- package/test-data/zen-reference/graphs/service-level-agreement-enforcement.json +0 -575
- package/test-data/zen-reference/graphs/set-fee.json +0 -243
- package/test-data/zen-reference/graphs/shipping-carrier-selector.json +0 -379
- package/test-data/zen-reference/graphs/smart-financial-product-matcher.json +0 -249
- package/test-data/zen-reference/graphs/supply-chain-risk.json +0 -316
- package/test-data/zen-reference/graphs/table-loop.json +0 -93
- package/test-data/zen-reference/graphs/tax-exemption.json +0 -295
- package/test-data/zen-reference/graphs/traffic-violation-penalty-calculator.json +0 -436
- package/test-data/zen-reference/graphs/transaction-compliance-classifier.json +0 -525
- package/test-data/zen-reference/graphs/vehicle-claims-resolution.json +0 -310
- package/test-data/zen-reference/graphs/warehouse-cross-docking.json +0 -313
- package/test-data/zen-reference/graphs/warehouse-storage-location.json +0 -345
- package/test-data/zen-reference/http-function.json +0 -34
- package/test-data/zen-reference/infinite-function.json +0 -46
- package/test-data/zen-reference/js/imports.js +0 -25
- package/test-data/zen-reference/passthrough.json +0 -31
- package/test-data/zen-reference/recursive-table1.json +0 -49
- package/test-data/zen-reference/recursive-table2.json +0 -49
- package/test-data/zen-reference/sleep-function.json +0 -34
- package/test-data/zen-reference/switch-node.json +0 -167
- package/test-data/zen-reference/switch-performance-2.json +0 -1307
- package/test-data/zen-reference/switch-performance.json +0 -691
- package/test-data/zen-reference/table.json +0 -76
- package/tests/helpers/index.ts +0 -73
- package/tests/helpers/mock-context.ts +0 -231
- package/tests/helpers/round-trip.ts +0 -398
- package/tests/helpers/test-harness-comparison.ts +0 -325
- package/tests/helpers/test-harness-wasm.ts +0 -710
- package/tests/helpers/test-harness.ts +0 -28
- package/tests/helpers/wasm-test.ts +0 -659
- package/tests/integration/compilation-errors.test.ts +0 -864
- package/tests/integration/decision-tables.test.ts +0 -531
- package/tests/integration/edge-cases.test.ts +0 -787
- package/tests/integration/expressions.test.ts +0 -513
- package/tests/integration/function-node-integration.test.ts +0 -182
- package/tests/integration/sub-decisions.test.ts +0 -108
- package/tests/integration/switch-nodes.test.ts +0 -399
- package/tests/integration/unary-or-matching.test.ts +0 -53
- package/tests/integration/wasm-data-types.test.ts +0 -398
- package/tests/integration/wasm-errors.test.ts +0 -199
- package/tests/integration/wasm-execution.test.ts +0 -348
- package/tests/integration/wasm-memory.test.ts +0 -228
- package/tests/scripts/analyze-coverage.ts +0 -166
- package/tests/scripts/categorize-tests.ts +0 -396
- package/tests/scripts/coverage-analysis.ts +0 -836
- package/tests/unit/compiler/cache.test.ts +0 -238
- package/tests/unit/compiler/errors.test.ts +0 -316
- package/tests/unit/compiler/graph-scalability.test.ts +0 -510
- package/tests/unit/compiler/graph.test.ts +0 -878
- package/tests/unit/compiler/input-validation.test.ts +0 -447
- package/tests/unit/compiler/logical-and-parser.test.ts +0 -143
- package/tests/unit/compiler/logical-not-parser.test.ts +0 -107
- package/tests/unit/compiler/logical-or-parser.test.ts +0 -236
- package/tests/unit/compiler/marshal-gen/marshal-gen.test.ts +0 -97
- package/tests/unit/compiler/nodes/decision-table.test.ts +0 -103
- package/tests/unit/compiler/nodes/decision.test.ts +0 -182
- package/tests/unit/compiler/nodes/function-compile.test.ts +0 -204
- package/tests/unit/compiler/nodes/function.test.ts +0 -176
- package/tests/unit/compiler/nodes/input.test.ts +0 -30
- package/tests/unit/compiler/nodes/switch.test.ts +0 -127
- package/tests/unit/compiler/optimizer-cache.test.ts +0 -327
- package/tests/unit/compiler/optimizer-implementation.test.ts +0 -625
- package/tests/unit/compiler/parser.test.ts +0 -508
- package/tests/unit/compiler/runtime-error-cleanup.test.ts +0 -426
- package/tests/unit/compiler/runtime-validation.test.ts +0 -303
- package/tests/unit/compiler/runtime.test.ts +0 -221
- package/tests/unit/compiler/schema/schema.test.ts +0 -248
- package/tests/unit/compiler/unary-ast-transforms.test.ts +0 -245
- package/tsconfig.json +0 -27
- package/tsup.config.ts +0 -11
- package/vitest.config.ts +0 -12
package/benchmarks/run.ts
DELETED
|
@@ -1,913 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance Benchmark Runner
|
|
3
|
-
*
|
|
4
|
-
* Runs performance benchmarks comparing zen-engine vs jdm-asm using Mitata.
|
|
5
|
-
* Supports both single-threaded and multi-threaded (concurrent) benchmarks.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { readFileSync } from 'node:fs';
|
|
9
|
-
import { cpus } from 'node:os';
|
|
10
|
-
import { styleText } from 'node:util';
|
|
11
|
-
|
|
12
|
-
import { run, bench, group, summary } from 'mitata';
|
|
13
|
-
import { ZenEngine } from '@gorules/zen-engine';
|
|
14
|
-
import { compile, type CompilationResult } from '../src/compiler';
|
|
15
|
-
import { ReusableWasmEvaluator, inferSchema } from '../tests/helpers/test-harness-wasm';
|
|
16
|
-
import { simpleInput, moderateInput, complexInput } from './input-fixtures';
|
|
17
|
-
import { WorkerPool, LatencyTracker } from './worker-pool';
|
|
18
|
-
|
|
19
|
-
// Uses simple string equality and numeric outputs
|
|
20
|
-
const simpleJdm = readFileSync('test-data/decision-tables/basic/merch-bags.json', 'utf-8');
|
|
21
|
-
|
|
22
|
-
// Uses more complex expressions like sum(map(...)) and contains($, ...)
|
|
23
|
-
const moderateJdm = readFileSync('test-data/decision-tables/basic/decision-table-shipping.json', 'utf-8');
|
|
24
|
-
|
|
25
|
-
// Complex: Large decision table with 8000+ rules
|
|
26
|
-
const complexJdm = readFileSync('test-data/decision-tables/basic/8k.json', 'utf-8');
|
|
27
|
-
|
|
28
|
-
// Initialize zen-engine
|
|
29
|
-
console.log('Initializing benchmark engines...\n');
|
|
30
|
-
const zenEngine = new ZenEngine();
|
|
31
|
-
|
|
32
|
-
// Create zen-engine decisions (done once, outside benchmarks)
|
|
33
|
-
console.log(' Loading zen-engine decisions...');
|
|
34
|
-
const zenSimple = zenEngine.createDecision(JSON.parse(simpleJdm));
|
|
35
|
-
const zenModerate = zenEngine.createDecision(JSON.parse(moderateJdm));
|
|
36
|
-
const zenComplex = zenEngine.createDecision(JSON.parse(complexJdm));
|
|
37
|
-
|
|
38
|
-
// Compiled jdm-asm decisions (using ReusableWasmEvaluator for proper hot path benchmarking)
|
|
39
|
-
let asmSimple: ReusableWasmEvaluator;
|
|
40
|
-
let asmModerate: ReusableWasmEvaluator;
|
|
41
|
-
let asmComplex: ReusableWasmEvaluator;
|
|
42
|
-
|
|
43
|
-
// Store compilation results for worker pool initialization
|
|
44
|
-
let compiledSimpleResult: CompilationResult;
|
|
45
|
-
let compiledModerateResult: CompilationResult;
|
|
46
|
-
let compiledComplexResult: CompilationResult;
|
|
47
|
-
|
|
48
|
-
// Worker pools for concurrent benchmarks
|
|
49
|
-
let workerPoolSimple: WorkerPool | null = null;
|
|
50
|
-
let workerPoolModerate: WorkerPool | null = null;
|
|
51
|
-
let workerPoolComplex: WorkerPool | null = null;
|
|
52
|
-
|
|
53
|
-
// Round-trip latency trackers (fair comparison - main thread perspective)
|
|
54
|
-
const rtLatencyTrackerSimple = new LatencyTracker();
|
|
55
|
-
const rtLatencyTrackerModerate = new LatencyTracker();
|
|
56
|
-
const rtLatencyTrackerComplex = new LatencyTracker();
|
|
57
|
-
|
|
58
|
-
// Execution latency trackers (worker-side only, for analysis)
|
|
59
|
-
const execLatencyTrackerSimple = new LatencyTracker();
|
|
60
|
-
const execLatencyTrackerModerate = new LatencyTracker();
|
|
61
|
-
const execLatencyTrackerComplex = new LatencyTracker();
|
|
62
|
-
|
|
63
|
-
// zen-engine latency (individual call latency, not queued)
|
|
64
|
-
const zenLatencyTrackerSimple = new LatencyTracker();
|
|
65
|
-
const zenLatencyTrackerModerate = new LatencyTracker();
|
|
66
|
-
const zenLatencyTrackerComplex = new LatencyTracker();
|
|
67
|
-
|
|
68
|
-
// In-thread latency trackers (jdm-asm running in main thread, no workers)
|
|
69
|
-
const inThreadLatencyTrackerSimple = new LatencyTracker();
|
|
70
|
-
const inThreadLatencyTrackerModerate = new LatencyTracker();
|
|
71
|
-
const inThreadLatencyTrackerComplex = new LatencyTracker();
|
|
72
|
-
|
|
73
|
-
// Track if complex compiled successfully
|
|
74
|
-
let complexCompiled = false;
|
|
75
|
-
|
|
76
|
-
// Batch size for concurrent benchmarks
|
|
77
|
-
const CONCURRENT_BATCH_SIZE = 1000;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Format a number with thousands separators
|
|
81
|
-
*/
|
|
82
|
-
function formatNumber(n: number): string {
|
|
83
|
-
return n.toLocaleString('en-US');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Format milliseconds as human-readable string
|
|
88
|
-
*/
|
|
89
|
-
function formatMs(ms: number): string {
|
|
90
|
-
if (ms < 1000) {
|
|
91
|
-
return `${ms.toFixed(0)} ms`;
|
|
92
|
-
} else {
|
|
93
|
-
return `${(ms / 1000).toFixed(2)} s`;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Warm up and verify
|
|
98
|
-
console.log('\nRunning warm-up validation...\n');
|
|
99
|
-
|
|
100
|
-
async function warmup() {
|
|
101
|
-
// Verify zen-engine
|
|
102
|
-
await zenSimple.evaluate(simpleInput);
|
|
103
|
-
console.log(' zen-engine simple: ready');
|
|
104
|
-
|
|
105
|
-
await zenModerate.evaluate(moderateInput);
|
|
106
|
-
console.log(' zen-engine moderate: ready');
|
|
107
|
-
|
|
108
|
-
// Complex might take longer, just log
|
|
109
|
-
try {
|
|
110
|
-
await zenComplex.evaluate(complexInput);
|
|
111
|
-
console.log(' zen-engine complex: ready');
|
|
112
|
-
} catch (_err) {
|
|
113
|
-
console.log(' zen-engine complex warm-up skipped (large file)');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Compile jdm-asm and measure compilation times
|
|
117
|
-
console.log('\nCompiling jdm-asm modules...\n');
|
|
118
|
-
|
|
119
|
-
const simpleStart = performance.now();
|
|
120
|
-
compiledSimpleResult = await compile({
|
|
121
|
-
inputSchema: inferSchema(simpleInput),
|
|
122
|
-
outputSchema: inferSchema({}),
|
|
123
|
-
jdm: simpleJdm,
|
|
124
|
-
optimize: true,
|
|
125
|
-
});
|
|
126
|
-
const simpleCompileTime = performance.now() - simpleStart;
|
|
127
|
-
asmSimple = new ReusableWasmEvaluator(compiledSimpleResult);
|
|
128
|
-
await asmSimple.initialize();
|
|
129
|
-
asmSimple.run(simpleInput); // Verify output
|
|
130
|
-
console.log(` Simple: ${formatNumber(compiledSimpleResult.wasm.length).padStart(12)} bytes in ${formatMs(simpleCompileTime).padStart(8)}`);
|
|
131
|
-
|
|
132
|
-
const moderateStart = performance.now();
|
|
133
|
-
compiledModerateResult = await compile({
|
|
134
|
-
inputSchema: inferSchema(moderateInput),
|
|
135
|
-
outputSchema: inferSchema({}),
|
|
136
|
-
jdm: moderateJdm,
|
|
137
|
-
optimize: true,
|
|
138
|
-
});
|
|
139
|
-
const moderateCompileTime = performance.now() - moderateStart;
|
|
140
|
-
asmModerate = new ReusableWasmEvaluator(compiledModerateResult);
|
|
141
|
-
await asmModerate.initialize();
|
|
142
|
-
asmModerate.run(moderateInput); // Verify output
|
|
143
|
-
console.log(` Moderate: ${formatNumber(compiledModerateResult.wasm.length).padStart(12)} bytes in ${formatMs(moderateCompileTime).padStart(8)}`);
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
const complexStart = performance.now();
|
|
147
|
-
compiledComplexResult = await compile({
|
|
148
|
-
inputSchema: inferSchema(complexInput),
|
|
149
|
-
outputSchema: inferSchema({}),
|
|
150
|
-
jdm: complexJdm,
|
|
151
|
-
optimize: true,
|
|
152
|
-
});
|
|
153
|
-
const complexCompileTime = performance.now() - complexStart;
|
|
154
|
-
asmComplex = new ReusableWasmEvaluator(compiledComplexResult);
|
|
155
|
-
await asmComplex.initialize();
|
|
156
|
-
asmComplex.run(complexInput); // Verify output
|
|
157
|
-
complexCompiled = true;
|
|
158
|
-
console.log(` Complex: ${formatNumber(compiledComplexResult.wasm.length).padStart(12)} bytes in ${formatMs(complexCompileTime).padStart(8)}`);
|
|
159
|
-
} catch (e) {
|
|
160
|
-
console.log(' Complex compilation skipped:', (e as Error).message.slice(0, 80));
|
|
161
|
-
// Fallback to simple for benchmarking structure
|
|
162
|
-
asmComplex = asmSimple;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
console.log('\nWarm-up complete\n');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Initialize worker pools for concurrent benchmarks
|
|
170
|
-
*/
|
|
171
|
-
async function initializeWorkerPools() {
|
|
172
|
-
const workerCount = cpus().length;
|
|
173
|
-
console.log(`\nInitializing worker pools (${workerCount} threads)...`);
|
|
174
|
-
|
|
175
|
-
console.log(' Initializing simple worker pool...');
|
|
176
|
-
workerPoolSimple = new WorkerPool(
|
|
177
|
-
new Uint8Array(compiledSimpleResult.wasm),
|
|
178
|
-
compiledSimpleResult.marshalCode
|
|
179
|
-
);
|
|
180
|
-
await workerPoolSimple.initialize();
|
|
181
|
-
console.log(` Simple pool ready with ${workerPoolSimple.getWorkerCount()} workers`);
|
|
182
|
-
|
|
183
|
-
console.log(' Initializing moderate worker pool...');
|
|
184
|
-
workerPoolModerate = new WorkerPool(
|
|
185
|
-
new Uint8Array(compiledModerateResult.wasm),
|
|
186
|
-
compiledModerateResult.marshalCode
|
|
187
|
-
);
|
|
188
|
-
await workerPoolModerate.initialize();
|
|
189
|
-
console.log(` Moderate pool ready with ${workerPoolModerate.getWorkerCount()} workers`);
|
|
190
|
-
|
|
191
|
-
if (complexCompiled) {
|
|
192
|
-
console.log(' Initializing complex worker pool...');
|
|
193
|
-
workerPoolComplex = new WorkerPool(
|
|
194
|
-
new Uint8Array(compiledComplexResult.wasm),
|
|
195
|
-
compiledComplexResult.marshalCode
|
|
196
|
-
);
|
|
197
|
-
await workerPoolComplex.initialize();
|
|
198
|
-
console.log(` Complex pool ready with ${workerPoolComplex.getWorkerCount()} workers`);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
console.log('Worker pools initialized\n');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Shutdown worker pools
|
|
206
|
-
*/
|
|
207
|
-
async function shutdownWorkerPools() {
|
|
208
|
-
if (workerPoolSimple) {
|
|
209
|
-
await workerPoolSimple.shutdown();
|
|
210
|
-
workerPoolSimple = null;
|
|
211
|
-
}
|
|
212
|
-
if (workerPoolModerate) {
|
|
213
|
-
await workerPoolModerate.shutdown();
|
|
214
|
-
workerPoolModerate = null;
|
|
215
|
-
}
|
|
216
|
-
if (workerPoolComplex) {
|
|
217
|
-
await workerPoolComplex.shutdown();
|
|
218
|
-
workerPoolComplex = null;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Format nanoseconds as human-readable string
|
|
224
|
-
*/
|
|
225
|
-
function formatNs(ns: number): string {
|
|
226
|
-
if (ns < 1000) {
|
|
227
|
-
return `${ns.toFixed(1)} ns`;
|
|
228
|
-
} else if (ns < 1_000_000) {
|
|
229
|
-
return `${(ns / 1000).toFixed(1)} µs`;
|
|
230
|
-
} else if (ns < 1_000_000_000) {
|
|
231
|
-
return `${(ns / 1_000_000).toFixed(1)} ms`;
|
|
232
|
-
} else {
|
|
233
|
-
return `${(ns / 1_000_000_000).toFixed(2)} s`;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Print latency percentiles summary
|
|
239
|
-
*/
|
|
240
|
-
function printLatencySummary() {
|
|
241
|
-
const workerCount = cpus().length;
|
|
242
|
-
|
|
243
|
-
console.log();
|
|
244
|
-
console.log(styleText('red', '=============== Per-Request Latency Percentiles ==============='));
|
|
245
|
-
|
|
246
|
-
// Round-trip latency section (fair comparison)
|
|
247
|
-
console.log();
|
|
248
|
-
console.log(styleText('green', 'Round-Trip Latency (concurrent, main thread perspective)'));
|
|
249
|
-
console.log(' p50 p95 p99');
|
|
250
|
-
|
|
251
|
-
// jdm-asm simple round-trip
|
|
252
|
-
const rtSimpleReport = rtLatencyTrackerSimple.report();
|
|
253
|
-
console.log(
|
|
254
|
-
`jdm-asm simple (${workerCount} thr)`.padEnd(25) +
|
|
255
|
-
formatNs(rtSimpleReport.p50).padStart(10) +
|
|
256
|
-
formatNs(rtSimpleReport.p95).padStart(11) +
|
|
257
|
-
formatNs(rtSimpleReport.p99).padStart(11)
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
// zen-engine simple
|
|
261
|
-
const zenSimpleReport = zenLatencyTrackerSimple.report();
|
|
262
|
-
console.log(
|
|
263
|
-
'zen-engine simple'.padEnd(25) +
|
|
264
|
-
formatNs(zenSimpleReport.p50).padStart(10) +
|
|
265
|
-
formatNs(zenSimpleReport.p95).padStart(11) +
|
|
266
|
-
formatNs(zenSimpleReport.p99).padStart(11)
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
// jdm-asm moderate round-trip
|
|
270
|
-
const rtModerateReport = rtLatencyTrackerModerate.report();
|
|
271
|
-
console.log(
|
|
272
|
-
`jdm-asm moderate (${workerCount} thr)`.padEnd(25) +
|
|
273
|
-
formatNs(rtModerateReport.p50).padStart(10) +
|
|
274
|
-
formatNs(rtModerateReport.p95).padStart(11) +
|
|
275
|
-
formatNs(rtModerateReport.p99).padStart(11)
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
// zen-engine moderate
|
|
279
|
-
const zenModerateReport = zenLatencyTrackerModerate.report();
|
|
280
|
-
console.log(
|
|
281
|
-
'zen-engine moderate'.padEnd(25) +
|
|
282
|
-
formatNs(zenModerateReport.p50).padStart(10) +
|
|
283
|
-
formatNs(zenModerateReport.p95).padStart(11) +
|
|
284
|
-
formatNs(zenModerateReport.p99).padStart(11)
|
|
285
|
-
);
|
|
286
|
-
|
|
287
|
-
// jdm-asm complex round-trip (only if complex was compiled)
|
|
288
|
-
if (complexCompiled) {
|
|
289
|
-
const rtComplexReport = rtLatencyTrackerComplex.report();
|
|
290
|
-
if (rtComplexReport.p50 > 0) {
|
|
291
|
-
console.log(
|
|
292
|
-
`jdm-asm complex (${workerCount} thr)`.padEnd(25) +
|
|
293
|
-
formatNs(rtComplexReport.p50).padStart(10) +
|
|
294
|
-
formatNs(rtComplexReport.p95).padStart(11) +
|
|
295
|
-
formatNs(rtComplexReport.p99).padStart(11)
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
// zen-engine complex
|
|
299
|
-
const zenComplexReport = zenLatencyTrackerComplex.report();
|
|
300
|
-
console.log(
|
|
301
|
-
'zen-engine complex'.padEnd(25) +
|
|
302
|
-
formatNs(zenComplexReport.p50).padStart(10) +
|
|
303
|
-
formatNs(zenComplexReport.p95).padStart(11) +
|
|
304
|
-
formatNs(zenComplexReport.p99).padStart(11)
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// In-thread latency section (jdm-asm in main thread, no workers)
|
|
310
|
-
console.log();
|
|
311
|
-
console.log(styleText('green', 'In-Thread Latency (jdm-asm in main thread, no worker overhead)'));
|
|
312
|
-
console.log(' p50 p95 p99');
|
|
313
|
-
|
|
314
|
-
const inThreadSimpleReport = inThreadLatencyTrackerSimple.report();
|
|
315
|
-
console.log(
|
|
316
|
-
'jdm-asm simple'.padEnd(25) +
|
|
317
|
-
formatNs(inThreadSimpleReport.p50).padStart(10) +
|
|
318
|
-
formatNs(inThreadSimpleReport.p95).padStart(11) +
|
|
319
|
-
formatNs(inThreadSimpleReport.p99).padStart(11)
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
const inThreadModerateReport = inThreadLatencyTrackerModerate.report();
|
|
323
|
-
console.log(
|
|
324
|
-
'jdm-asm moderate'.padEnd(25) +
|
|
325
|
-
formatNs(inThreadModerateReport.p50).padStart(10) +
|
|
326
|
-
formatNs(inThreadModerateReport.p95).padStart(11) +
|
|
327
|
-
formatNs(inThreadModerateReport.p99).padStart(11)
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
if (complexCompiled) {
|
|
331
|
-
const inThreadComplexReport = inThreadLatencyTrackerComplex.report();
|
|
332
|
-
if (inThreadComplexReport.p50 > 0) {
|
|
333
|
-
console.log(
|
|
334
|
-
'jdm-asm complex'.padEnd(25) +
|
|
335
|
-
formatNs(inThreadComplexReport.p50).padStart(10) +
|
|
336
|
-
formatNs(inThreadComplexReport.p95).padStart(11) +
|
|
337
|
-
formatNs(inThreadComplexReport.p99).padStart(11)
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
console.log();
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Format throughput as human-readable string
|
|
347
|
-
*/
|
|
348
|
-
function formatThroughput(decisionsPerSecond: number): string {
|
|
349
|
-
if (decisionsPerSecond >= 1_000_000) {
|
|
350
|
-
return `${(decisionsPerSecond / 1_000_000).toFixed(2)}M`;
|
|
351
|
-
} else if (decisionsPerSecond >= 1_000) {
|
|
352
|
-
return `${(decisionsPerSecond / 1_000).toFixed(1)}K`;
|
|
353
|
-
} else {
|
|
354
|
-
return `${decisionsPerSecond.toFixed(0)}`;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Print throughput summary from benchmark results
|
|
360
|
-
*/
|
|
361
|
-
function printThroughputSummary(results: unknown) {
|
|
362
|
-
const workerCount = cpus().length;
|
|
363
|
-
|
|
364
|
-
// Extract benchmark data from mitata results
|
|
365
|
-
// Mitata returns { benchmarks: [{ alias, runs: [{ name, stats: { avg } }] }, ...] }
|
|
366
|
-
const mitataResults = results as {
|
|
367
|
-
benchmarks?: Array<{
|
|
368
|
-
alias?: string;
|
|
369
|
-
group?: number;
|
|
370
|
-
runs?: Array<{
|
|
371
|
-
name?: string;
|
|
372
|
-
stats?: { avg?: number };
|
|
373
|
-
}>;
|
|
374
|
-
}>;
|
|
375
|
-
};
|
|
376
|
-
if (!mitataResults?.benchmarks || !Array.isArray(mitataResults.benchmarks)) {
|
|
377
|
-
console.log('\n(Throughput summary unavailable - results format not recognized)');
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Build an array of benchmark results (since names can duplicate across groups)
|
|
382
|
-
const benchmarkResults: Array<{ name: string; group: number; avgNs: number }> = [];
|
|
383
|
-
for (const b of mitataResults.benchmarks) {
|
|
384
|
-
const name = b.alias ?? b.runs?.[0]?.name;
|
|
385
|
-
const avgNs = b.runs?.[0]?.stats?.avg ?? 0;
|
|
386
|
-
const group = b.group ?? 0;
|
|
387
|
-
if (avgNs > 0 && name) {
|
|
388
|
-
benchmarkResults.push({ name, group, avgNs });
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Helper to find benchmark by name and optionally group index
|
|
393
|
-
const findBenchmark = (name: string, groupIndex?: number): { avgNs: number } | null => {
|
|
394
|
-
const matches = benchmarkResults.filter(b => b.name === name);
|
|
395
|
-
if (matches.length === 0) return null;
|
|
396
|
-
if (groupIndex !== undefined && groupIndex < matches.length) {
|
|
397
|
-
return matches[groupIndex];
|
|
398
|
-
}
|
|
399
|
-
return matches[0];
|
|
400
|
-
};
|
|
401
|
-
|
|
402
|
-
// Helper to calculate throughput (avgNs is in nanoseconds)
|
|
403
|
-
const calcThroughput = (avgNs: number, batchSize: number): number => {
|
|
404
|
-
const avgSeconds = avgNs / 1_000_000_000;
|
|
405
|
-
return batchSize / avgSeconds;
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
console.log();
|
|
409
|
-
console.log(styleText('red', '======== Throughput Summary (decisions per second) ========'));
|
|
410
|
-
|
|
411
|
-
// Single-decision throughput (batch size = 1)
|
|
412
|
-
// Group 0 = Simple Rules, Group 1 = Moderate Rules
|
|
413
|
-
console.log();
|
|
414
|
-
console.log(styleText('green', 'Single-Decision (no concurrency)'));
|
|
415
|
-
console.log(` ${styleText('yellow', 'zen-engine')} ${styleText('yellow', 'jdm-asm')}`);
|
|
416
|
-
|
|
417
|
-
const zenSimple = findBenchmark('zen-engine', 0);
|
|
418
|
-
const asmSimple = findBenchmark('jdm-asm', 0);
|
|
419
|
-
if (zenSimple && asmSimple) {
|
|
420
|
-
console.log(
|
|
421
|
-
'Simple Rules'.padEnd(18) +
|
|
422
|
-
(formatThroughput(calcThroughput(zenSimple.avgNs, 1)) + '/sec').padStart(14) +
|
|
423
|
-
(formatThroughput(calcThroughput(asmSimple.avgNs, 1)) + '/sec').padStart(14)
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const zenModerate = findBenchmark('zen-engine', 1);
|
|
428
|
-
const asmModerate = findBenchmark('jdm-asm', 1);
|
|
429
|
-
if (zenModerate && asmModerate) {
|
|
430
|
-
console.log(
|
|
431
|
-
'Moderate Rules'.padEnd(18) +
|
|
432
|
-
(formatThroughput(calcThroughput(zenModerate.avgNs, 1)) + '/sec').padStart(14) +
|
|
433
|
-
(formatThroughput(calcThroughput(asmModerate.avgNs, 1)) + '/sec').padStart(14)
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
if (complexCompiled) {
|
|
438
|
-
const zenComplex = findBenchmark('zen-engine', 2);
|
|
439
|
-
const asmComplex = findBenchmark('jdm-asm', 2);
|
|
440
|
-
if (zenComplex && asmComplex) {
|
|
441
|
-
console.log(
|
|
442
|
-
'Complex Rules'.padEnd(18) +
|
|
443
|
-
(formatThroughput(calcThroughput(zenComplex.avgNs, 1)) + '/sec').padStart(14) +
|
|
444
|
-
(formatThroughput(calcThroughput(asmComplex.avgNs, 1)) + '/sec').padStart(14)
|
|
445
|
-
);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Single-thread batch throughput
|
|
450
|
-
const zenSimpleBatch = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, 0);
|
|
451
|
-
const asmSimpleBatch = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, 0);
|
|
452
|
-
if (zenSimpleBatch && asmSimpleBatch) {
|
|
453
|
-
console.log();
|
|
454
|
-
console.log(styleText('green', `Single-Thread Batch (${CONCURRENT_BATCH_SIZE} simultaneous decisions)`));
|
|
455
|
-
console.log(` ${styleText('yellow', 'zen-engine')} ${styleText('yellow', 'jdm-asm')}`);
|
|
456
|
-
|
|
457
|
-
console.log(
|
|
458
|
-
'Simple Rules'.padEnd(18) +
|
|
459
|
-
(formatThroughput(calcThroughput(zenSimpleBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
460
|
-
(formatThroughput(calcThroughput(asmSimpleBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
461
|
-
);
|
|
462
|
-
|
|
463
|
-
const zenModerateBatch = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, 1);
|
|
464
|
-
const asmModerateBatch = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, 1);
|
|
465
|
-
if (zenModerateBatch && asmModerateBatch) {
|
|
466
|
-
console.log(
|
|
467
|
-
'Moderate Rules'.padEnd(18) +
|
|
468
|
-
(formatThroughput(calcThroughput(zenModerateBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
469
|
-
(formatThroughput(calcThroughput(asmModerateBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
470
|
-
);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
if (complexCompiled) {
|
|
474
|
-
const zenComplexBatch = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, 2);
|
|
475
|
-
const asmComplexBatch = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, 2);
|
|
476
|
-
if (zenComplexBatch && asmComplexBatch) {
|
|
477
|
-
console.log(
|
|
478
|
-
'Complex Rules'.padEnd(18) +
|
|
479
|
-
(formatThroughput(calcThroughput(zenComplexBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
480
|
-
(formatThroughput(calcThroughput(asmComplexBatch.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
481
|
-
);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Multi-thread batch throughput
|
|
487
|
-
const zenSimpleMulti = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, 0);
|
|
488
|
-
const asmSimpleMulti = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, 0);
|
|
489
|
-
if (zenSimpleMulti && asmSimpleMulti) {
|
|
490
|
-
console.log();
|
|
491
|
-
console.log(styleText('green', `Multi-Thread Batch (${workerCount} threads, ${CONCURRENT_BATCH_SIZE} simultaneous decisions)`));
|
|
492
|
-
console.log(` ${styleText('yellow', 'zen-engine')} ${styleText('yellow', 'jdm-asm')}`);
|
|
493
|
-
|
|
494
|
-
console.log(
|
|
495
|
-
'Simple Rules'.padEnd(18) +
|
|
496
|
-
(formatThroughput(calcThroughput(zenSimpleMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
497
|
-
(formatThroughput(calcThroughput(asmSimpleMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
498
|
-
);
|
|
499
|
-
|
|
500
|
-
const zenModerateMulti = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, 1);
|
|
501
|
-
const asmModerateMulti = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, 1);
|
|
502
|
-
if (zenModerateMulti && asmModerateMulti) {
|
|
503
|
-
console.log(
|
|
504
|
-
'Moderate Rules'.padEnd(18) +
|
|
505
|
-
(formatThroughput(calcThroughput(zenModerateMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
506
|
-
(formatThroughput(calcThroughput(asmModerateMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (complexCompiled) {
|
|
511
|
-
const zenComplexMulti = findBenchmark(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, 2);
|
|
512
|
-
const asmComplexMulti = findBenchmark(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, 2);
|
|
513
|
-
if (zenComplexMulti && asmComplexMulti) {
|
|
514
|
-
console.log(
|
|
515
|
-
'Complex Rules'.padEnd(18) +
|
|
516
|
-
(formatThroughput(calcThroughput(zenComplexMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14) +
|
|
517
|
-
(formatThroughput(calcThroughput(asmComplexMulti.avgNs, CONCURRENT_BATCH_SIZE)) + '/sec').padStart(14)
|
|
518
|
-
);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
console.log();
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Print the guide explaining how to interpret benchmark results
|
|
528
|
-
*/
|
|
529
|
-
function printBenchmarkGuide(workerCount: number) {
|
|
530
|
-
console.log(`\
|
|
531
|
-
${styleText('green', '========== Performance Benchmarks: zen-engine vs jdm-asm ==========')}
|
|
532
|
-
|
|
533
|
-
This benchmark compares zen-engine (JavaScript/Rust) against jdm-asm
|
|
534
|
-
(WebAssembly). Results are organized into several sections.
|
|
535
|
-
|
|
536
|
-
${styleText('yellow', '1. Single-Decision Latency (Simple/Moderate/Complex Rules)')}
|
|
537
|
-
Measures time to evaluate ONE decision. This is raw execution speed
|
|
538
|
-
with no concurrency. Lower time = faster. Use this to compare the
|
|
539
|
-
baseline performance of each engine.
|
|
540
|
-
|
|
541
|
-
${styleText('yellow', '2. Single-Thread Batch')}
|
|
542
|
-
Measures total time to evaluate ${CONCURRENT_BATCH_SIZE} decisions sequentially in the
|
|
543
|
-
main thread. Despite using Promise.all, jdm-asm is synchronous so
|
|
544
|
-
there is no parallelism - decisions run one after another. The
|
|
545
|
-
reported time is for the ENTIRE batch, not per-decision.
|
|
546
|
-
|
|
547
|
-
${styleText('yellow', '3. Multi-Thread Batch')}
|
|
548
|
-
Measures total time to evaluate ${CONCURRENT_BATCH_SIZE} decisions using ${workerCount} worker
|
|
549
|
-
threads. jdm-asm distributes work across threads for true parallelism,
|
|
550
|
-
while zen-engine runs in the main thread (its async API provides no
|
|
551
|
-
parallelism). Compare to single-thread batch to see parallelization
|
|
552
|
-
benefits. Includes IPC overhead for jdm-asm workers.
|
|
553
|
-
|
|
554
|
-
${styleText('yellow', '4. Latency Percentiles')}
|
|
555
|
-
Per-request latency distribution from the multi-thread batch runs.
|
|
556
|
-
Shows p50/p95/p99 latencies for individual requests within the batch.
|
|
557
|
-
|
|
558
|
-
${styleText('yellow', '5. Throughput Summary')}
|
|
559
|
-
Decisions per second derived from the benchmark timings. Higher = better.
|
|
560
|
-
|
|
561
|
-
${styleText('green', '========================== Test Scenarios ==========================')}
|
|
562
|
-
|
|
563
|
-
${styleText('yellow', 'Simple:')} Airline bag fee lookup. 3 input fields (origin, destination,
|
|
564
|
-
class), 5 rules. Tests basic string matching with first-hit
|
|
565
|
-
policy - the lightest realistic workload.
|
|
566
|
-
|
|
567
|
-
${styleText('yellow', 'Moderate:')} E-commerce shipping calculator. Nested input with cart items
|
|
568
|
-
and customer data. Uses sum() and map() to compute cart total,
|
|
569
|
-
contains() for tag checks. 12 rules across 4 region groups.
|
|
570
|
-
Represents typical business logic complexity.
|
|
571
|
-
|
|
572
|
-
${styleText('yellow', 'Complex:')} Stress test with ~8000 rules. 6 input fields across customer/
|
|
573
|
-
product domains. Heavy use of string functions (endsWith) and
|
|
574
|
-
comparisons. Tests rule engine scalability - how performance
|
|
575
|
-
degrades as decision tables grow.
|
|
576
|
-
|
|
577
|
-
----------------------------------------------------------------------------`);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/**
|
|
581
|
-
* Define single-threaded benchmarks
|
|
582
|
-
*/
|
|
583
|
-
function defineSingleThreadedBenchmarks() {
|
|
584
|
-
// Define benchmark groups
|
|
585
|
-
summary(() => {
|
|
586
|
-
group('Simple Rules (5-10 fields)', () => {
|
|
587
|
-
bench('zen-engine', async () => {
|
|
588
|
-
return zenSimple.evaluate(simpleInput);
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
bench('jdm-asm', () => {
|
|
592
|
-
return asmSimple.run(simpleInput);
|
|
593
|
-
});
|
|
594
|
-
});
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
summary(() => {
|
|
598
|
-
group('Moderate Rules (20-30 fields)', () => {
|
|
599
|
-
bench('zen-engine', async () => {
|
|
600
|
-
return zenModerate.evaluate(moderateInput);
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
bench('jdm-asm', () => {
|
|
604
|
-
return asmModerate.run(moderateInput);
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
|
|
609
|
-
if (complexCompiled) {
|
|
610
|
-
summary(() => {
|
|
611
|
-
group('Complex Rules (40+ fields)', () => {
|
|
612
|
-
bench('zen-engine', async () => {
|
|
613
|
-
try {
|
|
614
|
-
return await zenComplex.evaluate(complexInput);
|
|
615
|
-
} catch {
|
|
616
|
-
return { result: 0 }; // Fallback
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
bench('jdm-asm', () => {
|
|
621
|
-
return asmComplex.run(complexInput);
|
|
622
|
-
});
|
|
623
|
-
});
|
|
624
|
-
});
|
|
625
|
-
} else {
|
|
626
|
-
console.log('Note: Complex benchmark skipped (jdm-asm compilation failed)\n');
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/**
|
|
631
|
-
* Define in-thread concurrent benchmarks (no worker threads)
|
|
632
|
-
*/
|
|
633
|
-
function defineInThreadConcurrentBenchmarks() {
|
|
634
|
-
// Generate batch inputs (same input repeated for statistical significance)
|
|
635
|
-
const simpleBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(simpleInput);
|
|
636
|
-
const moderateBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(moderateInput);
|
|
637
|
-
|
|
638
|
-
summary(() => {
|
|
639
|
-
group(`Single-Thread Batch: Simple Rules (${CONCURRENT_BATCH_SIZE} decisions)`, () => {
|
|
640
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
641
|
-
const results = await Promise.all(
|
|
642
|
-
simpleBatchInputs.map(async (input) => {
|
|
643
|
-
return zenSimple.evaluate(input);
|
|
644
|
-
})
|
|
645
|
-
);
|
|
646
|
-
return results.length;
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
650
|
-
const results = await Promise.all(
|
|
651
|
-
simpleBatchInputs.map(async (input) => {
|
|
652
|
-
const startTime = process.hrtime.bigint();
|
|
653
|
-
const result = asmSimple.run(input);
|
|
654
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
655
|
-
inThreadLatencyTrackerSimple.record(latencyNs);
|
|
656
|
-
return result;
|
|
657
|
-
})
|
|
658
|
-
);
|
|
659
|
-
return results.length;
|
|
660
|
-
});
|
|
661
|
-
});
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
summary(() => {
|
|
665
|
-
group(`Single-Thread Batch: Moderate Rules (${CONCURRENT_BATCH_SIZE} decisions)`, () => {
|
|
666
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
667
|
-
const results = await Promise.all(
|
|
668
|
-
moderateBatchInputs.map(async (input) => {
|
|
669
|
-
return zenModerate.evaluate(input);
|
|
670
|
-
})
|
|
671
|
-
);
|
|
672
|
-
return results.length;
|
|
673
|
-
});
|
|
674
|
-
|
|
675
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
676
|
-
const results = await Promise.all(
|
|
677
|
-
moderateBatchInputs.map(async (input) => {
|
|
678
|
-
const startTime = process.hrtime.bigint();
|
|
679
|
-
const result = asmModerate.run(input);
|
|
680
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
681
|
-
inThreadLatencyTrackerModerate.record(latencyNs);
|
|
682
|
-
return result;
|
|
683
|
-
})
|
|
684
|
-
);
|
|
685
|
-
return results.length;
|
|
686
|
-
});
|
|
687
|
-
});
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
if (complexCompiled) {
|
|
691
|
-
const complexBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(complexInput);
|
|
692
|
-
|
|
693
|
-
summary(() => {
|
|
694
|
-
group(`Single-Thread Batch: Complex Rules (${CONCURRENT_BATCH_SIZE} decisions)`, () => {
|
|
695
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
696
|
-
const results = await Promise.all(
|
|
697
|
-
complexBatchInputs.map(async (input) => {
|
|
698
|
-
try {
|
|
699
|
-
return await zenComplex.evaluate(input);
|
|
700
|
-
} catch {
|
|
701
|
-
return { result: 0 };
|
|
702
|
-
}
|
|
703
|
-
})
|
|
704
|
-
);
|
|
705
|
-
return results.length;
|
|
706
|
-
});
|
|
707
|
-
|
|
708
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch)`, async () => {
|
|
709
|
-
const results = await Promise.all(
|
|
710
|
-
complexBatchInputs.map(async (input) => {
|
|
711
|
-
const startTime = process.hrtime.bigint();
|
|
712
|
-
const result = asmComplex.run(input);
|
|
713
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
714
|
-
inThreadLatencyTrackerComplex.record(latencyNs);
|
|
715
|
-
return result;
|
|
716
|
-
})
|
|
717
|
-
);
|
|
718
|
-
return results.length;
|
|
719
|
-
});
|
|
720
|
-
});
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Define multi-threaded concurrent benchmarks (with worker threads)
|
|
727
|
-
*/
|
|
728
|
-
function defineMultiThreadedConcurrentBenchmarks() {
|
|
729
|
-
const workerCount = cpus().length;
|
|
730
|
-
|
|
731
|
-
// Generate batch inputs (same input repeated for statistical significance)
|
|
732
|
-
const simpleBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(simpleInput);
|
|
733
|
-
const moderateBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(moderateInput);
|
|
734
|
-
|
|
735
|
-
summary(() => {
|
|
736
|
-
group(`Multi-Thread Batch: Simple Rules (${CONCURRENT_BATCH_SIZE} decisions, ${workerCount} threads)`, () => {
|
|
737
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, async () => {
|
|
738
|
-
const results = await Promise.all(
|
|
739
|
-
simpleBatchInputs.map(async (input) => {
|
|
740
|
-
const startTime = process.hrtime.bigint();
|
|
741
|
-
const result = await zenSimple.evaluate(input);
|
|
742
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
743
|
-
zenLatencyTrackerSimple.record(latencyNs);
|
|
744
|
-
return result;
|
|
745
|
-
})
|
|
746
|
-
);
|
|
747
|
-
return results.length;
|
|
748
|
-
});
|
|
749
|
-
|
|
750
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, async () => {
|
|
751
|
-
const { roundTripLatencies, executionLatencies } = await workerPoolSimple!.evaluateBatch(simpleBatchInputs);
|
|
752
|
-
// Record latencies for percentile reporting
|
|
753
|
-
for (const latency of roundTripLatencies) {
|
|
754
|
-
rtLatencyTrackerSimple.record(latency);
|
|
755
|
-
}
|
|
756
|
-
for (const latency of executionLatencies) {
|
|
757
|
-
execLatencyTrackerSimple.record(latency);
|
|
758
|
-
}
|
|
759
|
-
return roundTripLatencies.length;
|
|
760
|
-
});
|
|
761
|
-
});
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
summary(() => {
|
|
765
|
-
group(`Multi-Thread Batch: Moderate Rules (${CONCURRENT_BATCH_SIZE} decisions, ${workerCount} threads)`, () => {
|
|
766
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, async () => {
|
|
767
|
-
const results = await Promise.all(
|
|
768
|
-
moderateBatchInputs.map(async (input) => {
|
|
769
|
-
const startTime = process.hrtime.bigint();
|
|
770
|
-
const result = await zenModerate.evaluate(input);
|
|
771
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
772
|
-
zenLatencyTrackerModerate.record(latencyNs);
|
|
773
|
-
return result;
|
|
774
|
-
})
|
|
775
|
-
);
|
|
776
|
-
return results.length;
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, async () => {
|
|
780
|
-
const { roundTripLatencies, executionLatencies } = await workerPoolModerate!.evaluateBatch(moderateBatchInputs);
|
|
781
|
-
// Record latencies for percentile reporting
|
|
782
|
-
for (const latency of roundTripLatencies) {
|
|
783
|
-
rtLatencyTrackerModerate.record(latency);
|
|
784
|
-
}
|
|
785
|
-
for (const latency of executionLatencies) {
|
|
786
|
-
execLatencyTrackerModerate.record(latency);
|
|
787
|
-
}
|
|
788
|
-
return roundTripLatencies.length;
|
|
789
|
-
});
|
|
790
|
-
});
|
|
791
|
-
});
|
|
792
|
-
|
|
793
|
-
if (complexCompiled && workerPoolComplex) {
|
|
794
|
-
const complexBatchInputs = Array(CONCURRENT_BATCH_SIZE).fill(complexInput);
|
|
795
|
-
|
|
796
|
-
summary(() => {
|
|
797
|
-
group(`Multi-Thread Batch: Complex Rules (${CONCURRENT_BATCH_SIZE} decisions, ${workerCount} threads)`, () => {
|
|
798
|
-
bench(`zen-engine (${CONCURRENT_BATCH_SIZE}-decision batch, main thread)`, async () => {
|
|
799
|
-
const results = await Promise.all(
|
|
800
|
-
complexBatchInputs.map(async (input) => {
|
|
801
|
-
const startTime = process.hrtime.bigint();
|
|
802
|
-
try {
|
|
803
|
-
const result = await zenComplex.evaluate(input);
|
|
804
|
-
const latencyNs = Number(process.hrtime.bigint() - startTime);
|
|
805
|
-
zenLatencyTrackerComplex.record(latencyNs);
|
|
806
|
-
return result;
|
|
807
|
-
} catch {
|
|
808
|
-
return { result: 0 };
|
|
809
|
-
}
|
|
810
|
-
})
|
|
811
|
-
);
|
|
812
|
-
return results.length;
|
|
813
|
-
});
|
|
814
|
-
|
|
815
|
-
bench(`jdm-asm (${CONCURRENT_BATCH_SIZE}-decision batch, ${workerCount} threads)`, async () => {
|
|
816
|
-
const { roundTripLatencies, executionLatencies } = await workerPoolComplex!.evaluateBatch(complexBatchInputs);
|
|
817
|
-
// Record latencies for percentile reporting
|
|
818
|
-
for (const latency of roundTripLatencies) {
|
|
819
|
-
rtLatencyTrackerComplex.record(latency);
|
|
820
|
-
}
|
|
821
|
-
for (const latency of executionLatencies) {
|
|
822
|
-
execLatencyTrackerComplex.record(latency);
|
|
823
|
-
}
|
|
824
|
-
return roundTripLatencies.length;
|
|
825
|
-
});
|
|
826
|
-
});
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
/**
|
|
832
|
-
* Define all benchmarks
|
|
833
|
-
*/
|
|
834
|
-
async function defineBenchmarks(options: { concurrent: boolean }) {
|
|
835
|
-
const workerCount = cpus().length;
|
|
836
|
-
|
|
837
|
-
// Print the guide at the start
|
|
838
|
-
printBenchmarkGuide(workerCount);
|
|
839
|
-
|
|
840
|
-
defineSingleThreadedBenchmarks();
|
|
841
|
-
|
|
842
|
-
if (options.concurrent) {
|
|
843
|
-
// In-thread concurrent benchmarks (no worker overhead)
|
|
844
|
-
defineInThreadConcurrentBenchmarks();
|
|
845
|
-
|
|
846
|
-
// Multi-threaded concurrent benchmarks (with worker pool)
|
|
847
|
-
await initializeWorkerPools();
|
|
848
|
-
defineMultiThreadedConcurrentBenchmarks();
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
console.log('Running benchmarks...\n');
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
/**
|
|
855
|
-
* Main benchmark runner
|
|
856
|
-
*/
|
|
857
|
-
export async function runBenchmarks(options: { format?: 'mitata' | 'json'; json?: boolean; concurrent?: boolean } = {}) {
|
|
858
|
-
const concurrent = options.concurrent ?? true;
|
|
859
|
-
const wantJson = options.json || options.format === 'json';
|
|
860
|
-
|
|
861
|
-
try {
|
|
862
|
-
await warmup();
|
|
863
|
-
await defineBenchmarks({ concurrent });
|
|
864
|
-
|
|
865
|
-
// Always run with default format for nice console output
|
|
866
|
-
// Then run again with JSON to get structured results for throughput calculation
|
|
867
|
-
const runOptions: Parameters<typeof run>[0] = {
|
|
868
|
-
format: wantJson ? 'json' : (options.format || 'mitata'),
|
|
869
|
-
};
|
|
870
|
-
|
|
871
|
-
const results = await run(runOptions);
|
|
872
|
-
|
|
873
|
-
// Print latency percentiles if concurrent benchmarks were run
|
|
874
|
-
if (concurrent) {
|
|
875
|
-
printLatencySummary();
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// Print throughput summary
|
|
879
|
-
printThroughputSummary(results);
|
|
880
|
-
|
|
881
|
-
// Shutdown worker pools
|
|
882
|
-
if (concurrent) {
|
|
883
|
-
await shutdownWorkerPools();
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
return results;
|
|
887
|
-
} catch (error) {
|
|
888
|
-
console.error();
|
|
889
|
-
console.error('Benchmark failed:', error);
|
|
890
|
-
// Ensure worker pools are cleaned up on error
|
|
891
|
-
await shutdownWorkerPools();
|
|
892
|
-
throw error;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
// Run if executed directly
|
|
897
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
898
|
-
const args = process.argv.slice(2);
|
|
899
|
-
const json = args.includes('--json');
|
|
900
|
-
const concurrent = !args.includes('--no-concurrent');
|
|
901
|
-
|
|
902
|
-
runBenchmarks({ json, concurrent })
|
|
903
|
-
.then((results) => {
|
|
904
|
-
if (json) {
|
|
905
|
-
console.log('\n' + JSON.stringify(results, null, 2));
|
|
906
|
-
}
|
|
907
|
-
process.exit(0);
|
|
908
|
-
})
|
|
909
|
-
.catch((error) => {
|
|
910
|
-
console.error(error);
|
|
911
|
-
process.exit(1);
|
|
912
|
-
});
|
|
913
|
-
}
|