- kernel space
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/resource.h>
#include <asm/errno.h>
SYSCALL_DEFINE2(get_number_of_context_switches, pid_t, pid, unsigned int *, number_of_context_switches) {
struct task_struct *task;
struct rusage ru;
unsigned int ncsw;
task = find_task_by_vpid(pid);
if (!task) {
return -ESRCH;
}
getrusage(task, RUSAGE_SELF, &ru);
printk("---\n");
printk("task->nvcsw: %ld\n", task->nvcsw);
printk("task->nivcsw: %ld\n", task->nivcsw);
printk("task->signal->nvcsw: %ld\n", task->signal->nvcsw);
printk("task->signal->nivcsw: %ld\n", task->signal->nivcsw);
printk("task->last_switch_count: %ld\n", task->last_switch_count);
printk("ru.ru_nvcsw: %ld\n", ru.ru_nvcsw);
printk("ru.ru_nivcsw: %ld\n", ru.ru_nivcsw);
ncsw = ru.ru_nvcsw + ru.ru_nivcsw;
if(copy_to_user(number_of_context_switches, &ncsw, sizeof(unsigned int))) {
return -EFAULT;
}
return 0;
}
- user space
#include <stdio.h>
#include <syscall.h>
#include <unistd.h>
#define NUMBER_OF_ITERATIONS 99999999
#define __NR_get_number_of_context_switches 450
int main()
{
int i, t = 2, u = 3, v;
pid_t pid = getpid();
int nvcw;
for (i = 0; i < NUMBER_OF_ITERATIONS; i++)
v = (++t) * (u++);
if (syscall(__NR_get_number_of_context_switches, pid, &nvcw))
printf("Error!\n");
else
printf("This process encounters %u times context switches.\n", nvcw);
// getchar(); // cat /proc/PID/sched to validate the result
return 0;
- context switch有兩個情況 分別被兩個變數所記著
- nvcsw
- nivcsw
- kernel space
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/resource.h>
#include <asm/errno.h>
SYSCALL_DEFINE2(get_number_of_entering_a_wait_queue, pid_t, pid, unsigned int *, number_of_entering_a_wait_queue)
{
struct task_struct *task;
unsigned int newq;
task = find_task_by_vpid(pid);
if (!task)
{
return -ESRCH;
}
printk("---\n");
printk("task->enter_queue_count: %d\n", task->enter_queue_count);
newq = task->enter_queue_count;
if (copy_to_user(number_of_entering_a_wait_queue, &newq, sizeof(unsigned int)))
{
return -EFAULT;
}
return 0;
}
- user space
#include <stdio.h>
#include <syscall.h>
#include <unistd.h>
#define NUMBER_OF_IO_ITERATIONS 6
#define NUMBER_OF_ITERATIONS 99999999
#define __NR_get_number_of_context_switches 450
#define __NR_get_number_of_entering_a_wait_queue 451
int main()
{
char c;
int i, t = 2, u = 3, v;
unsigned int w;
pid_t pid = getpid();
for (i = 0; i < NUMBER_OF_IO_ITERATIONS; i++)
{
v = 1;
c = getchar();
}
for (i = 0; i < NUMBER_OF_ITERATIONS; i++)
v = (++t) * (u++);
if (syscall(__NR_get_number_of_context_switches, pid, &w) != 0)
printf("Error (1)!\n");
else
printf("This process encounters %u times context switches.\n", w);
if (syscall(__NR_get_number_of_entering_a_wait_queue, pid,&w) != 0)
printf("Error (2)!\n");
else
printf("This process enters a wait queue %u times.\n", w);
for (i = 0; i < NUMBER_OF_IO_ITERATIONS; i++)
{
v = 1;
c = getchar();
}
for (i = 0; i < NUMBER_OF_ITERATIONS; i++)
v = (++t) * (u++);
for (i = 0; i < NUMBER_OF_IO_ITERATIONS; i++)
{
v = 1;
printf("I love my home.\n");
}
if (syscall(__NR_get_number_of_context_switches, pid, &w) != 0)
printf("Error (3)!\n");
else
printf("This process encounters %u times context switches.\n", w);
if (syscall(__NR_get_number_of_entering_a_wait_queue, pid,&w) != 0)
printf("Error (4)!\n");
else
printf("This process enters a wait queue %u times.\n", w);
}
:::danger Fail histroy :::
default_wake_function-> try_to_wake_up->ttwu_queue-> ttwu_do_active-> ttwu_do_wake_up :::success Success history ::: copt_thread in v5.14.9
-
把2000多次持續遞增的原因清掉,原本以為是要在狀態圖中的fork清除task_struct的狀態,但是搞錯了方向,要在copy_thread的時候才把task_struct()清0,這樣才可以準確印出實際enter queue的次數
-
在執行999999 entering wait queue的時候他會因為priority order變小 所以被context switch掉
-
在執行I/O的時候 只要輸入有換行 process就會進行wake up 到TASK_RUNNING狀態然後再到current 發現到仍然要等待使用者輸入 所以又會被丟回去wait_queue進行等待(只要輸入多一行 enter queue就會多一次 ![ ](https://i.imgur.com/El3QwBd.png =600x)
-
只有default的6次getchar()+999999次迴圈,沒有額外的getchar()輸入
-
除了default的6次getchar()+999999次迴圈,還多用了6次getchar(),輸入1行
-
除了default的6次getchar()+999999次迴圈,還多用了6次getchar(),輸入2行
-
除了default的6次getchar()+999999次迴圈,還多用了6次getchar(),輸入3行
-
除了default的6次getchar()+999999次迴圈,還多用了6次getchar(),輸入1行+第二個999999次迴圈