My friends, my life, my style - James S.F. Hsieh

1/19/2010

ETW Scenario library and Real-time ETW Viewer

微軟在 Windows 2000 之後引入了 Performance Monitoring 機制 - Event Tracing for Windows ETW, 而在 Windows Vista 對於 ETW 有更多的改進, Vista 導入了 Unified event provider model 與新的 APIs 讓我們可以用一致的方式來處理 ETW event. 你不難發現微軟已經大量的整合 ETW event 到 CPU scheduler, File system, GPU Driver, Image Loader, .NET Framework JIT, GC, WPF render engine 等... 重要的模組中, 因為 ETW 是 Kernel build-in 等多種特性所以在使用上有較小的效能影響, 並且可以收集到 System-wide 的資訊. 微軟也為此提供豐富的 Tools 來支援軟體開發與 Performance tuning, 諸如  Microsoft Windows Performance Toolkit, Visual Profile, Logman, Reliability and Performance Monitor (RPM)...

但是, 如果我們要開發自己的 ETW event provider, 並且有圖形化的介面可以幫助我們了解效能上的問題有現成的 tool 嗎? 有的, Microsoft Windows Performance Toolkit 中的 Event Trace 或是 xperfview 都可以幫助我們圖型化我們自製的 ETW event, 但是, 它只能提供一般性的呈現方式, 原因很簡單, 因為這些 tool 並沒有足夠的 domain knowledge 來解釋這些 event, 所以他只能以 Generic event 的方式呈現, 如此我們只能以時間分佈的單一維度來觀察我們的 event, 其實這並不方便


xperfview - Generic event 只能看到事件發生的時間點

之前曾在微軟的 Blog 看到人家發問 "xperfview  是否能夠支援擴充" 不過到目前為止的答案是否定的, 其次 xperf 因為效率的考量所以只有提供 offline 的方式來分析 ETW event, 但對於有些特定的 use case 下將會非常麻煩, 我們總想知道使用者互動下效能與操作行為的相關性, real-time 的方式分析有時候比較快速與直覺, 有鑑於此我們就自己開發了簡單的 ETW Viewer 來幫助我們做到這些事情.

首先, 我們要定義比 Generic event 在豐富那麼一點點的語意來表達更多的資訊, 並且在 Client 的整合上可以更方便快速, 所以我們選擇一個 MSDN Code Gallery 上 ETW 相關的 Project - Scenario 來做為整合的目標, Scenario 是個 ETW event provider 的實做體, 它提供了 Native 與 Managed code 的兩種實做版本, 在 event 的格式部分, 因為 Scenario ETW Format 有定義了兩個值 Category (Unicode string) 與 Size (int64) 來讓我們描述 Client 想要描述的 "量" (你可以用來描述 FPS, cache miss rate 等等自訂的語意), 使用 Scenario 可以說非常的簡單, 我們只要埋入幾個特定的 check points: Begin, Step, End 在我們想觀察的 case 中, 並且將我們自訂的數值傳遞給 Scenario 就夠了. 就像:

// C#: Generate an ETW event (when enabled by an ETW controller)
using Scenario;
...
Scenario timer = new Scenario();
timer.Begin(); // checkpoint 1
// ...
// Code that you want to time
// ..
timer.Step(size// checkpoint 2
// ...
// Code that you want to time
// ..
timer.End(); // checkpoint 3

以上的程式為例, Scenario 就會幫我們把 3 個 checkpoint 的時間間隔量出來, 並且把我們自訂的 Size 值也跟著傳給 ETW consumer.

接下來我們的問題就是如何顯示這個收集到的 event , 我們使用了 C# 開發了一個簡單的 WinForm 程式, 這個程式包含了一個 ETW controller 跟 ETW consumer, ETW controller 有能力動態的 Enable 或 Disable 指定的 ETW event, 在配合 Scenario 的設計下當一個 ETW event 被 Disable 時我們所 monitor 的程式除了一些簡單的判斷式, 它將不會執行 ETW provider 相關的程式碼, 這樣能確保在 Disable 的狀況下只有很少的效能損失. 利用 ETW consumer 我們能即時且非同步的方式處理收到的 event, 並將其 Size 與 checkpoint 的時間顯示在 UI 的笛卡兒座標上, 這就是我們希望視覺化的部分. 此外, 這個程式也有能力將這些資訊寫進 SQLite 的 database 中, 這樣的好處是, 我們可以在將來更輕易的整合到 Auto testing 與 Build process 中. 以下就是  Real-time ETW Viewer 的 Snapshot!


ETW Realtime Scenario Viewer - timeline view


ETW Realtime Scenario Viewer - list view


Improve Debugging And Performance Tuning With ETW 是篇還蠻具體而微的文章, 對於這方面有興趣的人可以參考.

1/17/2010

2010 01 17 陽明山七星池

1/13/2010

什麼是好的軟體?



實務派的人說:
軟體是種高度特化的藝術品, 所以裡面怎麼做不重要, 只要整體的功能與效率符合需求並且執行的很好, 最好能夠用最低的成本來達到目標就是王道.
架構派的人說:
軟體是種有系統性的積木, 為了增加複用性與生產力, 降低擴充與維護的成本, 架構是軟體的靈魂.
產品派的人說:
軟體只要功能多成本低, 能快速生產能夠高度客製化, 在效能上有好的表現, 很少 BUG 就是好軟體.
使用者說:
軟體只要便宜 (最好不用錢), 好用, 快速就是好軟體.

軟體的特性還蠻複雜的, 它有著生產, 運作, 維護 時間長, 複製成本極低, 規格變動, 汰換率與人事變動成本高, 不易維護, 除錯與驗證等多種複雜特性. 要減少這些特性的缺點增加其優點是很明確的目標, 所以上面沒有一種人說錯, 軟體是在上述的多種衝突需求中找到一個最佳的平衡點就是好軟體. 但怎樣的平衡是正確的選擇就有很大的學問,

舉個例子: timing 就是市場的一切, 快速的做出產品可以爭取更多的機會來把握 timing, 然而好的架構會因為降低耦合增加彈性等多種考量而延長產品的開發時間, 有時候這些設計可能在當下會被視為 over design 而被捨棄或忽略, 某個層面這是對的. 如果這個產品賣得好而延長了程式與架構的生命週期, 接下來要面對的就是該產品的架構會因為未來的需求而受到考驗, 好的架構也可以降低維護的成本. 所以這個平衡的因子似乎因為生命週期而有不同的選擇, 儘管軟體的生命週期會因為市場的反應而難以評估, 有些軟體可能會沿用個 10 年, 有些則只會出一個版本.

再舉個例子: 架構的取捨有時候還得考量 programmer 的技術能力, 也許你會遇到一個窘境是你使用了一堆很棒的 design pattern 但你的同事卻一個也看不懂還是能存活下來. 你該用易懂直觀的架構還是稍微難懂但頗富彈性的架構呢?

再再舉個例子: 如果有個公司就是做 OEM 或是硬體驅動程式 BIOS 這類強烈需求導向的工作, 也許這個軟體一但 GM 就等於進了墳墓, reuse 對這類型的工作也許毫不重要, 也可能這些具有 reuse 特性的部分人家都已經做好了等著你用, 這樣的公司文化與工作特質下, 怎樣的選擇好呢?

什麼是好的軟體? 因為人, 因為時間, 因為佈署的方式, 因為舊有的包袱, 因為公司的文化與營運方式有著截然不同的答案. 連怎樣評估軟體是好是壞都是如此的複雜...

1/09/2010

幾個關於 .NET Framework 4 的幾個疑惑與希望...

.NET Framework 3.5 以來, 普及率一直不是很理想, 微軟也針對關鍵性的幾個因素做改善, 一下的幾點筆記是該去研究一下 :P
  1. 大家都知道 .NET 的 Application 的啟動時間可能會很慢, JIT 是個原因之一, 利用 NGEN 來改善 Startup Performance 是微軟提供的一種解決方法, 我們是該驗證一下這個方式, 有幾篇文章可以追一下: The Performance Benefits of NGenCLR Optimizations In .NET Framework 3.5 SP1Improvements to NGen in .NET Framework 4To NGen or Not to NGen?Improving WPF applications startup timeSplash Screen To Improve WPF Application Perceived Cold Startup Performance

    我驗證的結果, WPF 的 Cold/Cool Startup time 還是很久, 即使用了 NGen 速度還是沒辦法像 native code 一樣.

  2. WPF 與 Direct3D  的 footprint 差異有多大, WPF 的記憶體使用量一直為人所詬病 (相較於MFC), 不知道 4.0 是否有改善

  3. .NET Framework 的 installer size 一向不小, 所以微軟設計了.NET Framework 4 Client Profile 還有Web Bootstrapper, 文章上描述 .NET Framework 4 Client Profile 的安裝不一定需要 Reboot 並且可以 Parallel Download and Install, 這個也是需要追一下: What's up with the "Reboot" step? , The .NET Framework 4.0 Beta 2 Installer ImprovementsWhat’s new in .NET Framework 4 Client Profile Beta 2, .NET Framework Client Profile Deployment Guide

    Installer size 已經比以前小很多了, 但是 install size 還是一樣肥的嚇人, 以 x86 為例, installer 的大小大約是 30.9 MB, 但是解壓縮加上 JIT 之後的大小需要 850 MB 左右, 這真的讓人卻步, 不過我承認 installer 縮小有助於程式在網路上散佈. 不過如果我想寫個 WPF 小軟體卻要求使用者要有 850 MB 的空間來安裝我的軟體, 應該沒有幾個使用者能夠接受.

    今天在別人的電腦嘗試安裝 Client profile 結果 installer 還是要求重新開機, 仔細觀察 MsiInstaller 的 log 發現這台電腦必須重新開機有幾個原因:
    C:\WINDOWS\system32\dfshim.dll 正在被下列處理名稱所使用中: explorer 識別碼 1920
    C:\WINDOWS\system32\mscoree.dll 正在被下列處理名稱所使用中: explorer 識別碼 1920
    C:\WINDOWS\system32\mscoree.dll 正在被下列處理名稱所使用中: iexplore 識別碼 220
    C:\WINDOWS\system32\mscoree.dll 正在被下列處理名稱所使用中: iexplore
    識別碼 1764

    這台電腦的使用者算是個很基本的 End user 所以電腦安裝的軟體並沒有什麼特別之處但是還是被要求重新開機, 原因是 IE 跟 Shell 都佔住了 .NET Framework 的 runtime, 看來狀況並不明朗啊.. 然後查了一下 MSDN 發現, Client profile 的 installer 提供 command parameter




    /norestart: Setup doesn’t reboot automatically. The chaining application needs to capture the return code and process and handle reboot if this switch is used.
    但也只是暫時讓他不需要 reboot 罷了.

    根據 张羿的文章 ".NET中的幕后英雄MSCOREE.dll " 所描述, mscoree.dll 提供了 _CorExeMain 這個進入點做為 CLR 程式啟動之用, 重點是不管哪個版本的 .NET Framework 都是用這支 DLL 來啟動, 所以 mscoree.dll 在系統中只會有兩支 (32/64bit), 而 .NET Framework 4.0 似乎需要置換掉這個檔案, 所以重新開機也許在所難免. 除非類似 SxS 的方式使用私有的 mscoree.dll, 而 张羿 似乎有找到解決的方法不過還沒分享出來, 詳細可以參考 ".NET 4.0新功能:Mscoree.dll + Mscoreei.dll=更少的Reboot" 




1/08/2010

免費的 "IStream, IPropertyStorage" system-provided, stand-alone implementation COM



相信寫過 .NET C# 的人對於 System.IO.MemoryStream 這樣的物件都感到十分方便, 因為MemoryStream 會在需要的時候自己 ReAlloc 來改變大小, 並且由於 MemoryStream 繼承自 Stream 這個 class 所以用途十分廣泛. 其實 COM 也有相似的設計 (不如說 .NET Framework 學 COM 的) COM 有定義一個基本的 interface IStream, 概念上 IStream 就如同 .NET 中的 Stream 一樣, 不過它是 interface 而不是 abstract class, 在 COM 的世界裡 interface 是種 protocol, 所以任何人都可以實做 IStream 的 COM, 並且跟認得 IStream 的其它 COM 合作. 我之前就有寫過一個實做 IStream 的 COM, 它支援 non-buffering 的方式來 OpenFile. MSDN 就有一篇文章來教大家怎麼時做一個 FileStream - Default IStream Implementation.


COM 的定位並不是個 Framework 所以沒有那麼多現成的 class 可以使用, 而且系統提供的 COM implement 也少的可憐. 但是 OLE32.DLL 還是提供了類似 MemoryStream 這類好用的東西, 我們可以使用 CreateStreamOnHGlobal 來建立一個實做 IStream 的 COM instance, 而這個 instance 的功能就如同 MemoryStream 一樣會自動 ReAlloc.  當然 OLE32 也允許你從 IStream 拿到 HGlobal 的 HANDLE, 我們只要呼叫 GetHGlobalFromStream

HGLOBAL handle = NULL;
CComPtr spStream;
HRESULT hr = ::CreateStreamOnHGlobal(handle , FALSE, &spStream);
hr = ::GetHGlobalFromStream(spStream, handle);


一但有了這個類似 MemoryStream 的 IStream 實做體, 我們還可以利用更多 OLE32 提供的功能, 例如 IPropertyStorage, IPropertyStorage 這個 interface 的功能是個用來存放 property 的 container, property 可以是 PROPVARIANT 所支援的任何 type, WIC 就是用 PROPVARIANT 來記錄存放在 JPEG EXIF 中的 metadata 詳細可以參考 IWICEnumMetadataItem (說遠了), 為什麼要介紹 IPropertyStorage 呢, 因為 OLE32 又提供了一個 system-provided, stand-alone implementation 的實做體, 我們只要提供 IStream 或是 IStorage 給傳給 StgCreatePropStg 這個 API, 它就會送一個 IPropertyStorage 的 instance 給我們, 我想 property bag 這種東西的方變程度就不用說了. 有注意到嗎? 我們只要結合 CreateStreamOnHGlobal 和 StgCreatePropStg, 它就可以幫我們建立一個在記憶體中的 property bag, 這是何等的方便與容易呢?


延伸思考一下 IStream 能不能在 .NET 中使用呢? 當然可以啊因為 IStream 是 COM 呢, 連 .NET Framework 都有對應的 Interop interface System.Runtime.InteropServices.ComTypes.IStream 而 IPropertyStorage 則對應於 MS.Internal.IO.Packaging.CompoundFile.UnsafeNativeIPropertyStorage, 不過似乎沒有公開 ...
(後來查了一下 MSDN 發現 Microsoft.VisualStudio.OLE.Interop 有公開對應大部分 OLE32 的介面, 不過放在一個很怪的 DLL 中 microsoft.visualstudio.ole.interop.dll 而 IStream 與 Stream 的轉換則有 DataStreamFromComStream 與 ComStreamFromDataStream 兩個 wrapper class 可以使用, 不過都包在 System.Windows.Forms.UnsafeNativeMethods 這個 internal class 中, 微軟真的很小氣 = =. 不過 UnsafeNativeMethods 真的是大個誇張啊, 大家可以用 .NET Reflector 看一下就可以知道了. 


順帶一提 System.IO.UnmanagedMemoryStream 似乎是個不錯用的 class, 它可以 wrapper 一個 unmanaged 的 pointer 程為一個 Stream class, 雖然它是 unsafe 的 class 但是對於 performance 也許有不少幫助呢.

1/03/2010

2010 01 02-03 北插天山露營



這太白癡了 不得不貼出來 .....









1/01/2010

2010 01 01 跨年