From a7e381a31ec583b8ba3305b30cf3a0db0bb4c590 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sat, 8 Mar 2014 03:55:48 -0500 Subject: [PATCH] Mixing method invocation performance tests As expected, mixin method invocation is dramatically slower than conventional class method definitions. However, it is a bit slower than I had anticipated; future releases will definately need to take a look at improving performance, which should happen anyway, since the trait implementation takes the easy way out in a number of instances. Let's get an initial release first. --- test/perf/perf-trait-invoke-method.js | 170 ++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test/perf/perf-trait-invoke-method.js diff --git a/test/perf/perf-trait-invoke-method.js b/test/perf/perf-trait-invoke-method.js new file mode 100644 index 0000000..948a3a0 --- /dev/null +++ b/test/perf/perf-trait-invoke-method.js @@ -0,0 +1,170 @@ +/** + * Tests amount of time taken to apply trait (mixin) methods + * + * Copyright (C) 2014 Mike Gerwitz + * + * This file is part of GNU ease.js. + * + * ease.js is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Contrast with respective class tests. + * + * Note that there is a lot of code duplication; this is to reduce + * unnecessary lookups for function invocation to gain a more accurate + * estimate of invocation time (e.g., no foo[ bar ]()). + * + * Traits are expected to be considerably slower than conventional classes + * due to their very nature---dynamically bound methods. This should not be + * alarming under most circumstances, as the method invocation is still + * likely much faster than any serious logic contained within the method; + * however, performance issues could manifest when recursing heavily, so be + * cognisant of such. + * + * There is, at least at the time of writing this message, much room for + * optimization in the trait implementation. + */ + +var common = require( __dirname + '/common.js' ), + Trait = common.require( 'Trait' ), + Class = common.require( 'class' ), + Interface = common.require( 'interface' ), + + // misc. var used to ensure that v8 does not optimize away empty + // functions + x = 0, + + // method invocation is pretty speedy, so we need a lot of iterations + count = 500000 +; + +// objects should be pre-created; we don't care about the time taken to +// instantiate them +var T = Trait( +{ + 'public pub': function() { x++ }, + 'protected prot': function() { x++ }, + + 'virtual public vpub': function() { x++ }, + 'virtual public vprot': function() { x++ }, + + 'virtual public vopub': function() { x++ }, + 'virtual public voprot': function() { x++ }, +} ); + +var I = Interface( +{ + 'public aopub': [], + 'public vaopub': [], +} ); + +var Ta = Trait.implement( I ).extend( +{ + // TODO: protected once we support extending classes + 'abstract public override aopub': function() { x++ }, + 'virtual abstract public override vaopub': function() { x++ }, +} ); + +var o = Class.use( T ).extend( +{ + // overrides T mixin + 'override public vopub': function() { x++ }, + 'override public voprot': function() { x++ }, + + // overridden by Ta mixin + 'virtual public aopub': function() { x++ }, + 'virtual public vaopub': function() { x++ }, + + + 'public internalTest': function() + { + var _self = this; + + common.test( function() + { + var i = count; + while ( i-- ) _self.pub(); + }, count, "Invoke public mixin method internally" ); + + + common.test( function() + { + var i = count; + while ( i-- ) _self.prot(); + }, count, "Invoke protected mixin method internally" ); + + vtest( this, "internally" ); + }, +} ).use( Ta )(); + + +common.test( function() +{ + var i = count; + while ( i-- ) + { + o.pub(); + } +}, count, "Invoke public mixin method externally" ); + + +// run applicable external virtual tests +vtest( o, "externally" ); + + +function vtest( context, s ) +{ + common.test( function() + { + var i = count; + while ( i-- ) context.vpub(); + }, count, "Invoke public virtual mixin method " + s ); + + common.test( function() + { + var i = count; + while ( i-- ) context.vopub(); + }, count, "Invoke public overridden virtual mixin method " + s ); + + common.test( function() + { + var i = count; + while ( i-- ) context.aopub(); + }, count, "Invoke public abstract override mixin method " + s ); + + common.test( function() + { + var i = count; + while ( i-- ) context.vaopub(); + }, count, "Invoke public virtual abstract override mixin method " + s ); + + + if ( !( context.vprot ) ) return; + + + common.test( function() + { + var i = count; + while ( i-- ) context.vprot(); + }, count, "Invoke protected virtual mixin method " + s ); + + common.test( function() + { + var i = count; + while ( i-- ) context.voprot(); + }, count, "Invoke protected overridden virtual mixin method " + s ); +} + + +// run tests internally +o.internalTest();