cTID and sTID

Discussion of the xtools Toolkit

Moderators: Tom, Kukurykus

xbytor

cTID and sTID

Post by xbytor »

The new revs of cTID and sTID will probably look like this:

Code: Select allfunction _cTID(s) {
  if (!_cTID.cache) _cTID.cache = new Array();
  return _cTID.cache[s] || _cTID.cache[s] = app.charIDToTypeID(s);
};

function _sTID(s) {
  if (!_sTID.cache) _sTID.cache = new Array();
  return _sTID.cache[s] || _sTID.cache[s] = app.stringIDToTypeID(s);
};


I just re-scoped and re-named the caches from SzopeN version. The change makes them readily serialize-able.

-X
xbytor

cTID and sTID

Post by xbytor »

Or, to get really concise:

Code: Select allfunction cTID(s) {
  return cTID[s] || cTID[s] = app.charIDToTypeID(s);
};

function sTID(s) {
  return sTID[s] || sTID[s] = app.stringIDToTypeID(s);
};
SzopeN

cTID and sTID

Post by SzopeN »

xbytor wrote:Or, to get really concise:

Code: Select allfunction cTID(s) {
  return cTID[s] || cTID[s] = app.charIDToTypeID(s);
};

function sTID(s) {
  return sTID[s] || sTID[s] = app.stringIDToTypeID(s);
};
Very nice version
jacobolus

cTID and sTID

Post by jacobolus »

Sorry to dredge up such an old thread, but I'm curious, how slow are the app.charIDToTypeID and app.stringIDToTypeID functions? Do they really become a bottleneck? Seems like creating memoized wrappers might be unnecessary.

Anyway, if you do want to make memoized wrappers, my preferred solution in such cases is to use the underscore JavaScript library.* Then you’d just do:

Code: Select allvar cTID = _.memoize(app.charIDToTypeID)
var sTID = _.memoize(app.stringIDToTypeID)
* http://documentcloud.github.com/underscore/
xbytor

cTID and sTID

Post by xbytor »

Sorry to dredge up such an old thread, but I'm curious, how slow are the app.charIDToTypeID and app.stringIDToTypeID functions? Do they really become a bottleneck?

There's another thread on this site where somebody actually did some performance testing and found that the cTID/sTID versions posted above do actually provide some benefit. Whether or not there are real world situations where this performance gain matters, I don't know. But the implementation does measurably speed things up.
jacobolus

cTID and sTID

Post by jacobolus »

I tried clocking it, and it makes about a 10% difference to call cTID vs. calling app.charIDToTypeID directly. Either one can be called about 500,000 times per second on my laptop.

Unfortunately, you can't just assign the shorter name cTID to app.charIDToTypeID, because the implementation apparently expects to only be called in the context of the app object, and fails if called in another context. So you have to do: Code: Select allvar cTID = function (s) { return app.charIDToTypeID(s) } You can only do 280,000 lookups per second using this code, since calling it involves 2 function invocations rather than one. I would be astonished if there is any context in which it makes a difference, though, since whatever you do with the resulting IDs is going to be orders of magnitude more computationally expensive.

I think you should just skip the memoization; it's a textbook example of premature optimization.

Note: in ECMAScript 5, there's a Function.prototype.bind method which makes this sort of thing a bit easier: you can do justCode: Select allvar cTID = app.charIDToTypeID.bind(app) CS5’s ExtendScript doesn’t yet implement that ECMAScript feature though, so if you want something similar you have to define it yourself, either on the Function prototype or as a standalone function.
xbytor

cTID and sTID

Post by xbytor »

I tried clocking it, and it makes about a 10% difference to call cTID vs. calling app.charIDToTypeID directly. Either one can be called about 500,000 times per second on my laptop.

That sounds about right. I may remove the optimization.

Did you see any significant difference with sTID? I know the implementation of app.stringIDToTypeID is more complex.
jacobolus

cTID and sTID

Post by jacobolus »

I can run `app.stringIDToTypeID("select")` about 300,000 times per second, and I can run your `sTID("select")` about 550,000 times per second. Again, I would be astonished if there is any case in which this sort of difference matters.
SzopeN

cTID and sTID

Post by SzopeN »

Original post --> bb/viewtopic.php?p=12136#p12136

(Photoshop 12.0.3 x64, Windows)
Test 0: times 8778,8702,8643, min. duration: 8643 (sTID w/o caching) =>
Test 1: times 3365,3379,3392, min. duration: 3365 (sTID w/ caching)
Test 2: times 5493,5496,5500, min. duration: 5493 (direct app.stringIDToTypeID call)
Test 3: times 7264,7285,7261, min. duration: 7261 (cTID w/o caching)
Test 4: times 3197,3194,3201, min. duration: 3194 (cTID w/ caching)
Test 5: times 4455,4447,4451, min. duration: 4447 (direct app.charIDToTypeID call)
Code: Select all#target photoshop

var iter = 1000000;
var testCase0 = function() {
    sTID = function(s) { return app.stringIDToTypeID(s); };
    for ( var i=0; i<iter; ++i ) {
       sTID('vectorMask');
       sTID('pathContents');
       sTID('subpathListKey');
       sTID('anchor');
    }
}

var testCase1 = function() {
    sTID = function(s) { return sTID[s] || sTID[s] = app.stringIDToTypeID(s); };
    for ( var i=0; i<iter; ++i ) {
       sTID('vectorMask');
       sTID('pathContents');
       sTID('subpathListKey');
       sTID('anchor');
    }
}

var testCase2 = function() {
    for ( var i=0; i<iter; ++i ) {
       app.stringIDToTypeID('vectorMask');
       app.stringIDToTypeID('pathContents');
       app.stringIDToTypeID('subpathListKey');
       app.stringIDToTypeID('anchor');
    }
}

var testCase3 = function() {
    cTID = function(s) { return app.charIDToTypeID(s); };
    for ( var i=0; i<iter; ++i ) {
       cTID('setd');
       cTID('null');
       cTID('Prpr');
       cTID('Lefx');
    }
}

var testCase4 = function() {
    cTID = function(s) { return cTID[s] || cTID[s] = app.charIDToTypeID(s); };
    for ( var i=0; i<iter; ++i ) {
       cTID('setd');
       cTID('null');
       cTID('Prpr');
       cTID('Lefx');
    }
}

var testCase5 = function() {
    for ( var i=0; i<iter; ++i ) {
       app.charIDToTypeID('setd');
       app.charIDToTypeID('null');
       app.charIDToTypeID('Prpr');
       app.charIDToTypeID('Lefx');
    }
}

var test = [testCase0, testCase1, testCase2, testCase3, testCase4, testCase5]
var repeatCount = 3;
for (var t in test) {
    var shortestTime = +Infinity, timings = [];
    for (var i=0; i<repeatCount; ++i) {
        var start = Date.now();
        test[t]();
        var duration = Date.now()-start;
        timings.push(duration);
        if (duration < shortestTime) shortestTime = duration;
    }
    $.writeln("Test " + t + ": times " + timings + ", min. duration: " + shortestTime);
}
robpat

cTID and sTID

Post by robpat »

xbytor wrote:Or, to get really concise:

Code: Select allfunction cTID(s) {
  return cTID[s] || cTID[s] = app.charIDToTypeID(s);
};

function sTID(s) {
  return sTID[s] || sTID[s] = app.stringIDToTypeID(s);
};

I wonder why this wouldn't prompt any errors.
|| has a higher precedence than =.

Code: Select allreturn cTID[s] || cTID[s] = app.charIDToTypeID(s);
should do something like
Code: Select allreturn (cTID[s] || cTID[s]) = app.charIDToTypeID(s);
and prompt errors, however, Photoshop does
Code: Select allreturn cTID[s] || (cTID[s] = app.charIDToTypeID(s));.