




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
深入理解計算機系統(tǒng)
(1)對于一個無符號數(shù)字x,截斷它到k位的結(jié)果就相當(dāng)于計算xmod2”.
(2)在大多數(shù)的機器上,整數(shù)乘法指令相當(dāng)?shù)芈?,需?2或者更多的始終周期,然而其他整數(shù)
運算一例如加法、減法、位移運算和移位一只需要1個時鐘周期.因此,編譯器使用的一項重
要的優(yōu)化就是試著使用移位和加法運算的組合來代替乘以常數(shù)因子的乘法.
(3)在大多數(shù)的機器上,整數(shù)除法要比整數(shù)乘法更慢一需要30或者更多的始終周期.除以2
的哥也可以用移位運算來實現(xiàn),只不過我們用的是右移,而不是左移.對于無符號和二進制補
碼數(shù),分別使用邏輯移位和算術(shù)移位來到達目的.
1.注意系統(tǒng)的分類:主流的IA32(也就是X86),以及x86-64(也就是x64),還有種Intel的與原32位系統(tǒng)不兼容的
IA64.:
2.編譯系統(tǒng)由預(yù)處理器,編譯器,匯編器和鏈接器組成。
3.單指令多數(shù)據(jù)并行稱為SIMD并行,其擴展為SSE指令集。
4.x64上long為8字節(jié),指針也為8字節(jié)。
5.無符號數(shù)右移必須采用邏輯右移,而有符號數(shù)一?般采用算術(shù)右移.
6.有符號數(shù)遇見無符號數(shù)會默認(rèn)強轉(zhuǎn)為無符號數(shù)。
7.short轉(zhuǎn)為unsigned時,是先擴展大小再符號轉(zhuǎn)換。
8.補碼非的計算:從左到右將第一個為1的位前的所有位取反。
9.負(fù)數(shù)的補碼移位向下舍入。
10.正浮點數(shù)能使用整數(shù)排序函數(shù)來進行排序。
11.浮點加法和乘法不具備結(jié)合性,浮點乘法在加法上不具備分配性。
12.預(yù)處理器擴展源代碼,然后編譯器生成源代碼的文本匯編代碼,匯編器轉(zhuǎn)成二進制匯編碼,鏈接器生成exe
或dll或lib。
13.存放器可以保存地址也可以保存值。注意匯編中的加括號表示為取該地址指向的值,如(%eax)指%eax中保
存的地址指向的值。
14.傳送指令的兩個操作符不能都指向存儲器。
15.棧指針%esp保存著棧頂元素的值,%eax保存函數(shù)返回值。
16.棧從高地址往低地址分配,堆從低地址往高地址分配°
17.注意:lea,假設(shè)為Ieal7(%edx,%eax,4),那么當(dāng)%edx中保存的是地址時,lea為取有效地址,而當(dāng)%edx
中保存的是值時,lea為算術(shù)運算,即7+%edx+%eax*4。這兒的%eax總保存值。說白了,其實lea一直是在
做計算,只是%edx影響了直觀表達而已。
18.注意:處理有無符號值的操作是通過不同的匯編指令來區(qū)分的。
19.大多數(shù)匯編器根據(jù)一個循環(huán)的do-while形式來產(chǎn)生循環(huán)代碼,逆向工程會用到。
20.指令無視操作數(shù)的長度。
21.因為有個條件傳送的優(yōu)化策略,所以(xp?*xp:0)這條語句其實兩個選擇分支都會執(zhí)行。
22.32位系統(tǒng)中,大多數(shù)棧中信息的訪問其位置都是基于幀指針的。而64位系統(tǒng)中,棧的存儲信息數(shù)已被弱化,
所以無幀指針/,
23.訪問某個局部變量的前提是該局部變量至少有個可引用的地址,所以局部變量被保存在了棧中。
24.為了防止從效率低的存儲器讀與值時,可能因數(shù)據(jù)未對齊而造成屢次讀寫從而導(dǎo)致低性能,IA32要求數(shù)據(jù)一
定要對齊。編譯器在編譯肘會強制對齊。
25.匯編指令leave等于倆pop,效果?樣,選擇隨意。pop和push在棧上分配空間的方式是直接棧指針減去或
加上偏移量。
26.指針之差等于相差字節(jié)數(shù)/所指類型大小字節(jié)數(shù)。
27.存放器不夠用時會出現(xiàn)存放福溢出,這時就必須有值被保存在棧卜了,一般是將只讀變量放入棧.
28.GCC會對局部char類型的緩沖區(qū)插入金絲雀保護代碼。
29.在C中內(nèi)聯(lián)匯編代碼只能針對某?類機2〉
30.SSE2引入浮點數(shù)面向存放器的指令集,而不用基于棧的方法。
31.X64能讓匯編代碼比X32少很多,但是實際性能提升不會很大。但是從改良上來說性能應(yīng)該提升很大很大啊,
為什么。。。難道是x32已經(jīng)被優(yōu)化的變態(tài)了???
32.注意rep有時當(dāng)空操作使。
33*64中,枝空間向下128字節(jié)以內(nèi)的區(qū)域仍可以被函數(shù)訪問,該區(qū)域被ABI稱為紅色地帶。
34.浮點相關(guān):把存儲模型,指令和傳遞規(guī)那么組合稱為浮點體系結(jié)構(gòu)。
35.邏輯門只是簡單的響應(yīng)輸入的變化而已。
36.HCL中,上只是表示用一個名字來稱謂一個表達式。其類switch的表達中的”1.“等同于switch中的Default
Case。
37.存放器文件上的讀或?qū)懚丝诙挤謩e成對,一個傳ID,一個傳內(nèi)容。
38.訪存階段讀寫存儲器,寫回階段將結(jié)果寫到存放器文件。
39.存放器文件和數(shù)據(jù)存儲器等都是當(dāng)前時鐘隨意讀,下一時鐘統(tǒng)一寫入更新。即時鐘控制狀態(tài)元素的更新。
40.流水線即保持各單元在時鐘周期內(nèi)忙碌不已,一套流水線硬件供多個流水線使用。
41.加載互鎖和數(shù)據(jù)轉(zhuǎn)發(fā)技術(shù)結(jié)合起來足以處理可能類型的數(shù)據(jù)冒險。
42.當(dāng)流水線化的系統(tǒng)中出現(xiàn)多條指令引起的異常時,最深的指令被處理的優(yōu)先級最高。
43.每個時鐘周期執(zhí)行多個操作稱為超標(biāo)量,而超線程是指一個核同時運行倆線程。
44.處理器功能單元的性能表示中,延遲指按照嚴(yán)格順序執(zhí)行完成合并運算所需要的最小周期數(shù),而吞吐量指理
論上最快完成一個操作所需周期數(shù),
45.使用SSE可以降低吞吐量界限。
46.書寫適合條件傳送實現(xiàn)的”功能式“代碼。
47.每個加載/存儲單元每個時鐘周期只能啟動一條加載/存儲操作。
48.性能提高技術(shù):①.采用適宜的算法和數(shù)據(jù)結(jié)構(gòu)。②.消除連續(xù)的函數(shù)循環(huán)調(diào)用,在可能時盡量將計算移到循環(huán)
外:消除不必要的存儲器引用,引入臨時變量來保存中間結(jié)果;保持內(nèi)層循環(huán)在存儲器層面的局部性。③展開循環(huán);
通過多個累計變量和重新結(jié)合等技術(shù),提高指令級并行:用功能的風(fēng)格重寫條件操作,使得編譯采用條件數(shù)據(jù)傳送。
49.內(nèi)存是硬盤的緩存。
50.corei7上所有的SRAM高速緩存存儲器都在CPU芯片上。
51.對丁性能來說,存儲淵訪問總數(shù)和不命中率相比,不命中率影響要更大。估”是因為存儲器的寫何緩存機制。
52.存儲器性能注意:將注意力集中在內(nèi)循環(huán)上,大局部計算和存儲器訪問都發(fā)生在這里:通過按照數(shù)據(jù)對象存
儲在存儲器中的順序,以步長為1來讀數(shù)據(jù),從而使得空間局部性最大;一旦從存儲器中讀入了一個數(shù)據(jù)對象,
就盡可能多的使用它,從而使得時間局部性最大。
53.對于靜態(tài)庫的鏈接,只會鏈接程序中用到的該庫(.lib)中的模塊(.obj),這其實也解釋為什么分別鏈接靜態(tài)庫版
本和動態(tài)庫版本的兩程序大小相差不是那么懸殊。
54.當(dāng)前指令處理完后,處理器才能去發(fā)現(xiàn)中斷是否發(fā)生。
55.Linux系統(tǒng)調(diào)用的參數(shù)都是通過通用存放淵而不是棧傳遞的。
56.C++的try-catch是C種setjmp和longjmp的更加結(jié)構(gòu)化的版本。
57.DRAM作為磁盤的緩存,不命中開銷巨大。
58.磁盤上的交換文件同時乂作為DRAM保存數(shù)據(jù)的緩存。
59.延遲私有對象中的拷貝最充分的利用了稀有的物理存儲器,這是通過寫時拷貝實現(xiàn)的。
60.一個系統(tǒng)中被所有進程分配的虛擬存儲器的全部數(shù)量是受磁盤上交換空間的數(shù)量限制的.
61.造成堆利用率很低的主要原因是內(nèi)存碎片的存在。
62.有時為了極個別的幾個特殊情,兄而要去每次調(diào)用時都檢查,還不如通過某些方式直接把特殊情況一般化,能
用通用的方式去處理。
63.內(nèi)存引用導(dǎo)致的崩潰要注意;引用壞指針/野指針,以及讀未初始化的存儲器。
64.UNIX信號是不排隊的,假設(shè)為考慮處理,那么會直接丟棄。
65.函數(shù)內(nèi)部的static變量也是線程間共享的。
66.注意并行和并發(fā)的區(qū)別,并行程序是一個運行在多個處理器上的并發(fā)程序。
67.線程數(shù)多過核數(shù)對效率反而會有影響,但影響不大。
68.注意:rand和ctime,localtime等函數(shù)時線程不平安的,慎用啊慎用!可用其可重入版本。
69.互斥鎖記得相同順序加鎖解鎖,
70.包裝錯誤處理函數(shù),是一個非常不錯的做法。
//============================================
2010.07.08
深入理解計算機系統(tǒng)
(1)反匯編器一些特性說明:
1)IA32指令長度從1?15個字節(jié)不等.指令編碼被設(shè)計成使常用的指令以及操作較少的指令所需的字節(jié)
數(shù)少,二那些不太常用或操作數(shù)較多的指令所需字節(jié)數(shù)較多.
2)指令格式是按照這樣一種方式設(shè)計的,從某個給定位置開始,可以將字節(jié)唯一地解碼成機器指令.例如,
只有指令pushl%ebp是以字節(jié)值55開頭的.
3:i反匯編器只是根據(jù)目標(biāo)文件中的字節(jié)序列來確定匯編代碼的.它不需要訪問程序的源代碼或匯編代碼.
4)反匯編器使用的指令命名規(guī)那么與GAS(GnuASembler)使用的有些細微的差異.
5j與codes中的匯編代碼相比,我們發(fā)現(xiàn)結(jié)尾多了一條nop指令.這條指令板本不會被執(zhí)行(它在過程返
回指令之后),即使執(zhí)行了也不會有任何影響(所以稱之為nop,是“n。operation"的簡寫,同城讀作"noop").
編譯那插入這樣的指令是為了填充存儲該過程的空間.
(2)IA32加了?條限制,傳送指令的兩個操作數(shù)不能都指向存儲器位置.將?個值從?個存儲器位置拷到
另一個存儲器位置需要兩條指令一第一條指令將源值加載到存放器值寫入目的位置.
(4)根據(jù)慣例,所有返回真書或指針值的函數(shù)都是通過將結(jié)果放在存放器%eax中來到達目的的.
⑸加載有效地址(Loadeffectiveaddress)指令leal實際上是movl指令的變形.它的指令形式是從存儲
器讀取數(shù)據(jù)到存放器,但實際上它根本就沒有引用存儲器.它的第一個操作數(shù)看上去是一個存儲器引用,
但該指令并不是從指定的位置讀入數(shù)據(jù),而是將有效地址寫入到目的操作數(shù)(如存放器).
(6)一元操作,只有一個操作數(shù),既作源,也作口的.這個操作數(shù)可以是一個存放器,也可以是一個存儲器位
置.比方說incl(%esp)會是棧頂元素加1.這種語法讓人想起C口的加1運算符(++)和減1(-).
(7)二元操作,第二個操作數(shù)既是源乂是目的.這種語法讓人想起C中向+=這樣的賦值運算符.不過要注意,
源操作數(shù)是第一個,目的操作數(shù)是第二個,這是不可交換操作特有的.例如,指令subl%eax,%edx使存放
器%0<^<的值減去%eax中的值第一個操作數(shù)可以是立即數(shù)、存放器或存儲器位置.第二個操作數(shù)可以是
存放器或是存儲器位置.不過同movl指令一樣,兩個操作數(shù)不能同時都是存儲器位置.
(8)divi指令執(zhí)行無符號除法,通常會事先將存放器%3(^設(shè)置為0.
//============================================
2010.07.09
深入理解計算機系統(tǒng)
(1)匯編語言中,直接跳轉(zhuǎn)時給出一個標(biāo)號作為跳轉(zhuǎn)H標(biāo)地;間接跳轉(zhuǎn)的寫法是…后面跟一個操作數(shù)指示
符.如
jmp*%eax表示用存放器%eax中的值作為跳轉(zhuǎn)目標(biāo);
jmp*(%eax)表示已%eax中的值作為讀地址,從存儲器中讀出跳轉(zhuǎn)目標(biāo);
(2)call指令有一個目標(biāo),指明被調(diào)用過程起始的指令地址.同跳轉(zhuǎn)一樣,調(diào)用可以是直接的,也可以是間接
的.在匯編代碼中,直接調(diào)用的目標(biāo)是?個標(biāo)號,而間接調(diào)用的目標(biāo)是*后面跟?個操作數(shù)指示符,其語法與
rrovel指令的操作數(shù)的語法相同.
⑶call指令的效果是將返回地址入棧,并跳轉(zhuǎn)到被調(diào)用過程的起始處.返回地址是緊跟在程序中call后面
的那條指令的地址.這樣當(dāng)被調(diào)用過程返回時,執(zhí)行會從此繼續(xù)指令從棧中彈出地址,并跳轉(zhuǎn)到那個位
置.要正確使用這條指令,就要使棧準(zhǔn)備好,棧指針要指向前面call指令存儲返回地址的位置.leave指令可
以用來使棧做好返回的準(zhǔn)備.它等價于下面的代碼序列:
rrovl%ebp,%esp//setstackpointertobeginningofframe
popl%ebp//restoresaved%ebpandsetstackptrtoendofcall'sframe
另外這樣準(zhǔn)備工作也可以通過直接使用傳送和彈出操作來完成.
存放器%eax可以用來返回值,如果函數(shù)要返回整數(shù)或指針的話.
(4)根據(jù)慣例,存放器%eax,%edx,和%ecx被劃分為調(diào)用者俁存(callersave)存放器.當(dāng)過程p調(diào)用Q
時,Q可以覆蓋這些存放器,而不會被破壞任何P所需要的數(shù)據(jù).
另外,存放器%ebx,%esi和%81被劃分為被調(diào)用者保存(calleesave)存放器.這意味著Q必須在覆蓋他
們之前,將這些存放器的值保存到棧中,并在返回前恢復(fù)他們,應(yīng)為P(或某個更高層次的過程)可能會在今
后的計算中需要這些值.此外,根據(jù)這里描述的慣例,必須保持存放器%ebp和%esp.
(5)單操作數(shù)的操作符&和*可以產(chǎn)生指針和間接引用指針.也就是,對于一個表示某個對象的表達式
Expr,&Expr表示一個地址.對于表示一個地址的表達式Addr-Expr,*Addr-Expr表示該地址中的值.因此,
表達式Expr與*&Expr是等價的.
可以對數(shù)組和指針應(yīng)用數(shù)組下標(biāo)操作,如數(shù)組引用A[i]與表達式,(A+i)是一樣的.它計算第i個數(shù)組元素的
地址,然后訪問這個存儲器位置.
(6)數(shù)組元素在存儲器中是按照"行優(yōu)先"的順序排列的,這就意味著先是行0的所有元素,后面是行1的所
有元素,以此類推.
(7)一個聯(lián)合的總的大小等于它最大域的大小.
(8)無論數(shù)據(jù)是否對齊JA32硬件都能正確工作.不過Jntel還是建議要對齊數(shù)據(jù)以提高存儲器系統(tǒng)的性
能.Linux沿用的對齊策略是2字節(jié)數(shù)據(jù)類型(例如short)的地址必須是2的倍數(shù),而較大的數(shù)據(jù)烈性(例如
int,int*,float和double)的地址必須是4的倍數(shù).注意,這個要求就意味著一個short類型對象的地址最低
位必須等于。.類似地,任何int類型的對象或指針的地址的最低兩位必須都是0.
//============================================
2010.07.13
深入理解計算機系統(tǒng)
(1)編寫高效程序需要兩類活動:
第一、我們必須選擇一組最好的算法和數(shù)據(jù)結(jié)構(gòu);
第二、我們必須編寫出編譯器能夠有效優(yōu)化以轉(zhuǎn)換成高效可執(zhí)行代碼的源代碼.
(2)優(yōu)化程序性能的根本策略:
1:|高級設(shè)計.為手邊的問題懸著適當(dāng)?shù)乃惴ê蛿?shù)據(jù)結(jié)構(gòu).要特別警覺,防止使用會漸進的產(chǎn)生糟糕性能的
算法或編碼技術(shù).
2:i根本編碼原那么.防止限制優(yōu)化的因素,這樣編譯器就能產(chǎn)生高效的代碼.
消除連續(xù)的函數(shù)調(diào)用.在可能時,將計算移到循環(huán)之外.考慮有選擇的妥辦程序的模塊性以獲得更大的效
率.
消除不必要的存儲器引用.引入噴時變量來保存中間結(jié)果.只有在最后的值計算出來時,才將結(jié)果存放到
數(shù)組或全局變量中.
3)低級優(yōu)化.
嘗試各種與數(shù)組代碼相對的指針形式.
通過展開循環(huán)降低循環(huán)開銷.
通過諸如迭代分隔之類的技術(shù),找到使用流水線的功能單元的方法.
最后的忠告,要小心防止花費精力在令人位家的結(jié)果上.?項有用的技術(shù)是.在優(yōu)化代碼時使用檢查代碼
(checkingcode)來測試代碼的每個版本,以確保在這一過程中沒有引入錯誤,檢瓷代碼將一系列測試應(yīng)用
到程序上,確保它得到期望的結(jié)果.
(3)量化評價一個程序中局限性的簡單原那么:
重復(fù)引用同一個變量的程序有良好的時間局限性.
對于具有步長為k的引用模式的程序,步長越小,空間局限性越好.具有步長為1的引用模式的程序有很好
的空間局限性.在存儲器中以大步長跳來跳去的程序空間局限性會很差.
對于取指令來說,循環(huán)有好的時間和空間局限性.循環(huán)體越小,循環(huán)迭代次數(shù)越多,局部性越好.
(4)推薦以下技術(shù):
符你的注意力集中在內(nèi)部循環(huán)上,大局部計算和存儲器訪問都發(fā)生在這里.
通過按照數(shù)據(jù)對象存儲在存儲器中的順序來讀取數(shù)據(jù)數(shù)據(jù),從而使得你的程序中的空間局部性最大.
記住,不明中率只是確定你代碼性能的一個因素(雖然是重要的).存儲器訪問數(shù)量也扮演著重要角色,有
時需要在兩者之間做一下折中.
〃============================================
2010.07.19
深入理解計算機系統(tǒng)
(1)學(xué)習(xí)鏈接只是的原因:
理解連及其將幫助你構(gòu)造大型程序.
理解連接將幫助你防止一些危險的編程錯誤.
理解連將幫助你理解其他重要的系統(tǒng)概念.
理解鏈接將使你能夠開發(fā)共享庫.
(2)一個典型的ELF可重定位目標(biāo)文件包含下面兒個節(jié):
.text:以編譯程序的機器代碼.
.rodata:只讀數(shù)據(jù),如printf語句口的格式串和開關(guān)(switch)語句的跳轉(zhuǎn)表.
.data:以初始化的全局c變量.局部C變量在運行時被保存在棧中,既不出現(xiàn)在.data中,也不出現(xiàn)在.bss節(jié)
中.
.bss:未初始化的全局變量.在口標(biāo)文件中這個節(jié)不占據(jù)實際的空間,它僅僅是一個占位符.口標(biāo)文件格式
區(qū)分初始化和未初始化變量是為了空間效率:在目標(biāo)文件中,未初始化變量不需要占據(jù)任何實際的磁盤空
間.
.symtab:一個符號表(symboltable),他存放在程序中被定義和引用的函數(shù)和全局變量的信息.
?回.text:當(dāng)連接器把目標(biāo)文件和其他文件結(jié)合時,.text節(jié)中的許多位置都需要修改.一般而言,任何調(diào)用外
部函數(shù)或者引用全局變量的指令都需要修改.另一方面,調(diào)用本地函數(shù)的指令那么不需要修改.注意,可執(zhí)
行目標(biāo)文件中并不需要重定位信息,因此通常省略,除非使用者顯式地指示連接器包含這些信息.
.el.data:被模塊定義或引用的任何全局變量的信息.一般而言,任何已初始化全局變量的初始值是全局變
量或者外部定義函數(shù)的地址都需要被修改.
.Cebug:一個調(diào)試符號表,其中有些表目是程序中定義的局部變量和類型定義,有些表目是程序中定義和
引用的全局變量,有些是原始的C源代碼.只有以?g選項調(diào)用編譯驅(qū)動程序時,才會得到這張表.
.line:原始C源程序中的行號和.text節(jié)中機器指令之間的映射.只有以-g選項調(diào)用編譯驅(qū)動程序時才會得
到這張表.
.strtab:一個字符串表,其內(nèi)容包括.systab和.debug節(jié)中的符號表,以及節(jié)頭部中的節(jié)名字.字符串表就是
以null結(jié)尾的字符串序列.
(3)利用static屬性隱藏變量和函數(shù)的名字.
C程序員使用static屬性在模塊內(nèi)部隱藏變量和函數(shù)聲明,就像你在jave和C++中使用public和private
聲明一樣.C源代碼文件扮演模塊的角色.任何聲明帶有static屬性的全局變量或者函數(shù)都是模塊私有的.
類似的,任何聲明為不帶static屬性的全局變量和函數(shù)都是公開的,可以被其他模塊訪問.盡可能用static
書香來保護你的變量和函數(shù)時很好的編程習(xí)慣.
(4)函數(shù)和已經(jīng)初始化的全局變量是強符號,未初始化的全局變量是弱符號.
(5)根據(jù)強弱符號的定義,unix連接器使用下面的規(guī)那么來處理多出定義的符號:
規(guī)那么1:不允許有多個強符號.
規(guī)那么2:如果有一個強符號和多個弱符號,那么選擇強符號.
規(guī)那么3:如果有多個弱符號,那么從這些弱符號中任意選擇一個.
〃============================================
2010.07.20
深入理解計算機系統(tǒng)
(1)共享庫(sharedlibrary)是致力于解決靜態(tài)庫缺陷的一個現(xiàn)代創(chuàng)新產(chǎn)物.
共享庫是一個目標(biāo)模塊,在運行時,可以加載到任意的存儲器地址,并在存儲器中和一個程序連接起來,這
個過程稱為動態(tài)鏈接(dynamiclinking),是由一個叫動態(tài)連接器(dynamiclinker)的程序來執(zhí)行的.
(2)共享庫的“共享”在兩個方面有所不同.首先,在任何給定的文件系統(tǒng)中,對于一個庫只有一個.s。文件.
所有引用該庫的可執(zhí)行目標(biāo)文件共享這個.so文件中的代碼與數(shù)據(jù),而不像靜態(tài)庫的內(nèi)容那樣被拷貝和嵌
入到引用它們的可執(zhí)行的文件中.其次,在存儲器中,一個共享庫的.text節(jié)只有一個副本可以被不同的正
在運行的進程共享.
⑶java定義了一個標(biāo)準(zhǔn)調(diào)用規(guī)那么,叫做jave本地接口(javenativeinterface,JNI),它允許java程序調(diào)
用"本地的"c和C++函數(shù),JNI的根本思想是將本地的C函數(shù),比方說foo,編譯到共享庫中,如foo.so.3■
個長在運行的java程序試圖調(diào)月函數(shù)foo時,java解釋程序利用dlopen接口(或者某個類似于此的東西)
動態(tài)鏈接和加載foo.so,然后再調(diào)用函數(shù)too.
(4)理解ECF很重要的原因:
理解ECF將幫助你理解重要的系統(tǒng)概念.
理解ECF將幫助你理解應(yīng)用程序是如何與操作系統(tǒng)交互的.
理解ECF將幫助你編寫有趣的新應(yīng)用程序.
理解ECF將幫助你理解軟件異常如何工作.
(5)當(dāng)異常處理程序完成處理后、根據(jù)引起一場的事件的類型,會發(fā)生一下三種情況中的一種:
1.處理程序?qū)⒖刂品祷亟o當(dāng)前指令I(lǐng)curr(當(dāng)事件發(fā)生時正在執(zhí)行的指令).
2.處理程序?qū)⒖刂品祷亟oInext:如果沒有發(fā)生異常將會執(zhí)行的下一條指令).
3.處理程序終止被中斷的程序.
(6)異常的類型有:中斷(interrupt),陷阱(trap),故障(fault)和終止(abort).
⑺任何邏輯流在時間上和另外的邏輯流重疊的進程被稱為并發(fā)進程(concurrentprocess).
而這兩個進程就被稱為并發(fā)運行.
進程和其他進程輪換運行的概念稱為多任務(wù)(multitasking).一個進程執(zhí)行它的控制流的一局部的每一時
間段叫做時間片(timeslice).因此,多任務(wù)也叫做時間分片(timeslicing).
(8)進程的三種狀態(tài):
運行.進程要么在CPU上執(zhí)行,要么在等待被執(zhí)行且最終會被調(diào)度.
暫停.進程的執(zhí)行被掛起(suspended),且不會被調(diào)度.
終止.進程永遠地停止.進程因為三種原因終止:收到一個信號,該信號的默認(rèn)行為是終止進程;從主程序返
回;調(diào)用exit函數(shù).
(9)一個終止了但還未被回收的進程成為僵死進程(zombie).
//============================================
2010.07.21
深入理解計算機系統(tǒng)
(1)任意時刻,虛擬頁面的集合都分為三個不相交的子集:
未分配的:VM系統(tǒng)還未分配(或者創(chuàng)立)的頁.未分配的塊沒有任何數(shù)據(jù)和他們相關(guān)聯(lián),因此也就不占用任
何磁盤空間.
級存的:當(dāng)前緩存在物理存儲器中的已分配頁.
未緩存的:沒有緩存在物理存儲器中的已分配頁.
(2)顯示分配器的一些相當(dāng)嚴(yán)格的約束條件:
處理任意請求序列.
立即響應(yīng)請求.
只使用堆.
對齊塊(對齊要求).
不修改已分配的塊.
(3)與套接字限定相關(guān)的流限定:
限定一:輸入函數(shù)跟在輸出函數(shù)之后.如果中間沒有插入對fflush,fseek,fsetpos或者rewind的調(diào)用,一個
輸入函數(shù)不能跟在一個輸出函數(shù)之后flush函數(shù)清空與流相關(guān)的緩沖區(qū).
限定二:輸入函數(shù)跟在輸入函數(shù)之后.如果中間么有插入對fflush,fseek,fsetpos或者rewind的調(diào)用,一
個輸出函數(shù)不能跟隨在一個輸入函數(shù)之后,除非該輸入函數(shù)遇到了一個文件結(jié)束.
對I/O流的第-個限定能夠通過采用在每個輸入操作前刷新緩沖區(qū)這樣的規(guī)那么來保證實現(xiàn).
保證實現(xiàn)第二個限定的唯一方法是,對同一個翻開的套接字描述符翻開兩個流,一個用來讀,一個用來寫;
FILE*fpin,*fpout;
fpint=fopen(sockfd,"r");
fpout=fopen(sockfd,"w");
但是這樣做也有問題,因為它要求應(yīng)用程序在兩個流上都要調(diào)用fclose,這樣才能釋放與每個流相關(guān)聯(lián)的
存儲儲資源,防止存儲器xielou(bd太齷齪了).
fclose(fpin);
fclose(fpout);
//============================================
2010.08.05
深入理解計算機系統(tǒng)
(1)四類線程不平安函數(shù).
第一類:不保護共享變量的函數(shù);
第二類:保持跨越多個調(diào)用的狀態(tài)的函數(shù);
第三類:返回指向靜態(tài)變量的指針的函數(shù);
第四類:調(diào)用線程不平安函數(shù)的函數(shù);
⑵死鎖.
程序員使用p和v操作順序不當(dāng),以至兩個信號量的禁止區(qū)域(forbiddenregion)重疊.
重疊的禁止區(qū)域引起了一組稱為死鎖區(qū)域(deadlockregion)的狀態(tài).
死鎖是一個相當(dāng)困難的問題,因為它不總是可預(yù)測的.
(3)使用簡單而有效的規(guī)那么來防止死鎖.
互斥鎖加鎖順序規(guī)那么:如果對于程序中每對?互斥鎖(s,t),每個既包含s也包含t的線程都按照相同的
順序同時對他們加鎖,那么這個程序就是無死鎖的.
〈深入理解計算機系統(tǒng)〉筆記分享
第一章:計算機系統(tǒng)漫游這本書是為這樣一些程序員而寫的,他們希望通過了解這些部件如何工作以及如
何影響程序的準(zhǔn)確性和性能,來提高自身的技能.
系統(tǒng)中所有的信息一包括磁盤文件,存儲器中的程序,存儲器中存放的用戶數(shù)據(jù)以及網(wǎng)絡(luò)上傳送的數(shù)據(jù),都
是由一串比特表示的.
c語言是貝爾實驗室的DennisRitchie于1969T973年間創(chuàng)立的.美國國家標(biāo)準(zhǔn)化組織在1989年公布了
ANSIC的標(biāo)準(zhǔn).該標(biāo)準(zhǔn)定義了C語言和一系列函數(shù)庫,即所謂的標(biāo)準(zhǔn)C庫.
c和unix操作系統(tǒng)關(guān)系密切.c從開始就是作為一種用于unix系統(tǒng)的程序語言開發(fā)出來的.unix內(nèi)核的大
局部,以及所有它支持的工具和函數(shù)庫都是用c語言編寫的.
C是一個小而簡單的語言,C語言的設(shè)計是由一個人完成的,其結(jié)果就是這是一個簡潔明了,沒有什么冗贅
的設(shè)計.
c是為實踐目的設(shè)計的.c是設(shè)計用來實現(xiàn)unix操作系統(tǒng)的.它是系統(tǒng)編程的首選.同時它非常適用于應(yīng)用
級程序的編寫.
預(yù)處理器,編譯器,匯編器和連接器一起構(gòu)成.了編譯系統(tǒng).
匯編語言是非常有用的,因為它為不同的高級語言的不同編譯器提供了通用的輸出語言.
GNU環(huán)境包括EMAC編譯器,GCC編譯器,GDB調(diào)試器,匯編器,連接器,處理二進制文件的工具以及其他
一些部件.
shell是一種命令行解釋器,它輸出一個提示符,等待你輸入一行命令,然后執(zhí)行這個命令.如果該命令的第
一個單詞不是一個內(nèi)置的shell命令,那么shell就會假設(shè)這是一個可執(zhí)行文件的名字,要加載和執(zhí)行該文
件.
每個I/O設(shè)備都是通過一個控制器或適配器于I/O總線連接起求的.控制器和適配器之間的區(qū)別主要在
它們的組成方式.控制器是I/O設(shè)備本身中或是主板上的芯片組,而適配器那么是一塊插在主板插槽上的
卡.
主存是臨時存儲設(shè)備,在處理器執(zhí)行程序時,它被用來存放程序和程序處理的數(shù)據(jù).物理上來說,主存是由
一組DRAM芯片組成的,邏輯上來說,存儲器是由一個線性的字節(jié)數(shù)組組成的.
中央處理單元簡稱處理器,是解釋存儲在主存中指令的引擎.處理器的核心是一個被稱為程序計數(shù)器的字
長大小的存儲設(shè)備.在任何一個時間點上,PC都指向主存中的某條機器語言指令.
從系統(tǒng)通電開始,直到系統(tǒng)斷電,處理器一直在不假思索的重復(fù)執(zhí)行相同的根本任務(wù):從程序計數(shù)器指向
的存儲器處讀取指令,解釋指令中的位,執(zhí)行指令中的簡單操作,然后更新程序計數(shù)器指向下一條指令,而
這條指令并不一定在存儲器中和剛剛執(zhí)行的指令相鄰.
利用稱為DMA(直接存儲器存?。┑募夹g(shù),數(shù)據(jù)可以不通過處理器而直接從磁盤到達主存.
常字符串的顯示過程:存儲器到存放器文件,再從存放器文件到顯示設(shè)備.
?個典型的存放器文件只存儲幾百字節(jié)的信息,主存里可存放幾百萬字節(jié).然而,處理器從存放器文件中
讀數(shù)據(jù)比從主存中讀取要快幾乎100倍.
L1和L2高速緩存是用一種叫做靜態(tài)隨機訪問存儲器的硬件技術(shù)實現(xiàn)的.
我們可以把操作系統(tǒng)看成是應(yīng)用程序和硬件之間插入的一層軟件.
操作系統(tǒng)有兩個根本功能:防止硬件被失控的應(yīng)用程序濫用;在控制復(fù)雜而又通常廣泛不同的低級硬件設(shè)
備方面,為應(yīng)用程序提供簡單一致的方法.
程序在現(xiàn)代系統(tǒng)上運行時,操作系統(tǒng)會提供一種假象,就好似系統(tǒng)上只有這個程序是在運行的.這些假象
是通過進程的概念來實現(xiàn)的,進程是計算機科學(xué)中最重要和最成功的概念之一.
在現(xiàn)代系統(tǒng)中,一個進程實際上可以由多個稱為線程的執(zhí)行單元組成.每個線程都運行在進程的上下文中,
并共享同樣的代碼和全局?jǐn)?shù)據(jù).
虛擬存儲器是一個抽象概念,它為每個進程提供了一個假象,好似每個進程都在獨占的使用主存.每個進
程看到的存儲器都是一致的.
每個進程看到的虛擬地址空間由大量準(zhǔn)確定義的區(qū)組成,從最低的地址開始:程序代碼和數(shù)據(jù)(代碼和數(shù)
據(jù)區(qū)是由可執(zhí)行目標(biāo)文件直接初始化的);堆(作為調(diào)用像malloc和free這樣的c標(biāo)準(zhǔn)庫函數(shù)的結(jié)果,堆可
以在運行時動態(tài)的擴展和收縮);共享庫(共享庫的概念非常強大,但是也是個相當(dāng)難懂的概念);棧(位于
用戶虛擬地址空間頂部的是用戶棧,編譯器用它來實現(xiàn)函數(shù)的調(diào)用);內(nèi)核虛擬存儲器(內(nèi)核是操作系統(tǒng)總
是駐留在存儲器中的局部).
虛擬存儲器的運作需要硬件和操作系統(tǒng)軟件之間的精密更雜的相互合作,包括對處理器生成的每個地址
的硬件翻譯.根本思想是把一個進程虛擬存儲器的內(nèi)容存儲在磁盤上,然后用主存作為磁盤的高速緩存.
Linux逐漸開展成為一個技術(shù)和文化現(xiàn)象,通過和GNU工程的力量結(jié)合,Linux工程開展成為了一個完整
的,符合Posix標(biāo)準(zhǔn)的Unix操作系統(tǒng)的版本,包括內(nèi)核和所有支撐的根底設(shè)施.
操作系統(tǒng)內(nèi)核是應(yīng)用程序和硬件之間的媒介,它提供三個根本的抽象概念:文件是I/O設(shè)備的抽象概念:
虛擬存儲器是對主存和磁盤的抽象概念:進程是處理器,支撐和I/O設(shè)備的抽象概念.〃
第二章:信息的表示和處理
2的n次方的二進制表示為1后面加n個o;
指針變量將用到機器的全字長Jongint*也是這樣;
可移植性的?個方面就是使程序?qū)Σ煌瑪?shù)據(jù)不敏感;
c標(biāo)準(zhǔn)對不同類型的數(shù)字范圍設(shè)置了下限,但是沒有上限;
存儲數(shù)據(jù)分大端法和小端法;
反匯編器是?種確定可執(zhí)行程序文件所表示的指令序列的工具;
不同的機器使用不同的且不兼容的指令和編碼方式;
布爾的and和異或分別相當(dāng)于模2的乘法和加法;
c標(biāo)準(zhǔn)沒有明確定義使用那種類型的右移;
c和C++中的有符號樹是默認(rèn)的;
c的標(biāo)準(zhǔn)并沒有要求用二進制補嗎來表示有符號數(shù);
c庫中的文件<limits.h>定義了一-組常量,來限定運行編譯器的這臺機器的不同整型數(shù)據(jù)的范圍;
printf沒有使用任何輸出變量類型的信息(how);
無符號和有符號數(shù)混合運算,將有符號數(shù)轉(zhuǎn)化為無符號數(shù);
一種有名的用來執(zhí)行二進制補區(qū)的非的技術(shù)是取反并加一;
編譯器用移位和加法運算的組合來代替乘以常數(shù)因子的乘法;
單精度浮點的符號,指數(shù)和有效數(shù)字分別是1,8,23.雙精度為1,11,52.有效數(shù)字的第一位總是1,因此我們不
需要表示它;
IEEE浮點格式定義了4種不同的舍入方式,默認(rèn)是找到最接近的匹配.這四種方式為:向偶數(shù)舍入,向。舍
入,向上舍入,向下舍入;
浮點存放器使用一種特殊的8o位的擴展精度格式;
浮點數(shù)取亦就是簡單的將其符號位取反;
第三章:程序的機器級表示匯編程序員可以看到程序計數(shù)器,整數(shù),浮點數(shù)存放器和條件碼存放器;
匯編代碼只是將存儲器看成是一個很大且按字節(jié)尋址的數(shù)組;
對標(biāo)量數(shù)據(jù)類型,匯編代碼也不區(qū)分有符號和無符號數(shù),不區(qū)分各種類型的指針,甚至不區(qū)分指針和整數(shù);
程序存儲器包含程序的目標(biāo)代碼,操作系統(tǒng)需要的一些信息,用來管理過程調(diào)用和返回的運行時棧,以及
用戶分配的存儲器塊;
IA32CPU有8個32位值的存放器,前6個是通用的,后2個保存棧指針和幀指針;
最頻繁使用的指令是執(zhí)行數(shù)據(jù)傳送的指令;
局部變量通常是保存在存放器中;
除了右移操作,所有的指令都不區(qū)分有符號數(shù)和無符號數(shù);
IA32程序用程序棧來支持過程的調(diào)用,棧用來傳遞過程參數(shù),存儲返回信息,保存存放器以供以后的恢復(fù)
之用,以及用于本地存儲;
為單個過程分配的那局部棧稱為梭幀,它的最頂端是以兩個指針定界的;
存放器%eax可以用來返回值,如果函數(shù)要返【可整數(shù)或指針的話;
IA32中%02.%?(1*和%ecx被劃分為調(diào)用者保存存放器,其余三個為被調(diào)用者保存存放器;
IA32也仍然在不斷增加新的指令類,來支持處理多媒體應(yīng)用的需要;
許多計算機系統(tǒng)要求某種數(shù)據(jù)類型的對象必須是某個值的k倍,這種對其限制簡化了處理器和存儲器系
統(tǒng)之間的接口硬件設(shè)計;
&操作符可以應(yīng)用到任何左值類的C表達式上,包括變量,結(jié)構(gòu),聯(lián)合和數(shù)組元素;
用高級語言編寫的程序可在許多不同的機器上編譯執(zhí)行,而匯編代碼是于特定機器密切相關(guān)的;
1997-PentiumII1999-Pentiumin2OO1-Pentium4;
美國商標(biāo)局不允許用數(shù)字作為商標(biāo);
Intel現(xiàn)在稱其指令集為IA32;
匯編代碼非常接近于機器代碼;
匯編代碼只是將存儲器看成是一個很大的,按字節(jié)尋址的數(shù)組;
機器實際執(zhí)行的程序只是對一系列指令進行編碼的字節(jié)序列,機器對產(chǎn)生這些指令的源代碼一無所知;
call過程調(diào)用leave為返回準(zhǔn)備棧ret從過程調(diào)用中返回;
指針提供一種統(tǒng)一方式,能夠遠程訪問數(shù)據(jù)結(jié)構(gòu);
malloc函數(shù)返回一個通用指針;
指針也可以指向函數(shù),這提供了一個很強大的存儲和傳遞代碼引用的功能(how);
數(shù)年來,AMD的策略一致是在技術(shù)上緊跟Intel后面,生產(chǎn)性能稍低但是價格更廉價的處理器;
浮點數(shù)使用?組完全不同的指令和存放器(相對整數(shù)來說);
IA32加了一條限制,傳送指令的兩個操作數(shù)不能都指向存儲器的位置,第一個是源操作數(shù),第二個是目標(biāo)
操作數(shù);
局部變量通常是保存在存放器中的,這樣就能更快的訪問到它;
加載有效地址(loadeffectiveaddress)指令leal實際上是movl指令的變形,但H標(biāo)操作數(shù)必須是一個存放
器;
編譯器產(chǎn)生的代碼中會用一個存放器存放多個程序值,還會在存放器之間傳送程序值;
匯編代碼提供了實現(xiàn)非順序控機流的較低層次的機制,這是通過借助條件碼存放器來完成的;
當(dāng)執(zhí)行PC相關(guān)的尋址時,程序計數(shù)器的值是跳轉(zhuǎn)指令后面的那條指令的地址,,而不是跳轉(zhuǎn)指令本身的地
址;
switch語句不僅提高了C代碼的可讀性,而且通過使用一種跳轉(zhuǎn)表的數(shù)據(jù)結(jié)構(gòu)使得實現(xiàn)更加立效,跳轉(zhuǎn)表
是一個數(shù)組,表項i是一個代碼段的地址,這個代碼段實現(xiàn)的是些開關(guān)索引值等于i時程序應(yīng)該采取的動作;
數(shù)據(jù)傳遞,局部變量的分配了釋放是通過操縱程序棧來實現(xiàn)的;
IA32程序用程序棧來支持過程調(diào)用;
當(dāng)對一個局部變量使用地址操作符&的時候,該變量不能保存在存放器中;
call指令的效果是將返回地址入棧,并跳轉(zhuǎn)到被調(diào)用過程的起始處.返回地址是緊跟在程序中call后面的
那條指令的地址.ret指令從棧中彈出地址并跳轉(zhuǎn)到那個位置;
在較老的IA32處理器模型中,整數(shù)乘法指令要花費3。個時鐘周期,所以編譯器要盡可能的防上使用它,
而大多數(shù)新近的處理器模型中,乘法指令只需要3個時鐘周期,所以不一定會進行這樣的優(yōu)化;
c和C++都要求程序顯式的用free函數(shù)來釋放已經(jīng)分配的空間,在Java中,釋放是由運行時系統(tǒng)通過一個
稱為垃圾回收的進程自動完成的;
存放器溢出是IA32一個很常見的問題,因為處理器的存放器數(shù)量太少了;
結(jié)構(gòu)的實現(xiàn)類似于數(shù)組的實現(xiàn),因為結(jié)構(gòu)的所有組成局部都存放在存儲器中連續(xù)的區(qū)域內(nèi),而指向結(jié)構(gòu)的
指針就是結(jié)構(gòu)的第一個字節(jié)的地址;
struct數(shù)據(jù)類型的構(gòu)造函數(shù)是c提供的于C++和java對象最為接近的東西;
蠕蟲是這樣一種程序,它可以自己運行,并且能夠?qū)⒁粋€完全有效的自己傳播到其他的機器上.與此相應(yīng)
的,病毒是這樣一段代碼,它能將自己添加都包括操作系統(tǒng)在內(nèi)的其他程序中,但是它不能獨立的運行;〃
(141516節(jié)未看)
第五章:優(yōu)化程序性能編寫高效的程序需要兩類活動:第一,我們必須選擇一組最好的算法和數(shù)據(jù)結(jié)構(gòu);第
二,我們必須編寫出編譯器能夠有效優(yōu)化以轉(zhuǎn)成高效可執(zhí)行代碼的源代碼;
事實上,編譯器只能執(zhí)行有限的程序轉(zhuǎn)換,而且阻礙優(yōu)化的因素還會阻礙這種轉(zhuǎn)換,阻礙優(yōu)化的因素就是
程序行為中那些嚴(yán)重依賴丁執(zhí)行環(huán)境的方面;
編譯器優(yōu)化程序的能力受幾個因素的限制,包括:要求它們絕不能改變正確的程序行為:它們對程序行為,
對使用它們的環(huán)境了解有限;需要很快的完成編譯工作;
編譯器必須假設(shè)不同的指針可能會指向存儲器中同一個位置,這造成了一個主要的阻礙優(yōu)化的因素,這也
是可能嚴(yán)重限制編譯器產(chǎn)生優(yōu)化代碼時機的程序的?個方面;
編譯器會假設(shè)最糟的情況,并保持所有的函數(shù)調(diào)用不變;
代碼移動的優(yōu)化包括識別出要執(zhí)行屢次但是計算結(jié)果不會改變的計算,因而我們可以將計算移動到代碼
前面的,不會被屢次求值的局部;
c中的字符串是以null結(jié)尾的字符序列,strlen必須一步一步的檢查這個序列,直到遇到null字符;
過程的調(diào)用會帶來相當(dāng)大的開銷,而且阻礙大多數(shù)形式的程序優(yōu)化;
消除不必要的存儲器引用,具體是用一些臨時變量,這些變量很可能被存在存放器中(如果沒有溢出的話);
在匯編代碼級,看上去似乎是一次是執(zhí)行一條指令,每條指令都包括從存放器或存儲器取值,執(zhí)行一個操
作,并把結(jié)果存回到一個存放器或存儲器位置.在實際的處理器中,是同時對多條指令求值的.在某些設(shè)計
中,可以有8o或更多條指令在處理中.
P6微體系結(jié)構(gòu)是自20世紀(jì)9。年代后期以來許多廠商生.產(chǎn)的高端處理器的典型.在工業(yè)界稱為超標(biāo)量,
意思是它可以在每個時鐘周期執(zhí)行多個操作,而且是亂序的,整個設(shè)計有兩個主要局部:ICU(Instruction
ControlUnit,指令控制單元)和EU(ExecutionUnit,執(zhí)行單元).
ICU從指令高速緩存中讀取指令,指令高速緩存是一個特殊的高速緩存存儲器,它包含最近訪問的指令;
指令解碼邏輯接收實際的程序指令,并將它們轉(zhuǎn)換成一組根本的操作;
加載和存儲單元通過數(shù)據(jù)高速緩存訪問存儲器,這是一個高速存儲器,包含最近訪問的數(shù)據(jù)值;
退役單元紀(jì)錄正在進行的處理,并確保遵守機器級程序的順序語意.退役單元控制著存放器的更新;
任何對程序狀態(tài)的更新都只會在指令退役時才發(fā)生,只有在處理器能夠確信這條指令的所有分支都預(yù)測
正確了,才能這樣做;
執(zhí)行時間的范圍從根本整數(shù)操作的一個周期,到加載,存儲,整數(shù)乘法和更常見的浮點操作的幾個周期,到
除法和其他復(fù)雜操作的許多個周期;
處理器的幾個功能單元被流水線化了,這意味著在前一個操作完成之前,它們就可以開始一個新的操作;
浮點乘法器要求連續(xù)的操作之間至少要?兩個周期,而兩個除法器根本就沒有流水線化;
標(biāo)記可以與并不會寫道存放器文件中的中間值相關(guān)聯(lián);
循環(huán)展開本身只會幫助整數(shù)求利情況中代碼的性能,因為我們的其他情況是被功能單元的執(zhí)行時間限制
的;
編譯器可以很容易的執(zhí)行循環(huán)展開,只要優(yōu)化級別設(shè)置得足夠高(例如,優(yōu)化選項-02)許多編譯器都能例
行公事的做到這一點,在命令行上以'-funroll-loops'調(diào)用GCC,它會執(zhí)行循環(huán)展開;
有時候,我們能夠通過使用指針,而不是數(shù)組改良一個程序的性能;編譯器對數(shù)組代碼應(yīng)用非常高級的優(yōu)
化,而對指針只應(yīng)用最小限度的優(yōu)化,為了可讀性的緣故,通常數(shù)組代碼更可取一些;
循環(huán)分割:我們可以通過將一組合并操作分割成兩個或更多的局部,并在最后合并結(jié)果來提高性能;
對于整數(shù)數(shù)據(jù)類型的情況,總共只有八個整數(shù)據(jù)傳區(qū)可用.其中兩個指向棧中的區(qū)域;
八個整數(shù)和八個浮點存放器的限制是IA32指令集的不幸產(chǎn)物,前面講到國的重命名消除了存放器名字和
存放器數(shù)據(jù)實際位置之間的聯(lián)系.在現(xiàn)代處理器中,存放器名字之簡單的用來標(biāo)識在功能單元之間傳遞的
程序值.IA32只提供了很少量的這樣的標(biāo)識符,限制了在程序中能表達的并行性的數(shù)量;
某個與及其相關(guān)的因素將浮點乘法能到達的CPE限制在『15而不是理論極限值的1.0;
程序優(yōu)化的通用原那么對各種不同的機器都適用,即使某種特殊的特性組合導(dǎo)致最優(yōu)性能依賴于特殊的
機器;
到目前,臺式機或效勞器中幾乎每個處理器都支持投機執(zhí)行;
一個存儲器讀的結(jié)果依賴于一個非常近的存儲器的寫叫做讀寫相關(guān),它導(dǎo)致了處理速度的下降;
movl%edx,(%ecx)被翻譯成兩個操作:storeaddr指令計算存儲操作的地址,創(chuàng)立一個存儲緩沖區(qū)中的條
目,并設(shè)置該條目的地址字段;storedata指令設(shè)置該條目的數(shù)據(jù)字段;
通常,處理器/存儲器接口是處理器設(shè)計中最復(fù)雜的局部之一.不查閱詳細的文檔和使用機器分析工具,我
們只能給出實際行為的一個假象的描述;
由于存儲器操作占到了程序很大一局部,存儲器子系統(tǒng)優(yōu)化成以獨立的存儲器操作來提供更大的并行性;
優(yōu)化程序性能的根本策略:
1.高級設(shè)計,為手邊的問題選擇適當(dāng)?shù)乃惴ê蛿?shù)據(jù)結(jié)構(gòu);
2.根本編碼原那么,消除函數(shù)的連續(xù)調(diào)用,在可能時,將計算移到循環(huán)外.考慮有選擇的妥協(xié)程序的模塊性
以獲得更大的效率;消除不必要的存儲器引用,引入中間變量求保存中間結(jié)果,只有在最后的值計算由求
的時候,才將結(jié)果存放到數(shù)組或全局變量中;
3.低級優(yōu)化.嘗試各種于數(shù)組代碼相對的指針形式;通過展開循環(huán)降低循環(huán)開銷;通過諸如迭代分割之類
的技術(shù),找到使用流水線化的功能單元的方法;
Unix系統(tǒng)提供了一個剖析程序GPROF.這個程序產(chǎn)生兩種形式的信息.首先,它確定程序中每個函數(shù)花費
了多少CPU時間.其次,它計算每個函數(shù)被調(diào)用的次數(shù),以調(diào)用函數(shù)來分析;
庫函數(shù)qsort是際遇快速排序算法進行排序的;
剖析是工具箱中一個很有用的工具,但是它不應(yīng)該是唯一一個,即使測量不是很準(zhǔn)確,特別是對較短的運
行時間來說.結(jié)果只適用于被測試的那些特殊的數(shù)據(jù);
Amdahl定律的主要觀點:要想大幅度提高整個系統(tǒng)的速度,我們必須提高整個系統(tǒng)很大一局部的速度;
Amdahl定律描述了一個改良任何過程的通用原那么.除了適用于提高計算機系統(tǒng)的速度外花還能指導(dǎo)
一個公司試著降低生產(chǎn)剃須刀的本錢,或是指導(dǎo)一個學(xué)生改良他或她的平均績點.或許它在計箕機世界里
最有意義,在計算機世界中,我們通常將性能提高?倍或更多.只有通過優(yōu)化系統(tǒng)很大?局部才能獲得這
么高的提高率;
第六章:存儲器層次結(jié)構(gòu)
RAM分SRAM和DRAM
DDR-SDRAM:雙倍數(shù)據(jù)速率同步DRAM.通過時鐘的兩個邊沿作為控制信號,從而使DRAM的速度加倍.
ROM是以它們能被重編程的次數(shù)和對它們進行重新編程的機制來區(qū)分的:PROM,EPROM,EEDROM.閃
存是基于EEPROM的;
存儲在ROM設(shè)備中的程序通常被稱為固件,當(dāng)一個計算機系統(tǒng)通電以后,它會運行存儲在ROM中的固件;
總線是一組并行的導(dǎo)線,能攜帶數(shù)據(jù),地址和控制信號;
系統(tǒng)總線將CPU連接到I/O橋接器,存儲器總線將I/O橋接器連接到主存,1/0橋接器也將系統(tǒng)總線和存
儲器總線連接到I/O總線;
扇區(qū)包含相等數(shù)量的數(shù)據(jù)位,扇區(qū)之間由一些間隙分隔開,間隙用來存儲標(biāo)識扇區(qū)的格式化位;
多個盤面時,任何時刻,所有讀寫頭都位于同一柱面上;
磁盤是以扇區(qū)大小的塊來讀寫數(shù)據(jù)的;
磁盤中有一個小的硬件/固件設(shè)備,稱為磁盤控制器,維護著邏輯塊號和實際磁盤扇區(qū)之間的映射關(guān)系;
在磁盤可以存儲數(shù)據(jù)之前,它必須被磁盤控制器格式化,這包括標(biāo)識扇區(qū)的信息填寫扇區(qū)之間的間隙,標(biāo)
識出外表有故障的柱面并且不適用它們,以及在每個區(qū)中預(yù)留出一組柱面作為備用;
在使用存儲器映射I/O的系統(tǒng)中,地址空間中有一塊地址是為與I/O設(shè)備通信保存的,每個這樣的地址稱
為一個I/O端口;
現(xiàn)代計算機頻繁使用基于SRAM的高速緩存;
有良好局部性的程序比局部性差的程序運行得更快;
代碼區(qū)別于程序數(shù)據(jù)的一個重要屬性是在運行時不能修改;
局部變量的反更引用是好的,步長為1的引用模式是好的;
如果你的程序需要的數(shù)據(jù)是存儲在CPU存放器中的,那么在執(zhí)行期間,在零個周期內(nèi)就能訪問到它們;如
果存儲在高速緩存中,需要1-10個周期;如果存儲在主存中,需要50-100個周期;而如果存儲在磁盤上,需
要大約20OOOOOO個周期;
具有良好局部性的程序傾向于一次又一次的訪問相同的數(shù)據(jù)項集合,或是傾向于訪問鄰近的數(shù)據(jù)項集合;
恃別的,我們將注意力集中在CPU和主存之間作為緩存區(qū)域的高速緩存存儲器上,因為它們對應(yīng)用程序
性能影響最大;
隨機訪問存儲器(random-accessmemory,RAM)分為兩類一靜態(tài)的和動態(tài)的.靜態(tài)RAM(SRAM)比動態(tài)
RAM(DRAM)更快,但也貴得多;
SRAM將每個位存儲在一個雙穩(wěn)態(tài)的存儲器單元里;每個單元是用一個六晶體管電路來實現(xiàn)的.這個電路
有這樣一個屬性,它可以無限期的保持在兩個不同的電壓配置或狀態(tài)之一;
DRAM存儲器可以制造的非常密集一每個單元由一個電容和一個訪問晶體管組成;
只要有電,SRAM就是持續(xù)的,與DRAM不同,它不需要刷新.SRAM的存取比DRAM快.SRAM對諸如光
和電噪音這樣的干擾不敏感.代價是SRAM單元比DRAM單元使用更多的晶體管,因而沒那么密集,而且
更貴,功耗更大;
電路設(shè)計者將DRAM組織成二維陣列而不是線性數(shù)組的一個原因是降低芯片上地址管腳的數(shù)量;
DRAM芯片包裝在存儲器模塊中,它插到主板的擴展槽上;二維陣列組織的缺點是必須分兩步發(fā)送地址,
這增加了訪問時間;
增強的DRAM:FPMDRAM(fastpagemodeDRAM,快頁模式DRAM);EDODRAM(extendeddataout
DRAM,擴展數(shù)據(jù)輸出DRAM);SDRAM(synchronousDRAM,同步DRAM);DDRSDRAM(double
data-ratesynchronousDRAM,雙倍數(shù)據(jù)速率同步);RambusDRAM;
一些系統(tǒng)在固件中提供了少量的輸入和輸出函數(shù)一例如,PC的BIOS例程;I/O橋接都將系統(tǒng)總線的電信
號翻譯成存儲器總線的電信號;
磁盤是由一個或多個疊放在一起的盤片組成的,它們放在一個密封的包裝里,正個裝置通常別叫做磁盤驅(qū)
動滯,雖然我們通常簡稱位磁盤;
對扇區(qū)的訪問時間有三個主要局部:尋道時間,旋轉(zhuǎn)時間,傳送時間;
從存儲器中讀一個512字節(jié)扇區(qū)大小的塊的時間對SRAM來說大約是256ns,對DRAM來說大約是
4000ns.磁盤訪問時間比SRAM大約大4000倍;比DRAM大約大2500倍;
當(dāng)操作系統(tǒng)想要執(zhí)行一個I/O操作時,例如讀一個磁盤扇區(qū)的數(shù)據(jù)到主存,操作系統(tǒng)會發(fā)送一個命令到磁
盤控制器,讓它讀某個邏輯塊號.控制器上的固件執(zhí)行一個快速表查找,將一個邏輯塊號翻譯成一個(盤面,
磁道,扇區(qū))的三元組,這個三元組唯一的標(biāo)識了對應(yīng)的物理扇區(qū),控制器上的硬件解釋這個三元組,將I/O
頭移動到適當(dāng)?shù)闹?,等待扇區(qū)移動到I/O頭下,將I/O頭感知到的位放到控制器上的一個小緩沖區(qū)中,
然后將它們拷貝到主存中;
像圖形卡,監(jiān)視器,鼠標(biāo),鍵盤,這樣的設(shè)備都是通過諸如Intel的PCI(peripheralcomponentinterconnect
外圍設(shè)備互聯(lián))總線這樣的I/O總線連接到CPU和主存的;
雖然I/O總線比系統(tǒng)總線和存儲器總線慢,但是它快頁容納種類繁多的第三方I/O設(shè)備;
USB控制器是一個將設(shè)備連接到USB的電路,USB的吞吐率可以到達12Mbit/s,是為慢速或中速串行設(shè)
備設(shè)計的;
圖形卡包含硬件和軟件邏輯,它們負(fù)責(zé)代表CPU在顯示器上畫像素;
磁盤控制器包含硬件和軟件邏輯,它們用來代表CPU讀寫磁盤;
當(dāng)一個設(shè)備連接到總線時,它與一個或多個端口相關(guān)聯(lián);
邏輯塊的概念不僅能夠提供應(yīng)操作系統(tǒng)一個更簡單的接口,還能夠提供一層抽象,使得磁盤更加健壯;
磁盤中有一個小的硬件/固件設(shè)備,稱為磁盤控制器,維護著邏輯塊號和實際磁盤扇區(qū)之間的映射關(guān)系;
操作系統(tǒng)用主存來緩存磁盤文件系統(tǒng)中最近被使用的磁盤塊;
對于取指令來說,循環(huán)有好的時間和空間局部性,循環(huán)體越小,循環(huán)次數(shù)越多,局部性越好;
一般而言,層次結(jié)構(gòu)中較低層的設(shè)備的訪問時間較長,因此為了補償這些較長的訪問時間,傾向于使用較
大的塊;
在一個有虛擬存儲器的系統(tǒng)中,DRAM主存作為存儲在磁盤上的數(shù)據(jù)塊的緩存,是有操作系統(tǒng)軟件和
CPU上的地址翻譯硬件共同管理的;
高速緩存確定一個請求是否命中燃后抽取出被請求的字的過程,分為三步:組選擇;行匹配;字拍??;
沖突不命中在真實的程序中很常見,會導(dǎo)致令人困惑的性能問題;
即使程序有良好的空間局部性,而我們的高速緩存中也有足夠的空間來存放兩個數(shù)組的塊,每次引用還是
會導(dǎo)致沖突不命中,這是因為這些塊被映射到了同一個高速緩存組;
直寫高速緩存通常是非寫分配的,寫回高速緩存通常是寫分配的;
只保存指令的高速緩存稱為i-cache,只保存程序數(shù)據(jù)的高速緩存稱為d-cache.一個典型的桌面系統(tǒng)CPU
芯片本身就包括?個Lii-cache和?個Lid-cache;
一方面,較大的高速緩存可能會提高緩存命中率;另一方面,使得大存儲器運行得更快總是要難一些的;
現(xiàn)代系統(tǒng)通常會折中,使高速緩存塊包含4-8個字;
傳統(tǒng)上,努力爭取時鐘頻率的高性能系統(tǒng)會選擇直接映射L1高速緩存,而在較低層上使用比擬小的相關(guān)
度,但是沒有固定的規(guī)那么;
一般而言,高速緩存越往下層,越可能使用寫回而不是直寫;
因為一行總是存儲一個塊,術(shù)語行和塊通?;Q使用,例如,系統(tǒng)專家總是說高速緩存的行人小,實際上他
們指的是塊大??;
理解存儲器層次結(jié)構(gòu)本質(zhì)的程序員能夠利用這些知識,編寫出更有效的程序,無論具體的存儲系統(tǒng)是怎樣
的.特別的,我們推薦以下技術(shù):將你的注意力集中在內(nèi)部循環(huán)上,大局部計算和存儲器訪問都發(fā)生在這里;
通過按照數(shù)據(jù)對象存儲在存儲器中的順序來讀數(shù)據(jù),從而使得你程序中空間局部性最大;一旦從存儲器中
讀入一個數(shù)據(jù)對象,就盡可能多的使用它,從而使得你程序中的時間局部性最大;記住,不命中率只是確定
你代碼性能的一個因素,存儲器訪問數(shù)量也扮演著重要的角色,有時候要在兩者之間做一下折中;〃(6.6未
看)
第七章:連接
連接器完成的兩個主要任務(wù):符號解析和重定位.
編譯器和匯編器生成地址。開始的代碼和數(shù)據(jù)節(jié).
目標(biāo)文件:可重定位目標(biāo)文件,可執(zhí)行目標(biāo)文件,共享目標(biāo)文件.
ELF可重定位目標(biāo)文件:ELF頭以一個16字節(jié)的序列開始,這個序列描述了字的大小和生成該文件的系
統(tǒng)的字節(jié)順序..test.:已編譯程序的機器代碼;.rodata.:只讀數(shù)據(jù);.data.:已初始化的全局變量;.bss.:為初始
化的全局變量;.symtab.:存放程序中被定義和引用的函數(shù)和全局變量的信息.
連接器上下文中有三種符號:塊內(nèi)定義的全局符號;塊外定義的全局符號和本地符號;
定義為帶cstatic屬性的本地過程變量不是在棧中管理的,編譯器在.data.和.bss.中為每個定義分配空間;
任何聲明為static屬性的全局變量或函數(shù)是模塊私有的;
編譯相來保證本地符號的唯一性;
當(dāng)編譯器遇到一個不是在當(dāng)前模塊中定義的變量時,它會假設(shè)該符號是在其他某個模塊中定義的,生成一
個連接器符號表表目;
運行時的存儲器映像:未使用。只讀段->讀寫段->運行時堆->共享庫的存儲器映射區(qū)域。用戶棧。內(nèi)核
虛擬存儲器;
加載運行:可執(zhí)行文件中段頭表的指導(dǎo)下,加載代碼和數(shù)據(jù)->程序入口點_start->初始化函數(shù)->注冊函數(shù)
?>主函數(shù)?>返回;
c的啟動代碼對于每個c程序都是相同的,都需要跳到main函數(shù);
鏈接就是將不同局部的代碼和數(shù)據(jù)收集和組合成為一個單一文件的過程,這個文件可被加載到存儲器并
執(zhí)行.鏈接可以執(zhí)行于編譯時,也就是在源代碼被翻譯成機器代碼時丁也可以執(zhí)行于加載時,也就是在程序
被加我器加載到存儲器并執(zhí)行時;甚至執(zhí)行于運行時,由應(yīng)用程序來執(zhí)行;
鏈接器在軟件開發(fā)中扮演著一個關(guān)鍵的角色,因為他們使得別離編譯成為了可能;
理解鏈接器將幫助你構(gòu)造大型程序;理解鏈接器將幫助你防止一些危險的編程錯誤;理解鏈接器將幫助你
理解語言的作用域規(guī)那么是如何實現(xiàn)的;理解鏈接器將幫助你理解其他重要的系統(tǒng)概念;理解銃接器使你
能夠開發(fā)共享庫;
目標(biāo)文件純粹是字節(jié)塊的集合,這些塊中,有些包含程序代碼,有些那么包含程序數(shù)據(jù),而其他的那么包含
指導(dǎo)鏈接器和加載器的數(shù)據(jù)結(jié)構(gòu).鏈接器將這些塊連接起來,確定鏈接塊的運行時位置,并且修改代碼和
數(shù)據(jù)塊中的各種位置.鏈接器對目標(biāo)機器了解甚少,產(chǎn)生目標(biāo)文件的編譯器和匯編器已經(jīng)完成了大局部工
作;
目標(biāo)文件有三種形式:1.可重定位目標(biāo)文件包含二進制代碼和數(shù)據(jù),其形式可以在編譯時與其他可重定位
日標(biāo)文件合并起來,創(chuàng)立一個可執(zhí)行目標(biāo)文件;2.可執(zhí)行目標(biāo)文件包含二進制代碼和數(shù)據(jù),其形式可以被直
接拷貝到存儲器并執(zhí)行;3.共享巨標(biāo)文件一種特殊類型的可重定位目標(biāo)文件,可以在加載活著運行時,被動
態(tài)的加載到存儲器并鏈接;
各個系統(tǒng)之間,目標(biāo)文件的格式都不相同;
SUNSolaris使用的是UnixELF(可執(zhí)行可鏈接格式).盡管我們的討論集中在ELF上,但是不管是那種格
式,根本的概念是相似的;
ELF頭以一個16字節(jié)的序列開始,這個序列描述了字的大小和生成該文件的系統(tǒng)的字節(jié)順序.ELF頭剩
卜.的局部包含幫助徒接器解析用解釋目標(biāo)文件的信息.其中包括了ELF頭的大小,目標(biāo)文件的類型(可重
定位,可執(zhí)行或是共享等),機器類型(IA32等),節(jié)頭部表的文件偏移,以及節(jié)頭部表中的表目大小和數(shù)量.不
同節(jié)的位置和大小是有節(jié)頭部表描述的,其中目標(biāo)文件中每個節(jié)都有一個固定大小的表目;
每個可重定位目標(biāo)文件m都有一個符號表,它包含m所定義和引用的符號的信息.在鏈接器的上下文中,
有二種不同的符號.由m定義并能被其他模塊引用的全局符號.全局鏈接器符號對應(yīng)于非靜態(tài)的c函數(shù)
以及被定義為不帶c的static屬性的全局變量;2.由其他模塊定義的并被模塊m引用的全局符號.這些符
號稱為外部符號,對應(yīng)于定義在其他模塊中的c函數(shù)和變量;3.只被模塊m定義和引用的本地符號.有的
本地鏈接器符號對應(yīng)于代static屬
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 國家思政課題申報書
- 高職省級課題申報書
- 黨建雙創(chuàng)課題申報書
- 醫(yī)學(xué)婦科課題申報書范文
- 養(yǎng)殖設(shè)備銷售合同范本
- ai生成課題申報書
- 合同范本封面彩色設(shè)計
- 課題如何寫申報書
- 信用保證保險合同范本
- 印刷租賃合同范本
- 港股通開戶測評答案
- ISO9001質(zhì)量手冊
- 主機主冷油器切換操作票
- 屋面防水施工方案—自粘聚合物改性瀝青防水卷材
- 地球結(jié)構(gòu)示意圖.
- 三科變頻器SK說明書
- 廣東專插本高等數(shù)學(xué)真題
- 云南省普通初中學(xué)生成長記錄
- 仿真技術(shù)在車架防腐性能開發(fā)中的應(yīng)用
- 初一平面直角坐標(biāo)系集體備課
- 高一年級英語必修二學(xué)科導(dǎo)學(xué)案全冊
評論
0/150
提交評論