2017-2018-1 20155214 《信息安全系統設計基礎》第14周學習總結

2017-2018-1 20155214 《信息安全系統設計基礎》第14周學習總結

教材第5章學習內容總結

咱們描述許多提升代碼性能的技術。理想的狀況是編譯器可以接受咱們編寫的任何代碼併產生儘量高效的、具備指定行爲的機器級程序現代編譯器採用了複雜的分析和優化方式並且變得愈來愈好,然而即便是最好的編譯器也受到了妨礙優化因素的阻礙。程序員必須編寫容易優化的代碼,幫助編譯器。html

總結本章新收穫

  • 5.1 優化編譯器的能力和侷限性
    在只執行安全的優化中編譯器必須假設不一樣的指針可能會指向內存中的同一個位置。

兩個指針可能指向一個內存位置稱爲 內存別名使用git

void twiddle1(long *xp,long *yp){
    *xp += *yp;
    *xp += *yp;
}

當考慮指針 xp 和 yp 指向相同內存地址時,該函數可能產生二義性,及xp值翻了4倍程序員

當函數修改全局變量等 反作用 時,可能會妨礙優化。
那麼算法

long counter = 0;

long func1opt(){
    long t = 4 * counter + 6;
    counter += 4;
    return t;
}

經過內聯替換函數調用
顯然優於

long func1in(){
    long t = counter++;
    t += counter++;
        t += counter++;
            t += counter++;
            return t;
}
  • 每元素的週期數CPE
void psum2(float a[],float p[],long n)
{
    long i;
    p[0] = a[0];
    for(i = 1;i < n-1;i += 2){
        float mid_val =p[i-1] + a[i];
        p[i] = mid_val;
        p[i+1] = mid_val + a[i+1];
    }
    
    if(i < n)
    p[i] = p[i-1] + a[i];
}

當使用for循環迭代計算前置和。每次調用函數都會執行創建棧幀和恢復棧幀,這一段代碼的耗時是一個定值S。隨着循環次數n的變化,總的耗時T=S + n*L,其中L爲for循環的單位循環執行時間,在本書中又稱做每元素週期數CPE。數組

上述代碼的運行時間近似於 368+6.0n ,所以psum2的CPE爲6.0。安全

  • 未經優化的代碼是從C到機器代碼的直接翻譯,一般效率明顯較低。簡單地使用 -O1 ,就會進行基本的優化。顯著地提高程序性能。
  • 經過移動要執行屢次可是計算結果不會改變的計算,稱爲代碼移動。能夠幫助編譯器進行優化。
void combine4(vec_ptr v,data_t *dest){
    long i;
    long length = vec_length(v);
    data_t *data = get_vec_start(v);
    data_t acc = IDENT;
    
    for(i = 0;i < length;i++){
        acc = acc + data[i];
    }
    *dest = acc;
}

經過將循環中的累計結果放在臨時的局部變量中,能夠消除每次循環迭代沒必要要的內存讀寫
  • 亂序處理
    目前的高級處理器,爲了提升內部邏輯元件的利用率以提升運行速度,一般會採用多指令發射、亂序執行等各類措施。如今廣泛使用的一些超標量處理器一般可以在一個指令週期內併發執行多條指令。
    從編譯器的角度來看,編譯器可以對很大一個範圍的代碼進行分析,可以從更大的範圍內分辨出能夠併發的指令,並將其儘可能靠近排列讓處理器更容易預取和併發執行,充分利用處理器的亂序併發功能。因此現代的高性能編譯器在目標碼優化上都具有對指令進行亂序優化的能力。而且能夠對訪存的指令進行進一步的亂序,減小邏輯上沒必要要的訪存,以及儘可能提升 Cache命中率和CPU的LSU(load/store unit)的工做效率。因此在打開編譯器優化之後,看到生成的彙編碼並不嚴格按照代碼的邏輯順序是正常的。

  • 5.8循環展開

若是計算循環索引和測試循環條件的循環開銷部分所佔比重過大,這時就能夠考慮使用一種被稱做"循環展開"的方式來優化代碼。所謂循環展開就是經過在每次迭代中執行更多的數據操做來減少循環開銷的影響。其基本思想是設法把操做對象線性化,而且在一次迭代中訪問線性數據中的一小組而非單獨的某個。這樣獲得的程序將執行更少的迭代次數,因而循環開銷就被有效地下降了。數據結構

循環展開技術的好處在於它能減少循環開銷的影響。但它也不是沒有缺點的,天下沒有免費的午飯!首先,循環展開增長了生成的目標代碼的數量,這很容易理解,由於循環體在源代碼級別就已經變得龐大。讀者能夠試想它們被翻譯成目標代碼時的狀況。爲了驗證這一點,讀者可使用Visual C++來對比使用循環展開先後循環體的彙編代碼的長度,驗證結果將代表循環展開對目標代碼的長度的確有很大的影響。固然,在咱們所舉的例子中,循環展開所要付出的代價都是比較小的。固然這並不能歸納其餘全部的狀況,所以這個空間換時間的折中最優位置還須要針對具體問題來作具體的分析。 使用循環展開時一方面要考慮實際待處理數組的長度,並由此選擇一個較好的展開度;另外一方面要綜合考慮這個展開度對時空開銷比例的影響,在儘可能不會使目標代碼空間消耗激增的前提下得到最高的時間收益。另外,也可讓編譯器爲咱們完成這些工做。一般,編譯器能夠很容易地執行循環展開,但這須要設定其優化級別足夠高,因此程序員也能夠選擇讓編譯器來完成這個工做。固然,咱們曾經提醒過讀者,在開發階段並不適合將優化級別設置得太高,所以若是你但願讓編譯器執行循環展開,那麼最好等到軟件開發完成以後。併發

for(i=0;i<limit;i+=2){
    acc = (acc OP data[i]) OP data[i+1];
}
經過減小循環次數,減小關鍵路徑上的操做數量。
  • 從新結合變換
for(i=0;i<limit;i+=2){
    acc = acc OP (data[i] OP data[i+1]);
}
經過從新結合變換,提升程序並行性。

結對學習搭檔講解問題

  • 什麼是amdahl定律?

想要大幅提升整個系統的速度,必須提升整個系統很大一部分的速度。取決於這個部分有多麼重要和速度提升了多少。函數

  • 編寫高效程序須要幾類活動?
  1. 必須選擇一組合適的算法和數據結構;
  2. 必須編寫出編譯器能有效優化以轉換成高效可執行代碼的源代碼。
  3. 針對處理運算量特別大的計算,將一個任務分紅多個部分,這些部分能夠在 多核和多處理器的某種組合上並行地計算。

結對學習搭檔連接

博客園連接:http://www.cnblogs.com/LeeX1997/性能

結對學習照片

其餘(感悟、思考等,可選)

經過本週的再次學習,讓我對於如何編寫高效代碼有了進一步理解。
更重要的是,對於 高級語言-編譯器-處理器 之間的關係更明確了。

代碼託管

參考資料

相關文章
相關標籤/搜索