Problem
Drupal\Core\Template\Attribute has become a bit of a God class with too many responsibilities. Move CSS Class parsing code off to its own class and apply some speed improvements to the logic of the class.
Issue History Note
This issue ticket was began over two years ago with the Twig rendering system. There are references in the older patches to Twig Environment and the then concurrently being developed assertion system. As of the most recent patch these references are removed. This issue thread is maintained for needed context for the code reviewers. The remaining Twig issues have their own issues.
<?php
use Drupal\Core\Template\Attribute;
require_once 'autoload.php';
function providerTestAttributeData() {
return [
['&"\'<>' => 'value'],
['title' => '&"\'<>'],
['class' => ['first', 'last']],
['disabled' => TRUE],
['disabled' => FALSE],
['alt' => ''],
['alt' => NULL],
[
'id' => 'id-test',
'class' => ['first', 'last'],
'alt' => 'Alternate',
],
[],
];
}
$startTime = microtime(true);
// Your content to test
$attributesData = providerTestAttributeData();
for ($i=0; $i < 10000; $i++) {
foreach ($attributesData as $attributes) {
// Convert array to attribute object.
$attribute = new Attribute($attributes);
// Change Attribute.
$attribute->addClass(array('orange', 'blue'));
$attribute->removeAttribute('id');
// Cast to string.
$value = (string) $attribute;
}
}
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
echo "Execution time : $elapsed seconds";
Comment | File | Size | Author |
---|---|---|---|
#126 | 2444003-126.patch | 17.04 KB | MerryHamster |
#112 | 2444003-112.patch | 12.82 KB | Aki Tendo |
#104 | interdiff.diff | 7.04 KB | Aki Tendo |
#104 | 2444003-104.patch | 12.72 KB | Aki Tendo |
#102 | 2444003-102.patch | 8.38 KB | Aki Tendo |
Comments
Comment #1
tim.plunkettPer #2408013-19: Adding Assertions to Drupal - Test Tools., I think this should be rolled back into the parent issue, and this should be closed.
Comment #2
Aki Tendo CreditAttribution: Aki Tendo commentedDisagree because just as classes must not try to do too much, so too should individual tasks. The Assertion Handling ticket deals specifically with the resolution of the assertions. The Assertion tickets themselves, like this one, may end up numbering well over a hundred. We're talking about going over the entire Drupal 8 codebase over the next few years and finding spots where it will help our code development to have an assert statement. If all that material was bound to the Assertion Handling ticket that ticket would never be completed.
The scope of this may need to be expanded to handle the whole Template Core library though. An individual class likely is too specific, but I'm in a baby steps mentality.
Comment #3
tim.plunkettI'm asking for ONE (1) conversion to be made as part of the parent issue.
Comment #4
Aki Tendo CreditAttribution: Aki Tendo commentedAh. Makes sense. A good candidate for that would be the boot assertions.
Comment #5
Aki Tendo CreditAttribution: Aki Tendo commentedComment #6
Aki Tendo CreditAttribution: Aki Tendo commentedThe template assertions and the explanation of the services.yml snafu that inspired this whole project.
This patch can (and should) be tested without its parent however, if it fails it may be something other than the patch at fault. All I've done is insert assertion statements based on the PHPdoc lines and the assertions regarding the url and link generators. The testers run in ASSERT_WARN mode, and if they trip then either something is wrong with the test, or something is wrong with the code outside the assertion (that I'm not qualified to fix), or the PHP doc statements are wrong and least likely is the assertion is wrong.
Without it's parent there is no way for these assertions to become active and be trapped in actual use.
Again, these materials are here off in their own file to keep the parent from becoming monstrous in size.
Comment #7
Aki Tendo CreditAttribution: Aki Tendo commentedUpdated issue summary to conform with template.
Comment #9
Aki Tendo CreditAttribution: Aki Tendo commentedThe correction of these fails is a separate issue and will be reported as such. The assertion in question is working as designed assuming the php doc is correct.
Comment #10
Aki Tendo CreditAttribution: Aki Tendo commentedThis includes the patch at the tail of this ticket..
https://www.drupal.org/node/2449741
That fulfills both the failed tests and the assertion.
Comment #11
YesCT CreditAttribution: YesCT commentedneeds a beta evaluation (see instructions in the issue summary under the remaining tasks section) especially since this is a normal task and at risk for not being commitable.
#2449741: Drupal\Core\Template\Attribute->createAttributeValue does not always return instance of \Drupal\Core\Template\AttributeValueBase was marked duplicate of this. but it had test additions. I dont see those here. why not?
Comment #12
Aki Tendo CreditAttribution: Aki Tendo commentedIssue summary updated as requested.
Comment #13
Aki Tendo CreditAttribution: Aki Tendo commentedComment #14
Aki Tendo CreditAttribution: Aki Tendo commentedComment #15
Aki Tendo CreditAttribution: Aki Tendo commentedLot of changes, need to get a handle on what breaks on a system wide test. This patch is not up to snuff comments or code formatting wide - I just need to see how the test bots handle it. Also note - this particular patch is combined with it's parent. I'm unsure if I want to keep them divided any longer.
Comment #17
Aki Tendo CreditAttribution: Aki Tendo commentedAdded Beta eval.
Comment #18
Aki Tendo CreditAttribution: Aki Tendo commentedLast patch had a require statement I was using to pull var-dumper into PHP unit test I forgot to drop...
Comment #20
Aki Tendo CreditAttribution: Aki Tendo commentedCouple of fixes which locally look to be accounting for a least 3/4 of the errors - a bad regex and a failure to init the class array.
Comment #21
Aki Tendo CreditAttribution: Aki Tendo commentedComment #23
star-szrInterdiffs would be great for these @Aki Tendo for those following along at home :)
Comment #24
Aki Tendo CreditAttribution: Aki Tendo commentedThe last two I've tried to make had so many whitespace switchout notices I could understand what they meant and I wrote the code. The next patch I push will be properly formatted and will be the last one without an interdiff against previous patches, I swear. It will have an interdiff against itself and it's test code.
I'm not at a patch release point tonight as I end work, but this is what has been added.
1. TWIG. That should make themers happy. For the moment it is using its own internal templates and it starts a raw copy of twig with no Drupal extensions whatsoever. I plan to allow it to use the current theme's templates if I can accurately determine it is safe to do so. That or use an independent means of informing the fault system on were to find errors. Input on which to do appreciated.
2 Namespace changed. From Drupal\Core\Error to Drupal\Core\Fault Since "Error" refers to PHP's older trigger_error system it's a misleading name for the system. Fault however can apply to any of the three types.
3 Symfony Responder and Request are now used to compose the handler responses for consistency with the rest of the system. Note this means the fault system will require a clean copy of Symfony to work. It is not perturbed by issues in Drupal though. The assertion callback is now in a child class of Symfony's Response class.
4. The core of the parent system will be in three classes. Except for minor changes and additions, they are done.
# Additions I must make
I must get the system to close gracefully when Twig has a compile error against its own files.
Extensions to the unit tests
# Additions I'm mulling over as feasable in time for Drupal 8.0.x release
Translation file loading - this will work by simply looking in sites/default for a faults.yml file (formerly error.yml). That file can be in any language desired, and it's responses override those found elsewhere in the system. A method will be exposed that will be callable from the settings.php file to point the FaultHandler at a different local faults.yml file.
INPUT NEEDED!! Deprecation declaration - I know how to modify Drupal's base unit test class in PHPUnit and I believe simpletest to ignore trigger_error(' ', E_USER_DEPRECATED). This would allow deprecation throws to be put onto those methods scheduled for removal. The main ramification of this is production sites would need to run as E_ALL & ~E_USER_DEPRECATED instead of just E_ALL. Likewise the autotesters would have to be set up to note deprecation throws but not fail the test over them. Also, instead of coming up with error messages for these, the message string for them would be the projected removing version - for example
trigger_error('8.0rc1', E_USER_DEPRECATED)
The @deprecated php comment lets us know what's deprecated, but it doesn't let us know who's calling it. Clearing the way for that error throw solves this problem. Then again, maybe that should just get it's own ticket. Thoughts?
Comment #25
Aki Tendo CreditAttribution: Aki Tendo commentedI'm to the unit tests now, other problems are resolved - I think - though I won't *know* until the tests are running.
Comment #26
Aki Tendo CreditAttribution: Aki Tendo commentedMore changes
* Unrelated code from the Fault System library removed from this patch. What remains is what is needed by this patch's unit tests.
* The Attribute class has been converted to an array object - it was already implementing all of the interfaces. PHP's internal implementation of Array Object will run faster than the homemade one that has been replaced. The storage method now merely wraps copyArray to maintain BC.
* Class name validity assertion moved from the ValueBase class to Attribute.
* Null can now be passed to an attribute.
* Code formatting applied.
I was still having trouble with some tests locally unrelated - but since those same tests fail when I checkout head locally I'm going to see if it's just a local problem.
Comment #28
Aki Tendo CreditAttribution: Aki Tendo commentedChecking something. This patch should pass. If it don't, head is broken.
Comment #29
Aki Tendo CreditAttribution: Aki Tendo commentedThis should pass. The problem was the test suite requires XHTML attribute format to validate.
Comment #31
Aki Tendo CreditAttribution: Aki Tendo commentedThe tests that failed did so because they where checking for HTML5 style boolean attributes. The Attribute system cannot reliably be asked to provide alternating formats, and replacing XPath promises to be more difficult so the values these tests are looking for as been changed to XHTML.
Comment #32
Aki Tendo CreditAttribution: Aki Tendo commentedBetter title added.
Reminder, the patch above contains enough dupe code from the parent ticket to pass its own unit tests since those tests cannot be conducted without that supporting code.
Comment #33
star-szr@Aki Tendo much better title! :) To help patch reviewers, usually what folks do in cases like this is upload a second patch without the changes in the parent issue, ending with
-do-not-test.patch
to skip automated testing.Comment #34
Aki Tendo CreditAttribution: Aki Tendo commentedBut that would be patch 29. Should I re-upload it with that label?
Comment #35
star-szr@Aki Tendo no need, but in my opinion it needs to be clearer what you intend to get committed here versus on the parent issue. Basically reviewers don't generally like to review "dupe code", but from your comment I was initially under the impression that this patch also contained all the code from the parent issue, but it only contains some I guess? That feels messy in terms of issue/patch management.
The key takeaways I'm trying to get across are:
1. We need to be able to keep straight which code should live in which issue, because as things start to get committed we should try and avoid commit conflicts. I'm not saying you aren't doing this now, but from my perspective it's a bit opaque.
2. Others (especially reviewers, but if you hope to have collaborators as well!) should be aware via your issue comments when you are making patches combining code from multiple issues, and coming back to #1, we need to know how to strip down a patch to only the changes for this issue so that we can as a community review and eventually commit that code without its parent "dupe code".
Hope that makes some sense, just don't want this to get stopped up. Back to your regularly scheduled programming.
Comment #36
Aki Tendo CreditAttribution: Aki Tendo commentedUpdated the template patch to reflect the changes in its parent and the 7.0 compat changes which make the previous patch unappliable. As mentioned previously I had a git crash which lost my change record so I can't do an interdiff with the previous patch.
The do-not-test patch contains just the code relevant to this ticket. It isn't testable on its own though - the testing ticket includes the parent issue.
Comment #38
Aki Tendo CreditAttribution: Aki Tendo commentedSomehow the do not test patch ran when it wasn't supposed to. Full patch passed.
Comment #39
Fabianx CreditAttribution: Fabianx commentednit - exchangeArray() is way faster than setting every data via the set() calls (though most objects we create are empty anyway), but +1 to using ArrayObject.
Comment #40
Aki Tendo CreditAttribution: Aki Tendo commentedIt is faster but it does nothing to the incoming array, and neither does parent::_construct(). Take a closer look at offsetSet
There is a method to my madness up there - by doing that loop I force every value to pass through the validation and transformation performed by createAttributeValue.
Any call set done via $this[$var] = 'foo' will pass through offsetSet magically because of the ArrayAccess Interface.
Comment #41
Fabianx CreditAttribution: Fabianx commented#40: Hah, good catch, that was indeed a bug before setting the storage directly ... Thanks!
Comment #42
Aki Tendo CreditAttribution: Aki Tendo commentedOk, new class (And I guess a very minor API addition) added -- AttributeNamedId. This class monitors attributes named Id's, making sure they are of a valid format to be ID's, and making sure they are unique document wide (or in the case of Ajax responses they are at least unique within the dataset being transferred). These assertions will help diagnose certain JavaScript bugs - browser behavior when one or more elements share an ID is undefined.
There are three patches. The one that is being tested includes code from the parent ticket needed for testing to occur. Then there is the main template assertion patch for those just now reading the ticket. For those following along there is an interdiff with the version on post #36.
EDIT: Just noticed I didn't do a code standard sniff. I'll await the results of global unit testing to make that check.
SECOND EDIT: It occurred to me this class has the potential to issue random ID's safely to doc elements. I've seen jQuery and prototype both do this from time to time. Is there a usage scenario for this? The way I would implement this is simply $attribute['id]->randomize() with the function returning the assigned ID. Before I place that logic though I'd like to know a use case for it because at the moment I can't think of any useful application which makes it code bloat. Also, the presence of the feature would force the ID's issued to need to be tracked in production.
Comment #44
Aki Tendo CreditAttribution: Aki Tendo commentedI've double checked the failure output against several of the pages the fail is reported when the patch is *not* installed - there are indeed multiple pages with repeated id's in the system. Hence the AttributeNamedId class cannot be added to the system until these errors are removed.
A separate issue has been created for this problem.
Comment #45
Aki Tendo CreditAttribution: Aki Tendo commentedUpdating issue tags now that I have a better understanding on what they should be.
Also changing back to Needs Review. While the id issue is decided the previous working patch without AttributeNamedId (#36) can still be committed.
Comment #46
Aki Tendo CreditAttribution: Aki Tendo commentedChecking on exactly how many test fails was solved by fixing the simpletest master page id duping. If this works I'll do a more formal interdiff post.
Comment #48
Aki Tendo CreditAttribution: Aki Tendo commentedAs of this post, dividing the ticket. The Attribute work runs deeper than I anticipated as the newbie coming on board, and far out scopes what this ticket was originally meant for - simply adding some asserts to TwigExtension. So the patches attached address just that problem which was the original goal of this ticket. The assertion work will move to a new ticket I'll link up from here when it's ready, since it's massive.
The "asserts-only" is just this ticket's code. The other ticket includes supporting code from the parent ticket.
Comment #49
Aki Tendo CreditAttribution: Aki Tendo commentedComment #51
Aki Tendo CreditAttribution: Aki Tendo commentedThis is a start over. No assertion aware tests have been added to this ticket yet - they may not be needed since all the assertions are of the very straightforward 'is_a' variety. We do check to see if the urlGenerator is set.
Any assertions that fail on this preliminary search will be assigned their own child tickets and removed from this one. PHP Units have passed.
There is (and will be) no work on the Attribute classes in this ticket anymore.
Comment #52
star-szrThat's easier to review :) Thanks @Aki Tendo. Some comments below.
This looks out of scope unless it's needed for some reason.
Same with these changes? Again I may be wrong if they are needed for some reason but otherwise they are bloating the patch.
I think there is an extra space here between the opening parenthesis and
\Twig_Token
.Comment #53
Aki Tendo CreditAttribution: Aki Tendo commented1 is just a tiny optimization - I'll roll it back if desired. 2. is a code standards violation - I can't get phpcs to validate the changes unless I do that. 3 I can fix (I hadn't ran phpcs over the file yet.
Comment #54
star-szrFor #52.2 adding
public
to the methods is the only change that this patch makes in TwigNodeVisitor (that I can spot, anyway). So the changes to that file should be reverted altogether. Problem solved? I can't tell exactly how you're using phpcs to validate things though :)Comment #55
Aki Tendo CreditAttribution: Aki Tendo commentedChanges made.
Comment #56
Aki Tendo CreditAttribution: Aki Tendo commentedComment #57
star-szrI guess that's including code from the parent? Not sure how things are broken down. Anyway, interdiff looks good.
Comment #58
Aki Tendo CreditAttribution: Aki Tendo commentedYes. This particular assertion group doesn't need it's parent, but I accidentally merged it in anyway.
Comment #59
Aki Tendo CreditAttribution: Aki Tendo commentedWith the parent now in core, this should be a final re-roll. A followup ticket will adjust TwigExtensionTest to actually test the assertions being added here, but those assertion tests require #2536560: Runtime Assertion unit and functional testing to run.
NOTE: The .htaccess file in the patch has the assert flag set to 1 due to an issue with the test bots. This file change should not be included in the final commit to core.
Comment #60
Aki Tendo CreditAttribution: Aki Tendo commentedReuploading patch to force the test bots to eval.
Comment #62
geertvd CreditAttribution: geertvd at XIO commentedComment #63
borisson_Reroll of #60 attached.
Comment #64
Aki Tendo CreditAttribution: Aki Tendo commentedI forgot to note in this ticket that I'm splitting it up by class in attempt to speed things along. Should be able to get some work in on this after work (in about 12 hours)
Comment #65
Aki Tendo CreditAttribution: Aki Tendo commentedEnvironment work split to #2555549: Assertions in \Drupal\Template\TwigEnvironment
Comment #66
Aki Tendo CreditAttribution: Aki Tendo commentedExtensions work split to #2558079: Assertions in \Drupal\Template\TwigExtension
Comment #67
star-szrComment #68
joelpittet@Aki Tendo what's the status of this Meta? Should we move to try to do this in 8.1.x or do you think it stands to be achieved in the 8.0.x RC cycle?
Comment #69
Aki Tendo CreditAttribution: Aki Tendo commentedBoth sub tickets are ready, but Alex Pott stated in IRC he doesn't want to introduce any further assertions during the RC cycle. So 8.0.1 I guess is earliest possible - I dunno for sure.
Comment #70
joelpittetOk let's postpone on 8.0.0 release and pick-up after that. Thank you for checking into that.
Comment #71
joelpittetComment #73
Aki Tendo CreditAttribution: Aki Tendo commentedBoth child ticket patches for this work with 8.2.x, so I'm not sure this necessarily needs further postponement - it can probably be worked in.
Comment #76
Aki Tendo CreditAttribution: Aki Tendo commentedI'm working on this again, stripping out the disruptive stuff and leaving behind the optimizations.
Comment #77
Aki Tendo CreditAttribution: Aki Tendo commentedOk, new patch. The scope of this patch has been changed to just the optimizations for the Attribute classes. Twig related stuff will be handled off in their own patch.
I massively rewrote the issue summary so please check that.
Comment #78
Aki Tendo CreditAttribution: Aki Tendo commentedComment #79
Aki Tendo CreditAttribution: Aki Tendo commentedComment #81
Aki Tendo CreditAttribution: Aki Tendo commentedOk, Let's try that again with the Safe Markup branch of createAttributeValue properly implemented. Hopefully this test won't look like an explosion in a mattress factory.
Comment #83
Aki Tendo CreditAttribution: Aki Tendo commentedDropping AttributeBoolean and AttributeString. The former because it's gross overkill, the Attribute class can handle it with less overhead and lines of code than having a new class. The latter because its misleading - String was the catch all for anything not handled by another class since Attributes are written as string. The logic for this is now in Attribute class.
Render is removed from the interface and all classes. Attribute is responsible for rendering. This allows these helper classes to be ignorant of their names which cleans up the copying code of Attributes between elements.
Comment #84
Aki Tendo CreditAttribution: Aki Tendo commentedComment #86
Aki Tendo CreditAttribution: Aki Tendo commentedSeeing if the file name itself is the reason the patch won't work.
Comment #88
Aki Tendo CreditAttribution: Aki Tendo commentedTrying creating the patch from the command line rather than using sourcetree.
Comment #89
Aki Tendo CreditAttribution: Aki Tendo commented88 is going to fail, so here's 90. Git on Windows puts garbage before and after the diff calls, so I trimmed out the garbage. Maybe this will apply. Stupid Windows.
Comment #92
Aki Tendo CreditAttribution: Aki Tendo commentedAnother try. At least the patch is applying now.
Comment #94
Aki Tendo CreditAttribution: Aki Tendo commentedPerhaps the reason these outside tests are failing is I'm trying to refactor too much. So the AttributeValueInterfaces for all not null objects are back in place.
Comment #96
Aki Tendo CreditAttribution: Aki Tendo commentedAttribute must be able to accept objects with ArrayAccess.
Comment #98
Aki Tendo CreditAttribution: Aki Tendo commentedAgain.
Comment #100
joelpittet@Aki Tendo, just a tip, don't take it as a must do, but there is a issue queue trick I've seen some people do when trying to fire the testbot with lots of patches is to create a patch ignore issue set to Priority minor and dump all their tests in it. It's a show your work vs not thing I guess.
Here's one of mine for example: https://www.drupal.org/node/2465399
And all the other ones
https://www.drupal.org/project/issues/search/drupal?text=ignore&assigned...
Comment #101
joelpittetYou're getting close on this, but I'm a bit afraid of the changes in there that change the tests which gives a code smell of API change which is much harder to make a case for and could break people's sites. Also the
booleanAttributes
change in there seems to limit the scope of the boolean attributes to HTML when this could be used for XML as it was written.Clearing attributes with
clear()
sounds interesting but that sounds maybe a bit out of scope.Don't want to discourage the work you are doing because it's great to experiment like this but the more changes makes it harder get in. Can we keep the scope of this to the issue title so we can test that one change and get it in?
Then spin off follow-ups for the other ideas?
Particularly in the issue summary I'd like to keep these two items till later:
Comment #102
Aki Tendo CreditAttribution: Aki Tendo commentedOk, I'll do that. This patch only converts Attribute to an ArrayObject. I also modified the remove attributes test to work with the attributes being correctly unset. The test was calling assertEmpty but that isn't correct - Empty means the key is still set but the value is nulled out or an empty string. The original code and the comments imply that a test of whether the key was unset is needed.
The source of the problem was Attribute::removeAttribute() wasn't unsetting the keys.
Comment #103
joelpittetNice work this looks much more managable. I think the test changes here make sense and kinda unsure how they worked before the way they were written but I would suggest maybe
assertArrayNotHasKey()
instead if you think that makes more sense?Shouldn't *not* adding this do effectively the same thing or am I missing something? Also, the coding standards should be addressed here, can't remember the method call standard but I think it's ::offsetSet().? If you can clarify why this is being added, maybe the clarification needs to be added to the comment.
assertArrayNotHasKey(key, array)
instead?Comment #104
Aki Tendo CreditAttribution: Aki Tendo commentedOk, concerns above addressed. I forgot that assertArrayNotHasKey would work with an array object. Test coverage also expanded, see interdiff. I added the AttributeValueInterface so that I wouldn't have to turn around and rewrite my new tests in a future patch, but for the moment it's only attached to AttributeValueBase. Eventually it will replace that class.
EDIT: I changed the constructor out since I realized that wrapping must occur after exchangeArray is called as well. The unit tests make it clear why the wrapping must occur. Remember that the original constructor did a foreach loop to apply createAttributeValue as well instead of just piping the submitted array into storage.
QUESTION: Attribute will pick up the default ArrayObject implementation of the serializable interface after this patch. Should we test this in any way?
Comment #105
Aki Tendo CreditAttribution: Aki Tendo commentedUpdating the issue description to entail exactly what work is being done on this ticket.
Comment #106
joelpittet@Aki Tendo I don't think we have to test a feature we don't yet have a specific use-case for. That's just my opinion.
Going to run a performance test on this with xhprof-kit, feel free to try this too.
https://github.com/LionsAd/xhprof-kit
Comment #107
joelpittetWhile setting up my performance test I noticed that with the patch the attributes were getting double escaped. We should probably resolve that first and add a regression test. See the screenshot. Cache was rebuilt between screenshots.EDIT: ignore me, that was another patch that snuck into things.
Comment #108
joelpittetIgnore that, back to performance testing;)
Comment #109
Aki Tendo CreditAttribution: Aki Tendo commentedComment #110
joelpittetNeed someone else to confirm but I got some bad numbers in a performance test.
Running with
PHP 5.6.27 (cli) (built: Oct 14 2016 13:57:41)
On the
8.4.x
branch I got this: 2.45 seconds between 2.69 secondsOn the
2444003-104
branch I got: 12.80 seconds and 13.32 secondsHere's the drush script:
attribute-performance-test.php
Run the code above in your root on each branch with the following command:
drush src attribute-performance-test.php
Comment #111
Aki Tendo CreditAttribution: Aki Tendo commentedI couldn't get the script to run under kalabox so I modified it to run off my site's root using PHP directly. In that configuration the tests still favor the old code, but only by a tenth of a second. Seeing if I can get that last tenth back.
Whatever you name the script as you can invoke it with the PHP cli.
Comment #112
Aki Tendo CreditAttribution: Aki Tendo commentedThere was a notice error being raised when attempting to unset a not set element that slowed down the new code noticeably. Old code still edging it out, which doesn't make much sense since ArrayObject is implemented in C++
Comment #113
Aki Tendo CreditAttribution: Aki Tendo commentedHere's the interdiff for that.
Comment #114
joelpittetThanks @AkiTendo. I upped the loops to 100,000 from 10,000 to get some significant figures but the change and disabling xdebug helped.
With Patch:
Without Patch:
Which is still about 20% slower, but a hell of a lot better than 520% slower!
Comment #115
Aki Tendo CreditAttribution: Aki Tendo commentedI'm going to continue with the CSS class modification layer and see if the speed loss here can be gained back in that optimization since a large part of your test is passing through the CSS class code which is also slated for rewrite in this series of patches.
Comment #116
Aki Tendo CreditAttribution: Aki Tendo commentedOk, I've started over, running the speed check with each change. I'm going to move away from implementing \ArrayObject. So far I've picked up a 1/2 second improvement on this test:
The largest change to this test is I'm also testing attribute cloning efficiency. That's testing this:
The other change (and the one that makes an interdiff unreadable) is the createAttributeValue is removed in favor of putting it's logic directly into offsetSet, saving a function call on the stack. So far this line looks promising - 5.11 seconds on the old code, 4.5 seconds on the new. If the cloning efficiency check is skipped the speed improvement is a more narrow 3.4 for the old code, 3.2 for the new.
Comment #117
joelpittetJust for your curiosity this class re-implements an ArrayObject in PHP, would be interesting to run tests between the two.
vendor/symfony/validator/Tests/Fixtures/CustomArrayObject.php
Comment #118
Aki Tendo CreditAttribution: Aki Tendo commentedAfter speed tests failed it became clear that cleanly converting the class over to /ArrayObject comes with too large a performance loss. This next patch falls back to the basic task of doing the other optimizations of the class outside that conversion, including the splitting off of CSS Class related code to it's own class.
Since I started over after the last patch failed speed trials an interdiff won't be useful.
Comment #119
dawehnerUnneeded changes. We have our own issue for those.
This should contain some explantation about why this is done here.
This could be an elseif here, and actually they entire branch could me merged with the outer else
Why would args ever be empty?
Would setting $this->storage['class'] instead of $this['class'] be faster?
This could be inherited from the parent, I guess?
Comment #120
Aki Tendo CreditAttribution: Aki Tendo commented@dawehner
1. Ok, reverted
2. Added (see interdiff)
3. That speeds things up noticeably, so good catch.
4. Line 156 of Drupal\Tests\Core\Template\AttributeTest calls the function with no arguments and checks to see if we have no class key afterward. So, for the moment, fulfilling the test. We can probably get away with removing the test - class doesn't render when empty whether it's set or not. I don't know which of the other tests in the system might not like that change though - I'll try it if wanted.
5. It is.
6. K, done.
Comment #123
markhalliwellPatch no longer applies.
---
Semi-on topic. I've been working on improving this as well in https://cgit.drupalcode.org/plus/tree/src/Utility/Attributes.php?h=8.x-4.x
It'll require us to implement our own ArrayObject class, but I think it'd be better to completely re-think how we're doing attributes in general (plural, the
Attribute
class is misleading).This work will likely be needed in #2869859: [PP-1] Refactor theme hooks/registry into plugin managers.
Comment #124
markhalliwellComment #126
MerryHamster CreditAttribution: MerryHamster at Skilld for Skilld commentedReroll patch from #120 for 8.7.x
Comment #127
MerryHamster CreditAttribution: MerryHamster at Skilld for Skilld commentedComment #129
savkaviktor16@gmail.com CreditAttribution: savkaviktor16@gmail.com at Skilld commented