538 lines
12 KiB
C
538 lines
12 KiB
C
#include <common/smp.h>
|
|
#include <common/kprint.h>
|
|
#include <common/macro.h>
|
|
#include <common/kmalloc.h>
|
|
#include <process/thread.h>
|
|
#include <sched/context.h>
|
|
#include <sched/sched.h>
|
|
#include <tests/tests.h>
|
|
|
|
#define TEST_NUM 1
|
|
#define THREAD_NUM 8
|
|
|
|
volatile int sched_start_flag = 0;
|
|
volatile int sched_finish_flag = 0;
|
|
|
|
extern struct list_head rr_ready_queue[PLAT_CPU_NUM];
|
|
|
|
static void atomic_sched(void)
|
|
{
|
|
lock(&test_lock);
|
|
sched();
|
|
unlock(&test_lock);
|
|
|
|
BUG_ON(!current_thread);
|
|
BUG_ON(!current_thread->thread_ctx);
|
|
}
|
|
|
|
static int atomic_sched_enqueue(struct thread *thread)
|
|
{
|
|
int ret;
|
|
|
|
lock(&test_lock);
|
|
ret = sched_enqueue(thread);
|
|
unlock(&test_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct thread *atomic_sched_choose_thread(void)
|
|
{
|
|
struct thread *ret = NULL;
|
|
|
|
lock(&test_lock);
|
|
ret = sched_choose_thread();
|
|
unlock(&test_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static struct thread *create_test_thread(int prio, int aff)
|
|
{
|
|
int i = 0;
|
|
struct thread *thread = NULL;
|
|
|
|
lock(&test_lock);
|
|
thread = kmalloc(sizeof(struct thread));
|
|
BUG_ON(!(thread->thread_ctx = create_thread_ctx()));
|
|
unlock(&test_lock);
|
|
init_thread_ctx(thread, 0, 0, prio, TYPE_TESTS, aff);
|
|
for (i = 0; i < REG_NUM; i++)
|
|
thread->thread_ctx->ec.reg[i] = prio;
|
|
|
|
return thread;
|
|
}
|
|
|
|
static void check_thread_ctx(void)
|
|
{
|
|
int i = 0;
|
|
struct thread_ctx *thread_ctx = NULL;
|
|
|
|
lock(&test_lock);
|
|
thread_ctx = (struct thread_ctx *)switch_context();
|
|
unlock(&test_lock);
|
|
for (i = 0; i < REG_NUM; i++)
|
|
BUG_ON(thread_ctx->ec.reg[i] != thread_ctx->prio);
|
|
}
|
|
|
|
static void free_test_thread(struct thread *thread)
|
|
{
|
|
BUG_ON(thread->thread_ctx->type == TYPE_IDLE);
|
|
lock(&test_lock);
|
|
destroy_thread_ctx(thread);
|
|
kfree(thread);
|
|
unlock(&test_lock);
|
|
}
|
|
|
|
void tst_sched_param(bool is_bsp)
|
|
{
|
|
int i = 0;
|
|
u32 local_thread_num = 4;
|
|
u32 cpuid = smp_get_cpu_id();
|
|
struct thread *threads[4];
|
|
struct thread *idle_thread = NULL;
|
|
struct thread *thread = NULL;
|
|
struct thread_ctx *thread_ctx = NULL;
|
|
|
|
/* Init threads */
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
threads[i] = create_test_thread(i, NO_AFF);
|
|
}
|
|
|
|
{ // test enqueue
|
|
BUG_ON(!sched_enqueue(NULL));
|
|
{
|
|
thread_ctx = threads[0]->thread_ctx;
|
|
threads[0]->thread_ctx = NULL;
|
|
BUG_ON(!sched_enqueue(threads[0]));
|
|
threads[0]->thread_ctx = thread_ctx;
|
|
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
}
|
|
{
|
|
threads[0]->thread_ctx->state = TS_READY;
|
|
BUG_ON(!sched_enqueue(threads[0]));
|
|
threads[0]->thread_ctx->state = TS_INIT;
|
|
}
|
|
{
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
BUG_ON(sched_enqueue(threads[i]));
|
|
BUG_ON(threads[i]->thread_ctx->cpuid != cpuid);
|
|
BUG_ON(threads[i]->thread_ctx->state !=
|
|
TS_READY);
|
|
}
|
|
|
|
BUG_ON(!sched_enqueue(threads[0]));
|
|
}
|
|
}
|
|
|
|
{ // test dequeue
|
|
BUG_ON(!sched_dequeue(NULL));
|
|
{
|
|
thread_ctx = threads[0]->thread_ctx;
|
|
threads[0]->thread_ctx = NULL;
|
|
BUG_ON(!sched_dequeue(threads[0]));
|
|
threads[0]->thread_ctx = thread_ctx;
|
|
}
|
|
|
|
{
|
|
BUG_ON(sched_dequeue(threads[2]));
|
|
BUG_ON(sched_dequeue(threads[1]));
|
|
BUG_ON(sched_dequeue(threads[3]));
|
|
BUG_ON(sched_dequeue(threads[0]));
|
|
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
BUG_ON(threads[i]->thread_ctx->state !=
|
|
TS_INTER);
|
|
}
|
|
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
}
|
|
}
|
|
|
|
{ // test choose_thread & idle thread
|
|
idle_thread = sched_choose_thread();
|
|
BUG_ON(idle_thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
{
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
BUG_ON(sched_enqueue(idle_thread));
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
}
|
|
|
|
{
|
|
BUG_ON(sched_enqueue(threads[0]));
|
|
BUG_ON(!sched_dequeue(idle_thread));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[0]);
|
|
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
}
|
|
|
|
{
|
|
BUG_ON(sched_enqueue(threads[3]));
|
|
BUG_ON(sched_enqueue(threads[2]));
|
|
BUG_ON(sched_enqueue(threads[0]));
|
|
BUG_ON(sched_enqueue(threads[1]));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[3]);
|
|
|
|
BUG_ON(sched_dequeue(threads[2]));
|
|
BUG_ON(sched_dequeue(threads[1]));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[0]);
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != idle_thread);
|
|
}
|
|
}
|
|
|
|
{ // test sched
|
|
BUG_ON(sched_enqueue(threads[3]));
|
|
BUG_ON(sched_enqueue(threads[2]));
|
|
BUG_ON(sched_enqueue(threads[0]));
|
|
BUG_ON(sched_enqueue(threads[1]));
|
|
|
|
sched();
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
BUG_ON(threads[3]->thread_ctx->state != TS_RUNNING);
|
|
BUG_ON(!sched_dequeue(threads[3]));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[2]);
|
|
|
|
sched();
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
BUG_ON(threads[0]->thread_ctx->state != TS_RUNNING);
|
|
BUG_ON(!sched_dequeue(threads[0]));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[1]);
|
|
|
|
sched();
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
BUG_ON(threads[3]->thread_ctx->state != TS_RUNNING);
|
|
BUG_ON(!sched_dequeue(threads[3]));
|
|
|
|
thread = sched_choose_thread();
|
|
BUG_ON(thread != threads[0]);
|
|
|
|
BUG_ON(current_thread != threads[3]);
|
|
current_thread = NULL;
|
|
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
}
|
|
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
free_test_thread(threads[i]);
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_queue(bool is_bsp)
|
|
{
|
|
int i = 0;
|
|
struct thread *threads[THREAD_NUM];
|
|
|
|
/* Init threads */
|
|
for (i = 0; i < THREAD_NUM; i++) {
|
|
threads[i] = create_test_thread(i, NO_AFF);
|
|
BUG_ON(sched_enqueue(threads[i]));
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
for (i = 0; i < THREAD_NUM; i++) {
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
BUG_ON(current_thread != threads[i]);
|
|
check_thread_ctx();
|
|
}
|
|
|
|
for (i = 0; i < THREAD_NUM; i++) {
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
BUG_ON(current_thread != threads[i]);
|
|
free_test_thread(current_thread);
|
|
current_thread = NULL;
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_cooperative(bool is_bsp)
|
|
{
|
|
tst_sched_param(is_bsp);
|
|
tst_sched_queue(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
printk("pass tst_sched_cooperative\n");
|
|
}
|
|
}
|
|
|
|
void tst_sched_budget(bool is_bsp)
|
|
{
|
|
int i = 0;
|
|
u32 local_thread_num = 4;
|
|
struct thread *threads[4];
|
|
|
|
/* Init threads */
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
threads[i] = create_test_thread(i, NO_AFF);
|
|
BUG_ON(sched_enqueue(threads[i]));
|
|
}
|
|
BUG_ON(current_thread);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
sched();
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(current_thread != threads[0]);
|
|
}
|
|
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(current_thread != threads[1]);
|
|
}
|
|
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
BUG_ON(current_thread != threads[(i + 2) % PLAT_CPU_NUM]);
|
|
free_test_thread(threads[(i + 2) % PLAT_CPU_NUM]);
|
|
current_thread = NULL;
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_timer(bool is_bsp)
|
|
{
|
|
int i = 0, j = 0;
|
|
u32 local_thread_num = 4;
|
|
struct thread *threads[4];
|
|
|
|
/* Init threads */
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
threads[i] = create_test_thread(i, NO_AFF);
|
|
BUG_ON(sched_enqueue(threads[i]));
|
|
}
|
|
BUG_ON(current_thread);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
for (j = 0; j < DEFAULT_BUDGET; j++) {
|
|
sched_handle_timer_irq();
|
|
}
|
|
sched();
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(current_thread != threads[0]);
|
|
}
|
|
|
|
threads[0]->thread_ctx->sc->budget = 0;
|
|
for (j = 0; j < DEFAULT_BUDGET; j++) {
|
|
sched_handle_timer_irq();
|
|
}
|
|
sched();
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(current_thread != threads[1]);
|
|
}
|
|
|
|
BUG_ON(DEFAULT_BUDGET <= 1);
|
|
sched_handle_timer_irq();
|
|
sched();
|
|
BUG_ON(current_thread != threads[1]);
|
|
|
|
for (j = 0; j < DEFAULT_BUDGET; j++) {
|
|
sched_handle_timer_irq();
|
|
}
|
|
for (i = 0; i < local_thread_num; i++) {
|
|
sched();
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
BUG_ON(current_thread != threads[(i + 2) % PLAT_CPU_NUM]);
|
|
free_test_thread(threads[(i + 2) % PLAT_CPU_NUM]);
|
|
current_thread = NULL;
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_preemptive(bool is_bsp)
|
|
{
|
|
tst_sched_budget(is_bsp);
|
|
tst_sched_timer(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
printk("pass tst_sched_preemptive\n");
|
|
}
|
|
}
|
|
|
|
void tst_sched_aff_param(bool is_bsp)
|
|
{
|
|
u32 cpuid = smp_get_cpu_id();
|
|
struct thread *thread = NULL, *idle_thread = NULL;
|
|
|
|
/* should return idle thread */
|
|
thread = atomic_sched_choose_thread();
|
|
BUG_ON(thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
thread = create_test_thread(0, 6);
|
|
BUG_ON(!sched_enqueue(thread));
|
|
|
|
BUG_ON(!sched_dequeue(thread));
|
|
|
|
idle_thread = sched_choose_thread();
|
|
BUG_ON(idle_thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
free_test_thread(thread);
|
|
BUG_ON(!list_empty(&rr_ready_queue[cpuid]));
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_aff(bool is_bsp)
|
|
{
|
|
int i = 0;
|
|
u32 cpuid = smp_get_cpu_id();
|
|
struct thread *thread = NULL;
|
|
struct thread *threads[THREAD_NUM + 1];
|
|
|
|
/* should return idle thread */
|
|
thread = atomic_sched_choose_thread();
|
|
BUG_ON(thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
for (i = 0; i < THREAD_NUM + 1; i++) {
|
|
threads[i] = create_test_thread(i, cpuid);
|
|
BUG_ON(sched_enqueue(threads[i]));
|
|
}
|
|
for (i = 0; i < PLAT_CPU_NUM; i++) {
|
|
if (i != cpuid)
|
|
BUG_ON(!list_empty(&rr_ready_queue[i]));
|
|
}
|
|
|
|
threads[0]->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
for (i = 0; i < THREAD_NUM + 1; i++) {
|
|
threads[i]->thread_ctx->affinity = i % PLAT_CPU_NUM;
|
|
threads[i]->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
}
|
|
for (i = 0; i < THREAD_NUM / PLAT_CPU_NUM; i++) {
|
|
threads[i * PLAT_CPU_NUM]->thread_ctx->sc->budget = 0;
|
|
sched();
|
|
}
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
for (i = 0; i < THREAD_NUM / PLAT_CPU_NUM; i++) {
|
|
thread = atomic_sched_choose_thread();
|
|
BUG_ON(thread->thread_ctx->cpuid != cpuid);
|
|
BUG_ON(thread->thread_ctx->affinity % PLAT_CPU_NUM != cpuid);
|
|
BUG_ON(thread->thread_ctx->prio != i * PLAT_CPU_NUM + cpuid);
|
|
current_thread = NULL;
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
for (i = 0; i < THREAD_NUM + 1; i++) {
|
|
free_test_thread(threads[i]);
|
|
}
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
}
|
|
|
|
void tst_sched_affinity(bool is_bsp)
|
|
{
|
|
tst_sched_aff_param(is_bsp);
|
|
tst_sched_aff(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
printk("pass tst_sched_affinity\n");
|
|
}
|
|
}
|
|
|
|
void tst_sched(bool is_bsp)
|
|
{
|
|
int i = 0, j = 0, k = 0;
|
|
u32 cpuid = smp_get_cpu_id();
|
|
struct thread *thread = NULL;
|
|
|
|
/* should return idle thread */
|
|
thread = atomic_sched_choose_thread();
|
|
BUG_ON(thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
/* Init threads */
|
|
for (i = 0; i < PLAT_CPU_NUM; i++) {
|
|
for (j = 0; j < THREAD_NUM; j++) {
|
|
thread = create_test_thread(k, i);
|
|
BUG_ON(atomic_sched_enqueue(thread));
|
|
k++;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < TEST_NUM; j++) {
|
|
/* Each core try to get those threads */
|
|
for (i = 0; i < THREAD_NUM * PLAT_CPU_NUM; i++) {
|
|
/* get thread and dequeue from ready queue */
|
|
do {
|
|
/* do it again if choose idle thread */
|
|
atomic_sched();
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
} while (current_thread->thread_ctx->type == TYPE_IDLE);
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
/* Current thread set affinitiy */
|
|
current_thread->thread_ctx->affinity =
|
|
(i + cpuid) % PLAT_CPU_NUM;
|
|
check_thread_ctx();
|
|
}
|
|
if (smp_get_cpu_id() == 0) {
|
|
printk(".");
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < THREAD_NUM * PLAT_CPU_NUM; i++) {
|
|
/* get thread and dequeue from ready queue */
|
|
do {
|
|
/* do it again if choose idle thread */
|
|
atomic_sched();
|
|
current_thread->thread_ctx->sc->budget = 0;
|
|
} while (current_thread->thread_ctx->type == TYPE_IDLE);
|
|
BUG_ON(!current_thread->thread_ctx->sc);
|
|
free_test_thread(current_thread);
|
|
current_thread = NULL;
|
|
}
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
/* should return idle thread */
|
|
thread = atomic_sched_choose_thread();
|
|
BUG_ON(thread->thread_ctx->type != TYPE_IDLE);
|
|
|
|
global_barrier(is_bsp);
|
|
|
|
if (is_bsp) {
|
|
printk("pass tst_sched\n");
|
|
}
|
|
}
|