<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:base="en">
	<title>Changwoo Writes Code</title>
	<subtitle>Igalian blog.</subtitle>
	<link href="https://blogs.igalia.com/changwoo/feed/feed.xml" rel="self"/>
	<link href="https://blogs.igalia.com/changwoo/"/>
	<updated>2024-06-24T00:00:00Z</updated>
	<id>https://blogs.igalia.com/</id>
	<author>
		<name>Changwoo Min</name>
		<email>changwoo@igalia.com</email>
	</author>
	
	<entry>
		<title>sched_ext: scheduler architecture and interfaces (Part 2)</title>
		<link href="https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/"/>
		<updated>2024-06-24T00:00:00Z</updated>
		<id>https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/</id>
		<content type="html">&lt;p&gt;This is the second blog post about the sched_ext, a BPF-based extensible scheduler class. Just in case you didn’t read the first one, you can find it &lt;a href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;here&lt;/a&gt;. In this blog post, I briefly update what has been happening in sched_ext, then introduce the scheduler architecture and the sched_ext API. After reading this, you should have a good understanding of the sched_ext architecture and be ready to read the source code of any sched_ext schedulers. Let’s get started!&lt;/p&gt;
&lt;h2 id=&quot;now-it-is-happening&quot; tabindex=&quot;-1&quot;&gt;Now, it is happening! &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After a &lt;a href=&quot;https://lore.kernel.org/all/Zlit_RUFPparkS3h@slm.duckdns.org/&quot;&gt;long debate&lt;/a&gt; about the sched_ext patch, Linus finally &lt;a href=&quot;https://lore.kernel.org/all/CAHk-=wg8APE61e5Ddq5mwH55Eh0ZLDV4Tr+c6_gFS7g2AxnuHQ@mail.gmail.com/&quot;&gt;approved&lt;/a&gt; its inclusion in the 6.11 kernel. As of the time of this writing, the &lt;a href=&quot;https://lore.kernel.org/all/20240618212056.2833381-1-tj@kernel.org/&quot;&gt;V7 patch set&lt;/a&gt; has been posted to the mailing list. In addition, the developer and user communities around the sched_ext are expanding. More developers have been attending the weekly office hours. If you are interested in scheduler development, please join our &lt;a href=&quot;https://schedextworkspace.slack.com&quot;&gt;Slack channel&lt;/a&gt;. Also, many enthusiasts (especially from the &lt;a href=&quot;https://discord.gg/cachyos-862292009423470592&quot;&gt;CachyOS community&lt;/a&gt;) have been actively testing, benchmarking, and bug-reporting the sched_ext schedulers.&lt;/p&gt;
&lt;h2 id=&quot;where-to-start-developing-a-sched-ext-scheduler&quot; tabindex=&quot;-1&quot;&gt;Where to start developing a sched_ext scheduler? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As discussed in the first blog post, sched_ext is an extensible scheduler class, so more than one sched_ext-based scheduler exists (e.g., &lt;code&gt;scx_lavd&lt;/code&gt;, &lt;code&gt;scx_rusty&lt;/code&gt;, and &lt;code&gt;scx_rustland&lt;/code&gt;). To play with sched_ext schedulers, you should use a sched_ext-enabled kernel. There are three ways to get a sched_ext-enabled kernel:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You can install a Linux distribution that natively supports the sched_ext kernel by default. As of this writing, &lt;a href=&quot;https://cachyos.org/&quot;&gt;CachyOS&lt;/a&gt;—an Arch-based Linux distribution—supports the sched_ext enabled kernel and the BPF schedulers. This might be the most straightforward if you plan to set up a new machine. See this &lt;a href=&quot;https://wiki.cachyos.org/de/kernel/sched-ext/&quot;&gt;tutorial&lt;/a&gt;, which explains how to use sched_ext schedulers in CachyOS.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you plan to explore the sched_ext kernel as well, you can start with virtual machine. &lt;code&gt;virtme_ng&lt;/code&gt; is an excellent environment, which makes your VM-based kernel development seamless. See &lt;a href=&quot;https://arighi.blogspot.com/2024/04/getting-started-with-sched-ext.html&quot;&gt;Andrea’s blog post&lt;/a&gt; on &lt;code&gt;virtme_ng&lt;/code&gt; for more details.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you finally decide to run your own sched_ext kernel on your machine, you should build the kernel with proper config options. See the details in my &lt;a href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;first blog post&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, you are ready to hack. Congrats!&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-big-picture-of-linux-schedulers&quot; tabindex=&quot;-1&quot;&gt;Understanding the big picture of Linux schedulers &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before getting your hands dirty, let’s step back and see the big picture of the Linux scheduler first.&lt;/p&gt;
&lt;p&gt;The following diagram shows the architecture of Linux scheduler. As the figure illustrates, the Linux scheduler conceptually consists of two layers. &lt;strong&gt;The core kernel scheduler&lt;/strong&gt; (&lt;code&gt;core.c&lt;/code&gt;) defines the common behavior of all scheduling policies. For example, the core kernel scheduler defines what to do upon a timer interrupt (or scheduler tick). At the high level, it is analogous to the abstract base class for all schedulers in a C++ term.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Concrete scheduling policies&lt;/strong&gt; are defined on top of the core kernel scheduler. For example, Linux provides real-time scheduling policies (&lt;code&gt;rt.c&lt;/code&gt;) such as FIFO (First-In, First-Out, &lt;code&gt;SCHED_FIFO&lt;/code&gt;) and RR (Round Robin, &lt;code&gt;SCHED_RR&lt;/code&gt;). The fair scheduling policy (&lt;code&gt;SCHED_NORMAL&lt;/code&gt;, EEVDF: Earliest Eligible Virtual Deadline First) governs non-realtime regular tasks.&lt;/p&gt;
&lt;p&gt;This two-levels architecture allows one to write a new scheduling policy while reusing the logic of the core kernel scheduler. In Linux, such an architecture is called a &lt;strong&gt;scheduler class&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;                                                  +========================+
                                                  || User-space part of   ||
                                                  || your scheduler       ||
                                                  || (e.g., main.rs)      ||
                                                  +========================+
~~~~~~~~~~~~~~~~ &amp;lt;kernel space vs. user space boundary &amp;gt; ~~~~~~~~~~~~~~~~~~~
                                                  +========================+
                                                  || Your BPF scheduler   ||
                                                  || (e.g., main.bpf.c)   ||
                                                  +========================+
+-----------------------+ +---------------------+ +========================+
| Default scheduler     | | Real-time scheduler | || Sched_ext framework  ||
| (EEVDF)               | | (FIFO, RR)          | ||                      ||
| (kernel/sched/fair.c) | | (kernel/sched/rt.c) | || (kernel/sched/ext.c) ||
+-----------------------+ +---------------------+ +========================+
+--------------------------------------------------------------------------+
|   Core kernel scheduler                                                  |
|   (kernel/sched/core.c)                                                  |
+--------------------------------------------------------------------------+

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The sched_ext framework inside the kernel&lt;/strong&gt; (&lt;code&gt;ext.c&lt;/code&gt;) is defined on top of the core kernel scheduler like any other scheduler classes (e.g., &lt;code&gt;fair.c&lt;/code&gt; and &lt;code&gt;rt.c&lt;/code&gt;). That implies all the scheduler classes should communicate to the core kernel scheduler via the same interface; we will discuss that interface shortly.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The sched_ext framework is a vessel that ships a BPF scheduler with a user-defined policy.&lt;/em&gt; The sched_ext framework adds two more layers on top of it: &lt;strong&gt;a BPF scheduler layer&lt;/strong&gt; and &lt;strong&gt;a user-space process&lt;/strong&gt;, which interacts with the BPF scheduler. Writing a new sched_ext scheduler means writing a new BPF scheduler and its user-space counterpart.&lt;/p&gt;
&lt;h2 id=&quot;sharing-time-is-different-from-sharing-space&quot; tabindex=&quot;-1&quot;&gt;Sharing time is different from sharing space &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may notice that the idea of a &lt;em&gt;scheduler class&lt;/em&gt; is somewhat similar to the idea of a &lt;em&gt;VFS (Virtual File System)&lt;/em&gt; layer for file systems. Both define the common behavior of concrete policies (e.g., a new scheduling policy or file system layout) and the common interfaces for them.&lt;/p&gt;
&lt;p&gt;Yet, there is a key distinction. VFS, with its focus on &lt;em&gt;spatially partitioned disk space (or drive)&lt;/em&gt;, allows for the simultaneous existence of multiple file systems, as long as each manages disjoint disk (or drive) space.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; SCHED_FIFO =&amp;gt; SCHED_RR =&amp;gt; SCHED_NORMAL (either EEVDF or sched_ext)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In contrast, scheduling is about &lt;em&gt;how to slice and use CPU time&lt;/em&gt;, so at a certain point, &lt;em&gt;only one&lt;/em&gt; scheduling policy can make scheduling decisions. In that sense, the scheduler classes are hierarchical in using CPU time. Real-time schedulers will always take the CPU time first (&lt;code&gt;SCHED_FIFO&lt;/code&gt; =&amp;gt; &lt;code&gt;SCHED_RR&lt;/code&gt;). If no real-time task wants more CPU time, the schedulers for “normal” tasks (&lt;code&gt;SCHED_NORMAL&lt;/code&gt;) will take turns with the real-time schedulers. Since EEVDF and sched_ext are both defined as &lt;code&gt;SCHED_NORMAL&lt;/code&gt;, they cannot coexist at a certain point. When the sched_ext-based scheduler becomes active, it will take over all normal class tasks, replacing EEVDF.*&lt;/p&gt;
&lt;p&gt;(*Note that sched_ext provides a special mode for scheduling only a subset of normal class tasks, mainly for testing purposes. However, I won’t discuss it in this post for brevity of discussion.)&lt;/p&gt;
&lt;h2 id=&quot;interface-matters&quot; tabindex=&quot;-1&quot;&gt;Interface matters &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A sched_ext scheduler consists of four layers, as discussed from bottom to top: 1) core kernel scheduler, 2) sched_ext framework, 3) BPF scheduler, and 4) BPF’s user-space counterpart. These layers interact with each other through (relatively) well-defined interfaces. We now discuss those interfaces to understand how a scheduler works in action.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+========================+
|| User-space part of   ||
|| your scheduler       ||
|| (e.g., main.rs)      ||
+========================+
   &#92;&#92;//   ^^^^
   &#92;&#92;//   ^^^^ &amp;lt;== Interface 4: BPF scheduler &amp;lt;=&amp;gt; user-space counter part
   &#92;&#92;//   ^^^^
+========================+
|| Your BPF scheduler   ||
|| (e.g., main.bpf.c)   ||
+========================+
   ^^^^   &#92;&#92;// &amp;lt;== Interface 3: BPF scheduler =&amp;gt; sched_ext framework
   ^^^^   &#92;&#92;//
   ^^^^  &amp;lt;======== Interface 2: sched_ext framework =&amp;gt; BPF scheduler
+========================+
|| Sched_ext framework  ||
||                      ||
|| (kernel/sched/ext.c) ||
+========================+
          ^^^^
          ^^^^ &amp;lt;== Interface 1: core kernel scheduler =&amp;gt; scheduler class
          ^^^^
+------------------------+
| Core kernel scheduler  |
|  (kernel/sched/core.c) |
+------------------------+

&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;interface-1-core-kernel-scheduler-scheduler-class&quot; tabindex=&quot;-1&quot;&gt;Interface 1: core kernel scheduler ⇒ scheduler class &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The core kernel scheduler defines the common underlying behavior for scheduling and defines an interface for concrete scheduler classes (e.g., &lt;code&gt;SCHED_FIFO&lt;/code&gt;, &lt;code&gt;SCHED_NORMAL&lt;/code&gt;). It defines an &lt;code&gt;ops&lt;/code&gt; structure (&lt;code&gt;struct sched_class&lt;/code&gt;) – a &lt;code&gt;struct&lt;/code&gt; of function pointers – that needs to be filled by a concrete scheduler class to implement a concrete scheduling policy.&lt;/p&gt;
&lt;p&gt;In the Linux kernel, a task (thread or process) is represented by &lt;code&gt;struct task_struct&lt;/code&gt;, and a runnable (i.e., non-sleeping, ready-to-run) task should be in one of the run queues (&lt;code&gt;struct rq&lt;/code&gt;) associated with each CPU. Scheduling is the problem of treating runnable tasks through run queues.&lt;/p&gt;
&lt;p&gt;In a particular situation, when each scheduling policy needs its specific action, the core kernel scheduler calls an operation defined in &lt;code&gt;struct sched_class&lt;/code&gt;. For example, when the core kernel scheduler needs to select a task to be scheduled, it calls the &lt;code&gt;sched_class.pick_next_task(rq)&lt;/code&gt; callback of a concrete scheduling policy. When a task becomes runnable, the core kernel scheduler calls &lt;code&gt;sched_calss.enqueue(rq, p, flags)&lt;/code&gt; so the concrete scheduling policy enqueues task &lt;code&gt;p&lt;/code&gt; to run queue &lt;code&gt;rq&lt;/code&gt;. When a task’s runtime state needs to be updated, the core kernel scheduler calls &lt;code&gt;sched_calss.update_curr(rq)&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* kernel/sched/sched.h */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sched_class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;enqueue_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dequeue_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;yield_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;yield_to_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;wakeup_preempt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pick_next_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;put_prev_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;set_next_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool first&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;balance&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;prev&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                       &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq_flags&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rf&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;select_task_rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; task_cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pick_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;migrate_task_rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; new_cpu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task_woken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;set_cpus_allowed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                                    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;affinity_context&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq_online&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq_offline&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;find_lock_rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task_tick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; queued&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task_fork&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task_dead&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;switching_to&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;switched_from&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;switched_to&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;reweight_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;			      &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; newprio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;prio_changed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;this_rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;			      &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; oldprio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;get_rr_interval&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;					&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;update_curr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sched_ext kernel framework implements functions required in &lt;code&gt;struct sched_class&lt;/code&gt;. For example, when the core kernel scheduler enqueues a task or selects a next task to be scheduled or updates task’s runtime state, it eventually calls &lt;code&gt;enqueue_task_scx()&lt;/code&gt;, &lt;code&gt;pick_next_task_scx()&lt;/code&gt;, and  &lt;code&gt;update_curr_scx()&lt;/code&gt;, respectively, through &lt;code&gt;struct sched_class&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* kernel/sched/ext.c */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;DEFINE_SCHED_CLASS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enqueue_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; enqueue_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dequeue_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dequeue_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;yield_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; yield_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;yield_to_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; yield_to_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wakeup_preempt	&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wakeup_preempt_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pick_next_task	&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pick_next_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;put_prev_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; put_prev_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_next_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; set_next_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;CONFIG_SMP&lt;/span&gt;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;balance		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; balance_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;select_task_rq	&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; select_task_rq_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;set_cpus_allowed	&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; set_cpus_allowed_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rq_online		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rq_online_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rq_offline		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rq_offline_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;CONFIG_SCHED_CORE&lt;/span&gt;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pick_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pick_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;task_tick		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; task_tick_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;switching_to		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; switching_to_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;switched_from		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; switched_from_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;switched_to		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; switched_to_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reweight_task		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; reweight_task_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prio_changed		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prio_changed_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;update_curr		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; update_curr_scx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;CONFIG_UCLAMP_TASK&lt;/span&gt;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uclamp_enabled	&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sched_ext framework provides the common implementation for BPF schedulers. For example, when a task’s state needs to be updated, &lt;code&gt;update_curr_scx()&lt;/code&gt; in the sched_ext decrements the time slice of the currently running task.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;update_curr_scx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;curr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rq&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;curr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	u64 now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rq_clock_task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	u64 delta_exec&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	delta_exec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; curr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;se&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exec_start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;	curr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slice &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;curr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delta_exec&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;interface-2-sched-ext-framework-bpf-scheduler&quot; tabindex=&quot;-1&quot;&gt;Interface 2: sched_ext framework ⇒ BPF scheduler &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s think about another case of enqueuing a runnable task to a run queue. The core kernel scheduler will call &lt;code&gt;sched_class.enqueue_task()&lt;/code&gt;, actually &lt;code&gt;enqueue_task_scx()&lt;/code&gt; in the schd_ext framework. How should the &lt;code&gt;enqueue_task_scx()&lt;/code&gt; function be designed? The proper data structure and how tasks are organized in the queue depend on the BPF scheduler’s scheduling policy. For example, a FIFO queue would be the best data structure in the FIFO policy. In the deadline-based scheduling policy, it would be nice to maintain runnable tasks ordered by their deadlines. Any ordered map (e.g., &lt;a href=&quot;https://en.wikipedia.org/wiki/Red%E2%80%93black_tree&quot;&gt;red-black tree&lt;/a&gt;) would be appropriate.&lt;/p&gt;
&lt;p&gt;Now let’s briefly examine how sched_ext implements &lt;code&gt;enqueue_task_scx()&lt;/code&gt;. As the following code snippet shows, &lt;code&gt;enqueue_task_scx()&lt;/code&gt; eventually calls &lt;code&gt;scx_ops.enqueue(args)&lt;/code&gt;, which is an enqueue implementation of a BPF scheduler.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* kernel/sched/ext.c */&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;enqueue_task_scx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; sticky_cpu &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sticky_cpu&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	enq_flags &lt;span class=&quot;token operator&quot;&gt;|=&lt;/span&gt; rq&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extra_enq_flags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;do_enqueue_task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; enq_flags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sticky_cpu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;do_enqueue_task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;rq&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rq&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;			    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; sticky_cpu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;SCX_CALL_OP_TASK&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SCX_KF_ENQUEUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; enqueue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;SCX_CALL_OP_TASK&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;				&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;										&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;                                                            &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;SCX_CALL_OP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; task&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;##&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;					&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;                                                            &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;SCX_CALL_OP&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mask&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; args&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                       &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;										&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;                                                            &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token expression&quot;&gt;scx_ops&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                                    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;                                                            &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sched_ext framework defines an operation structure – &lt;code&gt;struct sched_ext_ops&lt;/code&gt;, where &lt;code&gt;scx_ops.enqueue()&lt;/code&gt; is defined. The following code snippet is a simplified version of &lt;code&gt;struct sched_ext_ops&lt;/code&gt;. The full version with API description can be found in the &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/edb95a6a6213b4460ea4de1a0efb18e3e59b97b0/kernel/sched/ext.c#L199&quot;&gt;source code&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* kernel/sched/ext.c */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sched_ext_ops&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;s32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;select_cpu&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s32 prev_cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 wake_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;enqueue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dispatch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s32 cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;prev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;tick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;runnable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;running&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;stopping&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool runnable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;quiescent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 deq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;update_idle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s32 cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool idle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;s32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;init_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;scx_init_task_args&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;exit_task&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;scx_exit_task_args&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;s32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;init&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;exit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;scx_exit_info&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;info&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sched_ext_ops&lt;/span&gt; scx_ops&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There seem to be a lot of callbacks in a BPF scheduler, but most of them are pretty straightforward.&lt;/p&gt;
&lt;p&gt;When a BPF scheduler is loaded and unloaded, you have control over it. The &lt;code&gt;sched_ext_ops.init()&lt;/code&gt; and &lt;code&gt;sched_ext_ops.exit()&lt;/code&gt; functions are your tools to initialize and de-initialize BPF scheduler-wide data structures. This is where you can create and destroy per-CPU structures and global run queues managed by the BPF scheduler.&lt;/p&gt;
&lt;p&gt;When a new task is created, &lt;code&gt;sched_ext_ops.init_task()&lt;/code&gt; is called. As you can expect, &lt;code&gt;sched_ext_ops.exit_task()&lt;/code&gt; is called when a task is terminated. You can manage per-task data structures there.&lt;/p&gt;
&lt;p&gt;During the lifetime, a task will become first runnable (&lt;code&gt;sched_ext_ops.runnable()&lt;/code&gt;), then it will be picked by the scheduler and will be running (&lt;code&gt;sched_ext_ops.running()&lt;/code&gt;). Then, when its time slice is exhausted, the task will be stopped and scheduled out (&lt;code&gt;sched_ext_ops.stopping()&lt;/code&gt;). The task becomes non-runnable (&lt;code&gt;sched_ext_ops.quiescent()&lt;/code&gt;), for example, when waiting for an IO event.&lt;/p&gt;
&lt;p&gt;When a task wakes up, for example, when an IO event is delivered, the BPF scheduler should first decide which CPU the task should run on (&lt;code&gt;sched_ext_ops.select_cpu()&lt;/code&gt;). Then, the task will be enqueued to a BPF-managed run queue (&lt;code&gt;sched_ext_ops.enqueue()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Each CPU will continue to execute the assigned tasks to it. When a CPU has nothing to run, it will get a task from the BPF-managed run queue (&lt;code&gt;sched_ext_ops.dispatch()&lt;/code&gt;). Even if there is no task to run on the BPF-managed run queue, the CPU will be idle to save power until there is something to run. The state transition from/to idle state can be tracked by &lt;code&gt;sched_ext_ops.update_idle()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Upon every scheduler tick (i.e., every 1/HZ seconds), &lt;code&gt;sched_ext_ops.tick()&lt;/code&gt; is called, so the BPF-scheduler can periodically do chores (e.g., power management, preemption, etc).&lt;/p&gt;
&lt;p&gt;That’s (almost) all! Writing a new BPF scheduler is nothing but implementing those &lt;code&gt;struct sched_ext_ops&lt;/code&gt; functions. Note that the sched_ext framework provides a default implementation of each callback, so when a callback implementation is not provided by the BPF scheduler, the default implementation will be executed. That’s straightforward, huh?&lt;/p&gt;
&lt;h3 id=&quot;interface-3-bpf-scheduler-sched-ext-framework&quot; tabindex=&quot;-1&quot;&gt;Interface 3: BPF scheduler ⇒ sched_ext framework &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A BPF scheduler needs to talk to the sched_ext kernel framework. For instance, after choosing a task to be run, it should be somehow notified to the sched_ext framework. There are two ways from a BPF scheduler to the sched_ext framework: 1) BPF helper function and 2) dispatch queue (DSQ). DSQ is also created and manipulated by the BPF helper functions. Here is a list of some essential BPF helper functions. A full list of BPF helper functions are &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/edb95a6a6213b4460ea4de1a0efb18e3e59b97b0/tools/sched_ext/include/scx/common.bpf.h#L31&quot;&gt;here&lt;/a&gt;, and their implementations with full API descriptions are &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/edb95a6a6213b4460ea4de1a0efb18e3e59b97b0/kernel/sched/ext.c#L5761&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* tools/shed_ext/include/scx/common.bpf.h */&lt;/span&gt;&lt;br&gt;s32 &lt;span class=&quot;token function&quot;&gt;scx_bpf_create_dsq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s32 node&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;s32 &lt;span class=&quot;token function&quot;&gt;scx_bpf_dsq_nr_queued&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; __ksym&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_bpf_destroy_dsq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; __ksym&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_bpf_dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                      u64 slice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_bpf_dispatch_vtime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 slice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                            u64 vtime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;bool &lt;span class=&quot;token function&quot;&gt;scx_bpf_consume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;u64 dsq_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;bool &lt;span class=&quot;token function&quot;&gt;scx_bpf_consume_task&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; it&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;s32 &lt;span class=&quot;token function&quot;&gt;scx_bpf_select_cpu_dfl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s32 prev_cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                           u64 wake_flags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;is_idle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_bpf_kick_cpu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s32 cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Dispatch queue (DSQ)&lt;/strong&gt; is a core construct between a BPF scheduler and the sched_ext kernel framework, so many BPF helper functions are around DSQ. DSQ is a queue holding runnable tasks. Tasks in a DSQ can be ordered by an arrival order (FIFO) or a &lt;code&gt;vtime&lt;/code&gt; (virtual time) order, where &lt;code&gt;vtime&lt;/code&gt; is an integer associated with a task. The sched_ext framework also creates and maintains its &lt;em&gt;internal DSQs&lt;/em&gt;: 1) one system-wide (named &lt;em&gt;global DSQ&lt;/em&gt;) and 2) one for each CPU (named &lt;em&gt;local DSQ&lt;/em&gt;). Both internal DSQs are FIFO-ordered. Each CPU in the sched_ext framework runs a task on its local DSQ in a FIFO order.&lt;/p&gt;
&lt;p&gt;A BPF scheduler can also create DSQs (either FIFO or &lt;code&gt;vtime&lt;/code&gt; DSQ) to manage runnable tasks in its own way (&lt;code&gt;scx_bpf_create_dsq()&lt;/code&gt;). &lt;code&gt;sched_ext_ops.init()&lt;/code&gt; is a typical place to create custom DSQs.&lt;/p&gt;
&lt;p&gt;A task can be enqueued to the DSQ in a FIFO order (&lt;code&gt;scx_bpf_dispatch()&lt;/code&gt;) or &lt;code&gt;vtime&lt;/code&gt; order (&lt;code&gt;scx_bpf_dispatch_vtime()&lt;/code&gt;), typically at &lt;code&gt;sched_ext_ops.enqueue()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A task in a DSQ can be consumed from tip (&lt;code&gt;scx_bpf_consume()&lt;/code&gt;) or a specified task can be consumed (&lt;code&gt;scx_bpf_consume_task()&lt;/code&gt;), typically at &lt;code&gt;sched_ext_ops.dispatch()&lt;/code&gt;. Here &lt;em&gt;consuming a task&lt;/em&gt; means that a task is removed from a custom DSQ and moved to the internal local DSQ, so a CPU can run a task in its locak DSQ.&lt;/p&gt;
&lt;p&gt;In addition, the number of tasks in a DSQ can be queried (&lt;code&gt;scx_bpf_dsq_nr_queued()&lt;/code&gt;). At the end, a DSQ should be destroyed (&lt;code&gt;scx_bpf_destroy_dsq()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Besides DSQ-related BPF helpers, two other helper functions are notable: &lt;code&gt;scx_bpf_select_cpu_dfl()&lt;/code&gt; and &lt;code&gt;scx_bpf_kick_cpu()&lt;/code&gt;. &lt;code&gt;scx_bpf_select_cpu_dfl()&lt;/code&gt; finds an appropriate CPU to run a task using default core selection policy. It can be used in &lt;code&gt;sched_ext_ops.select_cpu()&lt;/code&gt;. &lt;code&gt;scx_bpf_kick_cpu()&lt;/code&gt; sends an IPI (Inter-Processor Interrupt) signal to another CPU for waking up an idle CPU (&lt;code&gt;SCX_KICK_IDLE&lt;/code&gt; flag) and asking preempt out the currently running task (&lt;code&gt;SCX_KICK_PREEMPT&lt;/code&gt; flag).&lt;/p&gt;
&lt;h3 id=&quot;interface-4-bpf-scheduler-user-space-counterpart&quot; tabindex=&quot;-1&quot;&gt;Interface 4: BPF scheduler ⟺ user-space counterpart &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since the BPF scheduler is a regular BPF program, you can use any BPF tricks you like. A user-space program (typically written in C or Rust) can use any &lt;a href=&quot;https://libbpf.readthedocs.io/en/latest/libbpf_overview.html#&quot;&gt;&lt;code&gt;libbpf&lt;/code&gt; API&lt;/a&gt;. Most importantly, a BPF map is accessed and manipulated by a user-space program (e.g., &lt;code&gt;bpf_map_lookup_elem()&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;what-s-next&quot; tabindex=&quot;-1&quot;&gt;What’s next? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-scheduler-architecture-and-interfaces-part-2/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The best way to digest the sched_ext concept is to read the existing BPF scheduler code. I strongly encourage you to read the source code of one of &lt;code&gt;scx_lavd,&lt;/code&gt; &lt;code&gt;scx_rusty,&lt;/code&gt; or &lt;code&gt;scx_rustland&lt;/code&gt;. Then, you will have a solid foundation to write a new BPF scheduler or improve an existing one. In the next blog post, I will discuss how to find out what to improve as an author of the &lt;a href=&quot;https://github.com/sched-ext/scx/tree/main/scheds/rust/scx_lavd&quot;&gt;&lt;code&gt;scx_lavd&lt;/code&gt;&lt;/a&gt; scheduler. I hope you enjoyed this blog post.  Happy scheduling until the next blog post!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>sched_ext: a BPF-extensible scheduler class (Part 1)</title>
		<link href="https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/"/>
		<updated>2023-12-18T00:00:00Z</updated>
		<id>https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/</id>
		<content type="html">&lt;p&gt;This blog post introduces &lt;code&gt;sched_ext&lt;/code&gt;, a recently proposed extensible scheduler class. &lt;code&gt;sched_ext&lt;/code&gt; allows you to write and run your custom process scheduler optimized for your target workloads and hardware architectures using BPF programs. In the rest of the post, I recap the concept of a scheduler at the high level and go over the default schedulers in Linux kernel. Then, I introduce why an extensible scheduler framework, &lt;code&gt;sched_ext&lt;/code&gt;, is necessary, how to use it, and provide a BPF scheduler example.&lt;/p&gt;
&lt;h2 id=&quot;what-is-a-process-scheduler&quot; tabindex=&quot;-1&quot;&gt;What is a process scheduler? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A process scheduler is essential in any OS, including the Linux kernel. A scheduler multiplexes CPU time into multiple tasks – processes and threads. It essentially makes two decisions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task selection&lt;/strong&gt;: &lt;em&gt;Which task should be run next?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time slice&lt;/strong&gt;: &lt;em&gt;How long should the chosen next task be allowed to run?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a multi-core CPU, which is a norm today, a scheduler also makes one more decision:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Core selection&lt;/strong&gt;: &lt;em&gt;Which CPU core should be used for executing the chosen next task?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above three decisions often conflict each other. For example, a scheduler may assign a long time slice to reduce the context-switching overhead and take advantage of the warmed-up processor cache. However, a time slice that is too long may degrade the responsiveness of a system, hurting the interactive performance.&lt;/p&gt;
&lt;p&gt;Also, a scheduler may want to fully utilize multiple CPU cores, so it can assign a task to any idle CPU core. Such &lt;em&gt;work-conserving scheduling&lt;/em&gt; may increase overall CPU utilization, but higher CPU utilization does not always result in higher performance. When a task is too frequently migrated from one CPU to another CPU, the cache of the newly assigned CPU should be warmed up again so there is little chance to reuse the cache when the task is scheduled next, resulting in lower performance. The cache re-warming cost will be higher when a system has multiple cache domains, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Non-uniform_memory_access&quot;&gt;NUMA (Non-Uniform Memory Architecture)&lt;/a&gt; and &lt;a href=&quot;https://www.tomshardware.com/reviews/amd-ccx-definition-cpu-core-explained,6338.html&quot;&gt;AMD CCX (Core Complex)&lt;/a&gt; architectures.&lt;/p&gt;
&lt;h2 id=&quot;how-does-the-linux-scheduler-make-scheduling-decisions&quot; tabindex=&quot;-1&quot;&gt;How does the Linux scheduler make scheduling decisions? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;completely-fair-scheduler-cfs-scheduler&quot; tabindex=&quot;-1&quot;&gt;Completely Fair Scheduler (CFS) scheduler &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may wonder how the Linux scheduler makes scheduling decisions to meet such conflicting goals. The &lt;a href=&quot;https://en.wikipedia.org/wiki/Completely_Fair_Scheduler&quot;&gt;&lt;strong&gt;Completely Fair Scheduler (CFS)&lt;/strong&gt;&lt;/a&gt; has been the default scheduler for the last 15+ years since merged into the 2.6.23 kernel (October 2007). The core idea of CFS is simple (of course, the devil is in the details), but it works surprisingly well in many workloads. CFS manages the &lt;em&gt;virtual total execution time of a task&lt;/em&gt; –  &lt;strong&gt;vruntime&lt;/strong&gt;. The actual execution time of a task is adjusted based on the task’s static priority (i.e., nice value). CFS pursues the &lt;em&gt;complete fairness&lt;/em&gt; of tasks’ vruntime to equally distribute the CPU time to each task based on its priority. It always chooses a task with the smallest vruntime value for complete fair use of CPU time. CFS internally manages a run queue – a queue of runnable tasks – using a red-black tree indexed by each task’s vruntime. The red-black tree offers O(logN) time complexity in picking the next task where N is the number of runnable tasks. CFS handles IO-intensive tasks pretty well. The most IO-intensive tasks sleep most of the time, waiting for IO events, so their vruntime values tend to be small. Hence, whenever an IO event occurs and the IO-intensive task is wakened up and becomes runnable, CFS quickly chooses that task since it has a small vruntime value.&lt;/p&gt;
&lt;p&gt;However, CFS scheduler does not enforce any scheduling deadlines and has many &lt;em&gt;corner cases&lt;/em&gt; where a latency-critical task is not scheduled on time – such scheduling delay of latency-critical tasks results in high tail latency. For instance, &lt;a href=&quot;https://en.wikipedia.org/wiki/Wine_(software)&quot;&gt;Wine&lt;/a&gt; – a Windows-API emulation layer on Linux – has a &lt;code&gt;wineserver&lt;/code&gt; process. The &lt;code&gt;wineserver&lt;/code&gt; process is a single-threaded event router which relays Window events to other processes. It is super latency-critical, so scheduling delay of &lt;code&gt;wineserver&lt;/code&gt; triggers cascading delays of dependent tasks. However, CFS does not always schedule &lt;code&gt;wineserver&lt;/code&gt; immediately. Since &lt;code&gt;wineserver&lt;/code&gt; consumes a fair amount of CPU time as a central event rounter, its vruntime value would be pretty high so CFS won’t immediately pick the &lt;code&gt;wineserver&lt;/code&gt; task all the time.&lt;/p&gt;
&lt;h3 id=&quot;earliest-eligible-virtual-deadline-first-eevdf-scheduler&quot; tabindex=&quot;-1&quot;&gt;Earliest Eligible Virtual Deadline First (EEVDF) scheduler &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Due to such limitations, the CFS scheduler was recently retired after serving 15+ years. The &lt;a href=&quot;https://lwn.net/Articles/925371/&quot;&gt;&lt;strong&gt;Earliest Eligible Virtual Deadline First (EEVDF) scheduler&lt;/strong&gt;&lt;/a&gt; was introduced as a new default scheduler in the Linux kernel 6.6 release (November 2023).&lt;/p&gt;
&lt;p&gt;Like CFS, EEVDF pursues the fair use of CPU time among tasks. For this, EEVDF introduces two notions: &lt;strong&gt;eligibility&lt;/strong&gt; and &lt;strong&gt;lag&lt;/strong&gt; of a task. EEVDF manages how much CPU time should be allocated to a task adjusted by the task’s static (nice) priority. Task’s &lt;strong&gt;lag&lt;/strong&gt; is the gap between &lt;em&gt;the ideal CPU time&lt;/em&gt; and &lt;em&gt;the actual CPU time&lt;/em&gt; allocated to the task. The positive lag means less CPU time has been allocated. On the other hand, the negative lag means too much CPU time is allocated to the task, so scheduling such a task with a negative lag value violates the fair use of CPU time. With the EEVDF terms, tasks with only positive lag values are &lt;strong&gt;eligible&lt;/strong&gt; for the scheduling. EEVDF scheduler does not schedule an &lt;strong&gt;ineligible task&lt;/strong&gt;, which has a negative lag value, for fairness.&lt;/p&gt;
&lt;p&gt;Another essential concept in EEVDF is &lt;strong&gt;virtual deadline&lt;/strong&gt;. A virtual deadline is the time to finish executing the task’s requested time slice. It is calculated by adding the &lt;em&gt;task’s allocated time slice&lt;/em&gt;, and its heuristically estimated &lt;strong&gt;eligible time&lt;/strong&gt;, which is when a task may start to run. Conceptually, a task may start at the &lt;em&gt;eligible time&lt;/em&gt; and finish &lt;em&gt;its time slice&lt;/em&gt; at the &lt;em&gt;virtual deadline&lt;/em&gt;. EEVDF assumes the task’s time slice is given by setting a &lt;strong&gt;latency nice&lt;/strong&gt; value. The EEVDF scheduler always chooses &lt;em&gt;an eligible task with the earliest virtual deadline&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;EEVDF scheduler naturally handles latency-critical tasks unlike CFS. A latency-critical task has a small latency nice value, so it has a shorter time slice. Therefore, its virtual deadline is earlier than non-latency critical tasks with longer slices. Hence, suppose two tasks have the &lt;em&gt;same nice value&lt;/em&gt; with &lt;em&gt;different latency nice values&lt;/em&gt;. The latency-critical task will be scheduled more frequently with a shorter slice.&lt;/p&gt;
&lt;h2 id=&quot;one-size-does-not-fit-all-so-does-a-scheduler&quot; tabindex=&quot;-1&quot;&gt;One size does not fit all, so does a scheduler &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The upsteam schedulers, like CFS and EEVDF, aim to &lt;em&gt;generically&lt;/em&gt; work well for &lt;em&gt;most workloads&lt;/em&gt; (e.g., databases, games, micro-services) &lt;em&gt;on most hardware platforms&lt;/em&gt; (e.g., x86, ARM, NUMA, non-NUMA, CCX, etc.). It is not uncommon that one scheduler optimization works well in some workloads and shows pathological degradations in other workloads and hardware combinations. To avoid such performance regression bugs, the kernel community sets a high bar in changing the scheduler code.&lt;/p&gt;
&lt;p&gt;However, if you always run a particular set of workloads on a specific hardware, would it be best to use such &lt;em&gt;generic schedulers&lt;/em&gt;? In the real world, there are many such cases. For example, Linux-based gaming devices, like the &lt;a href=&quot;https://store.steampowered.com/steamdeck&quot;&gt;Steam Deck&lt;/a&gt;, usually run Windows-based games. Hyperscalars, like Google and Meta, standardize their servers to a few types (e.g., &lt;a href=&quot;https://www.opencompute.org/&quot;&gt;OCP&lt;/a&gt;) for maintenance and run a certain set of workloads in a cluster. Similarly, many other companies (e.g., Airbnb, eBay) run their own workloads on their own mini-datacenters.&lt;/p&gt;
&lt;p&gt;Adopting a custom scheduler for specific workload/hardware combinations would be more beneficial than using generic schedulers. However, implementing and maintaining custom schedulers is very painful. That is not only because replacing or customizing the in-kernel scheduler is challenging. But also, it is unlikely that a custom scheduling policy is upstreamed so that the custom scheduler will impose a heavy maintenance burden in the long term.&lt;/p&gt;
&lt;h2 id=&quot;here-comes-the-sched-ext-framework&quot; tabindex=&quot;-1&quot;&gt;Here comes the &lt;code&gt;sched_ext&lt;/code&gt; framework &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sched_ext&lt;/code&gt; was &lt;a href=&quot;https://lore.kernel.org/all/20231111024835.2164816-1-tj@kernel.org/&quot;&gt;proposed&lt;/a&gt; to address the problems mentioned above. It allows users to write a custom scheduling policy using &lt;a href=&quot;https://lwn.net/Articles/599755/&quot;&gt;BPF&lt;/a&gt; without modifying the kernel code. You don’t need to struggle to maintain the out-of-tree custom scheduler. In addition, BPF provides a safe kernel programming environment. In particular, the BPF verifier ensures that your custom scheduler has neither a memory bug nor an infinite loop. Also, if your custom scheduler misbehaves – like failing to schedule a task for too long (say 30 seconds), the kernel portion of &lt;code&gt;sched_ext&lt;/code&gt; kills your custom scheduler and falls back to the default kernel scheduler (CFS or EEVDF). Last but not least, you can update the BPF scheduler without reinstalling the kernel and rebooting a server. It is a charm in a large data center with hundreds of thousands of servers. Rebooting that many servers in a rolling manner easily takes several weeks.&lt;/p&gt;
&lt;p&gt;Obviously, &lt;code&gt;sched_ext&lt;/code&gt; is a safe and nice framework that allows for the rapid experimentation and deployment of various scheduling policies. In the long term, I believe providing such an environment will also positively affect the default scheduler’s improvement. Who knows that some scheduling policies battle-tested with &lt;code&gt;sched_ext&lt;/code&gt; have turned out beneficial to generic workloads (with some tweaks) so they can be re-implemented on the default scheduler?&lt;/p&gt;
&lt;h2 id=&quot;how-to-build-and-run-sched-ext&quot; tabindex=&quot;-1&quot;&gt;How to build and run &lt;code&gt;sched_ext&lt;/code&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Enough talking. Now, let’s get our hands dirty. As of this writing, &lt;a href=&quot;https://lore.kernel.org/all/20231111024835.2164816-1-tj@kernel.org/&quot;&gt;the fifth version of the &lt;code&gt;sched_ext&lt;/code&gt; patch&lt;/a&gt; set has been proposed. It still needs to be merged into the mainline kernel. Hence, you should apply the patch set to the kernel source or use the &lt;a href=&quot;https://github.com/sched-ext/sched_ext&quot;&gt;&lt;code&gt;sched_ext&lt;/code&gt; kernel code on GitHub&lt;/a&gt;. Either way, the following kernel configuration should be enabled to turn on &lt;code&gt;sched_ext&lt;/code&gt; and enable BPF. Make sure the following bits are included in your &lt;code&gt;.config&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# essential configs to enable sched_ext
CONFIG_BPF=y
CONFIG_SCHED_CLASS_EXT=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_PAHOLE_HAS_BTF_TAG=y
CONFIG_DEBUG_INFO_BTF=y

# useful debug features for sched_ext
CONFIG_DEBUG_INFO=y
CONFIG_SCHED_DEBUG=y
CONFIG_DEBUG_INFO_DWARF5=y
CONFIG_DEBUG_INFO_BTF_MODULES=y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the kernel configuration is done, you just follow your usual kernel compilation and installation procedure – one example is &lt;a href=&quot;https://forum.manjaro.org/t/howto-build-your-very-first-custom-kernel/47683&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After the kernel is compiled, it’s time to compile the BPF schedulers. The &lt;code&gt;sched_ext&lt;/code&gt; scheduler sources provide several BPF schedulers under &lt;code&gt;tools/sched_ext&lt;/code&gt;. BPF code should be compiled with clang/LLVM, so the following options should be added to the &lt;code&gt;make&lt;/code&gt; command. Note the &lt;code&gt;clang&lt;/code&gt; version should be 16 or higher to compile BPF code correctly.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; tools/sched_ext&lt;br&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; clang &lt;span class=&quot;token parameter variable&quot;&gt;--version&lt;/span&gt;    &lt;span class=&quot;token comment&quot;&gt;# check if clang version is 16 or higher&lt;/span&gt;&lt;br&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;CC&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;clang &lt;span class=&quot;token assign-left variable&quot;&gt;LLVM&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-j&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After rebooting with the &lt;code&gt;sched_ext&lt;/code&gt; kernel, let’s run any of the &lt;code&gt;sched_ext&lt;/code&gt; BPF schedulers.&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; tools/sched_ext/build/bin&lt;br&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; ./scx_simple  &lt;span class=&quot;token comment&quot;&gt;# a simple vruntime-based scheduler, like CFS&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;885&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;895&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;906&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yeah! Now the simple vruntime-based scheduler, &lt;code&gt;scx_simple&lt;/code&gt;, is up and running. The log message shows how many tasks are scheduled from the local or global dispatch queue (DSQ). For now, please consider DSQ as a run queue in &lt;code&gt;sched_ext&lt;/code&gt; holding runnable tasks. I will explain the concept of the dispatch queue in more detail in my next blog post. Stay tuned!&lt;/p&gt;
&lt;p&gt;While simple, &lt;code&gt;scx_simple&lt;/code&gt; performs better than the CFS scheduler under some workloads. You can check the status of &lt;code&gt;sched_ext&lt;/code&gt; from sysfs:&lt;/p&gt;
&lt;pre class=&quot;language-sh&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;$&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /sys/kernel/debug/sched/ext&lt;br&gt;ops                           &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; simple&lt;br&gt;enabled                       &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br&gt;switching_all                 &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br&gt;switched_all                  &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br&gt;enable_state                  &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; enabled&lt;br&gt;nr_rejected                   &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the BPF scheduler prints out some messages (using, for example, &lt;code&gt;bpf_printk()&lt;/code&gt;), you can check the message at &lt;code&gt;/sys/kernel/debug/tracing/trace_pipe&lt;/code&gt; as in any other BPF programs.&lt;/p&gt;
&lt;p&gt;By the way, if you are lucky enough to use Arch Linux or Ubuntu Linux (24.04 NobleNumbat), you can install a &lt;code&gt;sched_ext&lt;/code&gt;-enabled kernel and the necessary tools from package repositories. Please find the detailed instructions to install the &lt;code&gt;sched_ext&lt;/code&gt; packages in Arch or Ubuntu Linux &lt;a href=&quot;https://github.com/sched-ext/scx&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-s-inside-scx-simple&quot; tabindex=&quot;-1&quot;&gt;What’s inside &lt;code&gt;scx_simple&lt;/code&gt;? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s take a look the source code of &lt;code&gt;scx_simple&lt;/code&gt;. The &lt;code&gt;scx_simple&lt;/code&gt; scheduler has two files: &lt;code&gt;scx_simple.c&lt;/code&gt; and &lt;code&gt;scx_simple.bpf.c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;scx_simple.c&lt;/code&gt; opens and load the BPF scheduler (&lt;code&gt;scx_simple__open()&lt;/code&gt; and &lt;code&gt;scx_simple__load()&lt;/code&gt;). Then it enables the operations provided by the BPF scheduler (&lt;code&gt;bpf_map__attach_struct_ops(skel-&amp;gt;maps.simple_ops)&lt;/code&gt;). Once the BPF scheduler operations are enabled – the BPF scheduling policy is enabled, it periodically reads and prints the status.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;argv&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;	skel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_simple__open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;SCX_BUG_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;skel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Failed to open skel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;SCX_BUG_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scx_simple__load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Failed to load skel&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	link &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bpf_map__attach_struct_ops&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skel&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;maps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;simple_ops&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;SCX_BUG_ON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Failed to attach struct_ops&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;exit_req &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;uei_exited&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;skel&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;bss&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;uei&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;		__u64 stats&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;read_stats&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skel&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;local=%llu global=%llu&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stats&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;fflush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;bpf_link__destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;link&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;uei_print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;skel&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;bss&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;uei&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;scx_simple__destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sched_ext&lt;/code&gt; defines a &lt;code&gt;struct&lt;/code&gt; of callback functions, &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/sched_ext/include/linux/sched/ext.h#L172&quot;&gt;&lt;code&gt;struct sched_ext_ops&lt;/code&gt;&lt;/a&gt; defined at &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/sched_ext/include/linux/sched/ext.h&quot;&gt;&lt;code&gt;include/linux/sched/ext.h&lt;/code&gt;&lt;/a&gt;. A BPF scheduler, &lt;code&gt;scx_simple.bpf.c&lt;/code&gt;, implements those callback functions, which will be called in various situations by the in-kernel portion of &lt;code&gt;sched_ext&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token function&quot;&gt;SEC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.struct_ops.link&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;sched_ext_ops&lt;/span&gt; simple_ops &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enqueue		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_enqueue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dispatch		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_dispatch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;running		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_running&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stopping		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_stopping&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;enable			&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_enable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;init			&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_init&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exit			&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;simple_exit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name			&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;simple&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the BPF scheduler is initialized, an &lt;code&gt;init()&lt;/code&gt; callback will be called. &lt;code&gt;simple_init ()&lt;/code&gt; changes all tasks (governed by the default CFS/EEVDF scheduler) to be under the control of &lt;code&gt;scx_simple&lt;/code&gt; (&lt;code&gt;scx_bpf_switch_all()&lt;/code&gt;) if a command line option is specified (&lt;code&gt;!switch_partial&lt;/code&gt;). Then it creates a centralized task queue (&lt;code&gt;scx_bpf_create_dsq(SHARED_DSQ, -1)&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;s32 &lt;span class=&quot;token function&quot;&gt;BPF_STRUCT_OPS_SLEEPABLE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simple_init&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;switch_partial&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;scx_bpf_switch_all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scx_bpf_create_dsq&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SHARED_DSQ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a task starts to be controlled by &lt;code&gt;sched_ext&lt;/code&gt; (for instance, after &lt;code&gt;fork()&lt;/code&gt;, &lt;code&gt;clone()&lt;/code&gt;, &lt;code&gt;scx_bpf_switch_all()&lt;/code&gt;), an &lt;code&gt;enable()&lt;/code&gt; callback will be called. It is the best time to initialize per-task information. &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/sched_ext/include/linux/sched/ext.h#L645&quot;&gt;&lt;code&gt;struct sched_ext_entity&lt;/code&gt;&lt;/a&gt; is defined to store &lt;code&gt;sched_ext&lt;/code&gt;-specific scheduling information, such as time slice (&lt;code&gt;slice&lt;/code&gt;) and task’s virtual time (&lt;code&gt;dsq_vtime&lt;/code&gt;), and it is added to &lt;a href=&quot;https://github.com/sched-ext/sched_ext/blob/sched_ext/include/linux/sched.h#L801&quot;&gt;&lt;code&gt;struct task_struct&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;p-&amp;gt;scx&lt;/code&gt;). &lt;code&gt;simple_enable()&lt;/code&gt; simply initializes the task’s virtual time to the current time (&lt;code&gt;p-&amp;gt;scx.dsq_vtime = vtime_now&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BPF_STRUCT_OPS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simple_enable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;		    &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;scx_enable_args&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dsq_vtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vtime_now&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a task &lt;code&gt;p&lt;/code&gt; becomes ready to run, the &lt;code&gt;enqueue()&lt;/code&gt; callback is called. &lt;code&gt;simple_enqueue()&lt;/code&gt; dispatches a task to either the local or global dispatch queue (DSQ) (&lt;code&gt;SCX_DSQ_LOCAL&lt;/code&gt; vs. &lt;code&gt;SHARED_DSQ&lt;/code&gt; in&lt;code&gt;scx_bpf_dispatch()&lt;/code&gt;) for execution depending on its flag (&lt;code&gt;enq_flag&lt;/code&gt;) set by the underlying &lt;code&gt;sched_ext&lt;/code&gt; framework. The local dispatch queue (&lt;code&gt;SCX_DSQ_LOCAL&lt;/code&gt;) is a kind of staging area waiting for execution, so the underlying &lt;code&gt;sched_ext&lt;/code&gt; framework fetches a task from the per-CPU local DSQ and schedules that task to run on a CPU. &lt;code&gt;simple_enqueue()&lt;/code&gt; manages tasks on the local DSQ in a FIFO order (&lt;code&gt;scx_bpf_dispatch()&lt;/code&gt;) but tasks on the global DSQ in a vtime order (&lt;code&gt;scx_bpf_dispatch_vtime()&lt;/code&gt;). When dispatching a task to a DSQ, the time slice of a task is set as an argument of &lt;code&gt;scx_bpf_dispatch()&lt;/code&gt;. &lt;code&gt;scx_simple&lt;/code&gt; sets the time slice to the default value, SCX_SLICE_DFL (20 msec).&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BPF_STRUCT_OPS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simple_enqueue&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; u64 enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/*&lt;br&gt;	 * If scx_select_cpu_dfl() is setting %SCX_ENQ_LOCAL, it indicates that&lt;br&gt;	 * running @p on its CPU directly shouldn&#39;t affect fairness. Just queue&lt;br&gt;	 * it on the local FIFO.&lt;br&gt;	 */&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;enq_flags &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; SCX_ENQ_LOCAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;stat_inc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;token comment&quot;&gt;/* count local queueing */&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;scx_bpf_dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SCX_DSQ_LOCAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SCX_SLICE_DFL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;stat_inc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	&lt;span class=&quot;token comment&quot;&gt;/* count global queueing */&lt;/span&gt;&lt;br&gt;&lt;br&gt;	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fifo_sched&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;scx_bpf_dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SHARED_DSQ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SCX_SLICE_DFL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;		u64 vtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dsq_vtime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;		&lt;span class=&quot;token comment&quot;&gt;/*&lt;br&gt;		 * Limit the amount of budget that an idling task can accumulate&lt;br&gt;		 * to one slice.&lt;br&gt;		 */&lt;/span&gt;&lt;br&gt;		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;vtime_before&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vtime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vtime_now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; SCX_SLICE_DFL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;			vtime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vtime_now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; SCX_SLICE_DFL&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;		&lt;span class=&quot;token function&quot;&gt;scx_bpf_dispatch_vtime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SHARED_DSQ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SCX_SLICE_DFL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vtime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;				       enq_flags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a task &lt;code&gt;p&lt;/code&gt; gets scheduled out, the &lt;code&gt;stopping()&lt;/code&gt; callback is called. &lt;code&gt;simple_stopping()&lt;/code&gt; accumulates the consumed time slice so far (&lt;code&gt;SCX_SLICE_DFL - p-&amp;gt;scx.slice&lt;/code&gt;) to the task’s vtime (&lt;code&gt;p-&amp;gt;scx.dsq_vtime&lt;/code&gt;) based on its nice priority (&lt;code&gt;p-&amp;gt;scx.weight&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BPF_STRUCT_OPS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simple_stopping&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bool runnable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token comment&quot;&gt;/*&lt;br&gt;	 * Scale the execution time by the inverse of the weight and charge.&lt;br&gt;	 *&lt;br&gt;	 * Note that the default yield implementation yields by setting&lt;br&gt;	 * @p-&gt;scx.slice to zero and the following would treat the yielding task&lt;br&gt;	 * as if it has consumed all its slice. If this penalizes yielding tasks&lt;br&gt;	 * too much, determine the execution time by taking explicit timestamps&lt;br&gt;	 * instead of depending on @p-&gt;scx.slice.&lt;br&gt;	 */&lt;/span&gt;&lt;br&gt;	p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dsq_vtime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SCX_SLICE_DFL &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;slice&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;weight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When a per-CPU local DSQ becomes empty, there is no task to run on a CPU. In this case, the &lt;code&gt;dispatch()&lt;/code&gt; callback is called. &lt;code&gt;simple_dispatch()&lt;/code&gt; moves a task from the global DSQ to a local DSQ (&lt;code&gt;scx_bpf_consume(SHARED_DSQ)&lt;/code&gt;) for execution. Since the global DSQ is ordered by vtime (&lt;code&gt;scx_bpf_dispatch_vtime(p, SHARED_DSQ, ...)&lt;/code&gt;), &lt;code&gt;scx_simple&lt;/code&gt; picks a task with the smallest vtime, which consumed the least amount of CPU time so far, and it moves the task to the local DSQ for the execution.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BPF_STRUCT_OPS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;simple_dispatch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s32 cpu&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;task_struct&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;prev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token function&quot;&gt;scx_bpf_consume&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SHARED_DSQ&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-s-next&quot; tabindex=&quot;-1&quot;&gt;What’s next? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/changwoo/sched-ext-a-bpf-extensible-scheduler-class-part-1/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far, I have introduced the concept of process scheduler, and the key idea of the default scheduler in Linux (CFS and EEVDF). Then, I shared the motivation of &lt;code&gt;sched_ext&lt;/code&gt; framework and how to run on your machine. Finally, I skimmed through how a BPF scheduler is organized. In the next blog post, I will dive into what’s going on under the hood. Please stay tuned!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>This is a post with no description</title>
		<link href="https://blogs.igalia.com/changwoo/this-is-a-post-with-no-description/"/>
		<updated>2023-10-06T00:00:00Z</updated>
		<id>https://blogs.igalia.com/changwoo/this-is-a-post-with-no-description/</id>
		<content type="html">&lt;p&gt;When the post has not &lt;code&gt;description:&lt;/code&gt; field, this first paragraph is the &lt;strong&gt;excerpt&lt;/strong&gt; but we want it to be rendered using &lt;em&gt;markdown&lt;/em&gt;.
The rest of the post content is not relevant for this particular case.&lt;/p&gt;
</content>
	</entry>
</feed>
