Skip to content

Add per-context interrupt budget#1526

Open
dannote wants to merge 1 commit into
quickjs-ng:masterfrom
dannote:context-interrupt-budget
Open

Add per-context interrupt budget#1526
dannote wants to merge 1 commit into
quickjs-ng:masterfrom
dannote:context-interrupt-budget

Conversation

@dannote

@dannote dannote commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Add a context-local interrupt counter and optional limit.

The counter increments when the interpreter reaches the existing interrupt polling path. If a context limit is set and the counter reaches it, that context throws interrupted before consulting the runtime-level interrupt handler. A limit of 0 keeps the feature disabled.

This is useful for embedders that host multiple JSContext instances inside one JSRuntime and need each context to have an independent execution budget. In QuickBEAM, a pool worker owns one JSRuntime and creates many contexts with JS_NewContext(rt). A runtime-level interrupt handler remains useful as a global guard, but it cannot express a per-context budget for that pooled model.

Tested:

cmake --build build --target api-test -j2
./build/api-test

@bnoordhuis

Copy link
Copy Markdown
Contributor

Can you check in before/after style if this change impacts tests/microbench.js?

@dannote

dannote commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

I ran a before/after tests/microbench.js comparison.

Setup:

  • CPU: AMD Ryzen 9 7950X, Linux 7.0.0-27-generic
  • Compiler: GCC 15.2.0
  • Build: cmake -B build -DCMAKE_BUILD_TYPE=Release via make
  • Before: fd0a0210 (a480376^)
  • After: a480376f (this PR)
  • Command: taskset -c 2 ./build/qjs tests/microbench.js
  • Method: 10 alternating runs before/after; score is the total line from microbench, higher is better.

Results:

before totals: 5597.04, 5571.96, 5645.35, 5685.76, 5955.45, 5679.04, 5758.90, 5090.21, 5545.74, 5407.44
after totals:  5469.94, 5579.21, 5564.63, 5559.90, 5381.78, 5533.14, 4610.29, 5523.92, 5454.34, 5417.87

Summary:

before median:       5621.20
after median:        5496.93
delta:               -2.21%

before trimmed mean: 5611.40
after trimmed mean:  5488.19
delta:               -2.20%

The run-to-run noise on this machine is fairly high (about 4-5% RSD on total score), so I would not read this as a strong regression signal. The observed total-score delta is small relative to noise. The change only adds work in __js_poll_interrupts(), so a small effect in long-running loops is plausible, but I don't see an obvious large impact from this run.

@saghul

saghul commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Can you try to run the v8 benchmark? See: https://github.com/quickjs-ng/benchmarks

@dannote

dannote commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

@saghul Sure — I ran the V8 benchmark from quickjs-ng/benchmarks as well. Thanks for the pointer!

Setup:

  • CPU: AMD Ryzen 9 7950X, Linux 7.0.0-27-generic
  • Compiler: GCC 15.2.0
  • Build: Release CMake build from the earlier before/after check
  • Before: fd0a0210 (a480376^)
  • After: a480376f (this PR)
  • Benchmark repo: quickjs-ng/benchmarks
  • Command shape: from benchmarks/v8, running combined.js with each qjs
  • Method: 5 alternating runs, pinned with taskset -c 2

Median results:

Benchmark (higher is better) before median PR median delta
Richards 1225 1230 +0.4%
DeltaBlue 1196 1204 +0.7%
Crypto 623 611 -1.9%
RayTrace 2265 2252 -0.6%
EarleyBoyer 2556 2628 +2.8%
RegExp 397 449 +13.1%
Splay 3123 3378 +8.2%
NavierStokes 1506 1526 +1.3%
Score 1332 1336 +0.3%

Raw total scores:

before: 1367, 1332, 1320, 1337, 1281
after:  1312, 1381, 1336, 1317, 1403

Summary: the V8 benchmark looks neutral on my machine. Median score is essentially unchanged (+0.3%), and the run-to-run spread is larger than that delta, so I don't see a measurable regression from this PR here.

Comment thread quickjs.c
JSRuntime *rt = ctx->rt;
ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
ctx->interrupt_count++;
if (ctx->interrupt_limit > 0 && ctx->interrupt_count >= ctx->interrupt_limit) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (ctx->interrupt_limit > 0 && ctx->interrupt_count >= ctx->interrupt_limit) {
if (unlikely(ctx->interrupt_limit > 0) && ctx->interrupt_count >= ctx->interrupt_limit) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants