Monthly Archives: January 2009

How to learn WPF (or anything else)

I’ve recently been learning WPF. This is a huge topic that is uncontainable by any single book, tutorial, or web-site. The complexity and breadth of this framework is nearly oppressive, but the results are incredible. Or rather, I should say, potentially incredible.

Like this? Please check out my latest book, Writing High-Performance .NET Code.

From everything I’ve read, people who have suffered through the WPF learning curve have this to say, more or less:

yeah, it was really tough going for a few months. But now I can create awesome apps in a fraction of the time it would take with older technologies.

So with that in mind, I really do want to learn WPF. I have a number of C# references, weighty tomes that bend my shelves, but the main book I use is Programming WPFby Chris Sells and Ian Griffiths. I really like this book—it goes in deep. However, I realized that reading through it cover to cover and doing all the sample apps wasn’t going to work—it gets boring, no matter how good the book is. So here is my recommendation on how to learn WPF (and it probably applies to any programming technology):

  1. Start reading the book, do the code, type stuff in, copy it, tweak it. Do this for as long as you can.
  2. Once step 1 becomes boring, STOP. It is not productive to force yourself through the whole thing like this.
  3. Find a sample project in your target technology. I used Family.Show. There are plenty out there.
  4. Think of a project YOU find interesting that would be good in [WPF|other]. Start doing this. Even if you don’t know where to start at all.
  5. While getting started, every step will be a challenge. Figure it out step-by-step, going back to the book and online resources.

You might be tempted to skip steps 1-2. I think this is a bad idea. You need at least some foundational understanding. Only when you can’t take it any more and you’re in danger of quitting, move on.

This has worked well for me in learning WPF. I decided to implement a game (if it ever gets into a polished state, I’ll share it).

Don’t underestimate the challenges in step 4, though. I had to think about how to even start, going back to the book numerous times, reading large sections. I looked up articles online about patterns and WPF, user controls, and more. Many seemingly-small steps in just displaying windows took hours to figure out. Figuring out data binding (really figuring it out in the context of my app) took hours. The point of doing your own project isn’t because it’s easier than following the book—it’s because it’s fun and you have more motivation to learn.


Check out my latest book, the essential, in-depth guide to performance for all .NET developers:

Writing High-Performance.NET Code, 2nd Edition by Ben Watson. Available for pre-order:

Determine CPU usage of current process (C++ and C#)

Like this? Please check out my latest book, Writing High-Performance .NET Code.

Updated 2/4/2009: I changed the implementation of these classes from the original:

  • Instead of a critical section, InterlockedIncrement/Decrement is used.
  • The sample driver program now demos using multiple threads using the CpuUsage class to show thread safety.

Download the C++ and C# projects that accompany this article.

Just to make it clear, there is no API called GetProcessCpuPercentage(). To find out the percentage, we can use some other, real APIs and do some calculations. Before getting to the equation and code, let’s discuss the different types of time available.

There are four types of time:

  1. Wall time – The actual, real-world progression of time as measured by you on your watch.
  2. Kernel time – The amount of time spent in kernel mode (protected, high-order mode of operation)
  3. User time – the amount of time spent in user-mode (often by the process itself)
  4. Idle time – nothing going on at all

Kernel, User, and Idle sum to total time, which is approximately wall-time.

Each process spends some time in kernel mode and some time in user mode. We just need to compare the time spent by a process to the time spent by all processes on the computer, since the last time we made such a measurement. It is important to note that we do NOT take into account the idle time.

Thus, the equation is

CpuPercentageEquation

There are two APIs that are useful:

The times reported are absolute, so what we are actually interested is in the difference between the current times and those from a previous run.

Armed with this information, we can calculate the CPU usage for the current process (or any arbitrary process, for that matter).

Let’s do it first in C++ to demonstrate usage of the APIs.

CPU Usage Percentage in C++

Here’s the header file:

   1: #pragma once
   2: #include <windows.h>
   3:
   4: class CpuUsage
   5: {
   6: public:
   7:     CpuUsage(void);
   8:
   9:     short  GetUsage();
  10: private:
  11:     ULONGLONG SubtractTimes(const FILETIME& ftA, const FILETIME& ftB);
  12:     bool EnoughTimePassed();
  13:     inline bool IsFirstRun() const { return (m_dwLastRun == 0); }
  14:
  15:     //system total times
  16:     FILETIME m_ftPrevSysKernel;
  17:     FILETIME m_ftPrevSysUser;
  18:
  19:     //process times
  20:     FILETIME m_ftPrevProcKernel;
  21:     FILETIME m_ftPrevProcUser;
  22:
  23:     short m_nCpuUsage;
  24:     ULONGLONG m_dwLastRun;
  25:
  26:     volatile LONG m_lRunCount;
  27: };

The GetUsage() method is where the work occurs. The other methods are to help in the calculations. The critical section run count enables the code to be called in a multi-threaded environment without problems. I also prevent the code from being called more often than every 250ms. Here is the complete implementation:

   1: #include "StdAfx.h"
   2: #include <windows.h>
   3: #include "CpuUsage.h"
   4:
   5: CpuUsage::CpuUsage(void)
   6: :m_nCpuUsage(-1)
   7: ,m_dwLastRun(0)
   8: ,m_lRunCount(0)
   9: {
  10:     ZeroMemory(&m_ftPrevSysKernel, sizeof(FILETIME));
  11:     ZeroMemory(&m_ftPrevSysUser, sizeof(FILETIME));
  12:
  13:     ZeroMemory(&m_ftPrevProcKernel, sizeof(FILETIME));
  14:     ZeroMemory(&m_ftPrevProcUser, sizeof(FILETIME));
  15:
  16: }
  17:
  18:
  19: /**********************************************
  20: * CpuUsage::GetUsage
  21: * returns the percent of the CPU that this process
  22: * has used since the last time the method was called.
  23: * If there is not enough information, -1 is returned.
  24: * If the method is recalled to quickly, the previous value
  25: * is returned.
  26: ***********************************************/
  27: short CpuUsage::GetUsage()
  28: {
  29:     //create a local copy to protect against race conditions in setting the 
  30:     //member variable
  31:     short nCpuCopy = m_nCpuUsage;
  32:     if (::InterlockedIncrement(&m_lRunCount) == 1)
  33:     {
  34:         /*
  35:         If this is called too often, the measurement itself will greatly 
  36:         affect the results.
  37:         */
  38:
  39:         if (!EnoughTimePassed())
  40:         {
  41:             ::InterlockedDecrement(&m_lRunCount);
  42:             return nCpuCopy;
  43:         }
  44:
  45:         FILETIME ftSysIdle, ftSysKernel, ftSysUser;
  46:         FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;
  47:
  48:         if (!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser) ||
  49:             !GetProcessTimes(GetCurrentProcess(), &ftProcCreation,
  50:                 &ftProcExit, &ftProcKernel, &ftProcUser))
  51:         {
  52:             ::InterlockedDecrement(&m_lRunCount);
  53:             return nCpuCopy;
  54:         }
  55:
  56:         if (!IsFirstRun())
  57:         {
  58:             /*
  59:             CPU usage is calculated by getting the total amount of time 
  60:             the system has operated since the last measurement 
  61:             (made up of kernel + user) and the total
  62:             amount of time the process has run (kernel + user).
  63:             */
  64:             ULONGLONG ftSysKernelDiff =
  65:                 SubtractTimes(ftSysKernel, m_ftPrevSysKernel);
  66:             ULONGLONG ftSysUserDiff =
  67:                 SubtractTimes(ftSysUser, m_ftPrevSysUser);
  68:
  69:             ULONGLONG ftProcKernelDiff =
  70:                 SubtractTimes(ftProcKernel, m_ftPrevProcKernel);
  71:             ULONGLONG ftProcUserDiff =
  72:             SubtractTimes(ftProcUser, m_ftPrevProcUser);
  73:
  74:             ULONGLONG nTotalSys =  ftSysKernelDiff + ftSysUserDiff;
  75:             ULONGLONG nTotalProc = ftProcKernelDiff + ftProcUserDiff;
  76:
  77:             if (nTotalSys > 0)
  78:             {
  79:                 m_nCpuUsage = (short)((100.0 * nTotalProc) / nTotalSys);
  80:             }
  81:         }
  82:
  83:         m_ftPrevSysKernel = ftSysKernel;
  84:         m_ftPrevSysUser = ftSysUser;
  85:         m_ftPrevProcKernel = ftProcKernel;
  86:         m_ftPrevProcUser = ftProcUser;
  87:
  88:         m_dwLastRun = GetTickCount64();
  89:
  90:         nCpuCopy = m_nCpuUsage;
  91:     }
  92:
  93:     ::InterlockedDecrement(&m_lRunCount);
  94:
  95:     return nCpuCopy;
  96: }
  97:
  98: ULONGLONG CpuUsage::SubtractTimes(const FILETIME& ftA, const FILETIME& ftB)
  99: {
 100:     LARGE_INTEGER a, b;
 101:     a.LowPart = ftA.dwLowDateTime;
 102:     a.HighPart = ftA.dwHighDateTime;
 103:
 104:     b.LowPart = ftB.dwLowDateTime;
 105:     b.HighPart = ftB.dwHighDateTime;
 106:
 107:     return a.QuadPart - b.QuadPart;
 108: }
 109:
 110: bool CpuUsage::EnoughTimePassed()
 111: {
 112:     const int minElapsedMS = 250;//milliseconds
 113:
 114:     ULONGLONG dwCurrentTickCount = GetTickCount64();
 115:     return (dwCurrentTickCount - m_dwLastRun) > minElapsedMS;
 116: }

In order to test this, here is a simple program that starts two threads that run an infinite loop, eating the processor. On a dual-core system, this process will take roughly 85-95% of the CPU. I also start two threads to access the usage object and poll the CPU usage in order to demonstrate the thread safety of the object.

   1: // CpuUsageCpp.cpp : Defines the entry point for the console application.
   2: //
   3:
   4: #include "stdafx.h"
   5: #include <windows.h>
   6: #include "CpuUsage.h"
   7:
   8: DWORD WINAPI EatItThreadProc(LPVOID lpParam);
   9: DWORD WINAPI WatchItThreadProc(LPVOID lpParam);
  10:
  11: CpuUsage usage;
  12:
  13: int _tmain(int argc, _TCHAR* argv[])
  14: {
  15:     //start threads to eat the processor
  16:     CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
  17:     CreateThread(NULL, 0, EatItThreadProc, NULL, 0, NULL);
  18:
  19:     //start threads to watch the processor (to test thread-safety)
  20:     CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
  21:     CreateThread(NULL, 0, WatchItThreadProc, NULL, 0, NULL);
  22:
  23:     while (true)
  24:     {
  25:         Sleep(1000);
  26:     }
  27:
  28:     return 0;
  29: }
  30:
  31:
  32: DWORD WINAPI WatchItThreadProc(LPVOID lpParam)
  33: {
  34:     while (true)
  35:     {
  36:         short cpuUsage = usage.GetUsage();
  37:
  38:         printf("Thread id %d: %d%% cpu usage\n", ::GetCurrentThreadId(), cpuUsage);
  39:         Sleep(1000);
  40:     }
  41: }
  42:
  43: DWORD WINAPI EatItThreadProc(LPVOID lpParam)
  44: {
  45:     ULONGLONG accum = 0;
  46:     while (true)
  47:     {
  48:         accum++;
  49:     }
  50:
  51:     printf("%64d\n", accum);
  52: }

C# Version

In C#, The System.Diagnostics.Process can give us the time information for a specific process. However, we still need the Win32 API call for getting the total system times (GetSystemTimes). The Process class reports times in TimeSpans, not FILETIME, so our class is modified accordingly.

   1: using System;using System.Collections.Generic;
   2: using System.Linq;
   3: using System.Text;
   4: using System.Runtime.InteropServices;
   5: using ComTypes = System.Runtime.InteropServices.ComTypes;
   6: using System.Threading;
   7: using System.Diagnostics;
   8:
   9: namespace CpuUsageCs
  10: {
  11:     class CpuUsage
  12:     {
  13:         [DllImport("kernel32.dll", SetLastError = true)]
  14:         static extern bool GetSystemTimes(
  15:                     out ComTypes.FILETIME lpIdleTime,
  16:                     out ComTypes.FILETIME lpKernelTime,
  17:                     out ComTypes.FILETIME lpUserTime
  18:                     );
  19:
  20:         ComTypes.FILETIME _prevSysKernel;
  21:         ComTypes.FILETIME _prevSysUser;
  22:
  23:         TimeSpan _prevProcTotal;
  24:
  25:         Int16 _cpuUsage;
  26:         DateTime _lastRun;
  27:         long _runCount;
  28:
  29:         public CpuUsage()
  30:         {
  31:             _cpuUsage = -1;
  32:             _lastRun = DateTime.MinValue;
  33:             _prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
  34:             _prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
  35:             _prevProcTotal = TimeSpan.MinValue;
  36:             _runCount = 0;
  37:         }
  38:
  39:         public short GetUsage()
  40:         {
  41:             short cpuCopy = _cpuUsage;
  42:             if (Interlocked.Increment(ref _runCount) == 1)
  43:             {
  44:                 if (!EnoughTimePassed)
  45:                 {
  46:                     Interlocked.Decrement(ref _runCount);
  47:                     return cpuCopy;
  48:                 }
  49:
  50:                 ComTypes.FILETIME sysIdle, sysKernel, sysUser;
  51:                 TimeSpan procTime;
  52:
  53:                 Process process = Process.GetCurrentProcess();
  54:                 procTime = process.TotalProcessorTime;
  55:
  56:                 if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
  57:                 {
  58:                     Interlocked.Decrement(ref _runCount);
  59:                     return cpuCopy;
  60:                 }
  61:
  62:                 if (!IsFirstRun)
  63:                 {
  64:                     UInt64 sysKernelDiff =
  65:                         SubtractTimes(sysKernel, _prevSysKernel);
  66:                     UInt64 sysUserDiff =
  67:                         SubtractTimes(sysUser, _prevSysUser);
  68:
  69:                     UInt64 sysTotal = sysKernelDiff + sysUserDiff;
  70:
  71:                     Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
  72:
  73:                     if (sysTotal > 0)
  74:                     {
  75:                         _cpuUsage = (short)((100.0 * procTotal) / sysTotal);
  76:                     }
  77:                 }
  78:
  79:                 _prevProcTotal = procTime;
  80:                 _prevSysKernel = sysKernel;
  81:                 _prevSysUser = sysUser;
  82:
  83:                 _lastRun = DateTime.Now;
  84:
  85:                 cpuCopy = _cpuUsage;
  86:             }
  87:             Interlocked.Decrement(ref _runCount);
  88:
  89:             return cpuCopy;
  90:
  91:         }
  92:
  93:         private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
  94:         {
  95:             UInt64 aInt =
  96:             ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
  97:             UInt64 bInt =
  98:             ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
  99:
 100:             return aInt - bInt;
 101:         }
 102:
 103:         private bool EnoughTimePassed
 104:         {
 105:             get
 106:             {
 107:                 const int minimumElapsedMS = 250;
 108:                 TimeSpan sinceLast = DateTime.Now - _lastRun;
 109:                 return sinceLast.TotalMilliseconds > minimumElapsedMS;
 110:             }
 111:         }
 112:
 113:         private bool IsFirstRun
 114:         {
 115:             get
 116:             {
 117:                 return (_lastRun == DateTime.MinValue);
 118:             }
 119:         }
 120:     }
 121: }

These classes can now be used wherever you need to monitor the CPU usage of a process.

Notice any improvements to be made? Leave a comment.

Download C++ and C# projects


Check out my latest book, the essential, in-depth guide to performance for all .NET developers:

Writing High-Performance.NET Code, 2nd Edition by Ben Watson. Available for pre-order: