Friday, August 21, 2009

Code Inspection 經驗談

軟體測試的方法中,有一種是叫作 Code Inspection,測試的流程就是請工程師根據 Checklist 和人工 Walkthrough 程式邏輯去找出程式碼中的錯誤。按照 Wikipedia 的定義,流程可以分為:

  1. Planning: Moderator 負責計畫 Inspection 的內容和時程。目的是 Initiate 和 Follow 一次完整的 Inspection。
  2. Overview meeting: Author 簡介自己的程式碼。目的是先幫助 Inspector 可以更快進入狀況。
  3. Preparation: 每個 Inspector 在舉行 Inspection Meeting 之前先要閱讀程式碼並且標記所有找到的錯誤。目的是先將所有的錯誤找出來。目的是要 Identify 出所有的 Defect。
  4. Inspection meeting: 舉行 Meeting 時,Reader 負責 Walkthrough 程式碼,Inspector 此時就將找到的錯誤提出來,然後討論是否為 Defect。目的是要 Confirm 和 Prioritize Defect 然後產生 Action Items,並且決定誰來審查 Author 接下來的 Rework,同時也會討論此次 Inspection 的離場標準。
  5. Rework: Author 根據最終的 Action Items 去修訂程式碼。
  6. Follow-up: Reviewer 根據 Action Items 重新審查所有的修訂。

角色可分為:

  1. Author: 撰寫程式碼的作者。
  2. Moderator: 計畫並協調審查流程的主持人。
  3. Reader: 負責在 Inspection Meeting 上帶著大家閱覽程式碼的人。
  4. Recorder: 負責在 Inspection Meeting 上當會議紀錄。
  5. Inspector: 負責在 Preparation 階段詳細審查程式碼,並且在 Inspection Meeting 中指出錯誤的人。

很幸運的,最近有機會親身體驗 Code Inspection,感受比較多的好處大概就是:

  1. 就像是閱讀小說可以增進寫作的能力一樣;閱讀別人的程式碼,也可以幫助提升自己寫程式的能力(或者是作為警惕)。
  2. 平常大家都在自己手上的模組工作,設計藍圖也可能已經過時。經過 Inspection,所有成員對於整體的流程會有更實務的了解。
  3. 可以建立團隊的 Coding Standard。通常 Defect 的發生,很少是獨立的事件,多會有一定的模式。例如說,參數的 Nullity Check,或者是 Buffer Overrun ,然而這些問題都只要遵守簡單的規則就可以避免。若是可以把這些解決方式回饋到團隊的 Coding Standard,在撰寫程式碼都要遵守這些規則,減少愚蠢的錯誤發生。在下次的 Inspection 時,把 Coding Standard 當作 Checklist 就可以更快也更容易認出看起來有問題的程式碼。

當然 Code Inspection 不是軟體測試的萬靈丹,在審查某些程式碼的時候,若是 Inspector 對於程式碼沒有足夠的深入的了解,大概只能做到片面的審查。例如:

  1. 多執行緒的程式碼:用其他的 Modeling Tool (UML?) 來表達多執行緒的運作,會更容易檢驗。如果程式語言本身是 Multi-thread Friendly,也許可以直接讀程式碼。
  2. 用他人不熟析的程式語言或 Domain Knowledge 所撰寫的程式碼:這個可能需要在 Overview Meeting 之前需要另外的 Meeting 先幫大家做教育訓練。絕不可以因此就放棄 Inspection,這是絕佳的提升團隊能力的好時機。
  3. 沒有明確 Testibility 的程式碼:通常發生在設計階段就沒有良好定義的模組,不知道可以丟什麼東西進去,也不知道要輸出什麼樣的東西。這種情況通常需要的是更 High-Level 的 Inspection,Code Inspection 不能解決什麼。

以上就是一些感想,就先分享到這邊啦。

 

參考資料:

Wikipedia: Software Inspection

http://en.wikipedia.org/wiki/Software_inspection

Monday, August 17, 2009

[Windbg] How to Brake at Child Process Creation

有時候,想要從進程(Process)一建立起來就開始除錯,一種方式是直接用 Windbg 直接用 .create 去把進程跑起來。可是在 Google Chrome 這種多進程的程式,想要從某個子進程開始除錯,一定要等主進程把子進程帶起來時才可以除錯。此時,就會需要用一些技巧讓 Windbg 去中斷子進程。
首先,先執行 Google Chrome,它是一個多進程架構的瀏覽器,適合作為這次的範例。
image
然後,在用命令列或GUI的方式 Attach 到主進程 Chrome.exe (1508)。
1) 用 .childdbg 1 命令 Windbg 中斷在子進程的建立。
0:013> .childdbg 1    
Processes created by the current process will be debugged
2) 用 g 命令 Windbg 繼續執行程式,並且去 Chrome 瀏覽個網頁讓它另外建立子進程。
image
3) 接下來會發現 Windbg 已經中斷在子進程當中,可以注意到提示字元已經從 0:013> 切換到 1:016> 。
0:013> g    
Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols;SRV*c:\GoogleSyms*http://build.chromium.org/buildbot/symsrv     
Executable search path is:     
ModLoad: 00400000 004d6000   chrome.exe     
eax=0044092a ebx=7ffde000 ecx=7c9363bb edx=7c99e178 esi=0012dc28 edi=00189318     
eip=7c810705 esp=0012fffc ebp=00000000 iopl=0         nv up ei pl nz na po nc     
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000200     
7c810705 ??              ???     
1:016> |     
   0    id: 5e4    attach    name: C:\Documents and Settings\Administrator\Local Settings\Application Data\Google\Chrome\Application\chrome.exe     
.  1    id: c40    child    name: chrome.exe
4) 此時只需要用 |0s 切換到原本的主進程,然後用 .detach 放掉主進程。
1:016> |0s    
eax=7c930250 ebx=00000000 ecx=000e1714 edx=00000c88 esi=7c99e420 edi=7c99e440     
eip=7c92e514 esp=049eff70 ebp=049effb4 iopl=0         nv up ei ng nz na pe nc     
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000286     
ntdll!KiFastSystemCallRet:     
7c92e514 c3              ret     
0:015> .detach     
eax=0044092a ebx=7ffde000 ecx=7c9363bb edx=7c99e178 esi=0012dc28 edi=00189318     
eip=7c810705 esp=0012fffc ebp=00000000 iopl=0         nv up ei pl nz na po nc     
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000200     
7c810705 ??              ???     
Detached     
1:016> |     
.  1    id: c40    child    name: chrome.exe
5) 此時就大功告成,接下來就可以開始對子進程除錯了。

Saturday, August 15, 2009

免費 Win32 Kernel/User 效能分析工具 - Kernrate

“Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest.” - Rob Pike
在Windows平台上,Microsoft有推出一個可以測量Kernel/User Mode的System Profiler。我們可以用它測量某一段時間的各種Performance Statistics。最棒的是,它可以用取樣(Sampling)的方式來統計出哪些API是屬於HotSpot,可以成為Performance Tuning的根據。
首先,可以在Microsoft Download上面找到它。
http://www.microsoft.com/downloads/details.aspx?familyid=d6e95259-8d9d-4c22-89c4-fad382eddcd1&displaylang=en
把它安裝起來之後,建議先將Symbol Server的環境安裝起來。
  1. 在環境變數中加入”_NT_SYMBOL_PATH=SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols”
  2. 將dbghelp.dll和symsrv.dll複製到kernrate的執行路徑下。
然後就可以開始來試試測量第一支程式-Explorer.exe
  1. 切到kernrate的執行目錄下。
  2. 執行”Kernrate_i386_XP.exe -n explorer -z USER32”
  3. 接下來就可以看到類似”***> Press ctrl-c to finish collecting profile data”的訊息,表示Kernrate已經開始在進行取樣。
  4. 當想要結束取樣的話,就按ctrl-c。最後會有一大串的測量結果跑出來。
Time   20 hits, 19531 events per hit -------- 
Module                                Hits   msec  %Total  Events/Sec 
_FindProp                                 6     110338    23 %        1062 
_MapWindowPoints                          2     110338     7 %         354 
DIBFromBitmap                             1     110338     3 %         177 
CallWindowProcAorW                        1     110338     3 %         177 
GetPropW                                  1     110338     3 %         177 
HMValidateHandleNoRip                     1     110338     3 %         177 
`string'                                  1     110338     3 %         177 
IsWindow                                  1     110338     3 %         177 
ValidateHwndNoRip                         1     110338     3 %         177 
SendMessageWorker                         1     110338     3 %         177 
RealDefWindowProcWorker                   1     110338     3 %         177 
GetWindowLongA                            1     110338     3 %         177 
TranslateAcceleratorW                     1     110338     3 %         177 
_EndUserApiHook                           1     110338     3 %         177 
DispatchMessageWorker                     1     110338     3 %         177 
UserCallWinProcCheckWow                   1     110338     3 %         177 
_SEH_epilog                               1     110338     3 %         177 
_SEH_prolog                               1     110338     3 %         177 
HMValidateHandle                          1     110338     3 %         177 
ValidateHwnd                              1     110338     3 %         177
以上,依照API被取樣的次數由多到少排序。當然,這個結果並不足以下任何定論,至少可以給一個量化的基礎,根據一些推理和調整,就可以找出真正的HotSpot。
參考資料:

Sunday, August 09, 2009

軟體設計備忘錄《Btrfs & B-tree Shadowing》

Valerie Aurora在LWN上面寫了一篇關於Btrfs的短篇專文,簡短的介紹了Btrfs的歷史。Btrfs是由Chris Mason所開發的File System,即將取代Ext4成為Linux上預設的File System。Chris引進Ohad Rodeh在USENIX FAST '07發表的B-tree on Shadowing研究成果,改良Btrfs的設計。簡單整理了Rodeh的成果:

  1. Proactive Split/Merge on B-tree Updating:在Insertion或Deletion,在尋訪的過程中先做Split/Merge的動作。於是乎消除了Backtrace回去修改Parent Node的行為,如此一來就不會有Multi-thread Deadlock的情況發生。
  2. Reference Counting for COW:在做Snapshot的時候,會Shadow每個node都需要維護一個Counter。若是目前的Clone需要寫入任何的Node,那麼就會檢查Counter決定是否要COW;或者是直接覆寫。

 

相較於Reference Counting,WAFL(另一個File System)是用32-bit bitmap來1-to-1對應每一份Clone,所以最多只能有32個Clones,此稱之為Block-map File(謎之聲:怎麼會有這樣的設計呢?…)。關於Block-map的設計,本人猜測是因為原有的Block Entry就已經有Free Flag的設計,若是用Bitmap的設計來對應Clone可能較容易實做。

 

參考資料:

A short history of btrfs

http://lwn.net/Articles/342892/

B-trees, Shadowing, and Clones [PDF]

http://www.cs.tau.ac.il/~ohadrode/papers/btree_TOS.pdf

The Berkeley DB Book: B-tree Deadlock

http://books.google.com.tw/books?id=_WWbpeG9aOIC&pg=PA91&lpg=PA91&dq=Btree+deadlock&source=bl&ots=lKxZJg1G4R&sig=ZSYxO72Gv1EQSzJLbkEh9JVtDsI&hl=zh-TW&ei=EK99StvCEI_-tQP6vLjvCg&sa=X&oi=book_result&ct=result&resnum=1#v=onepage&q=Btree%20deadlock&f=false

Saturday, August 08, 2009

軟體設計備忘錄《IWebBrowser2 Hosting》

在Win32的環境下,要開發Web-UI Application的其中一個選擇就是Web Browser Control。

 

Topic:用程式化去捕捉Script Error:

Script error notification is not sent to Exec method of WebBrowser Host (註:Disable Script Debugging的解法)

http://support.microsoft.com/?scid=kb%3Ben-us%3B317024&x=6&y=8

How to handle script errors as a WebBrowser control host

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q261003

 

Topic:防止Web Browser Control的蹦現視窗:

IWebBrowser2 Stopping and Disabling Popups

http://www.nathanm.com/iwebbrowser2-stopping-and-disabling-popups/

Friday, August 07, 2009

IE AJAX & OnUnload 疑難排除

最近開發Web Application,和IE的整合上遇到了一些問題,這裡整理一些目前找到資料。
  1. 在OnUnload時,若執行了一個AJAX call,非同步的回應將不會觸發原本設定的callback。
    [Solution] 改用Synchronous XHR。
  2. 若離開頁面時,還有任何Pending的XHR物件,將有可能佔用IE的Connection Pool。
    [Solution] Tracking所有的XHR物件,在unload時,Abort所有的XHR Connection。
  3. 若有任何XHR物件的onreadystatechange沒有被重設(reset),會有memory leak。
    [Solution] readyState是DONE的時候就重設onreadystatechange。

參考資料:

Tuesday, August 04, 2009

IE JScript 效能校調原則

IE Blog上列舉了許多針對JScript效能校調的指南。雖然有些看起來似乎沒有順應Modern JavaScript的Programming Model。Anyway, 開發JScript應用程式的人還是可以看看自己的程式碼還可以擠出多少效能。

  1. Symbolic Look-up Recommendations
    • Evaluating Local Variables
    • Cache Variables Whenever Possible
    • Cache Function Pointers at all costs
    • Avoid Using the ‘with’ Keyword
  2. JScript Code Inefficiencies
    • Optimize String Manipulations by Avoiding Intermediate Results
    • Running Code Using the ‘eval’ Statement is Expensive
    • Requirements of Eval for JSON Expressions
    • Switch Blocks are Linear Evaluation Tables
    • Avoid Closures if Possible
    • Don’t use Property Accessor Functions

如果你想要直接Hack JScript Garbage Collection的機制,這邊請吧。

 

Reference:

IE + JavaScript Performance Recommendations - Part 1
http://blogs.msdn.com/ie/archive/2006/08/28/728654.aspx

IE+JavaScript Performance Recommendations Part 2: JavaScript Code Inefficiencies
http://blogs.msdn.com/ie/archive/2006/11/16/ie-javascript-performance-recommendations-part-2-javascript-code-inefficiencies.aspx

IE+JScript Performance Recommendations Part 3: JavaScript Code Inefficiencies
http://blogs.msdn.com/ie/archive/2007/01/04/ie-jscript-performance-recommendations-part-3-javascript-code-inefficiencies.aspx

You may experience slow performance when you view a Web page that uses JScript in Internet Explorer 6
http://support.microsoft.com/?scid=kb%3Ben-us%3B919237&x=9&y=9

Monday, August 03, 2009

軟體設計備忘錄《QueryPerformanceCounter()》

星期天沒出去玩,在家裡寫一個Anonymous Pipe Client & Server小程式來熟析Win32的Pipe IPC機制。寫完之後就想來測測看Pipe和另外某個Design的效能差異,就來評測一下IPC的Round-Trip Time。Win32底下要拿到High Resolution的CPU Tick,大概就屬QueryPerformanceCounter()最方便。不過在Modern Architecture下,有幾件事情要注意:

  1. 現代的CPU都有動態調頻的機制,就算你把Escaped CPU Tick算出來,要還原成Second還是需要功夫。
  2. 在SMP的環境下,CPU Tick不是同步的,要把你計算的目標都綁在同一個CPU上,這樣量出來Tick才會準。
  3. 千萬不能假設QueryPerformanceFrequency()就是CPU Clock Freq. (同樣的也不能假設QPC就是CPU Tick?)

另外,有誰可以和我清楚解釋AMD的TSC-Drift問題嗎? XD

 

延伸閱讀:

http://www.virtualdub.org/blog/pivot/entry.php?id=106

http://forums.indiegamer.com/showthread.php?p=95424

http://lkml.org/lkml/2005/11/4/173

http://blogs.msdn.com/oldnewthing/archive/2008/09/08/8931563.aspx