"Super" hoisting

Herby Vojčík herby at mailbox.sk
Fri May 13 16:19:56 UTC 2016



Nicolas B. Pierron wrote:
> I do not understand how having local variable should change any GC
> pattern unless you are creating them in the for-loop body.

If I understand correctly, the problem is in not reusing the objects. If 
you do `var x = new X()` in every call of the method, GC should take 
care of every `new X()`. OTOH, they are young object, and young space 
should be this sort-of pool like quick thing.

But if creating them / deleting them is actually taking it's toll, 
having reused one object in this.x can save GC.

That's why I suggested that what is in way wanted here, is in fact 
pooling of X instances (and maybe not necessarily by instance of their 
client). Which can be inlined as well, as it is pretty easy:

   var x = poolOfXs.pop() || new X();

to get an x, and

   poolOfXs.push(x);

to put it back. This may actually save even more GC (as only as much 
instances are created as needed).

But again, I would still like to believe that garbage coilector is best 
pooler (though it needs to reinitialize the object each time, but OP 
told he was getting gc pauses).

> 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
>
>
>


More information about the es-discuss mailing list