找出全書你認爲學得最差的一章,深刻從新學習一下,要求(期末佔5分):html
實際上,存儲器系統是一個具備不一樣容量、成本和訪問時間的存儲設備的層次結構。java
存儲器層次結構是可行的。總體效果是一個大的存儲器池,其成本與層次結構底層最便宜的存儲設備至關,可是卻以接近於層次結構頂部存儲設備的高速率向程序提供數據。git
計算機系統中一個基本而持久的思想:若是你理解了系統是如何將數據在存儲器層次結構中上下移動的,那麼你就能夠編寫你的應用程序,使得它們的數據項存儲在層次結構較高的地方,在那裏cpu能更快的訪問它們。程序員
這個思想圍繞着計算機程序的一個稱爲局部性的基本屬性。編程
在本章中,咱們會看看基本的存儲技術,並描述它們是如何被組織成層次結構的。數組
隨機訪問存儲器分爲兩類:靜態,動態。SRAM比DRAM更快,更貴。SRAM做爲高速緩存存儲器。DRAM做爲主存。緩存
SRAM將每一個位存儲在一個雙穩態存儲單元裏。只要有電,它就保持他的值。安全
DRAM將每一個位存儲爲對一個電容的充電。DRAM單元在10-100ms內失去電荷,因此須要刷新或者其餘的方法保證數據正確性。dom
DRAM表示通常寫成NW,w是一個單元的位數,N是單元數。自己稱這個單元是超單元。而後N又表示爲rc,這樣的表示是尋址的時候地址引腳不會太多,好比N=16,就要4個引腳。4*4的話,4須要兩個引腳。可是這種二維陣列組織有個缺點:兩步發送地址,增長了訪問時間。分佈式
DRAM的加強型有:FPM DRAM,EDO DRAM,SDRAM,DDR SDRAM(DDR,DDR2,DDR3),Random DRAM,VRAM。
PC使用的DRAM歷史:95以前FPM,96-99EDO,-02SDRAM和DDR,-10DDR3。
非易失性存儲器,SRAM和DRAM都是易失的。
ROM稱爲只讀存儲器是歷史緣由,不少ROM都是可寫的。ROM的分類是以它們可以被重編程(寫)的次數和對他們進行重編程的機制來劃分的。
ROM包括:PROM,EPROM,EEPROM,閃存(基於EEPROM)。
存儲在ROM設備中的程序一般稱爲固件。
總線事物:讀事物——從主存傳送數據到cpu,寫事物——從cpu傳送數據到內存。
磁盤是廣爲應用的保存大量數據的存儲設備:盤片,表面,主軸,RPM,磁道,扇區,柱面。
對於SRAM和DRAM,KMGT一般是1024爲基,但對於磁盤,KMGT以1000爲基。
像圖形卡,監視器,鼠標,鍵盤和磁盤這樣的I/O設備,都是經過I/O總線(PCI)鏈接到cpu和主存的。
系統總線和存儲器總線是與cpu總線相關的,但pci這樣的總線和底層cpu無關。
I/O總線老是比系統總線和存儲器總線慢,可是它能夠容納種類繁多的第三方I/O設備。主機總線適配器將一個或多個磁盤鏈接到I/O總線,最經常使用的是SCSI和SATA,前者更貴,更快。
cpu使用一種稱爲存儲器映射I/O的技術,在使用該技術的系統中,地址空間中有一塊地址是爲與I/O設備通訊保留的。每一個這樣的地址稱爲一個I/O端口。當一個設備鏈接到總線上時,它與一個或多個端口相聯繫。
cpu從磁盤讀數據時發生的步驟:cpu經過將命令、邏輯塊號和目的存儲器地址寫到與磁盤相關聯的存儲器映射地址,發起一個磁盤讀;磁盤控制器讀扇區,並執行到主存的DMA傳送;DMA傳送完成時,磁盤控制器用中斷的方式通知CPU。
現代磁盤將他們的構造呈現爲一個簡單的視圖,一個B個扇區大小的邏輯塊序列。磁盤控制器維護着邏輯塊號和實際(物理)磁盤扇區之間的映射關係。這裏看到,邏輯塊對應扇區。
SSD包,由一個或多個閃存芯片和閃存翻譯層組成。
存儲器和磁盤技術的一個基本事實:增長密度比下降訪問時間更容易。
DRAM和磁盤的性能滯後於cpu的性能。現代計算機頻繁的使用基於SRAM的高速緩存,試圖彌補處理器-存儲器之間的差距。這種方法可行是由於應用程序的局部性。
一個編寫良好的計算機程序嚐嚐具備良好的局部性。也就是說,他們傾向於引用臨近於其餘最近引用過的數據項的數據項,或者最近引用過的數據項自己。
這種傾向性,被稱爲局部性原理,是一個持久的概念,對硬件和軟件系統的設計和性能都有着極大的影響。
局部性一般有兩種不一樣的形式:時間局部性和空間局部性。
二者的區別在於時間對的是一個存儲器位置,空間對的是附近的存儲器位置。
被引用過一次的存儲器位置極可能在不遠的未來再被屢次引用——時間。一個存儲器位置被引用了一次,那麼程序極可能在不遠的未來引用附近的一個存儲器位置——空間。
對於空間局部性,步長爲1的引用模式稱爲順序引用模式,這種模式具備最好的空間局部性,如數組,一個一個的順序訪問具備最好的空間局部性。
多維數組,按照行優先順序,具備最好的空間局部性。
量化評價一個程序中局部性的簡單原則:
存儲器層次結構是組織存儲器系統的方法,人想的,如今全部的計算機系統都使用了這種方法。
通常而言,高速緩存是一個小而快速的存儲器設備,它做爲存儲在更大,也更慢的設備中的數據對象的緩衝區域。使用高速緩存的過程稱爲緩存。
存儲器層次結構的中心思想是:對於每一個k,位於k層的更快更小的存儲設備做爲位於k+1層的更大更慢的存儲設備的緩存。
也就是說層次結構的每一層都緩存來自較低一層的數據對象。
這裏必須強調一下,這也就是說數據時不能夠越級的嗎?
數據老是以塊大小爲傳送單元在第k層和第k+1層之間來回拷貝的。例子:L1和L0的傳送是1個字的塊,L2和L1之間是8-16個字的塊。
一些概念:緩存命中,緩存不命中,犧牲塊,替換策略,冷緩存,強制性不命中,冷不命中,放置策略,衝突不命中,容量不命中。
歸納來講,基於緩存的存儲器層次結構行之有效,是由於較慢的存儲設備比較快的存儲設備更便宜,同時,還由於程序每每展現局部性。
早期計算機系統的存儲器層次結構只有三層:cpu寄存器,DRAM主存,磁盤。隨着cpu和主存之間差距的逐漸增長,系統設計者被迫加入了SRAM高速緩存存儲器,稱爲L1/L2/L3高速緩存。
L1一般須要2-4個時鐘週期,L2一般須要10個時鐘週期,L3一般須要30-40個時鐘週期。
高速緩存存儲器結構的一些細節:直接映射高速緩存,組相聯高速緩存,全相聯高速緩存。
高速緩存參數的性能影響:不命中率,命中率,命中時間,不命中處罰。
(這一節,瞭解一些硬件知識,結構的細節無論了)
局部性比較好的程序更容易有較低的不命中率,而不命中率較低的程序每每比不命中率較高的程序運行的更快。
下面就是咱們用來確保代碼高速緩存友好的基本方法:
讓最多見的狀況運行得快。程序一般把大部分時間都花在少許的核心函數上,而這些函數一般把大部分時間都花在了少許循環上。
每一個循環內部緩存不命中數量最小。(對局部變量的反覆引用是好的,步長爲1的引用模式是好的)
存儲器系統的性能不是一個數字就能描述的,相反,它是一座時間和空間局部性的山,這座山的上升高度差異能夠超過一個數量級。明智的程序員會試圖構造他們的程序,使得程序運行在山峯而不是低谷。
仍是這幾項,推薦的技術:
將你的注意力集中在內循環上,大部分計算和存儲器訪問都發生在這裏。
經過按照數據對象存儲在存儲器中的順序、以步長爲1的來讀數據,從而使得你程序中的空間局部性最大。
一旦從存儲器中讀入了一個數據對象,就儘量多的使用它,從而使得程序中的時間局部性最大。
6.7 小結
程序經過編寫良好的局部性代碼利用好緩存。
1.隨機訪問存儲器(RAM, Random-Access Memory)
2.DRAM陣列
3.訪問主存
系統總線是一組並行的導線,能攜帶地址、數據和控制信號。可是不一樣總線不能直接互通,這就用到了I/O橋。
尋道時間:將磁頭定位到目標扇區所在的磁道。這個時間依賴於磁頭以前的位置和傳動臂在盤面上移動的速度。一般3~9ms。
旋轉時間:找到目標所在的第一個扇區。性能依賴於當前到達的磁道上相對目標扇區的位置和磁盤的旋轉速度。
傳送時間:讀寫扇區內容的時間。依賴於旋轉速度和當前磁道的扇區數目。
1.基本構造
(S, E, B, m),m是地址w的位長度。
容量計算:
高速緩存肯定一個請求是否命中,而後取出被請求的字的過程,分爲三步:1)組選擇,2)行匹配,3)字抽取。當且僅當設置了有效位,並且標記位與w地址中的標記位相匹配時纔算命中。
2.分類
全相聯高速緩存,只有一個組,全部的緩存行都在一個組裏。
N=64時:
sumA: 1/4
sumB: 1
sumC: 1/2
N= 60時:
sumA ,sumB,sumC的緩存不命中率均爲 1/4
比較難判斷的是N = 60時sumB的緩存不命中率(sumC與sumB是同樣的),我寫了一個函數返回不命中次數,將形參n賦值60便可。
//高速緩存命中率函數,返回不命中次數 int noHitPercentage(int n) { //不命中的次數 int result = 0; //總共要循環的次數 int count; //存儲塊的標記位 int a[256]; for(int i =0;i < 256;i++) { a[i] = -1; } for(int j = 0;j < n;j++) for(int i = 0;i < n;i++) { //求出這個數的相對索引 count = i * n + j; //求這個索引對應的塊號 int blockNo = (count/4) % 256; //求出標記t int t = (count/4)/256; //若是標記位不相等則不明中 if(t != a[blockNo]) { a[blockNo] = t; result++; } } return result; }
void betterTranspose(int *dst,int *src,int dim) { <span style="white-space:pre"> </span>int i, j; <span style="white-space:pre"> </span>int iCount,jCount; <span style="white-space:pre"> </span>//以4 * 4 的方陣爲單位依次計算,增長了寫的緩存命中率,多個元素一塊兒讀寫還減小了循環開銷 <span style="white-space:pre"> </span>for(i = 0;i < dim - 3;i += 4) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>iCount = i * dim; <span style="white-space:pre"> </span>for(j = 0;j < dim - 3;j += 4) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>jCount = j * dim; <span style="white-space:pre"> </span>dst[jCount + i] = src[iCount + j]; //dst[j][i] = src[i][j] <span style="white-space:pre"> </span>dst[jCount + i + 1] = src[iCount + dim + j]; //dst[j][i + 1] = src[i + 1][j] <span style="white-space:pre"> </span>dst[jCount + i + 2] = src[iCount + dim * 2 + j]; //dst[j][i + 2] = src[i + 2][j] <span style="white-space:pre"> </span>dst[jCount + i + 3] = src[iCount + dim * 3 + j]; //dst[j][i + 3] = src[i + 3][j] <span style="white-space:pre"> </span>dst[jCount + dim + i] = src[iCount + j + 1]; //dst[j + 1][i] = src[i][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 1] = src[iCount + dim + j + 1]; //dst[j + 1][i + 1] = src[i + 1][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 2] = src[iCount + dim * 2 + j + 1]; //dst[j + 1][i + 2] = src[i + 2][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim + i + 3] = src[iCount + dim * 3 + j + 1]; //dst[j + 1][i + 3] = src[i + 3][j + 1] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i] = src[iCount + j + 2]; //dst[j + 2][i] = src[i][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i + 1] = src[iCount + dim + j + 2]; //dst[j + 2][i + 1] = src[i + 1][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2 + i + 2] = src[iCount + dim * 2 + j + 2]; //dst[j + 2][i + 2] = src[i + 2][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 2+ i + 3] = src[iCount + dim * 3 + j + 2]; //dst[j + 2][i + 3] = src[i + 3][j + 2] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i] = src[iCount + j + 3]; //dst[j + 3][i] = src[i][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 1] = src[iCount + dim + j + 3]; //dst[j + 3][i + 1] = src[i + 1][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 2] = src[iCount + dim * 2 + j + 3]; //dst[j + 3][i + 2] = src[i + 2][j + 3] <span style="white-space:pre"> </span>dst[jCount + dim * 3 + i + 3] = src[iCount + dim * 3 + j + 3]; //dst[j + 3][i + 3] = src[i + 3][j + 3] <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>//記錄當前行和列的索引,以便執行完剩餘的項 <span style="white-space:pre"> </span>int curIndex = i; <span style="white-space:pre"> </span>//處理剩餘項,簡單的交換處理 <span style="white-space:pre"> </span>for(i = 0;i < curIndex;i++) <span style="white-space:pre"> </span>for(j = curIndex;j < dim;j++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>dst[j * dim + i] = src[i * dim + j]; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>for(i = curIndex;i < dim;i++) <span style="white-space:pre"> </span>for(j = 0;j < dim;j++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>dst[j * dim + i] = src[i * dim + j]; <span style="white-space:pre"> </span>} }
void better_col_convert(int *G,int dim) { int i, j; int iCount,jCount; //以4 * 4 的方陣爲單位依次計算,增長了寫的緩存命中率,多個元素一塊兒讀寫還減小了循環開銷 for(i = 0;i < dim - 3;i += 4) { iCount = i * dim; for(j = 0;j < dim - 3;j += 4) { jCount = j * dim; G[jCount + i] = G[iCount + j] || G[jCount + i]; //G[j][i] = G[i][j] || G[j][i] G[jCount + i + 1] = G[iCount + dim + j] || G[jCount + i + 1]; //G[j][i + 1] = G[i + 1][j] || G[j][i + 1] G[jCount + i + 2] = G[iCount + dim * 2 + j] || G[jCount + i + 2]; //G[j][i + 2] = G[i + 2][j] || G[j][i + 2] G[jCount + i + 3] = G[iCount + dim * 3 + j] || G[jCount + i + 3]; //G[j][i + 3] = G[i + 3][j] || G[j][i + 3] G[jCount + dim + i] = G[iCount + j + 1] || G[jCount + dim + i]; //G[j + 1][i] = G[i][j + 1] || G[j + 1][i] G[jCount + dim + i + 1] = G[iCount + dim + j + 1] || G[jCount + dim + i + 1]; //G[j + 1][i + 1] = G[i + 1][j + 1] || G[j +1][i + 1] G[jCount + dim + i + 2] = G[iCount + dim * 2 + j + 1] || G[jCount + dim + i + 2]; //G[j + 1][i + 2] = G[i + 2][j + 1] || G[j +1][i + 2] G[jCount + dim + i + 3] = G[iCount + dim * 3 + j + 1] || G[jCount + dim + i + 3]; //G[j + 1][i + 3] = G[i + 3][j + 1] || G[j + 1][i + 3] G[jCount + dim * 2 + i] = G[iCount + j + 2] || G[jCount + dim * 2 + i]; //G[j + 2][i] = G[i][j + 2] || G[j +2][i] G[jCount + dim * 2 + i + 1] = G[iCount + dim + j + 2] || G[jCount + dim * 2 + i +1]; //G[j + 2][i + 1] = G[i + 1][j + 2] || G[j +2][i + 1] G[jCount + dim * 2 + i + 2] = G[iCount + dim * 2 + j + 2] || G[jCount + dim * 2 + i + 2]; //G[j + 2][i + 2] = G[i + 2][j + 2] || G[j +2][i + 2] G[jCount + dim * 2+ i + 3] = G[iCount + dim * 3 + j + 2] || G[jCount + dim * 2 + i + 3]; //G[j + 2][i + 3] = G[i + 3][j + 2] || G[j + 2][i + 3] G[jCount + dim * 3 + i] = G[iCount + j + 3] || G[jCount + dim * 3 + i]; //G[j + 3][i] = G[i][j + 3] || G[j +3][i] G[jCount + dim * 3 + i + 1] = G[iCount + dim + j + 3] || G[jCount + dim * 3 + i + 1]; //G[j + 3][i + 1] = G[i + 1][j + 3] || G[j +3][i + 1] G[jCount + dim * 3 + i + 2] = G[iCount + dim * 2 + j + 3] || G[jCount + dim * 3 + i + 2]; //G[j + 3][i + 2] = G[i + 2][j + 3] || G[j + 3][i + 2] G[jCount + dim * 3 + i + 3] = G[iCount + dim * 3 + j + 3] || G[jCount + dim * 3 + i + 3]; //G[j + 3][i + 3] = G[i + 3][j + 3] || G[j + 3][i + 3] } } //記錄當前行和列的索引,以便執行完剩餘的項 int curIndex = i; //處理剩餘項,簡單的交換處理 for(i = 0;i < curIndex;i++) for(j = curIndex;j < dim;j++) { G[j * dim + i] = G[i * dim + j] || G[j * dim + i]; } for(i = curIndex;i < dim;i++) for(j = 0;j < dim;j++) { G[j * dim + i] = G[i * dim + j] || G[j * dim + i]; } }
(statistics.sh腳本的運行結果截圖)
- [20155324](博客連接) - 結對照片 - 結對學習內容 - XXXX - XXXX - ...
代碼行數(新增/累積) | 博客量(新增/累積) | 學習時間(新增/累積) | 重要成長 | |
---|---|---|---|---|
目標 | 5000行 | 30篇 | 400小時 | |
第十四周 | 3000/5000 | 1 /26 | 15/320 |
嘗試一下記錄「計劃學習時間」和「實際學習時間」,到期末看看能不能改進本身的計劃能力。這個工做學習中很重要,也頗有用。
耗時估計的公式
:Y=X+X/N ,Y=X-X/N,訓練次數多了,X、Y就接近了。
計劃學習時間:XX小時
實際學習時間:XX小時
改進狀況:
(有空多看看現代軟件工程 課件
軟件工程師能力自我評價表)