Top CPU Processes

Continuing the series of geeklets I’ve been posting for GeekTool and NerdTool1, here’s my “Top CPU Processes” monitor.

This geeklet is pretty useful. It’s effectively like running top on your desktop (but without the overhead) to see what processes are currently taking up the most cycles on your CPU. It works best in combination with a 1 minute CPU load monitor. I set this geeklet to update every 5 seconds. Within 5 seconds, things can change a lot, but any process that is taking up a significant portion of the current load will generally stay at the top and offer a clear idea of what might be slowing things down. It generally keeps running when other things start hanging, so it’s much more convenient than using Activity Monitor or top at the command line.

The script parses the ps command (process status, information about all of your processes). It uses the arguments ps -arcwwwxo "command %cpu" to display all processes (including other users’ and processes without terminals) by their executable name, sort by CPU and limit the columns in the output to just the command name and CPU percentage. That handles the bulk of the work right there. The rest of my script simply pulls out the top processes, limiting the number to 10 and cutting it short if there are more than five processes listed at 0%.

It color codes the output based on percentage, giving you red, yellow and blue lines if processes are above 10%, 20%, and 30%, respectively. It also justifies the output, truncating the process name if necessary and adding the percentage in parenthesis with a stretched space to right justify them. In order for the justification to work, you need to use a monospaced font such as Menlo or Droid Sans Mono (Inconsolata looks pretty good, too).

The script accepts one command line argument: -t "title". If you leave that off, it will automatically put “Top CPU processes” and a newline at the top of the output. If you add -t without an argument after it, it will remove the title entirely. If you use -t "Custom title" it will replace the default with your custom title (and automatic newline). Any other customization (colors, removing justification) will require manually editing the script. You’re on your own for that.

Here’s the script in its entirety. Just copy and paste it into a file called cpumeter.rb, place it in a script folder and make it executable (chmod a+x cpumeter.rb). Add the path to it as a shell geeklet and you’re good to go. In NerdTool, you may need to specify that the output is colorized.

#!/usr/bin/ruby

RED = "\033[31m"
GREEN = "\033[32m"
YELLOW = "\033[33m"
BLUE = "\033[34m"
MAGENTA = "\033[35m"
CYAN = "\033[36m"
WHITE = "\033[37m"
DEFAULT="\033[0;39m"

def spacer(string)
	if string.length > 15
		string = string[0 .. 12] + "...  "
	else
		spaces = 16 - string.length
		0.upto(spaces) do
			string += " "
		end
	end
	string
end

input = %x{ps -arcwwwxo "command %cpu"}.split("\n")
counter, total = 0, 0

title = ARGV[0] == "-t" ? ARGV[1] : "Top CPU processes"
print "#{title}\n\n" unless ARGV[0] == "-t" && ARGV[1].nil?

input.each {|line|
	if line =~ /^(.*?)\s+(\d{1,3}[\.,]\d)$/
		exit if counter == 5 or total == 10
		score = $2.to_i
		color = case score
		   when 0..10 then DEFAULT
		   when 11..20 then CYAN
		   when 21..30 then YELLOW
		   when 30..200 then RED
		   else RED
		end

		puts "#{color}#{spacer($1)}(#{$2})\033[0m"

		counter += 1 if $2.to_i < 1
		total += 1
	end
}

Updated to work with non-US systems

Next up, the same type of system monitor, but for physical memory size.

  1. If you’re still trying to figure out which you want to run, see Dr. Drang’s article on the subject.