【问题标题】:Is there any way for a WinRT app to measure its own CPU usage?WinRT 应用程序有什么方法可以测量自己的 CPU 使用率?
【发布时间】:2013-04-22 05:37:21
【问题描述】:

我正在尝试用不同的方法在 WinRT 中制作游戏图形,如果我的测试应用可以测量和显示它自己的 CPU 使用率,那就太好了,这样我就可以比较不同的方法(ItemsControl 与手动移动图像与 DirectX)。

在成熟的 .NET 中,我可以在两个已知时间点读取Process.TotalProcessorTime,然后将增量处理器时间除以增量时间(必要时根据处理器数量进行调整)。如果应用程序以完全信任的方式运行,我什至可以找到 dwm.exe 的 Process 实例(因为它完成了将 GUI 放在屏幕上的所有繁重工作)并将其添加到我的 CPU 时间中。这是我在 Game Graphics test suite 的 WinForms 和 WPF 版本中采用的方法。

但在 WinRT 中,System.Diagnostics.Process 类不存在。如果有备用 API,我不确定在哪里可以找到它。

我可以打开任务管理器并将其设置为保持在顶部,并在我的应用运行时密切关注它。这不太理想,因为(a)它覆盖了我的窗口的一部分,因此可能会稍微扭曲结果;并且 (b) 我不能对结果进行任何自己的聚合或记录(例如,“这是 10 秒跨度内的平均 CPU 使用率”)。因此,如果有某种方式可以让我以编程方式获取 CPU 使用率,我会更喜欢这种方式,因为它为我提供了额外的灵活性。

WinRT 应用有没有办法确定自己的 CPU 使用率?

【问题讨论】:

    标签: windows-runtime cpu-usage


    【解决方案1】:

    我不知道有任何“已批准”的 API 可以从 Windows 应用商店应用程序中获取此信息。

    但是,如果您只想在测试应用中执行此操作,则可以使用“未经批准”的 API。如果你使用未经批准的 API,你的程序将无法通过 WACK 认证,无法上传到商店,但在本地进行测试是可以的。请注意,当您调用未经批准的 API 时无法保证,因此该行为在形式上是未定义的,但许多函数都可以正常工作——至少在当前版本中是这样。

    我在今年夏天早些时候写的一篇文章"printf debugging in Metro style apps" 中演示了如何调用AllocConsole。您可以在 C# 中执行类似的操作,使用 P/Invoke 调用本机函数,或编写可从 C# 调用的 C++ Windows 运行时组件。

    对于您的情况,我建议调用GetCurrentProcess 来获取当前进程的句柄并将其传递给GetProcessTimes 以获取用户和内核时间。我进行了一个简短的测试,并通过这种方法获得了看起来合理的结果。

    这是一个使用 P/Invoke 进行调用的完整 C# 类:

    static class DebugProcessTimes
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct FileTime
        {
            public UInt32 Low;
            public UInt32 High;
        }
    
        private static UInt64 ToUInt64(FileTime time)
        {
            return ((UInt64)time.High << 32) + time.Low;
        }
    
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetCurrentProcess();
    
        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetProcessTimes(
            IntPtr hProcess,
            out FileTime lpCreationTime,
            out FileTime lpExitTime,
            out FileTime lpKernelTime,
            out FileTime lpUserTime);
    
        public struct ProcessTimes
        {
            public UInt64 CreationTime;
            public UInt64 ExitTime;
            public UInt64 KernelTime;
            public UInt64 UserTime;
        }
    
        public static ProcessTimes GetProcessTimes()
        {
            FileTime creation, exit, kernel, user;
    
            if (!GetProcessTimes(GetCurrentProcess(),
                    out creation, out exit, out kernel, out user))
                throw new Exception(":'(");
    
            return new ProcessTimes
            {
                CreationTime = ToUInt64(creation),
                ExitTime     = ToUInt64(exit),
                KernelTime   = ToUInt64(kernel),
                UserTime     = ToUInt64(user)
            };
        }
    }
    

    用法:

    var times = DebugProcessTimes.GetProcessTimes();
    

    【讨论】:

    • 有趣!由于 pinvoke.net 上的声明依赖于诸如 System.Runtime.InteropServices.FILETIME 之类的类型,这些类型未在 WinRT 中公开,您是否介意发布您的 P/Invoke 代码,因为听起来您已经对此感到困惑了?跨度>
    • 我还没有编写 P/Invoke 代码,但我快速尝试了一下。查看更新。结果看起来很合理。
    【解决方案2】:

    不幸的是,WinRT 中没有等效的 System.Diagnostics.Process 类,至少目前没有(Missing reference to System.Diagnostics.ProcessAccessing other processes in Win8 Metro-style app)。一些本机 API 向 WinRT 公开(参见 How can I get the number of logical CPUs on WinRT? 示例),但我找不到列表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多