【系統】深刻理解計算機系統·持續更新
- 對於一個無符號數字x,截斷它到k位的結果就至關於計算x mod 2^k.
- 在大多數的機器上,整數乘法指令至關地慢,須要12或者更多的始終週期,然而其餘整數運算-例如加法、減法、位移運算和移位-只須要1個時鐘週期.所以,編譯器使用的一項重要的優化就是試着使用移位和加法運算的組合來代替乘以常數因子的乘法.
- 在大多數的機器上,整數除法要比整數乘法更慢-須要30或者更多的始終週期.
- 除以2的冪也能夠用移位運算來實現,只不過咱們用的是右移,而不是左移.對於無符號和二進制補碼數,分別使用邏輯移位和算術移位來達到目的.
- 注意系統的分類:主流的IA32(也就是x86),以及x86-64(也就是x64),還有種Intel的與原32位系統不兼容的IA64。
- 編譯系統由預處理器,編譯器,彙編器和連接器組成。
- 單指令多數據並行稱爲SIMD並行,其擴展爲SSE指令集。
- x64上long爲8字節,指針也爲8字節。
- 無符號數右移必須採用邏輯右移,而有符號數通常採用算術右移。
- 有符號數碰見無符號數會默認強轉爲無符號數。
- short轉爲unsigned時,是先擴展大小再符號轉換。
- 補碼非的計算:從左到右將第一個爲1的位前的全部位取反
- 負數的補碼移位向下舍入。
- 正浮點數能使用整數排序函數來進行排序。
- 浮點加法和乘法不具有結合性,浮點乘法在加法上不具有分配性。
- 預處理器擴展源代碼,而後編譯器生成源代碼的文本彙編代碼,彙編器轉成二進制彙編碼,連接器生成exe或dll或lib。
- 寄存器能夠保存地址也能夠保存值。注意彙編中的加括號表示爲取該地址指向的值,如(%eax)指%eax中保存的地址指向的值。
- 傳送指令的兩個操做符不能都指向存儲器。
- 棧指針%esp保存着棧頂元素的值,%eax保存函數返回值。
- 棧從高地址往低地址分配,堆從低地址往高地址分配。
- 注意:lea,假設爲leal 7(%edx, %eax, 4),則當%edx中保存的是地址時,lea爲取有效地址,而當%edx中保存的是值時,lea爲算術運算,即7 + %edx + %eax * 4。這兒的%eax總保存值。說白了,其實lea一直是在作計算,只是%edx影響了直觀表達而已。
- 注意:處理有無符號值的操做是經過不一樣的彙編指令來區分的。
- 大多數彙編器根據一個循環的do-while形式來產生循環代碼,逆向工程會用到。
- 指令無視操做數的長度。
- 由於有個條件傳送的優化策略,因此(xp ? *xp : 0)這條語句其實兩個選擇分支都會執行。
- 32位系統中,大多數棧中信息的訪問其位置都是基於幀指針的。而64位系統中,棧的存儲信息數已被弱化,因此無幀指針了。
- 訪問某個局部變量的前提是該局部變量至少有個可引用的地址,因此局部變量被保存在了棧中。
- 爲了防止從效率低的存儲器讀寫值時,可能因數據未對齊而形成屢次讀寫從而致使低性能,IA32要求數據必定要對齊。編譯器在編譯時會強制對齊。
- 彙編指令leave等於倆pop,效果同樣,選擇隨意。pop和push在棧上分配空間的方式是直接棧指針減去或加上偏移量。
- 指針之差等於 相差字節數 / 所指類型大小字節數。
- 寄存器不夠用時會出現寄存器溢出,這時就必須有值被保存在棧上了,通常是將只讀變量放入棧。
- GCC會對局部char類型的緩衝區插入金絲雀保護代碼。
- 在C中內聯彙編代碼只能針對某一類機器。
- SSE2引入浮點數面向寄存器的指令集,而不用基於棧的方法。
- x64能讓彙編代碼比x32少不少,可是實際性能提高不會很大。
- 注意rep有時當空操做使。
- x64中,棧空間向下128字節之內的區域仍能夠被函數訪問,該區域被ABI稱爲紅色地帶。
- 浮點相關:把存儲模型,指令和傳遞規則組合稱爲浮點體系結構。
- 邏輯門只是簡單的響應輸入的變化而已。
- HCL中,'='只是表示用一個名字來稱謂一個表達式。其類switch的表達中的」1:「等同於switch中的Default Case。
- 寄存器文件上的讀或寫端口都分別成對,一個傳ID,一個傳內容。
- 訪存階段讀寫存儲器,寫回階段將結果寫到寄存器文件。
- 寄存器文件和數據存儲器等都是當前時鐘隨意讀,下一時鐘統一寫入更新。即時鐘控制狀態元素的更新。
- 流水線即保持各單元在時鐘週期內忙碌不已,一套流水線硬件供多個流水線使用。
- 加載互鎖和數據轉發技術結合起來足以處理可能類型的數據冒險。
- 當流水線化的系統中出現多條指令引發的異常時,最深的指令被處理的優先級最高。
- 每一個時鐘週期執行多個操做稱爲超標量,而超線程是指一個核同時運行倆線程。
- 處理器功能單元的性能表示中,延遲指按照嚴格順序執行完成合並運算所須要的最小週期數,而吞吐量指理論上最快完成一個操做所需週期數。
- 使用SSE能夠下降吞吐量界限。
- 書寫適合條件傳送實現的」功能式「代碼。
- 每一個加載/存儲單元每一個時鐘週期只能啓動一條加載/存儲操做。
- 性能提升技術:①.採用合適的算法和數據結構。②.消除連續的函數循環調用,在可能時儘可能將計算移到循環外;消除沒必要要的存儲器引用,引入臨時變量來保存中間結果;保持內層循環在存儲器層面的局部性。③展開循環;經過多個累計變量和從新結合等技術,提升指令級並行;用功能的風格重寫條件操做,使得編譯採用條件數據傳送。
- 內存是硬盤的緩存。
- core i7上全部的SRAM高速緩存存儲器都在CPU芯片上。
- 對於性能來講,存儲器訪問總數和不命中率相比,不命中率影響要更大。估計是由於存儲器的寫回緩存機制。
- 存儲器性能注意:將注意力集中在內循環上,大部分計算和存儲器訪問都發生在這裏;經過按照數據對象存儲在存儲器中的順序,以步長爲1來讀數據,從而使得空間局部性最大;一旦從存儲器中讀入了一個數據對象,就儘量多的使用它,從而使得時間局部性最大。
- 對於靜態庫的連接,只會連接程序中用到的該庫(.lib)中的模塊(.obj)。這其實也解釋爲何分別連接靜態庫版本和動態庫版本的兩程序大小相差不是那麼懸殊。
- 當前指令處理完後,處理器才能去發現中斷是否發生。
- Linux系統調用的參數都是經過通用寄存器而不是棧傳遞的。
- C++的try-catch是C種setjmp和longjmp的更加結構化的版本。
- DRAM做爲磁盤的緩存,不命中開銷巨大。
- 磁盤上的交換文件同時又做爲DRAM保存數據的緩存。
- 延遲私有對象中的拷貝最充分的利用了稀有的物理存儲器,這是經過寫時拷貝實現的。
- 一個系統中被全部進程分配的虛擬存儲器的所有數量是受磁盤上交換空間的數量限制的。
- 形成堆利用率很低的主要緣由是內存碎片的存在。
- 有時爲了極個別的幾個特殊狀況而要去每次調用時都檢查,還不如經過某些方式直接把特殊狀況通常化,能用通用的方式去處理。
- 內存引用致使的崩潰要注意:引用壞指針/野指針,以及讀未初始化的存儲器。
- UNIX信號是不排隊的,若爲考慮處理,則會直接丟棄。
- 函數內部的static變量也是線程間共享的。
- 注意並行和併發的區別,並行程序是一個運行在多個處理器上的併發程序。
- 線程數多過核數對效率反而會有影響,但影響不大。
- 注意:rand和ctime,localtime等函數時線程不安全的,慎用啊慎用!可用其可重入版本。
- 互斥鎖記得相同順序加鎖解鎖。
- 包裝錯誤處理函數,是一個很是不錯的作法。
歡迎關注本站公眾號,獲取更多信息