How to maximize script performance?

  • 2
  • Question
  • Updated 1 month ago
  • (Edited)
I have script which will create cca 500 layers

I would like to speed up this task as much as possible.
My question is... if I change some settings, can script run faster?

My ideas:
1) minimize app to taskbar
2) hide panels
3) set canvas size to 1x1 px
4) turn off layers thumbnails
5) hide navigator panel
6) some cache tiles changes
7) freezing history states - merging many history states into one

Anything else?
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes

Posted 2 years ago

  • 2
Photo of Max Johnson

Max Johnson, Champion

  • 450 Posts
  • 208 Reply Likes
It would be really amazing if there were some support to suspend the GUI entirely during an operation, similar to how you can suspend History states.

I haven't tried optimizing speed other than using AM commands as much as possible in lieu of the JS apis.

Please post back any of your findings!
Photo of Max Johnson

Max Johnson, Champion

  • 450 Posts
  • 208 Reply Likes
Have you tried exponential duplication? Create 5 layers, select all, duplicate, select all, duplicate, etc. It might update the layers and GUI faster, since it is sort of grouping the layer generation into batches.
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
Photoshop somehow freezes UI while performing scripts. But I am not sure how he is deciding about it. There is some code which can force redraw PS UI. 

var eventWait = charIDToTypeID("Wait")        
var enumRedrawComplete = charIDToTypeID("RdCm")
        var typeState = charIDToTypeID("Stte")
        var keyState = charIDToTypeID("Stte")
        var desc = new ActionDescriptor()
        desc.putEnumerated(keyState, typeState, enumRedrawComplete)
        executeAction(eventWait, desc, DialogModes.NO)
I was forced use this when I tried open smart object linked in Cloud. Because it was asynchronous.

I am not sure if there is "freezing" code.

I tried some experiments and seems that Photoshop is 2x faster when I minimize window. But this is only suspicion.
Photo of Naoki Hada

Naoki Hada

  • 3 Posts
  • 0 Reply Likes
For 7) freezing history states - merging many history states into one,
there's suspendHistory().
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 772 Posts
  • 161 Reply Likes
I know, I am using it. But question is. Does this improve performance? In theory, you don't need store/change so much data in RAM or scratch disk so freezing history should help. And you also don't need redraw GUI for history panel so fast ect.
Photo of Naoki Hada

Naoki Hada

  • 3 Posts
  • 0 Reply Likes
I think it's vary in situations. There is $.hiresTimer to measure execution time by micro second.
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
Next Idea is... if charID is faster than stringID... it's shorter and there should be less charIDs
Photo of Max Johnson

Max Johnson, Champion

  • 450 Posts
  • 208 Reply Likes
I finally did an actual test on that... turns out it's somewhere between 105-150% faster to use CID, but *mostly* falls into the 110-115% faster 



#target photoshop

var test, timeSID, timeCID = 0;
$.writeln('\n[[---- LETS DO THIS ----]]');

test = $.hiresTimer;//reset timer
for(i=0; i<1000;i++)
{
    test = app.charIDToTypeID( "null" );
}
timeCID = $.hiresTimer;// reset timer

for(i=0; i<1000;i++)
{
    test = app.stringIDToTypeID( "null" );
}
timeSID = $.hiresTimer;// reset timer

$.writeln('CID: '+timeCID + ' msec');
$.writeln('SID: '+timeSID + ' msec');
$.writeln('charIDToTypeID is ' + Math.floor((timeSID/timeCID)*100)+'% faster\n')
"\n------------------------------------------"
Photo of Max Johnson

Max Johnson, Champion

  • 450 Posts
  • 208 Reply Likes
Gives us:
"[[---- LETS DO THIS ----]]
CID: 905 msec
SID: 1008 msec
charIDToTypeID is 111% faster

Result: 
------------------------------------------"
(Edited)
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
Some notes
1) charID is static because number it is calculated from characters. So you can use just magic numbers instead (with comment what number means) :-D This should be fastest. But it makes sense only if there is a lot iterations.
2) stringIDToTypeID is faster with "app." prefix. I don't know why.
3) stringID without charID equivalent is dynamic and it's assigned once it is used. Which means something about 3600 stringID (without charID equivalent) are assigned during Photoshop start. Next are assigned on the fly.
4) if you want measure time in "ms" you need to divide time with 1000. HiresTimer works with "μs" So for more accurate results is better to use 10 000 000 iterations.
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
I noticed that you can set "preventAbort" flag to main action descriptor. In case of layers selecting it runs 2× faster. Can anyone do some more tests?

Example.
Note: you need to have 200+ layers in document.
for (var i = 1; i < 200; i++){
	var idslct = charIDToTypeID( "slct" );
	var desc217 = new ActionDescriptor();
	var idnull = charIDToTypeID( "null" );
		var ref51 = new ActionReference();
		var idLyr = charIDToTypeID( "Lyr " );
		ref51.putIndex( idLyr, i );
	desc217.putReference( idnull, ref51 );
	var idMkVs = charIDToTypeID( "MkVs" );
	desc217.putBoolean( idMkVs, false );
	desc217.putBoolean(stringIDToTypeID("preventAbort"),true); //2× faster with this
		
	executeAction( idslct, desc217, DialogModes.NO );
}
Photo of r-bin

r-bin

  • 28 Posts
  • 4 Reply Likes
Interesting observation.
It's a pity that does not work in CS6. I checked with CC2018.
Of course, there is a speed increase, but not twice.
In the hot pursuit I found another key, which, along with the specified one, gives another performance gain.

desc217.putBoolean(stringIDToTypeID("suppressLowPriorityEvents"),true);
(Edited)
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
On my PC it was twice, but it may differ a lot. I know about this flag, but I didn't measured better performance. Or how much faster it works for you? I don't know how excactly this flag should work. For completness there are universal flags:

desc.putBoolean(stringIDToTypeID("useStrictDispatch"),true);
desc.putBoolean(stringIDToTypeID("forceNotify"),true);
desc.putBoolean(stringIDToTypeID("preventAbort"),true); 
desc.putBoolean(stringIDToTypeID("suppressForcedMenuRebuild"),true);
desc.putBoolean(stringIDToTypeID("suppressLowPriorityEvents"),true);
desc.putBoolean(stringIDToTypeID('forceRecording'), true); // if you are recording action in action panel then your executeAction will be recorded.
Photo of r-bin

r-bin

  • 28 Posts
  • 4 Reply Likes
On my old home computer and on the CC2018 x32 win7 x32
In the file 1920x1080 with 271 duplicate layers, the panels are visible, the info panel is visible.

Results of the script

No keys.
When the mouse inside the document 8.11 sec
When the mouse is outside the document 6.8 sec

With your key
5.96 with mouse in
4.94 with mouse out

With my key
6.60 with mouse in
5.41 with mouse out

With both keys
4.74 with mouse in
3.85 with mouse out

With the panels turned off

Without keys 5.10
With your key 4.69
With my key 3.64
With both 3.63
Photo of Kukurykus

Kukurykus

  • 301 Posts
  • 46 Reply Likes
Now the question is how to move by script mouse cursor outside of document? ;)
Photo of Jaroslav Bereza

Jaroslav Bereza

  • 779 Posts
  • 166 Reply Likes
So I have proof that DOM layer browsing is not effective.
I have document with ~ 1200 layers (452 layers and 372 groups which have start and end layer so it counts as two)

With command: var lyr = app.activeDocument.layerSets[0];
It runs 3x get descriptor command for each layer + some additional commands.
It gets: layerSectionType, name, layerID
It means 3600 get descriptor commands + few extra.

And with var lyr = app.activeDocument.layerSets[0].layerSets[0] it means 7200 commands + few extra commands in addition to extra commands. So nesting inside layersets might be very costly.

It makes tree structure from linear structure and everytime it check every layer in document.

With AM code you can traverse all layers only once.
Photo of Kukurykus

Kukurykus

  • 301 Posts
  • 46 Reply Likes
It's similary much slower using DOM instead of AM for textItems and pathsItems.