1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Preempt / IRQ disable delay thread to test latency tracers 4 * 5 * Copyright (C) 2018 Joel Fernandes (Google) <joel@joelfernandes.org> 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/interrupt.h> 10 #include <linux/irq.h> 11 #include <linux/kernel.h> 12 #include <linux/kthread.h> 13 #include <linux/ktime.h> 14 #include <linux/module.h> 15 #include <linux/printk.h> 16 #include <linux/string.h> 17 18 static ulong delay = 100; 19 static char test_mode[10] = "irq"; 20 21 module_param_named(delay, delay, ulong, S_IRUGO); 22 module_param_string(test_mode, test_mode, 10, S_IRUGO); 23 MODULE_PARM_DESC(delay, "Period in microseconds (100 uS default)"); 24 MODULE_PARM_DESC(test_mode, "Mode of the test such as preempt or irq (default irq)"); 25 26 static void busy_wait(ulong time) 27 { 28 ktime_t start, end; 29 start = ktime_get(); 30 do { 31 end = ktime_get(); 32 if (kthread_should_stop()) 33 break; 34 } while (ktime_to_ns(ktime_sub(end, start)) < (time * 1000)); 35 } 36 37 static int preemptirq_delay_run(void *data) 38 { 39 unsigned long flags; 40 41 if (!strcmp(test_mode, "irq")) { 42 local_irq_save(flags); 43 busy_wait(delay); 44 local_irq_restore(flags); 45 } else if (!strcmp(test_mode, "preempt")) { 46 preempt_disable(); 47 busy_wait(delay); 48 preempt_enable(); 49 } 50 51 return 0; 52 } 53 54 static int __init preemptirq_delay_init(void) 55 { 56 char task_name[50]; 57 struct task_struct *test_task; 58 59 snprintf(task_name, sizeof(task_name), "%s_test", test_mode); 60 61 test_task = kthread_run(preemptirq_delay_run, NULL, task_name); 62 return PTR_ERR_OR_ZERO(test_task); 63 } 64 65 static void __exit preemptirq_delay_exit(void) 66 { 67 return; 68 } 69 70 module_init(preemptirq_delay_init) 71 module_exit(preemptirq_delay_exit) 72 MODULE_LICENSE("GPL v2"); 73