Questions about optimizing memory usage

Questions about optimizing memory usage

am 15.12.2005 08:15:39 von Chase Venters

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

am 15.12.2005 22:35:30 von Perrin Harkins

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

Re: Questions about optimizing memory usage

am 16.12.2005 10:33:56 von Chase Venters

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

am 16.12.2005 18:26:55 von Perrin Harkins

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

am 16.12.2005 18:51:36 von pgollucci

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

am 16.12.2005 18:52:45 von Chase Venters

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

am 16.12.2005 19:09:05 von Perrin Harkins

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

am 16.12.2005 19:59:38 von Frank Wiles

On Fri, 16 Dec 2005 12:51:36 -0500 (EST)
"Philip M. Gollucci" 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
http://www.wiles.org
---------------------------------

Re: Questions about optimizing memory usage

am 18.12.2005 13:06:42 von Tom Schindl

This is an OpenPGP/MIME signed message (RFC 2440 and 3156)
--------------enig877F04E045EE40C6B8F435B9
Content-Type: text/plain; charset=ISO-8859-6
Content-Transfer-Encoding: 7bit

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

--------------enig877F04E045EE40C6B8F435B9
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Using GnuPG with Mandriva - http://enigmail.mozdev.org

iD8DBQFDpVDXkVPeOFLgZFIRArF4AJ9phdBAR5ieFWpWAxFkxUbAZfZyigCc DzfT
sXEOqoE/IDeeb4zXH3lsvLg=
=utQI
-----END PGP SIGNATURE-----

--------------enig877F04E045EE40C6B8F435B9--