Commit 217a8bb
Add Fiber#runtime, Fiber#quantum, and back-edge based preemption
## Background
Ruby's Fiber Scheduler is cooperative: fibers yield voluntarily when
waiting for I/O or calling Fiber.yield. This breaks down when CPU-bound
work enters the picture — a tight loop blocks the scheduler's event
loop indefinitely, starving every waiting fiber.
This change follows Erlang's reduction-counting model. Erlang assigns
each process a fixed budget of "reductions" (function calls) per
scheduling slot; when the budget is exhausted the scheduler preempts it
without OS involvement. YARV already calls rb_vm_check_ints at every
loop back-edge. We add a single counter increment there, and yield to
the fiber scheduler when the count reaches a configurable quantum.
## New API
Fiber#runtime -> Integer
Back-edges executed in the current (or most recently completed)
scheduling slot. Resets to 0 on every resume/transfer.
Fiber#quantum -> Integer
Fiber#quantum= Integer
Slot size in back-edges before forced preemption. Default: 50_000
(~7 ms at ~7M iterations/s). Also settable at construction time
via Fiber.new(quantum: n).
rb_fiber_runtime_advance(uint32_t n) [C API]
Advance the current fiber's runtime counter by n units. Intended
for C extensions doing CPU work outside YARV dispatch (JSON
parsers, image codecs, matrix math). Triggers preemption if the
quantum is exhausted.
## Scheduler integration
When a non-blocking fiber exhausts its quantum, rb_fiber_scheduler_yield
is called. Schedulers that implement the `yield` hook (introduced
previously) can use this for work-conserving preemption.
The scheduler sees Fiber#runtime before the fiber is resumed. A
scheduler can order its ready queue by runtime — lowest first — so that
I/O-bound fibers (which yield early with low runtime) naturally sort
ahead of CPU-bound ones. This is stride scheduling: accumulated CPU
consumption drives priority without explicit priority assignments.
test/fiber/fair_scheduler.rb demonstrates a complete implementation: a
min-heap ordered by Fiber#runtime that gives I/O-bound fibers automatic
scheduling priority over CPU-bound ones.
## Implementation details
Three new fields in rb_execution_context_t:
uint32_t runtime — back-edges this slot (reset to 0 on resume)
uint32_t quantum — preemption threshold (default RUBY_FIBER_QUANTUM_DEFAULT)
uint8_t preempted — re-entrancy guard; prevents the scheduler's own
Ruby code from immediately re-triggering preemption
All three are correctly initialized in:
- fiber_t_alloc (new fibers)
- rb_threadptr_root_fiber_setup (root fiber per thread)
- rb_fiber_atfork (child process after fork)
The preempted flag is cleared in fiber_switch on every resume, giving
each scheduling slot a fresh start.
## Compatibility
Existing schedulers that do not implement `yield` see no change: the
call falls back to kernel_sleep(0). Blocking fibers are never preempted.
Programs without a scheduler pay only the cost of one counter increment
and one comparison per loop back-edge in rb_vm_check_ints.
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent 9fefb48 commit 217a8bb
17 files changed
Lines changed: 952 additions & 25 deletions
File tree
- ext
- coverage
- objspace
- ripper
- socket
- spec/ruby/core/fiber
- test
- fiber
- ruby
- yjit/src
- zjit/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
56 | 60 | | |
57 | 61 | | |
58 | 62 | | |
| |||
296 | 300 | | |
297 | 301 | | |
298 | 302 | | |
299 | | - | |
| 303 | + | |
300 | 304 | | |
301 | 305 | | |
302 | 306 | | |
| |||
2171 | 2175 | | |
2172 | 2176 | | |
2173 | 2177 | | |
| 2178 | + | |
| 2179 | + | |
| 2180 | + | |
2174 | 2181 | | |
2175 | 2182 | | |
2176 | 2183 | | |
| |||
2362 | 2369 | | |
2363 | 2370 | | |
2364 | 2371 | | |
2365 | | - | |
| 2372 | + | |
2366 | 2373 | | |
2367 | 2374 | | |
2368 | 2375 | | |
| |||
2380 | 2387 | | |
2381 | 2388 | | |
2382 | 2389 | | |
| 2390 | + | |
| 2391 | + | |
| 2392 | + | |
| 2393 | + | |
| 2394 | + | |
| 2395 | + | |
2383 | 2396 | | |
2384 | 2397 | | |
2385 | 2398 | | |
| |||
2422 | 2435 | | |
2423 | 2436 | | |
2424 | 2437 | | |
| 2438 | + | |
2425 | 2439 | | |
2426 | 2440 | | |
2427 | 2441 | | |
2428 | | - | |
| 2442 | + | |
2429 | 2443 | | |
2430 | 2444 | | |
2431 | | - | |
| 2445 | + | |
2432 | 2446 | | |
2433 | 2447 | | |
2434 | 2448 | | |
| |||
2439 | 2453 | | |
2440 | 2454 | | |
2441 | 2455 | | |
| 2456 | + | |
2442 | 2457 | | |
2443 | 2458 | | |
2444 | | - | |
| 2459 | + | |
2445 | 2460 | | |
2446 | 2461 | | |
2447 | 2462 | | |
| |||
2502 | 2517 | | |
2503 | 2518 | | |
2504 | 2519 | | |
2505 | | - | |
| 2520 | + | |
2506 | 2521 | | |
2507 | 2522 | | |
2508 | 2523 | | |
| |||
2698 | 2713 | | |
2699 | 2714 | | |
2700 | 2715 | | |
| 2716 | + | |
2701 | 2717 | | |
2702 | 2718 | | |
2703 | 2719 | | |
| |||
2887 | 2903 | | |
2888 | 2904 | | |
2889 | 2905 | | |
| 2906 | + | |
| 2907 | + | |
| 2908 | + | |
| 2909 | + | |
| 2910 | + | |
| 2911 | + | |
| 2912 | + | |
| 2913 | + | |
| 2914 | + | |
| 2915 | + | |
2890 | 2916 | | |
2891 | 2917 | | |
2892 | 2918 | | |
| |||
2945 | 2971 | | |
2946 | 2972 | | |
2947 | 2973 | | |
| 2974 | + | |
| 2975 | + | |
| 2976 | + | |
| 2977 | + | |
| 2978 | + | |
| 2979 | + | |
| 2980 | + | |
| 2981 | + | |
| 2982 | + | |
| 2983 | + | |
| 2984 | + | |
| 2985 | + | |
| 2986 | + | |
| 2987 | + | |
| 2988 | + | |
| 2989 | + | |
| 2990 | + | |
| 2991 | + | |
| 2992 | + | |
| 2993 | + | |
| 2994 | + | |
| 2995 | + | |
| 2996 | + | |
| 2997 | + | |
| 2998 | + | |
| 2999 | + | |
| 3000 | + | |
| 3001 | + | |
| 3002 | + | |
| 3003 | + | |
| 3004 | + | |
| 3005 | + | |
| 3006 | + | |
| 3007 | + | |
| 3008 | + | |
| 3009 | + | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + | |
| 3013 | + | |
| 3014 | + | |
| 3015 | + | |
| 3016 | + | |
| 3017 | + | |
| 3018 | + | |
| 3019 | + | |
| 3020 | + | |
| 3021 | + | |
| 3022 | + | |
| 3023 | + | |
| 3024 | + | |
| 3025 | + | |
| 3026 | + | |
| 3027 | + | |
| 3028 | + | |
| 3029 | + | |
2948 | 3030 | | |
2949 | 3031 | | |
2950 | 3032 | | |
| |||
3508 | 3590 | | |
3509 | 3591 | | |
3510 | 3592 | | |
| 3593 | + | |
| 3594 | + | |
| 3595 | + | |
3511 | 3596 | | |
3512 | 3597 | | |
3513 | 3598 | | |
| |||
3658 | 3743 | | |
3659 | 3744 | | |
3660 | 3745 | | |
| 3746 | + | |
3661 | 3747 | | |
3662 | 3748 | | |
3663 | 3749 | | |
| |||
3684 | 3770 | | |
3685 | 3771 | | |
3686 | 3772 | | |
| 3773 | + | |
| 3774 | + | |
| 3775 | + | |
3687 | 3776 | | |
3688 | 3777 | | |
3689 | 3778 | | |
| |||
0 commit comments