動機
都買了就讀一下
ch1
- cpu至少有兩種模式
- user mode
- kernel mode: 可以access所有記憶體
ch2
- sys call
- 目的: 讓user space的proc調用kernel space的功能,以操作或取得底層的資源
- 用eval+apply的interp的角度去看,sys call就像primitive opertor
- proc, mem, file, IPC, network, IO, time, ….
- 過程:
- 塞sys call的編號到reg
- 發中斷(trap)
- cpu切到kernel mode
- 請cpu跑sys call
- cpu根據sys call的數字去看表
- cpu跑kernel寫好的對應的handler
- 丟return 值,轉回去user mode
- 一些指令
sar -P ALL 1
: (mpstat) 可以看cpu的load- user% + nice%: cpu是執行在user space的時間佔比
- user%: 就是一般的proc跑的
- nice%: 有被調過nice有特權的proc所跑的時間
- sys%: cpu是執行在kernel space的時間佔比,也就是跑sys call的時間
- user% + nice%: cpu是執行在user space的時間佔比
strace -T
: 顯示proc所執行的每個sys call與花了多少時間ldd
: 看exe有link到哪些lib
- 目的: 讓user space的proc調用kernel space的功能,以操作或取得底層的資源
ch3
- fork, execve: skip here
- exe info
- exe的結構有三個部分
- info: 在linux是elf,會有很多資訊但對exe的結構來說重要的是
- 每個部份的
- 起點addr (fake addr)
- 長度
- mapping後的起點addr (real addr)
- entry point
- 每個部份的
- code
- data
- info: 在linux是elf,會有很多資訊但對exe的結構來說重要的是
- 一些指令
readelf -S
: 可以拿到起點addr與長度cat /proc/<pid>/maps
: 可以看proc的memory mapping
- exe的結構有三個部分
ch4
- proc scheduler:
- round-robin
- 1個cpu只會跑1個proc
- 每個proc都享有相同的時間去分cpu(沒nice的話)
- 有nice的proc分到的cpu時間會比較多
- 在書中有一個程式是會fork多個proc(work load都一樣)去看分到的時間與執行狀況
- 總執行時間隨fork出的proc變多而跟著上升
- 因為throughput不變,故隨著proc數上升,proc的latency(end_time-start_time)也會上升
- 多cpu時會把proc往最少proc的cpu塞
- 一些指令
tasklet -c <cpuid> <cmd>
: 強制cmd跑在cpuid的cpu上time ...
- proc state的變化大概像
run(a) | sleep | run(c) | sleep
- real: end_time-start_time
- user: user space
- sys: kernel space
- user+sys就是把所有run時間加起來
- proc state的變化大概像
- round-robin
- proc state
- executing
- waiting
- sleeping
- D: wait IO
- S: wait signal
- zombie
ch5
- virtual mem
- purpose:
- proc isolation
- C有ptr可以亂指,有virtual mem就指不出去
- 不過如果沒有ptr是不是就可以不用virtual mem?
- avoid mem fragment
- support of multiple procs
- proc isolation
- implement: page table
- 可以當成一個存在於kernel的函數,all fake addr -> all real addr
- demang page: lazy evaluation
- 直到proc寫入時kernel才去找一個real addr
- malloc是從先拿到的mem pool中拿addr,但mmap是sys call就是直接拿
- table太大了
- 階層式page table
- 從list變成tree,all fake addr -> (another table OR all real addr)
- huge page
- 把page的單位變大,讓table的item數量變少
- 階層式page table
- file mapping: 把file複製到mem操作,最後在適當的時候把對file的改動寫回去
- copy-on-write: 在fork時parent與child proc共用相同的Page,當其中一方改動時才複製新的,並把fake addr指到新的page上
- 在算proc使用的mem時會各自顯示所以佔有的mem,但是因為copy-on-write實際上的mem使用量沒那麼多
- swap
- swap-in: mem -> swap(hdd)
- swap-out: mem <- swap(hdd)
- 持續 swap-in & swap-out: thrashing
- VSS & RSS
- fake mem usage & real mem usage
- 都有用完的機會,VSS是當table不夠時,RSS就是真的沒了
- purpose:
- 一些指令
free
- total: 插了多少記憶體
- buff: 緩衝快取 (使用緩衝記憶體的快取)
- cache: 分頁快取 (使用kernel space記憶體去快取file的快取)
- avail: kernel space與user space的可以用的mem總和
ch6
- cache mem
- 裡面就是一張表
- name
- val
- is_dirty
- localty: time & space
- 讓proc同一時間使用的mem越少越好
- transition lookaside buffer
- proc取值要
- 從fake addr換real addr
- 從real addr換值 (有cache的機會)
- 從fake addr換real addr是記憶體即便後面有cache主要的overhead還是吃在第一個
- 所以多一個buffer來把fake addr換成val
- proc取值要
- 一些指令
/sys/system/cpu/cpu<i>/cache/index<j>
- type: data, code, unified
- shared_cpu_list
- size: total mem
- coherency_line_size: unit size
- 裡面就是一張表
- page cache
- 把file讀到kernel的mem去cahce
- 所以在第一次之後的讀寫,不會每次都跑到HDD去(page in(HDD->mem)/out(mem->HDD)沒有上升)
- 寫就會由kernel處理dirty的部分來做
- 一些指令
sar -d -p
: HDD statsat -B
: page in/outsysctl vm.dirty_...
echo 3 > /proc/sys/vm/drop_cache
: remove all cache
- 把file讀到kernel的mem去cahce
- hyper thread
- proc state的變化大概像
run(a) | sleep | run(c) | sleep
- 如果有多的reg的話可以在sleep時讓cpu當成一顆新的cpu去跑其他proc
- 所以,hyper thread就是保留一部份reg(一半),把cpu當成兩顆用
- proc state的變化大概像
ch7
- file system
- 一定會有
- name
- offset
- len
- 是不是很熟悉?
- 在exe info也有看過一樣的東西
- 其實就是把會記憶的東西當成一條常常的帶子(圖靈機)
- 但這樣不會有問題嗎?
- 特性
- 是一顆tree (從root開始)
- 有data與metadata
- 權限
- file size
- timestamp
- quota
- user, folder, sub-disk(brtfs)
- inconsistent
- 從a的link改成b的link
- 加一條到b的link
- 把原本的a的link刪掉 (在這裡斷電)
- sol
- 日誌
- 在做事前先寫下步驟,在一步一步做
- 寫完步驟前出事 => old tree
- 做到一半出事 => redo, new tree
- 在做事前先寫下步驟,在一步一步做
- copy-on-write (persistent data structrue)
- 每次的新增都是用新的位置
- 做到一半出事 => old tree
- 每次的新增都是用新的位置
- fsck
- 找出inconsistent做處理
- 像在加一條到b的link出事會出現兩條link
- 這是可以選擇砍其中一條或是兩條都砍
- 找出inconsistent做處理
- 日誌
- 從a的link改成b的link
- 一定會有
- device file
- type
- character
- 沒有seek,也就是沒有隨機讀取
- 可以寫字元與讀字元
- 用
ps
可以看到bash的/dev/pts/<n>
- 可以用
echo <cmd> > /dev/pts/<n>
與# <cmd>
一樣
- 可以用
- block
- 可以當成記憶體
- 用
mount
- 額外提一個
mount --bind olddir newdir
- 這是把現有的folder連到另一個folder去,olddir的path依舊,但內容是newdir
- 可以用在olddir無法改變屬性時
- 額外提一個
strings -t -x
可以把block dev的資料用string倒出來with addr- 所以可以配合
dd if=override_file of=/dev/sda1 seek=$((<addr>)) bs=1
來改寫檔案內容
- 所以可以配合
- character
- type
- 其他fs
- brtfs 大約等於 lvm+ext4
- procfs
/proc/<pid>
- maps
- cmdline
- stat
/proc
- cpuinfo, diskstat, meminfo
/proc/sys/
- sysctl
- sysfs
/sys
- devices
- fs
- tmpfs, cgroupfs, nfs
ch8
- HDD
- 轉動很慢
- IO scheduler: 在把req送到driver前
- merge: 一次讀多一點
- sort: 變成seq讀取
- preread: 順便把其他的附近的也一起讀出來
- IO scheduler: 在把req送到driver前
- 轉動很慢
- SSD
- 隨著IO單位數的上升
- throughput上升
- IO scheduler的增益越來越不明顯,甚至損害效能
- 隨著IO單位數的上升
- 結論
- 一次讀多一點,資料量大沒關係
- 次數越少越好
- 在HDD與SSD,seq去讀寫的效能都是最好的,資料最好存在連續的區塊