You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Chase Venters <ch...@clientec.com> on 2005/12/15 08:15:39 UTC

Questions about optimizing memory usage

Greetings,
	I have some questions about optimizing memory usage. I could probably get 
some of these answers myself with more study of the mod_perl / perl source, 
but I was hoping someone might just know the answer and be able to tell me :)
	First off, am I correct in the assumption that it has been wise even in 
mod_perl 1 (under Apache's child-per-request model) to preload all of your 
modules for memory savings?
	Where exactly do these savings come from if the processes are forked? Is 
there some sort of mmap / shmem way that the Apache children share their Perl 
trees? Or perhaps the processes each have all that memory *allocated* 
individually, but because of COW pages from the OS, you only need one copy 
resident (hence less paging)?
	In answering the above questions - are these reasons / behaviors consistent 
with mod_perl 2 under prefork?
	Also - as of the current Perl 5.8 series, we're still not sharing / doing COW 
with variable memory (SV/HV/AV) right?
	Now as for an optimization question... if the ops in the code tree are 
shared, let's suppose I declare this subroutine via a scalar passed to eval 
prior to the clone process:

sub _get_Big_Data_Structure {
	return {
		key => {
			nested => ['values'],
			lots => {'of' => 'data'},
		},
	};
}

	The thing is that I have a big nested config structure, along with lots of 
other big nested structures. A given request doesn't need *all* of the data, 
so I've been brainstorming and thought about writing a "reduce" method that I 
would dispatch around my module tree from one of the prior-to-clone handlers 
that would take these structures, use Data::Dumper to get their "source code" 
form, and eval them into subroutines in some "stash" package. 
	I don't particularly care if this adds seconds to the Apache startup time if 
it can reduce my runtime memory usage reasonably. I suppose the only other 
thing I have to be concerned about if the above idea will work is how long 
the "_get_Big_Data_Structure" call would take.
	Thoughts?

Thanks,
Chase Venters

Re: Questions about optimizing memory usage

Posted by Tom Schindl <to...@gmx.at>.
Chase Venters wrote:
> On Thursday 15 December 2005 03:35 pm, Perrin Harkins wrote:
> 
>>Not a great way to start your post.  Please read this:
>>http://modperlbook.org/html/ch10_01.html
> 
> 
> My apologies. I do own the book and I have read it, but it was some time ago 
> and I didn't remember that some of my questions were addressed. My biggest 
> question was the last one pertaining to the possible trick to optimize 
> memory. I'm starting to realize after reading over my original post (and your 
> reply) that I could have been more clear with some of my questions.
> 
> 
>>>	Also - as of the current Perl 5.8 series, we're still not sharing /
>>>doing COW with variable memory (SV/HV/AV) right?
>>
>>COW doesn't care what's in the memory.  It will share pages with
>>variables in them if they don't change.  Even reading a variable in a
>>new context can change it in perl though.
> 
> 
> Well, I should have been more clear here that I was no longer talking about 
> prefork. What I meant by COW here was actually that if you were going to use 
> multiplicity with Perl_clone, since the threads would share memory, Perl 
> would either need to:
> 
> (a) create a copy of all variables;
> or
> (b) use a thread sync primitive like an rwsem and do its own COW on this data.
> 
At the moment when using threads the ***whole*** memory is copied! Nick
Clark has been working on something like COW for threads but I don't
know the actual state. Although please note that thread performance has
been increased a lot in 5.8-releases so when using threads stick to the
latest 5.8 release available.

Tom

Re: Questions about optimizing memory usage

Posted by Frank Wiles <fr...@wiles.org>.
On Fri, 16 Dec 2005 12:51:36 -0500 (EST)
"Philip M. Gollucci" <pg...@p6m7g8.com> wrote:

> 
> >> And BDB would be dependency creep, which
> >> is quite difficult to fight in perl sometimes (that's just because
> >> there are a zillion useful CPAN modules) :)
> >
> > Personally, I don't fight it.  I just use zillions of CPAN modules.
> 
> Amen.
> 

  You guys are way more advanced than me.  I only use a few million
  CPAN modules. ;) 

 ---------------------------------
   Frank Wiles <fr...@wiles.org>
   http://www.wiles.org
 ---------------------------------


Re: Questions about optimizing memory usage

Posted by "Philip M. Gollucci" <pg...@p6m7g8.com>.
>> And BDB would be dependency creep, which
>> is quite difficult to fight in perl sometimes (that's just because there are
>> a zillion useful CPAN modules) :)
>
> Personally, I don't fight it.  I just use zillions of CPAN modules.

Amen.


Re: Questions about optimizing memory usage

Posted by Perrin Harkins <pe...@elem.com>.
On Fri, 2005-12-16 at 11:52 -0600, Chase Venters wrote:
> I wonder then if Perl would be smart enough to understand that the data is 
> constant and not copy it with Perl_clone()?

I'm pretty sure the answer is no.  You can try marking things shared
with threads::shared and see if that gets you anything.

> I suppose what I really should 
> be doing here is writing a test as a perl embedded app that does various 
> things to test out clone's behavior.

Or just try loading the same data in a threaded mod_perl in different
ways and look at how much memory it uses.

> Actually tried? No. But the data is in essence a big table of information 
> about how to build SQL queries from method calls, validate/convert the 
> information in the process, and pack it into objects. Having to first 
> fetch the model itself out of SQL (its structure not even lending to easy 
> storage in such a DB) would be clunky / awkward, and would basically 
> involve an extra query or set of queries against a table for every 
> request.

You might be surprised by how fast something like Cache::FastMmap can be
if you break your data up nicely across keys.  The thing that hurts is
when you store it as one big nested structure, requiring serialization.

- Perrin


Re: Questions about optimizing memory usage

Posted by Chase Venters <ch...@clientec.com>.
On Fri, 16 Dec 2005, Perrin Harkins wrote:

> It will probably be big.  Perl structures tend to use several times the
> size of the actual data they store.

That's what I'm worried about then I suppose.

>> is this root hash, its keys / values / etc stored along with variables, or is
>> it in the op tree?
>
> I assume that it's stored in exactly the same way all the other
> variables are stored.

I wonder then if Perl would be smart enough to understand that the data is 
constant and not copy it with Perl_clone()? I suppose what I really should 
be doing here is writing a test as a perl embedded app that does various 
things to test out clone's behavior.

>> I can't put the data in SQL for performance reasons.
>
> Have you tried?  It's hard for me to believe that the data can't be
> broken down in a way that would make external storage possible.

Actually tried? No. But the data is in essence a big table of information 
about how to build SQL queries from method calls, validate/convert the 
information in the process, and pack it into objects. Having to first 
fetch the model itself out of SQL (its structure not even lending to easy 
storage in such a DB) would be clunky / awkward, and would basically 
involve an extra query or set of queries against a table for every 
request.

Now, admittedly, I'm an extreme freak when it comes to optimizing for 
performance. In the age of J2EE, it's how I make my stuff shine. Seeing 
low-ms response times from mod_perl apps makes me smile.

>> And BDB would be dependency creep, which
>> is quite difficult to fight in perl sometimes (that's just because there are
>> a zillion useful CPAN modules) :)
>
> Personally, I don't fight it.  I just use zillions of CPAN modules.

Genearlly so do I. And so do the authors of those modules. Then one day 
you're installing Net::SSH::Perl and you realize that it pulls in fifteen 
module distribution dependencies once everything is accounted for.

I now understand the meaning of autosplit :)

> - Perrin

Thanks again for your remarks.

Cheers,
Chase

Re: Questions about optimizing memory usage

Posted by Perrin Harkins <pe...@elem.com>.
On Fri, 2005-12-16 at 03:33 -0600, Chase Venters wrote:
> Well, I should have been more clear here that I was no longer talking about 
> prefork. What I meant by COW here was actually that if you were going to use 
> multiplicity with Perl_clone, since the threads would share memory, Perl 
> would either need to:
> 
> (a) create a copy of all variables;
> or
> (b) use a thread sync primitive like an rwsem and do its own COW on this data.

I don't know much about threads, but I'm pretty sure it does a.

> What I'm 
> not clear yet on in my study of perlguts is how much overhead is associated 
> with a hash, because while the individual structures aren't huge, there could 
> be a lot of them.

It will probably be big.  Perl structures tend to use several times the
size of the actual data they store.

> is this root hash, its keys / values / etc stored along with variables, or is 
> it in the op tree?

I assume that it's stored in exactly the same way all the other
variables are stored.

> I can't put the data in SQL for performance reasons.

Have you tried?  It's hard for me to believe that the data can't be
broken down in a way that would make external storage possible.

> And BDB would be dependency creep, which 
> is quite difficult to fight in perl sometimes (that's just because there are 
> a zillion useful CPAN modules) :)

Personally, I don't fight it.  I just use zillions of CPAN modules.

- Perrin


Re: Questions about optimizing memory usage

Posted by Chase Venters <ch...@clientec.com>.
On Thursday 15 December 2005 03:35 pm, Perrin Harkins wrote:
> Not a great way to start your post.  Please read this:
> http://modperlbook.org/html/ch10_01.html

My apologies. I do own the book and I have read it, but it was some time ago 
and I didn't remember that some of my questions were addressed. My biggest 
question was the last one pertaining to the possible trick to optimize 
memory. I'm starting to realize after reading over my original post (and your 
reply) that I could have been more clear with some of my questions.

> > 	Also - as of the current Perl 5.8 series, we're still not sharing /
> > doing COW with variable memory (SV/HV/AV) right?
>
> COW doesn't care what's in the memory.  It will share pages with
> variables in them if they don't change.  Even reading a variable in a
> new context can change it in perl though.

Well, I should have been more clear here that I was no longer talking about 
prefork. What I meant by COW here was actually that if you were going to use 
multiplicity with Perl_clone, since the threads would share memory, Perl 
would either need to:

(a) create a copy of all variables;
or
(b) use a thread sync primitive like an rwsem and do its own COW on this data.

If the latter were true (perl doing its own COW under multiplicity), it would 
seem to me that reading a variable shouldn't automatically require the 
variable to be copied (except perhaps under SvMAGIC), though I understand 
that if you were using prefork and the OS was doing COW, if you so much as 
wrote a byte, you'd invalidate the page.

I remember there being talks in the mod_perl dev docs somewhere about a 
GvSHARED proposal... this question was just 'did this ever see the light of 
day?'

> How much data are we talking about?  If it's more than a few MBs, I
> wouldn't recommend it.  Just put it in MySQL, or Cache::FastMmap, or
> BerkeleyDB, and then access only the bits you need from each process.

Oh no, nothing on that order. Each structure consists of a base hash, with 
let's say 20 keys, and perhaps a few nested hashes under these keys. What I'm 
not clear yet on in my study of perlguts is how much overhead is associated 
with a hash, because while the individual structures aren't huge, there could 
be a lot of them.

(In essence it's a very flexible data modeller whose models are created during 
startup by a ordered dependency launcher 'plugin' system. Certain 'plugins' 
if you will can decorate existing models, so I maintain the hash structure to 
describe all the fields of the model).

Here's another way to put my question... in the case that I do:

sub _get_Model {
	return {
		hash => [qw(stuff here)],
	};
}

is this root hash, its keys / values / etc stored along with variables, or is 
it in the op tree? IE, without GvSHARED, would a Perl_clone under 
multiplicity create a separate copy of this structure per thread?

I can't put the data in SQL for performance reasons. Cache::FastMmap, despite 
being fast, would worry me as well, especially given that the structures 
would have to be serialized/deserialized. At that point, I'd rather just keep 
a copy per thread as I currently do. And BDB would be dependency creep, which 
is quite difficult to fight in perl sometimes (that's just because there are 
a zillion useful CPAN modules) :)

I'm just always looking for ways to optimize really. I've almost completed a 
multithreaded SIP server in C that provides a perl environment, sort of a 
mod_perl for SIP if you will. This is unfortunately stalled due to $work at 
the moment. In the process of doing so, I found both the mod_perl 2 code and 
the perl code itself to be enlightening, but honestly the perl code is 
beastly and takes time getting used to :)

I find myself wishing there were a comprehensive perlguts book.

> - Perrin

Thanks again.

Cheers,
Chase

Re: Questions about optimizing memory usage

Posted by Perrin Harkins <pe...@elem.com>.
On Thu, 2005-12-15 at 01:15 -0600, Chase Venters wrote:
> I could probably get 
> some of these answers myself with more study of the mod_perl / perl source, 
> but I was hoping someone might just know the answer and be able to tell me :)

Not a great way to start your post.  Please read this:
http://modperlbook.org/html/ch10_01.html

> 	First off, am I correct in the assumption that it has been wise even in 
> mod_perl 1 (under Apache's child-per-request model) to preload all of your 
> modules for memory savings?

Yes.

> Is 
> there some sort of mmap / shmem way that the Apache children share their Perl 
> trees?

No.

> Or perhaps the processes each have all that memory *allocated* 
> individually, but because of COW pages from the OS, you only need one copy 
> resident (hence less paging)?

Yes, it's all from COW.

> 	In answering the above questions - are these reasons / behaviors consistent 
> with mod_perl 2 under prefork?

Yes.

> 	Also - as of the current Perl 5.8 series, we're still not sharing / doing COW 
> with variable memory (SV/HV/AV) right?

COW doesn't care what's in the memory.  It will share pages with
variables in them if they don't change.  Even reading a variable in a
new context can change it in perl though.

> 	The thing is that I have a big nested config structure, along with lots of 
> other big nested structures. A given request doesn't need *all* of the data, 
> so I've been brainstorming and thought about writing a "reduce" method that I 
> would dispatch around my module tree from one of the prior-to-clone handlers 
> that would take these structures, use Data::Dumper to get their "source code" 
> form, and eval them into subroutines in some "stash" package.

How much data are we talking about?  If it's more than a few MBs, I
wouldn't recommend it.  Just put it in MySQL, or Cache::FastMmap, or
BerkeleyDB, and then access only the bits you need from each process.

- Perrin