2021-05-23 22:24:02 +08:00

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");
}
}