#include "prt_config.h"
#include "prt_task.h"
#include "prt_mem.h"
#include "prt_sem.h"
#include "prt_log.h"
#include "prt_clk.h"
#include "prt_sys_external.h"
#include "prt_task_external.h"
#include "securec.h"
#include "time.h"
#include "kern_test_public.h"
#define TASK_NUM 10
static volatile U64 g_task_count[TASK_NUM] = {0};
static volatile U64 g_task_prev_count[TASK_NUM] = {0};
static void test_sched_rr_tsk(uintptr_t index, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
{
(void)arg2;
(void)arg3;
(void)arg4;
TEST_LOG_FMT("[sched_test_tsk] task %d enter", (int)index);
while(!g_testFinish) {
g_task_count[index]++;
}
TEST_LOG_FMT("[sched_test_tsk] task %d finish", (int)index);
return;
}
#if !defined(OS_OPTION_RR_SCHED)
static bool test_check_only_first_task_sched(void) {
if (g_task_count[0] == 0) {
TEST_LOG("[sched_rr] error: task 0 count unchange");
return false;
}
for (int task = 1; task < TASK_NUM; task++) {
if (g_task_count[task] != 0) {
TEST_LOG_FMT("[sched_rr] error: task %d count changed", task);
return false;
}
}
return true;
}
#endif
* 10个同优先级任务,每个任务在循环中加计数
* 每一秒计数都会有变化,测10秒出结果
* (关闭RR功能后,只有第一个任务的计数在增长)
*/
static int test_sched_rr(void)
{
int task, sec;
g_testFinish = 0;
for (task = 0; task < TASK_NUM; task++) {
g_task_prev_count[task] = 0;
g_task_count[task] = 0;
test_start_task_param(test_sched_rr_tsk, 26, OS_TSK_SCHED_RR, task, 0, 0, 0);
}
for (sec = 0; sec < 10; sec++) {
PRT_TaskDelay(OS_TICK_PER_SECOND);
TEST_LOG_FMT("[sched_rr] %d second pass", sec + 1);
#if defined(OS_OPTION_RR_SCHED)
for (task = 0; task < TASK_NUM; task++) {
if (g_task_count[task] <= g_task_prev_count[task]) {
g_testResult = 1;
TEST_LOG_FMT("[sched_rr] error: task %d count unchange for 1 sec", task);
goto EXIT;
}
TEST_LOG_FMT("[sched_rr] task %d, count:%llu", task, g_task_count[task]);
g_task_prev_count[task] = g_task_count[task];
}
#endif
}
#if !defined(OS_OPTION_RR_SCHED)
if (!test_check_only_first_task_sched()) {
g_testResult = 1;
goto EXIT;
}
#endif
EXIT:
g_testFinish = 1;
PRT_TaskDelay(OS_TICK_PER_SECOND / 10);
return g_testResult;
}
* 10个同优先级任务,倒数第二个是FIFO任务,每个任务在循环中加计数
* 前8个任务计数只在第一秒有增长,FIFO任务计数每秒都在增长,最后一个任务计数永远是0,测10秒出结果
* (关闭RR功能后,只有第一个任务的计数在增长)
*/
static int test_sched_rr_fifo(void)
{
int task, sec;
g_testFinish = 0;
for (task = 0; task < TASK_NUM; task++) {
g_task_prev_count[task] = 0;
g_task_count[task] = 0;
if (task == 8) {
test_start_task_param(test_sched_rr_tsk, 26, OS_TSK_SCHED_FIFO, task, 0, 0, 0);
} else {
test_start_task_param(test_sched_rr_tsk, 26, OS_TSK_SCHED_RR, task, 0, 0, 0);
}
}
PRT_TaskDelay(OS_TICK_PER_SECOND);
TEST_LOG("[sched_rr_fifo] 1 seconds pass");
#if defined(OS_OPTION_RR_SCHED)
for (task = 0; task <= 8; task++) {
if (g_task_count[task] == 0) {
TEST_LOG_FMT("[sched_rr_fifo] error: task %d count unchange for 1 sec", task);
goto EXIT;
}
g_task_prev_count[task] = g_task_count[task];
}
if (g_task_count[9] != 0) {
TEST_LOG("[sched_rr_fifo] error: task 9 count changed");
goto EXIT;
}
g_task_prev_count[9] = g_task_count[9];
#endif
for (sec = 1; sec < 10; sec++) {
PRT_TaskDelay(OS_TICK_PER_SECOND);
TEST_LOG_FMT("[sched_rr_fifo] %d seconds pass", sec + 1);
#if defined(OS_OPTION_RR_SCHED)
for (task = 0; task < TASK_NUM; task++) {
if (task == 8 && g_task_count[task] <= g_task_prev_count[task]) {
g_testResult = 1;
TEST_LOG("[sched_rr_fifo] error: task 8 count unchange for 1 sec");
goto EXIT;
} else if (task != 8 && g_task_count[task] != g_task_prev_count[task]) {
g_testResult = 1;
TEST_LOG_FMT("[sched_rr_fifo] error: task %d count changed", task);
goto EXIT;
}
TEST_LOG_FMT("[sched_rr_fifo] task %d, count:%llu", task, g_task_count[task]);
g_task_prev_count[task] = g_task_count[task];
}
#endif
}
#if !defined(OS_OPTION_RR_SCHED)
if (!test_check_only_first_task_sched()) {
g_testResult = 1;
goto EXIT;
}
#endif
EXIT:
g_testFinish = 1;
PRT_TaskDelay(OS_TICK_PER_SECOND / 10);
return g_testResult;
}
#define TEST_REQUIRE 10000
volatile int g_test_count = 0;
volatile U64 g_cycle_before = 0;
volatile U64 g_cycle_after = 0;
volatile U32 g_test_elapse_start = 0;
U32 g_time_consume[TEST_REQUIRE] = {0};
static void test_sched_elapse_tsk(uintptr_t index, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
{
uintptr_t intSave;
(void)arg2;
(void)arg3;
(void)arg4;
int local_count = 0;
TEST_LOG_FMT("[sched_elapse_tsk] task %d enter", (int)index);
intSave = PRT_HwiLock();
while(!g_testFinish && g_test_count < TEST_REQUIRE) {
OsTskReadyDel(RUNNING_TASK);
OsTskReadyAdd(RUNNING_TASK);
g_cycle_before = PRT_ClkGetCycleCount64();
OsTskSchedule();
g_cycle_after = PRT_ClkGetCycleCount64();
if (g_cycle_after <= g_cycle_before) {
PRT_HwiRestore(intSave);
TEST_IF_ERR_RET_VOID_FMT(1, "[sched_elapse_tsk] task %d, cycle before:%llu, cycle after:%llu, local cnt:%d",
(int)index, g_cycle_before, g_cycle_after, local_count);
}
if (g_test_count >= TEST_REQUIRE) {
break;
}
g_time_consume[g_test_count] = (U32)(g_cycle_after - g_cycle_before);
g_test_count++;
local_count++;
}
PRT_HwiRestore(intSave);
g_testFinish = 1;
TEST_LOG_FMT("[sched_elapse_tsk] task %d exit, local cnt:%d", (int)index, local_count);
return;
}
static int test_sched_elapse(void)
{
U32 min = U32_MAX;
U32 max = 0;
U32 sum = 0;
U32 curr;
g_testFinish = 0;
g_testResult = 0;
g_test_elapse_start = 0;
for (int task = 0; task < TASK_NUM; task++) {
test_start_task_param(test_sched_elapse_tsk, 26, OS_TSK_SCHED_RR, task, 0, 0, 0);
}
PRT_TaskDelay(OS_TICK_PER_SECOND);
if (!g_testFinish) {
TEST_LOG("[sched_elapse_tsk] error: main tsk should delay longer");
g_testResult = 1;
}
for (int i = 0; i < TEST_REQUIRE; i++) {
curr = g_time_consume[i];
if (curr < min) {
min = curr;
}
if (curr > max) {
max = curr;
}
sum += curr;
}
TEST_LOG_FMT("[sched_elapse] test finished, max:%u, min:%u, avg:%f", max, min, (sum * 1.0 / TEST_REQUIRE));
return g_testResult;
}
#if defined(OS_OPTION_RR_SCHED)
SemHandle g_testSem;
static void test_sched_timeslice_update_tsk(void)
{
uintptr_t intSave;
U64 startTime, startTimePrev;
U32 timeSlice, timeSlicePrev;
startTimePrev = RUNNING_TASK->startTime;
PRT_TaskDelay(1);
startTime = RUNNING_TASK->startTime;
timeSlice = RUNNING_TASK->timeSlice;
TEST_IF_ERR_RET_VOID((startTime <= startTimePrev), "[sched_timeslice_update] error: startTime not update error");
TEST_IF_ERR_RET_VOID((timeSlice != g_timeSliceCycle), "[sched_timeslice_update] error: timeSlice not update error");
intSave = PRT_HwiLock();
startTimePrev = RUNNING_TASK->startTime;
timeSlicePrev = RUNNING_TASK->timeSlice;
PRT_ClkDelayUs(OS_SYS_US_PER_SECOND / OS_TICK_PER_SECOND);
#if defined OS_OPTION_SMP
OsTaskTrap((uintptr_t)RUNNING_TASK);
#else
OsTaskTrap();
#endif
startTime = RUNNING_TASK->startTime;
timeSlice = RUNNING_TASK->timeSlice;
PRT_HwiRestore(intSave);
TEST_IF_ERR_RET_VOID((startTime <= startTimePrev), "[sched_timeslice_update] error: startTime2 not update error");
TEST_IF_ERR_RET_VOID((timeSlice >= timeSlicePrev), "[sched_timeslice_update] error: timeSlice2 not update error");
intSave = PRT_HwiLock();
startTimePrev = RUNNING_TASK->startTime;
OsTskReadyDel(RUNNING_TASK);
OsTskReadyAdd(RUNNING_TASK);
startTime = RUNNING_TASK->startTime;
timeSlice = RUNNING_TASK->timeSlice;
PRT_HwiRestore(intSave);
TEST_IF_ERR_RET_VOID((startTime != startTimePrev), "[sched_timeslice_update] error: startTime3 not update error");
TEST_IF_ERR_RET_VOID((timeSlice != g_timeSliceCycle),
"[sched_timeslice_update] error: timeSlice3 not update error");
startTimePrev = startTime;
RUNNING_TASK->timeSlice = 100;
PRT_SemPend(g_testSem, 1);
startTime = RUNNING_TASK->startTime;
timeSlice = RUNNING_TASK->timeSlice;
TEST_IF_ERR_RET_VOID((startTime <= startTimePrev), "[sched_timeslice_update] error: startTime4 not update error");
TEST_IF_ERR_RET_VOID((timeSlice != g_timeSliceCycle),
"[sched_timeslice_update] error: timeSlice4 not update error");
g_testFinish = 1;
return;
}
static int test_sched_timeslice_update(void)
{
g_testFinish = 0;
g_testResult = 0;
PRT_SemCreate(0, &g_testSem);
test_start_task((TskEntryFunc)test_sched_timeslice_update_tsk, 24, OS_TSK_SCHED_RR);
while(!g_testFinish) {
PRT_TaskDelay(OS_TICK_PER_SECOND);
}
PRT_SemDelete(g_testSem);
TEST_LOG("[sched_timeslice_update] test finished");
return g_testResult;
}
#define TEST_IRQ_TIME_CONSUME ((OS_SYS_US_PER_SECOND / OS_TICK_PER_SECOND) / 10)
volatile U32 g_irq_cycle_spend = 0;
#if !defined(OS_OPTION_SMP)
extern void OsHwiMcTrigger(U32 coreMask, U32 hwiNum);
#else
extern void OsHwiMcTrigger(enum OsHwiIpiType type, U32 coreMask, U32 hwiNum);
#endif
static void test_sched_irqTime_remove_tsk(void)
{
U64 startTime, startTimePrev;
U32 timeSlice, timeSlicePrev, timeSliceDiff, startTimeDiff;
PRT_TaskDelay(1);
startTimePrev = RUNNING_TASK->startTime;
timeSlicePrev = RUNNING_TASK->timeSlice;
#if !defined(OS_OPTION_SMP)
OsHwiMcTrigger(0xf, OS_HWI_IPI_NO_015);
#else
OsHwiMcTrigger(OS_TYPE_TRIGGER_TO_SELF, 0, OS_HWI_IPI_NO_015);
#endif
PRT_ClkDelayUs(1);
TEST_IF_ERR_RET_VOID((g_irq_cycle_spend == 0), "[sched_irqTime_remove] error: irq not trigger yet!");
startTime = RUNNING_TASK->startTime;
timeSlice = RUNNING_TASK->timeSlice;
TEST_LOG_FMT("[sched_irqTime_remove] startTime:%llu->%llu, timeSlice:%u->%u",
startTimePrev, startTime, timeSlicePrev, timeSlice);
TEST_IF_ERR_RET_VOID((startTime <= startTimePrev), "[sched_irqTime_remove] error: startTime not update error");
TEST_IF_ERR_RET_VOID((timeSlice >= timeSlicePrev), "[sched_irqTime_remove] error: timeSlice not update error");
startTimeDiff = (U32)(startTime - startTimePrev);
timeSliceDiff = (U32)(timeSlicePrev - timeSlice);
TEST_IF_ERR_RET_VOID((startTimeDiff < timeSliceDiff), "[sched_irqTime_remove] error: timeSlice update invalid");
#if defined(OS_OPTION_RR_SCHED_IRQ_TIME_DISCOUNT)
TEST_IF_ERR_RET_VOID((startTimeDiff - timeSliceDiff) < g_irq_cycle_spend,
"[sched_irqTime_remove] error: irqTime not removed?")
#endif
TEST_LOG_FMT("[sched_irqTime_remove] task finished, irq cycle spend:%u, non-task time:%u",
g_irq_cycle_spend, startTimeDiff - timeSliceDiff);
g_testFinish = 1;
return;
}
static void test_sched_irq_handler(void)
{
U64 cycle = PRT_ClkGetCycleCount64();
TEST_LOG("[sched_irqTime_remove] irq enter");
PRT_ClkDelayUs(TEST_IRQ_TIME_CONSUME);
g_irq_cycle_spend = (U32)(PRT_ClkGetCycleCount64() - cycle);
}
static int test_sched_irqTime_remove(void)
{
g_testFinish = 0;
g_testResult = 0;
U32 ret = PRT_HwiSetAttr(OS_HWI_IPI_NO_015, 10, OS_HWI_MODE_ENGROSS);
if (ret != OS_OK) {
return ret;
}
ret = PRT_HwiCreate(OS_HWI_IPI_NO_015, (HwiProcFunc)test_sched_irq_handler, 0);
if (ret != OS_OK) {
return ret;
}
ret = PRT_HwiEnable(OS_HWI_IPI_NO_015);
if (ret != OS_OK) {
return ret;
}
test_start_task((TskEntryFunc)test_sched_irqTime_remove_tsk, 26, OS_TSK_SCHED_RR);
PRT_TaskDelay(OS_TICK_PER_SECOND);
if (!g_testFinish) {
g_testResult = 1;
}
TEST_LOG("[sched_irqTime_remove] test finished");
return g_testResult;
}
#endif
test_case_t g_cases[] = {
TEST_CASE_Y(test_sched_rr),
TEST_CASE_Y(test_sched_rr_fifo),
TEST_CASE_Y(test_sched_elapse),
#if defined(OS_OPTION_RR_SCHED)
TEST_CASE_Y(test_sched_timeslice_update),
TEST_CASE_Y(test_sched_irqTime_remove),
#endif
};
int g_test_case_size = sizeof(g_cases);
void prt_kern_test_end()
{
TEST_LOG("Round Robin Shcedule test finished\n");
}