In profiling #697760: Replace getInfo() in tests with native phpDoc + annotations (following PHPUnit), I noticed that some innocent-looking code appears very high in profiling results.
That is, primarily because the contained code paths are entered multiple thousands of times on a fairly large page that renders plenty of individual things (such as the page that lists all tests in Simpletest).
Attached patch performs some simple adjustments that makes the code no longer rank very high in profiling results.
Comment | File | Size | Author |
---|---|---|---|
#14 | various_small-2263279-14.patch | 8.69 KB | joelpittet |
#12 | various_small-2263279-12.patch | 8.58 KB | joelpittet |
#10 | various_small-2263279-10.patch | 8.35 KB | joelpittet |
#9 | test.php_.txt | 2.54 KB | joelpittet |
#9 | suggestions.txt | 7.79 KB | joelpittet |
Comments
Comment #1
sunperf.opt_.0.patch queued for re-testing.
Comment #3
sunperf.opt_.0.patch queued for re-testing.
Comment #5
dawehnerIt would be great to see a before and after of xhprof to see how much this actually improves.
How much faster is that?
Comment #6
tim.plunkettI'm pretty sure we purposefully allow callables here. I didn't think that
$callable = array($object, 'method'); $callable();
worked?Comment #7
sun@tim.plunkett: Support for calling a callable that is defined as an array in a variable is a new feature since PHP 5.4:
http://3v4l.org/snPDv
call_user_func()
is effectively the same and thus an obsolete wrapper.call_user_func_array()
only remains to be useful when dealing with an unknown amount of arguments (as in e.g.module_invoke()
).Comment #8
tim.plunkettLearn something new every day! Thanks for the tip @sun.
Just tagging for #5
Comment #9
joelpittetRe #5.
I've generated 50 nodes with 3 commments using
drush genc 50 3
.Then did clear cache vs warm cache json_encode export of the $suggestsions of what's now
ThemeManager:render()
onThemeManager.php:255
This should be much better performance test than xhprof because it's real results but localized to this case.
To export I just dropped in:
Suggestions Cold Cache
Reverse Foreach Times:
End While Times:
Suggestions Warm Cache
Reverse Foreach Times:
End While Times:
So essentially that change is twice as slow and also fairly negligible. but should be removed from this patch in my opinion because it's less clear as well as slower.
Running the script change it to test.php and run it with php or drush...
drush scr test.php
Comment #10
joelpittetHere's a re-roll without that foreach to while change and using this regular expression to find similar array callables.
call_user_func_array\([^,]*, array\(
Comment #12
joelpittetMade a typo missed $ and reroll for installer batch changes.
Comment #14
joelpittetVery interesting I wonder why the callback would fail in the AJAX request and before it didn't... wrapped them both in a check to see if we have a callbable.
Comment #16
dawehnerThe comment indicates that this was on purpose
Comment #17
joelpittet@dawehner re #16 yes it does but that logic change shouldn't change that fact it will just make it faster by doing
isset()
first if the key exists.NULL
will failover to the slowerarray_key_exists()
.Comment #18
dawehnerOh you are right. Do you mind adapting the comment a bit?
Comment #19
joelpittetI don't mind, just won't be looking at this realistically for another week as I'll be doing safemarkup at MWDS.
Though I'll pick this up again if nobody has and might squeeze it in somewhere between.
Comment #21
donquixote CreditAttribution: donquixote commentedMost of these changes are about replacing
call_user_func_array()
. Which I support very much.Should we focus on these changes only and then change the issue title?
I almost created a new issue for the same purpose, because I could not find this one with this very generic title.
I change the title myself for now, so at least it can be more easily found in searches.
If we actually decide to move the two other improvements to a different issue, we can simplify the title.
Comment #22
donquixote CreditAttribution: donquixote commentedThe main problem with replacing call_user_func_array() is callbacks of the format
'C::foo'
. These are supported bycall_user_func_array()
, but not by$callback()
.Only in PHP 7 is this fixed.
https://3v4l.org/KFAGV
For callbacks that are processed with
$form_state->prepareCallback($callback)
, we could extend theprepareCallback()
to also cover this case, with little extra overhead.We would have to verify which combination of explode(), strpos() and substr() is fastest. I think it depends on which case we optimize for.
Btw even faster would be if the form state had a method that invokes the method instead of just preparing it. And/or if it could prepare or invoke multiple of those methods in one call. So the loop over $element['#process'] would be in the new FormState::invokeProcessCallbacks() method, not in the FormBuilder::doBuildForm() method.
-------
For the other cases, we would simply have to wait for a release that allows a BC break like disallowing the
'S::foo'
syntax for callbacks. Or wait until Drupal requires PHP 7.See also comment #149 in #1499596-149: Introduce a basic entity form controller, the issue where the
call_user_func_array()
was introduced.Comment #23
joelpittetre #22 at the point where we cover the exception are we just making this more complicated and slower? strpos is pretty fast but explode isn't.
Comment #24
donquixote CreditAttribution: donquixote commentedWe would have to profile this and compare. The other option is
This would be two function calls instead of one, but possibly it is still faster. Only benchmarks can tell.
But more important is that the different if branches have a different likeliness. If e.g. only 2% of callbacks have the
'C::foo'
format, then the cost ofexplode()
does not really matter as much.Comment #25
joelpittetBroke off the small little change for
array_key_exists()
#2770065: array_key_exists() micro-optimization
So it can be removed form this and make the title change more accurate from #21
Comment #26
donquixote CreditAttribution: donquixote commentedBenchmark code:
Output:
Which means that the
explode()
solution is faster.EDIT: I added a
$pos =
before the firststrpos()
, and posted the new numbers. Still same conclusion.Comment #27
donquixote CreditAttribution: donquixote commentedIt turns out that
explode()
is even faster for the case of'::foo'
.Comment #28
donquixote CreditAttribution: donquixote commentedBut for the
'foo'
case (regular function),strpos()
is faster.