thang comparing the real-time scheduling policies of the linux kernel and an rtos 23p apr2012.pdf

23
Comparing the real-time scheduling policies of the Linux kernel and an RTOS Le Trung Thang - April 25, 2012 By default, the Linux kernel build used in the many open source distributions is the normal/default kernel which doesn’t support real time scheduling. If an embedded developer wants to compare the scheduling policies of Linux to a real time operating system it is more useful to compare RTOS performance to a version of Linux that does have real-time features. Fortunately, in addition to this default kernel, there is also available a Real-time kernel version that supports a real-time scheduling policy. In this article and in the code examples that are included, an effort is made to compare the real time operations of standard and real-time Linux with normal RTOS operation and evaluate the differences and similarities. Normal Linux kernel vs RTOS Normal Linux Kernel is a preemptive kernel but not real time, of course. In most multithreading environments (also called multitasking), a preemptive kernel allows the thread that has higher priority to receive longer time on the processor. And, conversely a lower priority thread will have less time with the processor. However, in the normal kernel, no particular thread can monopolize the services of the resident processor all the time, no matter what its priority. So, programs will never hang up even if an arbitrary thread of the program goes into a “forever loop.” Conversely, with almost any real time OS ( such as FreeRTOS, Micrium uC/OS, and ThreadX), the kernel supports both preemption and real-time features. This means that a thread ( also called a Task) can run forever when the following conditions are met: (1) it is not blocked by synchronized resource (I/O block, Mutex, Semaphore…) or (2) it isn’t preempted by threads which may have equal or higher priority. Figure 1 below shows the differences between the thread scheduling policy of normal Linux and the thread scheduling policy of a RTOS. In Figure 1, we assume that Thread1 has priority 2 and is higher than Thread2 which has priority 1. In the RTOS scheduler, Thread1, with higher priority, always runs. Thread2 with lower priority never has a chance to run. By comparison the Normal Linux Scheduler does exactly the opposite, bringing up both Thread1 and Thread2 to run. Thread1 with higher priority will have longer time to run as compared with Thread2 which has lower priority.

Upload: x2y2z2rm

Post on 06-Aug-2015

9 views

Category:

Documents


2 download

DESCRIPTION

By Le Trung Thang - April 25, 2012

TRANSCRIPT

Page 1: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

Comparing the real-time scheduling policies of the Linux kernel and an RTOSLe Trung Thang - April 25, 2012

By default, the Linux kernel build used in the many open source distributions is the normal/default kernel which doesn’t support real time scheduling. If an embedded developer wants to compare the scheduling policies of Linux to a real time operating system it is more useful to compare RTOS performance to a version of Linux that does have real-time features.

Fortunately, in addition to this default kernel, there is also available a Real-time kernel version that supports a real-time scheduling policy. In this article and in the code examples that are included, an effort is made to compare the real time operations of standard and real-time Linux with normal RTOS operation and evaluate the differences and similarities.

Normal Linux kernel vs RTOS Normal Linux Kernel is a preemptive kernel but not real time, of course. In most multithreading environments (also called multitasking), a preemptive kernel allows the thread that has higher priority to receive longer time on the processor. And, conversely a lower priority thread will have less time with the processor.

However, in the normal kernel, no particular thread can monopolize the services of the resident processor all the time, no matter what its priority. So, programs will never hang up even if an arbitrary thread of the program goes into a “forever loop.”

Conversely, with almost any real time OS (such as FreeRTOS, Micrium uC/OS, and ThreadX), the kernel supports both preemption and real-time features. This means that a thread (also called a Task) can run forever when the following conditions are met: (1) it is not blocked by synchronized resource (I/O block, Mutex, Semaphore…) or (2) it isn’t preempted by threads which may have equal or higher priority.

Figure 1 below shows the differences between the thread scheduling policy of normal Linux and the thread scheduling policy of a RTOS. In Figure 1, we assume that Thread1 has priority 2 and is higher than Thread2 which has priority 1.

In the RTOS scheduler, Thread1, with higher priority, always runs. Thread2 with lower priority never has a chance to run. By comparison the Normal Linux Scheduler does exactly the opposite, bringing up both Thread1 and Thread2 to run. Thread1 with higher priority will have longer time to run as compared with Thread2 which has lower priority.

Page 2: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

Click on image to enlarge.

Figure 1. Real Time OS and normal Linux kernel scheduler

Real Time Linux kernel versus RTOS In a real time kernel version of Linux, the scheduler has three (3) scheduling policies: Normal, FIFO and Round Robin.

In the Normal scheduling policy, a thread will be stopped (suspended) when one of three conditions occurs:

1. It is blocked by an accessing synchronize resource (I/O block, mutex, semaphone...) 2. It volunteers to give up control of processor (call sleep() or pthread_yield()).3. The Scheduler suspends the thread when its running time exhausted. The running time depends on each thread’s priority, as noted in Figure 1.

Normal real time scheduling policy is same as the default scheduling policy of normal kernel as described earlier.

With the FIFO scheduling policy, a thread will be stopped (suspended) when one of three conditions occurs:

1. It is blocked by accessing synchronize resource (I/O block, mutex, semaphore...) 2. It is preempted by a higher priority thread. 3. It volunteers to give up control of processor (call sleep() or pthread_yield()).

In the Round Robin scheduling policy, a thread will be stopped (suspended) when one in four following conditions occurs:

1. It is blocked by accessing synchronize resource (I/O block, mutex, semaphore...) 2. Or it is preempted by a higher priority thread. 3. Or it volunteers to give up control of processor (call sleep() or pthread_yield()).4. Or its Time slice expired.

(Most RTOSes embed Round Robin scheduling policy in their scheduler.)

Page 3: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

In Figure 2 below, we have four situations: First, Thread1 and Thread2 are of equal priority and run using the FIFO policy. Second, Thread1 and Thread2 are of equal priority and run on the Round Robin policy. Third, priority of Thread1 is higher priority of Thread2 and they run using the FIFO policy. Fourth, the priority of Thread1 is higher priority of Thread2 and they run using the Round Robin policy.

We also assume that Thread1 starts first, then Thread2 starts later and during running time, Thread1and Thread2 don’t make any system calls or are blocked by any synchronized resource (I/O, Mutex, Semaphore…). The result: the only differences that affect real time performance between the FIFO and Round Robin policies is when Thread1 and Thread2 have same priority.

Click on image to enlarge.

Figure 2. Real time Linux kernel scheduler

Conclusion: Viewed in this context, the typical RTOS scheduler is just a special case of real time Linux scheduler, or in other words, the RTOS scheduler is the real time Linux scheduler running with the Round Robin policy. (Some RTOSes allow configuration of the scheduler to run in a non-preemption mode. However this mode is seldom used.)

The examples included on Page 2 to 8 of this article show the different operational mechanisms of the real time Linux Scheduler in the context of this discussion. To download the source code for these examples, click here.

Important note: On the following pages, all of the examples are only correct when the program runs in CPU single core and in root permission . To enforce a thread/process so that it only runs in a particular core of the processor, this can be done via the function sched_setaffinity( ) which sets the process CPU affinity. The programs were tested in Real time Linux kernel version 3.0.17.

Page 4: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

If you want to install Real Time Linux and test it out yourself, more information is on Page 9, along with some references you may wish to consult.

(Editor’s Note: Any errors in the code listed on the following pages may have been introduced during the conversion process to ready it for online. If so, please contact me directly at [email protected].)

Page 2NORMAL scheduling policy of Linux, Thread1 & Thread2 are not equal priority.

In this policy, Thread1 and Thread2 both have a chance to run although thread1 has higher priority and runs first. Also, Thread1 with higher priority will get time to run longer than Thread2.

/*============================================== Name : Thread_NORMAL.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : NORMAL scheduling policy of Linux, Thread1 and Thread2 are not equal priority. ===============================================*/#define _GNU_SOURCE#include #include #include

#include #include

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effectingbool nice_set_1 = 0; bool nice_set_2 = 0;

//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // for synchronization when both threads can access to time variable at same time.

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

Page 5: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //===========================================

//set attributes pthread_attr_t attr1, attr2; struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//============================================= /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_max(SCHED_OTHER);// no effect with this policy, always return 0 pthread_attr_setschedpolicy(&attr1, SCHED_OTHER); pthread_attr_setschedparam(&attr1, &parm1);

iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function,

void*) message1); pthread_setschedparam(thread1, SCHED_OTHER, &parm1);

//=============================================== pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_min(SCHED_OTHER);// no effect with this policy, always return 0 pthread_attr_setschedpolicy(&attr2, SCHED_OTHER); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function, (void*) message2); pthread_setschedparam(thread2, SCHED_OTHER, &parm2);

//===============================================

/* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */

Page 6: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

/* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//===============================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++) i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { if(nice_set_1 == 0){ nice_set_1 = 1; nice(-20); // set thread1 to highest priority } count1 += 1; // count times Thread1 run

} else { if(nice_set_2 == 0) { nice_set_2 = 1; nice(19); // set thread2 to lowest priority } count2 += 1; // count times Thread2 run

}

//pthread_mutex_lock( &mutex ); times--; //pthread_mutex_unlock( &mutex ); }

return (void*) NULL; }

Result: count1 = 98563, count2 = 1438Thread 1 returns: 0

Page 7: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

Thread 2 returns: 0

Page 3FIFO scheduling policy of Linux, Thread1 priority is higher Thread2 priority.

Thread2 has no chance to run because its priority is lower thread1.

/*=======================================Name : Thread_FIFO_1.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : FIFO scheduling policy of Linux, Thread1 priority is higher Thread2 priority========================================*/#define _GNU_SOURCE#include #include #include

#include

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effecting

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if(sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //=========================================

//set attributes pthread_attr_t attr1, attr2;

Page 8: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//====================================== /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_max(SCHED_FIFO); pthread_attr_setschedpolicy(&attr1, SCHED_FIFO); pthread_attr_setschedparam(&attr1, &parm1);

iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1); pthread_setschedparam(thread1, SCHED_FIFO, &parm1);

//======================================= pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_min(SCHED_FIFO); pthread_attr_setschedpolicy(&attr2, SCHED_FIFO); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function, (void*) message2); pthread_setschedparam(thread2, SCHED_FIFO, &parm2);

//======================================== /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL); printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//===========================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++) i++; // only for delay

if (strcmp(message, "Thread 1") == 0) {

Page 9: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run }

times--; }

return (void*) NULL; }

</code>

<pre>Result: count1 = 100000, count2 = 0Thread 1 returns: 0Thread 2 returns: 0

</code>

<pre>

Page 4FIFO scheduling policy of Linux, Thread1 priority is lower Thread2 priority.

Because thread1 starts first, it runs for a short time before preemption by thread2 which has higher priority. When thread2 runs, thread1 has no chance to run again.

/*===================================Name : Thread_FIFO_2.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : FIFO scheduling policy of Linux, Thread1 priority is lower Thread2 priority==================================*/

#define _GNU_SOURCE#include #include #include

#include

void *print_message_function(void *ptr);

intcount1 = 0;

Page 10: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

intcount2 = 0; inttimes = 100000; // need set enough big to see effecting

intmain(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //=======================================

//set attributes pthread_attr_t attr1, attr2; struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//===================================== /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_min(SCHED_FIFO); pthread_attr_setschedpolicy(&attr1, SCHED_FIFO); pthread_attr_setschedparam(&attr1, &parm1);

iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1); pthread_setschedparam(thread1, SCHED_FIFO, &parm1);

//==================================== pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_max(SCHED_FIFO); pthread_attr_setschedpolicy(&attr2, SCHED_FIFO); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function, (void*) message2);

Page 11: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

pthread_setschedparam(thread2, SCHED_FIFO, &parm2);

//================================== /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */ pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//======================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++) i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run}

times--;}

return (void*) NULL; }

<code>

<pre>

Result:count1 = 5444, count2 = 94557Thread 1 returns: 0Thread 2 returns: 0

<code>

<pre>

Page 12: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

Page 5FIFO scheduling policy of Linux, Thread1 and Thread2 are equal priority. Thread1 runs first.

Because thread1 runs first and no thread has a priority higher than thread1, thread1 runs "forever." This is opposite to the Round-Robin policy.

/*====================================Name : Thread_FIFO_3.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : FIFO scheduling policy of Linux, Thread1 and Thread2 are equal priority. ====================================*/

#define _GNU_SOURCE#include #include #include

#include

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effecting

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //================================

//set attributes pthread_attr_t attr1, attr2;

Page 13: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//============================= /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_min(SCHED_FIFO); pthread_attr_setschedpolicy(&attr1, SCHED_FIFO); pthread_attr_setschedparam(&attr1, &parm1);

iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1);

pthread_setschedparam(thread1, SCHED_FIFO, &parm1);

//================================ pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_min(SCHED_FIFO); pthread_attr_setschedpolicy(&attr2, SCHED_FIFO); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function, (void*) message2); pthread_setschedparam(thread2, SCHED_FIFO, &parm2);

//================================ /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//=====================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++)

Page 14: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run }

times--; }

return (void*) NULL; }

<code>

<pre>

Result:count1 = 100000, count2 = 0Thread 1 returns: 0Thread 2 returns: 0

<code>

<pre>

Page 6Round Robin scheduling policy of Linux, Thread1 priority is higher Thread2 priority.

Thread2 has no chance to run because its priority is lower thread1

/*================================Name : Thread_RR_1.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : Round Robin scheduling policy of Linux, Thread1 priority is higher Thread2 priority. ==================================*/

#define _GNU_SOURCE#include #include #include

#include

Page 15: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effecting

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //==============================

//set attributes pthread_attr_t attr1, attr2; struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//============================= /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_max(SCHED_RR); pthread_attr_setschedpolicy(&attr1, SCHED_RR); pthread_attr_setschedparam(&attr1, &parm1); iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1); pthread_setschedparam(thread1, SCHED_RR, &parm1);

//============================== pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_min(SCHED_RR); pthread_attr_setschedpolicy(&attr2, SCHED_RR); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function,

Page 16: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

(void*) message2); pthread_setschedparam(thread2, SCHED_RR, &parm2);

//============================= /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//=================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++) i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run }

times--; } return (void*) NULL; }

<code>

</pre>

Result: count1 = 100000, count2 = 0Thread 1 returns: 0Thread 2 returns: 0

<code>

</pre>

Page 17: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

Page 7Round Robin scheduling policy of Linux, Thread1 priority is lower Thread2 priority.

Because thread1 starts first, it runs a short time before being preempted by thread2 which has higher priority. When thread2 runs, thread1 has no chance to run again.

/*

==================================Name : Thread_RR_2.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : Round Robin scheduling policy of Linux, Thread1 priority is lower Thread2 priority. =================================*/

#define _GNU_SOURCE#include #include #include

#include

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effecting

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //===============================

Page 18: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

//set attributes pthread_attr_t attr1, attr2; struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//============================= /* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_min(SCHED_RR); pthread_attr_setschedpolicy(&attr1, SCHED_RR); pthread_attr_setschedparam(&attr1, &parm1);

iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1); pthread_setschedparam(thread1, SCHED_RR, &parm1);

//============================ pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_max(SCHED_RR); pthread_attr_setschedpolicy(&attr2, SCHED_RR); pthread_attr_setschedparam(&attr2, &parm2);

iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function, (void*) message2); pthread_setschedparam(thread2, SCHED_RR, &parm2);

//=========================== /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }//================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0;

Page 19: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

for (i = 0; i < 20000; i++)

i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run }

times--; }

return (void*) NULL; }

<code>

</pre>

Result:count1 = 5809, count2 = 94192Thread 1 returns: 0Thread 2 returns: 0

<code>

</pre>

Page 8Round Robin scheduling policy of Linux, Thread1 & Thread2 of equal priority. Thread1 runs first.

Both thread1 and thread2 have the same chance to run. This is opposite to the FIFO policy. There is a slight difference between value of count1 and count2, because the time to execute the program in thread1 might slightly differ from thread2.

/*javascript:void(0); ===============================Name : Thread_RR_3.cAuthor : Thang LeCopyright : www.letrungthang.blogspot.comDescription : Round Robin scheduling policy of Linux, Thread1 and Thread2 are equal priority. Thread1 runs first. ==============================*/

#define _GNU_SOURCE

Page 20: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

#include #include #include

#include

void *print_message_function(void *ptr);

int count1 = 0; int count2 = 0; int times = 100000; // need set enough big to see effecting

int main(void) { pthread_t thread1, thread2; char *message1 = "Thread 1"; char *message2 = "Thread 2"; int iret1, iret2;

//Setting CPU affinity int num_CPUs = 0; // only run on 1 core cpu_set_t mask;

/* CPU_ZERO initializes all the bits in the mask to zero. */ CPU_ZERO(&mask); /* CPU_SET sets only the bit corresponding to cpu. */ CPU_SET(num_CPUs, &mask); /* sched_setaffinity returns 0 in success */ if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { printf("Could not set CPU Affinity \n"); } //==============================

//set attributes pthread_attr_t attr1, attr2; struct sched_param parm1, parm2; pthread_attr_init(&attr1); pthread_attr_init(&attr2);

//===============================

/* Create independent threads each of which will execute function */

pthread_attr_getschedparam(&attr1, &parm1); parm1.sched_priority = sched_get_priority_min(SCHED_RR); pthread_attr_setschedpolicy(&attr1, SCHED_RR); pthread_attr_setschedparam(&attr1, &parm1); iret1 = pthread_create(&thread1, &attr1, (void*) print_message_function, (void*) message1); pthread_setschedparam(thread1, SCHED_RR, &parm1);

Page 21: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

//=============================== pthread_attr_getschedparam(&attr2, &parm2); parm2.sched_priority = sched_get_priority_min(SCHED_RR); pthread_attr_setschedpolicy(&attr2, SCHED_RR); pthread_attr_setschedparam(&attr2, &parm2); iret2 = pthread_create(&thread2, &attr2, (void*) print_message_function,

(void*) message2); pthread_setschedparam(thread2, SCHED_RR, &parm2);

//=============================== /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */

pthread_join(thread1, NULL); pthread_join(thread2, NULL);

printf("count1 = %d, count2 = %d\n", count1, count2); printf("Thread 1 returns: %d\n", iret1); printf("Thread 2 returns: %d\n", iret2); exit(0); //return EXIT_SUCCESS; }

//=====================================void *print_message_function(void *ptr) { char *message; message = (char *) ptr;

while (times > 0) { int i = 0; for (i = 0; i < 20000; i++) i++; // only for delay

if (strcmp(message, "Thread 1") == 0) { count1 += 1; // count times Thread1 run } else { count2 += 1; // count times Thread2 run } times--; }

return (void*) NULL; }

<code>

Page 22: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

</pre>

Result: count1 = 48936, count2 = 51065Thread 1 returns: 0Thread 2 returns: 0

<code>

</pre>

Page 9How to install Real Time Linux Kernel In Fedora Linux, the real-time kernel can be obtained at the Planet CCRMA at Home software repositories (Figure 3, below).

Click on image to enlarge.

Figure 3. Real time kernel installation

You can install the real-time kernel, along with other system optimizations, by following these instructions:

1. Install the Planet CCRMA at Home repositories by entering the following:

rpm -Uvh

http://ccrma.stanford.edu/planetccrma/mirror/fedora/linux/planetccrma/15/i386/planetccrma-repo-1.1-3.fc15.ccrma.noarch.rpm

2. Run the following terminal command line:

su -c 'yum install planetccrma-

Note that this is a meta-package, which does not install anything by itself, but causes a number of other packages to be installed, which will themselves perform the desired installation and optimization.

3. To test the new kernel, shut down and reboot your computer. If you decided to modify your GRUB configuration, be sure that you leave a non-real-time kernel available for use.

Le Trung Thang has a BS in Electronics Engineering at Ho Chi Minh National University, Vietnam, and is currently working as an embedded software engineer in Singapore. He has five years experiences in software development, specific to embedded system. He is active in many projects with variant languages from C/C++ to Java and maintains a blog and can be contacted at [email protected].

Page 23: Thang Comparing the real-time scheduling policies of the Linux kernel and an RTOS 23p Apr2012.pdf

(Editor’s Note to readers: Any errors in the code listed on the preceding pages may have been introduced during the conversion process to ready it for online. If so, please contact me directly at [email protected].)

To download the source code, click here .

References: 1- Linux Kernel Development - Robert Love - Addison Wesley 2010. 2 - Using the FreeRTOS Real Time Kernel - A Practical Guide - 2009 Richard Barry (www.freertos.org ). 3 - uCOS-III The Real-Time Kernel, Jean Labrosse, Micrium Press 2011