if x = 0
compute_this()
else
compute_that()
function factorial(n)if n > 1return factorial(n - 1) * nelsereturn 1function factorial(n)result ← 1while n > 1result ← result * nn ← n - 1return result誠然,在不使用遞歸的情況下執行factorial 函數將消耗較少的計算資源,但仍然沒有理由因此而改變代碼。現代編譯器將自動重寫簡單的遞歸函數,舉例如下。
為避免進行兩次x+y 計算,編譯器將上述代碼重寫為:t1 ← x + yi ← t1 + 1j ← t1應專注於編寫清晰且自解釋的代碼。如果性能出現問題,可以利用分析工具尋找代碼中的瓶頸,並嘗試改用更好的方法計算存在問題的代碼。此外,避免在不必要的微操作上浪費太多時間。但在某些情況下,我們希望跳過編譯,接下來將對此進行討論。某些語言在執行時並未被直接編譯為機器碼,這些語言稱為腳本語言,包括JavaScript、Python 以及Ruby。在腳本語言中,代碼由解釋器而非CPU 執行,解釋器必須安裝在運行代碼的機器中。解釋器實時轉譯並執行代碼,因此其運行速度通常比編譯後的代碼慢得多。但另一方面,程式設計師隨時都能立即運行代碼而無須等待編譯過程。Google 工程師必須不斷編譯大量代碼,導致程式設計師「損失」了很多時間(圖7-9)。由於需要保證編譯後的二進位文件有更好的性能,Google 無法切換到腳本語言。公司為此開發了Go 語言,它的編譯速度極快,同時仍然保持很高的性能。給定一個已編譯的電腦程式,無法在編譯之前恢復其原始碼。但我們可以對二進位程序解碼,將用於編碼CPU 指令的數字轉換為人類可讀的指令序列。這個過程稱為反彙編。接下來,可以查看這些CPU 指令,並嘗試分析它們的用途,這就是所謂的逆向工程。某些反彙編程序對這一過程大有裨益,它們能自動檢測並注釋系統調用與常用函數。藉由反彙編工具,黑客對二進位代碼的各個環節了如指掌。我相信,許多頂尖的IT 公司都設有秘密的逆向工程實驗室,以便研究競爭對手的軟體。地下黑客經常分析Windows、Photoshop、《俠盜獵車手》等授權程序中的二進位代碼,以確定哪部分代碼負責驗證軟體許可證。黑客將二進位代碼修改,在其中加入一條指令,直接跳轉到驗證許可證後執行的代碼部分。運行修改後的二進位代碼時,它在檢查許可證前獲取注入的JUMP 命令,從而可以在沒有付費的情況下運行非法的盜版副本。在秘密的政府情報機構中,同樣設有供安全研究人員與工程師研究iOS、Windows、IE 瀏覽器等流行消費者軟體的實驗室。他們尋找這些程序中可能存在的安全漏洞,以防禦網絡攻擊或對高價值目標的入侵。在這類攻擊中,最知名的當屬「震網」病毒,它是美國與以色列情報機構研製的一種網絡武器。通過感染控制地下聚變反應堆的計算機,「震網」延緩了伊朗核計劃。如前所述,我們可以根據二進位可執行文件分析有關程序的原始指令,但無法恢復用於生成二進位文件的原始原始碼。在沒有原始原始碼的情況下,即使可以稍許修改二進位文件以便以較小的方式破解,實際上也無法對程序進行任何重大更改(如添加新功能)。一些人推崇協作構建代碼的方式,因此將自己的原始碼開放供他人修改。「開源」的主要概念就在於此:所有人都能自由使用與修改的軟體。基於Linux 的作業系統(如Ubuntu、Fedora 與Debian)是開源的,而Windows 與macOS 是閉源的。開源作業系統的一個有趣之處在於,任何人都可以檢查原始碼以尋找安全漏洞。現已證實,政府機構通過日常消費者軟體中未修補的安全漏洞,對數百萬平民進行利用和監視。但對開源軟體而言,代碼受到的關注度更高,因此惡意的第三方與政府機構很難植入監控後門程序。使用macOS 或Windows 時,用戶必須相信Apple 或Microsoft 對自己的安全不會構成危害,並盡最大努力防止任何嚴重的安全漏洞。而開源系統置於公眾的監督之下,因此安全漏洞被忽視的可能性大為降低。我們知道,計算機的操作可以歸結為使CPU 執行簡單的指令,這些指令只能對存儲在CPU 寄存器中的數據操作。但寄存器的存儲空間通常被限制在1000 字節以內,這意味著CPU 寄存器與RAM 之間必須不斷進行數據傳輸。如果存儲器訪問速度過慢,CPU 將被迫處於空閒狀態,以等待RAM 完成數據傳輸。CPU 讀寫存儲器中數據所需的時間與計算機性能直接相關。提高存儲器速度有助於加快計算機運行,也可以提高CPU 訪問數據的速度。CPU 能以近乎實時的速度(一個周期以內)訪問存儲在寄存器中的數據,但訪問RAM 則慢得多。對於時鐘頻率為1 GHz 的CPU,一個周期的持續時間約為十億分之一秒,這是光線從本書進入讀者眼中所需的時間。近年來的技術發展使得CPU 速度成倍增長。雖然存儲器速度同樣有所提高,但卻慢得多。CPU 與RAM 之間的這種性能差距稱為「處理器與存儲器之間的鴻溝」。我們可以執行大量CPU 指令,因此它們很「廉價」;而從RAM 獲取數據所需的時間較長,因此它們很「昂貴」。隨著兩者之間的差距逐漸增大,提高存儲器訪問效率的重要性越發明顯。現代計算機需要大約1000 個CPU 周期(1 微秒左右) 從RAM 獲取數據。這種速度已很驚人,但與訪問CPU 寄存器的時間相比仍然較慢。減少計算所需的RAM 操作次數,是計算機科學家追求的目標。
在兩個面對面的人之間,聲波傳播需要大約10 微秒。在嘗試儘量減少對RAM 的訪問時,計算機科學家開始注意到兩個事實。◎ 時間局部性:訪問某個存儲地址時,可能很快會再次訪問該地址。◎ 空間局部性:訪問某個存儲地址時,可能很快會訪問與之相鄰的地址。因此,將這些存儲地址保存在CPU 寄存器中,有助於避免大部分對RAM的「昂貴」操作。不過在設計CPU 晶片時,工業工程師並未找到可行的方法來容納足夠多的內部寄存器,但他們仍然發現了如何有效地利用時間局部性與空間局部性。接下來將對此進行討論。可以構建一種集成在CPU 內部且速度極快的輔助存儲器,這就是一級緩存。將數據從一級緩存讀入寄存器,僅比直接從寄存器獲取數據稍慢。利用一級緩存,我們將可能訪問的存儲地址中的內容複製到CPU 寄存器附近,藉此以極快的速度將數據載入CPU 寄存器。將數據從一級緩存讀入寄存器僅需大約10 個CPU 周期,速度是從RAM 獲取數據的近百倍。藉由10 KB 左右的一級緩存,併合理利用時間局部性與空間局部性,超過一半的RAM 訪問調用僅通過緩存就能實現。這一創新使計算技術發生了翻天覆地的變化。一級緩存可以極大縮短CPU 的等待時間,使CPU 將更多時間用於實際計算而非處於空閒狀態。提高一級緩存的容量有助於減少從RAM 獲取數據的操作,進而縮短CPU 的等待時間。但是,增大一級緩存的同時也會降低它的速度。在一級緩存達到50 KB 左右時,繼續增加其容量就要付出極高的成本。更好的方案是構建一種稱為二級緩存的緩存。二級緩存的速度稍慢,但容量比一級緩存大得多。現代CPU 配備的二級緩存約為200 KB,將數據從二級緩存讀入CPU 寄存器需要大約100 個CPU 周期。我們將最有可能訪問的地址複製到一級緩存,較有可能訪問的地址複製到二級緩存。如果CPU 沒有在一級緩存中找到某個存儲地址,仍然可以嘗試在二級緩存中搜索。僅當該地址既不在一級緩存、也不在二級緩存中時,CPU 才需要訪問RAM。目前,不少製造商推出了配備三級緩存的處理器。三級緩存的容量比二級緩存大,雖然速度不及二級緩存,但仍然比RAM 快得多。一級/ 二級/ 三級緩存非常重要,它們佔據了CPU 晶片內部的大部分矽片空間。見圖7-11。使用一級/ 二級/ 三級緩存能顯著提高計算機的性能。在配備200 KB的二級緩存後,CPU 發出的存儲請求中僅有不到10% 必須直接從RAM獲取。
讀者今後購買計算機時,對於所挑選的CPU,請記住比較一級/ 二級/三級緩存的容量。CPU 越好,緩存越大。一般來說,建議選擇一款時鐘頻率稍低但緩存容量較大的CPU。如前所述,計算機配有不同類型的存儲器,它們按層次結構排列。性能最好的存儲器容量有限且成本極高。沿層次結構向下,可用的存儲空間越來越多,但訪問速度越來越慢。在存儲器層次結構中,位於CPU 寄存器與緩存之下的是RAM,它負責存儲當前運行的所有進程的數據與代碼。截至2017 年,計算機配備的RAM 容量通常為1 GB 到10 GB。但在許多情況下,RAM 可能無法滿足作業系統以及所有運行程序的需要。
因此,我們必須深入探究存儲器層次結構,使用位於RAM 之下的硬碟。截至2017 年,計算機配備的硬碟容量通常為數百吉字節,足以容納當前運行的所有程序數據。如果RAM 已滿,當前的空閒數據將被移至硬碟以釋放部分內存空間。問題在於,硬碟的速度非常慢,它一般需要100 萬個CPU 周期(1 毫秒)a 在磁碟與RAM 之間傳輸數據。從磁碟訪問數據看似很快,但不要忘記,訪問RAM 僅需1000 個周期,而訪問磁碟需要100 萬個周期。RAM 通常稱為第一級存儲器,而存儲程序與數據的磁碟稱為第二級存儲器。CPU 無法直接訪問第二級存儲器。執行保存在第二級存儲器中的程序之前,必須將其複製到第一級存儲器。實際上,每次啟動計算機時,即便是作業系統也要從磁碟複製到RAM,否則CPU 無法運行。確保RAM 永不枯竭 在典型活動期間,確保計算機處理的所有數據與程序都能載入RAM 至關重要,否則計算機將不斷在磁碟與RAM 之間交換數據。由於這項操作的速度極慢,計算機性能將嚴重下降,甚至無法使用。這種情況下,計算機不得不花費更多時間等待數據傳輸,而無法進行實際的計算。當計算機不斷將數據從磁碟讀入RAM 時,則稱計算機處於抖動模式。必須對伺服器進行持續監控,如果伺服器開始處理無法載入RAM 的數據,那麼抖動可能會導致整個伺服器崩潰。銀行或收銀機前將因此排起長隊,而服務員除了責怪發生抖動的計算機系統之外別無他法。內存不足或許是導致伺服器故障的主要原因之一。我們繼續沿存儲器層次結構向下分析。在連接到網絡之後,計算機就能訪問由其他計算機管理的存儲器。它們要麼位於本地網絡,要麼位於網際網路(即雲端)。但訪問這些數據所需的時間更長:讀取本地磁碟需要1 毫秒,而獲取網絡中的數據可能耗時數百毫秒。網絡包從一臺計算機傳輸到另一臺計算機大約需要10 毫秒,如果經由網際網路傳輸則需要200 毫秒到300 毫秒,與眨眼的時間相仿。位於存儲器層次結構底部的是第三級存儲器,這種存儲設備並非總是在線與可用的。在盒式磁帶或CD 中存儲數百萬吉字節的數據成本較低,但訪問這類介質中的數據時,需要將介質插入某種讀取設備,這可能需要數分鐘甚至數天之久(不妨嘗試讓IT 部門在周五晚上備份磁帶中的數據……)。有鑑於此,第三級存儲器僅適合歸檔很少訪問的數據。一方面,很難顯著改進「快速」存儲器(位於存儲器層次結構頂端)所用的技術;另一方面,「慢速」存儲器的速度越來越快,價格也越來越低。幾十年來,硬碟存儲的成本一直在下降,這種趨勢似乎還將持續下去。新技術也使磁碟的速度得以提高。人們正從旋轉磁碟轉向固態硬碟(SSD),它沒有動件,因而更快、更可靠且更省電。採用SSD 技術的磁碟正變得越來越便宜且越來越快,但其價格仍然不菲。有鑑於此,一些製造商推出了同時採用SSD 與磁技術的混合磁碟。後者將訪問頻率較高的數據存儲在SSD 中,訪問頻率較低的數據存儲在速度較慢的磁碟中。當需要頻繁訪問原先不經常訪問的數據時,則將其複製到混合驅動器中速度較快的SSD。這與CPU 利用內部緩存提高RAM 訪問速度的技巧頗為類似。本文介紹了一些基本的計算機工作原理。任何可計算的事物都能採用簡單的指令來表示。為將複雜的計算命令轉換為CPU 可以執行的簡單指令,需要使用一種稱為編譯器的程序。計算機之所以能進行複雜計算,僅僅是因為CPU 可以執行大量基本操作。計算機的處理器速度很快,但存儲器相對較慢。CPU 並非以隨機方式訪問存儲器,而是遵循空間局部性與時間局部性原理。因此,可以將訪問頻率較高的數據緩存在速度更快的存儲器中。這一原則在多個級別的緩存中得到了應用:從一級緩存直到第三級存儲器,不一而足。本文討論的緩存原則可以應用於多種場景。確定應用程式頻繁使用的數據,並設法提高這部分數據的訪問速度,是縮短電腦程式運行時間的最常用策略之一。
【1】英特爾發布全球最大容量FPGA,問題來了:FPGA和ASIC孰優孰劣?
【2】挑戰收入規模30億元,這家連接器企業的底氣在哪兒?
【3】為什麼ST也要做MPU?入場雖晚但卻仍被看好?
【4】射頻廠商老大Qorvo進軍新業務,推出可編程電源SoC
【5】半導體行業的人都在關注這幾個公眾號
你和大牛工程師之間到底差了啥?
加入技術交流群,與高手面對面
添加管理員微信