動機

都買了就讀一下

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的時間
        • strace -T: 顯示proc所執行的每個sys call與花了多少時間
        • ldd: 看exe有link到哪些lib

ch3

  • fork, execve: skip here
  • exe info
    • exe的結構有三個部分
      • info: 在linux是elf,會有很多資訊但對exe的結構來說重要的是
        • 每個部份的
          • 起點addr (fake addr)
          • 長度
          • mapping後的起點addr (real addr)
        • entry point
      • code
      • data
    • 一些指令
      • readelf -S: 可以拿到起點addr與長度
      • cat /proc/<pid>/maps: 可以看proc的memory mapping

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
    • 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
    • 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數量變少
    • 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就是真的沒了
  • 一些指令
    • 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
    • 一些指令
      • /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 stat
      • sat -B: page in/out
      • sysctl vm.dirty_...
      • echo 3 > /proc/sys/vm/drop_cache: remove all cache
  • hyper thread
    • proc state的變化大概像
      • run(a) | sleep | run(c) | sleep
    • 如果有多的reg的話可以在sleep時讓cpu當成一顆新的cpu去跑其他proc
    • 所以,hyper thread就是保留一部份reg(一半),把cpu當成兩顆用

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
            • 這是可以選擇砍其中一條或是兩條都砍
  • 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來改寫檔案內容
  • 其他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: 順便把其他的附近的也一起讀出來
  • SSD
    • 隨著IO單位數的上升
      • throughput上升
      • IO scheduler的增益越來越不明顯,甚至損害效能
  • 結論
    • 一次讀多一點,資料量大沒關係
    • 次數越少越好
    • 在HDD與SSD,seq去讀寫的效能都是最好的,資料最好存在連續的區塊