Is there any way for a WinRT app to measure its ow

2019-08-11 04:50发布

问题:

I'm experimenting with different ways to do game graphics in WinRT, and it'd be nice if my test app could measure and display its own CPU usage, so I could compare different approaches (ItemsControl vs. manually moving Images around vs. DirectX).

In full-fledged .NET, I can read Process.TotalProcessorTime at two known points in time, and then take the delta processor time divided by the delta time (adjusted for number of processors if necessary). If the app is running in full-trust, I can even find the Process instance for dwm.exe (since it does all the heavy lifting of putting the GUI on the screen) and add that into my CPU time. This is the approach I took in the WinForms and WPF versions of my Game Graphics test suite.

But in WinRT, the System.Diagnostics.Process class does not exist. If there's an alternate API, I'm not sure where to look for it.

I can open Task Manager and set it to stay on top, and just keep an eye on it as my app runs. This is less than ideal, since (a) it covers part of my window, and therefore probably skews the results slightly; and (b) I can't do any of my own aggregation or logging of the results (e.g. "here was the average CPU usage over a ten-second span"). So if there's some way I could get my CPU usage programmatically, I'd prefer that, just because of the added flexibility it gives me.

Is there any way for a WinRT app to determine its own CPU usage?

回答1:

I don't know of any "approved" API to get this information from within a Windows Store app.

However, if you only want to do this in a test app, you can use "unapproved" APIs. If you use an API that is not approved, your program will not pass WACK certification and can't be uploaded to the store, but for testing locally that's okay. Note that there are no guarantees when you call unapproved APIs, so the behavior is formally undefined, but many functions work fine--at least in the current release.

I demonstrated how to call AllocConsole in an article I wrote earlier this summer, "printf debugging in Metro style apps". You can do something similar from C#, either using P/Invoke to call the native function, or by writing a C++ Windows Runtime Component that can be called from C#.

For your scenario, I'd recommend calling GetCurrentProcess to get the handle to the current process and passing it to GetProcessTimes to get the user and kernel times. I ran a brief test and got reasonable looking results with this approach.

Here's a complete C# class that uses P/Invoke to make the call:

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)
        };
    }
}

Usage:

var times = DebugProcessTimes.GetProcessTimes();


回答2:

Unfortunately, there is no equivalent of the System.Diagnostics.Process class in WinRT, at least not currently (Missing reference to System.Diagnostics.Process and Accessing other processes in Win8 Metro-style app). Some native APIs are exposed to WinRT (see How can I get the number of logical CPUs on WinRT? for an example) but I cannot find a list.