Bug 135255 - Merge CheckingContexts from SelectorCompiler and SelectorChecker
Summary: Merge CheckingContexts from SelectorCompiler and SelectorChecker
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords:
Depends on: 135733
Blocks: 135242 135293
  Show dependency treegraph
 
Reported: 2014-07-24 14:10 PDT by Alex Christensen
Modified: 2014-09-13 00:53 PDT (History)
6 users (show)

See Also:


Attachments
Patch (64.09 KB, patch)
2014-08-30 11:44 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (64.15 KB, patch)
2014-08-30 11:48 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (69.79 KB, patch)
2014-08-30 12:01 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (80.66 KB, patch)
2014-08-30 12:13 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (67.66 KB, patch)
2014-09-09 13:46 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Trunk Perf Results (482.72 KB, application/x-webarchive)
2014-09-12 08:56 PDT, Yusuke Suzuki
no flags Details
Perf Results with reverting this patch (482.77 KB, application/x-webarchive)
2014-09-12 08:56 PDT, Yusuke Suzuki
no flags Details
JIT Compiled version (507.99 KB, application/x-webarchive)
2014-09-12 11:27 PDT, Yusuke Suzuki
no flags Details
Patch (10.85 KB, patch)
2014-09-12 11:32 PDT, Yusuke Suzuki
no flags Details | Formatted Diff | Diff
Patch (10.42 KB, patch)
2014-09-12 14:48 PDT, Benjamin Poulain
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alex Christensen 2014-07-24 14:10:43 PDT
Eventually SelectorCompiler::CheckingContext and SelectorChecker::SelectorCheckingContext should be made the same class.  

m_mode should be moved from SelectorChecker to SelectorChecker::SelectorCheckingContext because the compiled selectors need it, too.  
m_element should probably be moved from SelectorChecker::SelectorCheckingContext to SelectorChecker because the compiled selectors probably don't need it.
There might be some other things that need to move around as we compile all selectors.
Comment 1 Yusuke Suzuki 2014-07-26 04:02:25 PDT
This looks really nice!
I think we can remove SelectorChecker::CheckingContext third parameter, visitedMatchType. Only when the mode is QueryingRules, we pass VisitedMatchDisabled value to this constructor.
When mode is moved to this CheckingContext, we can determine this value by `mode == QueryingRules ? VisitedMatchDisabled : VisitedMatchEnabled`!
Comment 2 Yusuke Suzuki 2014-08-30 11:44:41 PDT
Created attachment 237413 [details]
Patch
Comment 3 Yusuke Suzuki 2014-08-30 11:48:02 PDT
Created attachment 237414 [details]
Patch
Comment 4 Yusuke Suzuki 2014-08-30 12:01:51 PDT
Created attachment 237415 [details]
Patch
Comment 5 Yusuke Suzuki 2014-08-30 12:13:33 PDT
Created attachment 237416 [details]
Patch
Comment 6 Yusuke Suzuki 2014-08-30 12:19:12 PDT
Comment on attachment 237416 [details]
Patch

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

Added comments.

> Source/WebCore/css/ElementRuleCollector.cpp:312
> +    context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart;

Merged. So we simply use SelectorChecker::CheckingContext for slow path and CSS JIT.

> Source/WebCore/css/SelectorChecker.cpp:63
> +};

Moved into SelectorChecker.cpp!

> Source/WebCore/css/SelectorChecker.cpp:85
> +};

Defined SelectorChecker::CheckingContextWithStatus. It is extended CheckingContext with SelectorChecker specific fields.

> Source/WebCore/css/SelectorChecker.cpp:163
> +bool SelectorChecker::match(const CSSSelector* selector, Element* element, const CheckingContext& providedContext) const

Take selector and element. It is similar to CSS JIT checker interface.

> Source/WebCore/css/SelectorChecker.cpp:165
> +    CheckingContextWithStatus context(providedContext, selector, element);

Then update provided SelectorChecker::CheckingContext to SelectorChecker::CheckingContextWithStatus.

> Source/WebCore/css/SelectorChecker.h:-49
> -    enum VisitedMatchType { VisitedMatchDisabled, VisitedMatchEnabled };

Hidden!

> Source/WebCore/css/SelectorChecker.h:55
> +    struct CheckingContext {

Moved from SelectorCompiler::CheckingContext to here.

> Source/WebCore/css/SelectorChecker.h:89
> +    bool checkScrollbarPseudoClass(const CheckingContextWithStatus&, const CSSSelector*) const;

Internally, use CheckingContextWithStatus.

> Source/WebCore/css/SelectorCheckerTestFunctions.h:171
> +

ContextType is now unnecessary since CheckingContexts are merged.

> Source/WebCore/css/SelectorQueryFastPath.h:42
> +    bool matchesRightmostSelector() const;

Now don't take visitedMatchType parameter since visited match type is always disabled under the SelectorQuery context.

> Source/WebCore/css/SelectorQueryFastPath.h:47
> +    bool commonPseudoClassSelectorMatches() const;

matchesRightmostAttributeSelector is dropped since it is no longer used.
Comment 7 Benjamin Poulain 2014-09-03 20:49:29 PDT
Comment on attachment 237416 [details]
Patch

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

Sorry for the delay, I was finishing on some style invalidation bug.

The patch is a good improvement of the code base.

You can remove SelectorQueryFastPath instead of cleaning it up. SelectorQueryFastPath was invented by Antti to solve the performance problems before we had the CSS JIT. Nowadays it is no longer useful, the JIT is a lot faster.

> Source/WebCore/ChangeLog:4
> +        Merge CheckingContexts from SelectorCompiler and SelectorChecker
> +        https://bugs.webkit.org/show_bug.cgi?id=135255

You have 2 changeslog entries.

> Source/WebCore/CMakeLists.txt:1306
> -    css/SelectorCheckerFastPath.cpp
>      css/SelectorFilter.cpp
> +    css/SelectorQueryFastPath.cpp

You don't need to bother with SelectorCheckerFastPath. We should remove it, I just haven't had time to clean up SelectorQuery.
Comment 8 Yusuke Suzuki 2014-09-03 20:54:00 PDT
Comment on attachment 237416 [details]
Patch

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

Thank you for your review! OK, so I'll drop fast path implementation and upload the revised patch :)

>> Source/WebCore/ChangeLog:4
>> +        https://bugs.webkit.org/show_bug.cgi?id=135255
> 
> You have 2 changeslog entries.

Oops! Thank you for pointing it :D

>> Source/WebCore/CMakeLists.txt:1306
>> +    css/SelectorQueryFastPath.cpp
> 
> You don't need to bother with SelectorCheckerFastPath. We should remove it, I just haven't had time to clean up SelectorQuery.

Make sense. So I'll remove it and clean up SelectorQuery implementation.
Comment 9 Yusuke Suzuki 2014-09-09 13:46:58 PDT
Created attachment 237852 [details]
Patch
Comment 10 Yusuke Suzuki 2014-09-09 14:00:01 PDT
Comment on attachment 237852 [details]
Patch

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

Sorry for my further late reply.

> Source/WebCore/dom/SelectorQuery.cpp:-117
> -    if (selectorData.isFastCheckable && !element.isSVGElement()) {

SelectorCheckerFastPath is dropped.

> Source/WebCore/dom/SelectorQuery.cpp:421
>          }

In the old and new implementations, when `RightMostWithIdMatch` is used, basically `selectorMatches` is called and CSS Selector JIT is not used.

In the SelectorQuery implementation, in the some cases, CSS JIT is not used. Such as `RightMostWithIdMatch` case, and multiple selector case (`document.querySelector('a, b')`).
In the `RightMostWithIdMatch` case, the searched node basically becomes one (matched by id). So compiling CSS Selector may affect the performance.
In the multiple selector case, it also incurs larger CSS JIT compiling overhead compared to the typical one.

But, since the fast path is dropped, it sometimes raises the perf regression on `RightMostWithIdMatch`(But since the target node is typically only one, so it may not have any perf regression.).

My questions are,
1. Is the old behavior intended? (not performing CSS JIT in the case of `RightMostWithIdMatch`, multiple selectors and `Element.matches`)
2. Is it acceptable dropping the fast path from selectorMatches? It may raise perf regression on non CSS JIT cases (such as (1))

Do you think about this?

In this patch, I've simply dropped the fast path.
Comment 11 Benjamin Poulain 2014-09-09 17:56:11 PDT
Comment on attachment 237852 [details]
Patch

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

> Source/WebCore/ChangeLog:17
> +        always VisitedMatchDisabled. In this patch, we rename SelectorCheckerFastPath to SelectorQueryFastPath, and
> +        drop VisitedMatchType parameter.

The part regarding SelectorCheckerFastPath needs to be updated.

> Source/WebCore/css/SelectorChecker.cpp:66
> +    // Initial selector constructor

No need for the comment.
Comment 12 Yusuke Suzuki 2014-09-10 05:37:36 PDT
Oops. I've Ctrl-C on `webkit-patch land`. So closing this manually.
http://trac.webkit.org/changeset/173457
Comment 13 Benjamin Poulain 2014-09-11 19:14:11 PDT
It looks like the regression for comma separated selectors is bigger than anticipated: https://perf.webkit.org/#mode=charts&chartList=%5B%5B%22mac-mavericks%22%2C%22Dromaeo%2Fcssquery-jquery%3ARuns%22%5D%5D&days=6&zoom=%5B1410108072682.0085%2C1410415670537.5554%5D

I'll look into it tomorrow.
Comment 14 Yusuke Suzuki 2014-09-12 00:24:00 PDT
(In reply to comment #13)
> It looks like the regression for comma separated selectors is bigger than anticipated: https://perf.webkit.org/#mode=charts&chartList=%5B%5B%22mac-mavericks%22%2C%22Dromaeo%2Fcssquery-jquery%3ARuns%22%5D%5D&days=6&zoom=%5B1410108072682.0085%2C1410415670537.5554%5D
> 
> I'll look into it tomorrow.

Oops! Thank you for your catch!
Do you think about implementing CSS JIT for multiple selectors?
It will be refactored and reused for :matches implementation, and compared to :matches, it seems more stable.
If it's OK, I'll start to implement it.
Comment 15 Benjamin Poulain 2014-09-12 02:46:43 PDT
(In reply to comment #14)
> (In reply to comment #13)
> > It looks like the regression for comma separated selectors is bigger than anticipated: https://perf.webkit.org/#mode=charts&chartList=%5B%5B%22mac-mavericks%22%2C%22Dromaeo%2Fcssquery-jquery%3ARuns%22%5D%5D&days=6&zoom=%5B1410108072682.0085%2C1410415670537.5554%5D
> > 
> > I'll look into it tomorrow.
> 
> Oops! Thank you for your catch!
> Do you think about implementing CSS JIT for multiple selectors?
> It will be refactored and reused for :matches implementation, and compared to :matches, it seems more stable.
> If it's OK, I'll start to implement it.

Long term we should use :matches() but it will take a while before we have it complete. The complete :matches() is pretty tricky: multilevel backtracking, multiple pseudo element matching and :visited/:link. With all the tests this will require, it is gonna be a lot of work.

Short term for this regression we should:
1) Profile this benchmark to confirm the regression is caused by SelectorChecker.
2) If (2) is right, just compile everything that can be compiled and run a loop mixing CSS JIT and slow Selector checker.

For (2), I am thinking something like:
    // ... try to compile every selector.
    if (allSelectorsCompiled) {
        // Traversal checking each compiled selector for every element.
    } else {
        // Slow case like we do today.
    }

Once :matches() is ready and release quality, we'll remove the hack.

What do you think?
Comment 16 Yusuke Suzuki 2014-09-12 07:36:46 PDT
(In reply to comment #15)
> (In reply to comment #14)
> > (In reply to comment #13)
> > > It looks like the regression for comma separated selectors is bigger than anticipated: https://perf.webkit.org/#mode=charts&chartList=%5B%5B%22mac-mavericks%22%2C%22Dromaeo%2Fcssquery-jquery%3ARuns%22%5D%5D&days=6&zoom=%5B1410108072682.0085%2C1410415670537.5554%5D
> > > 
> > > I'll look into it tomorrow.
> > 
> > Oops! Thank you for your catch!
> > Do you think about implementing CSS JIT for multiple selectors?
> > It will be refactored and reused for :matches implementation, and compared to :matches, it seems more stable.
> > If it's OK, I'll start to implement it.
> 
> Long term we should use :matches() but it will take a while before we have it complete. The complete :matches() is pretty tricky: multilevel backtracking, multiple pseudo element matching and :visited/:link. With all the tests this will require, it is gonna be a lot of work.
> 
> Short term for this regression we should:
> 1) Profile this benchmark to confirm the regression is caused by SelectorChecker.
> 2) If (2) is right, just compile everything that can be compiled and run a loop mixing CSS JIT and slow Selector checker.
> 
> For (2), I am thinking something like:
>     // ... try to compile every selector.
>     if (allSelectorsCompiled) {
>         // Traversal checking each compiled selector for every element.
>     } else {
>         // Slow case like we do today.
>     }
> 
> Once :matches() is ready and release quality, we'll remove the hack.
> 
> What do you think?

It sounds reasonable.
I'll take a profile too. Now running `Tools/Scripts/run-perf-tests --release Dromaeo/cssquery-jquery.html`
Comment 17 Yusuke Suzuki 2014-09-12 08:56:14 PDT
Created attachment 238029 [details]
Trunk Perf Results
Comment 18 Yusuke Suzuki 2014-09-12 08:56:52 PDT
Created attachment 238030 [details]
Perf Results with reverting this patch
Comment 19 Yusuke Suzuki 2014-09-12 09:01:42 PDT
I've measured the performance with `Tools/Scripts/run-perf-tests --release Dromaeo/cssquery-jquery.html`, and I've found that actually performance regressions occur in the multiple selectors cases.

Attached perf test results. In this results, 

`div, a, span`: 6999.94/s => 3623.90/s
`div, div, div`: 8511.85/s => 3895.40/s
`div.character, div.dialog`: 11.53k/s => 5343.20/s

results significantly become worse. In the other results, there's no observable performance regression.
Comment 20 Yusuke Suzuki 2014-09-12 11:27:42 PDT
Created attachment 238039 [details]
JIT Compiled version
Comment 21 Benjamin Poulain 2014-09-12 11:31:31 PDT
(In reply to comment #20)
> Created an attachment (id=238039) [details]
> JIT Compiled version

Wow, that's awesome
Comment 22 Yusuke Suzuki 2014-09-12 11:32:47 PDT
Reopening to attach new patch.
Comment 23 Yusuke Suzuki 2014-09-12 11:32:53 PDT
Created attachment 238040 [details]
Patch
Comment 24 Yusuke Suzuki 2014-09-12 11:38:42 PDT
(In reply to comment #21)
> (In reply to comment #20)
> > Created an attachment (id=238039) [details] [details]
> > JIT Compiled version
> 
> Wow, that's awesome

Yeah, I'm surprised at such a great performance gain by applying JIT to multiple selectors!
Benchmarks are very very helpful for optimizing the existing software stacks.
Thank you for your great catch and https://perf.webkit.org/!

I need to monitor https://perf.webkit.org/ :)
And need to run run-perf-tests, it's great!!
Comment 25 Benjamin Poulain 2014-09-12 11:49:30 PDT
Comment on attachment 238040 [details]
Patch

Quick review because I am on the go, but everything looks right.
Comment 26 Benjamin Poulain 2014-09-12 14:48:41 PDT
Created attachment 238060 [details]
Patch
Comment 27 WebKit Commit Bot 2014-09-12 17:03:42 PDT
Comment on attachment 238060 [details]
Patch

Clearing flags on attachment: 238060

Committed r173590: <http://trac.webkit.org/changeset/173590>
Comment 28 WebKit Commit Bot 2014-09-12 17:03:48 PDT
All reviewed patches have been landed.  Closing bug.