Needs work
Project:
Drupal core
Version:
main
Component:
base system
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
3 Aug 2010 at 14:49 UTC
Updated:
2 Aug 2021 at 11:02 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
dalinComment #2
damien tournoud commentedHm. That should definitely not be. In what case have you bumped into this?
Comment #3
dalinForgot to mention that I'm profiling a D5 site, so things might be a bit different, but I think the general gist applies.
Comment #4
dalinComment #6
dalinFurther investigation tells me that on D5 the node form had a node element that was the object that caused the error plus some object from Panels 1.x.
In D7 this doesn't seem to be a problem. I've removed the casting, plus done the same for drupal_sort_weight() and a similar thing in element_children().
Here's my performance stats - total self cost on node/add/page. I switched back-and-forth to confirm:
element_sort()
with patch: .11%
without: 1.26%
element_children()
with patch: 1.89%
without: 2.86%
drupal_sort_weight()
with patch: .13%
without: 1.42
I ran through a bunch of tests on my dev site and all worked good, lets see what the test bot tells us.
Comment #7
moshe weitzman commentedNice catch.
Comment #8
webchickCurious. Does it make sense to explicitly specify the datatype of these function arguments now that we're not checking if they're arrays?
e.g. change:
to:
?
Comment #9
dmitrig01 commentedAccording to my testing it doens't make a difference - here are my results (test script is attached):
Also attached is a patch which adds the array parameters
Comment #10
dalinHmm interesting conclusion dmitrig01. I would've thought that internally it would be doing the same thing as is_array(). This seems to be the best of all worlds.
Comment #12
dmitrig01 commentedwoah i have no idea what happened here:
New patch should work.
Comment #14
dhthwy commented#12: 872680.patch queued for re-testing.
Comment #15
dhthwy commentedRemoving those array checks is a good idea if they aren't needed. Internally they result in multiple function calls > 4, none expensive by themselves but they add up quickly.
Comment #17
dalinI don't quite understand why the patch keeps failing. Test bot says that it can't even start up SimpleTest. It works on my dev install. The SimpleTest tests run as expected on my local install. And reinstalling SimpleTest works on my local.
Though it does appears that there are a plethora of places where we do have strings in the render arrays, for example in toolbar module:
These result in recoverable PHP errors.
I haven't really done much core development. What's the way to fix these: include fixes in this patch? Open one new cleanup issue? File individual cleanup issues?
I've also included a new version of this patch that removes a redundant array casting.
Comment #18
dalinErr, here's the patch.
Comment #20
catchSubscribing, unlikely to be able to look at this until next week though due to travelling.
Comment #21
c960657 commentedRelated: #639974: Speed up element_children() using array_multisort()
Comment #22
dalinSo we're not going to be able to do everything that we want in this patch. The proposed changes to element_property(), and element_child() will require all properties to start with # which is currently is not the case. Making that happen will require changes throughout the entire codebase which should probably wait till D8.
So the included patch is basically everything that we've talked about this in this issue, but only working with element_sort(), drupal_sort_weight(), element_properties(), and element_children().
Comment #23
dalinComment #25
dalin#22: 872680.diff queued for re-testing.
Comment #26
dalinTestbot gives a different result every time I tell it to re-test the same patch. Running cvs up on my local doesn't show any code changes so I'm not quite sure what the deal is.
Comment #28
aspilicious commented#22: 872680.diff queued for re-testing.
Comment #30
moshe weitzman commented#22: 872680.diff queued for re-testing.
Comment #32
moshe weitzman commentedWTF does this patch have to do with simpletest getting enabled. bot is on some extended bender i think.
Comment #33
moshe weitzman commentedComment #34
webchick#22: 872680.diff queued for re-testing.
Comment #35
webchickWell, bender or not, we can't put this in if it breaks testbot. Maybe ping boombatower, DamZ, or rfay and see if they can take a look.
Comment #37
damien tournoud commentedThis patch does fail (at least on PHP 5.3). At the end of the installation, I get:
On mostly every page, including on the modules page. That prevents the test bot from enabling the testing module.
Comment #38
dalinWeird. I ran a handful of simpletests locally before uploading the patch without issue. I'll look deeper into this today.
Comment #39
dalinSo it looks like there's some incompatibilities in modules that are included in the "standard", but not the "minimal" installation. Basically it's the "properties not prepended with #" problem.
This means that we won't be able to specify the datatype of the function arguments for element_sort() which is fine. We still have the basic performance gain, but without the gain in api consistency (and the smaller performance gain of not having to sort values that are really custom properties).
Lets see if this patch works.
Comment #40
dalinComment #42
dalinThis one fixes issues with the taxonomy admin form and drupal_sort_weight().
Comment #43
dalinWhoops, lets keep the debugging code out.
Comment #44
damien tournoud commentedFrankly, I would rather fix those "properties used without #", which is basically a bug.
Comment #46
dalin#43: 872680.diff queued for re-testing.
Comment #47
dalin@Damien agreed, adding # to all properties would be ideal. But we're talking 2598 tests failing in core (see #18). Plus it would be an API change, and so would affect contrib as well. I don't have a lot of experience with core development, but I don't think that would be an acceptable change, let alone doable before we're out of beta.
Comment #48
dalinAnyone else think we should fix all "properties used without #", or is this RTBC?
Comment #49
moshe weitzman commentedLast patch has lots of taxo changes. They are needed here?
Comment #50
dalinThe taxo changes are needed because we changed
And taxonomy.module was trying to do a drupal_sort_weight on an entire $form_state['values'] array. It looks like a lot of lines changed, but for the most part it's just indentation. We moved
if (isset($form[$tid]['#term'])) {earlier so that we only do drupal_sort_weight on the terms.Comment #51
moshe weitzman commentedMakes sense.
Comment #52
dries commentedI just committed #839556: Fix isset regression in tablesort, add tests, and cleanup theme_process_registry() which might conflict with this patch. Asking for a re-test.
Comment #53
dries commented#43: 872680.diff queued for re-testing.
Comment #54
giorgio79 commentedWhat's up with the testbot?
Comment #55
dalinTestbot was broken when Dries re-queued the patch, but it has since been fixed and the patch was tested and passed.
Comment #56
sunWhat happened to the regression that
isset($a['#weight'])
is TRUE, if $a is a string?
Powered by Dreditor.
Comment #57
dalinAh, good catch Sun. Array casting was in my original patch, but got lost somewhere along the way. This one adds that back in.
Comment #58
dalinI see that there's a function called element_sort_by_title() that is almost identical to element_sort() that we should be giving the same treatment to for consistencies sake.
Comment #59
dalinErr, here's the patch.
Comment #60
sunI skimmed the issue, but I don't see benchmarks, which prove that casting everything to an array is faster than is_array() - which would be a surprise to me. Sorry if I missed it.
Comment #61
dalin@sun in #0 I showed how the patch decreases the self-cost of element_sort(). Also attached is a benchmark using ab of the patch in #59 compared with head (all modules and blocks enabled, 10 nodes on the front page, page and block caches off, anon has all permissions). Benchmarks show ~2.3% improvement.
Also see #961908: Make drupal_attributes() faster where I used the same technique.
Comment #62
dalinAnd from what I learned in #961908: Make drupal_attributes() faster, we're supposed to have a space after a casting. This patch is the same as #59, but with that small formatting change.
Comment #63
dalinI believe this patch would get a benchmark of D6 vs. a benchmark of D7 to be equally performant. Would be nice to get this in before D7 ships (but we all know that a real world D7 site will be faster than an equivalent real world D6 site).
This patch has been RTBC before and only isn't now because testbot was momentarily broken. But I don't want to RTBC my own patch.
Comment #64
dalinComment #65
pounardActually, I found some inconsistencies in common.inc.
First, element_sort() and drupal_sort_weight() are duplicate functions.
The same form element_sort_title() and drupal_sort_title().
I did a really faster implementation of element_sort(), and merged all the duplicates functions.
I also did a lot of benchmarking (using xdebug, the best tool I think for) and it tells that element_children() is really a bottleneck for performances.
I did all this on my side, I did not known this issue exits.
See my patch for faster element_sort() implementation and functions merge (working on rc2 version actually).
EDIT: Sorry I did not do a patch using CVS because I had not a CVS on my box while doing this, I may redo it later if you really need to, thus this is not hard to read and merge there are really a few lines.
Comment #67
pounardNow that I read the full thread, I have some notes:
Comment #68
pounardHere is an even faster implementation for weight sorting:
This method does less tests than the previous. whatever is the type of $a, whatever the isset() returns true or not, the int cast will filter inconsistent types and return 0.
Then, this function, in best case, will do 2 if(isset()) and a int sub, in worst case will do 2 if(isset()), 2 int cast, and one int sub, without errors (untested on php 5.3, please tell me), which is quite fast.
I did some CLI tests, see attached file, it gave absolutely no errors on PHP 5.2.14 with default error handling set (so all notice should normally appear on the ouptut).
EDIT: This may not be revelant, but on let's say about 10 hits on my dev box on the same page (just displayying 10 nodes, no blocks), with RC2 implementation it gaves me PHP generation time scores between 550 and 700ms, with my patch it gaves me scores between 470 and 630ms approximatively, removing the lowest and the hightest scores which can be considered as statistic accidents and should not be taken into account. This leads to approximatively between 15% to 10% performance gain for a really simple and small page.
Comment #69
pounard#6 I would be pleased to know what tools did you use for benchmarking, I actually uses CLI scripts as a start, but then I already use xdebug profiles and kcachegrind time display to ensure my results, throught multiple hits, sometimes doing some statistics manually using dozens of hits on the same page. This is a method, but it's fastidious, any helper would be great to know.
Comment #70
dalinMy first thought was that @pounard's approach will cause different results than my patch. However closer examination reveals that none of the proposed solutions gives the same results as the current implementation. The attached test reveals this.
Therefore this issue has to get bumped to D8.
However the good news is that there must've been some other performance improvement gone into core that reduced the number of times per page that element_sort() is getting called. It's now only about .26-.5% of the page.
Also note that drupal_sort_weight() and element_sort() are *not* identical. One is looking for $a['weight'] the other for $a['#weight']. Kinda sketchy yes, but we can't fix that in D7 either.
Yes @pounard my workflow for benchamarking is quite manual:
- cvs_revert (my own little script to do the cvs equivalent of svn revert)
- refresh the URL in the browser with ?XDEBUG_PROFILE=1
- refresh webgrind and write down the total self cost of the function in question
- patch -p0 < 872680.diff
- refresh the URL in the browser with ?XDEBUG_PROFILE=1
- refresh webgrind and write down the total self cost of the function in question
- repeat
Comment #71
pounardYour test includes floats as weights, as I can remember weights are int, right? If not, my own patch can easily be fixed, either by casting as float (which then may be longer) either by not casting at all hoping the current form or elements array was not written by an idiot :) This should do the trick the revert to the original behavior. I think the second solution is better, developers will have notices or errors caused by their own code, which is kinda right here?
I didn't notice the slight difference between drupal_sort_weight and element_sort, this is my error here. If the difference is only a '#' char, then the same algorithm should be applied on both, and a strong comment should be added to both documentation functions to highlight that.
Whatever are the differences between all algorithmes, the fastest solution should be kept, even if the behavior changes slightly, it won't in most cases (usage of pure ints). Remember when you do your tests that elements array are all differents, and the results will vary among pages, so any kind of test should may be done over a random computed element array, I did that, see the code attached.
EDIT: Oh and I forgot, a test on only one page is not sufficient, it should be done on at least two very different profiles of page (a big form, a "normal" frontend page), with at least douzens of hit, using some average numbers as proof.
Comment #72
dalin@pounard D7 is frozen and no patches that modify the input or output of an API will be accepted unless they fix an honest to goodness bug. This issue is just about small performance tweak so it doesn't qualify.
But D8 is another matter. For D8 by all means, lets choose the fastest implementation and clean up any mess that it creates.
As for the specifics, yes weight can be a float.
Unfortunately it's not that simple. If you read back in this issue you'll see that we tried that approach very early on. But many places (even in core) do not properly use element arrays and so $a or $b may be a string instead of an array. See #951734 for more details.
If a proposed change is causing a performance increase so small that it requires benchmarking to that level of detail to prove, then your efforts are likely better spent elsewhere. Your proposed patch is clearly faster with just a few back-and-forths using a profiler on a few different URLs.
P.S. Don't edit your comments, no one will get email updates.
Comment #73
pounard@dalin: Ok for comment edition.
I must admin, I'm playing with D7 since beta3, and on all my testing environments, it's a lot slower than D6, and doing a lot of profiling, it this seems to be architectural because there is major bottleneck I could spot. I really think that 500ms to build a page, where the exact same site took 100ms using D6 is not acceptable.
IMHO this kind of performance improvement can easily gain up to 50ms on my environment, this is I think really *huge* and it worth the shot.
If you don't want to apply on core, I would understand, this is a reasonable choice, but I admit that I'll really apply this patch on any D7 install I will made because I can't neglect 50ms per page hit.
Not sure about that, what I meant is the real web environment has so much factors that can alter its behavior and speed, among all the layers a single page hit goes through that real benchmarking cannot be done in one hit, you'll always have many surprises if you stick to that, whatever the patch is.
Comment #74
pounardSo, you are telling me the real issue is that the core itself is buggy. If some code parts in core don't respect its own API, then it should be fixed, frozen or not. I'm an external developer, I tell you I can't rely on something I cannot trust.
Comment #75
pounardOk maybe my last comment was a little harsh, but that's the feeling it gaves me when I read something like this. I sincerely apologize for the reaction though.
Comment #76
dalinYeah fixing every single little bug before the product is shipped would be nice, however there will always be bugs. At some point you've just got to decide that the remaining bugs are known and small, freeze the API, and ship D7.
Comment #77
pounardThis is not only a bug, but a good performance improvement, however I understand your opinion and know this is the core way to deal with these kind of issues at RC phase. I respect that. I will still maintain some patches of my own an use them because I really can't neglect those 50ms.
Comment #78
kurund commented#62: 872680.diff queued for re-testing.
Comment #79
oriol_e9gWe still need some additional benchmarking and testing.
NR to see who thinks testbot.
Comment #80
sunThe difference between element_ and drupal_ ua_sort() helper functions is that the former checks a '#property' and the latter checks 'property'.
The drupal_ helpers need to be retained separately, as they're used in many places (not only in core).
Comment #81
oriol_e9gSo, I understand that we can only apply performance improvements.
Comment #82
oriol_e9gComment #83
jhedstromelement_sorthas moved toArraySort::sortByWeightProperty(), and the code doesn't appear to have been much refactored in there, so this could still be an issue.Comment #84
jeroentCreated a new patch for D8.
Comment #86
jeroentThis should fix a lot of the failed tests.
Comment #87
jeroentThis is the right patch.
Comment #89
mgiffordRe-uploading prior patch for the bots.
Comment #95
borisson_I really like this, but it still needs those benchmarks.
Comment #99
pameeela commentedComment #100
joachim commented> only to discover that yes it is necessary because sometimes the arguments are objects.
Is this still true?
If so, it looks like the patch will change the sort order of objects -- previously they would have been sorted as it the value was '' and now the value of the $key property is used.