Skip to content

Commit

Permalink
speeding up isSubtypeOf ( by memoization) , ensure a 10 fold performa…
Browse files Browse the repository at this point in the history
…nce improvement
  • Loading branch information
erossignon committed Sep 3, 2014
1 parent 8dd7ed9 commit d5f3394
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 2 deletions.
31 changes: 29 additions & 2 deletions lib/address_space/referenceType.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function _filterSubType(reference) {
* @param baseType {ReferenceType}
* @return {Boolean} true if self is a Subtype of baseType
*/
ReferenceType.prototype.isSubtypeOf = function(baseType) {
ReferenceType.prototype._slow_isSubtypeOf = function(baseType) {

var referenceType = this;
assert(referenceType instanceof ReferenceType);
Expand All @@ -89,14 +89,41 @@ ReferenceType.prototype.isSubtypeOf = function(baseType) {
if ( subType.nodeId === baseType.nodeId ) {
return true;
} else {
if (subType.isSubtypeOf(baseType)) {
if (subType._slow_isSubtypeOf(baseType)) {
return true;
}
}
}
return false;
};

// http://jsperf.com/underscore-js-memoize-refactor-test
// http://addyosmani.com/blog/faster-javascript-memoization/

function wrap_memoize(func, hasher) {

hasher = hasher || function(p) { return p.toString(); };

return function memoize(param) {

if (!this.__cache) {
this.__cache = {};
}
var hash = hasher.call(this,param);
var cache_value = this.__cache[hash];
if (cache_value === undefined ) {
cache_value = func.call(this,param); //custom function
this.__cache[hash] = cache_value;
}
return cache_value;
}
}

function hasher_func(e) { return e.nodeId.value; }
ReferenceType.prototype.isSubtypeOf = wrap_memoize(ReferenceType.prototype._slow_isSubtypeOf,hasher_func);



ReferenceType.prototype.toString = function()
{
var str = "";
Expand Down
87 changes: 87 additions & 0 deletions test/address_space/test_referencetype.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,90 @@ describe("testing ReferenceType",function(){
});

});


describe(" improving performance of isSubtypeOf",function() {
var NodeClass = require("../../lib/datamodel/nodeclass").NodeClass;
// References i=31
// +->(hasSubtype) NoHierarchicalReferences
// +->(hasSubtype) HasTypeDefinition
// +->(hasSubtype) HierarchicalReferences
// +->(hasSubtype) HasChild/ChildOf
// +->(hasSubtype) Aggregates/AggregatedBy
// +-> HasProperty/PropertyOf
// +-> HasComponent/ComponentOf
// +-> HasHistoricalConfiguration/HistoricalConfigurationOf
// +->(hasSubtype) HasSubtype/HasSupertype
// +->(hasSubtype) Organizes/OrganizedBy
// +->(hasSubtype) HasEventSource/EventSourceOf
var Benchmarker = require("../helpers/benchmarker").Benchmarker;
var bench = new Benchmarker();

var nodeset_filename = __dirname + "/../../lib/server/mini.Node.Set2.xml";
var address_space = new AddressSpace();

var referenceTypeNames = Object.keys(require("../../lib/opcua_node_ids").ReferenceTypeIds);

var referenceTypes = [];
before(function (done) {
generate_address_space(address_space, nodeset_filename, function () {

referenceTypes = referenceTypeNames.map(function (referenceTypeName) {
return address_space.findReferenceType(referenceTypeName);
});
referenceTypes = referenceTypes.filter(function (e) {
return e != undefined;
});

assert(referenceTypes[0].nodeClass === NodeClass.ReferenceType);
done();
});
});


it("should ensure that optimized version of isSubtypeOf produce same result as brute force version",function(done){

referenceTypes.forEach(function(referenceType){
var flags1 = referenceTypes.map(function(refType) { return referenceType.isSubtypeOf(refType); });
var flags2 = referenceTypes.map(function(refType) { return referenceType._slow_isSubtypeOf(refType); });

//xx console.log( referenceType.browseName,flags1.map(function(f){return f ? 1 :0;}).join(" - "));
//xx console.log( referenceType.browseName,flags2.map(function(f){return f ? 1 :0;}).join(" - "));
flags1.should.eql(flags2);

});
done();
});
it("should ensure that optimized version of isSubtypeOf is really faster that brute force version", function(done) {

//xx console.log("referenceTypes",referenceTypes.map(function(e){return e.browseName;}));
bench.add('isSubtypeOf slow', function() {

referenceTypes.forEach(function(referenceType){
var flags = referenceTypes.map(function(refType) { return referenceType._slow_isSubtypeOf(refType); });
});

})
.add('isSubtypeOf fast', function() {

referenceTypes.forEach(function(referenceType){
var flags = referenceTypes.map(function(refType) { return referenceType.isSubtypeOf(refType); });
});
})
.on('cycle', function(message) {
console.log(message);
})
.on('complete', function() {

console.log(' Fastest is ' + this.fastest.name);
console.log(' Speed Up : x', this.speedUp);
this.fastest.name.should.eql("isSubtypeOf fast");

this.speedUp.should.be.greaterThan(10);

done();
})
.run();

});
});

0 comments on commit d5f3394

Please sign in to comment.