# 2017q1 Homework1 (phonebook) contributed by <`Weinux`> ###### tags: `sysprog2017` `w1` `phonebook` `Weinux` ## Review by `Sean1127` 1. 實驗的結果在用 gnuplot 的時候,除了`append()`, `findName()`之外還可以增加`total`(也就是前面兩者相加)這一欄,實驗結果會更清楚 2. `$ sudo dmidecode -t cache | more`跟`$ lscpu`有什麼不同,結果有出入要如何解釋? ``` $ lscpu | grep cache L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 3072K ``` ``` $ sudo dmidecode -t cache # dmidecode 3.0 Getting SMBIOS data from sysfs. SMBIOS 2.7 present. Handle 0x000A, DMI type 7, 19 bytes Cache Information Socket Designation: CPU Internal L1 Configuration: Enabled, Not Socketed, Level 1 Operational Mode: Write Back Location: Internal Installed Size: 128 kB Maximum Size: 128 kB Supported SRAM Types: Unknown Installed SRAM Type: Unknown Speed: Unknown Error Correction Type: Single-bit ECC System Type: Other Associativity: 8-way Set-associative ``` 這是在我的電腦上跑的結果,這邊寫我的`L1 cache`有 128 kB,但上面寫我只有 64 kB 另外`cache block`大小這個指令並沒有顯示,那要如何知道? 3. cache miss 的計算需要再確認 4. 需要 >回答以下問題:本例選用的 dataset (也就是輸入電話簿的姓名) 是否存在問題? >* 有代表性嗎?跟真實英文姓氏差異大嗎? >* 資料難道「數大就是美」嗎? >* 如果我們要建立符合真實電話簿情境的輸入,該怎麼作? 5. git commit message 寫的不錯! ## 目標 * 作業要求 [B01: phonebook](https://hackmd.io/MwJgHAplBsELQGMAMwCGcAsHjDgIwgBMBOOAdmlSULADMRiBWYiIA===?both) * 準備 GNU/Linux 開發工具 * 學習使用 Git 與 GitHub * 學習效能分析工具 * 研究軟體最佳化 * 技術報告寫作練習 > 不是第一次接觸這個作業, 所以這次主要目標 > 1. 思考並實驗不同資料結構對於效能的影響(cache miss, append() & findName()時間比較). > 2. 以及思考電話簿字典檔的結構與可能問題 > 3. 嘗試實作挑戰題 > 4. 針對之前不熟悉的開發工具再學習與練習 > > [name=Weinux] ## 開發環境 * OS:Lubuntu 16.04 LTS * Linux 系統版本: 4.4.0-63-generic * Architecture: x86_64 * CPU 作業模式: 32-bit, 64-bit * Byte Order: Little Endian * CPU: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz * Model name: Intel(R) Core(TM) i5-2410M CPU @ 2.30GHz * Memory: 6GB (5870MB) * Cache: * L1d cache: 32K * L1i cache: 32K * L2 cache: 256K * L3 cache: 3072K 也可以使用指令得到電腦的系統架構圖 ``` $ sudo apt-get install hwloc $ lstopo ``` ![](https://i.imgur.com/75JUBWk.png) ## 作業分析: phonebook ### 更改 struct size ```clike=7 typedef struct __PHONE_BOOK_ENTRY { char lastName[MAX_LAST_NAME_SIZE]; char firstName[16]; char email[16]; char phone[10]; char cell[10]; char addr1[16]; char addr2[16]; char city[16]; char state[2]; char zip[5]; struct __PHONE_BOOK_ENTRY *pNext; } entry; ``` ``` size of entry : 136 bytes execution time of append() : 0.047197 sec execution time of findName() : 0.005958 sec Performance counter stats for './phonebook_orig' (100 runs): 1,955,691 cache-misses # 92.003% of all cache refs 2,125,670 cache-references 261,892,576 instructions # 1.38 insns per cycle 189,481,205 cycles 0.084996230 seconds time elapsed ``` ``` size of entry : 32 bytes execution time of append() : 0.042181 sec execution time of findName() : 0.003178 sec Performance counter stats for './phonebook_opt' (100 runs): 327,951 cache-misses # 59.565% of all cache refs 550,578 cache-references 250,927,988 instructions # 1.78 insns per cycle 141,234,044 cycles 0.070440497 seconds time elapse ``` ![](https://i.imgur.com/ML5arxM.png) ### 使用 Hash Function ``` Performance counter stats for './phonebook_hash' (100 runs): 885,265 cache-misses # 79.024 % of all cache refs ( +- 0.03% ) 1,120,246 cache-references ( +- 0.13% ) 350,152,192 instructions # 1.46 insns per cycle ( +- 0.21% ) 239,262,574 cycles ( +- 0.34% ) 0.107383867 seconds time elapsed ``` ![](https://i.imgur.com/gcIpMfq.jpg) * 回答以下問題:本例選用的 dataset (也就是輸入電話簿的姓名) 是否存在問題? * 有代表性嗎?跟真實英文姓氏差異大嗎? * 資料難道「數大就是美」嗎? * 如果我們要建立符合真實電話簿情境的輸入,該怎麼作? ## cache 相關知識 從 1980 年代開始,main memory 和 CPU 的速度差距急速拉大,主記憶體存取速度雖然時有提升,卻仍不及 CPU 的進展,因此需要一個中間層 cache 來彌補因為兩者間速度落差帶來的效能衝擊。 ![image alt](https://www.extremetech.com/wp-content/uploads/2014/08/CPU-DRAM.png) * 原理:cache 利用記憶體架構的兩大原則來設計 **1. Temporal Locality:** 剛剛用過的記憶體很容易再被使用(例如,for迴圈) **2. Spatial Locality:** 如果一個記憶體剛剛使用過,他附近的記憶體位址也很可能被使用到(例如,陣列存取) * "cache" 是為了讓資料存取的速度適應 CPU 的處理速度允許 CPU 直接到 cache memory 查看所需資料是否存在。若是,則直接存取不必再到 main memory —— 減少到 main memory 存取的次數,解決 main memory 存取不夠快的問題。 * 延伸閱讀: [Optimizing the data cache performance ](https://www.cs.umd.edu/class/fall2001/cmsc411/proj01/cache/matrix.html) * set associative:set associative 的方式,也就是把 cache 分成多個 set,CPU必須檢查指定set內的每個block是否有可用的cache。最極端的情況下就是Fully Associative,也就是CPU要檢查cache內所有的block。 ![](https://hackpad-attachments.s3.amazonaws.com/embedded2016.hackpad.com_kpfgwU6YgOF_p.566431_1457425384421_I8iy3IXoR5SV8QS8LOMU_set_associative.png) * 實作多個four-way set的方式 ![](https://hackpad-attachments.s3.amazonaws.com/embedded2016.hackpad.com_kpfgwU6YgOF_p.566431_1457425646712_CVd77vhsShmdZrefsYxZ_four_way_set.png) 更多內容如下: * 資料來源:[](http://enginechang.logdown.com/tags/cache)[http://enginechang.logdown.com/tags/cache](http://enginechang.logdown.com/tags/cache) * [](http://www.cs.iit.edu/~virgil/cs470/Book/chapter9.pdf)[http://www.cs.iit.edu/~virgil/cs470/Book/chapter9.pdf](http://www.cs.iit.edu/~virgil/cs470/Book/chapter9.pdf) * [](http://www.mouseos.com/arch/cache.html)[http://www.mouseos.com/arch/cache.html](http://www.mouseos.com/arch/cache.html) **Cache Miss的計算:以 phonebook 為例** 先透過指令查詢硬體規格如下: `$ sudo dmidecode -t cache | more` * cache 總大小是 32K Byte * 一個 cache 的 block 為 64 Byte * 一個 entry 的大小為( 136 byte) + memory control block ( 8 byte) = 144 byte * 8-way set associative 需要有多少block? (考慮main.c  findName() & append 這2個function 因為 linked-list 跟搜尋存取花最多時間) - 350000 筆資料 * 每筆 144 byte = 50400000 byte - 50400000 byte / 64byte ( block size ) * 2次 function = 1575000 block - 讀一個block是一次 reference 執行 phonebook 程式確認 perf 中 cache 相關訊息 `$ make cache-test ` size of entry : 136 bytes execution time of append() : 0.047197 sec execution time of findName() : 0.005958 sec Performance counter stats for './phonebook_orig' (100 runs): 1,955,691 cache-misses # 92.003% of all cache refs 2,125,670 cache-references 261,892,576 instructions # 1.38 insns per cycle 189,481,205 cycles - 可以看到計算出來的 cache-reference 1,575,000 與實際 2,125,679 量級相同 cache 有幾個 set? - cache 32K Byte / block 64 Byte = 512 block - 512 / 8-way set = 64 個 一個 cache line 可以存多少筆 entry - 144 byte / 64 byte = 2.25 所以需要 3 個 block 已知是系統為 8-way set 所以可以存 2 個 cache miss - 1,575,000 ( 總 block ) / 3(一個 entry 需要3 block) = 525,000 組 entry  - 525,000 / 64( index 數) = 8,203 ( tag 數,填到相同 index 的個數 ) - 由上知一個 cache line 最多可以放 2 組 entry,所以有兩次機會 - 8,203 / 2 = 4,101 ( 可能被對到次數 ) - 4,101 * 64 ( index 數) * 3 ( entry 佔的 block 數) = 787392 ( cache hit 次數 ) - 1,575,000 - 787,392 = 787,608 ( cache-miss) - 787,608 / 1,575,000 = 50%(miss rate) ?????? > >驗證助教的共筆,發現根據同樣方式計算. cache-miss rate 結果也是50%左右, 而非程式中的 92%, 需要再確認 cache 計算方式 * [cache 原理和實驗](https://hackmd.io/MwMwRgHGDsIIYFoAm04DYEBZMEYcIhwCYBTBNABgFYlgSRYBOUoA) * [关于CPU Cache -- 程序猿需要知道的那些事](http://cenalulu.github.io/linux/all-about-cpu-cache/) * [Programming Small](https://hackmd.io/KYYwzAjAHATAJgVgLQEMQDMxICwIcJATgHZhikowE4YA2AI2xnqgSA==?view) ## 工具學習 ### Perf ``` $ ./ "執行檔案名稱" & sudo perf top -p $! ``` ### Makefile * [Makefile 語法和示範](https://hackmd.io/s/SySTMXPvl#) ### gunplot * [gnuplot 語法解說和示範](https://hackmd.io/s/Skwp-alOg#) ### Github * [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) ## 參考資料