FastScripts 3 speed issues with ASObjC scripts

Only just catching up on this thread now. I’m sorry to hear the slowdown is affecting multiple people. Please don’t hesitate to get in touch about this kind of thing, even if you’re worried it might be "your own fault’ :slight_smile: If either of you, or anybody else, has any insights about how I might reproduce such a slowdown, that would be a good first step in trying to figure out how to reproduce it. I suspect whatever the difference is between FastScripts 2 vs 3 has to do with 3 launching a whole new process for every script. Maybe there is some once-per-process code that has to run when using ASObjC that slows things down. I’m not sure why I wouldn’t see the same slowdown here in my tests, though.

1 Like

Perhaps a good test for each of you to try would be putting one of these scripts affected by the slowdown in a script application, forcing it to be run in a separate process no matter how it is run. I’d be curious if you see the same slowdown then when running the script even from FastScripts 2 or, for that matter, from anywhere else?

1 Like

Daniel. When I first turn on my computer and run a script that uses ASObjC (regardless of how it’s run), there’s a small but noticeable pause while the frameworks used by the script are loaded into memory. Afterwards, the frameworks are apparently in memory and there is no pause the next time I run the script.

I know nothing about the operation of FastScripts 3, and less about when and how required frameworks are loaded into memory. However, I wondered if the frameworks are freshly loaded into memory every time an ASObjC script is run with FastScripts 3. This would account for the pause and would explain why I never encountered this pause with a script that uses basic AppleScript only. However, this would not explain why you are not experiencing the pause.

Yes, something like that sounds like it could be the cause. But in that case I guess a better question to figure out might be why the loading of the frameworks even causes a noticeable pause.

Daniel. The first time I run the script included below in Script Geek with no repetitions the timing result is 280 milliseconds. The second time I run the script the timing result is less than a millisecond. I encounter this all the time, and I assumed the difference was attributable to the required frameworks being loaded into memory, although I could easily be wrong about that.

This is also beyond my knowledge level, but I wondered if the time it takes to load the scripting bridge into memory might contribute towards the pause I notice. That’s just a guess, though.

use framework "Foundation"

set theString to current application's NSString's stringWithString:"Hello"

I wondered if the frameworks are freshly loaded into memory every time an ASObjC script is run with FastScripts 3.

I’ve particularly noticed this effect when using Dialog Toolkit Plus. Dialogs that appear instantaneously when run in Script Debugger take a noticeable moment in FastScripts. I had (however anecdotally) attributed this to the above cause.

Interesting.
Which version of macOS are you running?
And if you are using FastScripts, is it v2 or v3?

I think this delay is fairly typical for when the OSA Scripting component loads the necessary bridging files for ASObjC; I’d always noticed it with osascript (from the command line), which always starts a new process & has to load the bridging headers each time (unlike Script Debugger, which loads it once & reuses the Scripting Component). I’d always avoided ASObjC where possible because of the poor cold-start times.

Note that the slowdown/bridge loading only happens when a line of code calling/accessing ASObjC is actually used (i.e. a use framework "Foundation" on its own does not cause a slowdown).

Daniel, I’m not sure how FastScripts spawns the separate processes (in advance or on demand), but if the process were to first run an AppleScript similar to the below, that should take care of loading all the ASObjC bridge support prior to actually running a user script.

use framework "Foundation"
use framework "AppKit"
current application's NSString's |string|()
current application's NSWorkspace's sharedWorkspace()
return

(Edited to add AppKit call)

1 Like

Oh, that’s a great idea. In fact the processes are typically spawned in advance, so that they are ready to go when a script is executed. So that could indeed make a significant impact. I’ll work on a beta update and share it here so people can test it out to confirm.

5 Likes

It might also be a good idea to load AppKit as well, since it’s used for a lot of things (not sure how much extra loading time it adds). I’ve updated the scriptlet above.

2 Likes

Good idea to add AppKit, too. I made an experimental version of FastScripts that does this unilaterally at app launch time for each of the script runners, so it should have invoked a script like @tree_frog shared above by the time any user script is allowed to run in it.

https://redsweater.com/fastscripts/FastScripts3.2.3b3.zip

Let me know if anybody gives it a try, whether it makes any difference at all!

Daniel

2 Likes

First impression is that my Dialog Toolkit Plus-based scripts are now working effectively instantaneously (as they do when run from Script Debugger) whereas previously there was a slight delay (maybe 0.5s on my older machine) when run from FastScripts.

In other words, it’s working. Will report back if there are any issues.

2 Likes

Oh, that’s great. Thanks for the feedback @p1r2c1 … if there doesn’t seem to be any negative impact on scripts that DON’T use ASObjC then I’ll probably include this change in the next official update. Otherwise I’ll try to figure out a way to ensure these “pre-primed” versions of the script runners can be opted in to where appropriate.

2 Likes

Daniel. I installed FastScripts version 3.2.3b3, and the pause I had experienced with the release version of FastScripts 3 is entirely gone. So, for me, FastScripts 3 is now every bit as fast as FastScripts 2. Many thanks :slight_smile:

2 Likes

Amazing and wonderful news! Thanks for confirming.

1 Like

Same here.

Scripts that call libraries using AppleScriptObjC no longer trigger error at launch.
Other scripts behaves normally.
So far…


MacOS 12.6 (21G115)
FastScripts 3.2.3b3 (1730)

Testing from the command line (with wrapper shell scripts), the results speak for themselves.

The test AppleScript I’m using is (called Test.scpt):

use framework "Foundation"
use framework "CoreWLAN"

current application's CWInterface's interface()'s ssid() as string

Testing with osascript.sh:

time osascript.sh Test.scpt

real	0m0.261s
user	0m0.181s
sys		0m0.053s

Testing with fastscripts.sh on FastScripts 3.2.3b2:

time fastscripts.sh Test.scpt

real	0m0.375s
user	0m0.022s
sys		0m0.024s

Testing with fastscripts.sh on FastScripts 3.2.3b3:

time fastscripts.sh Test.scpt

real	0m0.163s
user	0m0.018s
sys		0m0.021s

So, about a 200 ms speedup with the new beta (the remaining 163 ms is because of how I call the script, not due to FastScripts), making it effectively instantaneous, and way faster than osascript ever could be.

2 Likes

Thank you so much for going the extra mile to obtain those metrics! I hadn’t ever thought of the possibility of FastScripts as a faster alternative for invoking command line scripts. That’s pretty neat. I guess leveraging the pre-loaded script runner is the big win here. I’ll have to figure out how to promote this better after the update is public :slight_smile:

3 Likes

I wonder if it would be a worthwhile enhancement to consider providing a “fastscripts” command line utility that would essentially behave like “osascript” but with all the execution happening via FS instead.

3 Likes

That would be fantastic. I was planning on writing something similar for myself, but just haven’t gotten around to doing it yet.

I ran the above tests above using the little shell script I shared here, which is fairly slow because the boilerplate AppleScript code used to send the Apple Events to FastScripts is compiled on-the-fly.

On my own machine, I use a modified version of that shell script that runs the boilerplate AppleScript from a compiled .scpt file, which is much faster (but harder to explain on the forum). The benefit of this approach is a good balance of speed vs. complexity, since osascript still handles unpacking the result.

I was planning on tinkering around with writing a proper CLI in Swift for my own use, but it would be a lot more involved than doing the above. That said, an “official” solution would be awesome as everyone would have access & it would be a much more visible feature.