Saturday, August 8, 2020

#1 2019-09-23 05:57:40 am

KniazidisR
Member
Registered: 2019-03-03
Posts: 1260

Advanced Scripts Execution Timing.

Applescript:


set repetitions to 12 -- or other. The more repetitions, the more accurate the result.

set theTime to 0
repeat repetitions times
   set timeStart to current date
   
   -- HERE PUT YOUR TESTED SCRIPT'S ON RUN HANDLER
   
   set theTime to theTime + ((current date) - timeStart)
end repeat
set theTime to (1000 * theTime / repetitions) as integer -- result as milliseconds

This tip is very useful for me to test code lines one by one, or some snippet of the script, or the whole script.

For example, getting all properties of selected in "Mail" messages results on my machine in 900 milliseconds (that is, 0.9 seconds) with 10 iterations:

Applescript:


set repetitions to 10 -- or other what you want.

set theTime to 0
repeat repetitions times
   set timeStart to current date
   
   tell application "Mail"
       set aMessage to item 1 of (get selection)
       tell aMessage
           set aContent to content
           set |source| to source
           set |subject| to subject
           set |sender| to sender
           set |messageId| to message id
           set messageSize to message size
           set wasForwarded to was forwarded
           set wasRedirected to was redirected
           set wasRepliedTo to was replied to
           set replyTo to reply to
           set readStatus to read status
           set junkMailStatus to junk mail status
           set |id| to id
           set flaggedStatus to flagged status
           set flagIndex to flag index
           set deletedStatus to deleted status
           set backgroundColor to background color
           set dateReceived to date received
           set dateSent to date sent
           set |mailBox| to its mailbox
       end tell
   end tell
   
   set timeEnd to current date
   set theTime to theTime + ((current date) - timeStart)
end repeat
set theTime to (1000 * theTime / repetitions) as integer -- result as milliseconds

Last edited by KniazidisR (2019-09-23 06:58:28 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#2 2019-09-23 09:07:16 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

KniazidisR wrote:

Applescript:


set repetitions to 12 -- or other. The more repetitions, the more accurate the result.

set theTime to 0
repeat repetitions times
   set timeStart to current date
   
   -- HERE PUT YOUR TESTED SCRIPT'S ON RUN HANDLER
   
   set theTime to theTime + ((current date) - timeStart)
end repeat
set theTime to (1000 * theTime / repetitions) as integer -- result as milliseconds


I was curious if the above script has any advantage over the following. I ran some timing tests using delay as the task being performed and the results were the same. So perhaps this is just a matter of style. BTW, I do a lot of script timing tests and would like to know if there is any best way to do this.

Applescript:


set repetitions to 10

set startTime to (time of (current date))
repeat repetitions times
   delay 1 --substitute whatever task is being performed
end repeat
set executeTime to (time of (current date)) - startTime

set theTime to (1000 * executeTime / repetitions) as integer

Last edited by peavine (2019-09-23 09:39:58 am)


2018 Mac mini - macOS Catalina

Offline

 

#3 2019-09-23 10:31:12 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5261

Re: Advanced Scripts Execution Timing.

Hi.

KniazidisR's script doesn't include the small amount of time it takes the repeat itself to execute, but does add two current date calls and some date math per repeat (although these only partially add to the timings). peavine's does the opposite. Also, by subtracting the dates' times instead of the dates themselves, it lays itself open to strange results if midnight occurs during the test!

In both cases, the time interval on which the final calculation is done is an exact number of seconds and is based on the number of date second boundaries crossed between the current date calls. So the "milliseconds" end result is likely to be far from accurate.

A more accurate result can be obtained by using NSDate in ASObjC. The interval result's still in seconds, but with the fractional part included to quite a large number of decimal places:

Applescript:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set repetitions to 10
set startTime to current application's class "NSDate"'s |date|()

repeat repetitions times
   delay 0.75 --or whatever
end repeat

-- startTime was so many seconds *ago*, so multiply the interval by *minus* 1000 for a positive number of milliseconds.
set thetime to ((startTime's timeIntervalSinceNow()) * -1000 / repetitions) as integer


NG

Offline

 

#4 2019-09-23 01:47:12 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

Nigel--thanks for the script. I tested it with various code snippets and it works great.

I was curious and ran each script with one repetition with a timed-task of "delay 0.3". The results were:

Peavine's script - 0 milliseconds

KniazidisR's script - 0 milliseconds

Nigel's script - 302 milliseconds

This is not a usable test of anything but appears to demonstrate the decimal seconds returned when using NSDate.

Last edited by peavine (2019-09-23 06:49:56 pm)


2018 Mac mini - macOS Catalina

Offline

 

#5 2019-09-23 05:42:54 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

You should keep in mind that editors add a certain amount of overhead via instrumentation callbacks, especially when the codes involve sending events. This can distort results significantly. You'll get a more accurate result if you use my Script Geek.app, which skips any callbacks, but ultimately an applet is the best host (assuming your ultimate destination is an applet).


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#6 2019-09-23 08:11:08 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

For geeks only...

I looked into this a bit more recently, and there are a couple of alternatives to using NSDate in ASObjC. First is the function CFAbsoluteTimeGetCurrent():

Applescript:

set theStart to current application's CFAbsoluteTimeGetCurrent()
-- do stuff
set timeTaken to (current application's CFAbsoluteTimeGetCurrent()) - theStart

Its main attraction is that it's a little simpler to use/type than NSDate. It's also actually a bit faster to execute, although that's unlikely to make any difference unless you're not timing repetitions.

There's also systemUptime() in NSProcessInfo:

Applescript:

set theStart to current application's NSProcessInfo's processInfo()'s systemUptime()
-- do stuff
set timeTaken to (current application's NSProcessInfo's processInfo()'s systemUptime()) - theStart

More effort to type, and a bit slower to boot.

However, all of these are tied to the calculated time, which can change (time syncing, OS making corrections, leap seconds, timezone changes). Depending on a range of factors, the first two are not infrequent.

The most accurate clock on the system is a low-level kernel function, mach_absolute_time(), which is precise to the nanosecond — but it is not accessible to ASObjC. However, there's another function, CACurrentMediaTime(), which is based on it and converts the result to seconds. So:

Applescript:

set theStart to current application's CACurrentMediaTime()
-- do stuff
set timeTaken to (current application's CACurrentMediaTime()) - theStart

Although it's part of the QuartzCore framework, I don't believe it needs a use framework statement other than for Foundation. In terms of overhead, it's somewhere between using NSDate and CFAbsoluteTimeGetCurrent().

Here's a bit more info:

https://kandelvijaya.com/2016/10/25/pre … minginios/


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#7 2019-09-23 09:13:36 pm

KniazidisR
Member
Registered: 2019-03-03
Posts: 1260

Re: Advanced Scripts Execution Timing.

peavine wrote:

Nigel--thanks for the script. I tested it with various code snippets and it works great.

I was curious and ran each script with one repetition with a timed-task of "delay 0.3". The results were:

Peavine's script - 0 milliseconds

KniazidisR's script - 0 milliseconds

Nigel's script - 302 milliseconds

This is not a usable test of anything but appears to demonstrate the decimal seconds returned when using NSDate.


The whole point of my hocus-pocus trick is the multiplicity of repetitions. If I meant 1 repetition, then the repetitions variable would not exist. As my article would not exist at all.

For myself, I decided to use the version with NSDate (by Nigel Garvey). I also consider this version the most optimal from all solutions, provided here. Of course, I will use a minimum of 2 repetitions.

And, Peavine, you forget say 1 thank to author of idea. This is not good. smile

Last edited by KniazidisR (2019-09-23 09:33:18 pm)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#8 2019-09-23 09:53:11 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

KniazidisR wrote:


The whole point of my hocus-pocus trick is the multiplicity of repetitions. If I meant 1 repetition, then the repetitions variable would not exist. As my article would not exist at all.


KniazidisR. I clearly stated my intent in running only one repetition of the three scripts:

This is not a usable test of anything but appears to demonstrate the decimal seconds returned when using NSDate.


It was not my intent to criticize your script, and I'm sorry if it appeared that way.


2018 Mac mini - macOS Catalina

Offline

 

#9 2019-09-23 11:20:30 pm

KniazidisR
Member
Registered: 2019-03-03
Posts: 1260

Re: Advanced Scripts Execution Timing.

Now, I will search for fastest way to get base name of file. (in microseconds).
To get such results, I will use -1000000 multiplier. I will use 100 repetitions and will run test 5 times x 100 repetitions.

The file on my disk is this:

Applescript:

set theFile to "/Users/123/Library/Scripts/Get the Selection in app.scpt"

The 1st way will be the text item delimiters way:

Applescript:

set TID to text item delimiters
   set text item delimiters to {"/"}
   set n to last text item of theFile
   set text item delimiters to TID
--> 8,9,9,10,9 --> about 9 microseconds

The 2nd way will be the do shell script way:

Applescript:

set n to do shell script "basename " & quoted form of theFile
--> 21992, 20921, 22719, 22846, 25280 --> about 23000 microseconds

The 3rd way will be the System Events way:

Applescript:

tell application "System Events" to set n to name of disk item theFile
--> 7749, 7798, 7806, 8404, 8136 --> about 8000 microseconds

Next will be the info for way:

Applescript:

set n to name of (info for (POSIX file theFile as alias))
--> 6130, 4558, 4259, 2498, 2500 --> about 4000 microseconds

And last but not least the ASObjC way:

Applescript:

set theURL to current application's |NSURL|'s fileURLWithPath:theFile
   set n to theURL's lastPathComponent() as text
--> 209, 194, 183, 200, 219 --> about 200 microseconds

Note: when I put 1st line of this code offside the repeat loop, 2nd  line code still takes 90 microseconds.

All these tests was performed with Nigel Garvey's timing wrapper smile

Last edited by KniazidisR (2019-09-24 12:16:31 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#10 2019-09-24 12:28:52 am

KniazidisR
Member
Registered: 2019-03-03
Posts: 1260

Re: Advanced Scripts Execution Timing.

Now, I will try the same tests with CACurrentMediaTime, proposed by Shane Stanley. (in nanoseconds)

Applescript:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theFile to "/Users/123/Library/Scripts/Get the Selection in app.scpt"
set repetitions to 100

set theStart to current application's CACurrentMediaTime()
repeat repetitions times
   
   set TID to text item delimiters
   set text item delimiters to {"/"}
   set n to last text item of theFile
   set text item delimiters to TID
   
end repeat
set timeTaken to 1000000 * ((current application's CACurrentMediaTime()) - theStart) as integer
--> about 950 nanoseconds (0,95 microseconds)

Applescript:

set n to do shell script "basename " & quoted form of theFile
--> about 1982328 nanoseconds (1982 microseconds)

Applescript:

tell application "System Events" to set n to name of disk item theFile
--> about 735700 nanoseconds (736 microseconds)

Wow! I will not continue. So everything is already clear. The method proposed by Shane Stanley is better since the last timing code line itself consume very little time.

Thank you all for your contribution in this thread. smile

Last edited by KniazidisR (2019-09-24 11:22:25 am)


Model: MacBook Pro
OS X: Catalina 10.15.4
Web Browser: Safari 13.1
Ram: 4 GB

Offline

 

#11 2019-10-01 12:26:33 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

Shane Stanley wrote:

You should keep in mind that editors add a certain amount of overhead via instrumentation callbacks, especially when the codes involve sending events. This can distort results significantly. You'll get a more accurate result if you use my Script Geek.app, which skips any callbacks, but ultimately an applet is the best host (assuming your ultimate destination is an applet).


Shane. I starting using Script Geek and like it a lot. I especially like the convenience of having it running to the side when I'm writing/optimizing a script in Script Editor. Thanks.


2018 Mac mini - macOS Catalina

Offline

 

#12 2019-10-03 09:18:41 am

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 335

Re: Advanced Scripts Execution Timing.

Shane Stanley wrote:

The most accurate clock on the system is a low-level kernel function, mach_absolute_time(), which is precise to the nanosecond — but it is not accessible to ASObjC. However, there's another function, CACurrentMediaTime(), which is based on it and converts the result to seconds.

One caveat with CACurrentMediaTime() that was pointed out in a post a few years ago is that it stops timing when the computer goes into stand-by mode. Although this scenario is unlikely in real-world testing, it is for this reason that I have gotten in the habit of timing scripts with CFAbsoluteTimeGetCurrent(), which differs from CACurrentMediaTime() in execution speed and accuracy by only a small handful of nanoseconds.

Last edited by bmose (2019-10-03 09:19:25 am)

Offline

 

#13 2019-10-03 05:35:33 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

Not only is it unlikely, but in the context we're talking about here, if it did happen, having the timer also stop would be a huge plus in terms of accuracy. But I think there's more chance of the operator going to sleep running these sorts of tests than the computer going to sleep.

(And if your computer does a clock resync while a test is running, the difference can be quite a bit more than a handful of nanoseconds.)


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#14 2019-10-03 08:29:49 pm

bmose
Member
From:: Massachusetts
Registered: 2006-01-03
Posts: 335

Re: Advanced Scripts Execution Timing.

Shane, while neither of the scenarios you mention is likely to happen in real-world testing, your points are well taken and have convinced me to go with CACurrentMediaTime().

Offline

 

#15 2019-10-03 11:45:50 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

FWIW, Script Geek uses mach_absolute_time(), and runs the scripts using an NSActivityOption of NSActivityLatencyCritical ("the activity requires the highest amount of timer and I/O precision available"). That probably makes its times a bit on the optimistic side.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#16 2020-07-23 02:51:22 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

I normally use Script Geek to run timing tests but I occasionally need to exclude sections of a script from the timing results. With Shane's help (see his posts below), I settled on the following revised script for this purpose:

Applescript:

use framework "Foundation"
use scripting additions

on main()
   
   -- decimal places in timing result
   set decimalPlaces to 3 -- works with 1 thru 5
   
   -- untimed code
   display dialog "Continue with timing test?" -- just an example
   
   -- start time
   set startTime to current application's CFAbsoluteTimeGetCurrent()
   
   -- timed code
   delay 0.33 -- just an example
   
   -- elapsed time
   set elapsedTime to (current application's CFAbsoluteTimeGetCurrent()) - startTime
   set nf to current application's NSNumberFormatter's new()
   nf's setFormat:("0." & (text 1 thru decimalPlaces of "00000"))
   set elapsedTime to ((nf's stringFromNumber:elapsedTime) as text) & " seconds"
   
   -- result
   elapsedTime
   
end main

main()

It should be noted that this script does not work reliably with HFS file specifiers and the solution is to build file references using coercions. This is explained at:

https://latenightsw.com/adding-applescr … g-scripts/

Last edited by peavine (2020-07-30 09:28:18 am)


2018 Mac mini - macOS Catalina

Offline

 

#17 2020-07-23 06:30:21 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

It's probably easier to use a number formatter:

Applescript:

use framework "Foundation"
use scripting additions

-- untimed code

set theStart to current application's CACurrentMediaTime()

-- timed code
delay 0.33 -- just an example

set timeTaken to (current application's CACurrentMediaTime()) - theStart
set nf to current application's NSNumberFormatter's new()
nf's setFormat:"0.0000"
return ((nf's stringFromNumber:timeTaken) as text) & " seconds"

Last edited by Shane Stanley (2020-07-25 06:03:08 pm)


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#18 2020-07-23 07:03:57 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

Thanks Shane. I tested both of our scripts and, as expected, the returned results were essentially identical. Your suggestion is simplest and is the one I'll use.

Last edited by peavine (2020-07-24 07:44:47 am)


2018 Mac mini - macOS Catalina

Offline

 

#19 2020-07-25 10:48:32 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

Shane (or another forum member). Your suggestion works great but it occasionally returns a number to 1 or 2 decimal places, and I would prefer that trailing 0's be shown. I can do this with basic AS but I wondered if this is possible with ASObjC.

BTW, I modified your script to return (log actually) the timing results to 3 decimal places. So, just  by way of example "0.2 seconds" would become "0.200 seconds" Thanks.


2018 Mac mini - macOS Catalina

Offline

 

#20 2020-07-25 06:03:50 pm

Shane Stanley
Member
From:: Australia
Registered: 2002-12-07
Posts: 6434

Re: Advanced Scripts Execution Timing.

I've changed the format string above to what it should have been.


Shane Stanley <sstanley@myriad-com.com.au>
www.macosxautomation.com/applescript/apps/
latenightsw.com

Offline

 

#21 2020-07-25 06:12:08 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 567

Re: Advanced Scripts Execution Timing.

Thanks Shane. That works great.


2018 Mac mini - macOS Catalina

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)