<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ian Chen</title>
    <description>The latest articles on DEV Community by Ian Chen (@ianchen0119).</description>
    <link>https://dev.to/ianchen0119</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3575889%2F9b7a73ce-76c4-4589-9c39-ce1ba93207a7.jpeg</url>
      <title>DEV Community: Ian Chen</title>
      <link>https://dev.to/ianchen0119</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ianchen0119"/>
    <language>en</language>
    <item>
      <title>Improving Network Performance with Custom eBPF-based Schedulers</title>
      <dc:creator>Ian Chen</dc:creator>
      <pubDate>Mon, 20 Oct 2025 16:46:42 +0000</pubDate>
      <link>https://dev.to/ianchen0119/improving-network-performance-with-custom-ebpf-based-schedulers-2akc</link>
      <guid>https://dev.to/ianchen0119/improving-network-performance-with-custom-ebpf-based-schedulers-2akc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Author: &lt;a href="https://www.linkedin.com/in/ian-chen-88b70b1aa/" rel="noopener noreferrer"&gt;Ian Chen&lt;/a&gt;&lt;br&gt;
If you’re interested, feel free to ⭐ the repo (aiming for CNCF Landscape recognition — the maintainers are happy to accept the project, but it needs at least 300 ⭐), try it out, share feedback, or even contribute together!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Linux Kernel has supported sched_ext since v6.12, which allows users to define custom CPU schedulers through eBPF programs. This feature enables developers to create more flexible and efficient scheduling strategies to meet specific performance requirements.&lt;/p&gt;

&lt;p&gt;The author was deeply inspired by the scx project and, referring to the concept of &lt;a href="https://github.com/sched-ext/scx/tree/main/scheds/rust/scx_rustland" rel="noopener noreferrer"&gt;scx_rustland&lt;/a&gt;, implemented a framework &lt;a href="https://github.com/Gthulhu/scx_goland_core" rel="noopener noreferrer"&gt;scx_goland_core&lt;/a&gt; that allows developers to write custom schedulers using the Go language.&lt;/p&gt;

&lt;h2&gt;
  
  
  Potential Integration of scx with 5G Domain
&lt;/h2&gt;

&lt;p&gt;Regarding the combination of 5G and scx, there has been some discussion &lt;a href="https://free5gc.org/blog/20250305/20250305/" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; &lt;a href="https://free5gc.org/blog/20250509/20250509/" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; &lt;a href="https://lwn.net/Articles/1027096/" rel="noopener noreferrer"&gt;[3]&lt;/a&gt;. However, considering the characteristics of modern Cloud-Native Apps (5G Core Network), there are currently no related cases exploring how scx operates on cloud-native architectures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ktm7f2d3fn0h2aiebcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ktm7f2d3fn0h2aiebcw.png" alt="alt text" width="767" height="272"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1: API Architecture&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In response, the author proposes an initial idea and developed a custom scheduler &lt;a href="https://gthulhu.github.io/docs/" rel="noopener noreferrer"&gt;Gthulhu&lt;/a&gt; based on the scx_goland_core framework that can run in cloud-native environments. It can be deployed in Kubernetes clusters and manage scheduling policies for numerous nodes in the cluster through deployment.&lt;/p&gt;

&lt;p&gt;We can issue scheduling policies to the Gthulhu API server through RESTful APIs, allowing the API server to identify workloads that need adjustment. Meanwhile, Gthulhu periodically sends heartbeat messages to the API server and updates scheduling policies when necessary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For detailed information about Gthulhu, please refer to &lt;a href="https://gthulhu.github.io/docs/how-it-works.en/" rel="noopener noreferrer"&gt;Gthulhu Docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  First Trial: Observing Data Plane Performance Differences After Loading Gthulhu
&lt;/h2&gt;

&lt;p&gt;In this experiment, the author's machine runs on Ubuntu 24.04 LTS with Linux Kernel 6.12. The experiment aims to observe the impact of Gthulhu on data plane performance after loading.&lt;/p&gt;

&lt;p&gt;The test environment is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VM1 (Ubuntu 24.04 LTS, Linux Kernel 6.12)

&lt;ul&gt;
&lt;li&gt;Deploy free5GC v4.0.1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;VM2 (Ubuntu 20.04 LTS, Linux Kernel 5.4.0)

&lt;ul&gt;
&lt;li&gt;Deploy UERANSIM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5842anas1a9ln726dk8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5842anas1a9ln726dk8v.png" alt="alt text" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After establishing the PDU Session, the author used the &lt;code&gt;ping&lt;/code&gt; tool to test the UPF N6 interface and observed latency changes before and after loading Gthulhu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdshddi4rh86sw10czz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdshddi4rh86sw10czz1.png" alt="alt text" width="560" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before loading, Linux's default scheduler was EEVDF, with RTT parameters as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rtt min = 1.263 ms&lt;/li&gt;
&lt;li&gt;rtt avg = 1.907 ms&lt;/li&gt;
&lt;li&gt;rtt max = 6.405 ms&lt;/li&gt;
&lt;li&gt;rtt mdev = 0.657 ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After loading Gthulhu, the RTT parameters changed as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rtt min = 1.222 ms&lt;/li&gt;
&lt;li&gt;rtt avg = 1.864 ms&lt;/li&gt;
&lt;li&gt;rtt max = 3.771 ms&lt;/li&gt;
&lt;li&gt;rtt mdev = 0.433 ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From these results, we can see that after loading Gthulhu, both the average and maximum RTT values decreased, indicating that Gthulhu indeed helps reduce latency in data plane scheduling.&lt;/p&gt;
&lt;h2&gt;
  
  
  Optimizing GTP5G Scheduling
&lt;/h2&gt;

&lt;p&gt;Based on the previous experimental results, we can see that without any scheduler adjustments, Gthulhu effectively reduces RTT performance. So, can we leverage knowledge of the network subsystem combined with Gthulhu to further optimize GTP5G?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!Note]&lt;br&gt;
Experimental environment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5GC on kubernetes&lt;/li&gt;
&lt;li&gt;N3/N6 use &lt;a href="https://github.com/k8snetworkplumbingwg/multus-cni" rel="noopener noreferrer"&gt;Multus CNI&lt;/a&gt; to create macvlan interfaces (N6 bound to enp7s0, N3 interface bound to dummy interface)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Observing Which CPU Handles Downlink Processing
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep enp7s0 /proc/interrupts

 159:     116096     131508     763166     532207    4697697    3924514   24589811    5660340   29315073   11862910   25971964    8494127    1935719    2420802    5149765     948266    6835920    2126158    1825640    1044404  IR-PCI-MSIX-0000:07:00.0    0-edge      enp7s0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;From the command above, we can see that enp7s0 corresponds to IRQ 159. Next, using &lt;code&gt;cat /proc/irq/${IRQ}/smp_affinity_list&lt;/code&gt;, we can determine which CPU IRQ 159 is bound to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /proc/irq/159/smp_affinity_list
11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When enp7s0 receives packets from the Data Network, it forwards them to the n6 interface corresponding to the UPF Container, and the N6 interface forwards downlink packets to the virtual interface gtp5g.&lt;br&gt;
Therefore, the CPU handling gtp5g downlink traffic should be CPU 11, which can be verified through an eBPF program.&lt;/p&gt;

&lt;p&gt;In the author's previous article &lt;a href="https://free5gc.org/blog/20241224/" rel="noopener noreferrer"&gt;Debug gtp5g kernel module using stacktrace and eBPF&lt;/a&gt;, the possibility of using eBPF to trace kernel modules was explored. By examining the gtp5g source code, we can see that downlink packets eventually enter &lt;code&gt;gtp5g_xmit_skb_ipv4&lt;/code&gt;. Using &lt;code&gt;sudo cat /sys/kernel/tracing/available_filter_functions | grep gtp5g&lt;/code&gt; also confirms that this function is in the available_filter_functions list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;SEC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fentry/gtp5g_xmit_skb_ipv4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;BPF_PROG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capture_skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sk_buff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;skb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;gtp5g_pktinfo&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pktinfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;__u64&lt;/span&gt; &lt;span class="n"&gt;pid_tgid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpf_get_current_pid_tgid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;__u32&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pid_tgid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;__u32&lt;/span&gt; &lt;span class="n"&gt;tgid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pid_tgid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;__u32&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpf_get_smp_processor_id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="n"&gt;bpf_printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gtp5g_xmit_skb_ipv4: PID=%u, TGID=%u, CPU=%u"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tgid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After loading the above eBPF program into the kernel, when using UERANSIM to establish a PDU Session and send ICMP packets to &lt;code&gt;8.8.8.8&lt;/code&gt;, we can observe the eBPF program output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156182.987076: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156183.987343: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156184.986858: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156185.987004: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156186.987574: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156187.987330: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156188.987722: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156189.988054: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156190.988038: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
        kubelite-3377186 [011] b.s21 6156191.987614: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=3377186, TGID=3376931, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156192.987963: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156193.987763: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
          &amp;lt;idle&amp;gt;-0       [011] b.s31 6156194.988095: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the eBPF program output, we can confirm that gtp5g's downlink traffic is indeed handled by CPU 11, consistent with our previous speculation.&lt;br&gt;
When I use &lt;code&gt;echo "12" | sudo tee /proc/irq/159/smp_affinity_list&lt;/code&gt; to modify the CPU bound to IRQ 159, the eBPF program output immediately changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156445.013125: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156446.012413: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156447.012498: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156448.013280: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156449.012909: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156450.013119: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
          &amp;lt;idle&amp;gt;-0       [012] b.s31 6156451.013496: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=0, TGID=0, CPU=12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note:&lt;br&gt;
The CPU bound to IRQ may be dynamically updated by irqbalance. It's recommended to use &lt;code&gt;$ sudo systemctl stop irqbalance&lt;/code&gt; to temporarily disable irqbalance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That said, even with irqbalance disabled, the eBPF program output may still show unexpected situations.&lt;br&gt;
When I changed the ICMP target from an external IP to the UPF container's own N6 interface IP, the eBPF program output was as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          nr-gnb-168420  [016] b.s41 6158463.012636: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=16
          nr-gnb-168420  [016] b.s41 6158464.012282: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=16
          nr-gnb-168420  [017] b.s41 6158465.012408: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=17
          nr-gnb-168420  [017] b.s41 6158466.012551: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=17
          nr-gnb-168420  [016] b.s41 6158467.012401: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=16
          nr-gnb-168420  [006] b.s41 6158468.012565: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=6
          nr-gnb-168420  [006] b.s41 6158469.012700: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=6
          nr-gnb-168420  [006] b.s41 6158470.012549: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=6
          nr-gnb-168420  [006] b.s41 6158471.012763: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=6
          nr-gnb-168420  [006] b.s41 6158472.012862: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=168420, TGID=168410, CPU=6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically, the CPU executing &lt;code&gt;gtp5g_xmit_skb_ipv4&lt;/code&gt; will always be the CPU that the scheduler allocates to the &lt;code&gt;nr-gnb&lt;/code&gt; process. The reason is simple: packets sent to the N6 interface are processed completely within the container and don't pass through the enp7s0 interface, so packets from UERANSIM all the way to N6 and back are handled within the same context.&lt;/p&gt;

&lt;p&gt;Understanding the Linux kernel's packet processing behavior, we can experiment to see how UERANSIM performs when sending ICMP echo requests to the UPF N6 IP through uesimtun0 under system full load conditions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gthulhu Configuration Settings
&lt;/h3&gt;

&lt;p&gt;In this experiment, the configuration settings are fixed as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gthulhu Scheduler Configuration&lt;/span&gt;
&lt;span class="c1"&gt;# This configuration file allows you to adjust scheduler parameters before eBPF program loading&lt;/span&gt;

&lt;span class="na"&gt;scheduler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Default time slice in nanoseconds (default: 5000000 = 5ms)&lt;/span&gt;
  &lt;span class="na"&gt;slice_ns_default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2000000&lt;/span&gt;

  &lt;span class="c1"&gt;# Minimum time slice in nanoseconds (default: 500000 = 0.5ms)&lt;/span&gt;
  &lt;span class="na"&gt;slice_ns_min&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500000&lt;/span&gt;
&lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:8080&lt;/span&gt;
  &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;early_processing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="na"&gt;builtin_idle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Using &lt;code&gt;stress-ng&lt;/code&gt; to Generate Load
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;stress-ng &lt;span class="nt"&gt;-c&lt;/span&gt; 20 &lt;span class="nt"&gt;--timeout&lt;/span&gt; 60s &lt;span class="nt"&gt;--metrics-brief&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing with &lt;code&gt;ping&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Since the Gthulhu scheduler borrows from the design of scx_rustland, we use scx_rustland as the control group in this experiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/UERANSIM &lt;span class="c"&gt;# taskset -c 5 ping 10.10.2.60 -I uesimtun0 -c 10&lt;/span&gt;
PING 10.10.2.60 &lt;span class="o"&gt;(&lt;/span&gt;10.10.2.60&lt;span class="o"&gt;)&lt;/span&gt;: 56 data bytes
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;75.589 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;75.917 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;63.919 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;71.934 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;72.005 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64.108 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;83.945 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;100.525 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;59.987 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;63.940 ms

&lt;span class="nt"&gt;---&lt;/span&gt; 10.10.2.60 ping statistics &lt;span class="nt"&gt;---&lt;/span&gt;
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max &lt;span class="o"&gt;=&lt;/span&gt; 59.987/73.186/100.525 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can observe that when every CPU in the system is fully loaded, scx_rustland performs very poorly in packet processing efficiency. This problem also exists with the Gthulhu scheduler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/UERANSIM &lt;span class="c"&gt;# taskset -c 5 ping 10.10.2.60 -I uesimtun0 -c 10&lt;/span&gt;
PING 10.10.2.60 &lt;span class="o"&gt;(&lt;/span&gt;10.10.2.60&lt;span class="o"&gt;)&lt;/span&gt;: 56 data bytes
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;22.085 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;59.904 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;96.299 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;20.349 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;71.244 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;28.001 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;74.964 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;59.977 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;32.617 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;90.945 ms

&lt;span class="nt"&gt;---&lt;/span&gt; 10.10.2.60 ping statistics &lt;span class="nt"&gt;---&lt;/span&gt;
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max &lt;span class="o"&gt;=&lt;/span&gt; 20.349/55.638/96.299 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's try the following approach to see if we can reduce round-trip-time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assign a specific CPU (using CPU 5 here) to UERANSIM and the &lt;code&gt;icmp&lt;/code&gt; tool&lt;/li&gt;
&lt;li&gt;If other tasks are assigned to CPU 5, randomly assign them to other CPUs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Related changes can be found in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;    // ...
    log.Println("scheduler started")
&lt;span class="gi"&gt;+   var specialPid int32 = 168420 // Special case for PID 168420
+   var specialPidCpu int32 = 5
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;    for true {
        select {
        case &amp;lt;-ctx.Done():
            log.Println("context done, exiting scheduler loop")
            return
        default:
        }
        sched.DrainQueuedTask(bpfModule)
        t = sched.GetTaskFromPool()
        if t == nil {
            bpfModule.BlockTilReadyForDequeue(ctx)
        } else if t.Pid != -1 {
            task = core.NewDispatchedTask(t)
            err, cpu = bpfModule.SelectCPU(t)
            if err != nil {
                log.Printf("SelectCPU failed: %v", err)
            }
&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gi"&gt;+           if t.Pid == specialPid {
+               if specialPidCpu == -1 &amp;amp;&amp;amp; cpu != core.RL_CPU_ANY {
+                   specialPidCpu = cpu
+               } else {
+                   cpu = specialPidCpu
+               }
+           } else {
+               if cpu == core.RL_CPU_ANY {
+                   // ramdom select cpu 0-19
+                   cpu = int32(rand.Intn(20))
+               }
+               if specialPidCpu == cpu {
+                   if (cpu &amp;amp; 1) == 1 {
+                       cpu = cpu - 1
+                   } else {
+                       cpu = cpu + 1
+                   }
+               }
+           }
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;            // Evaluate used task time slice.
            nrWaiting := core.GetNrQueued() + core.GetNrScheduled() + 1
            task.Vtime = t.Vtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Special pid &lt;code&gt;168420&lt;/code&gt; was observed through the eBPF program as the process id responsible for executing &lt;code&gt;gtp5g_xmit_skb_ipv4()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;          nr-gnb-770208  [005] b.s41 6233538.456200: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233711.301750: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233712.346565: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233713.312931: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233714.314609: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233715.340537: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] b.s41 6233716.337300: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] b.s41 6233717.389852: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] b.s41 6233718.387986: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] b.s41 6233719.368526: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
          nr-gnb-770208  [005] bNs41 6233720.396073: bpf_trace_printk: gtp5g_xmit_skb_ipv4: PID=770208, TGID=770198, CPU=5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After completing the modifications, let's try running Gthulhu again and test once more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/UERANSIM &lt;span class="c"&gt;# taskset -c 5 ping 10.10.2.60 -I uesimtun0 -c 10&lt;/span&gt;
PING 10.10.2.60 &lt;span class="o"&gt;(&lt;/span&gt;10.10.2.60&lt;span class="o"&gt;)&lt;/span&gt;: 56 data bytes
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.767 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.150 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.120 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.968 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.002 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.601 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.132 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.833 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.666 ms
64 bytes from 10.10.2.60: &lt;span class="nb"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;9 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.795 ms

&lt;span class="nt"&gt;---&lt;/span&gt; 10.10.2.60 ping statistics &lt;span class="nt"&gt;---&lt;/span&gt;
10 packets transmitted, 10 packets received, 0% packet loss
round-trip min/avg/max &lt;span class="o"&gt;=&lt;/span&gt; 0.601/0.903/1.150 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the results, the modified Gthulhu scheduler enables the UPF to process packets from UERANSIM in a short time under high load conditions. This performance is consistent with our expectations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducing RTT through Custom Configuration
&lt;/h3&gt;

&lt;p&gt;In the previous experiments, we allocated dedicated CPUs for specific processes, which indeed improved RTT performance under high load conditions. However, this approach is not universal, as each system's load conditions and workloads may differ.&lt;br&gt;
Therefore, Gthulhu has developed a set of custom configuration settings that allow users to adjust scheduling strategies according to their needs. For the project source code, please refer to &lt;a href="https://github.com/Gthulhu/api" rel="noopener noreferrer"&gt;Gthulhu/api&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"read_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"write_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"idle_timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"level"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"info"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jwt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"private_key_path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./config/jwt_private_key.key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"token_duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"strategies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"priority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"execution_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"selectors"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ueransim-macvlan"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"command_regex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nr-gnb|nr-ue|ping"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Through the above JSON file, the API server can identify corresponding processes and update these processes' scheduling strategies to Gthulhu.&lt;br&gt;
If a task has &lt;code&gt;"priority": true&lt;/code&gt;, the task itself can preempt other non-&lt;code&gt;"priority": true&lt;/code&gt; tasks, significantly reducing the time from &lt;code&gt;runnable&lt;/code&gt; to &lt;code&gt;running&lt;/code&gt; state.&lt;br&gt;
In the free5GC integration case, reducing ueransim's scheduling delay means that the UPF can process packets from the RAN more quickly, thereby reducing overall RTT.&lt;/p&gt;

&lt;p&gt;The above video demonstrates how Gthulhu significantly reduces RTT performance through custom scheduling strategies under high load conditions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=MfU64idQcHg" rel="noopener noreferrer"&gt;DEMO&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, Gthulhu also supports a simple WEB GUI, allowing users to manage and monitor&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;5G introduces the concept of network slicing, expecting to provide different service qualities by dividing physical networks into multiple virtual networks. With custom schedulers like Gthulhu, we can more flexibly manage and optimize the performance of these virtual networks, deploy UPFs with different business requirements on different nodes, and adjust scheduling strategies according to actual needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;Ian Chen is a developer passionate about open source technology, focusing on research in 5G and cloud-native architectures. He initiated the &lt;a href="https://gthulhu.github.io/docs/" rel="noopener noreferrer"&gt;Gthulhu&lt;/a&gt; project and is also a major contributor to free5GC, dedicated to promoting and implementing open source solutions for 5G networks.&lt;/p&gt;

</description>
      <category>scheduler</category>
      <category>ebpf</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
