From: David Bakhash
Subject: using CLOS with compile-time resources
Date: 
Message-ID: <wkemorndln.fsf@mit.edu>
Hi,

I would like to know if the following is possible, and if I'm thinking
about it right.

I have a program which runs well (functionally).  It is written almost
entirely in CLOS.  It produces a lot of garbage.  Now, in the process of
optimizing it, I'd like to make a simple object pool as a resource of
objects which are used a lot.

So, since `allocate-instance' is a generic function, and I'm saying,
WOW, this is really great, I can't seem to figure out how to go about
this.  Here goes.

At compile time, say I want to pre-allocate 100 instances of class
`my-class'.  I figure I can make an adjustable, array with a
fill-pointer, and use that along with vector-push-extend.  Then, I'll
simply define an around method for allocating instances which _really_
just pops one off the stack (pool, array).  I I thought I could do
something like:

;; simplified...
(defmethod allocate-instance :around ((class my-class) &rest args)
  (or (vector-pop *pool*)
      (call-next-method)))

Why isn't this working?  Also, what is the purpose of args?  Arn't those
only used in the `initialize-instance'?

Of course, CLOS won't have the ability to push (via
`vector-push[-extent]') an instance that's about to be GC'd away
generically, but I suppose that I can do that manually.

Lastly, I'd like to know if CLOS has the ability to (and if most
implementations already do) keep old objects around, so that
`make-instance' ends up seeming faster.  In other words, when a class
instance gets GC'd, is it even possible that it _really_ goes into a
resource pool that the programmer doesn't even know about?  I suspect
not, because CLOS and GC are done at 2 very different levels.
Basically, by the time all of the CLOS macros have been expanded, can
the GC'er even know what's going on?

dave

From: Lyman S. Taylor
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <783a4q$cdn@pravda.cc.gatech.edu>
In article <··············@mit.edu>, David Bakhash  <·····@mit.edu> wrote:
>Hi,
>
>I would like to know if the following is possible, and if I'm thinking
>about it right.
>
>I have a program which runs well (functionally).  It is written almost
>entirely in CLOS.  It produces a lot of garbage.  Now, in the process of
>optimizing it, I'd like to make a simple object pool as a resource of
>objects which are used a lot.

   I think you are better off designate you own special constructor
   generic (or function)  for doing this.    The Keene book suggests
   in some cases, writing you own constructors and reserving MAKE-INSTANCE
   for its use.    

   So instead of MAKE-INSTANCE  the new protocol would invoke MAKE-SOME-CLASS
   instead.   This could draw out of a buffer pool or call MAKE-INSTANCE
   if necessary.  You'd need a manual "FREE" method too to put "garabage"
   back in so making the user use a different constructor than the "normal"
   one isn't too out of the ordinary. 

>At compile time, say I want to pre-allocate 100 instances of class
>`my-class'. 

   At "compile time" or after some initialization call?  "compile time"
   implies these 100 instances need to be in the code image. 

   With your own constructor you could amortize this by calling MAKE-INSTANCE
   the first 100 times MAKE-SOME-CLASS is called and then on starting
   to use the buffer.   Which gradually gets filled as folks call "free". 

   I'm sure someone will correct me but I think "allocate instance" is 
   something for people who create their own class protocols. [ Doing MOP like
   stuff].  It just gets you a blob of memory and unitialized slots for this 
   particular class.  What the classes future up the chain might do is in 
   question. You then have to make sure everything gets initialized that 
   should be. 

   However, I think I see the bug.... if you wish to do it this way....

>
>;; simplified...
 (defmethod allocate-instance :around ((class my-class) &rest args)
                                       ^^^^^^^^^^^^^^^^
      I think this should be  (class (eql (find-class 'my-class)))

  You want a singleton method that matches only the _instance_ this is your 
  class. ALLOCATE-INSTANCE takes a class as an argument. You wish to
  match _one_ of those values.  Remember classes are objects too ( unlike
  some other OO languages that shall go nameless. )

  The above is a method for arguments where are instances of MY-CLASS.
  I very much doubt you really want to pass one of them to this generic.
-- 
					
Lyman S. Taylor          "The Borg --  party poopers of the Galaxy. "
(·····@cc.gatech.edu)                 EMH Doctor  Star Trek Voyager. 
From: Lyman S. Taylor
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <783d77$cll@pravda.cc.gatech.edu>
Sorry for the gaffs I probably wrote the original too quickly....


In article <··········@pravda.cc.gatech.edu>,
Lyman S. Taylor <·····@cc.gatech.edu> wrote:
>   if necessary.  You'd need a manual "FREE" method too to put "garabage"
>   back in so making the user use a different constructor than the "normal"
    back into the pool. Therefore, a different constructor
    only emphasizes the fact that something "different" must be done here. 
    [ Of course, for the goof balls who don't pay attention to protocol...
        you have a problem. ]

>   the first 100 times MAKE-SOME-CLASS is called and then on starting
>   to use the buffer.   Which gradually gets filled as folks call "free". 
                       The buffer pool gradually gets filled as folks call 
                       "free". 

>   something for people who create their own class protocols. [ Doing MOP like
>   stuff].  

       For instance, what happens when there is a sublcass?  What if it calls 
       this ALLOCATE-INSTANCE through a NEXT-METHOD? You sure you want to 
       return an instance of the superclass? 
       [ Granted  why would a concrete class have a subclass, but these are
         the sort of gotchas you have to ponder if you want to step into
         the "guts" of the instance creation protocol. ]



>  You want a singleton method that matches only the _instance_ this is your 
                                                                that
>  class. 
...
>  The above is a method for arguments where are instances of MY-CLASS.
                                       which 

    Dispatching on a particular value might be a "new" feature to some so
    an example or two:


USER(9): (defmethod fubu  (  (obj integer) )
             (format t "I'm an integer: ~a ~%" obj))
#<STANDARD-METHOD FUBU (INTEGER)>

USER(10): (defmethod fubu (  (obj class) )
             (format t "I'm a class: ~a ~%" obj ))
#<STANDARD-METHOD FUBU (CLASS)>

USER(11): (defmethod fubu  ( (obj (eql 6 )) )
              (format t "I'm special I'm six: ~a ~%" obj))
#<STANDARD-METHOD FUBU ((EQL 6))>

USER(12): (defmethod fubu  ( (obj (eql (find-class 'integer))))
             (format t "I'm special I'm the integer class: ~a ~%" obj ))
#<STANDARD-METHOD FUBU ((EQL #<BUILT-IN-CLASS INTEGER>))>

USER(13): (fubu 23 )
I'm an integer: 23 
NIL

USER(14): (fubu 45)
I'm an integer: 45 
NIL

USER(15): (fubu 6 )
I'm special I'm six: 6 
NIL

USER(16): (fubu (find-class 'integer ))
I'm special I'm the integer class: #<BUILT-IN-CLASS INTEGER> 
NIL

USER(17): (fubu (find-class 'class ))
I'm a class: #<STANDARD-CLASS CLASS> 
NIL


-- 
					
Lyman S. Taylor          "The Borg --  party poopers of the Galaxy. "
(·····@cc.gatech.edu)                 EMH Doctor  Star Trek Voyager. 
From: David Gadbois
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <w0k7luhj2b7.fsf@lagavulin.cyc.com>
David Bakhash <·····@mit.edu> writes:

> I would like to know if the following is possible, and if I'm
> thinking about it right.
> 
> I have a program which runs well (functionally).  It is written
> almost entirely in CLOS.  It produces a lot of garbage.  Now, in the
> process of optimizing it, I'd like to make a simple object pool as a
> resource of objects which are used a lot.

In general, resourcing makes sense if 1) Objects have expensive
initialization that could otherwise be shared amongst "instantiations"
of an object; or 2) The storage manager makes allocating the space for
new objects more expensive than just reusing the space occupied by an
old object.

In the first case, I would also look at why the initialization is
expensive.  It may be that the expensive-to-compute information can be
factored out into more static objects that the objects you are
allocating can refer to, or it may be a win to compute the expensive
stuff lazily.

In the second case, the issue is very implementation-specific, and, in
fact, there are storage systems where reusing old objects can be
considerably more expensive than just allocating a new one.  A notable
example is a system with a generational garbage collector where object
lifetimes are such that there are no memory hierarchy benefits to
reuse or the reuse hits the boundaries of the assumptions the GC makes
about intergenerational references.  I have seen several systems where
removing resourcing has sped things up considerably.

A huge disadvantage to resourcing is that it brings back the "dangling
pointer" problem that easily crops up with manual storage management.
Yuck.

There are situations where resourcing makes sense.  For example, if
the storage manager can go off into the weeds doing a GC on
allocation, and there are tight time requirements on getting the
allocation done, then resourcing may be a requirement.  The canonical
example is buffers for receiving network packets where the data goes
away if you don't copy it quickly enough.

In any case, resourcing is about the last thing I'd look at in
optimizing for speed, space, engineering time, etc.  There is usually
much lower hanging fruit, and there is too much risk of making things
worse.

--David Gadbois
From: David Bakhash
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <wkd849oocb.fsf@mit.edu>
David Gadbois <·······@lagavulin.cyc.com> writes:

> In any case, resourcing is about the last thing I'd look at in
> optimizing for speed, space, engineering time, etc.  There is usually
> much lower hanging fruit, and there is too much risk of making things
> worse.

I will take this advice.  but I've used resources before, in other
programming situations, and many times I've been successful at making my
programs faster and not GC-prone.  But _never_ using CLOS.  So, I
appreciate your advice, but I'd also like to know other people's
opinions and experiences with it.

dave
From: Kent M Pitman
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <sfwlnixqup2.fsf@world.std.com>
David Gadbois <·······@lagavulin.cyc.com> writes:

> A huge disadvantage to resourcing is that it brings back the "dangling
> pointer" problem that easily crops up with manual storage management.
> Yuck.

For this reason, when I think about resourcing, I sometimes end up
bargaining down to a poor man's approximation to them that once in a
while errs on the side of losing a thing it meant to return to the
heap, and so once in a while stresses the gc.  e.g.,

(defun make-foo () ...)

(defvar *foo* (make-foo))

(defun use-foo ()
  (let* ((foo (or *foo* (setq *foo* (make-foo))))
         (*foo* nil))
     ...))

works pretty well in single-processed systems where you don't expect
to be called recursively much but want to tolerate the rare occasion
where you do--perhaps only in debugging breakpoints or error handling.

This approach works only in certain system configuration modes--it
does not work when the resource might be used in another thread
that also has a desire for *foo* at the same time, if *foo* if not
going to be bound in at least one of the two threads...  Still,
for some apps you can easily prove this--it's modular componentware
that has to be more careful.
From: Rainer Joswig
Subject: Re: using CLOS with compile-time resources
Date: 
Message-ID: <joswig-2001991236250001@pbg3.lavielle.com>
In article <··············@mit.edu>, David Bakhash <·····@mit.edu> wrote:

> I have a program which runs well (functionally).  It is written almost
> entirely in CLOS.  It produces a lot of garbage.  Now, in the process of
> optimizing it, I'd like to make a simple object pool as a resource of
> objects which are used a lot.

CL-HTTP has a resource management facility.

Genera uses a very general machinery for this purpose
(manual memory management and tuning).

-- 
http://www.lavielle.com/~joswig