We currently have what I consider to be a serious problem. We introduced the drupal_static() construct in order to encourage most static variables to be resettable. Some need to be resettable just for normal page execution, and others benefit from being resettable in order for certain kinds of tests to be written with a controlled environment. However, for functions that get called hundreds of times per page request, the overhead of drupal_static() becomes noticeable, and in these cases, there's a tension between using it (and playing nice with simpletest) and not using it (and accepting the corresponding limitations to testing). And in some cases, important patches are in limbo, while we debate whether testability or performance is more important, and if both are, whether the benefit of the patch is worth the performance loss.
Example 1: #320331: Turn custom_url_rewrite_inbound and custom_url_rewrite_outbound into hooks was committed adding a drupal_alter() step to every url() invocation, causing a marked increase to the time it took that function to run. When drupal_alter() added support for alter functions from themes, this got even worse. Then (just recently, and I'm not sure from which issue), url() added non-resettable static caching as to whether drupal_alter() needs to be called. The argument is that code can't be unloaded during a page request, but do we really not want to support simpletests that change which modules are enabled? Plus the static caching in url() doesn't take into account alter functions from themes.
Example 2: #601806: drupal_render() should not set default element properties when #type is not known is a really nice cleanup. But it's spinning in circles around the question of whether the performance impact is ok, and/or whether it's ok to use non-resettable static caching to mitigate it.
My proposal in a follow-up comment.
| Comment | File | Size | Author |
|---|---|---|---|
| #5 | drupal_static-620452-5.patch | 7.67 KB | effulgentsia |
| #3 | drupal_static-620452-3.patch | 7.67 KB | effulgentsia |
| #1 | drupal_static-620452-1.patch | 6.28 KB | effulgentsia |
| #1 | benchmark_url_theme_render.txt | 3.13 KB | effulgentsia |
Comments
Comment #1
effulgentsia commentedAttached is my proposed solution. It changes drupal_static() to save its data in a global variable. According to @sun in http://drupal.org/node/601806#comment-2212386, this has been shot down in #254491: Standardize static caching, but I skimmed through that issue and couldn't find the arguments against it. This patch still maintains the drupal_static() interface for writing to the variable. But for reading, it allows the existing interface to be used OR the more direct way of checking a global variable for functions that need to be fast. My thought is that we need something like this, or else we need to clarify when non-resettable statics are okay, and where they're not, and then we need to be okay with the performance hit of resettables, and not refuse important patches because of that performance impact.
I'm attaching a micro-benchmarking script. Here's what I got on my computer (times are in micro-seconds per invocation, averaged over a lot):
The patch introduces virtually no performance impact to url(), while making the alter() step re-settable, and the patch removes most of the performance difference between a drupal_render() of an element without a type vs. one with a type, while maintaining resettability, hopefully, clearing the path to #601806: drupal_render() should not set default element properties when #type is not known being solved in a way that works for everyone.
Comment #3
effulgentsia commentedHow about this one, bot?
Comment #5
effulgentsia commentedI can't replicate the invalid syntax error locally, but perhaps some weird invisible mac character made its way into the file. Trying again.
Comment #6
catchSimilar issue here #537724: Consider $GLOBALS['drupal_static'] instead of drupal_static().
Comment #7
moshe weitzman commentedIMO, this global is very bad form. We need a function where we can monitor changes to the $static array. Without that, you are just in grep hell trying to figure out when a value was added/removed/changed in the static array.
Comment #8
effulgentsia commented@moshe: while PHP won't let us enforce this, my recommendation is to always use the drupal_static() function for writing to the variable (or retrieving a reference for writing to it), and to continue to use the drupal_static_reset() function for resetting. The only change would be to allow a few functions which get called very often to be able to read directly from the global. Please see patch for the code details on this. Does this work for you, or does the lack of PHP's ability to prevent direct writing to the global make this a no-go for you?
Comment #9
catchThere's also #619666: Make performance-critical usage of drupal_static() grokkable which doesn't use the global.
Comment #10
moshe weitzman commentedI can't really stomach all the complexity thats going in right now. This is an exception to an already complex pattern. Contrib devs will use
&drupal_static(__FUNCTION__, array());if they have to, but if we give them a global to mess with, they will happily mess. I'll let others decide this one. I won't be too chuffed either way.Comment #11
effulgentsia commented@moshe: I want to take your gut reaction seriously. Does #619666: Make performance-critical usage of drupal_static() grokkable work for you (either the original patch or #6)? Either one would need further refinement, but the key thing being that the return of drupal_static() being something that can itself be persisted and guaranteed to revert to NULL after a call to drupal_static_reset(). If that seems less prone to contrib devs running amuck, I'll happily mark this issue a duplicate, and let community effort focus on that one instead.
Comment #12
moshe weitzman commented@eff - #619666: Make performance-critical usage of drupal_static() grokkable looks pretty complex too. sorry i can't be of more help here. do whatever makes sense to you.
Comment #13
effulgentsia commentedWe can simplify #619666: Make performance-critical usage of drupal_static() grokkable if that's what people want. I'm sold on a global being more easily abused than the solution in that issue. Therefore, marking this as duplicate.