Problem/Motivation

@yched has reported slowness generating valid css class names in template_preprocess and was proposed a solution for this

   // Initialize html class attribute for the current hook.
-  $variables['classes_array'] = array($hook);
+  $variables['classes_array'] = array(drupal_html_class($hook));

But drupal_html_class also is slow and this runs on every template call.

Proposed resolution

A proposed resolution provided by @effulgentsia in comment #9 but was not approved by @Dries (comment #12)

Personally, I think this extra parameter is a little bit of a hack that degrades the DX.

And @webchick also agree with that at that moment (comment #50)

Last word on this patch was that Dries didn't like it, so once again leaving for The Spikey Haired One.

(Though I agree that it seems hackish, and it would also introduce an API change for people calling drupal_html_class() in order to take advantage of a 0.5% performance benefit outlined in #9. Not sure it's really worth it at this point, honestly.)

Remaining tasks

Patch in comment #28 fail, needs review.

Patch in comment #23 it's ok but needs approval. This patch changes the new parameter name from $underscores_only to $is_machine_name. To make to impression of less hacky.

Original report by yched

   // Initialize html class attribute for the current hook.
-  $variables['classes_array'] = array($hook);
+  $variables['classes_array'] = array(drupal_html_class($hook));

Not visible currently because the only templates that currently use $classes / $classes_array correspond to one-word theme hooks: theme('node'), theme('comment')...

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

yched’s picture

The remark above also means the patch won't change any existing markup nor break CSS or jQuery behaviors.

agentrickard’s picture

Status: Needs review » Reviewed & tested by the community

This is correct, according to the new API for class names.

webchick’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

Hm. Is it possible to write a test for this?

yched’s picture

Hmm, not sure how this can be tested right now, actually.
From the OP:
"the only templates that currently use $classes / $classes_array correspond to one-word theme hooks: theme('node'), theme('comment')..."
#499192: Fix display and forms for "Fieldable terms" changes that fact, but before this lands, I don't really see us defining a dummy test template just to check the class name :-/.

webchick’s picture

Status: Needs work » Fixed

Ok, fair enough.

Committed to HEAD.

yched’s picture

Status: Fixed » Needs review
Issue tags: +Performance
FileSize
917 bytes

Reopening, drupal_html_class() is slow, and this runs on every template call.

In this specific case we can be smarter - a valid theme hook name is [az_].
Sorry about that.

effulgentsia’s picture

Status: Needs review » Reviewed & tested by the community

Yes. This one's a no-brainer. The same hunk is in #652246-10: Optimize theme('field') and use it for comment body with a discussion about its impact. That hunk also has a more detailed code comment, if that's of interest. Makes sense for this hunk to land separately of that other issue which is still being worked on.

yched’s picture

Crap, I didn't notice that this change was already included in the perf measures over there. I was hoping we'd get a couple ms more :-(.

Agreed that it's best committed separately anyway.

effulgentsia’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
1.68 KB

Sorry for downgrading an RTBC patch, but whether in core or contrib, there's gonna be other places where only underscore -> hyphen conversion is needed and needed quickly (for example, template_preprocess_field()), and it would help code readability and greppability to still call drupal_html_class(). So, what do you think of this? If you don't like it, feel free to re-upload #6 and mark it RTBC.

Benchmarking front page with 10 article teasers:
HEAD: 82.46ms
Patch #6: 81.96ms
Patch #9: 82.00ms

There's definitely other pages with MANY more calls to template_preprocess(), but even for this simple page, there's >0.5% savings with either #6 or #9, and not much difference between the two.

yched’s picture

Status: Needs review » Reviewed & tested by the community

Fully agreed, this approach is better.

effulgentsia’s picture

Title: template_preprocess() generates invalid CSS classes » template_preprocess() is too slow in generating valid CSS class name
Issue tags: -Needs tests +Quick fix

Updating title and tags for #9.

Dries’s picture

Personally, I think this extra parameter is a little bit of a hack that degrades the DX.

moshe weitzman’s picture

Yes it is a tiny hack, but I think it is a bit much to say that it degrades DX. No developer outside of a core theme system hacker has to care about this. This is just the sort of hack that you have to accept in order to speed up core. My .02.

catch’s picture

Agreed. Bad DX is atrocities like hook_mail(), not optional parameters to largely internal functions.

Tiny, self-contained, documented hacks which only a handful of people will ever see but speed things up are completely harmless. Needless CPU usage on tens of thousands of servers running Drupal sites isn't. We don't have a lot of space to reduce PHP overhead for Drupal 7 despite it being so poor, so we need to do what we can.

effulgentsia’s picture

spam sucks (#15,#16).

webchick’s picture

Leaving for Dries to respond to this one.

sun’s picture

Status: Reviewed & tested by the community » Needs review

errr, an additional confusing argument for 0.04 ms? Are you serious, guys?

Patch #6: 81.96ms
Patch #9: 82.00ms

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

we said before that these benchmarks are done on a very simple page. they will be more favorable on real pages that theme the value every cell in a table (Views) or list lots of username and so on.

effulgentsia’s picture

Re #19: #6 and #9 are essentially equivalent performance-wise. Either one vs. HEAD is what's important (>0.5% on a simple page, more on complex pages as Moshe points out). Personally, I think #9 is better than #6 in terms of code readability, especially if we find places other than template_preprocess() that can benefit from the same optimization (and we most certainly will).

sun’s picture

ok, let's do this.

effulgentsia’s picture

@Dries, #12:

Personally, I think this extra parameter is a little bit of a hack that degrades the DX.

This patch changes the new parameter name from $underscores_only to $is_machine_name. Does that make it feel less hacky?

JohnAlbin’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
5.94 KB

The reason why drupal_html_class() wasn't originally included in template_preprocess() was because of the performance issues. I'm glad the bug (whoops!) was fixed in #5 above and I am totally cool with the added parameter. It means we can use a drupal_html_class() in more places without killing performance.

In fact, here's eff's patch with a few more places using the new is_machine_name parameter. I've also added a test for the new parameter.

Status: Needs review » Needs work

The last submitted patch, template_preprocess_class-680022-24.patch, failed testing.

JohnAlbin’s picture

Status: Needs work » Needs review
FileSize
5.94 KB

And here's the patch where the test that checks the $is_machine_name parameter is no longer broken and actually uses said parameter. :-p

Status: Needs review » Needs work

The last submitted patch, template_preprocess_class-680022-26.patch, failed testing.

JohnAlbin’s picture

Status: Needs work » Needs review
FileSize
4.99 KB

Bah. Attached the wrong patch in #26. This is the one I meant.

yched’s picture

Patch should be ready, it's now a question of whether we want to do this.
Back to RTBC for Dries / webchick. Discussion is in #12-#24 above.

sun’s picture

Status: Needs review » Reviewed & tested by the community

Ready to fly.

yched’s picture

Er, yes, that's what I meant. /me slaps himself.

catch’s picture

If we don't do this version of the patch, then we should go through and convert all the places that need the optimization to strtr(), per #6.

quicksketch’s picture

I know this is already RTBC, but we could we get one further change into this issue? Right now the template_preprocess() function is super-aggressive when it comes to creating these variables. Could we wrap them in an isset() check?

In template_preprocess():

   // Initialize html class attribute for the current hook.
-  $variables['classes_array'] = array(drupal_html_class($hook));
+  if (!isset($variables['classes_array'])) {
+    $variables['classes_array'] = array(drupal_html_class($hook, TRUE));
+  }

In theme.inc template_process()...

   // Flatten out classes.
-  $variables['classes'] = implode(' ', $variables['classes_array']);
+  if (!isset($variables['classes'])) {
+    $variables['classes'] = implode(' ', $variables['classes_array']);
+  }

BTW, what's up with a function named template_preprocess() and one with template_process()? I was literally looking for 5 minutes to distinguish the difference between the two names.

quicksketch’s picture

To elaborate on the problem in #33, I actually had a template that used a variable called "classes", that wasn't even related to CSS at all. It was literally an array of courses (as in for teaching). But because template_preprocess() runs on all templates, it kept blowing it away with the name of the template instead. I appreciate the "help" the theme system was providing, but it was a downright baffling experience trying to figure out what was happening to my variables.

effulgentsia’s picture

@quicksketch (re #33/#34): Let's discuss that in a separate issue, please. Please open one, post a patch, and link from here.

what's up with a function named template_preprocess() and one with template_process()?

The D7 theme() function preprocesses variables in two phases. It does all the *_preprocess()/*_preprocess_HOOK() functions first, as in D6. Then, new in D7, a 2nd phase where it calls *_process()/*_process_HOOK() functions. I'm not sure that "process" was the best choice for the name of the 2nd phase, but "postpreprocess" or "latepreprocess" have their own ugliness too. Too late for changing the naming approach for D7, but let's improve it for D8.

quicksketch’s picture

I'll wait for this issue to complete. I can't post a patch with the overlap. In the mean time I've just renamed the variable to "courses".

axyjo’s picture

Issue tags: -Performance, -Quick fix

#28: template_preprocess_class-680022-28.patch queued for re-testing.

It's been a long time since it was rolled. Let's see if it still applies/passes.

aspilicious’s picture

Issue tags: +Performance, +Quick fix
aspilicious’s picture

*Retesting old patches*

catch’s picture

Issue tags: -Performance, -Quick fix

old again..

sun’s picture

Issue tags: +Performance, +Quick fix
sun’s picture

Version: 7.x-dev » 8.x-dev

Although badly needed, this is D8 material according to the rules (I had to learn today). It may be backported at a later point in time (though that's unlikely).

mlncn’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Needs review

This is a performance improvement not affecting external APIs. Could have been committed months ago. If the testbot still likes it, it's RTBC for D7.

mlncn’s picture

mlncn’s picture

Status: Needs review » Reviewed & tested by the community

And it still passes. The test is a little ... weird, but back to RTBC. This is a performance enhancement that does not endanger any code, in core or contrib (if the extra parameter isn't passed, it works just the same as before). So a tiny API extension that rfay can decide if it even gets a mention ;-)

webchick’s picture

webchick’s picture

Issue tags: -Performance, -Quick fix
tom_o_t’s picture

Issue tags: +Performance, +Quick fix
moshe weitzman’s picture

1 failure in DrupalHTMLIdentifierTestCase

webchick’s picture

Last word on this patch was that Dries didn't like it, so once again leaving for The Spikey Haired One.

(Though I agree that it seems hackish, and it would also introduce an API change for people calling drupal_html_class() in order to take advantage of a 0.5% performance benefit outlined in #9. Not sure it's really worth it at this point, honestly.)

catch’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7
xjm’s picture

Tagging issues not yet using summary template.

catch’s picture

Status: Reviewed & tested by the community » Needs work

The last submitted patch, template_preprocess_class-680022-28.patch, failed testing.

xcafebabe’s picture

Issue summary: View changes

Creating an Issue summary for a concise overview of this issue

jiv_e’s picture

This issue seems to be completely outdated because of these changes:

https://www.drupal.org/node/2121713
https://www.drupal.org/node/1305882

The issue title is also confusing because it doesn't touch template_preprocess() function anymore. Reopen if you disagree with my decision to close!