Spin-off from #438570: Field API conversion leads to lots of expensive function calls (comments #52 and below)

Attached patch:
- introduces hook_field_formatter(), instead of previously theme_field_formatter_*() functions. The hook returns a render array. Basic formatters just return some '#markup' = $output, while more advanced formatters can still go through a theme call if ant to provide ease of overridability.
Better performance (less theme calls), and also makes formatters and widgets much more alike.
- does not remove hook_field_sanitize(), there will be use cases for that. Only, this is not where formatters sanitize their data anymore (the hook was lame at that task anyway, since its a field hook, not a formatter hook)
- Side gain: streamlines field_default_view() and the overall structure of the render array returned by field_attach_view() / field_default_view() - see the PHPdoc of f_a_view().
- while breaking formatter APIs, rename hook_field_formatter_prepare_view() to hook_field_formatter_prepare(). For formatters, 'view' is implied.
- changes existing core formatters to the new API.

Still a couple documentation @todos, but posting what I have so far for bot and peer review.

Comments

yched’s picture

Notes about the last item: "changes existing core formatters to the new API"

- @quicksketch: the choices I made for image and file field formatters could use an approbation from you, regarding "which formatters are simple enough to return a simple #markup value / which formatters deserve to go through a theme function". Probably not a blocker, though.

- @bangpound/quicksketch: I left a remark in a @todo note in taxonomy_field_formatter(), needs your feedback.

yched’s picture

Status: Active » Needs review

Status: Needs review » Needs work
Issue tags: -Performance

The last submitted patch failed testing.

Status: Needs work » Needs review
Issue tags: +Performance

yched requested that failed test be re-tested.

yched’s picture

StatusFileSize
new47.32 KB

"Invalid PHP syntax in locale.field.inc."
No way.

Rerolled.

effulgentsia’s picture

See #538164-127: Comment body as field: at least for comment body as field, it's not promising yet, but let's keep exploring.

yched’s picture

doh ? degradation ?
Hmmm. I could use confirmation on a frontpage with 10 nodes (see #438570-60: Field API conversion leads to lots of expensive function calls)

Status: Needs review » Needs work

The last submitted patch failed testing.

effulgentsia’s picture

Status: Needs work » Needs review

devel_generate is failing to add node body, so i manually created 10 article nodes (title = "Article #", body = "Body").

HEAD: 99.5ms
Patch 5: 98.2ms

catch’s picture

Status: Needs review » Needs work

Subscribing.

effulgentsia’s picture

Status: Needs work » Needs review

And for anyone else wanting to help with benchmarks, here's the fix to devel_generate: #652898: Small fix so nodes can be generated with field data

effulgentsia’s picture

Status change was unintentional.

yched’s picture

StatusFileSize
new47.32 KB

Slave #32 insists to report a PHP syntax error in locale.field.inc that I cannot see with eyes wide open.
Rerolled, re-upload, hoping I'll get a different slave ?

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new47.33 KB

Heh, embarrassing that DamZ had to put my nose on it... no function calls inside empty()...
New patch.

Additionally: #538164-127: Comment body as field reported fairly disappointing benches for this on 'comment body as field' (slight *degradation* ?), while an earlier proof-of-concept patch showed encouraging results in #438570-60: Field API conversion leads to lots of expensive function calls.

So sorry to ask for a confirmation benchmark...
Test scenario:
1) 10 article nodes with just a title and a body - devel's 'generate' feature should be just fine, just be sure not to add taxo terms to the created nodes.
2) disable page cache
3) view the frontpage once to fill in field cache (to benchmark the 'display' side more accurately)
4) benchmark 500 page views of the front page as an anonymous user
5) apply patch
6) devel 'clear cache'
7) repeat steps 3) and 4)

effulgentsia’s picture

@yched: Not the exact sequence you outlined, but #9 has my system's benchmarks for home page with 10 article nodes.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new47.4 KB

Attached patch fixes some but not all failures yet.
Leaving to CNR for peer review of the code, though.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new47.4 KB

doh, forgot the .txt extension so that bot leaves it to CNR.

yched’s picture

Dries left us til tomorrow to get this straight.
I'm working on the last test failures, but I could use some help with code reviews and benchmarks...

yched’s picture

StatusFileSize
new50.12 KB

Strange thing in forum tests where the taxonomy formatter is called without field_attach_prepare_view() being called (raises warnings), while it doesn't happen in HEAD right now. Beats me for now, so I added temporary workaround code to handle this case in the taxonomy_field_formatter().
+ Fixed the other fails / warnings.

I won't be able to push this further today, so reviews + benches (see #16) really welcome.

Status: Needs review » Needs work

The last submitted patch failed testing.

yched’s picture

Status: Needs work » Needs review
StatusFileSize
new50.43 KB

Last exception, similar reason - taxonomy formatter is called without field_attach_prepare_view() being called.
Trying to figure out why current HEAD doesn't raise those, but this is an occurrence of the more general "single node_build() call doesn't trigger field_attach_prepare_view()" (#493314: Add multiple hook for formatters)

yched’s picture

Got it. When adding a comment to a node, comment_reply() does a node_build(), but the render array is never actually rendered, because we are redirected to the node page - I'm not sure why that is, BTW, buidling a node to ditch the result sounds like CPU waste. Separate issue, though, created #654854: Clean up conditions in comment_reply(), avoid node_view() when unnecessary..

So:
- In HEAD, the formatter (theme function for an element in the array) is not executed since the array is not rendered, and hook_formatter_prepare_view() not having run has no actual consequence.
- with patch, the formatter (code returning a render array) is executed when building the node, and thus bumps on hook_formatter_prepare_view() not having run beforehands.

So the workarounds in the patch (let the formatter load the missing bits) are correct for the current situation, and "node_build() doesn't trigger field_attach_prepare_view()" should be tackled in #493314: Add multiple hook for formatters - or #636992: Entity loading needs protection from infinite recursion, which touches the area.

yched’s picture

As I said in the OP, patch still has a couple documentation @todos, but is ready for review.

sun’s picture

Looks pretty cool.

However, I don't really understand why it's called 'formatter'. A hook_field_format(), or better yet, hook_field_view() would make much more sense to me. I guess that back then when this was introduced, CCK wanted to be extra cool and figured that, hey, all the other shit is old shit and we have quite a lot new shit, so let's call it "formatter", because "viewing" stuff is lame and in general associated with old-school shit, and we are absolutely new-school shit, so we don't view, no, we implement auto-formatting robots that are totally different than viewing a field, errr, are they? Anyway, who cares, this is cool.

Probably a separate issue. ;) If you fill out the @todos, then we're probably set. :)

sun’s picture

errrrr. Now I even have to realize that it would have to be hook_field_build() and hook_field_build_multiple() in D7, because that's the common name for such functions. Ah well, it all takes some time to get used to. ;)

catch’s picture

Generated content with devel, each just has a body field, hit the front page with ten of them.

I could only measure around a 2% improvement. However if that equates to a ten percent improvement with 5 fields per-node instead of one, then that's really good to have. 5 fields isn't many at all.

HEAD:

Concurrency Level:      1
Time taken for tests:   103.634 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22663000 bytes
HTML transferred:       22198000 bytes
Requests per second:    9.65 [#/sec] (mean)
Time per request:       103.634 [ms] (mean)
Time per request:       103.634 [ms] (mean, across all concurrent requests)
Transfer rate:          213.56 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    95  104   7.6    101     160
Waiting:       88   96   7.2     94     153
Total:         95  104   7.6    101     160

Time taken for tests:   104.010 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22663000 bytes
HTML transferred:       22198000 bytes
Requests per second:    9.61 [#/sec] (mean)
Time per request:       104.010 [ms] (mean)
Time per request:       104.010 [ms] (mean, across all concurrent requests)
Transfer rate:          212.79 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    95  104   7.8    101     169
Waiting:       87   96   7.0     94     149
Total:         95  104   7.8    101     169



Patch:

Concurrency Level:      1
Time taken for tests:   102.453 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22663000 bytes
HTML transferred:       22198000 bytes
Requests per second:    9.76 [#/sec] (mean)
Time per request:       102.453 [ms] (mean)
Time per request:       102.453 [ms] (mean, across all concurrent requests)
Transfer rate:          216.02 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:    95  102   6.1    101     160
Waiting:       88   95   5.8     94     153
Total:         95  102   6.1    101     160

Concurrency Level:      1
Time taken for tests:   102.319 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22663000 bytes
HTML transferred:       22198000 bytes
Requests per second:    9.77 [#/sec] (mean)
Time per request:       102.319 [ms] (mean)
Time per request:       102.319 [ms] (mean, across all concurrent requests)
Transfer rate:          216.30 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    96  102   5.7    100     148
Waiting:       89   95   5.3     93     123
Total:         96  102   5.7    100     148

catch’s picture

Tried a single node and manually added a bunch of different fields for it, then stuck some dummy content in. Two term fields, two images, 4 text fields etc.

In this case it actually comes out slower though... There are ten less calls to theme, and one less call to drupal_render() in the patched version according to cachegrind.

HEAD


Server Software:        Apache/2.2.11
Server Hostname:        d7.7
Server Port:            80

Document Path:          /node/204
Document Length:        9241 bytes

Concurrency Level:      1
Time taken for tests:   81.189 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      9771000 bytes
HTML transferred:       9241000 bytes
Requests per second:    12.32 [#/sec] (mean)
Time per request:       81.189 [ms] (mean)
Time per request:       81.189 [ms] (mean, across all concurrent requests)
Transfer rate:          117.53 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    70   81  12.5     76     125
Waiting:       63   74  11.7     69     117
Total:         70   81  12.5     76     125

Patch:

Concurrency Level:      1
Time taken for tests:   92.960 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      9771000 bytes
HTML transferred:       9241000 bytes
Requests per second:    10.76 [#/sec] (mean)
Time per request:       92.960 [ms] (mean)
Time per request:       92.960 [ms] (mean, across all concurrent requests)
Transfer rate:          102.65 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    83   93   9.4     90     151
Waiting:       77   86   8.9     83     142
Total:         83   93   9.4     90     151
moshe weitzman’s picture

@catch - there are fewer calls to theme() with the patch and still it came out slower? can you tell why patched is slower? this is a bit disheartening.

@sun - formatter deserves a new word, IMO. It refers to a function that transforms raw database values for viewing, and can be shared across different fields. modules can declare the availability of these functions and admins choose which they want to use on the Display fields tab or whatever it is called.

catch’s picture

@moshe, no I didn't get very far working out why it's slower. I just repeated the benchmarks with ten nodes on front page and it came out slightly slower consistently. effulgentsia also got degradation testing an earlier version of the patch at http://drupal.org/node/538164#comment-2346970 - however it'd be great to get benchmarks by a third person to verify this.

yched’s picture

re @sun #28 - "formatters".
- No 1-1 relationship between field types and formatters. Right now, hook_field_*() are field-type hooks, hook_field_widget_*() are widget hooks... Thus hook_field_formatter_*()
- Agreed that a new word might be more accurate given the approach in the patch where a 'formatter' just builds a field for viewing. Having a specific word however was just not for hype, it reflected the fact that it's a pluggable component, next to (and independant from) the notions of 'field types', 'widgets', (and in D7 'storage backends'). We need an unambiguous terminology (preferably single word). 'widget' has long been controversial too, BTW, but no better term emerged.
- In Views terminology (and if Field API was OO), it would be a 'build handler' ? 'Formatter' has years of usage, has the advantage of being one single word, and makes more sense than other, more technically accurate terminologies.

More generally, I don't think it's the appropriate timing to change terminology now :-(. I vote for the status quo, and rethinking names in D8 when (hopefully) moving to a OO architecture.

re @catch: many thanks for the benches.
#30 is consistent with moshe's early benches in #438570-60: Field API conversion leads to lots of expensive function calls. Performance gains should IMO scale more or less linearly with the # of fields on each node or # of nodes in the list.
#31 is indeed confusing, beats me. Profiling data could be helpful, but I won't be able to look into it tonight.
Also, might be worth testing a single node with 10 *text* fields, to check that the slowdown is not caused by my conversion of a specific file or taxonomy formatter.
*Theoretically*, it should show a similar speedup than '10 nodes with one body each' (at least in terms of ms, maybe not in terms of %)

yched’s picture

from the end of #34 above "...check that the slowdown is not caused by my conversion of a specific file or taxonomy formatter"
Regarding the 'taxonomy_term_link' formatter:
see taxonomy_field_formatter() / rdf_field_attach_view_alter() in the patch - this translates the current theme_field_formatter_taxonomy_term_link() and rdf_preprocess_field_formatter_taxonomy_term_link() :append the term RDF data within displayed value, unlike 'regular' RDF properties that are assigned to fields as a whole but do not depend on the actual field values.

The new form using hook_f_a_view_alter() is possibly more CPU costly.
IMO this is a case where we could save CPU if the RDF properties were handled directly in the formatter - besides, the current only works for 'taxonomy_term_link' formatter, but there's no reason other taxo formatters would not benefit from this as well. Different issue I guess.

More generally, I think this is patch is a win if benches prove that the architecture change saves CPU for a given, simple formatter (like text), which are the most common case. Improving the performance of a specific formatter is then a separate task.
Also, possibly we should bench with RDF module disabled ?

effulgentsia’s picture

StatusFileSize
new3.44 KB

Not encouraging. Here's benchmarks with overlay and rdf modules disabled. I added 2 text fields to the page type, made each multi-valued, and put 30 items into each, so the patch saves on 60 formatter theme() calls.

HEAD: 66.7ms
Patch: 68.8ms

Unfortunately, I don't have time today to help investigate this. But, I'd like to point out that a theme() call isn't as expensive as one might think. I don't have up to date microbenchmarks, but from previous testing, it's about 10us on my computer (including the calling of a theme implementation function that's fast, such as theme('links', array('links' => array())). Replacing each of these items that has a #theme of a formatter with an item that has a #markup, means saving a theme() call, but still invoking drupal_pre_render_markup() as a variable function name from within drupal_render(), so it's probably a net savings of roughly 5us per item, or for 60 items, 0.3ms. However, this patch is large and does a lot of other stuff, so it clearly includes something that's causing a degradation that's much larger than this savings.

On the other hand, drupal_render() is slow (roughly 20us even for a non-item such as the 'items' array that's in HEAD, and that this patch removes by placing the numeric items directly inside the field without the extra 'items' layer), so I like that part of what this patch does, and that might be what accounts for a chunk of the savings in the 10 teaser nodes scenario.

By far the biggest slowdown in field rendering, however, is theme('field'). Just removing that from the comment body conversion to a field (#538164-133: Comment body as field) resulted in the patch moving from having a net 6% - 10% impact (depending on system used to benchmark) to having a net -1% - 0.5% impact. theme('field') is slow because field.tpl.php is a template, and because there's quite a bit of preprocessing logic. Seems like we need to focus our time on that, but I can't help with that in time for tomorrow's deadline. On the other hand, improvements to that might not be as sweeping an API change, and could maybe happen after that deadline.

To be honest, I just don't think removing formatter theme functions is gonna result in much savings, but if someone can figure out what in this patch is causing degradation larger than those savings and fix that, then it still might be a good architectural thing to do. But I do think when we put some effort into optimizing theme('field'), then we'll see some nice rendering speed improvements.

yched’s picture

...the 'items' array that's in HEAD, and that this patch removes by placing the numeric items directly inside the field without the extra 'items' layer (...) and that might be what accounts for a chunk of the savings in the 10 teaser nodes scenario.

Well, the proof of concept patch in #438570: Field API conversion leads to lots of expensive function calls didn't include that change, and moshe's initial bench over there for the '/node' case were pretty similar to the one in #30.
These savings should also be seen similarly on the 'node/%nid' case [edit: well, OK, not in the case of your bench, since it used a node with 2 fields instead of 10]

The patch is big because it updates all core formatters, but I can't think of anything in there that would add extra burden on a single node view using text fields.

Sorry to ask but: are we sure the field cache was pre-populated with a preliminary page view when benching both HEAD and the patch ?

effulgentsia’s picture

Are we sure the field cache was pre-populated with a preliminary page view when benching both HEAD and the patch?

Yes. For each test, I empty cache, then view the page in Firefox as the root user, and in Safari as an anonymous user, then run "ab" for 100 iterations, and then run "ab" for 500 iterations (that's the one attached in #36). The first 100 iteration run helps any other caches (like APC) get well primed.

It does seem odd that there's an improvement for 10 teasers, but a degradation for a single node with many fields or many field items. Seems worth exploring. However, since there is improvement for 10 teasers, maybe it makes sense to have this land, and then we can find the mysterious trouble spot and optimize that after the deadline.

Sorry I can't be of any more help on this today. Best of luck to you, yched, and anyone else who keeps working on it up until the deadline. I think the basic approach makes sense and is sound, and that remaining performance anomalies are findable and fixable.

effulgentsia’s picture

StatusFileSize
new50.6 KB

This is a re-roll of #25, plus the following changes:

1. In template_preprocess_field(), NOT changing HEAD's use of strtr() with drupal_html_class(), as #25 does. We probably should make this change, but in a separate issue. Doing it here affects benchmarks.

2. In field_default_view(), calling the formatter function directly instead of with module_invoke(), because module_invoke() is slow.

Will follow up with benchmarks, but wanted to get this into bot's queue.

bleen’s picture

superscribe

effulgentsia’s picture

StatusFileSize
new3.14 KB
new3.43 KB
new3.1 KB

Benchmarks with rdf and overlay modules disabled:

A: Home page with 10 article teasers, each article node has a body field:
HEAD: 94.2ms
Patch: 91.9ms

B: Home page with 10 article teasers, each article node has a body field plus 3 single-valued plain-text single-line textfields:
HEAD: 113.5ms
Patch: 111.7ms

C: Single page node with a multi-valued plain-text single-line text field with 40 items populated:
HEAD: 65.5ms
Patch: 65.7ms

Conclusion: This patch doesn't do performance harm. It gives a nice boost to home page with 10 articles, which is a nice scenario to get a boost on. The boost doesn't seem to scale as more fields get added. There seems to be a no-op with just the formatter change alone (page node with 40 items). The no-op in case C makes sense to me. See my comment on #36. We're still invoking the formatter function for as many times as there are items, and as a variable function name. Just instead of doing it from theme(), we're doing it from field_default_view(). I don't see how we gain anything performance-wise from that. There must be something else that's giving us the nice benefit in case A.

So, I think the decision in front of us is whether we think the change to formatters returning render arrays instead of being theme implementations is a good change conceptually. Or does it open the door to further optimization in a way that having it as a theme implementation doesn't? If we think either of those is true, let's do it.

Otherwise, if it's a no-op performance wise, and has no other benefit, let's not do it, and instead try to find what the real cause for case A improvement is, and create a patch that has that, but without changing the formatter architecture.

effulgentsia’s picture

Unless Dries changed his mind from what he wrote on #438570-62: Field API conversion leads to lots of expensive function calls, the deadline for making this decision is today. I have no strong preference either way (I just haven't thought deeply enough on the architectural implications of formatters as theme functions vs. not). But for anyone with insight on this, today's the day to share it.

effulgentsia’s picture

Status: Needs review » Reviewed & tested by the community

Setting to RTBC because sun approved it (except for needing more comments) in #28, and to get it in front of Dries (seems like this is a big and deep enough issue / patch, that he'll need to do his own review and analysis of it).

yched’s picture

Status: Reviewed & tested by the community » Needs review

effulgentsia: *Many* thanks for pushing this.

Performance considerations aside, the architectural change makes sense for the following reasons:
- the 'sanitize displayed data' step can be merged back into hook_field_formatter(), since this is out of reach of the theme layer. Each formatter gets to do the exact amount of data massaging it needs, instead of currently the *field type* module doing some 'reasonable' (= extra careful at best, insufficient at worst) sanitation without knowing what the formatter actually does or need.
- displaying simple stuff like flat markup strings or links without going through theme() is the exact purpose for the introduction of #type 'markup' and 'link'. Most commonly used formatters will be of this kind,
- More generally, D7 is largely "render array + alter hooks" oriented. Was not so true in D6 or back when the Field API initially landed. Making everything themeable just so that it can be modified is an outdated approach.

I'll try to finish the doc @todos later tonight.

yched’s picture

StatusFileSize
new52 KB

- updated API docs
- reverted the "hook_field_formatter_prepare_view() -> hook_field_formatter_prepare()" change done in earlier iterations. 'view' is a bit redundant when dealing with formatters, but #636992: Entity loading needs protection from infinite recursion is making 'prepare_view' a little more official, so it's probably better to stick to that.
- introduced a small change in the arguments for hook_field_formatter_prepare_view(): takes $display settings instead of a $build_mode pointing to display settings within the $instance definition. This will be needed by #612894: field_format() is just a pile of code that doesn't work (allow one-off field display using custom display settings - needed for Views and Panels). The patch over there is not fully ready yet, but making the API change here is harmless and lets us break APIs only once.

Additionally, hook_field_sanitize() is now useless in its current form for 'sanitize field values' (this is now in the hands of formatters), no current core field type uses it. Such a hook still has value at the field-type level, for instance for 'do not display values the current user has no permissions to see' (e.g nodereference), but
- it would be more accurate and consistent if renamed hook_field_prepare_view() : 'prepare_view' at field-type level.
- it would be more efficient as a 'multiple object' hook (like other 'prepare_view' stuff)
Not done in this patch, feedback on this welcome from Dries (and catch).

yched’s picture

oops, crossposts with #43.

yched’s picture

Status: Needs review » Reviewed & tested by the community

Just thought of this: we might also gain a couple cycles by calling the formatter hooks on the whole values array and have them return a render array keyed by value delta, instead of currently doing

foreach ($items as $delta => $item) {
  $element[$delta] = $formatter_function($obj_type, $object, $field, $instance, $langcode, $display, $items, $delta);
  $element[$delta]['#weight'] = $delta;
}

This could even possibly let us get rid of the distinction between 'single value' formatters and 'multiple value formatters'.

effulgentsia’s picture

Re: #47: +1 from me. Also, please re-read #29 and #32. If we simplify formatters in the way you're suggesting, it really starts looking pretty indistinguishable from other *_build() functions.

sun’s picture

+1 from me as well. Removing the distinction between single value formatters and multiple value formatters would be awesome for DX. I recall how I got stuck understanding that bit in CCK when it got introduced.

Anonymous’s picture

subscribe. i see it's RTBC, but i need to read it all anyway.

catch’s picture

Has anything changed since #41 which requires new benchmarks?

dries’s picture

Status: Reviewed & tested by the community » Fixed

Great. Let's do this -- it is a nice win for the main page. Committed to CVS HEAD.

yched’s picture

Status: Fixed » Reviewed & tested by the community

"Has anything changed since #41 which requires new benchmarks?"
No. I'll try to add the change mentioned in #47 later today. Then new benchmarks could be worth. But patch #45 is ready as is.

catch’s picture

Status: Reviewed & tested by the community » Fixed

#47 sounds good but let's do a new issue for that.

yched’s picture

Agreed - #53 crossposted with Dries commit message. Yay !

yched’s picture

Patch with the followup adjustments described in #47: #657828: Make hook_field_formatter() act on all field values. API break too, so we might want to be quick :-/

yched’s picture

effulgentsia’s picture

In response to sun's #28/#29 comments: #658364: Does build/view/formatter terminology make sense?

Status: Fixed » Closed (fixed)
Issue tags: -Performance

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