2011-04-02 37 views
8

我正在尝试剖析我的应用程序,以便在重构之前和之后监视函数的影响。我已经对我的应用程序进行了分析,并查看了摘要我注意到Hot Path列表没有提及我使用的任何函数,它只提到了Application.Run()的函数。()函数剖析的困境 - Visual Studio 2010 Ultimate

我很公平新分析,并希望知道如何通过MSDN documentation得到关于热路径的更多信息;

MSDN例子:

MSDN Example

我的结果:

Hot Path Summary

我注意到在输出窗口中有很多关于失败的消息当加载符号时,其中一些在下面;

Failed to load symbols for C:\Windows\system32\USP10.dll. 
Failed to load symbols for C:\Windows\system32\CRYPTSP.dll. 
Failed to load symbols for (Omitted)\WindowsFormsApplication1\bin\Debug\System.Data.SQLite.dll. 
Failed to load symbols for C:\Windows\system32\GDI32.dll. 
Failed to load symbols for C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\comctl32.dll. 
Failed to load symbols for C:\Windows\system32\msvcrt.dll. 
Failed to load symbols for C:\Windows\Microsoft.NET\Framework\v4.0.30319\nlssorting.dll. 
Failed to load symbols for C:\Windows\Microsoft.Net\assembly\GAC_32\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll. Failed to load symbols for 
C:\Windows\Microsoft.Net\assembly\GAC_32\System.Transactions\v4.0_4.0.0.0__b77a5c561934e089\System.Transactions.dll. 
Unable to open file to serialize symbols: Error VSP1737: File could not be opened due to sharing violation: - D:\(Omitted)\WindowsFormsApplication1110402.vsp 

感谢任何指针(使用代码工具,所以它是可读格式化)。

回答

13

摘要视图中显示的“热路径”是基于包含样本的数量(来自函数的样本以及函数调用的函数的样本)和独占样本(仅来自功能)。一个“样本”就是事实上,当探查器的驱动程序捕获堆栈时(这种情况发生在非常短的时间间隔内),该函数位于堆栈的顶部。因此,函数的样本越多,执行的越多。

默认情况下,抽样分析,所谓的“仅我的代码”功能被启用,堆栈是从非用户模块来对隐藏功能(它会显示1非用户功能的深度,如果叫一个用户功能;在你的情况下Application.Run)。来自未加载符号的模块或已知来自Microsoft的模块的功能将被排除。摘要视图中的“热门路径”表明,最昂贵的堆栈没有任何东西,从探查器认为是您的代码(Main除外)。来自MSDN的示例显示更多功能,因为PeopleTrax.*PeopleNS.*函数来自“用户代码”。点击摘要视图中的“显示所有代码”链接即可关闭“我的代码”,但我不建议在此处这样做。

查看摘要视图中的“最独立工作的功能”。这将显示具有最高独占样本计数的函数,因此根据分析方案调用最昂贵的函数。你应该在这里看到更多你的函数(或函数调用的函数)。此外,“视图”屏幕可能会显示更多详细信息(报表顶部有一个用于选择当前视图的下拉菜单)。

至于你的符号警告,其中大部分是预期的,因为它们是Microsoft模块(不包括System.Data.SQLite.dll)。虽然您不需要这些模块的符号来正确分析报告,但如果您在“工具 - >选项 - >调试 - >符号”中选中了“Microsoft Symbol Servers”并重新打开报告,则应加载这些模块的符号。请注意,第一次打开报告需要更长的时间,因为需要下载和缓存符号。

另一个关于无法将符号序列化到报告文件中的警告是文件无法写入的结果,因为它是由阻止写入的其他内容打开的。符号序列化是一种优化,允许分析器直接从下一次分析的报告文件中加载符号信息。如果没有符号序列化,分析只需要执行与第一次打开报告时相同的工作量。

最后,您可能还想尝试仪器,而不是在您的分析会话设置中进行采样。 Instrumentation会修改您指定的模块以捕获每个函数调用的数据(请注意,这可能导致更大,更大的.vsp文件)。仪器非常适合专注于特定代码段的时间,而采样对于一般的低开销分析数据采集来说非常理想。

+0

仪表似乎更多地转向我需要什么,我可以清楚地看到每个功能花了多长时间。再次感谢! – 2011-04-14 13:02:49

+0

@Peter Huene:有点偏离主题,但我很好奇,是否可以在单次运行中获取native代码和.net代码的源代码覆盖率信息。我的主要exe文件是一个native .exe,它使用.net dll – Chubsdad 2013-09-24 06:47:36

+0

@Chubsdad:是的。如果您使用的是VS 2010或之前的版本,则需要使用VSInstr对每个可执行文件进行本地和受管理操作,并使用VSPerfMon进行收集。在2012年,代码覆盖工具(CodeCoverage.exe)将即时处理本机和托管可执行文件(在内存中),前提是它们的.pdbs在收集时存在。 – 2013-09-24 16:55:09

6

如果我谈论一下关于性能分析,什么可行,哪些不可行,你是否介意太多?

让我们编写一个人工程序,其中一些语句正在做一些可以优化的工作 - 即它们并非真正必要。 他们是“瓶颈”。

子程序foo运行CPU约束循环,需要一秒钟。 同时假设子程序CALL和RETURN指令与其他所有操作相比,占用微不足道或零时间。

子程序bar拨打电话foo拨打电话foo拨打10次,但其中9次是不必要的,您事先不知道,直到您的注意力集中在那里才能知道。

子程序ABC,... J是10子程序,他们每次通话bar一次。

顶级例程main每次调用AJ一次。

所以总通话树是这个样子:

main 
    A 
    bar 
     foo 
     foo 
     ... total 10 times for 10 seconds 
    B 
    bar 
     foo 
     foo 
     ... 
    ... 
    J 
    ... 
(finished) 

多久都需要? 100秒,显然。

现在让我们看看分析策略。 堆栈样本(比如说1000个样本)以统一的时间间隔进行。

  1. 有没有自我时间?是。 foo需要100%的自我时间。 这是一个真正的“热点”。 这能帮助你找到瓶颈吗?没有,因为它不在foo

  2. 什么是热路?那么堆栈样本如下所示:

    main - > A - > bar - > foo(100个样本或10%)
    main - > B - > bar - > foo(100个样本或10% )
    ...
    主 - >的J - >酒吧 - > FOO(100个样本,或10%)

有10条热门路径,它们不会显得足够大,以多获得你加速。

如果您发现了GUESS,并且如果配置文件允许,您可以使bar成为呼叫树的“根”。然后你会看到这一点:

bar -> foo (1000 samples, or 100%) 

那么你会知道每个foobar是对时间的100%,独立负责,因此是地方寻找优化。 你看看foo,但当然你知道问题不在那里。 然后你看看bar,你看到10个电话foo,你看到其中9个是不必要的。问题解决了。

,如果你没有碰巧猜了,而不是简单地探查表明您包含每个常规样品的百分比,你会看到:

main 100% 
bar 100% 
foo 100% 
A 10% 
B 10% 
... 
J 10% 

,告诉你看看mainbar,和foo。你看到mainfoo是无辜的。你看看bar在哪里调用foo,你看到了问题,所以它解决了。

如果除了向您展示这些功能之外,您还可以看到函数被调用的行。这样,无论源文本的功能有多大,都可以找到问题。

现在,让我们更改foo,以便它确实sleep(oneSecond)而不是CPU绑定。这是如何改变的?

这是什么意思,挂钟仍然需要100秒,但CPU时间为零。在仅CPU采样器中采样将显示没有任何内容

所以现在你被告知要尝试仪器而不是采样。包含它告诉你的所有事情,它也告诉你上面显示的百分比,所以在这种情况下,你可以找到问题,假设bar不是很大。 (可能有编写小函数的原因,但是应该满足分析器是其中之一吗?)

实际上,采样器的主要错误是它不能在sleep(或I/O或其他阻止),并且它不会显示代码行百分比,只是功能百分比。

顺便说一句,1000个样本给你很好的精确百分比。假设你抽取了更少的样本。你有多少人需要找到瓶颈?那么,由于90%的时间都是瓶颈,如果你只抽取了10个样本,那么这个样本大概有9个样本,所以你仍然可以看到它。 如果你甚至抽取了3个样本,那么它出现在两个或更多个样本上的概率是97.2%。**

当您的目标是找到瓶颈时,高采样率被高估。

无论如何,这就是为什么我依靠random-pausing

**我是怎么得到97.2%的?把它想象成投掷硬币3次,这是一个非常不公平的硬币,其中“1”意味着看到了瓶颈。有8种可能:

 #1s probabality 
0 0 0 0 0.1^3 * 0.9^0 = 0.001 
0 0 1 1 0.1^2 * 0.9^1 = 0.009 
0 1 0 1 0.1^2 * 0.9^1 = 0.009 
0 1 1 2 0.1^1 * 0.9^2 = 0.081 
1 0 0 1 0.1^2 * 0.9^1 = 0.009 
1 0 1 2 0.1^1 * 0.9^2 = 0.081 
1 1 0 2 0.1^1 * 0.9^2 = 0.081 
1 1 1 3 0.1^0 * 0.9^3 = 0.729 

所以看到它2〜3次的概率是0.081 * 3 + 0.729 = 0.972

+0

很棒的信息,谢谢! :) – 2011-04-06 11:04:14

相关问题