# Linux Lab 3 report ###### tags: `linux`, `linux-2022-autumn` ## Task 1 > Requierment: > Write a new system call int get_CPU_number() so that a process can use it to get the number of the CPU that executes it. ![](https://i.imgur.com/xpHXax1.png =x100) If we look close enough, we can see a variable called `unsigned int cpu` in `task_struct` ```c struct task_struct { ... /* Current CPU: */ unsigned int cpu; ... ``` ### Result ```bash ❯ gcc test1.c && ./a.out 10 10 10 11 11 11 11 11 11 11 ``` > 嘗試多跑幾次後,結果都在 0~11 之間。而我的 CPU 是 6 核 12 執行序,因此是合理的結果 > 根據執行結果我們可以發現一 process 會盡量不換去其他 cpu,猜測是因為 cache 的機制關西。 ## Task 2 > Write a new system call start_to_count_number_of_process_switches() so that a process can use it to begin to count the number of process switches the process makes. Besides, write another new system call int stop_to_count_number_of_process_switches() so that a process can use it to stop to count the number of process switches the process makes and return the number of process switches the process makes. ![](https://i.imgur.com/0K8lgPQ.png =200x) switch_cnt 加在 `task_struct` 最後面 switch_to 去改 :::spoiler arch/x86/include/asm/switch_to.h ```c struct task_struct *__switch_to_asm(struct task_struct *prev, struct task_struct *next); ... #define switch_to(prev, next, last) \ do { \ ((last) = __switch_to_asm((prev), (next))); \ } while (0) ``` ::: :::spoiler arch/x86/entry/entry_64.S ```asm SYM_FUNC_START(__switch_to_asm) /* * Save callee-saved registers * This must match the order in inactive_task_frame */ pushq %rbp pushq %rbx pushq %r12 pushq %r13 pushq %r14 pushq %r15 /* switch stack */ movq %rsp, TASK_threadsp(%rdi) movq TASK_threadsp(%rsi), %rsp #ifdef CONFIG_STACKPROTECTOR movq TASK_stack_canary(%rsi), %rbx movq %rbx, PER_CPU_VAR(fixed_percpu_data) + stack_canary_offset #endif /* * When switching from a shallower to a deeper call stack * the RSB may either underflow or use entries populated * with userspace addresses. On CPUs where those concerns * exist, overwrite the RSB with entries which capture * speculative execution to prevent attack. */ FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW /* restore callee-saved registers */ popq %r15 popq %r14 popq %r13 popq %r12 popq %rbx popq %rbp jmp __switch_to SYM_FUNC_END(__switch_to_asm) ``` ::: :::spoiler arch/x86/kernel/process_64.c ```c /* * switch_to(x,y) should switch tasks from x to y. * * This could still be optimized: * - fold all the options into a flag word and test it with a single test. * - could test fs/gs bitsliced * * Kprobes not supported here. Set the probe on schedule instead. * Function graph tracer not supported too. */ __visible __notrace_funcgraph struct task_struct * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) { if (prev_p->switch_cnt_switch) { prev_p->switch_cnt += 1; } ... ``` ::: ### Result #### CPU-bound :::spoiler code ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #define SYS_N_START 452 #define SYS_N_STOP 453 unsigned long long fib(unsigned long long n) { if (n <= 1) { return 1; } else { return fib(n-1) + fib(n-2); } } int main() { struct timespec ts; ts.tv_nsec = 1000; ts.tv_sec = 0; long retval = 0; unsigned long long b = 1; syscall(SYS_N_START); for (int i = 0; i < 10000; i++) { nanosleep(&ts, &ts); b = fib(26); } printf("%llu\n", b); retval = syscall(SYS_N_STOP); printf("\n\nnum: %ld\n", retval); return 0; } ``` ::: </br> **Result** ```bash ❯ gcc ./cpu-bound.c && ./a.out 196418 num: 10021 ``` </br> #### IO-bound :::spoiler code ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #define SYS_N_START 452 #define SYS_N_STOP 453 int main() { struct timespec ts; ts.tv_nsec = 1000; ts.tv_sec = 0; long retval = 0; int b = 1; syscall(SYS_N_START); for (int i = 0; i < 1000000; i++) { printf("%d", b++); fflush(stdout); nanosleep(&ts, &ts); } retval = syscall(SYS_N_STOP); printf("\n\nnum: %ld\n", retval); return 0; } ``` ::: </br> **Result** ```bash ❯ gcc ./io-bound.c && ./a.out num: 1000034 ``` </br> </br> ## 問題準備 - what is switch_to, prev, next - what is `last` :thinking_face: - ![](https://i.imgur.com/N7J9keR.png) - `last` is last prev !!! :confetti_ball: - TASK_threadsp - what is role of sp register ?? - THE rsp register ?? - definition of cpu_number - per cpu - run queue 中有 cpu info, 因此只要知道自己在哪個 run queue 就知道 cpu - TLS - thread load storge - pointer to `struct pthread` - cs, ds, es, ss, fs, gs - cs: code segment - ds: Data segment - es: estination segment - ss: stack segment - fs: TLS entry - gs: TLS entry - switch PDA, FPU context - on_cpu, cpu, recent_used_cpu, wake_cpu ## TODO - project 1 重跑 - 也許有些 vma 是 kernel 的 stack/heap ### after number of run queue systrace perf </br> </br> ## Reference - https://liujunming.top/2018/11/20/%E8%BF%9B%E7%A8%8B%E5%88%87%E6%8D%A2switch-to%E5%AE%8F%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0%E5%88%86%E6%9E%90/