Re: About optimization

From: Date: Thu, 14 Jan 2010 03:18:45 +0000
Subject: Re: About optimization
References: 1 2 3 4 5 6 7 8 9 10 11  Groups: php.internals 
Request: Send a blank email to internals+get-46728@lists.php.net to get a copy of this message
Stanislav Malyshev wrote:
>
> opcodes can be cached (bytecode caches do it) but op_array can't
> really be cached between requests because it contains dynamic
> structures. Unlike Java, PHP does full cleanup after each request,
> which means no preserving dynamic data.

APC deep-copies the whole zend_op_array, see apc_copy_op_array() in
apc_compile.c. It does it using an impressive pile of hacks which break
with every major release and in some minor releases too. Every time the
compiler allocates memory, there has to be a matching shared memory
allocation in APC.

But maybe you missed my point. I'm talking about a cache which is cheap
to construct and cleared at the end of each request. It would optimise
tight loops of calls to user-defined functions. The dynamic data, like
static variable hashtables, would be in it. The compact pointerless
structure could be stored between requests, and would not contain
dynamic data.

Basically a structure like the current zend_op_array would be created on
demand by the executor instead of in advance by the compiler.

>
> I'm not sure how using pointers in op_array in such manner would help
> though - you'd still need to store things like function names, for
> example, and since you need to store it somewhere, you'd also have
> some pointer to this place.

You can do it with a length field and a char[1] at the end of the
structure. When you allocate memory for the structure, you add some on
for the string. Then you copy the string into the char[1], overflowing it.

If you need several strings, then you can have several byte offsets,
which are added to the start of the char[1] to find the location of the
string in question. You can make the offset fields small, say 16 bits.

But it's mostly zend_op I'm interested in rather than zend_op_array.
Currently if a zend_op has a string literal argument, you'd make a zval
for it and copy it into op1.u.constant. But the zval allocation could be
avoided. The handler could cast the zend_op to a zend_op_with_a_string,
which would have a length field and an overflowed char[1] at the end for
the string argument.

A variable op size would make iterating through zend_op_array.opcodes
would be slightly more awkward, something like:

for (; op < oparray_end; op = (zend_op*)((char*)op + op->size)) {
   ...

But obviously you could clean that up with a macro.

For Mr. "everyone has 8GB of memory and tiny little data sets" Lerdorf,
I could point out that reducing the average zend_op size and placing
strings close to other op data will also make execution faster, due to
the improved CPU cache hit rate.

-- Tim Starling


Thread (42 messages)

« previous php.internals (#46728) next »