Weird behavoir while using function aliases

Discussion in 'Javascript' started by Daniel Rucareanu, Sep 19, 2006.

  1. I have the following script:

    function Test(){}
    Test.F = function(){}
    Test.F.FF = function(){}
    Test.F.FF.FFF = function(){}
    Test.F.FF.FFF.FFFF = function(){}

    //var alias = function(){};
    var alias = Test.F.FF.FFF.FFFF;

    var date1 = new Date();
    for (var index = 0; index < 100000; index++)
    Test.F.FF.FFF.FFFF();
    //alias();
    var date2 = new Date();
    print(date2.getTime() - date1.getTime());


    Why is it when I use Test.F.FF.FFF.FFFF() I get around 100ms and when I
    get alias() I get around 280ms?
    What is going on here? This is something I would have never anticipated
    and I think that neither of you as well. Aliases whould work faster
    then doing lockups at each iteration, right?
    Also if I uncomment this line: var alias = function(){}, from 280ms I
    get a drop to 265 ms?

    Does anybody now the reason for this? It only happends in Firefox (I
    have 1.5.0.6). IE and Opera behaive as they should
     
    Daniel Rucareanu, Sep 19, 2006
    #1
    1. Advertisements

  2. Daniel Rucareanu wrote:
    Given the relatively low resolution and precision of javascript date
    objects, and the influence of task switching on the processor, I would
    not trust results from measurements of periods as short as this.
    If the effect is real, and particular to Firefox then asking the people
    who wrote the javascript engine for Firefox may help. They:-

    netscape.public.mozilla.jseng

    Richard.
     
    Richard Cornford, Sep 19, 2006
    #2
    1. Advertisements

  3. The precision of js date objects is indeed kind of low, but more the
    enough when measuring durations larger than a few hundred milliseconds.

    Also I don't think that tasks / threading switching have any influence,
    because the result are constant, no matter how may time I run this
    test. I also increased the loop from 100K iterations to 1M and the
    results stay the same: using the alias is a lot slower.
     
    Daniel Rucareanu, Sep 19, 2006
    #3
  4. Daniel Rucareanu

    Matt Kruse Guest

    I get different results than you:
    http://javascripttoolbox.com/temp/func_lookup_speed_test.html

    Using alias for me is always almost twice as fast in Firefox 2 beta 2,
    10%-25% faster in FF 1.5, and 15%-20% faster in IE6.
    Try my url and see if you get the same results.

    In any case, doing a lookup 100,000 times and only taking 100-200ms total
    surely makes these results insignificant.
     
    Matt Kruse, Sep 19, 2006
    #4
  5. Strange enough, I get results close to you. Probably must have
    something to do the fact the functions are passed as parameters... even
    the total executions time, in both situations are smaller. Anyway, this
    complicates thing even more, rather than answering them.
    I have posted this on another forum as well and there people have
    confirmed by results. You might want to try with my test as well, just
    to see what kind of result you get.
    In FF 2, beta 2, using my test, the alias() test runs 3 times more
    slowly that the other test. Also, the fact the 100,000 iterations take
    about 200ms is because the application is extremely simple. Rest assure
    then in more complex applications with a lot of object, heavy dom usage
    etc., the results will be different.

    Thank you,
    Daniel
     
    Daniel Rucareanu, Sep 19, 2006
    #5
  6. Daniel Rucareanu wrote:
    <snip>

    Firefox 1.5.0.6 gives me - alias() - running in about 3/4 of the time
    that - Test.F.FF.FFF.FFFF() - takes, with your code. Your case is not
    demonstrated.

    Richard.
     
    Richard Cornford, Sep 19, 2006
    #6
  7. Daniel Rucareanu

    Matt Kruse Guest

    Same here. Are you sure that your posted code is actually your complete test
    case?
     
    Matt Kruse, Sep 19, 2006
    #7
  8. Yes, the test case is complete. Hoever, for testing I was using an
    online environment that evaluates whatever code you write. It suited me
    fine until now when I needed just a quick way to test something. It
    seems that is has something to do with it. Creating a standalone page
    and running it does creates some more plausible results.
    Strange that this is the first time the environments in giving me
    results other then what a real page would give. If anybody want to run
    the test there and to check the result, the url is:
    http://www.squarefree.com/jsenv/.
    In IE and Opera however, running the test in this environment or
    running the standalone page gives the same results...
    Now I wonder why 2 persons (whom I don't know) confirmed my first
    results... :) What were they using?

    Daniel
     
    Daniel Rucareanu, Sep 19, 2006
    #8
  9. <snip>

    And that online environment branches its execution based upon a - !!
    document.all - test, so no comparison of its results on different
    browsers will be meaningful.

    Richard.
     
    Richard Cornford, Sep 19, 2006
    #9
  10. Daniel Rucareanu

    Matt Kruse Guest

    Ah, so you weren't just testing the speed of your test case, but also the
    speed of any code wrapped around it to make the "environment" function.
    These are important details not to be left out in the original post ;)

    BTW, if you want to do speed tests, take a look at the code in the url I
    posted in a previous message. I wrote the timeIt() function because I was
    tired of manually doing the new Date() thing before and after, and I wanted
    side-by-side comparisons of multiple ways of doing the same task. It's been
    working nicely for me for a while.

    One caveat: When testing long-running functions or many iterations, browsers
    will usually pop up the "code is running slow" messages. Disable these in
    your browser before doing speed tests.
     
    Matt Kruse, Sep 19, 2006
    #10
  11. Daniel Rucareanu

    VK Guest

    Not at all. That may be true for some C-like language with pointers and
    an execution cache (a la processor cache). I do not know for sure of a
    such language but a technical possibility is here. For a Java-like
    language without pointers, byRef aliases only slow down the execution
    as the engine gets one more reference to resolve (alias > ref > ref >
    ref instead of ref > ref > ref). The difference is fractional, so feel
    free to use aliases if it improves the code readability: but do not
    expect any serious performance changes.

    That can be a performance improvement using a byVal intermediary
    variable rather than recalculations, the most known sample is
    var len = something.length;
    for (var i=0; i<len; ++i) {
    //...
    }

    It is also beneficial to use byRef intermediary variable for DOM
    references rather than using getElementById each time. The latter is
    especially true for IE because their getElementById implementation is
    an artificial build-up atop of IE's native schema (with ID'ed elements
    automatically referenced in the Global scope) and about four times
    slower than a ready to use reference (MSDN says sorry for it, but they
    are really not and it doesn't help too much in neither case :)

    For within JavaScript references only (like in your case) that is the
    matter of such fractions that pigs will become flying aces before you
    get some practical impact out of it :)

    What practical is that IE'e schema is much quicklier in resolving
    references, because they do not use ECMAScript standard for Function
    objects. Instead they treat each and every function as expression. The
    result of this expression is function reference added to the Global
    scope, no matter how deep this function is burried inside and by how
    many syntax signs is it surrounded.
    var foo = function bar(){};
    window.alert(typeof bar);
    - as just a starting hint of what am I talking about, not as an
    explanation.

    This speeds up the lookup process, because the engine jumps from one
    ref to another in the same Global scope. It also mean that IE schema is
    rather indifferent to how many levels down to go, as it really stays on
    the same top level.

    It also means that for really speed crutial processes like say visible
    points calculation for 3D SVG/VML graphics it is highly benefitial to
    skip on "correctness of approach" and use only top level functions
    calling each other. IE is indifferent, but FF will "appreciate it".


    P.S.
    The draw back of traditional timerON > many loops > timerOFF tests is
    that any good engine is much more than just "execute a chunk - move to
    next chunk". A good engine (and both FF and IE ones are) has a
    look-ahead and code optimisation mechanics inside. So starting with the
    second loop you are dealing not only with the test subject but also
    with optimization mechanics differences.
    And this is just an icing on the cake where the cake is Date object
    working with the precision no better than one system tick (10ms - 60ms
    depending on OS).
     
    VK, Sep 19, 2006
    #11
  12. Daniel Rucareanu

    Matt Kruse Guest

    Wow, after Richard and I have already identified the root problem (the
    environment used to do the test) and in fact posted results showing that the
    aliased function *does* run faster in both IE and FF, you come out with this
    load of crap? Almost everything you've written is wrong. You have no
    understanding of the lookup process used to resolve the function references.

    Maybe pictures are easier for you to understand:

    Test --> F --> FF --> FFF --> FFFF <-- alias

    Count the arrows.
    What a perfectly cromulant word!
     
    Matt Kruse, Sep 19, 2006
    #12
  13. Daniel Rucareanu

    VK Guest

    ....UA producers have nothing left but urge to bring their engines
    uniformly to the spelled rules. I'm not a big help to expedite the
    process though ;-)
    A nice picture. From what programing language did you get it?
     
    VK, Sep 19, 2006
    #13
  14. Daniel Rucareanu

    Matt Kruse Guest

    From the javascript posted:

    function Test(){}
    Test.F = function(){}
    Test.F.FF = function(){}
    Test.F.FF.FFF = function(){}
    Test.F.FF.FFF.FFFF = function(){}
    var alias = Test.F.FF.FFF.FFFF;

    If you don't see how the "diagram" corresponds exactly to the code above,
    you have more learning to do than I thought.
     
    Matt Kruse, Sep 19, 2006
    #14
  15. Daniel Rucareanu

    scriptguru Guest

    VK напиÑав:
    It is not important in this case that there is no pointers in JS. In
    the first case interpreter will search few times in hashtables (bacause
    in objects of JS properties and methods names are always keys of
    hashtables). In the second case it is not needed to search in hashtable
    because there is no properites or methods. Alias contains direct
    reference to function object.

    Val
     
    scriptguru, Sep 20, 2006
    #15
  16. Generalisations abut implementation details are rarely going to be
    true. It has been shown that JScript appears to uses a list-like
    structure for its javascript objects rather than a hashtable.
    The Identifier for - alias - still needs to be resolved against the
    scope chain, which does involve looking up the properties of objects.
    The alias is quicker because it will take as long to resolve its
    identifier to a function, that can then be called, as it does to
    resolve the - test - identifier, and then the property accessor has to
    look-up another three objects before it gets to the function.

    Richard.
     
    Richard Cornford, Sep 20, 2006
    #16
  17. Daniel Rucareanu

    VK Guest

    <OT>
    There is an all time slogan in this group "JavaScript is not Java". I
    feel it's time to re-introduce the 2nd most popular: "JavaScript is not
    C++" :) The timing seems right, as "memory leaks", "destructors",
    "aliases", "pointers" and stuff is hitting the fan again. (This is why
    many popular libraries are sub-optimal: not because they are imitating
    the "classical" class-based paradigm - let them imitate whatever
    customers want - but because they are written with performance
    considerations taken from a rather *uniformed* and *very different*
    environment).
    </OT>

    You want a performance jump (not random fractions due to run-time
    optimization)? Then follow particular engine's mechanics.

    // C-like thinking (? bad):
    function Test(){}
    Test.F = function(){}
    Test.F.FF = function(){}
    Test.F.FF.FFF = function(){}
    Test.F.FF.FFF.FFFF = function(){}
    var alias = Test.F.FF.FFF.FFFF();
    ....
    for (var j=0; j<100000; ++j) {
    alias();
    }
    ....


    // Script engine thinking (good):
    // double performance improve for FF, IE doesn't care:
    function Test(){
    this.f1 = Test.F;
    this.f1.f2 = Test.FF;
    this.f1.f2.f3 = Test.FFF;
    this.f1.f2.f3.f4 = Test.FFFF;
    }
    Test.F = function(){}
    Test.FF = function(){}
    Test.FFF = function(){}
    Test.FFFF = function(){}
    ....
    for (var j=0; j<100000; ++j) {
    obj.f1.f2.f3.f4();
    }
    ....


    P.S. That is with leaving aside practical needs of a "package member"
    like
    utils.member.doing.something.useful()
    If one needs to build such long chain, she's most definitely doing
    something way too conceptual to be practical. IMO.
     
    VK, Sep 20, 2006
    #17
  18. Daniel Rucareanu

    VK Guest

    that's a typo of course, correct:

    var alias = Test.F.FF.FFF.FFFF;
     
    VK, Sep 21, 2006
    #18
  19. You didn't try running your code, did you? There are many errors in it
    beyond that one, and it doesn't demonstrate anything, or any better
    performance in the second loop.

    Richard.
     
    Richard Cornford, Sep 21, 2006
    #19
  20. Daniel Rucareanu

    VK Guest

    "Alias is more effective then explicit method call" is some kind of
    urban legend to me appealing to one of the most strong mythologems of
    programming: "shorter text === quicker program"; "alias()" is much
    shorter than "f.ff.fff.ffff()", thusly it just has to be more
    effective.
    With such linear interpretation it would be also obvious to expect that
    f() - f.ff.fff.ffff() - f.ff.fff.ffff.f.ff.fff.ffff() - ... have to
    show twice bigger time difference between each pair from left to right.

    In fact the maximum possible performance is very rarely the primary
    target in programming. There are much more important factors:
    stability, easiness of maintenance (including readability), easiness to
    upgrade and to incorporate into other blocks of code. Speed is really
    the last in the list. And with speed itself timed loops is the worst
    tool one can get: because as I said you are really studying run-time
    optimization mechanics of a particular engine, and only after (and if
    lucky) your own question.

    There is a simple and effective alternative to it: the code is quick
    enough if it's quick enough for yourself. That leads to: never program
    on a "best configuration of the year": always use an average-good
    configuration of the *last* year (or even few years old). If say you
    are satisfied with results on 900Mz/128Mb, your customers will be most
    definitely satisfied on 3Gz/1Gb.

    That doesn't eliminate a normal human curiosity: "how is this stuff
    really ticking inside?" It's ticking rather interestingly and
    differently for different script engines. In application to Microsoft
    JScript one can study IDispatch interface (search MSDN for "IDispatch",
    "IDispatch::Invoke", "IDispatch dispid").


    P.S. See
    <http://www.geocities.com/schools_ring/chicken_runs/index.html> What do
    one thinks is being studied here? alias or run-time optimization and
    threads management in different UA's? If one thinks the first, then
    play with setTimeout delay, try runs with different handycaps. Choose
    the "J-horse" you bet for sure by three runs results and tell me when
    ready :)

    P.P.S. As it is build on frames, it can be boring to copy page by page
    (if one wants).
    <http://www.geocities.com/schools_ring/chicken_runs/chicken_runs.zip>
    contains full frameset.
     
    VK, Sep 21, 2006
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.