2013-03-22 70 views
0

我正在研究一个基准测试工具,其中包括测量执行操作的外部过程使用的时间和内存。我最感兴趣的是峰值可分页内存大小(a.k.a. PageFileBytesPeak性能计数器/ Process.PeakPagedMemorySize64 /峰值专用字节)。这是一个.NET项目,所以纯.NET解决方案会更好,但这很可能不是一种可能性。测量过程高峰内存使用率验尸

这里的问题是我不知道进程退出前的峰值内存使用情况。当过程不再存在时,我无法读取过程的性能计数器。所以我可以在流程运行的时候轮询它。

然而,这并不是优选的,因为如果我经常轮询,我会干扰该过程完成其工作所花费的时间,并且如果轮询结果太少,结果将不准确(该过程很可能会中断它的峰值内存使用权在退出之前)。所以我希望有一些方法来做到这一点确实比我想出了迄今为止的解决方案少哈克:

  1. 进样DLL注入过程中,通过对DLL_PROCESS_DETACH IPC机制报告的价值。
  2. 在执行真正的ExitProcess之前,在目标进程中修补/挂钩ExitProcess,通过IPC机制报告值。
  3. 假装为调试器,测量EXIT_PROCESS_DEBUG_EVENT上的值(在调用ContinueDebugEvent之前,内核不会清理进程)。

回答

1

原来,即使在进程退出后,只要您有一个活动的句柄,GetProcessMemoryInfo也能正常工作。虚拟内存的使用情况不适用于这种方式,但如果您碰巧需要这样做的话。

唯一需要注意的是值的大小取决于调用的进程的位数,因此如果32位进程测量64位进程的内存使用情况,则值可能会溢出。

例子:

[DllImport("psapi.dll", SetLastError=true)] 
static extern bool GetProcessMemoryInfo(IntPtr hProcess, out PROCESS_MEMORY_COUNTERS counters, int size); 

[StructLayout(LayoutKind.Sequential)] 
private struct PROCESS_MEMORY_COUNTERS 
{ 
    public uint cb; 
    public uint PageFaultCount; 
    public UIntPtr PeakWorkingSetSize; 
    public UIntPtr WorkingSetSize; 
    public UIntPtr QuotaPeakPagedPoolUsage; 
    public UIntPtr QuotaPagedPoolUsage; 
    public UIntPtr QuotaPeakNonPagedPoolUsage; 
    public UIntPtr QuotaNonPagedPoolUsage; 
    public UIntPtr PagefileUsage; 
    public UIntPtr PeakPagefileUsage; 
} 

public long BenchmarkProcessMemoryUsage(string fileName, string arguments) 
{ 
    ProcessStartInfo startInfo = new ProcessStartInfo(fileName, arguments); 
    startInfo.UseShellExecute = false; 
    Process process = Process.Start(); 
    process.WaitForExit(); 
    PROCESS_MEMORY_COUNTERS counters; 
    if (!GetProcessMemoryInfo(process.Handle, out counters, Marshal.SizeOf(typeof(PROCESS_MEMORY_COUNTERS)))) 
     throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); 
    return (long)counters.PeakPagefileUsage; 
} 
1

读取现存的PerfMon计数器应该是一个非常低的开销操作,因为计数器通常(可能总是不确定)使用共享内存块(映射文件)来实现。

我会用运行时可配置的时间间隔来实现轮询,如果您发现这会影响您的应用程序,那么只能使用更复杂的技术。如果您想首先检查它,请设置PerfMon以监视感兴趣的计数器,并查看在可用刷新间隔下运行时是否会导致应用程序死机。

+0

即使忽略与使用我还是有问题的过程可能最后一次量子内分配大量内存的问题时干扰的可能性,这将意味着我不能如果我的代码被安排在与分配内存的线程相同的内核中,无论我轮询的速度如何,都可以看到它。这个操作可能需要不到200ms才能完成,而在服务器系统上的时间约为180ms,我甚至没有机会在流程启动和退出之间获得时间片。 – poizan42 2013-03-22 17:29:16

+0

我同意,如果您担心流程关闭(或民意调查之间)的巨大峰值,那么投票是不够的。我只是想知道这是否真的像你想象的那样是一个问题,考虑到它的额外成本。 – 2013-03-22 17:49:49

+0

不幸的是,这是一个基准工具,其主要目的是基准新的后端(它实际上是测试不同的引擎进行PDF转换和连接,但这不是真的与问题相关),所以你可能是对的,它赢了不需要,但我事先不知道。似乎我将不得不去dll注入路线。 – poizan42 2013-03-25 12:04:35