How to tell a process is busy

Hey all,

I was just wondering if anyone could point me towards a way to tell whether a process is still busy doing something, or is sitting idle? I don’t want to quit the program after it’s done and then check whether it’s open or not, but I need to figure out a way to tell when it’s done doing its thing so I can safely move on.

Any ideas? Something through Process Manager or something?


You need to be specific about the application in question.

Some applications (e.g. iTunes, Printer Setup Utility, others) include an application state property that you can query. This typically returns a value such as ‘idle’, ‘playing’, ‘paused’, ‘printing’, etc.

You’d need to examine the dictionary of the application in question to see if it falls into this category. If it does, you’re lucky, and you’re all set.

If not you’ll need to use something such as top and parse out the results. This quick hack should give you an idea of the CPU usage of Safari, although I’m sure there are many other ways of doing the same thing:

do shell script "top -s 2 -l 2 | awk '/Safari/ {busy= $3}; END {print busy}'"

Unfortunately, the application in question is PorDiBle, which isn’t scriptable (at least, no dictionary shows up when I look for it - that’s the same thing, right?).

So I need a generic version.

Yeah, unfortunately I’ve only got a very basic knowledge of unix scripting, so I have no idea what this is doing. :wink: If I substitute the correct application name in to the script above, will it work? :slight_smile:


Correct. Just to be safe, run ‘top’ in a terminal window and look for the process name in question. You need to enter it in the script in the exact same way (including case, etc.).

[*] Technically, ‘Process Viewer’ is the gui equivalent of the command-line app, ‘top’ - it shows running processes, along with various status indicators such as CPU time, memory usage, etc.
The shell script calls top with a couple of options that take a snapshot of what’s running. This is then run through awk, a powerful text=processing utility. The text following ‘awk’ essentially filters out other processes and looks at the CPU time for the process in question.

This does not work if i replace Safari with System Preferences


Here is a generic idle process testing handler that is a bit involved but does the job. Before describing it, I would just note that I use this only as a last resort. Whenever possible, it’s better to query a “busy” property value, or test for a side effect (such as a window or file that opens or closes when the application has completed its task.)

The script uses the shell command “ps” to extract % cpu usage (ranging in value from 0 to 100) by the application process (one of several alternatives, including the “top” command that has already been discussed.) The problem I have encountered with raw % cpu values is that the idle value can vary substantially, sometimes at or near 0%, other times in the 2-10% range, depending unpredictably on the particular process and the environment in which it is running. To overcome this, my script performs a moving average not of the raw % cpu usage but rather of the change in % cpu usage (actually its absolute value) from its last value (“delta cpu”), effectively measuring the first derivative or slope of the % cpu usage curve. As the process “winds down”, the slope approaches zero, and once below a user-specified threshold, the handler signals that the process is idle by returning a true value. To avoid an “idle” signal for a process that is constantly using a high % cpu usage (in which case the slope will also approach zero), the % cpu usage must also be below a user-specified absolute threshold value in order for the handler to return an “idle” signal. Finally, a “testing frequency in seconds” parameter is provided so that the user can tell the handler how often to sample the running process. If the testing frequency is set to 0 seconds, the handler will continuously test the process’s cpu usage (at the cost of the handler expending significant cpu usage itself.) This may seem a bit involved, but it’s really not.



 processName :
 -         name of application process exactly as it appears in Activity Monitor, including case
 testingFrequencyInSeconds :
 -         Lower values = quicker execution speed :
 -         0 = cpu-intensive continuous testing (feedback within 1 second of process becoming idle)
 -         1-5 = general purpose setting (feedback within about 2-8 seconds of process becoming idle)
 -         20-30 = cpu-nonintensive testing for processes running for many minutes (feedback within 30-60 seconds)
 movingAverageSampleCount :
 -         Lower values = quicker execution speed (use "0" for default value => 20) :
 -         5-10 = quicker feedback when process becomes idle (but occasionally returning a false "idle" signal)
 -         20 = general purpose setting
 -         30-40 = slower feedback, but little chance of a false "idle" signal
 deltaCPUThreshold :
 -         Higher values = quicker execution speed (use "0" for default value => 0.5) :
 -         0.1-0.2 = conservative setting with little chance of a false "idle" signal
 -         0.5 = general purpose setting
 -         1-2 = for rare processes with an inherently very large fluctuation in % cpu usage in the idle state
 absoluteCPUThreshold :
 -         Higher values = quicker execution speed (use "0" for default value => 5) :
 -         1-2 = for processes whose % cpu usage dependably approaches zero in the idle state
 -                   (but occasionally not returning an "idle" signal if the process becomes persistent at a low level of cpu usage)
 -         5 = general purpose setting
 -         10 = for processes with dependably large % cpu usage in idle state (but occasionally returning a false "idle" signal)
 -        idle_process_test("Safari",2,20,0.5,5)   -or equivalently-   idle_process_test("Safari",2,0,0,0)

on idle_process_test(processName, testingFrequencyInSeconds, movingAverageSampleCount, deltaCPUThreshold, absoluteCPUThreshold)
	-- Set default values for parameters whose value is set to zero by user
	if movingAverageSampleCount = 0 then set movingAverageSampleCount to 10
	if deltaCPUThreshold = 0 then set deltaCPUThreshold to 0.5
	if absoluteCPUThreshold = 0 then set absoluteCPUThreshold to 5
	-- Initialize variable values
	set deltaCPUSampleValues to {}
	repeat movingAverageSampleCount times
		set end of deltaCPUSampleValues to 100
	end repeat
	set movingAverageSum to 100 * movingAverageSampleCount
	set lastCPUValue to 100
	set {deltaCPUIsBelowThreshold, absoluteCPUIsBelowThreshold} to {false, false}
	-- Loop until delta CPU (moving average) and absolute CPU are below their respective thresholds, then return from handler with a true value
		repeat with i from 1 to movingAverageSampleCount
			set currentCPUValue to (do shell script "ps -acxo %cpu,command | egrep '^ *[.0-9]+ +" & processName & " *$' | egrep -o [.0-9]+") as real
			set oldDeltaCPUSampleValue to item i of deltaCPUSampleValues
			set item i of deltaCPUSampleValues to ((currentCPUValue - lastCPUValue) ^ 2) ^ 0.5
			set lastCPUValue to currentCPUValue
			set movingAverageSum to movingAverageSum + (item i of deltaCPUSampleValues) - oldDeltaCPUSampleValue
			set deltaCPUIsBelowThreshold to (movingAverageSum / movingAverageSampleCount) < deltaCPUThreshold
			set absoluteCPUIsBelowThreshold to currentCPUValue < absoluteCPUThreshold
			if (deltaCPUIsBelowThreshold and absoluteCPUIsBelowThreshold) then return true
			delay testingFrequencyInSeconds / movingAverageSampleCount
		end repeat
	end repeat
end idle_process_test

Hi bmose,

I tried your handler and at first resukt got this error message: «Impossible to render 0.0 in real». Can you tell me what does it mean ?

Thank you for sharing.