Swift Script - JIT? Or precompiled and cached?

A question which is also a feature request.

I'm not familiar with how KM is invoking Swift scripts but I'm curious if it can compile them into binary and cache it so that macro execution performance can be increased?

@peternlewis will have to confirm this since I don't use Swift, but the KM Execute a Swift Script action would seem to indicate "yes", since it can execute a Swift File:

image

This does work for AppleScript files (using a compiled script file).

The best way, of course, is for your to test it yourself using both text as the script, and a compiled file as the script.

I am thinking more in the case of a text script, where Keyboard Maestro could have greater potential to cache a compiled binary.

You can compile your Swift script into a binary tool, and then use the Execute a Shell Script action to execute it.

I have no idea if that will be any faster tho, it would depend on the script.

1 Like

Just tried this and it's much, much faster execution - almost instantaneous. Which is what I'd expect, naturally.

Not as elegant or transportable a solution as I'd hope for though, as it means the macro now has external dependencies. (I sync macros across machines via Dropbox, which means I need to copy and install the compiled binary tools to all the machines and ensure they're kept up-to-date manually if the script code ever needs revising.)

I still believe it's possible for KM to manage this completely under the hood and transparently to the user. Ostensibly, KM could compile a swift text script to binary executable (via swiftc) and cache the resulting binary locally in some system folder managed by KM. KM would only need to recompile the binary in future when changes are made to the text script. Then all calls to that Swift Script macro action will just invoke the pre-compiled binary off disk instead of asking the Swift toolchain to run the raw text script upon each and every macro invocation.

The only reason I suggest this is that it can (and does) produce a massive improvement in performance. The Swift script macro action took between 4-6 seconds to process a fairly simple Swift script on first invocation, then 3-4 seconds on each subsequent invocation. Whereas, compiling it to a binary tool and running it through a Shell Script action, the execution was <1 second, or near instantaneous.

As a matter of interest, how does one compile a Swift program for use in this way? Do I really need to use Xcode?

(I might well do this; It’d be a good excuse to learn Swift.)

Swift scripts can be run and optionally compiled via the Terminal. swift is the command to run text script files, and swiftc is the command to compile an executable version.

The first time you ask KM to run a Swift script, macOS will prompt you to install the Swift packages if they are not already installed. (KM does not bundle any Swift runtime, it uses the swift command that gets installed). At the same time, swiftc will be installed because it is part of the core Swift package. Xcode is not necessary to run or compile scripts.

1 Like

Have you tried creating a Swift compiled file outside of KM, and then calling that file using the "Execute script file" option? That is how I run most of my Execute AppleScript Actions.

1 Like

Already did that, said it was faster in the same post. Was in reply to Peter suggesting that exact same thing.

My point is, I think it's possible for KM to manage compiling scripts into binaries and caching the binaries. There's many benefits to this, not the least of which is convenience, as well as simplifying syncing macros across computers.

1 Like

Sorry I missed that.
Was running the compiled script file from KM as fast as running it from Terminal?

I get your point and the benefits. It is a similar situation to using AppleScript compiled files, and so far we have been unable to convince Peter to use a faster, more effective method to execute AppleScript compiled files.

No worries - yes, virtually the same. Near instantaneous execution.

I believe this concept I am theorizing is fully possible, just a question of how much time Peter wants to put into improving the Swift module in KM. In the meantime I can get around it with some creative workarounds.

There's a lot that can be done with scripting in general when using KM as a middeman for parsing data (ie: read clipboard, run a complex custom parser which Swift is very well suited for, then output contents to a window or paste). Or just for making complex decisions in KM where AppleScript can be cumbersome and slow.

I'm honestly fairly excited at the possibilities of Swift in KM but I'm a little less likely to jump into adding it to a script if I know I have to deal with the manual overhead of compiling, syncing across Macs, etc. as I outlined a few replies up.

I agree that it would be great if Peter provided enhanced scripting support.

In the meantime, here is what I have done to address the issues you have raised:

  1. Store all of my compiled script files in a specific KM folder, which is in my DropBox folder.
  2. Create a KM Global Variable which defines the path for this folder:
    DND__KM_Scripts_Folder
  3. Use this KM Variable in all of my "Execute AppleScript" Actions (and other script actions as well), so that I only have to provide the name of the script file:
    image

I also use Dropbox to sync my KM Macros. So all of my Macros and scripts are sync'd seamlessly.

HTH.

Funny, I was already doing the same thing. My solution is slightly different: I made a symlink of my Dropbox "bin" folder (which has compiled Swift binary versions of my scripts) into the system disk's root as a folder called /syncbin/. That way all my KM Shell Script actions that utilize my compiled Swift scripts can perpetually use it as a static path even if the Dropbox folder changes locations across various Macs.

I also wrote a bash script that could be run once, just to chmod all the compiled binaries to make them executable on all the Macs. Dropbox does not sync permissions.

There are significant behaviour differences (most obviously with properties) between a compiled script and a text script. Caching compiled AppleScripts, especially if the cache was cleaned periodically, would result in unpredictable behaviour.

I do not believe Swift would not have the same issue.

It would probably not be all that difficult to write your own cache/compiling script. Might happen sooner than me implementing it anyway. Probably you could write your code something like:

  • Set variable Instance Swift Script to (swift code)
  • Execute macro Compile Swift with parameter (your script name)
  • Execute Shell Script ~/Documents/KMScripts/(your script name)

And the Compile Swift macro could be something like:

  • if text condition %Dictionary[Swift,%TriggerValue%]% is not %Variable%Instance Swift Script%
    • Write File ~/Documents/KMScripts/%TriggerValue%.swift with %Variable%Instance Swift Script%
    • Compile ~/Documents/KMScripts/%TriggerValue%.swift to ~/Documents/KMScripts/%TriggerValue%
    • Set Dictionary Swift,%TriggerValue% to %Variable%Instance Swift Script%

Something like that anyway.

1 Like

14 posts were split to a new topic: Request: Improve Performance of Executing AppleScript Compiled Files