C++/CLI之间的托管/非托管并衡量其成本

问题描述:

我仍然相当新的C++/CLI,当我写的东西我是否做的事情,创造托管和非托管运行时间之间的过渡是常常难以确定认识的转变。例如我不能添加LARGE_INTEGER或std :: vector作为托管类的成员,但我可以在托管方法中使用,但我不知道这是否会在托管方法和非托管方法之间创建转换运行时间。我怎样才能看到我强迫过渡的每一点,以及如何衡量这些过渡的成本?这发生在我C++/CLI之间的托管/非托管并衡量其成本

一种可能性是,我希望有一个“过渡到非托管”,并在Windows中“过渡管理”的代码块。是否有可以放置断点的符号,例如用windbg,所以我可以看到每个转换?有没有办法让Visual Studio在运行时向你展示每个转换?

要测量的时候有很多的转变,是否有相应的Windows事件跟踪事件,我可以看到xperf对他们来说,还是性能计数器,我可以与性能监视器看到inpact?

“非托管运行时”有点矛盾。非托管代码不会在虚拟机中运行。另外,托管运行时本身也是非托管代码。我认为你一般对代码感兴趣,不仅仅是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

分析器是可以给你答案的。您可以使用VS2010 Profiler来测量转换。

你也可以使用ETW跟踪,但它是更难分析它们。 PerfMonitor可以帮助您进行ETW跟踪。

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