Surprising timing result

I was comparing these two methods of getting the length of an integer and timing a large number of repetitions with GetMilliSec. Surprisingly, the time taken is about the same.

set n to 123456
-- method 1 --
set k to 0
set d to 1
repeat while n div d > 0   -- could be until n div d = 0
	set k to k + 1
	set d to d * 10
end repeat
k --> 6
-- method 2 --
set c to count of characters of (n as text)
c --> 6

Hi, Adam.

On both my machines, the second method is 1.5 to 1.6 times as fast as the first (when n is set to 123456). The timing of the second can be improved very slightly by simply counting the text rather than specifically the characters in it:

set c to (count (n as text))

The first method can be made to catch up a little (and give the correct result with 0) if arranged like this:

set k to 1
set d to n div 10
repeat until (d is 0)
	set k to k + 1
	set d to d div 10
end repeat

The text method will need extra code if it’s likely to have to handle negative numbers, of course. :slight_smile:

How do you eliminate the latency in GetMilliSec, Nigel? Or do you use some other timing?

Note while you were adding your response, I was noting that = 0 is better than > 0, but hadn’t got to your n div 10 approach. Nice - eliminates the multiply.

Hi. Adam.

I do use GetMilliSec, as in the template script below. I’m not interested in the exact timings, of course, but in getting some idea of whether one way of doing things is more efficient than another. This was more important with my old 4400 than it is with the latest G5s, but it’s still nice to know the score occasionally.

The test script gets rewritten as necessary. The code to be compared goes either directly into the script’s repeats or into handlers that are called from the repeats. (In which case, handlers are used for both bits of code.) The value of ‘lotsa’ can be increased or decreased, maybe by several orders of magnitude, as deemed sensible.

I run the comparisons several times to make sure the results are consistent. If one piece of code proves several times faster than the other, then it’s the clear winner (as regards speed). If there’s very little in it, I swap the order of the tests (as this sometimes has a small influence on the result!) before coming to any conclusions

Comparative tests like these can only show what’s faster on a particular machine at a particular time, not why. Scripters have to develop their own feel for what’s an inherently better approach and what’s a transitory phenomenon due to a software version or system configuration.

main()

on main()
	set lotsa to 500
	-- Any other preliminary values here.
	
	-- Dummy loop to absorb a small observed
	-- time handicap in the first repeat.
	repeat lotsa times
	end repeat
	
	-- Test 1.
	set t to GetMilliSec
	repeat lotsa times
		-- First test code or handler call here.
	end repeat
	set t1 to ((GetMilliSec) - t) / 1000
	
	-- Test 2.
	set t to GetMilliSec
	repeat lotsa times
		-- Second test code or handler call here.
	end repeat
	set t2 to ((GetMilliSec) - t) / 1000
	
	-- More test loops here if required.
	
	-- Timings.
	{t1, t2, t1 / t2}
end main

Thanks, that’s a nice framework for testing that minimizes the calls to GetMilliSec and accumulates the result without averaging. It’s also easy to rate the machine too - just run it with nothing in the loops with lotsa set to 100,000 or so.

i dont know if you’ll like this way but here is my results from terminal using time to test the script.

Method 1:

time osascript -e 'set n to 123456 set k to 0 set d to 1 repeat while n div d > 0 -- could be until n div d = 0 set k to k + 1 set d to d * 10 end repeat'
Result: 1000000

Time:
real 0m0.812s
user 0m0.276s
sys 0m0.414s

and the second way,

time osascript -e 'set n to 123456 set c to count of characters of (n as text)'
Result: 6

Time:
real 0m0.819s
user 0m0.275s
sys 0m0.414s

Something cooking with that method that I don’t understand, though. If you run either test repeatedly (just copying your text to the terminal and then using up arrow to get it again and return to run it again) the times decline for several trials.

My Jaguar and Tiger Terminals certainly don’t like it! :wink: They poo-poo nearly every line. Variously: “Unmatched '.” “Command not found.” “Variable name must begin with a letter.” “Badly formed number.”

Some time ago I spent some time on an approach to find out the timing of some lines of applescript.
My first thoughts were using repeat loops like Nigel did - but the repeat contrution will also need some time to process so the solution I finally used was like so (no idea if this is any closer to the truth than your preceding ideas):

set noLoopingPart to "set n to 123456"
set testPart1 to "set c to (count (n as text))"
set testPart2 to "set k to 1
set d to n div 10
repeat until (d is 0)
   set k to k + 1
   set d to d div 10
end repeat"
set loops to 500

set thistest to display dialog "Run Test" buttons {"1", "2"}
if button returned of thistest = "1" then
	test(noLoopingPart, testPart1, loops)
else
	test(noLoopingPart, testPart2, loops)
end if

property tmpDir : "/private/tmp/"
property firstLine : "set theStart to GetMilliSec"
property lastLine : "set theEnd to GetMilliSec
set theResult to (theEnd - theStart) / nTimes
display dialog \"Done \" & return & \" The Result: \" & theResult & \" milliseconds\""

on test(noLoop, thisScript, nTimes)
	set tmpScript to POSIX file (tmpDir & (do shell script "date \"+tempScript_%Y-%m-%d_%H-%M-%S.app\""))
	tell application "Script Editor"
		set thisDoc to make new document
		set thescript to "set nTimes to " & nTimes & return
		set thescript to thescript & noLoop & return
		set thescript to thescript & firstLine & return
		repeat with n from 1 to nTimes
			set thescript to thescript & thisScript & return
		end repeat
		set thescript to thescript & lastLine & return
		set text of thisDoc to thescript
		close thisDoc saving in tmpScript
	end tell
	tell application "Finder" to open tmpScript
end test

That’s an interesting approach, Dominik, and like the others it gives variable results. Although test 1 always trumps test 2 by a bit, the bit varies quit a lot. Your test, by the way, won’t run in Script Debugger 4 because it is not scriptable.

I’m rapidly getting the impression that there isn’t an easy and reliable way to measure AppleScript performance, and I’m not too sure that even comparisons tell you much unless the two alternatives differ a lot.

I have no problems on Tiger.

Kim, I’ll add some code tags to your post.