Hi again Dmitry, all,
Hopefully the final update on this, before all is revealed... :-)
----- Original Message -----
From: "Matt Wilmas"
Sent: Tuesday, July 07, 2015
Hi again Dmitry, all,
[...]
Just an update... I didn't abandon this; quite the opposite! I thought
I'd just put the finishing touches on my implementation and have it to you
almost a week ago. After my rough initial test version, I made some
obvious, simple changes to reduce instructions/code size (slightly). And
then analyzing different stuff with GCC and MSVC to see if it could be
improved more (not really since fairly straightforward), etc...
~5 days ago when I was done messing and changed the macros to recompile
the existing FAST_ZPP parts, I didn't know what the size difference would
be vs no FAST_ZPP (traditional). I had overestimated the savings ("maybe
a few more bytes" for instructions). It was in the 30-45% range of your
inlined version.
I made a change to save instructions, but, strangely, it didn't really
have the effect on size I thought it would. :-/
BTW, the improvement on Linux with GCC 4.8 was about the same: ~70% of
inlined. So roughly ~2/3 speed for ~1/3 space. I also finally installed
Valgrind and used Callgrind for the first time. Simple. :^) About same
relative reduction in instructions.
I really wanted the code size to be smaller if this could get widespread
use, and started wondering, "What if...?", "How?", "Why not?", "But..."
Then I had a new idea, but wasn't sure what the compilers would do with
it. So I spent Sunday prototyping a couple key parts of it outside of PHP.
GCC can make a HUGE mess of it, but easily worked around. So it looks
good, even better than the ideal I had imagined. Now I just have to do it
for PHP...
This way saves the lea instructions for each &dest variable (like the
inline version), and then some. And just earlier I realized there's a way
to save the other instructions (while using the same macro syntax), which
would also apply to the previous implementation.
So ideally, this means at the CALL site, we should be able to have the
zend_fast_parse_... function call: Just mov+mov+lea+call on 64-bit, and
that's it. The rest of the stuff (a good amount) can be COMPLETELY
optimized away! :-O
And in the parse_... function, compared to the *inline* FAST_ZPP, that
should get it down to about 3 dozen more instructions per parameter: while
+ switch + checks in zend_parse_arg_* that would get optimized away when
inlined.
Well, I'll send the implementation(s) for you to test as soon as I can!
I tried to rush and finish things up before the weekend *2 weeks ago*, but
it took me too long to get the macros sorted out and working right. :-/
Sorry for the delay, but more and better goodness should now be included.
The extra time allowed me to "relax and take notes" (Notorious B.I.G.),
however. :-D
So yeah, that was all working 10 days ago. Then I realized more function
param data could be packed together which saved another mov instruction --
so at the call site, it's just mov+lea+call on 64-bit (since execute_data is
already in %rdi). There's nothing else (ignoring checking return
value/return on error, etc.), and each &dest variable is filled in even
though their address isn't taken (thanks to compiler magic). The only
exceptions are FUNC (4 instructions I think) and OBJECT_OF_CLASS and
VARIADIC (1 instruction) types.
Unfortunately (only because I said "same macro syntax," but no big deal),
the syntax had to be changed, from:
ZEND_PARSE_PARAMETERS_START[_EX](...)
Z_PARAM_*(...)
Z_PARAM_*(...)
ZEND_PARSE_PARAMETERS_END[_EX]
to
ZEND_PARSE_PARAMETERS_START[_EX](...)( // Parentheses
Z_PARAM_*(...), // Comma-separated
Z_PARAM_*(...)
) ZEND_PARSE_PARAMETERS_END[_EX]
Overall, the *code* size is reduced (vs traditional ZPP), but the file size
isn't (static stuff in rodata or whatever), which was a bit surprising,
although most of these PHP functions don't have many parameters...
The biggest size savings actually came from the simple initial optimization
of zend_parse_params_none(). Down to almost nothing, much faster, and saved
4KB on my --disable-all builds.
NEW GOODNESS -- What would of course be nice to have is a big optimization
of the traditional zend_parse[_method]_parameters[_ex|_throw] to avoid
changing them all. And it seems some people, like Derick, prefer it.
Of course the obvious way I first had in mind weeks ago was to simply parse
its format string faster (once-ish) at runtime, and then feed it to this new
FAST_parse function. Should give at least 2x speedup I figured. But with
this latest implementation, where the function should probably now be called
parse_parameters_ARRAY instead of fast_parse, it would need a second pass
after parsing the string. Not a huge deal, but...
What would be *really nice* is to have the compiler parse the format string,
at compile time, and use the new system directly. And... that should be
possible!! 8-)
Last week I figured GCC's "statement expressions" [1] could be used, which
most compilers seem to support, except MSVC. But just over the weekend I
realized an inline function could be used with a compound literal (for the
varargs), which is also supported in the latest MSVC versions. Awesome!
And again, fear not, ALL the code can be completely removed by the compiler,
leaving only movb instructions instead of lea+mov/push for the traditional
ZPP function call. So, better than my initial implementation(s), and nearly
the same as my final macro version! I was just testing prototypes of
portions with GCC yesterday, which does fine after adjusting to not generate
*horribly stupid* code.
Now to implement it into PHP ASAP! Then I'll save a few more
banches/instructions in the parse function (specialized for common cases;
some useless GCC instructions), comment and clean up my experimental mess,
and write up some explanation of the changes before sending patch. Oh, and
I should verify what Clang does with the code as well...
Stay tuned!
[1] https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
- Matt
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php