Friday, September 23, 2011

Gotcha of the Day: Detecting CPU Usage on Windows via PHP

I'm working on an app for a client that has a Windows based server component. The Windows server sits around and waits some items in a queue, and when present, kicks off a potentially very resource intensive process. I quickly learned that having multiple copies of this process running can end up overloading the machine. The fix seemed simple: before kicking off the process check the current CPU usage. If the CPU is at a safe percentage, then go ahead and kick off the process.

While PHP offers some information about memory usage, not surprisingly, it doesn't have any CPU info to give you. On Linux, this sort of problem is trivial to solve. Just install sysstat and kick off mpstat. An even easier approach is to no bother getting the CPU, but base the decision on the load average. If load average is all that's needed, just reading from /proc/loadavg should be all that's necessary. Heck, if you were on Linux you could probably avoid writing any custom code, and just use .

But I'm not on Linux, I'm on Windows.

I couldn't find a PHP solution, so I widened my search to look for how people in the Windows world use command line tools to figure out CPU usage. It didn't take long to figure out that I wanted to use the command typeperf, one I'd never heard of. Apparently, on Windows you can do this:

C:\>typeperf -sc 1 "processor(_Total)\% Processor Time"

"(PDH-CSV 4.0)","\\IP-0A4856C0\processor(_Total)\% Processor Time"
"09/23/2011 13:43:02.430","3.076302"

The command completed successfully.

The -sc 1 says to generate a single sample. Leaving it off will get you a continuous stream of updates on CPU usage. Pretty sweet, eh? The output is even CSV'd, how nice of them.

Another command I tripped over in my search was tasklist. Tasklist is effectively like /bin/ps in the Linux world. It gives you a snapshot of the current process list. It too can be convinced to generate CSV output:

C:>tasklist /FO CSV
"Image Name","PID","Session Name","Session#","Mem Usage"
"System Idle Process","0","Services","0","24 K"
"System","4","Services","0","836 K"
"smss.exe","396","Services","0","376 K"
...

Using this output, I could implement a slightly different strategy for checking server performance. Rather than looking at CPU usage, I could detect how many copies of my resource intensive process were spawned. I could set a limit, say 3, and if more than 3 processes are running, refuse to run more.

I've wrapped the above utilities up into functions below. Feel free to use an enjoy. Of course, I can't guarantee that they are the best solution, they're just what I was able to come up with in a pinch.


/*
 * Return the current CPU usage of a windows server.
 * Inspired by: http://www.sitaram-pamarthi.com/2009/09/how-to-get-cpu-utilization-of-remote.html
 */
function win_sys_current_cpu_usage() {
  $cmd = 'typeperf  -sc 1  "\Processor(_Total)\% Processor Time"';
  exec($cmd, $lines, $retval);
  if($retval == 0) {
    $values = str_getcsv($lines[2]);
    return floatval($values[1]);
  } else {
    return false;
  }
}

/*
 * Return the current list of running process.
 * Inspired by:  http://commandwindows.com/tasklist.htm
 */
function win_sys_current_process_list() {
  $cmd = 'tasklist /FO CSV';
  exec($cmd, $lines, $retval);
  if($retval == 0) {
    array_shift($lines);
    $procs = array();
    foreach($lines as $row) {
      $values = str_getcsv($row);
      $procs[] = $values[0];
    }
    return $procs;
  } else {
    return false;
  }
}

3 comments:

  1. Massive thanks for this. I was stuck with the same problem.

    I used this with Google chart api to show a nice speedometer graphic.

    ReplyDelete
  2. Nice one, but it will not work always. The PHP script might not have (and surely it will not have on a webserver) sufficient rights to call this command prompt sequence.

    ReplyDelete
  3. Anonymous12:18 AM

    wow,, i found great solution there,, thank you

    ReplyDelete