diff options
| author | babenko <[email protected]> | 2026-06-03 22:48:15 +0300 |
|---|---|---|
| committer | babenko <[email protected]> | 2026-06-03 23:05:38 +0300 |
| commit | c21931d639da07f4ff17880a5462a4d271a3fdb0 (patch) | |
| tree | 69b91af36bbca9c0ab9616f74a2dd8b16d742f28 /contrib/python/ipython/py2/IPython/kernel/__init__.py | |
| parent | 06e1c52cb7acac420aedc2d7f0a3a14001c9a5c1 (diff) | |
Make bind state accessible in GDB regardless of Propagate flag
## What changed
- `yt/yt/core/actions/callback.h` — `TCallback::operator()` now spills `BindState_.Get()` to the stack under the well-known name `fiberBindState` (one `volatile` store). The GDB printer reads that slot.
- `yt/yt/core/actions/bind-inl.h` — dropped the old `volatile state` / `unoptimizedState` spill from `TBindState::Run<>`. With the spill lifted to the caller, `Run<false>` collapses to a single instruction.
- `devtools/gdb/yt_fibers_printer.py` — primary extractor reads `fiberBindState`, walks the bind state via vtable detection and the fixed `sizeof(TBindStateBase)` offset to `Storage_` (avoids `gdb.lookup_type` failures on unnamed-lambda mangled names). The legacy `unoptimizedState` extractor is kept as a `COMPAT(babenko)` fallback for older binaries.
## Why
The previous spill lived in `TBindState::Run<>` so it had to be paid even by `Propagate=false` callbacks, and the synthetic types of lambda-bound states (`TBindState<true, main::$_1, ...>`) couldn't be resolved by `gdb.lookup_type`. Lifting the spill into the caller solves both: every callback invocation site materializes `fiberBindState` regardless of propagating-ness, and the printer can compute `Storage_` purely by offset, no type lookup required.
## ASM diff
`TBindState<false, void(*)()>::Run<>` is now a 3-byte single-instruction tail call:
```
jmp QWORD PTR [rdi+0x18]
```
No frame, no spill, no save/restore.
`TCallback::operator()` stays fully inlined. Hot loop bodies of `BM_Run_NoPropagate` and `BM_Run_NonEmptyPS` are identical 5-instruction sequences:
```
mov rdi, QWORD PTR [rsp+0x8] ; rdi = BindState_.Get()
mov rax, QWORD PTR [rsp+0x10] ; rax = UntypedInvoke_
mov QWORD PTR [rsp+0x18], rdi ; fiberBindState spill (gdb-visible)
call rax
dec rXXXXXX
jne .loop
```
The spill is one extra store into an already-warm stack slot.
## Benchmark deltas
| Benchmark | Before | After | Δ |
|----------------------------|---------|---------|----------|
| BM_Run_NoPropagate | ~1.96 ns| 2.29 ns | +0.33 ns |
| BM_Run_NullPS | ~16 ns | 16.4 ns | flat |
| BM_Run_EmptyPS | ~41 ns | 40.9 ns | flat |
| BM_Run_NonEmptyPS | ~43 ns | 43.3 ns | flat |
| BM_CaptureAndRun_NullPS | ~55 ns | 55.1 ns | flat |
| BM_CaptureAndRun_NonEmptyPS| ~81 ns | 81.0 ns | flat |
The spill shows up only in `BM_Run_NoPropagate` (a 2 ns single-indirect-call microbench). Everywhere else it's hidden inside the 40+ ns of propagating-storage guard work.
commit_hash:5cce2055f6220c1adc4637d872ff96cd3c6658a3
Diffstat (limited to 'contrib/python/ipython/py2/IPython/kernel/__init__.py')
0 files changed, 0 insertions, 0 deletions
