題精析:CPU性能與數(shù)據(jù)表示機制)
簡介計算機組成與系統(tǒng)結(jié)構(gòu)袁春風(fēng)·第三版課后習(xí)題答案匯總面向計算機專業(yè)本科生、考研復(fù)習(xí)者及自學(xué)計組、指令系統(tǒng)與匯編語言的人。內(nèi)容緊密圍繞性能評估、MIPS、CPI、時鐘頻率、性價比分析等高頻考點通過典型習(xí)題給出逐步推導(dǎo)與參考答案文檔用多組機器對比、指令條數(shù)與執(zhí)行時間表格演示了機器選型、平均時鐘周期數(shù)、執(zhí)行時間占比等題型的規(guī)范解法并對易混淆的結(jié)論如速度提升百分比和CPI比例做了辨析。資源為一篇doc文檔壓縮包共1個文件、約1.75MB按章節(jié)整理收錄第一、二章等關(guān)鍵習(xí)題并給出答案要點便于配合教材邊學(xué)邊對照、查漏補缺。已有1190人學(xué)習(xí)下載既適合課后消化例題也適合考前快速梳理重點計算題型。整體是一份緊湊、可復(fù)用的計組習(xí)題答案解析能幫助讀者在較短時間內(nèi)掌握性能計算類題目的通用思路。1. 計組課后習(xí)題不是背公式為什么指令條數(shù)少的程序反而跑得慢計組這門課最容易讓人栽跟頭的地方不是公式記不住而是做題全靠直覺。第三章有一道題很反直覺同一臺機器上指令序列 S2 只有 8 條指令另一個序列 S1 有 10 條結(jié)果 S1 跑完只要 38nsS2 卻要花 52ns。指令少的反而慢。這個現(xiàn)象背后正好是計算機組成與系統(tǒng)結(jié)構(gòu)里性能分析的靈魂程序執(zhí)行時間等于指令條數(shù)、CPI、時鐘周期三者的乘積。三個變量互相牽制只看其中一個結(jié)論就必然翻車。這份課后習(xí)題答案匯總的價值也在這里它把基準(zhǔn)測試、數(shù)據(jù)表示、運算機制、校驗原理全部落成了可驗證的數(shù)字適合一題一題推演而不是把參考答案背下來。搞懂這些題等于把指令系統(tǒng)底層的設(shè)計邏輯重新走了一遍。2. 性能標(biāo)尺CPU時間、MIPS與性價比如何決定機器選型2.1 CPU執(zhí)行時間的三因子分解任何程序的 CPU 執(zhí)行時間都可以寫成CPU 時間 指令條數(shù) × CPI × 時鐘周期。這里 CPI 是每條指令的平均時鐘周期數(shù)時鐘周期是主頻的倒數(shù)。三個因子中任何一個變化執(zhí)行時間都會跟著變。回到習(xí)題 9。編譯器把同一段高級語言代碼生成兩個指令序列 S1 和 S2機器主頻都是 500MHz。S1 的 10 條指令里5 條 CPI1、2 條 CPI2、2 條 CPI3、1 條 CPI4算下來 CPI 是 1.9S2 有 8 條指令但 5 條是 CPI4 的 D 類指令CPI 高達 3.25。各自執(zhí)行時間S110 × 1.9 / 500MHz 38nsS28 × 3.25 / 500MHz 52nsS2 指令少了 20%但 CPI 漲了 71%最終執(zhí)行時間反而長了 36.8%。習(xí)題答案后面補了一句很關(guān)鍵的話并不是指令條數(shù)少的目標(biāo)程序執(zhí)行時間就一定少。這句話值得刻在腦子里。這個公式最大的用途是把“快慢”這種模糊感受拆成可定位的變量。機器慢可以先看主頻是不是低再看程序是不是用了大量高 CPI 的指令最后才看指令條數(shù)。很多人調(diào)性能一上來就數(shù)指令方向就錯了。2.2 MIPS峰值與實際的差距MIPS 是每秒百萬條指令計算公式是指令條數(shù)除以執(zhí)行時間再除以 10^6。習(xí)題 5 給了兩臺機器跑兩個基準(zhǔn)程序的數(shù)據(jù)???M1 和 M2 跑 P2 的結(jié)果M1 是 300×10^3 條指令用 3ms算出來 100MIPSM2 是 420×10^3 條指令用 6ms算出來 70MIPS。從 MIPS 看M1 比 M2 快 1.43 倍。但注意M1 和 M2 的價格分別是 5000 元和 8000 元如果只比 MIPS 就草率選 M1后面性價比那步就會算錯。更迷惑的是峰值 MIPS。習(xí)題 6 里M1 主頻 1GHzM2 主頻 1.5GHz但 M2 的各類指令 CPI 都更高。M1 找一段全是 A 類指令的程序CPI1峰值 1000MIPSM2 即使用最快的 A、B 兩類指令因為 B 類 CPI2峰值也只有 750MIPS。主頻更高的機器峰值 MIPS 反而更低因為峰值 MIPS 只反映“這臺機器理論上最快能跑多快”而現(xiàn)實中程序必然混合使用各種指令真實 CPI 一定比最理想情況高。2.3 性價比算術(shù)平均與幾何平均誰說了算習(xí)題 5 的第四問和第五問是整套答案里設(shè)計得很妙的題目。用戶大量使用 P1關(guān)心響應(yīng)時間性價比公式定義為 R 1 /執(zhí)行時間 × 價格。M1 跑 P1 要 10msM2 只要 5ms但 M1 便宜 3000 元。算“執(zhí)行時間 × 價格”M1 是 10 × 5000 50000M2 是 5 × 8000 40000。值越小性價比越高所以選 M2。第五問變成兩個程序同等使用結(jié)果就復(fù)雜了。用算術(shù)平均還是 M2 勝出但用幾何平均sqrt(10 × 0.003) × 5000 小于 sqrt(5 × 0.006) × 8000結(jié)論反過來了應(yīng)該選 M1。同一批數(shù)據(jù)兩種平均方法給出完全相反的選型建議。算術(shù)平均把執(zhí)行時間大的 P1 的差異直接放大幾何平均則削弱了量綱差異帶來的影響。實際做性能選型時選擇哪種平均方式取決于負載特征——如果耗時集中在單個程序算術(shù)平均更符合直覺如果是大量同質(zhì)任務(wù)的綜合吞吐幾何平均更能反映真實的感知比。3. 數(shù)據(jù)表示補碼、移碼與IEEE 754的底層邏輯3.1 補碼為什么減法能變成加法習(xí)題 4 列了一組 8 位定點小數(shù)要求寫原碼和補碼。比如 -0.1001 的原碼是 1.1001000補碼是 1.0111000。補碼的定義是負數(shù)取反加一但這樣定義的原因是為了讓減法統(tǒng)一成加法。CPU 里的加法器只要實現(xiàn)加法減法通過“補碼加一”轉(zhuǎn)換為加法硬件就能少做一套減法電路。更有意思的是邊界值。同樣的 8 位格式1.0 在原碼和補碼里都溢出因為 7 位數(shù)值位最大只能表示 0.1111111不到 1但 -1.0 的補碼 1.0000000 卻能表示。這是補碼特有的不對稱性定點小數(shù)的補碼表示范圍是 -1 到 (1-2^-7)負數(shù)端比正數(shù)端多一個點。習(xí)題 6 里給了 [x] 補 10000000求 x答案是 -128也是這個道理。補碼把“0”唯一化了原碼里 0 和 -0 都在補碼里 10000000 不再表示 -0而是整個范圍最左邊的那個負數(shù)。3.2 移碼與偏置為什么指數(shù)要加127習(xí)題 5 讓寫補碼和移碼。1001 的補碼是 00001001移碼是 10001001-1001 的補碼是 11110111移碼是 01110111。對比就能看出來移碼和補碼的區(qū)別只在符號位補碼的符號位取反就是移碼。移碼的核心設(shè)計動機是讓階碼可以按無符號數(shù)比較大小。浮點數(shù)做加減法時要先對階比較兩個指數(shù)的大小。如果指數(shù)用補碼表示比較大的負數(shù)在二進制序里會排在后面比較電路就要額外處理符號。用了偏置常數(shù)后指數(shù)加上 127或題目里的 16、128最小指數(shù)變成全 0最大指數(shù)變成全 1大小順序和二進制序完全一致。IEEE 754 選 127 是因為單精度階碼 8 位能表示 -126 到 127全 0 和全 1 另有用途加上 127 后映射到 1 到 254正好避開兩個保留的邊界值。3.3 IEEE 754的隱藏位與漸進下溢習(xí)題 7 是這份答案里最值得反復(fù)看的一道題。R1 內(nèi)容 0000108BHR2 內(nèi)容 8080108BH三條指令把它們當(dāng)作無符號數(shù)、帶符號整數(shù)、單精度浮點數(shù)真值完全不同。作為浮點數(shù)R1 的階碼全 0是非規(guī)格化數(shù)沒有隱藏的 1尾數(shù)是 0.002116H指數(shù)固定為 -126真值是 0.002116H × 2^-126R2 的階碼是 00000001規(guī)格化數(shù)尾數(shù)里有隱藏的 1指數(shù)的真值是 1 - 127 -126結(jié)果是 -1.002116H × 2^-126。同一個位模式符號位和階碼差一個 1規(guī)格化狀態(tài)就完全不同。規(guī)格化數(shù)隱藏位的設(shè)計很精妙規(guī)格化數(shù)尾數(shù)最高位必然是 1那就干脆不存省下的那一位多存一個有效位。但代價是 0 無法用規(guī)格化表示所以階碼全 0 時改走非規(guī)格化路徑。習(xí)題 15 的范圍表里最小非規(guī)格化數(shù)是 2^-23 × 2^-126 2^-149而最小規(guī)格化數(shù)是 1.0 × 2^-126兩者之間是連續(xù)的、平滑逼近 0 的而不是直接掉到 0。這種“漸進下溢”避免了數(shù)值從 2^-126 突然跳成 0 的精度斷層。3.4 大端小端同一個數(shù)在不同內(nèi)存布局下的機器數(shù)習(xí)題 17 讓畫出 x-0.125、y7.5、i100 在大小端機器上的內(nèi)存分布。先算出機器數(shù)-0.125 是 BE000000H7.5 是 40F00000H100 是 0064H。大端機把最高字節(jié)放在最低地址地址 100 處是 BEH小端機把最低字節(jié)放在最低地址地址 100 處是 00H。這題的陷阱在于很多人以為“大小端只是字節(jié)序顛倒”實際上浮點數(shù)的符號位、階碼、尾數(shù)在內(nèi)存里也跟著一起按字節(jié)倒置。x 在地址 100~103在小端機上就是 00H 00H 00H BEH連符號位所在的字節(jié)都被搬到了最后。網(wǎng)絡(luò)協(xié)議用大端x86 用端小端跨端傳數(shù)據(jù)時如果直接讀內(nèi)存字節(jié)符號位、指數(shù)位全部錯位這就是為什么序列化要用明確的字節(jié)序約定。4. 運算機制類型轉(zhuǎn)換、移位、乘除優(yōu)化與檢錯糾錯4.1 unsigned的len-1一個循環(huán)災(zāi)難的根因習(xí)題 9 的 C 程序參數(shù) len 是 unsigned 類型循環(huán)條件是 i len-1。len 為 0 時程序沒有返回 0而是觸發(fā)存儲器訪問異常。float sum_elements(float a[], unsigned len) { int i; float result 0; for (i 0; i len-1; i) result a[i]; return result; }根因是 unsigned 的溢出行為。len0 時len-1 不是 -1而是 0xFFFFFFFF即 unsigned 能表示的最大值。任何有符號的 i 和它比較時i 先被隱式轉(zhuǎn)換成 unsigned于是 i 永遠小于等于 0xFFFFFFFF循環(huán)體一直執(zhí)行a[i] 越界訪問。修復(fù)方法有兩個把 len 聲明成 int或者把測試條件改成 i len。后者更符合直覺因為 i len 在 len0 時直接不進入循環(huán)。這類問題在真實代碼里很常見尤其是把接口里的長度參數(shù)寫成 unsigned 又做了 -1 運算的。C 語言的隱式類型轉(zhuǎn)換規(guī)則決定了有符號和無符號混合比較時有符號會轉(zhuǎn)成無符號負數(shù)的真值瞬間變成幾十億。4.2 邏輯移位與算術(shù)移位func1和func2為什么結(jié)果不同習(xí)題 3 的兩個函數(shù)看起來只差一個括號行為卻有本質(zhì)區(qū)別。int func1(unsigned word) { return (int) ((word 24) 24); } int func2(unsigned word) { return ((int) word 24) 24; }func1 全程按無符號數(shù)處理左移 24 位再邏輯右移 24 位相當(dāng)于把高 24 位清零結(jié)果必然是非負的。func2 先把 word 轉(zhuǎn)成 int左移 24 位后做的是算術(shù)右移右移補的是符號位。所以 w0000 0080H 時func1 返回 128func2 先左移得到 80000000H符號位是 1算術(shù)右移后得到 FFFFFF80H對應(yīng) -128。而 w0000 0100H 時左移 24 位把唯一的 1 移出了 32 位結(jié)果是 0。這里值得停下來想一層為什么帶符號整數(shù)必須用算術(shù)右移因為補碼的負數(shù)右移時高位補 0 會讓負數(shù)變成正數(shù)數(shù)值完全錯亂。算術(shù)右移保持符號位相當(dāng)于對負數(shù)做向下取整的除以 2 的冪。代價是右移對負數(shù)不是向零取整這正好引出下一節(jié)的除法優(yōu)化。4.3 編譯器優(yōu)化乘法如何變成移位與加減習(xí)題 5 給了一段反編譯得到的機器代碼要從它反推出原函數(shù)里的常量 M 和 N。int optarith(int x, int y) { int t x; x 4; x - t; if (y 0) y 3; y 2; return x y; }x4 是乘 16再減掉原來的 x就是 x×15所以 M15。y2 是除以 4但算術(shù)右移對負數(shù)向負無窮取整而 C 語言整數(shù)除法向零取整所以先給負數(shù)加上一個偏置量。y0 時 y3加上 3 之后右移 2 位等價于向零取整的除以 4。為什么要加 3因為 2^2 減 1。對任意負數(shù) y右移 2 位是 floor(y/4)要向零取整就得先把負數(shù)墊高 3使得 floor((y3)/4) trunc(y/4)。如果換成偏置 2y-3 時 -32-1右移兩位還是 -1但 -3/4 向零取整是 0就錯了。這道題同時也是指令系統(tǒng)的縮影高級語言里的乘除編譯成一堆移位、加減、條件分支而不是真的調(diào)用乘法指令。機器不提供乘除指令程序照樣能跑只是生成的指令序列更長執(zhí)行更慢。4.4 傳輸可靠性奇偶校驗、SEC與CRC怎么工作數(shù)據(jù)在總線上傳輸時會出錯習(xí)題 18、19、20 分別展示了三個層次的檢錯糾錯機制。奇偶校驗最簡單。32 位數(shù)據(jù) 8F 3C AB 96H 分成四個字節(jié)每個字節(jié)配一個奇校驗位要求每 9 位里 1 的個數(shù)為奇數(shù)。8F 展開是 1000 1111有 5 個 1校驗位 03C 是 0011 1100有 4 個 1校驗位 1AB 是 1010 1011有 5 個 1校驗位 096 是 1001 0110有 4 個 1校驗位 1。接收端收到的數(shù)據(jù)變成 87 3C AB 96H校驗位是 0101。重新計算前四個字節(jié)的奇校驗87 只有 4 個 1期望校驗位是 1收到的是 0異或結(jié)果為 1定位到第一個字節(jié)出錯。SEC 海明碼更進一步能指出具體哪一位錯。16 位數(shù)據(jù)的 SEC 碼用 5 個校驗位放在 1、2、4、8、16 位其余位置放數(shù)據(jù)。每個校驗位覆蓋一組特定位置的數(shù)據(jù)位出錯時重新計算校驗位和發(fā)送方的校驗位異或得到故障字故障字的二進制值正好是出錯位的編號。習(xí)題 19 里數(shù)據(jù)錯在第 5 位 M5故障字是 01001即 9對應(yīng)碼字第 9 位——正好是 M5 的位置。這個設(shè)計的巧妙之處在于校驗位位置選 2 的冪讓每個出錯位都產(chǎn)生一個唯一的故障字。CRC 校驗則是多項式的世界。習(xí)題 20 的數(shù)據(jù)是 100011生成多項式 G(x)x^31即二進制 1001。發(fā)送方在數(shù)據(jù)后補 3 個 0用模 2 除法去除以 1001余數(shù)是 111CRC 碼就是 100011 111。接收方收到 100010 111同樣做模 2 除法余數(shù) 001非 0判定出錯。這里的除法不是算術(shù)除法是按位異或相當(dāng)于判斷接收到的多項式是否能被生成多項式整除。不能整除就說明有錯這正是 CRC 能被廣泛用于鏈路層的原因。5. 常見問題排查計組題里最常翻車的五個現(xiàn)場5.1 現(xiàn)象CPI 直接相比差多少就算快多少習(xí)題 6 后面有個思考題程序 P 在 M1 上 CPI 是 2.4M2 上 CPI 是 3.8有人說 M1 比 M2 快 (3.8-2.4)/3.8 36.8%。原因CPI 只是執(zhí)行時間的一個因子這臺題目里 M1 主頻 1GHz、M2 主頻 1.5GHz。完整的執(zhí)行時間是 CPI × 指令條數(shù) / 主頻。假設(shè)指令條數(shù)為 NM1 是 2.4N nsM2 是 3.8N/1.5 2.53N nsM1 只快約 5%。CPI 直接比錯在丟掉了時鐘周期這一個維度。解決永遠把執(zhí)行時間公式三項寫齊再算任何性能結(jié)論都要落到時間上。5.2 現(xiàn)象指令條數(shù)少程序一定更快習(xí)題 9 的 S1 有 10 條指令S2 只有 8 條S2 反而慢 14ns。原因S2 的 CPI 是 3.25是 S1 的 1.7 倍多出的 D 類指令全是高 CPI 指令。解決比較兩個程序或兩個編譯版本要看 “指令數(shù)、CPI、時鐘周期” 的乘積任何單一指標(biāo)都不能直接證明快慢。5.3 現(xiàn)象十進制小數(shù)轉(zhuǎn)二進制算幾位就停習(xí)題 10 里1.7 轉(zhuǎn)成二進制是無限循環(huán)小數(shù)。如果手算時取 0.1101 就收手后續(xù)的階碼、尾數(shù)全是錯的。參考答案用 0 舍 1 入得到 0.011011×4^1階碼是 17尾數(shù) 0.011011。-0.12 轉(zhuǎn)出來是 -0.000111101B要左移到 0.011111×4^-1 再取補碼。原因浮點格式尾數(shù)位有限十進制小數(shù)在二進制里可能無限循環(huán)必須按格式位數(shù)做舍入。解決先確定格式有多少位尾數(shù)再決定保留幾位最后一步做 0 舍 1 入不要提前截斷。5.4 現(xiàn)象unsigned 的邊界值當(dāng)普通整數(shù)算習(xí)題 9 的 len0 時len-1 是 0xFFFFFFFF 而不是 -1循環(huán)不退出。習(xí)題 8 里 -1 0U 的結(jié)果是 0因為 -1 轉(zhuǎn)成 unsigned 后是 4294967295。原因C 語言的隱式類型轉(zhuǎn)換把有符號轉(zhuǎn)成無符號負數(shù)變成大正數(shù)。解決涉及 unsigned 的循環(huán)條件不用 len-1 這種寫法直接 i len混合比較時先想清楚兩邊會被轉(zhuǎn)換成什么類型。5.5 現(xiàn)象除法優(yōu)化偏置量想當(dāng)然習(xí)題 5 的 y/4 優(yōu)化有人覺得負數(shù)加 2 就行。加 2 對 y-4 恰好成立但對 y-3 就錯了-32-1算術(shù)右移兩位是 -1而 -3/4 向零取整是 0。原因偏置量必須是 2^k - 1目的是讓 floor((ybias)/2^k) 等于 trunc(y/2^k)。解決不要背特例直接從向下取整和向零取整的關(guān)系推k 位右移配 2^k - 1 的偏置。6. 設(shè)計取舍每個聰明的設(shè)計都在“浪費”位寬這套習(xí)題答案看下來會發(fā)現(xiàn)一個規(guī)律計算機里每個關(guān)鍵設(shè)計都在用某種“浪費”換另一種收益。補碼浪費了直觀性換來的是加減法統(tǒng)一CPU 里少一套減法器移碼浪費了純二進制的大小順序直覺換來浮點指數(shù)可以直接按無符號數(shù)比較IEEE 754 浪費了規(guī)格化數(shù)尾數(shù)最高位的一位空間但把這一位變成隱藏位多給了 24 位有效精度非規(guī)格化數(shù)浪費了指數(shù)編碼空間換來的是下溢時數(shù)值能平滑逼近 0而不是從 2^-126 直接跳成 0。這些取舍在習(xí)題里體現(xiàn)得非常具體。習(xí)題 4 里 1.0 溢出而 -1.0 不溢出就是補碼不對稱性的代價習(xí)題 15 里最大規(guī)格化數(shù)和最小非規(guī)格化數(shù)相差那么多數(shù)量級就是浮點表示把范圍撐大后精度分布不均的代價。做題的時候如果不看設(shè)計動機這些邊界情況都像冷門考點但一旦理解了“每個位模式都有它的用途和代價”它們就成了驗證設(shè)計合理性的檢查點。從那以后我每次拿到一道計組題都強制自己先列出參與計算的公式和前提再代入數(shù)值最后才看結(jié)論。尤其是性能題和浮點題直覺幾乎總是錯的公式和位模式才是唯一可靠的工具。這份習(xí)題答案匯總適合放在手邊邊做邊對照把每一道題的“為什么”推演一遍比直接背參考答案有用得多。希望幫到你。本文還有配套的精品資源點擊獲取