€•3Œsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ'/translations/zh_CN/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/zh_TW/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/it_IT/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ja_JP/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/ko_KR/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/pt_BR/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ'/translations/sp_SP/scheduler/sched-ext”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒtarget”“”)�”}”(hŒ.. _sched-ext:”h]”h}”(h]”h ]”h"]”h$]”h&]”Œrefid”Œ sched-ext”uh1hµh´Khhh²hh³ŒA/var/lib/git/docbuild/linux/Documentation/scheduler/sched-ext.rst”ubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒExtensible Scheduler Class”h]”hŒExtensible Scheduler Class”…”�”}”(hhËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhhÆh²hh³hÃh´KubhŒ paragraph”“”)�”}”(hŒjsched_ext is a scheduler class whose behavior can be defined by a set of BPF programs - the BPF scheduler.”h]”hŒjsched_ext is a scheduler class whose behavior can be defined by a set of BPF programs - the BPF scheduler.”…”�”}”(hhÛh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KhhÆh²hubhŒ bullet_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒjsched_ext exports a full scheduling interface so that any scheduling algorithm can be implemented on top. ”h]”hÚ)�”}”(hŒisched_ext exports a full scheduling interface so that any scheduling algorithm can be implemented on top.”h]”hŒisched_ext exports a full scheduling interface so that any scheduling algorithm can be implemented on top.”…”�”}”(hhôh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K hhðubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhhëh²hh³hÃh´Nubhï)�”}”(hŒŽThe BPF scheduler can group CPUs however it sees fit and schedule them together, as tasks aren't tied to specific CPUs at the time of wakeup. ”h]”hÚ)�”}”(hŒ�The BPF scheduler can group CPUs however it sees fit and schedule them together, as tasks aren't tied to specific CPUs at the time of wakeup.”h]”hŒ�The BPF scheduler can group CPUs however it sees fit and schedule them together, as tasks aren’t tied to specific CPUs at the time of wakeup.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhhëh²hh³hÃh´Nubhï)�”}”(hŒ@The BPF scheduler can be turned on and off dynamically anytime. ”h]”hÚ)�”}”(hŒ?The BPF scheduler can be turned on and off dynamically anytime.”h]”hŒ?The BPF scheduler can be turned on and off dynamically anytime.”…”�”}”(hj$h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Khj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhhëh²hh³hÃh´Nubhï)�”}”(hŒÝThe system integrity is maintained no matter what the BPF scheduler does. The default scheduling behavior is restored anytime an error is detected, a runnable task stalls, or on invoking the SysRq key sequence `SysRq-S`. ”h]”hÚ)�”}”(hŒÜThe system integrity is maintained no matter what the BPF scheduler does. The default scheduling behavior is restored anytime an error is detected, a runnable task stalls, or on invoking the SysRq key sequence `SysRq-S`.”h]”(hŒÒThe system integrity is maintained no matter what the BPF scheduler does. The default scheduling behavior is restored anytime an error is detected, a runnable task stalls, or on invoking the SysRq key sequence ”…”�”}”(hj<h²hh³Nh´NubhŒtitle_reference”“”)�”}”(hŒ `SysRq-S`”h]”hŒSysRq-S”…”�”}”(hjFh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jDhj<ubhŒ.”…”�”}”(hj<h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Khj8ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhhëh²hh³hÃh´Nubhï)�”}”(hXxWhen the BPF scheduler triggers an error, debug information is dumped to aid debugging. The debug dump is passed to and printed out by the scheduler binary. The debug dump can also be accessed through the `sched_ext_dump` tracepoint. The SysRq key sequence `SysRq-D` triggers a debug dump. This doesn't terminate the BPF scheduler and can only be read through the tracepoint. ”h]”hÚ)�”}”(hXwWhen the BPF scheduler triggers an error, debug information is dumped to aid debugging. The debug dump is passed to and printed out by the scheduler binary. The debug dump can also be accessed through the `sched_ext_dump` tracepoint. The SysRq key sequence `SysRq-D` triggers a debug dump. This doesn't terminate the BPF scheduler and can only be read through the tracepoint.”h]”(hŒÍWhen the BPF scheduler triggers an error, debug information is dumped to aid debugging. The debug dump is passed to and printed out by the scheduler binary. The debug dump can also be accessed through the ”…”�”}”(hjhh²hh³Nh´NubjE)�”}”(hŒ`sched_ext_dump`”h]”hŒsched_ext_dump”…”�”}”(hjph²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jDhjhubhŒ$ tracepoint. The SysRq key sequence ”…”�”}”(hjhh²hh³Nh´NubjE)�”}”(hŒ `SysRq-D`”h]”hŒSysRq-D”…”�”}”(hj‚h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jDhjhubhŒo triggers a debug dump. This doesn’t terminate the BPF scheduler and can only be read through the tracepoint.”…”�”}”(hjhh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Khjdubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhhëh²hh³hÃh´Nubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ*”uh1héh³hÃh´K hhÆh²hubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒSwitching to and from sched_ext”h]”hŒSwitching to and from sched_ext”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj¨h²hh³hÃh´KubhÚ)�”}”(hŒ½``CONFIG_SCHED_CLASS_EXT`` is the config option to enable sched_ext and ``tools/sched_ext`` contains the example schedulers. The following config options should be enabled to use sched_ext:”h]”(hŒliteral”“”)�”}”(hŒ``CONFIG_SCHED_CLASS_EXT``”h]”hŒCONFIG_SCHED_CLASS_EXT”…”�”}”(hj¿h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj¹ubhŒ. is the config option to enable sched_ext and ”…”�”}”(hj¹h²hh³Nh´Nubj¾)�”}”(hŒ``tools/sched_ext``”h]”hŒtools/sched_ext”…”�”}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj¹ubhŒb contains the example schedulers. The following config options should be enabled to use sched_ext:”…”�”}”(hj¹h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K!hj¨h²hubhŒ literal_block”“”)�”}”(hŒšCONFIG_BPF=y CONFIG_SCHED_CLASS_EXT=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_DEBUG_INFO_BTF=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_JIT_DEFAULT_ON=y”h]”hŒšCONFIG_BPF=y CONFIG_SCHED_CLASS_EXT=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_DEBUG_INFO_BTF=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_BPF_JIT_DEFAULT_ON=y”…”�”}”hjësbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”Œforce”‰Œlanguage”Œnone”Œhighlight_args”}”uh1jéh³hÃh´K%hj¨h²hubhÚ)�”}”(hŒDsched_ext is used only when the BPF scheduler is loaded and running.”h]”hŒDsched_ext is used only when the BPF scheduler is loaded and running.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K/hj¨h²hubhÚ)�”}”(hŒµIf a task explicitly sets its scheduling policy to ``SCHED_EXT``, it will be treated as ``SCHED_NORMAL`` and scheduled by the fair-class scheduler until the BPF scheduler is loaded.”h]”(hŒ3If a task explicitly sets its scheduling policy to ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ ``SCHED_EXT``”h]”hŒ SCHED_EXT”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ, it will be treated as ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_NORMAL``”h]”hŒ SCHED_NORMAL”…”�”}”(hj(h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒM and scheduled by the fair-class scheduler until the BPF scheduler is loaded.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K1hj¨h²hubhÚ)�”}”(hŒÈWhen the BPF scheduler is loaded and ``SCX_OPS_SWITCH_PARTIAL`` is not set in ``ops->flags``, all ``SCHED_NORMAL``, ``SCHED_BATCH``, ``SCHED_IDLE``, and ``SCHED_EXT`` tasks are scheduled by sched_ext.”h]”(hŒ%When the BPF scheduler is loaded and ”…”�”}”(hj@h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_OPS_SWITCH_PARTIAL``”h]”hŒSCX_OPS_SWITCH_PARTIAL”…”�”}”(hjHh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ is not set in ”…”�”}”(hj@h²hh³Nh´Nubj¾)�”}”(hŒ``ops->flags``”h]”hŒ ops->flags”…”�”}”(hjZh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ, all ”…”�”}”(hj@h²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_NORMAL``”h]”hŒ SCHED_NORMAL”…”�”}”(hjlh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ, ”…”�”}”(hj@h²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_BATCH``”h]”hŒ SCHED_BATCH”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ, ”…”�”}”hj@sbj¾)�”}”(hŒ``SCHED_IDLE``”h]”hŒ SCHED_IDLE”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ, and ”…”�”}”(hj@h²hh³Nh´Nubj¾)�”}”(hŒ ``SCHED_EXT``”h]”hŒ SCHED_EXT”…”�”}”(hj¢h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj@ubhŒ" tasks are scheduled by sched_ext.”…”�”}”(hj@h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K5hj¨h²hubhÚ)�”}”(hX\However, when the BPF scheduler is loaded and ``SCX_OPS_SWITCH_PARTIAL`` is set in ``ops->flags``, only tasks with the ``SCHED_EXT`` policy are scheduled by sched_ext, while tasks with ``SCHED_NORMAL``, ``SCHED_BATCH`` and ``SCHED_IDLE`` policies are scheduled by the fair-class scheduler which has higher sched_class precedence than ``SCHED_EXT``.”h]”(hŒ.However, when the BPF scheduler is loaded and ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_OPS_SWITCH_PARTIAL``”h]”hŒSCX_OPS_SWITCH_PARTIAL”…”�”}”(hjÂh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ is set in ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ``ops->flags``”h]”hŒ ops->flags”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ, only tasks with the ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ ``SCHED_EXT``”h]”hŒ SCHED_EXT”…”�”}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ5 policy are scheduled by sched_ext, while tasks with ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_NORMAL``”h]”hŒ SCHED_NORMAL”…”�”}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ, ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_BATCH``”h]”hŒ SCHED_BATCH”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ and ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ``SCHED_IDLE``”h]”hŒ SCHED_IDLE”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒa policies are scheduled by the fair-class scheduler which has higher sched_class precedence than ”…”�”}”(hjºh²hh³Nh´Nubj¾)�”}”(hŒ ``SCHED_EXT``”h]”hŒ SCHED_EXT”…”�”}”(hj.h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjºubhŒ.”…”�”}”(hjºh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K9hj¨h²hubhÚ)�”}”(hŒ×Terminating the sched_ext scheduler program, triggering `SysRq-S`, or detection of any internal error including stalled runnable tasks aborts the BPF scheduler and reverts all tasks back to the fair-class scheduler.”h]”(hŒ8Terminating the sched_ext scheduler program, triggering ”…”�”}”(hjFh²hh³Nh´NubjE)�”}”(hŒ `SysRq-S`”h]”hŒSysRq-S”…”�”}”(hjNh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1jDhjFubhŒ–, or detection of any internal error including stalled runnable tasks aborts the BPF scheduler and reverts all tasks back to the fair-class scheduler.”…”�”}”(hjFh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K?hj¨h²hubjê)�”}”(hŒÃ# make -j16 -C tools/sched_ext # tools/sched_ext/build/bin/scx_simple local=0 global=3 local=5 global=24 local=9 global=44 local=13 global=56 local=17 global=72 ^CEXIT: BPF scheduler unregistered”h]”hŒÃ# make -j16 -C tools/sched_ext # tools/sched_ext/build/bin/scx_simple local=0 global=3 local=5 global=24 local=9 global=44 local=13 global=56 local=17 global=72 ^CEXIT: BPF scheduler unregistered”…”�”}”hjfsbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´KChj¨h²hubhÚ)�”}”(hŒEThe current status of the BPF scheduler can be determined as follows:”h]”hŒEThe current status of the BPF scheduler can be determined as follows:”…”�”}”(hjvh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KNhj¨h²hubjê)�”}”(hŒU# cat /sys/kernel/sched_ext/state enabled # cat /sys/kernel/sched_ext/root/ops simple”h]”hŒU# cat /sys/kernel/sched_ext/state enabled # cat /sys/kernel/sched_ext/root/ops simple”…”�”}”hj„sbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´KPhj¨h²hubhÚ)�”}”(hŒºYou can check if any BPF scheduler has ever been loaded since boot by examining this monotonically incrementing counter (a value of zero indicates that no BPF scheduler has been loaded):”h]”hŒºYou can check if any BPF scheduler has ever been loaded since boot by examining this monotonically incrementing counter (a value of zero indicates that no BPF scheduler has been loaded):”…”�”}”(hj”h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KWhj¨h²hubjê)�”}”(hŒ(# cat /sys/kernel/sched_ext/enable_seq 1”h]”hŒ(# cat /sys/kernel/sched_ext/enable_seq 1”…”�”}”hj¢sbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´K[hj¨h²hubhÚ)�”}”(hŒØEach running scheduler exposes an ``events`` file under its sysfs kobject (``/sys/kernel/sched_ext/root/events`` for the root scheduler) that tracks diagnostic counters. Each counter occupies one ``name value`` line:”h]”(hŒ"Each running scheduler exposes an ”…”�”}”(hj²h²hh³Nh´Nubj¾)�”}”(hŒ ``events``”h]”hŒevents”…”�”}”(hjºh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj²ubhŒ file under its sysfs kobject (”…”�”}”(hj²h²hh³Nh´Nubj¾)�”}”(hŒ%``/sys/kernel/sched_ext/root/events``”h]”hŒ!/sys/kernel/sched_ext/root/events”…”�”}”(hjÌh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj²ubhŒT for the root scheduler) that tracks diagnostic counters. Each counter occupies one ”…”�”}”(hj²h²hh³Nh´Nubj¾)�”}”(hŒ``name value``”h]”hŒ name value”…”�”}”(hjÞh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj²ubhŒ line:”…”�”}”(hj²h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K`hj¨h²hubjê)�”}”(hX‘# cat /sys/kernel/sched_ext/root/events SCX_EV_SELECT_CPU_FALLBACK 0 SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE 0 SCX_EV_DISPATCH_KEEP_LAST 123 SCX_EV_ENQ_SKIP_EXITING 0 SCX_EV_ENQ_SKIP_MIGRATION_DISABLED 0 SCX_EV_REENQ_IMMED 0 SCX_EV_REENQ_REPEAT 0 SCX_EV_REFILL_SLICE_DFL 456789 SCX_EV_BYPASS_DURATION 0 SCX_EV_BYPASS_DISPATCH 0 SCX_EV_BYPASS_ACTIVATE 0 SCX_EV_INSERT_NOT_OWNED 0 SCX_EV_SUB_BYPASS_DISPATCH 0”h]”hX‘# cat /sys/kernel/sched_ext/root/events SCX_EV_SELECT_CPU_FALLBACK 0 SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE 0 SCX_EV_DISPATCH_KEEP_LAST 123 SCX_EV_ENQ_SKIP_EXITING 0 SCX_EV_ENQ_SKIP_MIGRATION_DISABLED 0 SCX_EV_REENQ_IMMED 0 SCX_EV_REENQ_REPEAT 0 SCX_EV_REFILL_SLICE_DFL 456789 SCX_EV_BYPASS_DURATION 0 SCX_EV_BYPASS_DISPATCH 0 SCX_EV_BYPASS_ACTIVATE 0 SCX_EV_INSERT_NOT_OWNED 0 SCX_EV_SUB_BYPASS_DISPATCH 0”…”�”}”hjösbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´Kdhj¨h²hubhÚ)�”}”(hŒGThe counters are described in ``kernel/sched/ext/internal.h``; briefly:”h]”(hŒThe counters are described in ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``kernel/sched/ext/internal.h``”h]”hŒkernel/sched/ext/internal.h”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ ; briefly:”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Kuhj¨h²hubhê)�”}”(hhh]”(hï)�”}”(hŒ‹``SCX_EV_SELECT_CPU_FALLBACK``: ops.select_cpu() returned a CPU unusable by the task and the core scheduler silently picked a fallback CPU.”h]”hÚ)�”}”(hŒ‹``SCX_EV_SELECT_CPU_FALLBACK``: ops.select_cpu() returned a CPU unusable by the task and the core scheduler silently picked a fallback CPU.”h]”(j¾)�”}”(hŒ``SCX_EV_SELECT_CPU_FALLBACK``”h]”hŒSCX_EV_SELECT_CPU_FALLBACK”…”�”}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj-ubhŒm: ops.select_cpu() returned a CPU unusable by the task and the core scheduler silently picked a fallback CPU.”…”�”}”(hj-h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Kwhj)ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒ�``SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE``: a local-DSQ dispatch was redirected to the global DSQ because the target CPU went offline.”h]”hÚ)�”}”(hŒ�``SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE``: a local-DSQ dispatch was redirected to the global DSQ because the target CPU went offline.”h]”(j¾)�”}”(hŒ%``SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE``”h]”hŒ!SCX_EV_DISPATCH_LOCAL_DSQ_OFFLINE”…”�”}”(hjWh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjSubhŒ\: a local-DSQ dispatch was redirected to the global DSQ because the target CPU went offline.”…”�”}”(hjSh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KyhjOubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒˆ``SCX_EV_DISPATCH_KEEP_LAST``: a task continued running because no other task was available (only when ``SCX_OPS_ENQ_LAST`` is not set).”h]”hÚ)�”}”(hŒˆ``SCX_EV_DISPATCH_KEEP_LAST``: a task continued running because no other task was available (only when ``SCX_OPS_ENQ_LAST`` is not set).”h]”(j¾)�”}”(hŒ``SCX_EV_DISPATCH_KEEP_LAST``”h]”hŒSCX_EV_DISPATCH_KEEP_LAST”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒJ: a task continued running because no other task was available (only when ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_OPS_ENQ_LAST``”h]”hŒSCX_OPS_ENQ_LAST”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ is not set).”…”�”}”(hjyh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K{hjuubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒž``SCX_EV_ENQ_SKIP_EXITING``: an exiting task was dispatched to the local DSQ directly, bypassing ops.enqueue() (only when ``SCX_OPS_ENQ_EXITING`` is not set).”h]”hÚ)�”}”(hŒž``SCX_EV_ENQ_SKIP_EXITING``: an exiting task was dispatched to the local DSQ directly, bypassing ops.enqueue() (only when ``SCX_OPS_ENQ_EXITING`` is not set).”h]”(j¾)�”}”(hŒ``SCX_EV_ENQ_SKIP_EXITING``”h]”hŒSCX_EV_ENQ_SKIP_EXITING”…”�”}”(hjµh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj±ubhŒ_: an exiting task was dispatched to the local DSQ directly, bypassing ops.enqueue() (only when ”…”�”}”(hj±h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_OPS_ENQ_EXITING``”h]”hŒSCX_OPS_ENQ_EXITING”…”�”}”(hjÇh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj±ubhŒ is not set).”…”�”}”(hj±h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K}hj­ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒ¥``SCX_EV_ENQ_SKIP_MIGRATION_DISABLED``: a migration-disabled task was dispatched to its local DSQ directly (only when ``SCX_OPS_ENQ_MIGRATION_DISABLED`` is not set).”h]”hÚ)�”}”(hŒ¥``SCX_EV_ENQ_SKIP_MIGRATION_DISABLED``: a migration-disabled task was dispatched to its local DSQ directly (only when ``SCX_OPS_ENQ_MIGRATION_DISABLED`` is not set).”h]”(j¾)�”}”(hŒ&``SCX_EV_ENQ_SKIP_MIGRATION_DISABLED``”h]”hŒ"SCX_EV_ENQ_SKIP_MIGRATION_DISABLED”…”�”}”(hjíh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjéubhŒP: a migration-disabled task was dispatched to its local DSQ directly (only when ”…”�”}”(hjéh²hh³Nh´Nubj¾)�”}”(hŒ"``SCX_OPS_ENQ_MIGRATION_DISABLED``”h]”hŒSCX_OPS_ENQ_MIGRATION_DISABLED”…”�”}”(hjÿh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjéubhŒ is not set).”…”�”}”(hjéh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Khjåubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒ’``SCX_EV_REENQ_IMMED``: a task dispatched with ``SCX_ENQ_IMMED`` was re-enqueued because the target CPU was not available for immediate execution.”h]”hÚ)�”}”(hŒ’``SCX_EV_REENQ_IMMED``: a task dispatched with ``SCX_ENQ_IMMED`` was re-enqueued because the target CPU was not available for immediate execution.”h]”(j¾)�”}”(hŒ``SCX_EV_REENQ_IMMED``”h]”hŒSCX_EV_REENQ_IMMED”…”�”}”(hj%h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj!ubhŒ: a task dispatched with ”…”�”}”(hj!h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_ENQ_IMMED``”h]”hŒ SCX_ENQ_IMMED”…”�”}”(hj7h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj!ubhŒR was re-enqueued because the target CPU was not available for immediate execution.”…”�”}”(hj!h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K‚hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒÀ``SCX_EV_REENQ_REPEAT``: a reenqueue led to another reenqueue without the task running in between; recurring counts indicate that the BPF scheduler keeps re-deciding placements it can't honor.”h]”hÚ)�”}”(hŒÀ``SCX_EV_REENQ_REPEAT``: a reenqueue led to another reenqueue without the task running in between; recurring counts indicate that the BPF scheduler keeps re-deciding placements it can't honor.”h]”(j¾)�”}”(hŒ``SCX_EV_REENQ_REPEAT``”h]”hŒSCX_EV_REENQ_REPEAT”…”�”}”(hj]h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjYubhŒ«: a reenqueue led to another reenqueue without the task running in between; recurring counts indicate that the BPF scheduler keeps re-deciding placements it can’t honor.”…”�”}”(hjYh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K„hjUubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒi``SCX_EV_REFILL_SLICE_DFL``: a task's time slice was refilled with the default value (``SCX_SLICE_DFL``).”h]”hÚ)�”}”(hŒi``SCX_EV_REFILL_SLICE_DFL``: a task's time slice was refilled with the default value (``SCX_SLICE_DFL``).”h]”(j¾)�”}”(hŒ``SCX_EV_REFILL_SLICE_DFL``”h]”hŒSCX_EV_REFILL_SLICE_DFL”…”�”}”(hjƒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ=: a task’s time slice was refilled with the default value (”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_SLICE_DFL``”h]”hŒ SCX_SLICE_DFL”…”�”}”(hj•h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ).”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K‡hj{ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒC``SCX_EV_BYPASS_DURATION``: total nanoseconds spent in bypass mode.”h]”hÚ)�”}”(hjµh]”(j¾)�”}”(hŒ``SCX_EV_BYPASS_DURATION``”h]”hŒSCX_EV_BYPASS_DURATION”…”�”}”(hjºh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj·ubhŒ): total nanoseconds spent in bypass mode.”…”�”}”(hj·h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K‰hj³ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒL``SCX_EV_BYPASS_DISPATCH``: number of tasks dispatched while in bypass mode.”h]”hÚ)�”}”(hjÚh]”(j¾)�”}”(hŒ``SCX_EV_BYPASS_DISPATCH``”h]”hŒSCX_EV_BYPASS_DISPATCH”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÜubhŒ2: number of tasks dispatched while in bypass mode.”…”�”}”(hjÜh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KŠhjØubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒF``SCX_EV_BYPASS_ACTIVATE``: number of times bypass mode was activated.”h]”hÚ)�”}”(hjÿh]”(j¾)�”}”(hŒ``SCX_EV_BYPASS_ACTIVATE``”h]”hŒSCX_EV_BYPASS_ACTIVATE”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ,: number of times bypass mode was activated.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K‹hjýubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒƒ``SCX_EV_INSERT_NOT_OWNED``: attempted to insert a task not owned by this scheduler into a DSQ; such attempts are silently ignored.”h]”hÚ)�”}”(hŒƒ``SCX_EV_INSERT_NOT_OWNED``: attempted to insert a task not owned by this scheduler into a DSQ; such attempts are silently ignored.”h]”(j¾)�”}”(hŒ``SCX_EV_INSERT_NOT_OWNED``”h]”hŒSCX_EV_INSERT_NOT_OWNED”…”�”}”(hj*h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj&ubhŒh: attempted to insert a task not owned by this scheduler into a DSQ; such attempts are silently ignored.”…”�”}”(hj&h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KŒhj"ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubhï)�”}”(hŒ``SCX_EV_SUB_BYPASS_DISPATCH``: tasks dispatched from sub-scheduler bypass DSQs (only relevant with ``CONFIG_EXT_SUB_SCHED``). ”h]”hÚ)�”}”(hŒ~``SCX_EV_SUB_BYPASS_DISPATCH``: tasks dispatched from sub-scheduler bypass DSQs (only relevant with ``CONFIG_EXT_SUB_SCHED``).”h]”(j¾)�”}”(hŒ``SCX_EV_SUB_BYPASS_DISPATCH``”h]”hŒSCX_EV_SUB_BYPASS_DISPATCH”…”�”}”(hjPh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjLubhŒF: tasks dispatched from sub-scheduler bypass DSQs (only relevant with ”…”�”}”(hjLh²hh³Nh´Nubj¾)�”}”(hŒ``CONFIG_EXT_SUB_SCHED``”h]”hŒCONFIG_EXT_SUB_SCHED”…”�”}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjLubhŒ).”…”�”}”(hjLh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´KŽhjHubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj&h²hh³hÃh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´Kwhj¨h²hubhÚ)�”}”(hŒ]``tools/sched_ext/scx_show_state.py`` is a drgn script which shows more detailed information:”h]”(j¾)�”}”(hŒ%``tools/sched_ext/scx_show_state.py``”h]”hŒ!tools/sched_ext/scx_show_state.py”…”�”}”(hjŠh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj†ubhŒ8 is a drgn script which shows more detailed information:”…”�”}”(hj†h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K‘hj¨h²hubjê)�”}”(hŒØ# tools/sched_ext/scx_show_state.py ops : simple enabled : 1 switching_all : 1 switched_all : 1 enable_state : enabled (2) aborting : False bypass_depth : 0 nr_rejected : 0 enable_seq : 1”h]”hŒØ# tools/sched_ext/scx_show_state.py ops : simple enabled : 1 switching_all : 1 switched_all : 1 enable_state : enabled (2) aborting : False bypass_depth : 0 nr_rejected : 0 enable_seq : 1”…”�”}”hj¢sbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´K”hj¨h²hubhÚ)�”}”(hŒBWhether a given task is on sched_ext can be determined as follows:”h]”hŒBWhether a given task is on sched_ext can be determined as follows:”…”�”}”(hj²h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K¡hj¨h²hubjê)�”}”(hŒ_# grep ext /proc/self/sched ext.enabled : 1”h]”hŒ_# grep ext /proc/self/sched ext.enabled : 1”…”�”}”hjÀsbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒnone”jþ}”uh1jéh³hÃh´K£hj¨h²hubeh}”(h]”Œswitching-to-and-from-sched-ext”ah ]”h"]”Œswitching to and from sched_ext”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´KubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒ The Basics”h]”hŒ The Basics”…”�”}”(hjÛh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjØh²hh³hÃh´K©ubhÚ)�”}”(hX^Userspace can implement an arbitrary BPF scheduler by loading a set of BPF programs that implement ``struct sched_ext_ops``. The only mandatory field is ``ops.name`` which must be a valid BPF object name. All operations are optional. The following modified excerpt is from ``tools/sched_ext/scx_simple.bpf.c`` showing a minimal global FIFO scheduler.”h]”(hŒcUserspace can implement an arbitrary BPF scheduler by loading a set of BPF programs that implement ”…”�”}”(hjéh²hh³Nh´Nubj¾)�”}”(hŒ``struct sched_ext_ops``”h]”hŒstruct sched_ext_ops”…”�”}”(hjñh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjéubhŒ. The only mandatory field is ”…”�”}”(hjéh²hh³Nh´Nubj¾)�”}”(hŒ ``ops.name``”h]”hŒops.name”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjéubhŒl which must be a valid BPF object name. All operations are optional. The following modified excerpt is from ”…”�”}”(hjéh²hh³Nh´Nubj¾)�”}”(hŒ$``tools/sched_ext/scx_simple.bpf.c``”h]”hŒ tools/sched_ext/scx_simple.bpf.c”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjéubhŒ) showing a minimal global FIFO scheduler.”…”�”}”(hjéh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´K«hjØh²hubjê)�”}”(hXÂ/* * Decide which CPU a task should be migrated to before being * enqueued (either at wakeup, fork time, or exec time). If an * idle core is found by the default ops.select_cpu() implementation, * then insert the task directly into SCX_DSQ_LOCAL and skip the * ops.enqueue() callback. * * Note that this implementation has exactly the same behavior as the * default ops.select_cpu implementation. The behavior of the scheduler * would be exactly same if the implementation just didn't define the * simple_select_cpu() struct_ops prog. */ s32 BPF_STRUCT_OPS(simple_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags) { s32 cpu; /* Need to initialize or the BPF verifier will reject the program */ bool direct = false; cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &direct); if (direct) scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0); return cpu; } /* * Do a direct insertion of a task to the global DSQ. This ops.enqueue() * callback will only be invoked if we failed to find a core to insert * into in ops.select_cpu() above. * * Note that this implementation has exactly the same behavior as the * default ops.enqueue implementation, which just dispatches the task * to SCX_DSQ_GLOBAL. The behavior of the scheduler would be exactly same * if the implementation just didn't define the simple_enqueue struct_ops * prog. */ void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags) { scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); } s32 BPF_STRUCT_OPS_SLEEPABLE(simple_init) { /* * By default, all SCHED_EXT, SCHED_OTHER, SCHED_IDLE, and * SCHED_BATCH tasks should use sched_ext. */ return 0; } void BPF_STRUCT_OPS(simple_exit, struct scx_exit_info *ei) { exit_type = ei->kind; } SEC(".struct_ops") struct sched_ext_ops simple_ops = { .select_cpu = (void *)simple_select_cpu, .enqueue = (void *)simple_enqueue, .init = (void *)simple_init, .exit = (void *)simple_exit, .name = "simple", };”h]”hXÂ/* * Decide which CPU a task should be migrated to before being * enqueued (either at wakeup, fork time, or exec time). If an * idle core is found by the default ops.select_cpu() implementation, * then insert the task directly into SCX_DSQ_LOCAL and skip the * ops.enqueue() callback. * * Note that this implementation has exactly the same behavior as the * default ops.select_cpu implementation. The behavior of the scheduler * would be exactly same if the implementation just didn't define the * simple_select_cpu() struct_ops prog. */ s32 BPF_STRUCT_OPS(simple_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags) { s32 cpu; /* Need to initialize or the BPF verifier will reject the program */ bool direct = false; cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &direct); if (direct) scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0); return cpu; } /* * Do a direct insertion of a task to the global DSQ. This ops.enqueue() * callback will only be invoked if we failed to find a core to insert * into in ops.select_cpu() above. * * Note that this implementation has exactly the same behavior as the * default ops.enqueue implementation, which just dispatches the task * to SCX_DSQ_GLOBAL. The behavior of the scheduler would be exactly same * if the implementation just didn't define the simple_enqueue struct_ops * prog. */ void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags) { scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); } s32 BPF_STRUCT_OPS_SLEEPABLE(simple_init) { /* * By default, all SCHED_EXT, SCHED_OTHER, SCHED_IDLE, and * SCHED_BATCH tasks should use sched_ext. */ return 0; } void BPF_STRUCT_OPS(simple_exit, struct scx_exit_info *ei) { exit_type = ei->kind; } SEC(".struct_ops") struct sched_ext_ops simple_ops = { .select_cpu = (void *)simple_select_cpu, .enqueue = (void *)simple_enqueue, .init = (void *)simple_init, .exit = (void *)simple_exit, .name = "simple", };”…”�”}”hj-sbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüŒc”jþ}”uh1jéh³hÃh´K±hjØh²hubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒScheduler-Dependent Knobs”h]”hŒScheduler-Dependent Knobs”…”�”}”(hj@h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj=h²hh³hÃh´KöubhÚ)�”}”(hX¦The fair-class scheduler enforces CPU controller settings such as ``cpu.max``, ``cpu.weight`` and ``cpu.idle``. For sched_ext tasks, the scheduler core communicates these settings to the BPF scheduler through ``ops.cgroup_init()`` and reports subsequent changes through the corresponding ``ops.cgroup_set_*()`` callbacks. Similarly, per-task nice changes are converted to weights and reported through ``ops.set_weight()``.”h]”(hŒBThe fair-class scheduler enforces CPU controller settings such as ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ ``cpu.max``”h]”hŒcpu.max”…”�”}”(hjVh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒ, ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ``cpu.weight``”h]”hŒ cpu.weight”…”�”}”(hjhh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒ and ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ ``cpu.idle``”h]”hŒcpu.idle”…”�”}”(hjzh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒc. For sched_ext tasks, the scheduler core communicates these settings to the BPF scheduler through ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ``ops.cgroup_init()``”h]”hŒops.cgroup_init()”…”�”}”(hjŒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒ: and reports subsequent changes through the corresponding ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ``ops.cgroup_set_*()``”h]”hŒops.cgroup_set_*()”…”�”}”(hjžh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒ[ callbacks. Similarly, per-task nice changes are converted to weights and reported through ”…”�”}”(hjNh²hh³Nh´Nubj¾)�”}”(hŒ``ops.set_weight()``”h]”hŒops.set_weight()”…”�”}”(hj°h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjNubhŒ.”…”�”}”(hjNh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Køhj=h²hubhÚ)�”}”(hŒËEach BPF scheduler is responsible for implementing the scheduling semantics of these settings and may choose to ignore them. Consult the loaded scheduler's documentation before relying on these controls.”h]”hŒÍEach BPF scheduler is responsible for implementing the scheduling semantics of these settings and may choose to ignore them. Consult the loaded scheduler’s documentation before relying on these controls.”…”�”}”(hjÈh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj=h²hubeh}”(h]”Œscheduler-dependent-knobs”ah ]”h"]”Œscheduler-dependent knobs”ah$]”h&]”uh1hÄhjØh²hh³hÃh´KöubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒDispatch Queues”h]”hŒDispatch Queues”…”�”}”(hjáh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjÞh²hh³hÃh´MubhÚ)�”}”(hX†To match the impedance between the scheduler core and the BPF scheduler, sched_ext uses DSQs (dispatch queues) which can operate as both a FIFO and a priority queue. By default, there is one global FIFO (``SCX_DSQ_GLOBAL``), and one local DSQ per CPU (``SCX_DSQ_LOCAL``). The BPF scheduler can manage an arbitrary number of DSQs using ``scx_bpf_create_dsq()`` and ``scx_bpf_destroy_dsq()``.”h]”(hŒÌTo match the impedance between the scheduler core and the BPF scheduler, sched_ext uses DSQs (dispatch queues) which can operate as both a FIFO and a priority queue. By default, there is one global FIFO (”…”�”}”(hjïh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_GLOBAL``”h]”hŒSCX_DSQ_GLOBAL”…”�”}”(hj÷h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjïubhŒ), and one local DSQ per CPU (”…”�”}”(hjïh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjïubhŒB). The BPF scheduler can manage an arbitrary number of DSQs using ”…”�”}”(hjïh²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_create_dsq()``”h]”hŒscx_bpf_create_dsq()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjïubhŒ and ”…”�”}”(hjïh²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_destroy_dsq()``”h]”hŒscx_bpf_destroy_dsq()”…”�”}”(hj-h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjïubhŒ.”…”�”}”(hjïh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjÞh²hubhÚ)�”}”(hŒ—A CPU always executes a task from its local DSQ. A task is "inserted" into a DSQ. A task in a non-local DSQ is "move"d into the target CPU's local DSQ.”h]”hŒ¡A CPU always executes a task from its local DSQ. A task is “insertedâ€� into a DSQ. A task in a non-local DSQ is “moveâ€�d into the target CPU’s local DSQ.”…”�”}”(hjEh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjÞh²hubhÚ)�”}”(hŒòWhen a CPU is looking for the next task to run, if the local DSQ is not empty, the first task is picked. Otherwise, the CPU tries to move a task from the global DSQ. If that doesn't yield a runnable task either, ``ops.dispatch()`` is invoked.”h]”(hŒÖWhen a CPU is looking for the next task to run, if the local DSQ is not empty, the first task is picked. Otherwise, the CPU tries to move a task from the global DSQ. If that doesn’t yield a runnable task either, ”…”�”}”(hjSh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjSubhŒ is invoked.”…”�”}”(hjSh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjÞh²hubeh}”(h]”Œdispatch-queues”ah ]”h"]”Œdispatch queues”ah$]”h&]”uh1hÄhjØh²hh³hÃh´MubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒScheduling Cycle”h]”hŒScheduling Cycle”…”�”}”(hj~h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj{h²hh³hÃh´MubhÚ)�”}”(hŒHThe following briefly shows how a waking task is scheduled and executed.”h]”hŒHThe following briefly shows how a waking task is scheduled and executed.”…”�”}”(hjŒh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj{h²hubhŒenumerated_list”“”)�”}”(hhh]”(hï)�”}”(hX³When a task is waking up, ``ops.select_cpu()`` is the first operation invoked. This serves two purposes. First, CPU selection optimization hint. Second, waking up the selected CPU if idle. The CPU selected by ``ops.select_cpu()`` is an optimization hint and not binding. The actual decision is made at the last step of scheduling. However, there is a small performance gain if the CPU ``ops.select_cpu()`` returns matches the CPU the task eventually runs on. A side-effect of selecting a CPU is waking it up from idle. While a BPF scheduler can wake up any cpu using the ``scx_bpf_kick_cpu()`` helper, using ``ops.select_cpu()`` judiciously can be simpler and more efficient. Note that the scheduler core will ignore an invalid CPU selection, for example, if it's outside the allowed cpumask of the task. A task can be immediately inserted into a DSQ from ``ops.select_cpu()`` by calling ``scx_bpf_dsq_insert()`` or ``scx_bpf_dsq_insert_vtime()``. If the task is inserted into ``SCX_DSQ_LOCAL`` from ``ops.select_cpu()``, it will be added to the local DSQ of whichever CPU is returned from ``ops.select_cpu()``. Additionally, inserting directly from ``ops.select_cpu()`` will cause the ``ops.enqueue()`` callback to be skipped. Any other attempt to store a task in BPF-internal data structures from ``ops.select_cpu()`` does not prevent ``ops.enqueue()`` from being invoked. This is discouraged, as it can introduce racy behavior or inconsistent state. ”h]”(hÚ)�”}”(hŒ¼When a task is waking up, ``ops.select_cpu()`` is the first operation invoked. This serves two purposes. First, CPU selection optimization hint. Second, waking up the selected CPU if idle.”h]”(hŒWhen a task is waking up, ”…”�”}”(hj£h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj«h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj£ubhŒŽ is the first operation invoked. This serves two purposes. First, CPU selection optimization hint. Second, waking up the selected CPU if idle.”…”�”}”(hj£h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjŸubhÚ)�”}”(hX The CPU selected by ``ops.select_cpu()`` is an optimization hint and not binding. The actual decision is made at the last step of scheduling. However, there is a small performance gain if the CPU ``ops.select_cpu()`` returns matches the CPU the task eventually runs on.”h]”(hŒThe CPU selected by ”…”�”}”(hjÃh²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hjËh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÃubhŒœ is an optimization hint and not binding. The actual decision is made at the last step of scheduling. However, there is a small performance gain if the CPU ”…”�”}”(hjÃh²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÃubhŒ5 returns matches the CPU the task eventually runs on.”…”�”}”(hjÃh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjŸubhÚ)�”}”(hŒØA side-effect of selecting a CPU is waking it up from idle. While a BPF scheduler can wake up any cpu using the ``scx_bpf_kick_cpu()`` helper, using ``ops.select_cpu()`` judiciously can be simpler and more efficient.”h]”(hŒpA side-effect of selecting a CPU is waking it up from idle. While a BPF scheduler can wake up any cpu using the ”…”�”}”(hjõh²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_kick_cpu()``”h]”hŒscx_bpf_kick_cpu()”…”�”}”(hjýh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjõubhŒ helper, using ”…”�”}”(hjõh²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjõubhŒ/ judiciously can be simpler and more efficient.”…”�”}”(hjõh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M$hjŸubhÚ)�”}”(hŒ€Note that the scheduler core will ignore an invalid CPU selection, for example, if it's outside the allowed cpumask of the task.”h]”hŒ‚Note that the scheduler core will ignore an invalid CPU selection, for example, if it’s outside the allowed cpumask of the task.”…”�”}”(hj' h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M(hjŸubhÚ)�”}”(hŒŽA task can be immediately inserted into a DSQ from ``ops.select_cpu()`` by calling ``scx_bpf_dsq_insert()`` or ``scx_bpf_dsq_insert_vtime()``.”h]”(hŒ3A task can be immediately inserted into a DSQ from ”…”�”}”(hj5 h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj= h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj5 ubhŒ by calling ”…”�”}”(hj5 h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hjO h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj5 ubhŒ or ”…”�”}”(hj5 h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert_vtime()``”h]”hŒscx_bpf_dsq_insert_vtime()”…”�”}”(hja h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj5 ubhŒ.”…”�”}”(hj5 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M+hjŸubhÚ)�”}”(hXIf the task is inserted into ``SCX_DSQ_LOCAL`` from ``ops.select_cpu()``, it will be added to the local DSQ of whichever CPU is returned from ``ops.select_cpu()``. Additionally, inserting directly from ``ops.select_cpu()`` will cause the ``ops.enqueue()`` callback to be skipped.”h]”(hŒIf the task is inserted into ”…”�”}”(hjy h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjy ubhŒ from ”…”�”}”(hjy h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj“ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjy ubhŒF, it will be added to the local DSQ of whichever CPU is returned from ”…”�”}”(hjy h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj¥ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjy ubhŒ(. Additionally, inserting directly from ”…”�”}”(hjy h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj· h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjy ubhŒ will cause the ”…”�”}”(hjy h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjÉ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjy ubhŒ callback to be skipped.”…”�”}”(hjy h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M.hjŸubhÚ)�”}”(hŒàAny other attempt to store a task in BPF-internal data structures from ``ops.select_cpu()`` does not prevent ``ops.enqueue()`` from being invoked. This is discouraged, as it can introduce racy behavior or inconsistent state.”h]”(hŒGAny other attempt to store a task in BPF-internal data structures from ”…”�”}”(hjá h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hjé h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjá ubhŒ does not prevent ”…”�”}”(hjá h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjû h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjá ubhŒb from being invoked. This is discouraged, as it can introduce racy behavior or inconsistent state.”…”�”}”(hjá h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M4hjŸubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîhjœh²hh³hÃh´Nubhï)�”}”(hXÔ Once the target CPU is selected, ``ops.enqueue()`` is invoked (unless the task was inserted directly from ``ops.select_cpu()``). ``ops.enqueue()`` can make one of the following decisions: * Immediately insert the task into either the global or a local DSQ by calling ``scx_bpf_dsq_insert()`` with one of the following options: ``SCX_DSQ_GLOBAL``, ``SCX_DSQ_LOCAL``, or ``SCX_DSQ_LOCAL_ON | cpu``. * Immediately insert the task into a custom DSQ by calling ``scx_bpf_dsq_insert()`` with a DSQ ID which is smaller than 2^63. * Queue the task on the BPF side. **Task State Tracking and ops.dequeue() Semantics** A task is in the "BPF scheduler's custody" when the BPF scheduler is responsible for managing its lifecycle. A task enters custody when it is dispatched to a user DSQ or stored in the BPF scheduler's internal data structures. Custody is entered only from ``ops.enqueue()`` for those operations. The only exception is dispatching to a user DSQ from ``ops.select_cpu()``: although the task is not yet technically in BPF scheduler custody at that point, the dispatch has the same semantic effect as dispatching from ``ops.enqueue()`` for custody-related purposes. Once ``ops.enqueue()`` is called, the task may or may not enter custody depending on what the scheduler does: * **Directly dispatched to terminal DSQs** (``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, or ``SCX_DSQ_GLOBAL``): the BPF scheduler is done with the task - it either goes straight to a CPU's local run queue or to the global DSQ as a fallback. The task never enters (or exits) BPF custody, and ``ops.dequeue()`` will not be called. * **Dispatch to user-created DSQs** (custom DSQs): the task enters the BPF scheduler's custody. When the task later leaves BPF custody (dispatched to a terminal DSQ, picked by core-sched, or dequeued for sleep/property changes), ``ops.dequeue()`` will be called exactly once. * **Stored in BPF data structures** (e.g., internal BPF queues): the task is in BPF custody. ``ops.dequeue()`` will be called when it leaves (e.g., when ``ops.dispatch()`` moves it to a terminal DSQ, or on property change / sleep). Note that ``ops.enqueue()`` can be called multiple times in a row without an intervening call to ``ops.dequeue()``. This can happen, for example, when a task on a user-created DSQ is re-enqueued using ``scx_bpf_dsq_reenq()``. The task stays in BPF custody the entire time. When a task leaves BPF scheduler custody, ``ops.dequeue()`` is invoked. The dequeue can happen for different reasons, distinguished by flags: 1. **Regular dispatch**: when a task in BPF custody is dispatched to a terminal DSQ from ``ops.dispatch()`` (leaving BPF custody for execution), ``ops.dequeue()`` is triggered without any special flags. 2. **Core scheduling pick**: when ``CONFIG_SCHED_CORE`` is enabled and core scheduling picks a task for execution while it's still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_CORE_SCHED_EXEC`` flag. 3. **Scheduling property change**: when a task property changes (via operations like ``sched_setaffinity()``, ``sched_setscheduler()``, priority changes, CPU migrations, etc.) while the task is still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_SCHED_CHANGE`` flag set in ``deq_flags``. **Important**: Once a task has left BPF custody (e.g., after being dispatched to a terminal DSQ), property changes will not trigger ``ops.dequeue()``, since the task is no longer managed by the BPF scheduler. ”h]”(hÚ)�”}”(hŒ»Once the target CPU is selected, ``ops.enqueue()`` is invoked (unless the task was inserted directly from ``ops.select_cpu()``). ``ops.enqueue()`` can make one of the following decisions:”h]”(hŒ!Once the target CPU is selected, ”…”�”}”(hj h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hj% h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj ubhŒ8 is invoked (unless the task was inserted directly from ”…”�”}”(hj h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj7 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj ubhŒ). ”…”�”}”(hj h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjI h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj ubhŒ) can make one of the following decisions:”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M9hj ubhê)�”}”(hhh]”(hï)�”}”(hŒÏImmediately insert the task into either the global or a local DSQ by calling ``scx_bpf_dsq_insert()`` with one of the following options: ``SCX_DSQ_GLOBAL``, ``SCX_DSQ_LOCAL``, or ``SCX_DSQ_LOCAL_ON | cpu``. ”h]”hÚ)�”}”(hŒÎImmediately insert the task into either the global or a local DSQ by calling ``scx_bpf_dsq_insert()`` with one of the following options: ``SCX_DSQ_GLOBAL``, ``SCX_DSQ_LOCAL``, or ``SCX_DSQ_LOCAL_ON | cpu``.”h]”(hŒMImmediately insert the task into either the global or a local DSQ by calling ”…”�”}”(hjh h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hjp h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjh ubhŒ$ with one of the following options: ”…”�”}”(hjh h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_GLOBAL``”h]”hŒSCX_DSQ_GLOBAL”…”�”}”(hj‚ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjh ubhŒ, ”…”�”}”(hjh h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hj” h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjh ubhŒ, or ”…”�”}”(hjh h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL_ON | cpu``”h]”hŒSCX_DSQ_LOCAL_ON | cpu”…”�”}”(hj¦ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjh ubhŒ.”…”�”}”(hjh h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M=hjd ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhja ubhï)�”}”(hŒ|Immediately insert the task into a custom DSQ by calling ``scx_bpf_dsq_insert()`` with a DSQ ID which is smaller than 2^63. ”h]”hÚ)�”}”(hŒ{Immediately insert the task into a custom DSQ by calling ``scx_bpf_dsq_insert()`` with a DSQ ID which is smaller than 2^63.”h]”(hŒ9Immediately insert the task into a custom DSQ by calling ”…”�”}”(hjÈ h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hjÐ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÈ ubhŒ* with a DSQ ID which is smaller than 2^63.”…”�”}”(hjÈ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MAhjÄ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhja ubhï)�”}”(hŒ Queue the task on the BPF side. ”h]”hÚ)�”}”(hŒQueue the task on the BPF side.”h]”hŒQueue the task on the BPF side.”…”�”}”(hjò h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MDhjî ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhja ubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´M=hj ubhÚ)�”}”(hŒ3**Task State Tracking and ops.dequeue() Semantics**”h]”hŒstrong”“”)�”}”(hj h]”hŒ/Task State Tracking and ops.dequeue() Semantics”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MFhj ubhÚ)�”}”(hX0A task is in the "BPF scheduler's custody" when the BPF scheduler is responsible for managing its lifecycle. A task enters custody when it is dispatched to a user DSQ or stored in the BPF scheduler's internal data structures. Custody is entered only from ``ops.enqueue()`` for those operations. The only exception is dispatching to a user DSQ from ``ops.select_cpu()``: although the task is not yet technically in BPF scheduler custody at that point, the dispatch has the same semantic effect as dispatching from ``ops.enqueue()`` for custody-related purposes.”h]”(hXA task is in the “BPF scheduler’s custodyâ€� when the BPF scheduler is responsible for managing its lifecycle. A task enters custody when it is dispatched to a user DSQ or stored in the BPF scheduler’s internal data structures. Custody is entered only from ”…”�”}”(hj% h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hj- h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj% ubhŒL for those operations. The only exception is dispatching to a user DSQ from ”…”�”}”(hj% h²hh³Nh´Nubj¾)�”}”(hŒ``ops.select_cpu()``”h]”hŒops.select_cpu()”…”�”}”(hj? h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj% ubhŒ‘: although the task is not yet technically in BPF scheduler custody at that point, the dispatch has the same semantic effect as dispatching from ”…”�”}”(hj% h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjQ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj% ubhŒ for custody-related purposes.”…”�”}”(hj% h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MHhj ubhÚ)�”}”(hŒmOnce ``ops.enqueue()`` is called, the task may or may not enter custody depending on what the scheduler does:”h]”(hŒOnce ”…”�”}”(hji h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjq h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hji ubhŒW is called, the task may or may not enter custody depending on what the scheduler does:”…”�”}”(hji h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MRhj ubhê)�”}”(hhh]”(hï)�”}”(hXJ**Directly dispatched to terminal DSQs** (``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, or ``SCX_DSQ_GLOBAL``): the BPF scheduler is done with the task - it either goes straight to a CPU's local run queue or to the global DSQ as a fallback. The task never enters (or exits) BPF custody, and ``ops.dequeue()`` will not be called. ”h]”hÚ)�”}”(hXI**Directly dispatched to terminal DSQs** (``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, or ``SCX_DSQ_GLOBAL``): the BPF scheduler is done with the task - it either goes straight to a CPU's local run queue or to the global DSQ as a fallback. The task never enters (or exits) BPF custody, and ``ops.dequeue()`` will not be called.”h]”(j )�”}”(hŒ(**Directly dispatched to terminal DSQs**”h]”hŒ$Directly dispatched to terminal DSQs”…”�”}”(hj” h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj� ubhŒ (”…”�”}”(hj� h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hj¦ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj� ubhŒ, ”…”�”}”(hj� h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL_ON | cpu``”h]”hŒSCX_DSQ_LOCAL_ON | cpu”…”�”}”(hj¸ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj� ubhŒ, or ”…”�”}”(hj� h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_GLOBAL``”h]”hŒSCX_DSQ_GLOBAL”…”�”}”(hjÊ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj� ubhŒ¸): the BPF scheduler is done with the task - it either goes straight to a CPU’s local run queue or to the global DSQ as a fallback. The task never enters (or exits) BPF custody, and ”…”�”}”(hj� h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hjÜ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj� ubhŒ will not be called.”…”�”}”(hj� h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MUhjŒ ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj‰ ubhï)�”}”(hX**Dispatch to user-created DSQs** (custom DSQs): the task enters the BPF scheduler's custody. When the task later leaves BPF custody (dispatched to a terminal DSQ, picked by core-sched, or dequeued for sleep/property changes), ``ops.dequeue()`` will be called exactly once. ”h]”hÚ)�”}”(hX**Dispatch to user-created DSQs** (custom DSQs): the task enters the BPF scheduler's custody. When the task later leaves BPF custody (dispatched to a terminal DSQ, picked by core-sched, or dequeued for sleep/property changes), ``ops.dequeue()`` will be called exactly once.”h]”(j )�”}”(hŒ!**Dispatch to user-created DSQs**”h]”hŒDispatch to user-created DSQs”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjþ ubhŒÄ (custom DSQs): the task enters the BPF scheduler’s custody. When the task later leaves BPF custody (dispatched to a terminal DSQ, picked by core-sched, or dequeued for sleep/property changes), ”…”�”}”(hjþ h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjþ ubhŒ will be called exactly once.”…”�”}”(hjþ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M[hjú ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj‰ ubhï)�”}”(hŒæ**Stored in BPF data structures** (e.g., internal BPF queues): the task is in BPF custody. ``ops.dequeue()`` will be called when it leaves (e.g., when ``ops.dispatch()`` moves it to a terminal DSQ, or on property change / sleep). ”h]”hÚ)�”}”(hŒå**Stored in BPF data structures** (e.g., internal BPF queues): the task is in BPF custody. ``ops.dequeue()`` will be called when it leaves (e.g., when ``ops.dispatch()`` moves it to a terminal DSQ, or on property change / sleep).”h]”(j )�”}”(hŒ!**Stored in BPF data structures**”h]”hŒStored in BPF data structures”…”�”}”(hj: h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj6 ubhŒ: (e.g., internal BPF queues): the task is in BPF custody. ”…”�”}”(hj6 h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hjL h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj6 ubhŒ+ will be called when it leaves (e.g., when ”…”�”}”(hj6 h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hj^ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj6 ubhŒ< moves it to a terminal DSQ, or on property change / sleep).”…”�”}”(hj6 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mahj2 ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj‰ ubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´MUhj ubhÚ)�”}”(hXNote that ``ops.enqueue()`` can be called multiple times in a row without an intervening call to ``ops.dequeue()``. This can happen, for example, when a task on a user-created DSQ is re-enqueued using ``scx_bpf_dsq_reenq()``. The task stays in BPF custody the entire time.”h]”(hŒ Note that ”…”�”}”(hj‚ h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjŠ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj‚ ubhŒF can be called multiple times in a row without an intervening call to ”…”�”}”(hj‚ h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hjœ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj‚ ubhŒW. This can happen, for example, when a task on a user-created DSQ is re-enqueued using ”…”�”}”(hj‚ h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_reenq()``”h]”hŒscx_bpf_dsq_reenq()”…”�”}”(hj® h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj‚ ubhŒ0. The task stays in BPF custody the entire time.”…”�”}”(hj‚ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mfhj ubhÚ)�”}”(hŒ�When a task leaves BPF scheduler custody, ``ops.dequeue()`` is invoked. The dequeue can happen for different reasons, distinguished by flags:”h]”(hŒ*When a task leaves BPF scheduler custody, ”…”�”}”(hjÆ h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hjÎ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÆ ubhŒR is invoked. The dequeue can happen for different reasons, distinguished by flags:”…”�”}”(hjÆ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mkhj ubj›)�”}”(hhh]”(hï)�”}”(hŒÈ**Regular dispatch**: when a task in BPF custody is dispatched to a terminal DSQ from ``ops.dispatch()`` (leaving BPF custody for execution), ``ops.dequeue()`` is triggered without any special flags. ”h]”hÚ)�”}”(hŒÇ**Regular dispatch**: when a task in BPF custody is dispatched to a terminal DSQ from ``ops.dispatch()`` (leaving BPF custody for execution), ``ops.dequeue()`` is triggered without any special flags.”h]”(j )�”}”(hŒ**Regular dispatch**”h]”hŒRegular dispatch”…”�”}”(hjñ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjí ubhŒB: when a task in BPF custody is dispatched to a terminal DSQ from ”…”�”}”(hjí h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjí ubhŒ& (leaving BPF custody for execution), ”…”�”}”(hjí h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjí ubhŒ( is triggered without any special flags.”…”�”}”(hjí h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mnhjé ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjæ ubhï)�”}”(hŒ×**Core scheduling pick**: when ``CONFIG_SCHED_CORE`` is enabled and core scheduling picks a task for execution while it's still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_CORE_SCHED_EXEC`` flag. ”h]”hÚ)�”}”(hŒÖ**Core scheduling pick**: when ``CONFIG_SCHED_CORE`` is enabled and core scheduling picks a task for execution while it's still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_CORE_SCHED_EXEC`` flag.”h]”(j )�”}”(hŒ**Core scheduling pick**”h]”hŒCore scheduling pick”…”�”}”(hj; h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj7 ubhŒ: when ”…”�”}”(hj7 h²hh³Nh´Nubj¾)�”}”(hŒ``CONFIG_SCHED_CORE``”h]”hŒCONFIG_SCHED_CORE”…”�”}”(hjM h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj7 ubhŒ^ is enabled and core scheduling picks a task for execution while it’s still in BPF custody, ”…”�”}”(hj7 h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hj_ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj7 ubhŒ is called with the ”…”�”}”(hj7 h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DEQ_CORE_SCHED_EXEC``”h]”hŒSCX_DEQ_CORE_SCHED_EXEC”…”�”}”(hjq h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj7 ubhŒ flag.”…”�”}”(hj7 h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mrhj3 ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjæ ubhï)�”}”(hX.**Scheduling property change**: when a task property changes (via operations like ``sched_setaffinity()``, ``sched_setscheduler()``, priority changes, CPU migrations, etc.) while the task is still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_SCHED_CHANGE`` flag set in ``deq_flags``. ”h]”hÚ)�”}”(hX-**Scheduling property change**: when a task property changes (via operations like ``sched_setaffinity()``, ``sched_setscheduler()``, priority changes, CPU migrations, etc.) while the task is still in BPF custody, ``ops.dequeue()`` is called with the ``SCX_DEQ_SCHED_CHANGE`` flag set in ``deq_flags``.”h]”(j )�”}”(hŒ**Scheduling property change**”h]”hŒScheduling property change”…”�”}”(hj— h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj“ ubhŒ4: when a task property changes (via operations like ”…”�”}”(hj“ h²hh³Nh´Nubj¾)�”}”(hŒ``sched_setaffinity()``”h]”hŒsched_setaffinity()”…”�”}”(hj© h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ ubhŒ, ”…”�”}”(hj“ h²hh³Nh´Nubj¾)�”}”(hŒ``sched_setscheduler()``”h]”hŒsched_setscheduler()”…”�”}”(hj» h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ ubhŒR, priority changes, CPU migrations, etc.) while the task is still in BPF custody, ”…”�”•Ÿ }”(hj“ h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hjÍ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ ubhŒ is called with the ”…”�”}”(hj“ h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DEQ_SCHED_CHANGE``”h]”hŒSCX_DEQ_SCHED_CHANGE”…”�”}”(hjß h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ ubhŒ flag set in ”…”�”}”(hj“ h²hh³Nh´Nubj¾)�”}”(hŒ ``deq_flags``”h]”hŒ deq_flags”…”�”}”(hjñ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ ubhŒ.”…”�”}”(hj“ h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mwhj� ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjæ ubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ.”uh1jšhj ubhÚ)�”}”(hŒÐ**Important**: Once a task has left BPF custody (e.g., after being dispatched to a terminal DSQ), property changes will not trigger ``ops.dequeue()``, since the task is no longer managed by the BPF scheduler.”h]”(j )�”}”(hŒ **Important**”h]”hŒ Important”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubhŒw: Once a task has left BPF custody (e.g., after being dispatched to a terminal DSQ), property changes will not trigger ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hj0h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ;, since the task is no longer managed by the BPF scheduler.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M}hj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîhjœh²hh³hÃh´Nubhï)�”}”(hXÏWhen a CPU is ready to schedule, it first looks at its local DSQ. If empty, it then looks at the global DSQ. If there still isn't a task to run, ``ops.dispatch()`` is invoked which can use the following two functions to populate the local DSQ. * ``scx_bpf_dsq_insert()`` inserts a task to a DSQ. Any target DSQ can be used - ``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, ``SCX_DSQ_GLOBAL`` or a custom DSQ. While ``scx_bpf_dsq_insert()`` currently can't be called with BPF locks held, this is being worked on and will be supported. ``scx_bpf_dsq_insert()`` schedules insertion rather than performing them immediately. There can be up to ``ops.dispatch_max_batch`` pending tasks. * ``scx_bpf_dsq_move_to_local()`` moves a task from the specified non-local DSQ to the dispatching DSQ. This function cannot be called with any BPF locks held. ``scx_bpf_dsq_move_to_local()`` flushes the pending insertions tasks before trying to move from the specified DSQ. ”h]”(hÚ)�”}”(hŒóWhen a CPU is ready to schedule, it first looks at its local DSQ. If empty, it then looks at the global DSQ. If there still isn't a task to run, ``ops.dispatch()`` is invoked which can use the following two functions to populate the local DSQ.”h]”(hŒ“When a CPU is ready to schedule, it first looks at its local DSQ. If empty, it then looks at the global DSQ. If there still isn’t a task to run, ”…”�”}”(hjRh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hjZh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjRubhŒP is invoked which can use the following two functions to populate the local DSQ.”…”�”}”(hjRh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M‚hjNubhê)�”}”(hhh]”(hï)�”}”(hX²``scx_bpf_dsq_insert()`` inserts a task to a DSQ. Any target DSQ can be used - ``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, ``SCX_DSQ_GLOBAL`` or a custom DSQ. While ``scx_bpf_dsq_insert()`` currently can't be called with BPF locks held, this is being worked on and will be supported. ``scx_bpf_dsq_insert()`` schedules insertion rather than performing them immediately. There can be up to ``ops.dispatch_max_batch`` pending tasks. ”h]”hÚ)�”}”(hX±``scx_bpf_dsq_insert()`` inserts a task to a DSQ. Any target DSQ can be used - ``SCX_DSQ_LOCAL``, ``SCX_DSQ_LOCAL_ON | cpu``, ``SCX_DSQ_GLOBAL`` or a custom DSQ. While ``scx_bpf_dsq_insert()`` currently can't be called with BPF locks held, this is being worked on and will be supported. ``scx_bpf_dsq_insert()`` schedules insertion rather than performing them immediately. There can be up to ``ops.dispatch_max_batch`` pending tasks.”h]”(j¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hj}h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ7 inserts a task to a DSQ. Any target DSQ can be used - ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ, ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL_ON | cpu``”h]”hŒSCX_DSQ_LOCAL_ON | cpu”…”�”}”(hj¡h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ, ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_GLOBAL``”h]”hŒSCX_DSQ_GLOBAL”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ or a custom DSQ. While ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hjÅh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒa currently can’t be called with BPF locks held, this is being worked on and will be supported. ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hj×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒQ schedules insertion rather than performing them immediately. There can be up to ”…”�”}”(hjyh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch_max_batch``”h]”hŒops.dispatch_max_batch”…”�”}”(hjéh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjyubhŒ pending tasks.”…”�”}”(hjyh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M‡hjuubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjrubhï)�”}”(hX``scx_bpf_dsq_move_to_local()`` moves a task from the specified non-local DSQ to the dispatching DSQ. This function cannot be called with any BPF locks held. ``scx_bpf_dsq_move_to_local()`` flushes the pending insertions tasks before trying to move from the specified DSQ. ”h]”hÚ)�”}”(hX``scx_bpf_dsq_move_to_local()`` moves a task from the specified non-local DSQ to the dispatching DSQ. This function cannot be called with any BPF locks held. ``scx_bpf_dsq_move_to_local()`` flushes the pending insertions tasks before trying to move from the specified DSQ.”h]”(j¾)�”}”(hŒ``scx_bpf_dsq_move_to_local()``”h]”hŒscx_bpf_dsq_move_to_local()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj ubhŒ moves a task from the specified non-local DSQ to the dispatching DSQ. This function cannot be called with any BPF locks held. ”…”�”}”(hj h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_move_to_local()``”h]”hŒscx_bpf_dsq_move_to_local()”…”�”}”(hj!h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj ubhŒS flushes the pending insertions tasks before trying to move from the specified DSQ.”…”�”}”(hj h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M�hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjrubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´M‡hjNubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîhjœh²hh³Nh´Nubhï)�”}”(hX�After ``ops.dispatch()`` returns, if there are tasks in the local DSQ, the CPU runs the first one. If empty, the following steps are taken: * Try to move from the global DSQ. If successful, run the task. * If ``ops.dispatch()`` has dispatched any tasks, retry #3. * If the previous task is an SCX task and still runnable, keep executing it (see ``SCX_OPS_ENQ_LAST``). * Go idle. ”h]”(hÚ)�”}”(hŒ‹After ``ops.dispatch()`` returns, if there are tasks in the local DSQ, the CPU runs the first one. If empty, the following steps are taken:”h]”(hŒAfter ”…”�”}”(hjOh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hjWh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjOubhŒs returns, if there are tasks in the local DSQ, the CPU runs the first one. If empty, the following steps are taken:”…”�”}”(hjOh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M”hjKubhê)�”}”(hhh]”(hï)�”}”(hŒ>Try to move from the global DSQ. If successful, run the task. ”h]”hÚ)�”}”(hŒ=Try to move from the global DSQ. If successful, run the task.”h]”hŒ=Try to move from the global DSQ. If successful, run the task.”…”�”}”(hjvh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M—hjrubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjoubhï)�”}”(hŒ:If ``ops.dispatch()`` has dispatched any tasks, retry #3. ”h]”hÚ)�”}”(hŒ9If ``ops.dispatch()`` has dispatched any tasks, retry #3.”h]”(hŒIf ”…”�”}”(hjŽh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hj–h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjŽubhŒ$ has dispatched any tasks, retry #3.”…”�”}”(hjŽh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M™hjŠubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjoubhï)�”}”(hŒfIf the previous task is an SCX task and still runnable, keep executing it (see ``SCX_OPS_ENQ_LAST``). ”h]”hÚ)�”}”(hŒeIf the previous task is an SCX task and still runnable, keep executing it (see ``SCX_OPS_ENQ_LAST``).”h]”(hŒOIf the previous task is an SCX task and still runnable, keep executing it (see ”…”�”}”(hj¸h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_OPS_ENQ_LAST``”h]”hŒSCX_OPS_ENQ_LAST”…”�”}”(hjÀh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj¸ubhŒ).”…”�”}”(hj¸h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M›hj´ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjoubhï)�”}”(hŒ Go idle. ”h]”hÚ)�”}”(hŒGo idle.”h]”hŒGo idle.”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MžhjÞubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjoubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´M—hjKubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîhjœh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”jjjhjjuh1jšhj{h²hh³hÃh´MubhÚ)�”}”(hXONote that the BPF scheduler can always choose to dispatch tasks immediately in ``ops.enqueue()`` as illustrated in the above simple example. If only the built-in DSQs are used, there is no need to implement ``ops.dispatch()`` as a task is never queued on the BPF scheduler and both the local and global DSQs are executed automatically.”h]”(hŒONote that the BPF scheduler can always choose to dispatch tasks immediately in ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒo as illustrated in the above simple example. If only the built-in DSQs are used, there is no need to implement ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hj"h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒn as a task is never queued on the BPF scheduler and both the local and global DSQs are executed automatically.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M hj{h²hubhÚ)�”}”(hX�``scx_bpf_dsq_insert()`` inserts the task on the FIFO of the target DSQ. Use ``scx_bpf_dsq_insert_vtime()`` for the priority queue. Internal DSQs such as ``SCX_DSQ_LOCAL`` and ``SCX_DSQ_GLOBAL`` do not support priority-queue dispatching, and must be dispatched to with ``scx_bpf_dsq_insert()``. See the function documentation and usage in ``tools/sched_ext/scx_simple.bpf.c`` for more information.”h]”(j¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hj>h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒ5 inserts the task on the FIFO of the target DSQ. Use ”…”�”}”(hj:h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert_vtime()``”h]”hŒscx_bpf_dsq_insert_vtime()”…”�”}”(hjPh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒ/ for the priority queue. Internal DSQs such as ”…”�”}”(hj:h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_LOCAL``”h]”hŒ SCX_DSQ_LOCAL”…”�”}”(hjbh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒ and ”…”�”}”(hj:h²hh³Nh´Nubj¾)�”}”(hŒ``SCX_DSQ_GLOBAL``”h]”hŒSCX_DSQ_GLOBAL”…”�”}”(hjth²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒK do not support priority-queue dispatching, and must be dispatched to with ”…”�”}”(hj:h²hh³Nh´Nubj¾)�”}”(hŒ``scx_bpf_dsq_insert()``”h]”hŒscx_bpf_dsq_insert()”…”�”}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒ.. See the function documentation and usage in ”…”�”}”(hj:h²hh³Nh´Nubj¾)�”}”(hŒ$``tools/sched_ext/scx_simple.bpf.c``”h]”hŒ tools/sched_ext/scx_simple.bpf.c”…”�”}”(hj˜h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj:ubhŒ for more information.”…”�”}”(hj:h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M¦hj{h²hubeh}”(h]”Œscheduling-cycle”ah ]”h"]”Œscheduling cycle”ah$]”h&]”uh1hÄhjØh²hh³hÃh´MubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒTask Lifecycle”h]”hŒTask Lifecycle”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj¸h²hh³hÃh´M®ubhÚ)�”}”(hŒwThe following pseudo-code presents a rough overview of the entire lifecycle of a task managed by a sched_ext scheduler:”h]”hŒwThe following pseudo-code presents a rough overview of the entire lifecycle of a task managed by a sched_ext scheduler:”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M°hj¸h²hubjê)�”}”(hXUops.init_task(); /* A new task is created */ ops.enable(); /* Enable BPF scheduling for the task */ while (task in SCHED_EXT) { if (task can migrate) ops.select_cpu(); /* Called on wakeup (optimization) */ ops.runnable(); /* Task becomes ready to run */ while (task_is_runnable(task)) { if (task is not in a DSQ || task->scx.slice == 0) { ops.enqueue(); /* Task can be added to a DSQ */ /* Task property change (i.e., affinity, nice, etc.)? */ if (sched_change(task)) { ops.dequeue(); /* Exiting BPF scheduler custody */ ops.quiescent(); /* Property change callback, e.g. ops.set_weight() */ ops.runnable(); continue; } /* Any usable CPU becomes available */ ops.dispatch(); /* Task is moved to a local DSQ */ ops.dequeue(); /* Exiting BPF scheduler custody */ } ops.running(); /* Task starts running on its assigned CPU */ while (task_is_runnable(task) && task->scx.slice > 0) { ops.tick(); /* Called every 1/HZ seconds */ if (task->scx.slice == 0) ops.dispatch(); /* task->scx.slice can be refilled */ } ops.stopping(); /* Task stops running (time slice expires or wait) */ } ops.quiescent(); /* Task releases its assigned CPU (wait) */ } ops.disable(); /* Disable BPF scheduling for the task */ ops.exit_task(); /* Task is destroyed */”h]”hXUops.init_task(); /* A new task is created */ ops.enable(); /* Enable BPF scheduling for the task */ while (task in SCHED_EXT) { if (task can migrate) ops.select_cpu(); /* Called on wakeup (optimization) */ ops.runnable(); /* Task becomes ready to run */ while (task_is_runnable(task)) { if (task is not in a DSQ || task->scx.slice == 0) { ops.enqueue(); /* Task can be added to a DSQ */ /* Task property change (i.e., affinity, nice, etc.)? */ if (sched_change(task)) { ops.dequeue(); /* Exiting BPF scheduler custody */ ops.quiescent(); /* Property change callback, e.g. ops.set_weight() */ ops.runnable(); continue; } /* Any usable CPU becomes available */ ops.dispatch(); /* Task is moved to a local DSQ */ ops.dequeue(); /* Exiting BPF scheduler custody */ } ops.running(); /* Task starts running on its assigned CPU */ while (task_is_runnable(task) && task->scx.slice > 0) { ops.tick(); /* Called every 1/HZ seconds */ if (task->scx.slice == 0) ops.dispatch(); /* task->scx.slice can be refilled */ } ops.stopping(); /* Task stops running (time slice expires or wait) */ } ops.quiescent(); /* Task releases its assigned CPU (wait) */ } ops.disable(); /* Disable BPF scheduling for the task */ ops.exit_task(); /* Task is destroyed */”…”�”}”hj×sbah}”(h]”h ]”h"]”h$]”h&]”jùjújû‰jüj;jþ}”uh1jéh³hÃh´M³hj¸h²hubhÚ)�”}”(hŒuNote that the above pseudo-code does not cover all possible state transitions and edge cases, to name a few examples:”h]”hŒuNote that the above pseudo-code does not cover all possible state transitions and edge cases, to name a few examples:”…”�”}”(hjæh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Måhj¸h²hubhê)�”}”(hhh]”(hï)�”}”(hŒœ``ops.dispatch()`` may fail to move the task to a local DSQ due to a racing property change on that task, in which case ``ops.dispatch()`` will be retried. ”h]”hÚ)�”}”(hŒ›``ops.dispatch()`` may fail to move the task to a local DSQ due to a racing property change on that task, in which case ``ops.dispatch()`` will be retried.”h]”(j¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hjÿh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjûubhŒf may fail to move the task to a local DSQ due to a racing property change on that task, in which case ”…”�”}”(hjûh²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjûubhŒ will be retried.”…”�”}”(hjûh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mèhj÷ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjôh²hh³hÃh´Nubhï)�”}”(hŒµThe task may be direct-dispatched to a local DSQ from ``ops.enqueue()``, in which case ``ops.dispatch()`` and ``ops.dequeue()`` are skipped and we go straight to ``ops.running()``. ”h]”hÚ)�”}”(hŒ´The task may be direct-dispatched to a local DSQ from ``ops.enqueue()``, in which case ``ops.dispatch()`` and ``ops.dequeue()`` are skipped and we go straight to ``ops.running()``.”h]”(hŒ6The task may be direct-dispatched to a local DSQ from ”…”�”}”(hj3h²hh³Nh´Nubj¾)�”}”(hŒ``ops.enqueue()``”h]”hŒ ops.enqueue()”…”�”}”(hj;h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj3ubhŒ, in which case ”…”�”}”(hj3h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dispatch()``”h]”hŒops.dispatch()”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj3ubhŒ and ”…”�”}”(hj3h²hh³Nh´Nubj¾)�”}”(hŒ``ops.dequeue()``”h]”hŒ ops.dequeue()”…”�”}”(hj_h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj3ubhŒ# are skipped and we go straight to ”…”�”}”(hj3h²hh³Nh´Nubj¾)�”}”(hŒ``ops.running()``”h]”hŒ ops.running()”…”�”}”(hjqh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj3ubhŒ.”…”�”}”(hj3h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mìhj/ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjôh²hh³hÃh´Nubhï)�”}”(hXXProperty changes may occur at virtually any point during the task's lifecycle, not just when the task is queued and waiting to be dispatched. For example, changing a property of a running task will lead to the callback sequence ``ops.stopping()`` -> ``ops.quiescent()`` -> (property change callback) -> ``ops.runnable()`` -> ``ops.running()``. ”h]”hÚ)�”}”(hXWProperty changes may occur at virtually any point during the task's lifecycle, not just when the task is queued and waiting to be dispatched. For example, changing a property of a running task will lead to the callback sequence ``ops.stopping()`` -> ``ops.quiescent()`` -> (property change callback) -> ``ops.runnable()`` -> ``ops.running()``.”h]”(hŒæProperty changes may occur at virtually any point during the task’s lifecycle, not just when the task is queued and waiting to be dispatched. For example, changing a property of a running task will lead to the callback sequence ”…”�”}”(hj“h²hh³Nh´Nubj¾)�”}”(hŒ``ops.stopping()``”h]”hŒops.stopping()”…”�”}”(hj›h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ubhŒ -> ”…”�”}”(hj“h²hh³Nh´Nubj¾)�”}”(hŒ``ops.quiescent()``”h]”hŒops.quiescent()”…”�”}”(hj­h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ubhŒ" -> (property change callback) -> ”…”�”}”(hj“h²hh³Nh´Nubj¾)�”}”(hŒ``ops.runnable()``”h]”hŒops.runnable()”…”�”}”(hj¿h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ubhŒ -> ”…”�”}”hj“sbj¾)�”}”(hŒ``ops.running()``”h]”hŒ ops.running()”…”�”}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj“ubhŒ.”…”�”}”(hj“h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mðhj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjôh²hh³hÃh´Nubhï)�”}”(hŒ¼A sched_ext task can be preempted by a task from a higher-priority scheduling class, in which case it will exit the tick-dispatch loop even though it is runnable and has a non-zero slice. ”h]”hÚ)�”}”(hŒ»A sched_ext task can be preempted by a task from a higher-priority scheduling class, in which case it will exit the tick-dispatch loop even though it is runnable and has a non-zero slice.”h]”hŒ»A sched_ext task can be preempted by a task from a higher-priority scheduling class, in which case it will exit the tick-dispatch loop even though it is runnable and has a non-zero slice.”…”�”}”(hjóh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Möhjïubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjôh²hh³hÃh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´Mèhj¸h²hubhÚ)�”}”(hŒpSee the "Scheduling Cycle" section for a more detailed description of how a freshly woken up task gets on a CPU.”h]”hŒtSee the “Scheduling Cycleâ€� section for a more detailed description of how a freshly woken up task gets on a CPU.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Múhj¸h²hubeh}”(h]”Œtask-lifecycle”ah ]”h"]”Œtask lifecycle”ah$]”h&]”uh1hÄhjØh²hh³hÃh´M®ubeh}”(h]”Œ the-basics”ah ]”h"]”Œ the basics”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´K©ubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒ Where to Look”h]”hŒ Where to Look”…”�”}”(hj.h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhj+h²hh³hÃh´Mþubhê)�”}”(hhh]”(hï)�”}”(hŒ¬``include/linux/sched/ext.h`` defines the core data structures and constants, while the ops table (``struct sched_ext_ops``) is defined in ``kernel/sched/ext/internal.h``. ”h]”hÚ)�”}”(hŒ«``include/linux/sched/ext.h`` defines the core data structures and constants, while the ops table (``struct sched_ext_ops``) is defined in ``kernel/sched/ext/internal.h``.”h]”(j¾)�”}”(hŒ``include/linux/sched/ext.h``”h]”hŒinclude/linux/sched/ext.h”…”�”}”(hjGh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjCubhŒF defines the core data structures and constants, while the ops table (”…”�”}”(hjCh²hh³Nh´Nubj¾)�”}”(hŒ``struct sched_ext_ops``”h]”hŒstruct sched_ext_ops”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjCubhŒ) is defined in ”…”�”}”(hjCh²hh³Nh´Nubj¾)�”}”(hŒ``kernel/sched/ext/internal.h``”h]”hŒkernel/sched/ext/internal.h”…”�”}”(hjkh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjCubhŒ.”…”�”}”(hjCh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj?ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj<h²hh³hÃh´Nubhï)�”}”(hŒž``kernel/sched/ext/ext.c`` contains sched_ext core implementation and helpers. The functions prefixed with ``scx_bpf_`` can be called from the BPF scheduler. ”h]”hÚ)�”}”(hŒ�``kernel/sched/ext/ext.c`` contains sched_ext core implementation and helpers. The functions prefixed with ``scx_bpf_`` can be called from the BPF scheduler.”h]”(j¾)�”}”(hŒ``kernel/sched/ext/ext.c``”h]”hŒkernel/sched/ext/ext.c”…”�”}”(hj‘h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj�ubhŒQ contains sched_ext core implementation and helpers. The functions prefixed with ”…”�”}”(hj�h²hh³Nh´Nubj¾)�”}”(hŒ ``scx_bpf_``”h]”hŒscx_bpf_”…”�”}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj�ubhŒ& can be called from the BPF scheduler.”…”�”}”(hj�h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj‰ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj<h²hh³hÃh´Nubhï)�”}”(hŒM``kernel/sched/ext/idle.c`` contains the built-in idle CPU selection policy. ”h]”hÚ)�”}”(hŒL``kernel/sched/ext/idle.c`` contains the built-in idle CPU selection policy.”h]”(j¾)�”}”(hŒ``kernel/sched/ext/idle.c``”h]”hŒkernel/sched/ext/idle.c”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÅubhŒ1 contains the built-in idle CPU selection policy.”…”�”}”(hjÅh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjÁubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhj<h²hh³hÃh´Nubhï)�”}”(hX6``tools/sched_ext/`` hosts example BPF scheduler implementations. * ``scx_simple[.bpf].c``: Minimal global FIFO scheduler example using a custom DSQ. * ``scx_qmap[.bpf].c``: A multi-level FIFO scheduler supporting five levels of priority implemented with arena-backed doubly-linked lists. * ``scx_central[.bpf].c``: A central FIFO scheduler where all scheduling decisions are made on one CPU, demonstrating ``LOCAL_ON`` dispatching, tickless operation, and kthread preemption. * ``scx_cpu0[.bpf].c``: A scheduler that queues all tasks to a shared DSQ and only dispatches them on CPU0 in FIFO order. Useful for testing bypass behavior. * ``scx_flatcg[.bpf].c``: A flattened cgroup hierarchy scheduler implementing hierarchical weight-based cgroup CPU control by compounding each cgroup's share at every level into a single flat scheduling layer. * ``scx_pair[.bpf].c``: A core-scheduling example that always makes sibling CPU pairs execute tasks from the same CPU cgroup. * ``scx_sdt[.bpf].c``: A variation of ``scx_simple`` demonstrating BPF arena memory management for per-task data. * ``scx_userland[.bpf].c``: A minimal scheduler demonstrating user space scheduling. Tasks with CPU affinity are direct-dispatched in FIFO order; all others are scheduled in user space by a simple vruntime scheduler. ”h]”(hÚ)�”}”(hŒA``tools/sched_ext/`` hosts example BPF scheduler implementations.”h]”(j¾)�”}”(hŒ``tools/sched_ext/``”h]”hŒtools/sched_ext/”…”�”}”(hjïh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjëubhŒ- hosts example BPF scheduler implementations.”…”�”}”(hjëh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M hjçubhê)�”}”(hhh]”(hï)�”}”(hŒR``scx_simple[.bpf].c``: Minimal global FIFO scheduler example using a custom DSQ. ”h]”hÚ)�”}”(hŒQ``scx_simple[.bpf].c``: Minimal global FIFO scheduler example using a custom DSQ.”h]”(j¾)�”}”(hŒ``scx_simple[.bpf].c``”h]”hŒscx_simple[.bpf].c”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ;: Minimal global FIFO scheduler example using a custom DSQ.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒ‰``scx_qmap[.bpf].c``: A multi-level FIFO scheduler supporting five levels of priority implemented with arena-backed doubly-linked lists. ”h]”hÚ)�”}”(hŒˆ``scx_qmap[.bpf].c``: A multi-level FIFO scheduler supporting five levels of priority implemented with arena-backed doubly-linked lists.”h]”(j¾)�”}”(hŒ``scx_qmap[.bpf].c``”h]”hŒscx_qmap[.bpf].c”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj4ubhŒt: A multi-level FIFO scheduler supporting five levels of priority implemented with arena-backed doubly-linked lists.”…”�”}”(hj4h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj0ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒº``scx_central[.bpf].c``: A central FIFO scheduler where all scheduling decisions are made on one CPU, demonstrating ``LOCAL_ON`` dispatching, tickless operation, and kthread preemption. ”h]”hÚ)�”}”(hŒ¹``scx_central[.bpf].c``: A central FIFO scheduler where all scheduling decisions are made on one CPU, demonstrating ``LOCAL_ON`` dispatching, tickless operation, and kthread preemption.”h]”(j¾)�”}”(hŒ``scx_central[.bpf].c``”h]”hŒscx_central[.bpf].c”…”�”}”(hj^h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjZubhŒ]: A central FIFO scheduler where all scheduling decisions are made on one CPU, demonstrating ”…”�”}”(hjZh²hh³Nh´Nubj¾)�”}”(hŒ ``LOCAL_ON``”h]”hŒLOCAL_ON”…”�”}”(hjph²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjZubhŒ9 dispatching, tickless operation, and kthread preemption.”…”�”}”(hjZh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjVubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒœ``scx_cpu0[.bpf].c``: A scheduler that queues all tasks to a shared DSQ and only dispatches them on CPU0 in FIFO order. Useful for testing bypass behavior. ”h]”hÚ)�”}”(hŒ›``scx_cpu0[.bpf].c``: A scheduler that queues all tasks to a shared DSQ and only dispatches them on CPU0 in FIFO order. Useful for testing bypass behavior.”h]”(j¾)�”}”(hŒ``scx_cpu0[.bpf].c``”h]”hŒscx_cpu0[.bpf].c”…”�”}”(hj–h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj’ubhŒ‡: A scheduler that queues all tasks to a shared DSQ and only dispatches them on CPU0 in FIFO order. Useful for testing bypass behavior.”…”�”}”(hj’h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjŽubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒÐ``scx_flatcg[.bpf].c``: A flattened cgroup hierarchy scheduler implementing hierarchical weight-based cgroup CPU control by compounding each cgroup's share at every level into a single flat scheduling layer. ”h]”hÚ)�”}”(hŒÏ``scx_flatcg[.bpf].c``: A flattened cgroup hierarchy scheduler implementing hierarchical weight-based cgroup CPU control by compounding each cgroup's share at every level into a single flat scheduling layer.”h]”(j¾)�”}”(hŒ``scx_flatcg[.bpf].c``”h]”hŒscx_flatcg[.bpf].c”…”�”}”(hj¼h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj¸ubhŒ»: A flattened cgroup hierarchy scheduler implementing hierarchical weight-based cgroup CPU control by compounding each cgroup’s share at every level into a single flat scheduling layer.”…”�”}”(hj¸h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´Mhj´ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒ|``scx_pair[.bpf].c``: A core-scheduling example that always makes sibling CPU pairs execute tasks from the same CPU cgroup. ”h]”hÚ)�”}”(hŒ{``scx_pair[.bpf].c``: A core-scheduling example that always makes sibling CPU pairs execute tasks from the same CPU cgroup.”h]”(j¾)�”}”(hŒ``scx_pair[.bpf].c``”h]”hŒscx_pair[.bpf].c”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÞubhŒg: A core-scheduling example that always makes sibling CPU pairs execute tasks from the same CPU cgroup.”…”�”}”(hjÞh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MhjÚubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒp``scx_sdt[.bpf].c``: A variation of ``scx_simple`` demonstrating BPF arena memory management for per-task data. ”h]”hÚ)�”}”(hŒo``scx_sdt[.bpf].c``: A variation of ``scx_simple`` demonstrating BPF arena memory management for per-task data.”h]”(j¾)�”}”(hŒ``scx_sdt[.bpf].c``”h]”hŒscx_sdt[.bpf].c”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ: A variation of ”…”�”}”(hjh²hh³Nh´Nubj¾)�”}”(hŒ``scx_simple``”h]”hŒ scx_simple”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ= demonstrating BPF arena memory management for per-task data.”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M!hjubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubhï)�”}”(hŒ×``scx_userland[.bpf].c``: A minimal scheduler demonstrating user space scheduling. Tasks with CPU affinity are direct-dispatched in FIFO order; all others are scheduled in user space by a simple vruntime scheduler. ”h]”hÚ)�”}”(hŒÖ``scx_userland[.bpf].c``: A minimal scheduler demonstrating user space scheduling. Tasks with CPU affinity are direct-dispatched in FIFO order; all others are scheduled in user space by a simple vruntime scheduler.”h]”(j¾)�”}”(hŒ``scx_userland[.bpf].c``”h]”hŒscx_userland[.bpf].c”…”�”}”(hj@h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj<ubhŒ¾: A minimal scheduler demonstrating user space scheduling. Tasks with CPU affinity are direct-dispatched in FIFO order; all others are scheduled in user space by a simple vruntime scheduler.”…”�”}”(hj<h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M$hj8ubah}”(h]”h ]”h"]”h$]”h&]”uh1hîhjubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´M hjçubeh}”(h]”h ]”h"]”h$]”h&]”uh1hîhj<h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”j¦j§uh1héh³hÃh´Mhj+h²hubeh}”(h]”Œ where-to-look”ah ]”h"]”Œ where to look”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´MþubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒModule Parameters”h]”hŒModule Parameters”…”�”}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjxh²hh³hÃh´M)ubhÚ)�”}”(hX6sched_ext exposes two module parameters under the ``sched_ext.`` prefix that control bypass-mode behaviour. These knobs are primarily for debugging; there is usually no reason to change them during normal operation. They can be read and written at runtime (mode 0600) via ``/sys/module/sched_ext/parameters/``.”h]”(hŒ2sched_ext exposes two module parameters under the ”…”�”}”(hj‰h²hh³Nh´Nubj¾)�”}”(hŒ``sched_ext.``”h]”hŒ sched_ext.”…”�”}”(hj‘h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj‰ubhŒÐ prefix that control bypass-mode behaviour. These knobs are primarily for debugging; there is usually no reason to change them during normal operation. They can be read and written at runtime (mode 0600) via ”…”�”}”(hj‰h²hh³Nh´Nubj¾)�”}”(hŒ%``/sys/module/sched_ext/parameters/``”h]”hŒ!/sys/module/sched_ext/parameters/”…”�”}”(hj£h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj‰ubhŒ.”…”�”}”(hj‰h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M+hjxh²hubhŒdefinition_list”“”)�”}”(hhh]”(hŒdefinition_list_item”“”)�”}”(hŒÛ``sched_ext.slice_bypass_us`` (default: 5000 µs) The time slice assigned to all tasks when the scheduler is in bypass mode, i.e. during BPF scheduler load, unload, and error recovery. Valid range is 100 µs to 100 ms. ”h]”(hŒterm”“”)�”}”(hŒ1``sched_ext.slice_bypass_us`` (default: 5000 µs)”h]”(j¾)�”}”(hŒ``sched_ext.slice_bypass_us``”h]”hŒsched_ext.slice_bypass_us”…”�”}”(hjÌh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjÈubhŒ (default: 5000 µs)”…”�”}”(hjÈh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÆh³hÃh´M4hjÂubhŒ definition”“”)�”}”(hhh]”hÚ)�”}”(hŒ¨The time slice assigned to all tasks when the scheduler is in bypass mode, i.e. during BPF scheduler load, unload, and error recovery. Valid range is 100 µs to 100 ms.”h]”hŒ¨The time slice assigned to all tasks when the scheduler is in bypass mode, i.e. during BPF scheduler load, unload, and error recovery. Valid range is 100 µs to 100 ms.”…”�”}”(hjéh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M2hjæubah}”(h]”h ]”h"]”h$]”h&]”uh1jähjÂubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÀh³hÃh´M4hj½ubjÁ)�”}”(hŒÜ``sched_ext.bypass_lb_intv_us`` (default: 500000 µs) The interval at which the bypass-mode load balancer redistributes tasks across CPUs. Set to 0 to disable load balancing during bypass mode. Valid range is 0 to 10 s. ”h]”(jÇ)�”}”(hŒ5``sched_ext.bypass_lb_intv_us`` (default: 500000 µs)”h]”(j¾)�”}”(hŒ``sched_ext.bypass_lb_intv_us``”h]”hŒsched_ext.bypass_lb_intv_us”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hjubhŒ (default: 500000 µs)”…”�”}”(hjh²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÆh³hÃh´M9hjubjå)�”}”(hhh]”hÚ)�”}”(hŒ¥The interval at which the bypass-mode load balancer redistributes tasks across CPUs. Set to 0 to disable load balancing during bypass mode. Valid range is 0 to 10 s.”h]”hŒ¥The interval at which the bypass-mode load balancer redistributes tasks across CPUs. Set to 0 to disable load balancing during bypass mode. Valid range is 0 to 10 s.”…”�”}”(hj&h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M7hj#ubah}”(h]”h ]”h"]”h$]”h&]”uh1jähjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jÀh³hÃh´M9hj½h²hubeh}”(h]”h ]”h"]”h$]”h&]”uh1j»hjxh²hh³hÃh´Nubeh}”(h]”Œmodule-parameters”ah ]”h"]”Œmodule parameters”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´M)ubhÅ)�”}”(hhh]”(hÊ)�”}”(hŒABI Instability”h]”hŒABI Instability”…”�”}”(hjQh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÉhjNh²hh³hÃh´M<ubhÚ)�”}”(hXNThe APIs provided by sched_ext to BPF schedulers programs have no stability guarantees. This includes the ops table callbacks defined in ``kernel/sched/ext/internal.h`` and the constants defined in ``include/linux/sched/ext.h``, as well as the ``scx_bpf_`` kfuncs defined in ``kernel/sched/ext/ext.c`` and ``kernel/sched/ext/idle.c``.”h]”(hŒ‰The APIs provided by sched_ext to BPF schedulers programs have no stability guarantees. This includes the ops table callbacks defined in ”…”�”}”(hj_h²hh³Nh´Nubj¾)�”}”(hŒ``kernel/sched/ext/internal.h``”h]”hŒkernel/sched/ext/internal.h”…”�”}”(hjgh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj_ubhŒ and the constants defined in ”…”�”}”(hj_h²hh³Nh´Nubj¾)�”}”(hŒ``include/linux/sched/ext.h``”h]”hŒinclude/linux/sched/ext.h”…”�”}”(hjyh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj_ubhŒ, as well as the ”…”�”}”(hj_h²hh³Nh´Nubj¾)�”}”(hŒ ``scx_bpf_``”h]”hŒscx_bpf_”…”�”}”(hj‹h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj_ubhŒ kfuncs defined in ”…”�”}”(hj_h²hh³Nh´Nubj¾)�”}”(hŒ``kernel/sched/ext/ext.c``”h]”hŒkernel/sched/ext/ext.c”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj_ubhŒ and ”…”�”}”(hj_h²hh³Nh´Nubj¾)�”}”(hŒ``kernel/sched/ext/idle.c``”h]”hŒkernel/sched/ext/idle.c”…”�”}”(hj¯h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1j½hj_ubhŒ.”…”�”}”(hj_h²hh³Nh´Nubeh}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´M>hjNh²hubhÚ)�”}”(hŒ“While we will attempt to provide a relatively stable API surface when possible, they are subject to change without warning between kernel versions.”h]”hŒ“While we will attempt to provide a relatively stable API surface when possible, they are subject to change without warning between kernel versions.”…”�”}”(hjÇh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÙh³hÃh´MDhjNh²hubeh}”(h]”Œabi-instability”ah ]”h"]”Œabi instability”ah$]”h&]”uh1hÄhhÆh²hh³hÃh´M<ubeh}”(h]”(Œextensible-scheduler-class”hÂeh ]”h"]”(Œextensible scheduler class”Œ sched-ext”eh$]”h&]”uh1hÄhhh²hh³hÃh´KŒexpect_referenced_by_name”}”jãh·sŒexpect_referenced_by_id”}”hÂh·subeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÃuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hÉNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”Œentry”Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÃŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”hÂ]”h·asŒnameids”}”(jãhÂjâjßjÕjÒj(j%jÛjØjxjujµj²j jjujrjKjHjÚj×uŒ nametypes”}”(jãˆjâ‰jÕ‰j(‰jÛ‰jx‰jµ‰j ‰ju‰jK‰jÚ‰uh}”(hÂhÆjßhÆjÒj¨j%jØjØj=jujÞj²j{jj¸jrj+jHjxj×jNuŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”hŒsystem_message”“”)�”}”(hhh]”hÚ)�”}”(hhh]”hŒ/Hyperlink target "sched-ext" is not referenced.”…”�”}”hjwsbah}”(h]”h ]”h"]”h$]”h&]”uh1hÙhjtubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ŒINFO”Œsource”hÃŒline”Kuh1jrubaŒ transformer”NŒ include_log”]”Œ decoration”Nh²hub.