banner
zam

zam

君子可内敛而不可懦弱,面不公可起而论之。
twitter
telegram
github

第一章 計算機系統漫遊

問題#

  1. 信息的兩個要素。
    位 + 上下文。
  2. 文本文件是有什麼組成的?
    由 ASCII 標準表的字符。
  3. 從源程序到目標程序的四個階段?
    預處理,編譯,匯編,鏈接。
  4. 系統硬件組成的四個部分?
    處理器,主存,I/O 設備,總線。
  5. 從邏輯上看主存是什麼樣的?
    一串線性字節數組,每個字節有唯一的地址。
  6. 主存硬件上是什麼組成的?
    動態隨機存取內存(DRAM)。
  7. 處理器的核心是什麼?它主要幹什麼?
    程序計數器,存儲下一條指令的地址。
  8. 用最簡單的方式描述處理器運行的過程?
    執行 PC 所指向的指令,然後更新 PC。
  9. 指令操作圍繞哪三個部件執行?
    主存,寄存器和 ALU(運算器)。寄存器存放指令、數據、狀態等,ALU 進行運算。
  10. 四個指令操作:加載、存儲、操作、跳轉分別是什麼?
    (1) 加載(Load):這是從內存中將數據加載到寄存器或其他處理器內部的操作。
    (2) 存儲(Store):這是將數據從寄存器或其他處理器內部存儲到內存中的操作。
    (3)操作(Arithmetic/Logical):這涉及到在處理器內部執行算術或邏輯運算的操作。算術操作包括加法、減法、乘法、除法等;邏輯操作涉及位操作,如與、或、非、異或等。
    (4)跳轉(Jump):這是用於改變程序執行順序的操作。
  11. 指令集架構和微體系架構分別是什麼?
    描述指令的效果。硬件的實現方式。
  12. CPU 執行一個目標文件的流程?
    把文件存磁盤讀取到寄存器,再放到主存(直接存取可以實現不經過寄存器),執行目標文件的指令。
  13. 從源程序到得出運行結果的整個流程?
    源程序 -> 目標程序 -> 處理器執行目標程序
  14. 主存比磁盤快多少?寄存器比磁盤快多少?
    千萬倍,百倍。
  15. L1 cache 位於哪裡?有多大?有多快?L2 呢?
    CPU 上,幾十 MB,比 L2 快 5 倍;L2 通過特殊的總線與 CPU 相連,幾百 MB~ 幾 GB,比主存快 5~10 倍。
  16. 高速緩存是怎麼用的?
    存儲需要經常訪問的數據。
  17. 存儲器層次結構有幾層,主要思想是什麼?
    7 層,用上一層做下一層的高速緩存。
  18. 操作系統的三個基本抽象概念是什麼?
    文件、虛擬內存、進程。
  19. 什麼是進程?進程有什麼特點?
    系統正在執行的程序,系統在某一時刻只能執行一個進程。
  20. 什麼是操作系統內核?主要做什麼?
    操作系統常駐主存的部分,負責管理進程的切換,方式是上下文切換。
  21. 什麼是虛擬地址空間?由幾個部分組成?
    進程看到的是一個虛擬的地址空間。從低到高依次是程序代碼和數據、運行時堆、共享庫、用戶棧、內核虛擬內存。
  22. 並發和並行的區別,和順序執行的區別?
    並發是交錯執行,並行是同時進行,順序是執行完一個再執行另一個。
  23. 什麼是線程級並行?
    四個核一個核一個線程就是四線程並行。
  24. 什麼是超線程?
    超線程可以實現一個核兩個線程。因為如 PC、寄存器等硬件有多個備份,可以在一個線程需要等待拷貝的時候執行另一個線程。相當於充分利用硬件交錯執行不同線程。
  25. 什麼是指令級並行?
    一個指令需要 20 多個時鐘周期,並行後一秒可以執行 2~4 個指令。
  26. 什麼是單指令、多數據並行?
    一個指令的幾個簡單操作並行執行(硬件層面)。
  27. 什麼是指令集架構?
    一種抽象,看起來好像是指令順序依次執行,實際上背地裡是指令級並行。

1.1 信息就是位 + 上下文#

程序#

  • 程序的生命周期從 ** 源程序(源文件)** 開始。源程序實際上就是由 0 和 1 組成的位序列
  • 一般由ASCII 標準來表示文本字符,實際上使用一個字節的整數值來表示一種字符。
  • 源文件中每個文本行都是以看不見的 '\n' 結束的。
  • 只由 ASCII 字符組成的文件稱為文本文件,其他都是二進制文件。如.cpp 文件就是文本文件。
  • 系統中的所有信息都是有一串比特(bit:位)表示的,區分不同數據對象的唯一方法就是根據上下文

C 語言的特點#

  1. C 語言小而簡單
  2. C 語言是為了實現 unix 而設計的
  3. C 語言與 unix 關係密切

C 語言是系統級編程的首選,也非常適用於應用級程序。

1.2 程序被其他程序翻譯成不同的格式#

    #include <stdio.h>
    int main(){
        printf("hello, world!\n");
        return 0;
    }

從源程序到目標程序的四個步驟:#

  1. 源程序被預處理器處理得到修改後的源程序(文本文件,hello.i)
  2. 再由編譯器處理得到匯編程序(文本文件,hello.s)
  3. 匯編程序由匯編器處理得到可重定位目標程序(二進制文件,hello.o)
  4. 最後由鏈接器鏈接得到可執行目標程序(二進制文件,hello)
  • 預處理階段:預處理器(cpp)根據以字符 #開頭的命令,修改原始的 C 程序。比如hello.c中第一行的#include <stdio.h>命令告訴預處理器讀取洗頭文件stdio.h的內容,並把它直接插入程序文本中。最終得到另一個 C 程序,通常是以 .i 作為文件擴展名。
  • 編譯階段:編譯器(ccl)將文本文件hello.i翻譯成文本文件hello.s,它包含一個匯編語言程序。該程序包含函數main的定義,如下所示:
    1   main:
    2     subq  $8,  %rsp
    3     movl  $.LC0,  %edi
    4     call  puts
    5     movl  $0,  %eax
    6     addq  $8,  %rsp
    7     ret
  • 匯編階段:接下來,匯編器(as)將hello.s翻譯成機器語言指令,將這些指令打包成一種叫做可重定位目標程序(relocatable object program)的格式,並將結果保存在目標文件hello.o中,hello.o文件是一個二進制文件,它包含的 17 個字節是函數main的指令編碼。
  • 鏈接階段:應該注意的是,hello程序調用了printf函數,它是每個 C 編譯器都提供的標準 C 庫中的一個函數。printf函數存在於一個名為printf.o的單獨預編譯好了的目標文件中。鏈接器(ld)負責將該文件合併到我們的hello.o文件中,最終得到一個可執行目標文件hello文件,可以被加載到內存中,由系統執行。

1.3 了解編譯系統如工作是大有用處的#

用處#

  1. 優化程序性能
  2. 理解鏈接時出現的錯誤
  3. 避免安全漏洞

1.4 處理器讀並解釋儲存在內存中的指令#

shell 是一個命令行解釋器, 它輸出一個提示符(>>), 等待輸入一個命令行,然後執行命令。如果輸入的是可執行文件的名字,就執行該文件。

1.4.1 系統的硬件組成#

主要包括總線、I/O 設備、處理器、主存儲器四個部分。

總線#
  • 總線一次可以傳輸一個定長的字節快,稱為字。64 位系統即總線一次可以傳輸 64 位(8 字節),這裡一個字就是 8 字節。
I/O 設備#
  • 每個 I/O 設備通過一個控制器適配器與 I/O 總線相連。
  • 控制器是 I/O 設備本身或主板上的芯片組,適配器則是一塊插在主板上的卡。
主存#
  • 主存是由一組 ** 動態隨機存取內存(DRAM)** 組成的。
  • 從邏輯上看,存儲器是一個線性的字節數組,每個字節都有唯一的地址
處理器#
  • 處理器是解釋存儲在主存中指令的引擎。
  • 處理器的核心是一個程序計數器(PC)
  • 程序計數器是一個大小為一個字的存儲設備,存儲 CPU 即將執行的下一條指令的地址.
  • 處理器就是在不斷執行程序計數器指向的指令。每執行一條,程序計數器就更新一下,指向下一條指令
  • 處理器會按照指令執行模型(指令集架構) 解釋指令中的位並執行相應操作
  • 每條指令的操作是圍繞主存、寄存器文件、算術邏輯單元(ALU) 進行的。
寄存器文件#
  • 單個字長,有唯一的名字。
ALU#
  • 簡單指令的操作:
    • 加載:從主存複製一個字或字節到寄存器,覆蓋原來內容。
    • 存儲:從寄存器複製一個字或字節到主存,覆蓋原來內容。
    • 操作:把兩個寄存器的內容複製到 ALU,ALU 對這兩個字做算術運算,並把結果存到一個寄存器中。
    • 跳轉:從指令中抽取一個字複製到程序計數器中,覆蓋原來內容。

區分處理器指令集架構和微體系架構

  • 指令集架構:每條機器指令的效果。
  • 微體系架構:處理器實際上是如何實現的。

1.4.2 運行 hello 程序#

  • 執行目標文件時,shell 程序將位於磁盤目標文件中的字符逐個讀入寄存器,然後放到主存中。之後處理器就開始執行目標文件的機器語言指令,從mian程序開始。利用直接存儲器存取(DMA) 可以不通過寄存器,直接將數據從磁盤讀到內存。
  • 整個流程讀取文件字符到寄存器 -> 存儲到主存 -> 執行指令 -> 加載hello wolrd到寄存器 -> 複製到顯示器 -> 顯示

1.5 高速緩存至關重要#

  • 從主存讀取一個字比磁盤快 1000 萬倍
  • 從寄存器文件讀取比主存快 100 倍
  • 高速緩存(cache)用來解決處理器和主存間的差異
  • L1 高速緩存位於 CPU 上,容量為數萬字節(幾十 MB)。L1 比 L2 快 5 倍。
  • L2 高速緩存通過一條特殊的總線與 CPU 連接,容量為數十萬到數百萬字節(幾百 MB 到幾 GB)。L2 比主存快5~10倍。
  • 通過讓高速緩存裡存放可能經常訪問的數據,讓大部分的內存操作都在高速緩存中完成。

1.6 存儲設備形成層析結構#

  • 存儲器結構共 7 層,主要思想上一層的存儲器作為低一層的高速緩存。
  • 從上到下,容量更大,運行更慢,每字節價格更便宜。
    • 0 層:寄存器
    • 1 層:L1 高速緩存(SRAM)
    • 2 層:L2 高速緩存 (SRAM)
    • 3 層:L3 高速緩存(SRAM)
    • 4 層:主存(DRAM)
    • 5 層:本地二級存儲(本地磁盤)
    • 6 層:遠程二級存儲(分佈式文件系統,Web 伺服器)

1.7 操作系統管理硬件#

  • 操作系統的兩個基本功能
    1. 防止硬件被失控的應用程序濫用。
    2. 向應用程序提供簡單一致的機制來控制複雜的低級硬件設備
  • 操作系統所應用的三個基本的抽象概念
    1. 進程:對處理器、主存和 I/O 設備的抽象表示。
    2. 虛擬內存:對內存和磁盤的抽象表示。
    3. 文件:對 I/O 設備的抽象表示。

1.7.1 進程#

  • 進程:對操作系統正在運行的程序的一種抽象。
  • 並發運行:一個進程的指令和另一個進程的指令是交錯執行的。一個系統可以同時運行多個進程,實際上這些進程是並發運行的。
  • 操作系統通過上下文切換來實現並發運行。上下文是跟蹤進程運行所需的所有狀態信息,可能存在於 PC、寄存器文件、主存等地方。
  • 任何時刻,單處理只能執行一個進程的代碼
  • 操作系統內核操作系統代碼常駐內存的部分,從一個進程到另一個進程的轉換是由內核管理的
  • 內核不是一個獨立的進程,是一系列代碼和數據結構的集合。
  • 當應用程序需要操作系統的某些操作時,就把控制權傳遞給內核,內核完成操作後返回應用程序。

1.7.2 線程#

  • 一個進程是由多個線程組成,每個線程都運行在進程的上下文中,共享同樣的代碼和全局數據
  • 多線程之間比多進程之間更容易共享數據,且線程一般來說比進程更高效。

1.7.3 虛擬內存#

  • 機器程序將內存視為一個龐大的字節數組,稱為虛擬內存
  • 內存的每個字節由地址來標識,所有可能地址的集合就是虛擬地址空間
  • 虛擬內存使每個進程都以為自己獨佔了主存。每個進程看到的內存都是一致的,即虛擬地址空間
  • 在 Linux 中,每個進程看到的虛擬地址空間由以下幾個部分組成:
    1. 程序代碼和數據
    2. 堆(運行時堆)
    3. 共享庫
    4. 棧(用戶棧)
    5. 內核虛擬內存
  • 地址從低到高,最高層的內核虛擬內存保存的是操作系統中的代碼和數據,這部分每個進程都一樣
  • 程序代碼和數據:對所有進程來說,代碼都是從同一個固定地址開始,緊接著是與全局變量對應的數據區。代碼和數據區都是按照可執行文件的內容初始化的。代碼和數據區在進程開始運行時就被指定了大小
  • :運行時堆是根據mallocfree函數的調用在運行時動態地擴展和收縮的
  • 共享庫:地址空間的中間部分用來存放共享庫的代碼和數據。如 C 標準庫、數學庫等都屬於共享庫
  • :用戶棧和堆一樣,在程序執行期間可以動態地擴展和收縮,編譯器用它來實現函數調用。當調用函數時,棧增長,從函數返回時,棧收縮

1.7.4 文件#

  • 文件就是字節序列,僅此而已。
  • 每個 I/O 設備,包括磁盤、鍵盤、顯示器、網絡,都可以看成是網絡

1.8 系統之間利用網絡通信#

  • 從一個單獨的系統而言,網絡可以視為一個 I/O 設備
    + 以在一個遠端伺服器運行程序為例,在本地輸入,在遠端執行,執行結果發送回本地輸出。

1.9 主要主題#

1.9.1 Amdahl 定律#

  • Amdahl 定律的主要觀點:要加速整個系統,必須是提升全系統中相對大的部分。

1.9.2 並發和並行#

  • 區分並發與並行:
    • 並發:一個通用的概念,指一個同時具有多個活動的系統
    • 並行:用並發來使系統運行得更快
  • 並行可以在多個抽象層次上運用。從高到低有以下三個層次:
  1. 線程級並行
    • 傳統意義上的並發執行是通過單處理器在進程間快速切換模擬出來的。
    • 多處理器系統由一個操作系統控制多個 CPU。結構如下

高速緩存

  • L1 高速緩存被分為兩個部分: 一個保存最近取到的指令,一個存放數據。
  • 超線程又稱同時多線程,它允許一個 CPU 執行多個控制流。 CPU 有的硬件有多個備份,比如程序計數器和寄存器文件,而其他硬件只有一份,比如浮點算術運算單元。常規 CPU 需要約 ** 20000** 個時鐘周期來切換線程,超線程 CPU 可以單個周期的基礎上切換線程,比如一個線程在等待數據裝在到高速緩存,CPU 就可以去執行另一個線程。
  • i7 處理器每個核執行兩個線程,所以是** 4 核 8 線程 **,8 個線程都並行執行。
  1. 指令級並行
    • 每條指令從開始到結束一般需要 20 個或更多的時鐘周期,通過指令級並行,可以實現每個周期 2~4 條指令的執行速率。
    • 如果比一個周期一條指令更快,就稱為超標量處理器,現在一般都是超標量。
  2. 單指令、多數據並行
    • 在最低層次上,現代處理器允許一條指令產生多個可以並行執行的操作,稱為單指令、多數據並行,即 SIMD 並行。

1.9.3 計算機系統中抽象的重要性#

操作系統的抽象

  • 指令集架構是對 CPU 硬件的抽象,CPU看起來像一次只執行機器代碼程序的一條指令,實際上底層硬件並行地執行多條指令
  • 虛擬機是對整個計算機系統的抽象,包括操作系統、處理器和程序。
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。