Problem/Motivation

Function Name Calls Diff Calls
Diff%
Incl. Wall
Diff
(microsec)
IWall
Diff%
Incl.
MemUse
Diff
(bytes)
IMemUse
Diff%
Incl.
PeakMemUse
Diff
(bytes)
IPeakMemUse
Diff%
Current Function
Drupal\Component\Utility\Html::cleanCssIdentifier 0 0.0% -317 -3.5% 1,952 5.5% -490,304 -1434.3%
Exclusive Metrics Diff for Current Function 49 15.5% -25,416 -1302.0% 784 0.2%
Parent function
Drupal\Component\Utility\Html::getClass 0 N/A% -317 -100.0% 1,952 100.0% -490,304 -100.0%
Child functions
strtr -14 -25.0% -370 -116.7% -2,000 -102.5% -494,328 -100.8%
str_replace 42 75.0% 3 0.9% 5,360 274.6% 288 0.1%
array_keys 14 25.0% 3 0.9% 14,808 758.6% 1,384 0.3%
preg_replace 0 0.0% -2 -0.6% 0 0.0% 0 0.0%
array_values 14 25.0% 0 0.0% 9,200 471.3% 1,568 0.3%

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Task because nothing is broken.
Issue priority Normal, because just a little micro-optimization, but micro-optimizations can also add up.
Prioritized changes The main goal of this issue is performance.
Disruption Not disruptive for core/contributed and custom modules/themes.

Comments

dawehner’s picture

Title: Get rid of strtr in Html::cleanCssIdentifie » Get rid of strtr in Html::cleanCssIdentifier
StatusFileSize
new14.76 KB

This isn't that bad, given how few strings we render on the frontpage.

jibran’s picture

Status: Active » Needs review
jibran’s picture

Status: Needs review » Needs work

Needs rebase.

dawehner’s picture

Issue tags: +Novice

. Yeah we just need the html related changes.

The last submitted patch, 1: 2541102-1.patch, failed testing.

fabianx’s picture

Issue summary: View changes

Added beta eval

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new847 bytes

meh

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, RTBC!

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I think in this case a comment would be worth it here

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new14.94 KB
new748 bytes

Maybe something like this?

dawehner’s picture

StatusFileSize
new1 KB

Upload #8 with the interdiff from #11

The last submitted patch, 11: 2541102-11.patch, failed testing.

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

That works for me.

dawehner’s picture

Just a quick update. I did some profiling of /node/1 as a non admin user and there this strtr() call was almost a 1ms out of 140ms in total.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -78,12 +78,17 @@ public static function getClass($class) {
+    $identifier = str_replace('__', '##', $identifier);
+    $identifier = str_replace(array_keys($filter), array_values($filter), $identifier);
+    $identifier = str_replace('##', '__', $identifier);

If the passed in $filter = ['__'=>'_']; this does does something different than before. Why is $filter configurable?

joelpittet’s picture

+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -78,12 +78,17 @@ public static function getClass($class) {
     '_' => '-',
-    '__' => '__',

These both together is a pain in the ass, it's a legacy workaround for BEM support. I wonder how much damage it would be if we removed both?

I can open a new issue for that but just wanted to bring this up in light of the un-RTBC marked by it.

hussainweb’s picture

Status: Needs work » Needs review
StatusFileSize
new1.03 KB
new1.4 KB

Addressing the concern in #16, I want to see what fails if we remove the $filter parameter. From what I could see in PHPStorm, nothing is using it. It is probably a BC break, but I want to see if something breaks in core.

Status: Needs review » Needs work

The last submitted patch, 18: 2541102-18.patch, failed testing.

hussainweb’s picture

The only things failing are situations we are checking only in tests. These are the two replacements that fail.

1) Drupal\Tests\Component\Utility\HtmlTest::testCleanCssIdentifier with data set #0 ('abcdefghijklmnopqrstuvwxyz_AB...456789', 'abcdefghijklmnopqrstuvwxyz_AB...456789', array())
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789
+abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789

/var/www/d8task/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php:50

2) Drupal\Tests\Component\Utility\HtmlTest::testCleanCssIdentifier with data set #3 ('invalididentifier', 'invalid !"#$%&'()*+,./:;<=>?@...tifier', array())
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-invalididentifier
+invalid---identifier

/var/www/d8task/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php:50

Both of these replacements are passed in with an empty array for filter, which means there should no replacements. I am not sure if this is a required use case.

Of course, another option is that we only do str_replace('__', '##',...) if it is not set in $filter. Does that sound workable?

john cook’s picture

StatusFileSize
new1.92 KB
new2.14 KB

I have undone patch #18 and wrapped the double underscore replacements in a conditional statement.

I have also added a test to ensure that $filter = ['__'=>'_']; works as expected - from #16

john cook’s picture

The other way to fix #18 would be to change the tests.

Either \Drupal\Tests\Component\Utility\HtmlTest::testCleanCssIdentifier() should also test for !empty($filter) or \Drupal\Tests\Component\Utility\HtmlTest::providerTestCleanCssIdentifier() should provide NULL as the third parameter in the arrays.

Also, removing $filter from the \Drupal\Component\Utility\Html::cleanCssIdentifier() definition would be an API change.

john cook’s picture

Status: Needs work » Needs review
joelpittet’s picture

Just some more backup for this issue, noticed Twig is doing this change as well:
https://github.com/twigphp/Twig/pull/1818

Benchmark https://3v4l.org/PXWDg/perf#tabs vs https://3v4l.org/iuq1Z/perf#tabs

dawehner’s picture

@joelpittet
That is interesting!

fabianx’s picture

Status: Needs review » Reviewed & tested by the community

RTBC, looks great to me now.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -78,12 +78,21 @@ public static function getClass($class) {
+    if (!isset($filter['__'])) {
+      $identifier = str_replace('__', '##', $identifier);
+    }
+    $identifier = str_replace(array_keys($filter), array_values($filter), $identifier);
+    if (!isset($filter['__'])) {
+      $identifier = str_replace('##', '__', $identifier);
+    }

Given this is about a micro-optimisation we can actually go further. str_replace() has another parameter which is a count of how many replacements made. So we could define a variable $double_underscore_replacements and pass it to the first str_replace() and then only do the final str_replace() if it is greater than 0.

hussainweb’s picture

Status: Needs work » Needs review
StatusFileSize
new1.03 KB
new2.03 KB

Great idea.

alexpott’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -78,12 +78,22 @@ public static function getClass($class) {
+    if (!isset($filter['__']) && $double_underscore_replacements > 0) {

The isset check here now is not needed.

hussainweb’s picture

Status: Needs work » Needs review
StatusFileSize
new702 bytes
new2 KB

True.

dawehner’s picture

Indeed nice idea!

+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -85,11 +85,12 @@ public static function cleanCssIdentifier($identifier, array $filter = array(
+    $double_underscore_replacements = 0;
     if (!isset($filter['__'])) {
-      $identifier = str_replace('__', '##', $identifier);
+      $identifier = str_replace('__', '##', $identifier, $double_underscore_replacements);
     }
     $identifier = str_replace(array_keys($filter), array_values($filter), $identifier);
-    if (!isset($filter['__'])) {
+    if (!isset($filter['__']) && $double_underscore_replacements > 0) {
       $identifier = str_replace('##', '__', $identifier);

Does someone mind adding a quick comment about that micro opt?

cilefen’s picture

StatusFileSize
new585 bytes
new2.07 KB
dawehner’s picture

+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -90,6 +90,7 @@
+    // Replace temporary placeholder '##' with '__' only if needed.

I'd be more explicit: '... only if the starting string contained '__'

john cook’s picture

StatusFileSize
new2.1 KB
new798 bytes

Changed the comment to be more specific as suggested in #33.

dawehner’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Component/Utility/Html.php
@@ -90,7 +90,7 @@ public static function cleanCssIdentifier($identifier, array $filter = array(
-    // Replace temporary placeholder '##' with '__' only if needed.
+    // Replace temporary placeholder '##' with '__' only if the original $identifier contained '__'.

80 chars :(

john cook’s picture

Issue tags: +Documentation

Added the documentation tag for the DrupalCon sprint.

joshi.rohit100’s picture

Status: Needs work » Needs review
StatusFileSize
new2.11 KB
new839 bytes
cyberschorsch’s picture

Reviewing this at drupalcon barcelona

cyberschorsch’s picture

Status: Needs review » Reviewed & tested by the community

This looks good, liked the idea of alex :)

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 7ae23ca and pushed to 8.0.x. Thanks!

  • alexpott committed 5260279 on 8.0.x
    Issue #2541102 by dawehner, hussainweb, John Cook, cilefen, joshi....

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.