From: Darren Hart <darren@dvhart.com>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>, Thomas Gleixner <tglx@linutronix.de>,
"Stultz, John" <johnstul@us.ibm.com>
Subject: realtime-preempt scheduling - rt_overload behavior
Date: Wed, 5 Apr 2006 20:13:48 -0700 [thread overview]
Message-ID: <200604052013.49222.darren@dvhart.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1624 bytes --]
I have been experimenting with realtime scheduling and have come across some
unexpected results. When running the attached testcase it's apparent that
lower priority SCHED_FIFO threads are running while higher priority
SCHED_FIFO threads sit runnable on another CPU's run_queue.
First, what are the expectations for the realtime scheduler? Are we trying
for "system wide strict realtime priority scheduling", should we consider the
above scenario a bug?
From what I could gather reading sched.c (2.6.16-rt11), the scheduler will
increment rt_overload anytime a run_queue has 2 RT tasks on it - so
rt_overload is >0 anytime NR_CPUS+1 RT tasks are runnable on the system.
schedule() calls pull_rt_tasks() anytime it runs and sees that rt_overload is
> 0 and pulls the highest priority runnable rt task off each run_queue and
places them on its CPU's run_queue. I also see that we call
smp_send_reschedule() (or similar) when an RT task is waking up or being
bumped off the run_queue. So clearly we are trying to prevent the above
scenario from happening.
I'd appreciate your thoughts on this. Any comments on the test case are also
welcome. As I understand it, sched_yield() will place a SCHED_FIFO task back
on the active array, and if it is still the highest prio RT task it will get
rescheduled immediately (which it likely is since a higher priority task
should have preempted it when it became runnable).
(the testcase "fails" more often on 4way and bigger machines, with around
2xCPUS threads per team. './sched_football 8 10' for example.)
Thanks,
--Darren
[-- Attachment #2: sched_football.c --]
[-- Type: text/x-csrc, Size: 4418 bytes --]
/* Threaded Football - by John Stultz <johnstul@us.ibm.com>
*
* This is a scheduler test that uses a football analogy.
* The premise is that we want to make sure that lower priority threads
* (the offensive team) do not preempt higher priority threads (the
* defensive team). The offense is trying to increment the balls position,
* while the defense is trying to block that from happening.
* And the ref (highest priority thread) will blow the wistle if the
* ball moves. Finally, we have crazy fans (higer prority) that try to
* distract the defense by occasionally running onto the field.
*
* PS: I really don't like football that much, it just seemed to fit.
*
* 2006-03-16 Reduced verbosity, non binary failure reporting, removal of
* crazy_fans thread, added game_length argument by Darren Hart.
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#include <sys/syscall.h>
#define MAXTHREADS 256
#define DEF_GAME_LENGTH 5
/* Here's the position of the ball */
volatile int the_ball;
/* Game status */
volatile int game_over;
/* Keep track of who's on the field */
volatile int offense_count;
volatile int defense_count;
volatile int crazyfan_count;
/* simple mutex for our atomic increments */
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#define min(x,y) (x < y ? x: y)
/* This is the defensive team. They're trying to block the offense */
void *thread_defense(void* arg)
{
pthread_mutex_lock(&mutex);
defense_count++;
pthread_mutex_unlock(&mutex);
/*keep the ball from being moved */
while (!game_over) {
sched_yield(); /* let other defenders run */
}
}
/* This is the offensive team. They're trying to move the ball */
void *thread_offense(void* arg)
{
pthread_mutex_lock(&mutex);
offense_count++;
pthread_mutex_unlock(&mutex);
while (!game_over) {
the_ball++; /* move the ball ahead one yard */
sched_yield(); /* let other offensive players run */
}
}
void referee(int game_length)
{
struct timeval start, now;
printf("Game On (%d seconds)!\n", game_length);
gettimeofday(&start, 0);
now = start;
the_ball = 0;
/* Watch the game */
while ((now.tv_sec - start.tv_sec) < game_length) {
sleep(1);
gettimeofday(&now, 0);
}
/* Blow the whistle */
printf("Game Over!\n");
printf("Final ball position: %d\n", the_ball);
game_over = 1;
}
void create_thread(pthread_t *thread, void*(*func)(void*), int prio)
{
pthread_attr_t attr;
struct sched_param param;
param.sched_priority = sched_get_priority_min(SCHED_FIFO) + prio;
pthread_attr_init(&attr);
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedparam(&attr, ¶m);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
if (pthread_create(thread, &attr, func, (void *)0)) {
perror("pthread_create failed");
}
pthread_attr_destroy(&attr);
}
int main(int argc, char* argv[])
{
struct sched_param param;
int players_per_team, game_length;
int priority;
int thread_count = 0;
pthread_t thread_id[MAXTHREADS];
int i;
if (argc < 2 || argc > 3) {
printf("Usage: %s players_per_team [game_length (seconds)]\n", argv[0]);
exit(1);
}
players_per_team = atoi(argv[1]);
if (argc == 3)
game_length = atoi(argv[2]);
else
game_length = DEF_GAME_LENGTH;
/* We're the ref, so set our priority right */
param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 80;
sched_setscheduler(0, SCHED_FIFO, ¶m);
/* Start the offense */
priority = 15;
printf("Starting %d offense threads at priority %d\n",
players_per_team, priority);
for (i = 0; i < players_per_team; i++)
create_thread(&thread_id[thread_count],
thread_offense, priority);
while (offense_count < players_per_team)
usleep(100);
/* Start the defense */
priority = 30;
printf("Starting %d defense threads at priority %d\n",
players_per_team, priority);
for (i = 0; i < players_per_team; i++)
create_thread(&thread_id[thread_count++],
thread_defense, priority);
while (defense_count < players_per_team)
usleep(100);
/* Ok, everyone is on the field, bring out the ref */
printf("Starting referee thread\n");
referee(game_length);
for (i = 0; i < thread_count; i++) {
usleep(100);
pthread_join(thread_id[i], 0);
}
return 0;
}
reply other threads:[~2006-04-06 3:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200604052013.49222.darren@dvhart.com \
--to=darren@dvhart.com \
--cc=johnstul@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome