Bug 64865

Summary: Switch isQuirkValue() virtual function to inline one.
Product: WebKit Reporter: Tamas Czene <tczene>
Component: CSSAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, davidbarr, dglazkov, eric, hyatt, jamesr, koivisto, loki, macpherson, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Bug Depends on:    
Bug Blocks: 64262    
Attachments:
Description Flags
Switch isQuirkValue virtual function to inline one.
eric: review-, webkit.review.bot: commit-queue-
Archive of layout-test-results from ec2-cr-linux-03
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Description Tamas Czene 2011-07-20 06:05:49 PDT
Removing the virtual functions - removing the calls - makes measurable performance progression on CSS.

We measured the following performance progressions on some very popular websites, for example:
msn.com: 32,4%
yandex.ru: 2%

The number of variables created during the test.
m_isQuirkValue 229806
The max number of variables in the memory during the test.
m_isQuirkValue 2749
Comment 1 Tamas Czene 2011-07-20 06:08:47 PDT
Created attachment 101455 [details]
Switch isQuirkValue virtual function to inline one.
Comment 2 WebKit Review Bot 2011-07-20 06:42:11 PDT
Comment on attachment 101455 [details]
Switch isQuirkValue virtual function to inline one.

Attachment 101455 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/9200248

New failing tests:
css1/basic/comments.html
css1/basic/grouping.html
css1/box_properties/border_bottom_width.html
css1/box_properties/border_bottom_width_inline.html
css1/box_properties/border_left_width.html
css1/basic/inheritance.html
css1/box_properties/border_color_inline.html
css1/box_properties/border_inline.html
css1/basic/class_as_selector.html
css1/box_properties/border.html
css1/box_properties/border_right.html
css1/box_properties/border_color.html
css1/box_properties/border_left_width_inline.html
css1/basic/id_as_selector.html
css1/box_properties/border_left.html
css1/box_properties/border_bottom_inline.html
css1/basic/containment.html
css1/box_properties/border_bottom.html
css1/box_properties/border_left_inline.html
css1/basic/contextual_selectors.html
Comment 3 WebKit Review Bot 2011-07-20 06:42:17 PDT
Created attachment 101461 [details]
Archive of layout-test-results from ec2-cr-linux-03

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: ec2-cr-linux-03  Port: Chromium  Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Comment 4 Dave Hyatt 2011-07-20 13:26:01 PDT
See my comments in https://bugs.webkit.org/show_bug.cgi?id=64262.
Comment 5 Eric Seidel (no email) 2011-09-12 16:59:05 PDT
Comment on attachment 101455 [details]
Switch isQuirkValue virtual function to inline one.

Um.  This increases the size of all CSSPrimativeValues.  I suspect this could cause a large memory regression?
Comment 6 David Barr 2011-10-10 21:26:48 PDT
(In reply to comment #5)
> (From update of attachment 101455 [details])
> Um.  This increases the size of all CSSPrimativeValues.  I suspect this could cause a large memory regression?

I believe an alternative approach might hit both targets, investigating.
Comment 7 Antti Koivisto 2011-10-11 11:32:30 PDT
Inreasing the size of CSSPrimativeValue is definitely not acceptable.
Comment 8 Antti Koivisto 2011-10-11 11:39:56 PDT
The performance claims are obviously bs. This is WONTFIX.
Comment 9 Eric Seidel (no email) 2011-10-11 12:16:13 PDT
Another way of saying what Antti said:  A change like this would need to provide evidence (results from a trusted, repeatable benchmark) that this change is a perf improvement.
Comment 10 Luke Macpherson 2011-10-11 15:25:10 PDT
FWIW, I've also noticed that the virtual dispatch on CSSValue shows up a lot in profiling. I wouldn't be surprised if there were some performance gains to be found here by eliminating the virtual call, but as Eric points out, there is a tradeoff with the size on these objects because there tend to be a lot of them.
Comment 11 David Barr 2011-10-11 16:31:55 PDT
(In reply to comment #10)
> FWIW, I've also noticed that the virtual dispatch on CSSValue shows up a lot in profiling. I wouldn't be surprised if there were some performance gains to be found here by eliminating the virtual call, but as Eric points out, there is a tradeoff with the size on these objects because there tend to be a lot of them.

I believe there are some wasted bits that could be put to good use for a perf enhancement without increasing the memory overhead. Please give a chance to upload an RFC patch.
Comment 12 Antti Koivisto 2011-10-12 01:18:49 PDT
I'm all for eliminating virtual functions. This particular bug just didn't start very well (wild, unsubstantiated performance claims, patch that doesn't actually remove a virtual function and adds a member variable to hold value "false"). 

Better continue in a new bug.
Comment 13 Antti Koivisto 2011-10-12 02:49:29 PDT
Hmm, I was wrong, it does actually eliminate the virtual call. The patch is just buggy. I think this can be recovered.
Comment 14 Antti Koivisto 2011-10-12 02:54:40 PDT
Comment on attachment 101455 [details]
Switch isQuirkValue virtual function to inline one.

View in context: https://bugs.webkit.org/attachment.cgi?id=101455&action=review

> Source/WebCore/css/CSSPrimitiveValue.h:27
> +#include <wtf/AlwaysInline.h>

Not needed.

> Source/WebCore/css/CSSPrimitiveValue.h:196
> -    virtual bool isQuirkValue() { return false; }
> +    ALWAYS_INLINE bool isQuirkValue() { return m_isQuirkValue; }

Remove ALWAYS_INLINE. This will almost surely inline without it.

> Source/WebCore/css/CSSPrimitiveValue.h:206
>  
> +    bool m_isQuirkValue;

Move this to this bitfield:

    signed m_type : 31;
    mutable unsigned m_hasCachedCSSText : 1;

Take one bit out from m_type. Make all member variables protected instead of private.

> Source/WebCore/css/CSSQuirkPrimitiveValue.h:44
>      {
> +        m_isQuirkValue = false;
>      }

Should be set to true here.
Comment 15 David Barr 2011-10-13 22:33:54 PDT
Created attachment 110958 [details]
Patch
Comment 16 David Barr 2011-10-13 22:37:03 PDT
Created attachment 110959 [details]
Patch
Comment 17 Gabor Loki 2011-10-13 23:27:55 PDT
Comment on attachment 110959 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110959&action=review

> Source/WebCore/ChangeLog:9
> +2011-10-13  David Barr  <davidbarr@chromium.org>
> +
> +        Inline CSSPrimitiveValue::isQuirkValue() as non-virtual function
> +        https://bugs.webkit.org/show_bug.cgi?id=64865
> +
> +        Reviewed by NOBODY (OOPS!).
> +
> +        This is expected to produce a small performance progression.
> +        Additional memory overhead is avoided by using spare bits.

David, may I ask you to mention Tamas Czene here? Basically it was his idea, and the previous patch was done by him.
Comment 18 Darin Adler 2011-10-14 08:39:13 PDT
Comment on attachment 110959 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=110959&action=review

> Source/WebCore/css/CSSPrimitiveValue.h:249
> +    unsigned m_isQuirkValue : 1;

We should expose a protected inline setter for m_isQuirkValue instead of exposing the data member itself.
Comment 19 Darin Adler 2011-10-14 08:44:59 PDT
Comment on attachment 110959 [details]
Patch

This idea is fine, but there is no reason to keep an entire class, CSSQuirkPrimitiveValue, any more given that the class has no contents. Instead we just need a new create function in CSSPrimitiveValue that creates a quirk value.

Doing it that way will remove an entire unnecessary vtable, make the code cleaner and easier to understand, and also remove the need to add new protected members.

I’m going to say review+ but I’d much prefer this be redone to eliminate the class.
Comment 20 Antti Koivisto 2011-10-14 11:05:00 PDT
(In reply to comment #19)
> Doing it that way will remove an entire unnecessary vtable, make the code cleaner and easier to understand, and also remove the need to add new protected members.

Unfortunately it will take much more than that to remove vtable from CSSValues. CSSPrimitiveValue is not the base class.

> I’m going to say review+ but I’d much prefer this be redone to eliminate the class.

Yeah, definitely. I didn't notice that there was nothing else there.
Comment 21 David Barr 2011-10-14 23:03:00 PDT
Created attachment 111125 [details]
Patch
Comment 22 David Barr 2011-10-14 23:04:41 PDT
Comment on attachment 111125 [details]
Patch

As suggested, updated patch to remove now trivial class CSSQuirkPrimitiveValue and due credit given to Tamas Czene.
Comment 23 David Barr 2011-10-14 23:27:49 PDT
Comment on attachment 111125 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111125&action=review

Sorry for the noise, I noticed some nits just after uploading the patch.

> Source/WebCore/WebCore.gypi:-2383
> -            'css/CSSQuirkPrimitiveValue.h',

As a developer new to WebKit, I'm not familiar with the process of propagating this change. FWIW, it doesn't appear to break the build.

> Source/WebCore/css/CSSQuirkPrimitiveValue.h:-31
> -// This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE.
> -// The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em.
> -// When the quirky value is used, if you're in quirks mode, the margin will collapse away
> -// inside a table cell.

I think this comment should have followed CSSQuirkPrimitiveValue::create() when it became CSSPrimitiveValue::createQuirk().
Comment 24 Darin Adler 2011-10-15 13:17:32 PDT
Comment on attachment 111125 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111125&action=review

Not setting commit-queue+ because of David’s comment, and my related one.

>> Source/WebCore/css/CSSQuirkPrimitiveValue.h:-31
>> -// inside a table cell.
> 
> I think this comment should have followed CSSQuirkPrimitiveValue::create() when it became CSSPrimitiveValue::createQuirk().

I agree. I also would suggest naming the new function CSSPrimitiveValue::createAllowingMarginQuirk().
Comment 25 David Barr 2011-10-15 15:11:21 PDT
Created attachment 111150 [details]
Patch
Comment 26 Darin Adler 2011-10-15 15:19:30 PDT
Comment on attachment 111150 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111150&action=review

> Source/WebCore/css/CSSPrimitiveValue.h:140
> +    /*
> +     * This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE.
> +     * The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em.
> +     * When the quirky value is used, if you're in quirks mode, the margin will collapse away
> +     * inside a table cell.
> +     */

We use "//" comments, not "/*" comments. Not sure why you changed this one.

> Source/WebCore/css/CSSPrimitiveValue.h:143
> +        CSSPrimitiveValue *ptr = new CSSPrimitiveValue(value, type);

The "*" goes next to the type, not the local variable name.

Instead of ptr this local variable should be named value.
Comment 27 David Barr 2011-10-15 15:52:57 PDT
Comment on attachment 111150 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111150&action=review

>> Source/WebCore/css/CSSPrimitiveValue.h:140
>> +     */
> 
> We use "//" comments, not "/*" comments. Not sure why you changed this one.

I was matching style with the nearest comment block in the destination file, which just happened to be the only incorrectly styled comment in the whole file. Will fix.

>> Source/WebCore/css/CSSPrimitiveValue.h:143
>> +        CSSPrimitiveValue *ptr = new CSSPrimitiveValue(value, type);
> 
> The "*" goes next to the type, not the local variable name.
> 
> Instead of ptr this local variable should be named value.

Given that the parameter is also called value, I'll take the liberty of calling it quirkValue.
This has the advantage that the middle line reads quite clearly:
quirkValue->m_isQuirkValue = true;
Comment 28 David Barr 2011-10-15 15:56:03 PDT
Created attachment 111152 [details]
Patch
Comment 29 David Barr 2011-10-15 15:57:11 PDT
Comment on attachment 111152 [details]
Patch

All nits addressed, requesting commit-queue.
Comment 30 Eric Seidel (no email) 2011-10-16 02:05:54 PDT
Comment on attachment 111152 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111152&action=review

Seems OK.

> Source/WebCore/css/CSSPrimitiveValue.h:257
> -    signed m_type : 31;
> +    signed m_type : 30;

Why is m_type bigger than it needs to be?
Comment 31 David Barr 2011-10-16 02:41:31 PDT
(In reply to comment #30)
> (From update of attachment 111152 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=111152&action=review
> 
> Seems OK.
> 
> > Source/WebCore/css/CSSPrimitiveValue.h:257
> > -    signed m_type : 31;
> > +    signed m_type : 30;
> 
> Why is m_type bigger than it needs to be?

It takes values from enum CSSPrimitiveValue::UnitType, the maximum of which is presently
CSS_COUNTER_NAME = 109, so I think it only needs 7 unsigned bits.
However it began as an int even though it's always implicitly cast to short by its accessors.
One bit was borrowed for m_cachedCSSText in r59386 to resolve a substantially larger
memory regression but the extra bits were left assigned to m_type.
It seems Sam Weinig and I were both timid when shrinking it. Principal of least change perhaps?
Comment 32 Eric Seidel (no email) 2011-10-16 10:50:37 PDT
Comment on attachment 111152 [details]
Patch

Its fine to not shink it, but we should explain exacxtly what you just did.  Where it gets its size from, and how large it currently would need to be.  That way the next reviewer won't have any question when we lop another bit off it, since the comment right above will explain that it only uses 7 of the 31 bits and they can verify that by searching for the right enum.
Comment 33 Eric Seidel (no email) 2011-10-16 10:50:56 PDT
Anyway, the change is fine.  ADding a comment to explain woudl be gravy.
Comment 34 Eric Seidel (no email) 2011-10-16 10:55:22 PDT
Did we ever validate the profiling?

Did we ever test this with the PLT or with PerformanceTests/Parser/html5-full-render.html?  It seems at least one of those should show this change.
Comment 35 David Barr 2011-10-16 12:38:16 PDT
Created attachment 111184 [details]
Patch
Comment 36 David Barr 2011-10-16 12:41:22 PDT
Comment on attachment 111184 [details]
Patch

Added comment above m_type declaration for future reference.
Comment 37 David Barr 2011-10-16 16:36:38 PDT
PerformanceTests/Parser/html5-full-render.html with 20 runs:

ToT:
Testing 6092696 byte document in 13 500000 byte chunks.
Running 20 times
Ignoring warm-up run (43271)
42328 42366 42265 42350 42285 42353 42270 42247 42309 42647
42622 42305 42305 42283 42286 42223 42162 42278 42375 42391

avg 42332.5
median 42305
stdev 113.7002638519366
min 42162
max 42647

With patch:
Testing 6092696 byte document in 13 500000 byte chunks.
Running 20 times
Ignoring warm-up run (42394)
42100 42123 42166 42121 42017 42113 41883 41853 42158 41996
42160 42056 42209 42098 41933 42182 41880 41806 41981 42063

avg 42044.9
median 42080.5
stdev 117.5461186088252
min 41806
max 42209

That gives a progression of 2.45 stdevs or 0.7%
Comment 38 Luke Macpherson 2011-10-16 16:43:55 PDT
Comment on attachment 111184 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111184&action=review

> Source/WebCore/css/CSSPrimitiveValue.h:257
> +    // This holds enum UnitType, so only 7 unsigned bits are necessary.

I would recommend adding a UnitTypeBits constant defined as 7, remove this comment, and use the constant here.
Also it would be good to add a COMPILE_ASSERT to the constructor of PrimitiveValue that asserts that its size never exceeds what you expect.
Comment 39 Luke Macpherson 2011-10-16 16:46:07 PDT
Performance numbers look really good, and IMHO getting rid of the quirk value class is good too.
Comment 40 David Barr 2011-10-16 17:16:22 PDT
Created attachment 111192 [details]
Patch
Comment 41 Luke Macpherson 2011-10-16 17:25:17 PDT
Comment on attachment 111192 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=111192&action=review

> Source/WebCore/css/CSSPrimitiveValue.h:145
> +    }

Also, I'd delete this comment + code and and just add a boolean parameter that defaults to false to create(double, UnitTypes).
Comment 42 WebKit Review Bot 2011-10-16 17:38:32 PDT
Comment on attachment 111192 [details]
Patch

Attachment 111192 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/10078747
Comment 43 David Barr 2011-10-16 17:45:00 PDT
Created attachment 111193 [details]
Patch
Comment 44 David Barr 2011-10-16 17:48:32 PDT
Comment on attachment 111193 [details]
Patch

Leaving m_type signed and 8 bits to work around 'sign mismatch  in comparison' errors. While I agree that the semantics of constructing CSSPrimitiveValues for quirky ems could be improved, I think it is beyond the scope of this change.
Comment 45 Eric Seidel (no email) 2011-10-16 20:23:33 PDT
Thank you David.
Comment 46 WebKit Review Bot 2011-10-16 21:26:17 PDT
Comment on attachment 111193 [details]
Patch

Clearing flags on attachment: 111193

Committed r97583: <http://trac.webkit.org/changeset/97583>
Comment 47 WebKit Review Bot 2011-10-16 21:26:29 PDT
All reviewed patches have been landed.  Closing bug.