# 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.

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.

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:
- 
- `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/