# linux2023: 819george
## 測驗 α - 1
[Incomplete S-Tree](https://gist.github.com/jserv/4dfaf78cf516cc20f4bc55ce388c195d)
解釋上述程式碼運作原理
S-Tree 的平衡機制與 AVL tree 較為相像利用 hint 來評估是否需要做 rotate ,然而 st_node 的 hint 的計算方式為其左右節點 hint 最大值 +1 並且只有在被呼叫到 st_update 時才會被更新。
## 測驗 β - 1
```cpp
#include <stdint.h>
static inline uintptr_t align_up(uintptr_t sz, size_t alignment)
{
uintptr_t mask = alignment - 1;
if ((alignment & mask) == 0) { /* power of two? */
return ((sz + mask) & ~mask);
}
return (((sz + mask) / alignment) * alignment);
}
```
說明上述程式碼的運作原理
- 一般情況下會用 `(數字+大小-1)/大小` (去掉小數) 再 `*大小` 做到向上對齊。
- 2 的冪用 bit operation 加速
:::danger
「加速」的依據何在?實驗並觀察機械碼指令行為。
:notes: jserv
:::
### 位元運算加速
:::info
利用組合語言觀察
:::
用 `gcc -S -fverbose-asm align_up.c` 編譯
- `-fverbose-asm` C語言變數的名稱作為組合語言裡的註解
align_up.c
```c=
#include <stdint.h>
#include <stddef.h>
int main(){
int sz, alignment;
uintptr_t mask = alignment - 1;
uintptr_t bit,ans;
if ((alignment & mask) == 0) { /* power of two? */
bit = ((sz + mask) & ~mask);
}
ans = (((sz + mask) / alignment) * alignment);
return 0;
}
```
align_up.s
```s
# align_up.c:12: bit = ((sz + mask) & ~mask);
movq -24(%rbp), %rdx # sz, tmp94
movq -32(%rbp), %rax # mask, tmp95
addq %rax, %rdx # tmp95, _2
# align_up.c:12: bit = ((sz + mask) & ~mask);
movq -32(%rbp), %rax # mask, tmp96
notq %rax # _3
# align_up.c:12: bit = ((sz + mask) & ~mask);
andq %rdx, %rax # _2, tmp97
movq %rax, -16(%rbp) # tmp97, bit
.L2:
# align_up.c:14: ans = (((sz + mask) / alignment) * alignment);
movq -24(%rbp), %rdx # sz, tmp98
movq -32(%rbp), %rax # mask, tmp99
addq %rdx, %rax # tmp98, _4
# align_up.c:14: ans = (((sz + mask) / alignment) * alignment);
movl $0, %edx #, tmp101
divq -40(%rbp) # alignment
movq %rax, %rdx # tmp100, _5
# align_up.c:14: ans = (((sz + mask) / alignment) * alignment);
movq -40(%rbp), %rax # alignment, tmp103
imulq %rdx, %rax # _5, tmp102
movq %rax, -8(%rbp) # tmp102, ans
```
組語後綴
* "movb"(byte 8 位元)
* "movw"(word 16 位元)
* "movl"(long 32 位元)
* "movq"(quadword 四字 64 位元)
可以看到用 bit operation 少了兩次的 mov ,有效減少指令次數,節省時間。
## 測驗 β - 2
在 Linux 核心原始程式碼找出類似 align_up 的程式碼,並舉例說明其用法
> bootlin ```/tools/testing/selftests/kvm/include/test_util.h```
```c
/* Aligns x up to the next multiple of size. Size must be a power of 2. */
static inline uint64_t align_up(uint64_t x, uint64_t size)
{
uint64_t mask = size - 1;
TEST_ASSERT(size != 0 && !(size & (size - 1)),
"size not a power of 2: %lu", size);
return ((x + mask) & ~mask);
}
```
將數值向上對齊到指定的倍數
:::danger
解說「如何應用」,不是機械性張貼程式碼,推理和驗證!
:notes: jserv
:::
### 概念
& mask 取補數可以把低位去掉,達到進位效果。
1. 假設要對齊的 size = 4。
1. mask = 3 = 0b0011。
1. ~mask = 0b1100。
1. size 以下位元都變成 0。
舉例
觀察表格 x MSB,直接把 x 和 mask 補數取交集會向下對齊。
向上對齊要再 +mask ,把最高位向上提升一位。
| x | 0b x | x MSB | x+mask | 0b (x+mask) |
| --- | ---- | ---- | ------ | ---------- |
| 5 | 0101 | 0100 | 8 | 1000 |
| 6 | 0110 | 0100 | 9 | 1001 |
| 7 | 0111 | 0100 | 10 | 1010 |
| 8 | 1000 | 1000 | 11 | 1011 |
### 案例
::: info
查找 bootlin `/arch/hexagon/lib/memcpy.S`
:::
Qualcomm hexagon 是一款 DSP 處理器,用在 audio, imaging embedded vision, video and computationally intensive applications。
- 其中的 memcpy.c 根據 八位元對齊做優化
> For blocks less than 16 bytes a byte by byte copy is performed. For 8byte alignments, and length multiples, a dword copy is performed up to 96bytes
直接向下對齊
```c
void * memcpy(char * ptr_out, char * ptr_in, int len) {
u8 offset;
...
offset = ((int) ptr_in) & 7;
ptr8_in = (s64 *) &ptr_in[-offset];
//read in the aligned pointers
```
讓 ptr_in 根據長度 len 複製到 ptr_out ,長度 0 ~ 32 位元內都可以.
> library function for memcpy where length bytes are copied from ptr_in to ptr_out. ptr_out is returned unchanged. Allows any combination of alignment on input and output pointers and length from 0 to 2^32-1
舉例
| 變數 | 數字 | 0b |
|:----------------:|:----:|:---------:|
| ptr_in | 0x13 | 0001 1011 |
| offset | 3 | 0000 0011 |
| &ptr_in[-offset] | 0x10 | 0001 1000 |
## 測驗 γ - 1
[qsort-mt (incomple)](https://gist.github.com/jserv/38bca4ebfea1c434e1dfc15337f80eeb)
解釋上述程式碼運作原理
```c
struct qsort *qs, *qs2 //暫存當前的 thread
struct common c //c.pool 放所有的 thread
```
`qsort_mt`
- 參數: 排序的陣列、元素數量、元素大小、比較函數、最大線程數和分割線程的最小元素數量
`qsort_algo()`
- 個數小於7用插入排序,大於用 quick sort。
- Advanced Quick Sort (Hybrid Algorithm)
`qsort_thread`
- 等所有執行緒空閒,狀態改成工作,開始排序。
- 等到所有都空閒,讓此執行緒可以回到 again 重新排序。
## reference
[2023 年暑期 Linux 核心課程第 1 次測驗/作業檢討](https://hackmd.io/@sysprog/SkmKiSfh2)
[課前測驗參考解答: Q1](https://hackmd.io/@sysprog/bitwise-reverse)