2010-11-18 96 views
2

我仍然相當新的C++/CLI,當我寫的東西我是否做的事情,創造託管和非託管運行時間之間的過渡是常常難以確定認識的轉變。例如我不能添加LARGE_INTEGER或std :: vector作爲託管類的成員,但我可以在託管方法中使用,但我不知道這是否會在託管方法和非託管方法之間創建轉換運行時間。我怎樣才能看到我強迫過渡的每一點,以及如何衡量這些過渡的成本?這發生在我C++/CLI之間的託管/非託管並衡量其成本

一種可能性是,我希望有一個「過渡到非託管」,並在Windows中「過渡管理」的代碼塊。是否有可以放置斷點的符號,例如用windbg,所以我可以看到每個轉換?有沒有辦法讓Visual Studio在運行時向你展示每個轉換?

要測量的時候有很多的轉變,是否有相應的Windows事件跟蹤事件,我可以看到xperf對他們來說,還是性能計數器,我可以與性能監視器看到inpact?

回答

6

「非託管運行時」有點矛盾。非託管代碼不會在虛擬機中運行。另外,託管運行時本身也是非託管代碼。我認爲你一般對代碼感興趣,不僅僅是CLR和標準庫,但最終一切都是本地代碼,其中一些是由CLR JIT創建的,其中一些是由本地編譯器創建的,但它都是本機代碼到底。甚至有一個針對.NET和本機異常(或更確切地說,.NET使用操作系統提供的異常模型)的通用異常處理模型(SEH)。

JIT運行後,沒有太多的託管 - >非託管轉換的跡象,因爲它們只是一個簡單的函數調用(調試器可以區分不同的代碼,因爲非託管代碼位於本地庫的地址空間中,並且JIT編譯的託管代碼位於JIT擁有的動態地址空間中)。由於調用指令是在它調用的代碼之前創建的,它必須是一個間接調用(通過函數指針),所以涉及的方向相反。但它仍然是一個指向JIT編譯代碼的指針,而不是一個單獨的非託管的>管理的thunk,您可以在其中放置一個斷點。實際上,函數指針可能開始指向JIT本身,該指針指出正在調用的方法,編譯它,更新函數指針,並最終對目標進行尾部調用,就像它首先被調用一樣。

這是C++ interop的神奇之處。這也意味着託管式和非託管式轉換實在不值得擔憂。配置文件並找出哪些代碼路徑非常昂貴,如果事實證明是託管代碼與非託管代碼之間的調用,則優化它。但不要隨意尋找託管/非託管轉換。

現在,有一個你可能想看看所有的託管/非託管過渡之外的原因。例如,垃圾收集器可以中斷運行託管代碼的任何線程(同樣,實際運行的代碼是本地代碼,但GC可以識別它,因爲它位於JIT使用的內存空間內部,JIT生成的對象使用表詳細說明了什麼堆棧變量在任何給定的指令指針處都是可達的對象)。所以如果你想保證某個線程永遠不會被垃圾回收所阻擋,你需要搜索並消除在該線程中運行的函數中的所有非託管 - >受管理的轉換。即使有地方放置斷點,斷點注入仍然不是正確的方法,因爲它只捕獲實際進行的轉換,而不是那些有條件的轉換。

+0

非常有趣。從JITed託管代碼調用本地代碼在運行時是不可見的(儘管可能有一些必須包含的堆棧fanangling?)。 – 2010-11-18 19:21:50

0

分析器是可以給你答案的。您可以使用VS2010 Profiler來測量轉換。

你也可以使用ETW跟蹤,但它是更難分析它們。 PerfMonitor可以幫助您進行ETW跟蹤。

FYI甚至VS2010探查只使用ETW跟蹤,但它有更好的方式呈現它。