You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Cliff Woolley <cl...@yahoo.com> on 2001/09/25 05:39:22 UTC
apr_bucket_alloc prototype
I'm trying to decide whether apr_bucket_alloc should take a length
parameter or not. If it takes a length parameter, it can allocate in a
few different increments (say 16B, 32B, 64B, 128B), but of course it will
have to have separate free lists for each thread for each size. That
would allow it to allocate space for the apr_bucket_(heap|pool|file|mmap)
private structures with the same system that allocates for the
apr_bucket's. Or it can just use a single size (64B should be sufficient
for all current bucket types), and if sizeof(apr_bucket_foo)>64, it will
fail. But that seems pointless to me because we're testing at runtime a
condition that's known at compile time [it may or may not be able to be
compiled away depending on whether apr_bucket_alloc gets inlined or not].
But at least if we test it we can avoid situations where maybe a structure
is 40B on a 32bit system but blows up to 72B on a 64bit system. If it
weren't for that possibility, I'd just say we should leave it up to the
developer to ensure his structure is within the allowed size and not check
it explicitly, so we could just leave off the size parameter. So we'd end
up with one free list, all blocks allocated would be the same size.
That's clearly the absolute fastest way to allocate these things. Is it
safe?
Thoughts?
--Cliff
--------------------------------------------------------------
Cliff Woolley
cliffwoolley@yahoo.com
Charlottesville, VA
Re: apr_bucket_alloc prototype
Posted by Ryan Bloom <rb...@covalent.net>.
On Monday 24 September 2001 09:22 pm, Brian Pane wrote:
> Cliff Woolley wrote:
> >I'm trying to decide whether apr_bucket_alloc should take a length
> >parameter or not. If it takes a length parameter, it can allocate in a
> >few different increments (say 16B, 32B, 64B, 128B), but of course it will
> >have to have separate free lists for each thread for each size. That
> >would allow it to allocate space for the apr_bucket_(heap|pool|file|mmap)
> >private structures with the same system that allocates for the
> >apr_bucket's. Or it can just use a single size (64B should be sufficient
> >for all current bucket types), and if sizeof(apr_bucket_foo)>64, it will
> >fail. But that seems pointless to me because we're testing at runtime a
> >condition that's known at compile time [it may or may not be able to be
> >compiled away depending on whether apr_bucket_alloc gets inlined or not].
> >But at least if we test it we can avoid situations where maybe a structure
> >is 40B on a 32bit system but blows up to 72B on a 64bit system. If it
> >weren't for that possibility, I'd just say we should leave it up to the
> >developer to ensure his structure is within the allowed size and not check
> >it explicitly, so we could just leave off the size parameter. So we'd end
> >up with one free list, all blocks allocated would be the same size.
> >That's clearly the absolute fastest way to allocate these things. Is it
> >safe?
>
> Is it always going to be true that all the bucket subclasses are declared
> in apr_buckets.h? If so, how about doing something like this:
>
> union bucket_size {
> struct apr_bucket t1;
> struct apr_bucket_heap t2;
> struct apr_bucket_pool t3;
> /* rest of the bucket types omitted for clarity... */
> };
>
> and using sizeof(union bucket_size) as the single block size for the
> free list?
It is not true that all bucket types are declared in apr_buckets. It is perfectly
possible for a module writer to create their own bucket type. In fact, httpd does
this for HTTP error codes. I haven't digested the original question yet, but
I wanted to answer this. I'll answer the original in about an hour. I am doing
work-work right now.
Ryan
______________________________________________________________
Ryan Bloom rbb@apache.org
Covalent Technologies rbb@covalent.net
--------------------------------------------------------------
Re: apr_bucket_alloc prototype
Posted by Brian Pane <bp...@pacbell.net>.
Cliff Woolley wrote:
>On Mon, 24 Sep 2001, Brian Pane wrote:
>
>>Is it always going to be true that all the bucket subclasses are declared
>>in apr_buckets.h? If so, how about doing something like this:
>>
>> union bucket_size {
>> struct apr_bucket t1;
>> struct apr_bucket_heap t2;
>> struct apr_bucket_pool t3;
>> /* rest of the bucket types omitted for clarity... */
>> };
>>
>>and using sizeof(union bucket_size) as the single block size for the
>>free list?
>>
>
>That's a very good start... the only problem is that we have no way to
>know how much space custom bucket types will need. As long as the space
>requirement is "reasonable," I think we should provide for it. If the
>definition of reasonable that we choose is <=sizeof(union bucket_size),
>then that's okay with me. Or maybe it should be the size of the union or,
>say, 64B, whichever is bigger? Should we even bother?
>
Well, it's easy to add a char[64] field to the union to make sure it's
at least that large, but I'm still worried that specifying a byte size
limit for custom bucket subtypes makes portability difficult.
The only other ideas that I can think of are:
* Create a convention whereby each bucket subtype has to call a
function to register its size at runtime, or
* Let the free list adaptively figure out the maximum size that needs
to be supported in the current program: Start out the block size at
sizeof(union bucket_size), and increase it if there's ever an alloc
larger than that. And if blocks smaller than the current size
are freed (meaning that the block size has increased since they
were allocated), just free them to the system heap instead of putting
them back on the free list. In the httpd, this approach probably
would settle at a stable block size after the first request or two
for each thread.
--Brian
Re: apr_bucket_alloc prototype
Posted by Ryan Bloom <rb...@covalent.net>.
On Monday 24 September 2001 09:52 pm, Cliff Woolley wrote:
> On Mon, 24 Sep 2001, Ryan Bloom wrote:
> > > void apr_bucket_free(void *ptr, int list);
> > >
> > > But that means it'll be tricky to support the b->free(b) thing that
> > > FirstBill requested. It was nice and clean with SMS (grumble), since
> > > the function to use and the particular instance to be freed (and
> > > knowledge of its parent) were tied together as b->sms... any ideas? I
> > > suppose we could wrap free() with some other function in order to
> > > discard the extra parameter for those bucket types that might still
> > > want to use malloc/free directly... ugh.
> >
> > Why not just put the list number in the bucket itself?
>
> It already is. It's also in the apr_bucket_file/mmap/etc's so that
> file_destroy, mmap_destroy, etc, can work. Remember that I'm trying to
> use apr_bucket_alloc and apr_bucket_free to handle the
> apr_bucket_file/mmap/etc's as well as just the apr_bucket's. So unless
> the list number is at the same offset in apr_bucket_file and
> apr_bucket_mmap et al as it is in apr_bucket (which it almost certainly
> won't be), you can't just do this:
>
> void apr_bucket_free(void *ptr) {
> apr_bucket *b = ptr;
> free_the_damned_thing(b, b->list);
> }
>
> Because b->list will point to the wrong spot in the thing pointed to by
> ptr.
I have two different suggestions.
1) Put everything in the same list. When you need to grab the next bucket,
just check the alloc size to see if you can use that spot. Doing this assumes that
we won't have too many buckets in the free list. We could optimize this a bit
by making sure the list is sorted, so that we don't always have to walk the entire
list. We could also optimize this by making all of the standard buckets the same
size, or at least decide on two or three sizes.
This has the advantage of solving the other problem too.
2) Keep a separate list of free_buckets for all different bucket types. This
way, the id's in each bucket type can be the same, because they all refer to
different arrays.
Ryan
______________________________________________________________
Ryan Bloom rbb@apache.org
Covalent Technologies rbb@covalent.net
--------------------------------------------------------------
Re: apr_bucket_alloc prototype
Posted by Cliff Woolley <cl...@yahoo.com>.
On Mon, 24 Sep 2001, Ryan Bloom wrote:
> > void apr_bucket_free(void *ptr, int list);
> >
> > But that means it'll be tricky to support the b->free(b) thing that
> > FirstBill requested. It was nice and clean with SMS (grumble), since the
> > function to use and the particular instance to be freed (and knowledge of
> > its parent) were tied together as b->sms... any ideas? I suppose we could
> > wrap free() with some other function in order to discard the extra
> > parameter for those bucket types that might still want to use malloc/free
> > directly... ugh.
>
> Why not just put the list number in the bucket itself?
It already is. It's also in the apr_bucket_file/mmap/etc's so that
file_destroy, mmap_destroy, etc, can work. Remember that I'm trying to
use apr_bucket_alloc and apr_bucket_free to handle the
apr_bucket_file/mmap/etc's as well as just the apr_bucket's. So unless
the list number is at the same offset in apr_bucket_file and
apr_bucket_mmap et al as it is in apr_bucket (which it almost certainly
won't be), you can't just do this:
void apr_bucket_free(void *ptr) {
apr_bucket *b = ptr;
free_the_damned_thing(b, b->list);
}
Because b->list will point to the wrong spot in the thing pointed to by
ptr.
--Cliff
--------------------------------------------------------------
Cliff Woolley
cliffwoolley@yahoo.com
Charlottesville, VA
Re: apr_bucket_alloc prototype
Posted by Ryan Bloom <rb...@covalent.net>.
On Monday 24 September 2001 09:41 pm, Cliff Woolley wrote:
> On Mon, 24 Sep 2001, Brian Pane wrote:
> > Is it always going to be true that all the bucket subclasses are declared
> > in apr_buckets.h? If so, how about doing something like this:
> >
> > union bucket_size {
> > struct apr_bucket t1;
> > struct apr_bucket_heap t2;
> > struct apr_bucket_pool t3;
> > /* rest of the bucket types omitted for clarity... */
> > };
> >
> > and using sizeof(union bucket_size) as the single block size for the
> > free list?
>
> That's a very good start... the only problem is that we have no way to
> know how much space custom bucket types will need. As long as the space
> requirement is "reasonable," I think we should provide for it. If the
> definition of reasonable that we choose is <=sizeof(union bucket_size),
> then that's okay with me. Or maybe it should be the size of the union or,
> say, 64B, whichever is bigger? Should we even bother?
>
> I'm also having trouble coming up with a prototype for apr_bucket_free:
> unless you do something magical, you have to pass it the list number:
>
> void apr_bucket_free(void *ptr, int list);
>
> But that means it'll be tricky to support the b->free(b) thing that
> FirstBill requested. It was nice and clean with SMS (grumble), since the
> function to use and the particular instance to be freed (and knowledge of
> its parent) were tied together as b->sms... any ideas? I suppose we could
> wrap free() with some other function in order to discard the extra
> parameter for those bucket types that might still want to use malloc/free
> directly... ugh.
Why not just put the list number in the bucket itself?
______________________________________________________________
Ryan Bloom rbb@apache.org
Covalent Technologies rbb@covalent.net
--------------------------------------------------------------
Re: apr_bucket_alloc prototype
Posted by Cliff Woolley <cl...@yahoo.com>.
On Mon, 24 Sep 2001, Brian Pane wrote:
> Is it always going to be true that all the bucket subclasses are declared
> in apr_buckets.h? If so, how about doing something like this:
>
> union bucket_size {
> struct apr_bucket t1;
> struct apr_bucket_heap t2;
> struct apr_bucket_pool t3;
> /* rest of the bucket types omitted for clarity... */
> };
>
> and using sizeof(union bucket_size) as the single block size for the
> free list?
That's a very good start... the only problem is that we have no way to
know how much space custom bucket types will need. As long as the space
requirement is "reasonable," I think we should provide for it. If the
definition of reasonable that we choose is <=sizeof(union bucket_size),
then that's okay with me. Or maybe it should be the size of the union or,
say, 64B, whichever is bigger? Should we even bother?
I'm also having trouble coming up with a prototype for apr_bucket_free:
unless you do something magical, you have to pass it the list number:
void apr_bucket_free(void *ptr, int list);
But that means it'll be tricky to support the b->free(b) thing that
FirstBill requested. It was nice and clean with SMS (grumble), since the
function to use and the particular instance to be freed (and knowledge of
its parent) were tied together as b->sms... any ideas? I suppose we could
wrap free() with some other function in order to discard the extra
parameter for those bucket types that might still want to use malloc/free
directly... ugh.
--Cliff
--------------------------------------------------------------
Cliff Woolley
cliffwoolley@yahoo.com
Charlottesville, VA
Re: apr_bucket_alloc prototype
Posted by Brian Pane <bp...@pacbell.net>.
Cliff Woolley wrote:
>I'm trying to decide whether apr_bucket_alloc should take a length
>parameter or not. If it takes a length parameter, it can allocate in a
>few different increments (say 16B, 32B, 64B, 128B), but of course it will
>have to have separate free lists for each thread for each size. That
>would allow it to allocate space for the apr_bucket_(heap|pool|file|mmap)
>private structures with the same system that allocates for the
>apr_bucket's. Or it can just use a single size (64B should be sufficient
>for all current bucket types), and if sizeof(apr_bucket_foo)>64, it will
>fail. But that seems pointless to me because we're testing at runtime a
>condition that's known at compile time [it may or may not be able to be
>compiled away depending on whether apr_bucket_alloc gets inlined or not].
>But at least if we test it we can avoid situations where maybe a structure
>is 40B on a 32bit system but blows up to 72B on a 64bit system. If it
>weren't for that possibility, I'd just say we should leave it up to the
>developer to ensure his structure is within the allowed size and not check
>it explicitly, so we could just leave off the size parameter. So we'd end
>up with one free list, all blocks allocated would be the same size.
>That's clearly the absolute fastest way to allocate these things. Is it
>safe?
>
Is it always going to be true that all the bucket subclasses are declared
in apr_buckets.h? If so, how about doing something like this:
union bucket_size {
struct apr_bucket t1;
struct apr_bucket_heap t2;
struct apr_bucket_pool t3;
/* rest of the bucket types omitted for clarity... */
};
and using sizeof(union bucket_size) as the single block size for the
free list?
--Brian
Re: apr_bucket_alloc prototype
Posted by Ryan Bloom <rb...@covalent.net>.
On Monday 24 September 2001 08:39 pm, Cliff Woolley wrote:
> I'm trying to decide whether apr_bucket_alloc should take a length
> parameter or not. If it takes a length parameter, it can allocate in a
> few different increments (say 16B, 32B, 64B, 128B), but of course it will
> have to have separate free lists for each thread for each size. That
> would allow it to allocate space for the apr_bucket_(heap|pool|file|mmap)
> private structures with the same system that allocates for the
> apr_bucket's. Or it can just use a single size (64B should be sufficient
> for all current bucket types), and if sizeof(apr_bucket_foo)>64, it will
> fail. But that seems pointless to me because we're testing at runtime a
> condition that's known at compile time [it may or may not be able to be
> compiled away depending on whether apr_bucket_alloc gets inlined or not].
> But at least if we test it we can avoid situations where maybe a structure
> is 40B on a 32bit system but blows up to 72B on a 64bit system. If it
> weren't for that possibility, I'd just say we should leave it up to the
> developer to ensure his structure is within the allowed size and not check
> it explicitly, so we could just leave off the size parameter. So we'd end
> up with one free list, all blocks allocated would be the same size.
> That's clearly the absolute fastest way to allocate these things. Is it
> safe?
>
> Thoughts?
If we made people register their bucket types like we used to, this problem
would be easy to solve, because we could just take the max of all registered
buckets.
I was thinking of telling you to make the code just adapt, but that is just going
to be very ugly code. So, then I was thinking of doing it all with macros, but I
can't really see a good way to do that.
So, I'm still thinking about this.
Ryan
______________________________________________________________
Ryan Bloom rbb@apache.org
Covalent Technologies rbb@covalent.net
--------------------------------------------------------------