| PeeR: First-Class Scheduling for Latency-Critical eBPF Applications | |
|---|---|
| Author | Jeremy Carin, Ben Holmes, Weiyang Wang, Ankit Bhardwaj, Manya Ghobadi |
| Conference | 20th USENIX Symposium on Operating Systems Design and Implementation (OSDI 2026) |
| Year | 2026 |
개요
이 논문은 latency-critical eBPF application이 non-preemptable softirq에서 실행될 때 발생하는 Head-of-line blocking과 CPU accounting 부재를, verifier가 보장하는 helper boundary에서의 cooperative preemption과 sched_ext 기반 2-level scheduling으로 해결하였다.
Motivation
eBPF는 kernel 안에서 application logic을 실행하여 context switch와 data copy를 줄이지만, 그 실행 모델은 짧고 예측 가능한 packet filter를 가정한 채 run-to-completion으로 남아 있다[1]. 반면 최신 eBPF application은 복잡한 기능을 담당하는 Helper function을 eBPF program의 instruction대비 매우 많은 빈도로 실행시킨다. 이러한 환경에서는 eBPF Verifier의 eBPF 프로그램은 Instruction limit이 있기 떄문에 non-preemtible하다는 가정이 깨진다.
즉, 현재 복잡한 eBPF workload가 latency-critical I/O path의 softirq에서 실행되면 두 문제가 생긴다.
- Intra-application blocking: long request가 먼저 도착하면 뒤의 short request가 preempt할 수 없어 Tail latency가 증가한다.
- Inter-application unfairness: softirq 실행 시간은 eBPF application이 아니라 interrupt된 process에 귀속된다. 따라서 만약 Process A가 eBPF를 사용하게 된다면, eBPF 프로그램을 사용하지 않는 Process B도 Process A의 eBPF time을 paying해, scheduling에서 불리한 위치에 놓여지게 된다.
ksoftirq를 사용하더라도, ksoftirq는 invocation 내부를 preempt하거나 개별 eBPF task의 CPU 사용량과 우선순위를 scheduler에 드러내지 못한다. 따라서 application을 kernel fast path에 유지하면서도 invocation을 scheduling 가능한 resource로 만드는 새로운 Scheduling unit을 만들어야 한다.
Importance
- PeeR는 eBPF의 안전성을 verifier 통과 여부에만 한정하지 않고, scheduler-visible accounting, preemption, policy enforcement까지 포함하는 resource-management 문제로 확장한다.
- eBPF verifier의 compile-time type/liveness 정보를 runtime continuation 복원에 재사용한다는 점이 핵심적인 architecture/runtime co-design이다.
Challenges
eBPF를 schedulable하게 만드는 것은 다음의 요소 때문에 도전적인 과제이다.
- Enaling fine-grained preemption with low overhead
- Preserving eBPF correctness under preemption
- Providing expressive scheduling abstractions
Main Idea
eBPF program이 kernel state와 상호작용하기 위해 helper function이나 kfunc를 자주 호출하고, verifier가 각 call boundary에서 register, stack, lock, reference의 상태를 이미 추적한다는 것이다. PeeR는 안전한 helper boundary에 JIT budget check를 삽입하여, budget을 넘긴 invocation이 다음 safe point에서 자동으로 yield하도록 만든다. 즉 application code에 명시적 yield()를 요구하지 않으면서 verifier-guided cooperative preemption을 구현한다.
실행 모델은 hybrid fast/slow path이다. budget 안에서 끝나는 task는 softirq에서 기존처럼 FCFS로 완료한다. budget을 넘긴 task만 상태를 continuation에 저장하고 per-CPU PeeR-kthread에서 복원한다. sched_ext가 outer macro-scheduler로서 eBPF workload와 userspace process 사이의 총 CPU 배분을 제어하고, kthread 내부의 micro-scheduler가 FIFO, SRPT, weighted round-robin 같은 policy로 개별 continuation의 순서를 정한다.
Design
- Verifier-guided preemption point
- 문제: timer interrupt로 임의 지점에서 끊으면 fast-path overhead가 크고, register·stack·kernel resource가 복원 가능한 상태인지 보장할 수 없다.
- Mechanism: PeeR는 JIT compiler가 안전한 helper/kfunc call 직전에 per-CPU epoch flag를 확인하는 prologue와 고유
site_id를 삽입하게 한다. budget이 만료되면 helper 실행 전에 yield handler로 분기하여 11개 register(88 B), 512 B eBPF stack, hook-specific context를 저장한다. flag가 꺼진 일반 경로의 check는 helper call당 1 cycle, scheduler가 flag를 갱신할 때는 2 cycle이다. - 효과와 tradeoff: 대부분의 짧은 task는 context switch 없이 기존 fast path를 유지하지만, preemption granularity는 안전한 helper 사이의 실제 실행 시간에 제한된다.
- Continuation 저장과 정확한 resume
- 문제: softirq에서 저장한 stack/context pointer를 다른 kernel stack의 worker thread에서 그대로 복원하면 stale pointer가 되어 memory corruption을 일으킨다.
- Mechanism: verifier가 각 yield site에서 추적한
PTR_TO_STACK과PTR_TO_CTX정보를 patch descriptor로 보존하고, resume 시 새 stack/context base에 맞게 pointer를 rebase한다. JIT가 site별 CFI-safe trampoline을 생성하므로, worker는 저장된site_id에 대응하는 helper call 직전으로 돌아가 helper의 side effect를 정확히 한 번만 수행한다. - 효과와 tradeoff: source eBPF program 수정 없이 context를 옮길 수 있지만, verifier type이 모든 incoming path에서 일치하는 위치만 patch할 수 있다.
- Kernel resource와 RCU 안전성
- 문제: softirq가 끝나면 implicit RCU read-side critical section도 끝나므로, live map-value/RCU pointer를 가진 채 yield하면 resume 전에 대상이 변경되거나 해제될 수 있다.
- Mechanism: verifier의 type 및 liveness 정보로 RCU-protected pointer, acquired reference, active lock이 없는 helper site에만 preemption check를 넣는다. lock-held region이나 unsafe resource가 live한 site는 yield point가 아니다.
- 효과와 tradeoff: memory safety invariant를 보존하지만 cooperative gap이 길어질 수 있다. 또한 invocation이 서로 interleave되고 per-core completion order가 바뀔 수 있으므로 shared state의 원자성을 가정한 program은 spin lock 등으로 명시적으로 동기화해야 한다.
- Hook-specific continuation
- 문제: verifier는 eBPF 내부 상태만 검증하므로, caller가 즉시 verdict를 요구하거나 lock을 쥔 hook은 결과를 나중에 적용할 수 없다.
- Mechanism: compatible hook은 input lifetime을 연장할 수 있고, caller가 deferred result를 허용하며, caller-side lock이 없어야 한다. 구현된 native XDP path는 packet을 reference-counted
xdp_frame으로 전환하고XDP_YIELD를 반환하여 NAPI poll을 계속한 뒤, worker에서 실제 DROP, ABORTED, PASS, TX, REDIRECT verdict를 적용한다. - 효과와 tradeoff: fast path가 deferred task를 기다리지 않지만 현재 구현은 native single-buffer XDP만 지원하며 multi-buffer와 tail-call program은 거부한다. 논문은 direct-action tc/TCX와 XRP storage hook이 model에 맞는다고 분석하지만 구현하지 않았다.
- Two-level scheduling과 accounting
- 문제: sched_ext는 여러 continuation을 담은 하나의 PeeR-kthread만 보므로 개별 eBPF invocation의 순서나 owner별 CPU 시간을 직접 구분할 수 없다.
- Mechanism: outer sched_ext macro-scheduler는
runtime_eventper-CPU ring buffer의 owner, CPU, duration, completion/yield 정보를 userspace daemon이 집계한 결과로 application별 CPU allocation을 조정한다.set_budget()은 기본 5 μs quantum을 설정한다. 각 per-CPU kthread 안의 micro-scheduler는 continuation priority와enqueue()/requeue()callback으로 FIFO, SRPT, WRR을 구현한다. - 효과와 tradeoff: userspace와 eBPF를 하나의 CPU-sharing policy 아래 둘 수 있고 short/long request 사이의 policy도 선택할 수 있지만, task는 originating CPU에 고정되어 migration하지 않으며 SRPT에는 application-provided remaining-work estimate가 필요하다.
Result
논문이 보고한 전체 범위에서 PeeR는 mixed workload의 latency-sensitive request p99를 current eBPF runtime보다 3–19.8배 줄였으며, 위 결과는 그 개선이 safe-point preemption과 scheduler-visible accounting이라는 두 mechanism에서 각각 발생함을 뒷받침한다.
Contribution
- 7개의 modern eBPF application을 static analysis와 runtime profiling으로 조사하여, run-to-completion fast-path assumption이 execution-time variance, head-of-line blocking, CPU misaccounting 때문에 깨졌음을 정량화했다.
- verifier의 helper-boundary invariant와 type/liveness 정보를 이용해 low-overhead cooperative preemption, state capture, pointer rebasing, CFI-safe resume를 구현했다.
- softirq fast path와 per-CPU worker slow path를 결합하고, sched_ext macro-scheduler와 per-kthread micro-scheduler를 통해 intra-/inter-application policy를 함께 표현하는 2-level scheduling architecture를 제시했다.
- Redis, Memcached, synthetic TPC-C, colocation 및 microbenchmark에서 tail-latency 개선, CPU allocation enforcement, 247 ns preemption-resumption cost를 검증하고 quantum의 성능 tradeoff를 밝혔다.
Conclusion
이 연구는 복잡해진 eBPF fast path를 단순한 안전한 kernel extension이 아니라 CPU accounting과 scheduling이 필요한 first-class workload로 바라보게 만든다. PeeR는 verifier가 보장하는 helper boundary를 safe point로 재사용하고, 짧은 task는 softirq에 남기되 긴 task만 continuation으로 전환하여 low overhead preemption과 policy control을 양립시킬 수 있음을 보였다. 다만, Correctness측면에서 PeeR을 Support하기 위한 방법이 XDP가 아니라 좀더 복잡한 영역으로 확장 가능할지는 의문이다. 만약 할당된 Struct를 eBPF program내부에서 수정하고, Helper function에 의해서 Preemption된다면, 기본적으로 atomic을 가정하는 Helper function입장에서는 TOCTOU가 발생할 수 있다. 또한 전체 eBPF의 Kfunc라던지 이러한 시스템에 통합하기 위해서는 많은 Kernel-patch가 필요한 점도 Implementation측면에서의 약점이 될 수 있을듯 하다. 그러나 Motivation이 매우 좋고, Design또한 Motivation에 잘 이어지며, 전체적인 시스템의 Nolvety도 좋아보인다. 그리고 Implementation details들이 잘 나와 있어서, Sound하다는 인상을 받았다.
- ↑ While eBPF programs have grown dramatically in complexity, their execution model, which was originally designed for tiny packet filters, has remained largely unchanged.