AppleScript Speed Stunner: Round vs. Mod & Div

I was working on a routine the other day and, quite by accident discovered that the round() function is extremely slow. How slow? Compared to a routine that uses DIV and MOD functions, round() is significantly slower.

Here’s my Timing Test script, fitted with two different ways to round the results of a division to the nearest integer:

set theDivisor to 256
set theLoopCount to 20
set {theDividendStart, theDividendStop} to {120, 130}
 --bracket values around tipping points to show equivalent results

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from theDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor)
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat

set t2 to the ticks
repeat theLoopCount times
    set resB to {}
    repeat with theDividend from theDividendStart to theDividendStop
        if ((theDividend mod theDivisor) > (theDivisor div 2)) then
            set extra to 1
        else
            set extra to 0
        end if
        set theQuotient to (theDividend div theDivisor) + extra
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

On my old G4/733, round() is about 30 times slower.

There is even more of a disparity when you add “Rounding up|down” to the mix. The code for rounding up:

set theDivisor to 256
set theLoopCount to 100
set {TheDividendStart, theDividendStop} to {250, 260}

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor) rounding up
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat
set t2 to the ticks

repeat theLoopCount times
    set resB to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        if ((theDividend mod theDivisor) = 0) then
            set extra to 0
        else
            set extra to 1
        end if
        set theQuotient to (theDividend div theDivisor) + extra
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

And rounding down is even simpler:

set theDivisor to 256
set theLoopCount to 100
set {TheDividendStart, theDividendStop} to {250, 260}

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor) rounding down
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat

set t2 to the ticks
repeat theLoopCount times
    set resB to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to (theDividend div theDivisor)
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

In these tests, Round() rounding up|down runs about 50 times slower than the same function written with DIV and MOD.

At this point I am curious about two things. First: is round() any faster on Intel? Second: what sort of timings would you get for equivalent routines written in C (or its variants)?

Apr 18, 2009 1:00 PM

New Drive Still Running

So now we’re into October, 2008 and this drive is still running fine. Helix Server 6.1.x betas have been running here for the last few weeks, too.

It might actually be time to start the move from xhost1 for real.

Oct 9, 2008 11:32 AM

OS X Server Software Updates

After a few miserable attempts at getting OS X Server to handle Software Updates for local machines, I finally figured out what the problem is: Apple’s documentation.

In the System Imaging and SW Update Admin guide it says:

Pointing Unmanaged Clients to a Software Update Server
Use the defaults command in Terminal to point unmanaged client computers to a specific Software Update server. To point unmanaged clients to a specific software update server:

  1. Open Terminal on the unmanaged client.
  2. Enter the following command:

defaults write com.apple.SoftwareUpdate CatalogURL http://host.domain.com:8088/

(Replace the sample URL with the URL of your Software Update server.)

This is wrong!

You can’t simply point at your user’s SoftwareUpdate plist, you have to point at the system’s plist! The correct example then, is:

defaults write /Library/Preferences/com.apple.SoftwareUpdate CatalogURL http://host.domain.com:8088/

That works for OS X 10.4. For 10.5 and 10.6 there is more to do. See a later entry for the rest of the story.

You can check your work with this line:

defaults read /Library/Preferences/com.apple.SoftwareUpdate

Jul 29, 2008 6:22 PM

Retrospect Lives!

So, it appears the EMC hasn’t pulled the plug on Retrospect after all! A public beta test of “Retrospect X” is currently under way. They expect to release the upgrade sometime in 2008.
I was interested in knowing two things: is the issue with Leopard’s firewall resolved and is the issue with OS X Server and SQL files resolved.
I’m happy to report that the Leopard firewall issue seems to be fixed. I put the beta (2nd round) of Retrospect Client on my home Mac mini, which simply would not backup before unless the Firewall was off, (despite trying of the tricks I’ve seen). Now it works fine. Whee.
As for the OS X Server / SQL issue, I don’t know. The new Client requires OS X 10.4 and the Server I am having trouble with runs 10.3. Rats.
Jul 20, 2008 6:54 PM