"Super" hoisting

Nicolas B. Pierron nicolas.b.pierron at mozilla.com
Fri May 13 15:47:01 UTC 2016


I do not understand how having local variable should change any GC
pattern unless you are creating them in the for-loop body.
Even though, Scalar Replacement optimizations (which are implemented
in all engine?) should be able to remove these allocations once the
optimizing JIT is reached, unless the "setFromPoint", "rotate", and
"average" functions are not inlined.


On Fri, May 13, 2016 at 3:09 PM, Herby Vojčík <herby at mailbox.sk> wrote:
>
>
> Brian Barnes wrote:
>>
>> It could be, but there is a difference between:
>>
>> var x;
>>
>> and:
>>
>> this.x
>
>
> You should probably do `var x = XPool.get();` and at the end `XPool.put(x);`
> and do `XPool`s for every possible X type which you want to not GC. And then
> happily use local variable, as it should be. If things are not very parallel
> / reentrant, the pools will likely only contains zero / single element.
>
>
>>
>> Because you’ll get leakage from the last run, so it would probably be
>> something that would need to be hinted, unless the engine was smart enough
>> to reset everything it hoisted (which is doable) but not optimal, as you
>> might always know that will be discarded (a really smart engine could
>> probably figure this out.)
>>
>> Again, all this is to try to eliminate GC as much as possible.  It’s not a
>> philosophical argument, GC has pros and cons, it’s just bad for performance
>> sensitive stuff like games.  I do this all by hand now, so a super hoist
>> would just eliminate a lot of hard to read code I’ve written!
>>
>> [>] Brian
>>
>>> On May 13, 2016, at 10:43 AM, Alan Johnson<alan at breakrs.com>  wrote:
>>>
>>> Sounds like a potential JS engine optimization, rather than a language
>>> feature per se.
>>>
>>>
>>>> On May 12, 2016, at 1:53 PM, Brian Barnes<ggadwa at charter.net>  wrote:
>>>>
>>>> Not by my testing, at least.
>>>>
>>>> My original example is a simple one to explain what the procedure is.
>>>> Here’s a more complex example, from my code, from my mesh classes.  This
>>>> function updates the vertices in the mesh based on the position of the bones
>>>> of a skeleton, it gets called every frame for every model mesh that can be
>>>> seen in the scene:
>>>>
>>>>    updateVertexesToPoseAndPosition(view,skeleton,angle,position)
>>>>    {
>>>>        var n,v;
>>>>        var bone,parentBone;
>>>>
>>>>            // move all the vertexes
>>>>
>>>>        var vIdx=0;
>>>>        var nIdx=0;
>>>>
>>>>        for (n=0;n!==this.vertexCount;n++) {
>>>>            v=this.vertexList[n];
>>>>
>>>>                // bone movement
>>>>
>>>>            bone=skeleton.bones[v.boneIdx];
>>>>
>>>>            this.rotVector.setFromPoint(v.vectorFromBone);
>>>>            this.rotVector.rotate(bone.curPoseAngle);
>>>>
>>>>            this.rotVector.x=bone.curPosePosition.x+this.rotVector.x;
>>>>            this.rotVector.y=bone.curPosePosition.y+this.rotVector.y;
>>>>            this.rotVector.z=bone.curPosePosition.z+this.rotVector.z;
>>>>
>>>>            this.rotNormal.setFromPoint(v.normal);
>>>>            this.rotNormal.rotate(bone.curPoseAngle);
>>>>
>>>>                // average in any parent movement
>>>>
>>>>            if (v.parentBoneIdx!==-1) {
>>>>                parentBone=skeleton.bones[v.parentBoneIdx];
>>>>
>>>>
>>>> this.parentRotVector.setFromPoint(v.vectorFromParentBone);
>>>>                this.parentRotVector.rotate(parentBone.curPoseAngle);
>>>>
>>>>
>>>> this.parentRotVector.x=parentBone.curPosePosition.x+this.parentRotVector.x;
>>>>
>>>> this.parentRotVector.y=parentBone.curPosePosition.y+this.parentRotVector.y;
>>>>
>>>> this.parentRotVector.z=parentBone.curPosePosition.z+this.parentRotVector.z;
>>>>
>>>>                this.parentRotNormal.setFromPoint(v.normal);
>>>>                this.parentRotNormal.rotate(parentBone.curPoseAngle);
>>>>
>>>>                this.rotVector.average(this.parentRotVector);
>>>>                this.rotNormal.average(this.parentRotNormal);
>>>>            }
>>>>
>>>>                // whole model movement
>>>>
>>>>            this.rotVector.rotate(angle);
>>>>
>>>>            this.drawVertices[vIdx++]=this.rotVector.x+position.x;
>>>>            this.drawVertices[vIdx++]=this.rotVector.y+position.y;
>>>>            this.drawVertices[vIdx++]=this.rotVector.z+position.z;
>>>>
>>>>            this.rotNormal.rotate(angle);
>>>>
>>>>            this.drawNormals[nIdx++]=this.rotNormal.x;
>>>>            this.drawNormals[nIdx++]=this.rotNormal.y;
>>>>            this.drawNormals[nIdx++]=this.rotNormal.z;
>>>>        }
>>>>
>>>>            // set the buffers
>>>>
>>>>        var gl=view.gl;
>>>>        gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexPosBuffer);
>>>>        gl.bufferData(gl.ARRAY_BUFFER,this.drawVertices,gl.DYNAMIC_DRAW);
>>>>
>>>>        gl.bindBuffer(gl.ARRAY_BUFFER,this.vertexNormalBuffer);
>>>>        gl.bufferData(gl.ARRAY_BUFFER,this.drawNormals,gl.STATIC_DRAW);
>>>>    }
>>>>
>>>> Notice that rotVector, rotNormal, parentRotVector, and parentRotNormal,
>>>> are all “this”, i.e., globals.  They are *only* used in this function, no
>>>> where else in the class.  If I put them as local variables, I get enormous
>>>> GC pauses.  If I don’t, I get none (granted, I have to do this everywhere,
>>>> so it’s just not this function.)
>>>>
>>>> The example I gave existed only to show how it would work; not a real
>>>> example.  Here’s a real example, that shows obvious problems with local
>>>> variables.  Yes, these are objects.
>>>>
>>>> Not that moving the objects would ONLY be something that happened at
>>>> compile time and would be a hint; they wouldn’t be effected in the warm up
>>>> runs.  You’d almost have to say that same hint would force a compile (which
>>>> has it’s own problems.)
>>>>
>>>> [>] Brian
>>>>
>>>>> On May 12, 2016, at 1:33 PM, Allen Wirfs-Brock<allen at wirfs-brock.com>
>>>>> wrote:
>>>>>
>>>>>
>>>>>> On May 12, 2016, at 9:39 AM, Brian Barnes<ggadwa at charter.net>  wrote:
>>>>>>
>>>>>> ...
>>>>>> If I call doSomething a lot of times, I get a lot of objects to be
>>>>>> tracked and GC’d.  Yes, I can rewrite that code to obviously eliminate them,
>>>>>> but pretend there is actually something interesting happening here that
>>>>>> requires those variables.  And engines can be smart enough to mark them and
>>>>>> deal with them with the function ends (I don’t know if this is done.)
>>>>>>
>>>>>> What I’m thinking is some kind of class based hint that would “super”
>>>>>> hoist all local function variables.  It would be sugar but it would
>>>>>> transform it into:
>>>>>>
>>>>>
>>>>>
>>>>> Local variables like a,b,c in your example are probably the least
>>>>> expensive construct in JS. In your example, there are no objects created by
>>>>> doSomething, not state that persists after doSomething  returns, and no GC
>>>>> pressure. Anything you do WRT moving such local state into object properties
>>>>> is going to be more expensive.
>>>>>
>>>>> Allen
>>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss



-- 
Nicolas B. Pierron


More information about the es-discuss mailing list