The Inbox: System-cwp.662.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
26 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Re: allObjectsDo: (was Re: [squeak-dev] The Inbox: System-cwp.662.mcz)

Nicolas Cellier

2014/1/13 Eliot Miranda <[hidden email]>
Hi Nicolas,


On Mon, Jan 13, 2014 at 10:20 AM, Nicolas Cellier <[hidden email]> wrote:

2014/1/13 Eliot Miranda <[hidden email]>
Hi David,

On Sun, Jan 12, 2014 at 5:13 PM, David T. Lewis <[hidden email]> wrote:
On Sun, Jan 12, 2014 at 09:53:27PM +0100, Bert Freudenberg wrote:
>
> On 12.01.2014, at 20:42, David T. Lewis <[hidden email]> wrote:
>
> > It is worth noting that allObjectsDo: relies on assumptions about how
> > the objects memory works internally. It requires that #someObject will
> > always answer the object at the lowest address in the object memory, and
> > also that a newly allocated object will always be placed at a higher
> > address location than all other objects. Either of these assumptions is
> > likely to be a problem as new and better object memories and garbage
> > collectors are implemented.
> >
> > Dave
>
> Right (as Eliot's vm-dev post shows).
>
> So IMHO the only sensible semantics of allObjectsDo: is as in "allObjects do:" -
> which might be implemented as a primitive in some VMs soonish. It *should not*
> enumerate objects created after calling the method.
>


On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
>
> The bug is in implementing allObjects in terms of someObject and nextObject
> in the first place.  It's cheap and cheerful but horribly error-prone and
> restrictive.  It's cheap because the collection of objects doesn't have to
> be created, and on the original 16-bit Smalltalk machines that was really
> important.  It's horribly restrictive because it assumes much about the
> implementation.
>
> Before closures a sentinel wasn't even needed because enumerating the block
> didn't create a new object (the block context was reused).  So the code had
> to be rewritten just to support closures.
>
> Spur has a generation scavenger operating in a distinct new space and that
> doesn't jive well with a consistent ordering at all.  So far the system is
> limping along by tenuring all objects on someObject and someInstance (so
> that newSpace is either empty, or doesn't contain any instances of a
> specific class) and having nextObject enumerate only objects in oldSpace.
>
> But I think now we can afford a primitive that answers all the objects
> (remember that average object size means that such a collection will be ~
> 10% of the heap, average object size in Squeak V3 is about 10.6 words).  At
> least that's what Spur will do, along with an allInstancesOf: primitive.
>  And then the become example won't cause any problems at all.  Far more
> reliable.  I suppose there are circumstances when enumerating without a
> container is the only feasible approach, but VisualWorks has got along with
> only an allObjects primitive for a long time now.  I suspect we can too.
>

Implementation attached. Works on interpreter VM, not yet tested on Cog but
it should be ok there also. If no objections or better suggestions I will
commit it to VMMaker tomorrow.

InterpreterPrimitives>>primitiveAllObjects
        "Answer an array of all objects that exist when the primitive is called, excluding those
        that may be garbage collected as a side effect of allocating the result array. Multiple
        references to nil in the last slots of the array are an indication that garbage collection
        occured, such that some of the unreferenced objects that existed at the time of calling
        the primitive no longer exist. Sender is responsible for handling multiple references to
        nil in the result array."

Instead of filling the unused slots with nil or 0, I think you should shorten the object so that it contains each object only once, and contains only the objects.  Cog contains some code for shortening.  See [New]ObjectMemory>>shorten:toIndexableSize:. 

HTH
--
best,
Eliot


Oh, I missed this one. I can't check now, could it cleanly address my hugly trick of modifying the header like explained at
http://smallissimo.blogspot.fr/2013/04/still-hacking-largeintegerplugins-in.html ?

It would on SqueakV3.  On Spur it could be more difficult as there's no support for one-double-word free objects, so one can't free a singe 64-bit pair (objects are rounded up to 64-bits in length).  But perhaps you should inflict this on me to force my hand ;-).  The problem is that a single 64-bit word is big enough for an object header but not for an object header plus an indirection in the first slot, which takes 129 bits, when rounded up to a 64-bit boundary.  So such fragments are only reclaimable if an object next to them is freed.  They can't be compacted because there's no forwarding pointer.  So I expect in Spur I'd just have to disable the code and always create the copy.  However, what *can* be shortened, always, is the last object in eden.  So if the object is newly created it can easily be shortened; all that needs ot happen is the allocation pointer, freeStart, is cut-back.

HTH,
Eliot


It was more for the fun of hacking than for solving a bottleneck: indeed, macro benchmark show that benefit is really tiny.
I think that case of LargeInteger to be shorten will most often be the last created but if it's too complex for such small return, just let a hacker do it ;)



Reply | Threaded
Open this post in threaded view
|

Re: allObjectsDo: (was Re: [squeak-dev] The Inbox: System-cwp.662.mcz)

Igor Stasenko
In reply to this post by Eliot Miranda-2



On 13 January 2014 19:31, Eliot Miranda <[hidden email]> wrote:
 

Oh, I missed this one. I can't check now, could it cleanly address my hugly trick of modifying the header like explained at
http://smallissimo.blogspot.fr/2013/04/still-hacking-largeintegerplugins-in.html ?

It would on SqueakV3.  On Spur it could be more difficult as there's no support for one-double-word free objects, so one can't free a singe 64-bit pair (objects are rounded up to 64-bits in length).  But perhaps you should inflict this on me to force my hand ;-).  The problem is that a single 64-bit word is big enough for an object header but not for an object header plus an indirection in the first slot, which takes 129 bits, when rounded up to a 64-bit boundary.

12*9* bits? :)
 
 So such fragments are only reclaimable if an object next to them is freed.  They can't be compacted because there's no forwarding pointer.  So I expect in Spur I'd just have to disable the code and always create the copy.  However, what *can* be shortened, always, is the last object in eden.  So if the object is newly created it can easily be shortened; all that needs ot happen is the allocation pointer, freeStart, is cut-back.

HTH,
Eliot





--
Best regards,
Igor Stasenko.


Reply | Threaded
Open this post in threaded view
|

Re: allObjectsDo: (was Re: [squeak-dev] The Inbox: System-cwp.662.mcz)

David T. Lewis
In reply to this post by Eliot Miranda-2
On Mon, Jan 13, 2014 at 09:26:31AM -0800, Eliot Miranda wrote:

> Hi David,
>
> On Sun, Jan 12, 2014 at 5:13 PM, David T. Lewis <[hidden email]> wrote:
>
> > On Sun, Jan 12, 2014 at 09:53:27PM +0100, Bert Freudenberg wrote:
> > >
> > > On 12.01.2014, at 20:42, David T. Lewis <[hidden email]> wrote:
> > >
> > > > It is worth noting that allObjectsDo: relies on assumptions about how
> > > > the objects memory works internally. It requires that #someObject will
> > > > always answer the object at the lowest address in the object memory,
> > and
> > > > also that a newly allocated object will always be placed at a higher
> > > > address location than all other objects. Either of these assumptions is
> > > > likely to be a problem as new and better object memories and garbage
> > > > collectors are implemented.
> > > >
> > > > Dave
> > >
> > > Right (as Eliot's vm-dev post shows).
> > >
> > > So IMHO the only sensible semantics of allObjectsDo: is as in
> > "allObjects do:" -
> > > which might be implemented as a primitive in some VMs soonish. It
> > *should not*
> > > enumerate objects created after calling the method.
> > >
> >
> >
> > On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
> > >
> > > The bug is in implementing allObjects in terms of someObject and
> > nextObject
> > > in the first place.  It's cheap and cheerful but horribly error-prone and
> > > restrictive.  It's cheap because the collection of objects doesn't have
> > to
> > > be created, and on the original 16-bit Smalltalk machines that was really
> > > important.  It's horribly restrictive because it assumes much about the
> > > implementation.
> > >
> > > Before closures a sentinel wasn't even needed because enumerating the
> > block
> > > didn't create a new object (the block context was reused).  So the code
> > had
> > > to be rewritten just to support closures.
> > >
> > > Spur has a generation scavenger operating in a distinct new space and
> > that
> > > doesn't jive well with a consistent ordering at all.  So far the system
> > is
> > > limping along by tenuring all objects on someObject and someInstance (so
> > > that newSpace is either empty, or doesn't contain any instances of a
> > > specific class) and having nextObject enumerate only objects in oldSpace.
> > >
> > > But I think now we can afford a primitive that answers all the objects
> > > (remember that average object size means that such a collection will be ~
> > > 10% of the heap, average object size in Squeak V3 is about 10.6 words).
> >  At
> > > least that's what Spur will do, along with an allInstancesOf: primitive.
> > >  And then the become example won't cause any problems at all.  Far more
> > > reliable.  I suppose there are circumstances when enumerating without a
> > > container is the only feasible approach, but VisualWorks has got along
> > with
> > > only an allObjects primitive for a long time now.  I suspect we can too.
> > >
> >
> > Implementation attached. Works on interpreter VM, not yet tested on Cog but
> > it should be ok there also. If no objections or better suggestions I will
> > commit it to VMMaker tomorrow.
> >
> > InterpreterPrimitives>>primitiveAllObjects
> >         "Answer an array of all objects that exist when the primitive is
> > called, excluding those
> >         that may be garbage collected as a side effect of allocating the
> > result array. Multiple
> >         references to nil in the last slots of the array are an indication
> > that garbage collection
> >         occured, such that some of the unreferenced objects that existed
> > at the time of calling
> >         the primitive no longer exist. Sender is responsible for handling
> > multiple references to
> >         nil in the result array."
> >
>
> Instead of filling the unused slots with nil or 0, I think you should
> shorten the object so that it contains each object only once, and contains
> only the objects.  Cog contains some code for shortening.  See
> [New]ObjectMemory>>shorten:toIndexableSize:.
>

That would be a better solution. However, I cannot offer an implementation
in the near term because of:

  shorten: obj toIndexableSize: nSlots
      "Currently this works for pointer objects only, and is almost certainly wrong for 64 bits."

Given that this is currently intended for pointer objects, it is probably
fairly straightforward to get it working on the 64-bit object memory. In fact,
it might already work as written. But I think that it will take some time to
test so it's not going to happen tonight.

We could consider a variation on Bert's suggestion, in which the result array
might have trailing zeros if garbage collection has occurred. Later the primitive
can be improved with shorten:toIndexableSize: after which the trailing zeros
will never occur in practice. That would still put the burden on the image
to ignore the trailing junk, so I don't know if it would be worth doing.

Dave



Reply | Threaded
Open this post in threaded view
|

Re: allObjectsDo:

David T. Lewis
In reply to this post by Bert Freudenberg
On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:

> On 13.01.2014, at 02:13, David T. Lewis <[hidden email]> wrote:
>
> > On Sun, Jan 12, 2014 at 12:01:00PM -0800, Eliot Miranda wrote:
> >>
> >> But I think now we can afford a primitive that answers all the objects
> >> (remember that average object size means that such a collection will be ~
> >> 10% of the heap, average object size in Squeak V3 is about 10.6 words).  At
> >> least that's what Spur will do, along with an allInstancesOf: primitive.
> >> And then the become example won't cause any problems at all.  Far more
> >> reliable.  I suppose there are circumstances when enumerating without a
> >> container is the only feasible approach, but VisualWorks has got along with
> >> only an allObjects primitive for a long time now.  I suspect we can too.
> >>
> >
> > Implementation attached. Works on interpreter VM, not yet tested on Cog but
> > it should be ok there also. If no objections or better suggestions I will
> > commit it to VMMaker tomorrow.
> >
> > InterpreterPrimitives>>primitiveAllObjects
> > "Answer an array of all objects that exist when the primitive is called, excluding those
> > that may be garbage collected as a side effect of allocating the result array. Multiple
> > references to nil in the last slots of the array are an indication that garbage collection
> > occured, such that some of the unreferenced objects that existed at the time of calling
> > the primitive no longer exist. Sender is responsible for handling multiple references to
> > nil in the result array."
> >
> > Dave
> >
> > <InterpreterPrimitives-primitiveAllObjects-dtl.1.cs>
>
> Nice, except that I'd fill the remaining slots with 0 instead of nil. Even
> better: allocate the array as object count + 1 and *always* put a 0 last.
> That way the image code cannot ever "forget" to check for 0.
>
Attached is an implementation of Bert's proposal. There is at least one integer
zero at the end of the result array, or more if the primitive caused a GC.

I sort of like this idea now that I understand the rational for using integer
zero as the fill.

But Eliot is right, it would be better to answer only the objects that still
exist after any possible GC.

Dave
 



InterpreterPrimitives-primitiveAllObjects-dtl.2.cs (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: allObjectsDo:

Bert Freudenberg
On 14.01.2014, at 01:36, David T. Lewis <[hidden email]> wrote:

> On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
>> I'd fill the remaining slots with 0 instead of nil. Even
>> better: allocate the array as object count + 1 and *always* put a 0 last.
>> That way the image code cannot ever "forget" to check for 0.
>>
>
> Attached is an implementation of Bert's proposal. There is at least one integer
> zero at the end of the result array, or more if the primitive caused a GC.
>
> I sort of like this idea now that I understand the rational for using integer
> zero as the fill.
>
> But Eliot is right, it would be better to answer only the objects that still
> exist after any possible GC.
>
> Dave
>
> <InterpreterPrimitives-primitiveAllObjects-dtl.2.cs>
Nice. Now we just need the same for allInstances :)

- Bert -





smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Vm-dev] Re: allObjectsDo:

David T. Lewis
On Tue, Jan 14, 2014 at 02:27:11PM +0100, Bert Freudenberg wrote:

>  
> On 14.01.2014, at 01:36, David T. Lewis <[hidden email]> wrote:
>
> > On Mon, Jan 13, 2014 at 12:28:33PM +0100, Bert Freudenberg wrote:
> >> I'd fill the remaining slots with 0 instead of nil. Even
> >> better: allocate the array as object count + 1 and *always* put a 0 last.
> >> That way the image code cannot ever "forget" to check for 0.
> >>
> >
> > Attached is an implementation of Bert's proposal. There is at least one integer
> > zero at the end of the result array, or more if the primitive caused a GC.
> >
> > I sort of like this idea now that I understand the rational for using integer
> > zero as the fill.
> >
> > But Eliot is right, it would be better to answer only the objects that still
> > exist after any possible GC.
> >
> > Dave
> >
> > <InterpreterPrimitives-primitiveAllObjects-dtl.2.cs>
>
> Nice. Now we just need the same for allInstances :)
>
> - Bert -
>
One more update for primitiveAllObjects to fix a buglet. If garbage collection
occurs during allocation of the result array, then the result array itself was
being included in the result. We want to have self includes: self ==> false for
the result array. This fixes it.

Truncating the array per Eliot's suggestion remains on the to-do list.

Dave




InterpreterPrimitives-primitiveAllObjects-dtl.3.cs (2K) Download Attachment
12