Skip to content
Snippets Groups Projects
Select Git revision
  • 0ada692defbf30c31b5c2ed37a90c596aebbef6f
  • master default protected
2 results

edf_test.c

Blame
  • edf_test.c 4.75 KiB
    #define _GNU_SOURCE
    
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    
    #include <kselftest.h>
    
    #include <shared.h>
    #include <kmalloc_test_wrapper.h>
    #include <wrap_ktime_get.h>
    
    #include <kernel/kthread.h>
    
    #ifdef printk
    #undef printk
    #define printk(fmt, ...) printk(fmt, ...)
    #endif
    
    
    /* include header + src file for static function testing */
    //#include <kernel/sysctl.h>
    #include <sched/edf.c>
    
    
    static ktime kernel_time;
    static unsigned long tick_period_min_ns = 100000UL;
    
    /* needed dummy functions */
    unsigned long tick_get_period_min_ns(void)
    {
            return tick_period_min_ns;
    }
    
    int sched_register(struct scheduler *sched)
    {
    }
    
    
    /* tests */
    
    
    /*
     * @test sched_edf_init_test
     */
    
    static void sched_edf_init_test(void)
    {
    	KSFT_ASSERT(sched_edf_init() == 0);
    }
    
    
    /*
     * @test sched_edf_create_tasks_test
     */
    
    static void sched_edf_create_tasks_test(void)
    {
    	struct task_struct *t;
    	struct sched_attr attr;
    
    
    	/* create task 1 */
    	t = kmalloc(sizeof(struct task_struct));
    	KSFT_ASSERT_PTR_NOT_NULL(t);
    
    	t->name = kmalloc(32);
    	KSFT_ASSERT_PTR_NOT_NULL(t->name);
    
    	snprintf(t->name, 32, "task_1");
    
    	t->sched = &sched_edf;
    	t->attr.policy       = SCHED_EDF;
    	t->attr.period       = us_to_ktime(1000);
    	t->attr.deadline_rel = us_to_ktime(900);
    	t->attr.wcet         = us_to_ktime(255);
    	edf_enqueue(&t->sched->tq, t);
    
    
    	/* create task 2 */
    	t = kmalloc(sizeof(struct task_struct));
    	KSFT_ASSERT_PTR_NOT_NULL(t);
    
    	t->name = kmalloc(32);
    	KSFT_ASSERT_PTR_NOT_NULL(t->name);
    
    	snprintf(t->name, 32, "task_2");
    
    	t->sched = &sched_edf;
    	t->attr.policy       = SCHED_EDF;
    	t->attr.period       = us_to_ktime(800);
    	t->attr.deadline_rel = us_to_ktime(700);
    	t->attr.wcet         = us_to_ktime(89);
    	edf_enqueue(&t->sched->tq, t);
    
    
    	/* create task 3 */
    	t = kmalloc(sizeof(struct task_struct));
    	KSFT_ASSERT_PTR_NOT_NULL(t);
    
    	t->name = kmalloc(32);
    	KSFT_ASSERT_PTR_NOT_NULL(t->name);
    
    	snprintf(t->name, 32, "task_3");
    
    	t->sched = &sched_edf;
    	t->attr.policy       = SCHED_EDF;
    	t->attr.period       = us_to_ktime(3);
    	t->attr.deadline_rel = us_to_ktime(2);
    	t->attr.wcet         = us_to_ktime(1);
    	edf_enqueue(&t->sched->tq, t);
    
    
    	/* create task 4 */
    	t = kmalloc(sizeof(struct task_struct));
    	KSFT_ASSERT_PTR_NOT_NULL(t);
    
    	t->name = kmalloc(32);
    	KSFT_ASSERT_PTR_NOT_NULL(t->name);
    
    	snprintf(t->name, 32, "task_4");
    
    	t->sched = &sched_edf;
    	t->attr.policy       = SCHED_EDF;
    	t->attr.period       = us_to_ktime(2000);
    	t->attr.deadline_rel = us_to_ktime(900);
    	t->attr.wcet         = us_to_ktime(125);
    	edf_enqueue(&t->sched->tq, t);
    
    
    
    	/* create task 5 */
    	t = kmalloc(sizeof(struct task_struct));
    	KSFT_ASSERT_PTR_NOT_NULL(t);
    
    	t->name = kmalloc(32);
    	KSFT_ASSERT_PTR_NOT_NULL(t->name);
    
    	snprintf(t->name, 32, "task_5");
    
    	t->sched = &sched_edf;
    	t->attr.policy       = SCHED_EDF;
    	t->attr.period       = us_to_ktime(1000);
    	t->attr.deadline_rel = us_to_ktime(900);
    	t->attr.wcet         = us_to_ktime(99);
    	edf_enqueue(&t->sched->tq, t);
    
    }
    
    
    /*
     * @test sched_edf_create_tasks_test
     */
    
    #define CYCLES 20000
    
    static void sched_edf_schedule_test(void)
    {
    	int i;
    	int64_t wake;
    	int64_t slice;
    
    	struct task_struct *next = NULL;
    	struct task_struct *curr = NULL;
    
    
    
    	for (i = 0; i < CYCLES; i++) {
    		curr = next;
    
    		if (curr) {
    			printk("started: %lld now %lld\n", curr->exec_start, ktime_get());
    			/* remove runtime of slice from curr */
    			curr->runtime = ktime_sub(curr->runtime, ktime_sub(ktime_get(), curr->exec_start));
    		}
    
    		edf_wake_next(&sched_edf.tq);
    
    		sched_print_edf_list_internal(&sched_edf.tq, ktime_get());
    
    		next = edf_pick_next(&sched_edf.tq);
    		sched_print_edf_list_internal(&sched_edf.tq, ktime_get());
    
    		if (next) {
    			slice = next->runtime;
    			printk("Next: %s slice %lld\n", next->name, ktime_to_us(slice));
    		} else {
    			slice = 1000000000; /* retry in 1 second */
    			printk("Next: NONE\n");
    		}
    
    		wake = edf_task_ready_ns(&sched_edf.tq);
    		printk("New task ready in %llu\n", ktime_to_us(wake));
    
    		if (wake < slice) {
    			printk("reducing slice from %lld to %lld (%lld)\n", ktime_to_us(slice), ktime_to_us(wake), ktime_to_us(wake - slice));
    			slice = wake;
    		}
    
    
    		/* prepare run: save slice start time */
    		if (next)
    			next->exec_start = ktime_get();
    
    
    
    		/* our timeslice has passed: assume we return in time */
    		kernel_time += slice;
    		printk("\npretending slice of %lld\n", ktime_to_us(slice));
    		ktime_wrap_set_time(kernel_time);
    
    	}
    }
    
    
    
    int main(int argc, char **argv)
    {
    
    	printk("Testing EDF scheduler\n\n");
    
    	/* we need full control over ktime */
    	ktime_get_wrapper(ENABLED);
    
    	KSFT_RUN_TEST("sched_edf_init",
    		      sched_edf_init_test);
    
    	KSFT_RUN_TEST("creating tasks",
    		      sched_edf_create_tasks_test)
    
    	KSFT_RUN_TEST("emulating scheduling cycles",
    		      sched_edf_schedule_test)
    
    
    	printk("\n\nEDF scheduler test complete:\n");
    
    	ksft_print_cnts();
    
    	return ksft_exit_pass();
    }