Baeldung Pro – Linux – NPI EA (cat = Baeldung on Linux)
announcement - icon

Learn through the super-clean Baeldung Pro experience:

>> Membership and Baeldung Pro.

No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.

Partner – Orkes – NPI EA (tag=Kubernetes)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

1. Overview

Linux is a preemptive operating system (OS). Therefore, it shares resources between processes and their threads. One of those resources is the central processing unit (CPU). Linux allocates CPU resources using process scheduling policies.

In this tutorial, we’ll discuss how to get the time slice of a process running under the SCHED_RR scheduling policy.

2. What Is a Time Slice?

The time slice is the period a thread is allowed to run. Another name for time slice is time quantum.

The Linux kernel provides several process scheduling policies, which we can classify as real-time and non-real-time policies. The default scheduling policy, SCHED_OTHER, is a non-real-time policy. There isn’t a fixed time slice allocated to threads in SCHED_OTHER. The OS allocates a dynamic time slice to threads depending on several factors such as the load in the system, thread priorities, and targeted preemption latency.

However, real-time scheduling policies aim to run tasks predictably. For example, the SCHED_RR scheduling policy uses a fixed time slice. Every thread with the same priority runs in a round-robin fashion under SCHED_RR. Once its time slice expires, it voluntarily yields the CPU and the kernel places the thread at the end of the queue for that priority level. However, a thread can be preempted by the kernel if there’s a thread with a higher priority. Therefore, each thread within the same priority queue gets a fair share of the CPU.

The time slice doesn’t apply to other real-time scheduling policies. For example, in the SCHED_FIFO scheduling policy, a thread runs until it finishes its job or is preempted by a higher-priority thread. There’s no time slice for SCHED_FIFO. Therefore, we’ll focus on the SCHED_RR scheduling policy in the subsequent sections.

3. Using kernel.sched_rr_timeslice_ms

We can get the value of the time slice of a process running under the SCHED_RR scheduling policy using the kernel.sched_rr_timeslice_ms kernel parameter:

$ sudo sysctl kernel.sched_rr_timeslice_ms
kernel.sched_rr_timeslice_ms = 100

We use the sysctl command to print the value of a kernel parameter by passing it as an argument. The kernel.sched_rr_timeslice_ms kernel parameter specifies the time slice in milliseconds as its name implies. We see that it’s 100 milliseconds by default.

This kernel parameter is stored in the /proc/sys/kernel/sched_rr_timeslice_ms file. Therefore, we can also check its value by printing the content of the file, for example using the cat command:

$ cat /proc/sys/kernel/sched_rr_timeslice_ms
100

The default time slice value for the SCHED_RR scheduling policy is defined in a header file, named rt.h:

/*
 * default timeslice is 100 msecs (used only for SCHED_RR tasks).
 * Timeslices get refilled after they expire.
 */
#define RR_TIMESLICE            (100 * HZ / 1000)

The location of this header file depends on the Linux distro and its version. In RHEL 8, for example, it’s in the /usr/include/linux/sched directory.

4. Using sched_rr_get_interval()

Another alternative is to use the sched_rr_get_interval() system call. We’ll use the following C program, get_time_interval.c, to examine its usage:

$ cat get_time_interval.c
#include <stdio.h>
#include <sched.h>
#include <unistd.h>

int main() {
    struct timespec ts;
    while (1) {
        sched_rr_get_interval(0, &ts);
        printf("Timeslice: %lu.%lu\n", ts.tv_sec, ts.tv_nsec);

        sleep(1);
    }
    return 0;
}

Next, we’ll analyze, build, and test the code.

4.1. Explanation of the Source Code

The program runs in an infinite while loop. First, we get the time slice within the loop by calling sched_rr_get_interval():

sched_rr_get_interval(0, &ts);

The first argument of sched_rr_get_interval() specifies the process ID (PID) of the process whose time slice we want to obtain. If it’s 0 as in our case, we get the time slice of the calling process, which is simply our own process.

The second argument, &ts, is a pointer to a timespec structure. The value of the time slice is written into this structure. It has two fields, tv_sec and tv_nsec. The first one holds the time in seconds, while the second one holds the time in nanoseconds.

The declaration of sched_rr_get_interval() is in the sched.h header file, so we include it at the beginning of get_time_interval.c using #include <sched.h>.

Then, we print the time slice using the printf() function:

printf("Timeslice: %lu.%lu\n", ts.tv_sec, ts.tv_nsec);

Finally, the program sleeps for one second using sleep(1) and then executes the same statements within the loop periodically.

4.2. Building and Running the Example

Let’s build the application using gcc:

$ gcc -o get_time_interval get_time_interval.c

The -o option of gcc specifies the executable’s name, get_time_interval.

Having built the executable, let’s run it:

$ ./get_time_interval
Timeslice: 0.23000000
Timeslice: 0.23000000
Timeslice: 0.11000000
Timeslice: 0.23000000
Timeslice: 0.23000000
Timeslice: 0.23000000
Timeslice: 0.23000000
Timeslice: 0.11000000
...

The running process prints the time slice value periodically, as expected. The value of the time slice is either 230 or 110 milliseconds in our case. The process should be running with the SCHED_OTHER policy by default, so this is expected since there isn’t a fixed time slice in SCHED_OTHER.

Let’s check the process’s scheduling policy. We can get the real-time attributes of the process using the chrt command in a new terminal after getting its PID using ps:

$ ps -ef | grep get_time_interval | grep -v grep
baeldung 185163 2596 0 11:30 pts/1 00:00:00 ./get_time_interval
$ chrt -p 185163
pid 185163’s current scheduling policy: SCHED_OTHER
pid 185163’s current scheduling priority: 0

The PID of the process is 185163. We pass the process’s PID to chrt using the -p option. The process’s scheduling policy is SCHED_OTHER as expected, and its priority is 0. POSIX requires that sched_rr_get_interval() must work with processes running under the SCHED_RR scheduling policy. However, we see that it can also print the time slice of a process running with the SCHED_OTHER scheduling policy.

Now, let’s change the current scheduling policy of the process using chrt:

$ sudo chrt -r -p 20 185163

chrt may need root privileges, so we use it with the sudo command. The -r option sets the scheduling policy to SCHED_RR. While changing a process’s scheduling policy, chrt expects us to pass a priority value together with the PID. In our case, we set the process’s priority to 20. Let’s recheck the new settings using chrt:

$ chrt -p 185163
pid 185163’s current scheduling policy: SCHED_RR
pid 185163’s current scheduling priority: 20

The process’s scheduling policy is now SCHED_RR and its priority is 20, as expected. Now, let’s check the time slice value printed by the running process:

$ ./get_time_interval
...
Timeslice: 0.23000000
Timeslice: 0.23000000
Timeslice: 0.100000000
Timeslice: 0.100000000
Timeslice: 0.100000000
Timeslice: 0.100000000
Timeslice: 0.100000000
...

Notably, the value of the time slice becomes 100 milliseconds as soon as we set the process’s scheduling policy to SCHED_RR.

4.3. Changing the Time Slice

Additionally, let’s change the time slice using the sysctl command:

$ sudo sysctl -w kernel.sched_rr_timeslice_ms=300

We set the time slice to 300 milliseconds using the -w option. We need to use the sudo command since changing kernel parameters requires root privileges.

Now, let’s check the time slice that the running process prints:

$ ./get_time_interval
...
Timeslice: 0.100000000
Timeslice: 0.100000000
Timeslice: 0.100000000
Timeslice: 0.300000000
Timeslice: 0.300000000
Timeslice: 0.300000000
...

As we see from the output, the time slice becomes 300 milliseconds as soon as we update the kernel.sched_rr_timeslice_ms kernel parameter.

5. Conclusion

In this article, we discussed how to get a process’s time slice. In particular, we explored the SCHED_RR scheduling policy since it has a fixed time slice.

First, we learned that the kernel parameter kernel.sched_rr_timeslice_ms holds the time slice of SCHED_RR. We can get its value using the sysctl command or the /proc/sys/kernel/sched_rr_timeslice_ms file. It’s also defined in system header files.

Then, we learned that we can use the sched_rr_get_interval() system call to get the time slice. Additionally, we saw that it can print the dynamic time slice of a process running with the SCHED_OTHER scheduling policy.