Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add test for round robin threads #125

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion apps/sel4test-tests/src/tests/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ periodic_thread(int id, volatile unsigned long *counters)
while (1) {
counters[id]++;
test_leq(counters[id], (unsigned long) 10000);
printf("Tick\n");
printf("Tick (%d)\n", id);
seL4_Yield();
}
}
Expand Down Expand Up @@ -1695,3 +1695,72 @@ static int test_changing_affinity(struct env *env)
}
DEFINE_TEST(SCHED0022, "test changing a helper threads core", test_changing_affinity,
(config_set(CONFIG_KERNEL_MCS) &&(CONFIG_MAX_NUM_NODES > 1)));


/* busy wait for a number of iterations */
static void delay_loop(unsigned iterations) {
for (int i = 0; i < iterations; i++) {
__asm__ __volatile__ ("");
}
}

#define SCHED0023_NUM_ROUNDS 5

/* used in test_round_robin below */
static void round_robin_thread(int id, volatile unsigned long *counters)
{
delay_loop(id * 10000);

/* assumes counters are initialised already */
while (counters[id] < SCHED0023_NUM_ROUNDS) {
counters[id]++;
/* thread "id" should run after thread "id-1", so we should be at the same
count after incrementing if we are scheduled round robin. */
if (0 < id) {
test_eq(counters[id], counters[id - 1]);
}
printf("Tick (%d)\n", id);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a explicit note here that the blocking printing is not interfering with the test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not sure it isn’t actually, I’m still experimenting. A good 30% of the configs where this test is enabled are still failing. But of course not when I’m trying to run it manually..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will interfere with the test, as it messes up all timing and hence scheduling.

/* busy wait so we can be preempted at least once before we increment
the counter again */
delay_loop(5000000);
Copy link
Member

@axel-h axel-h Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a note here why this magic value seem quite safe based on the assumption about time slice and core frequency/IPS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it isn’t safe yet on all machines, esp when printing is off. I might have to actually try to compute a value here instead. Just wanted to avoid making any syscalls in these threads that could affect scheduling.

}

test_eq(counters[id], (unsigned long) SCHED0023_NUM_ROUNDS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a note there why this would ever fail. Is there any other cause besides memory corruption?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making sure every thread is only writing to its own counter.

}

/* Test that round robin threads are indeed round robin. */
static int test_round_robin(struct env *env)
{
const int num_threads = 5;
helper_thread_t helpers[num_threads];
volatile unsigned long counters[num_threads];

for (int i = 0; i < num_threads; i++) {
counters[i] = 0;
create_helper_thread(env, &helpers[i]);
/* keep at lower priority first, we will drop our own priority when they are all started */
set_helper_priority(env, &helpers[i], env->priority - 1);
/* budget == priority makes them round robin */
set_helper_sched_params(env, &helpers[i], 1 * US_IN_MS, 1 * US_IN_MS, 0);
}

/* start in reverse order, because most recently started is first in scheduling
queue and we want id 0 to run first */
for (int i = num_threads - 1; i >= 0; i--) {
start_helper(env, &helpers[i],
(helper_fn_t) round_robin_thread, i, (seL4_Word) counters, 0, 0);
}

int error = seL4_TCB_SetPriority(env->tcb, env->tcb, env->priority - 2);
test_error_eq(error, seL4_NoError);

/* We will only get to run again when the round robin threads have all finished,
because they are higher priority */
for (int i = 0; i < num_threads; i++) {
test_eq(counters[i], (unsigned long) SCHED0023_NUM_ROUNDS);
}

return sel4test_get_result();
}
DEFINE_TEST(SCHED0023, "test round robin threads", test_round_robin,
(config_set(CONFIG_KERNEL_MCS)));
Loading