tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bench.rs (6820B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 use cssparser::SourceLocation;
      6 use rayon;
      7 use servo_arc::Arc;
      8 use servo_url::ServoUrl;
      9 use style::context::QuirksMode;
     10 use style::error_reporting::{ContextualParseError, ParseErrorReporter};
     11 use style::media_queries::MediaList;
     12 use style::properties::{longhands, Importance, PropertyDeclaration, PropertyDeclarationBlock};
     13 use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
     14 use style::shared_lock::SharedRwLock;
     15 use style::stylesheets::{CssRule, Origin, Stylesheet};
     16 use style::thread_state::{self, ThreadState};
     17 use test::{self, Bencher};
     18 
     19 struct ErrorringErrorReporter;
     20 impl ParseErrorReporter for ErrorringErrorReporter {
     21    fn report_error(&self, url: &ServoUrl, location: SourceLocation, error: ContextualParseError) {
     22        panic!(
     23            "CSS error: {}\t\n{}:{} {}",
     24            url.as_str(),
     25            location.line,
     26            location.column,
     27            error
     28        );
     29    }
     30 }
     31 
     32 struct AutoGCRuleTree<'a>(&'a RuleTree);
     33 
     34 impl<'a> AutoGCRuleTree<'a> {
     35    fn new(r: &'a RuleTree) -> Self {
     36        AutoGCRuleTree(r)
     37    }
     38 }
     39 
     40 impl<'a> Drop for AutoGCRuleTree<'a> {
     41    fn drop(&mut self) {
     42        unsafe {
     43            self.0.gc();
     44            assert!(
     45                ::std::thread::panicking() || !self.0.root().has_children_for_testing(),
     46                "No rule nodes other than the root shall remain!"
     47            );
     48        }
     49    }
     50 }
     51 
     52 fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
     53    let lock = SharedRwLock::new();
     54    let media = Arc::new(lock.wrap(MediaList::empty()));
     55 
     56    let s = Stylesheet::from_str(
     57        css,
     58        ServoUrl::parse("http://localhost").unwrap(),
     59        Origin::Author,
     60        media,
     61        lock,
     62        None,
     63        Some(&ErrorringErrorReporter),
     64        QuirksMode::NoQuirks,
     65        0,
     66    );
     67    let guard = s.shared_lock.read();
     68    let rules = s.contents.rules.read_with(&guard);
     69    rules
     70        .0
     71        .iter()
     72        .filter_map(|rule| match *rule {
     73            CssRule::Style(ref style_rule) => Some((
     74                StyleSource::from_rule(style_rule.clone()),
     75                CascadeLevel::UserNormal,
     76            )),
     77            _ => None,
     78        })
     79        .collect()
     80 }
     81 
     82 fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>) -> StrongRuleNode {
     83    rule_tree.insert_ordered_rules(rules.into_iter())
     84 }
     85 
     86 fn test_insertion_style_attribute(
     87    rule_tree: &RuleTree,
     88    rules: &[(StyleSource, CascadeLevel)],
     89    shared_lock: &SharedRwLock,
     90 ) -> StrongRuleNode {
     91    let mut rules = rules.to_vec();
     92    rules.push((
     93        StyleSource::from_declarations(Arc::new(shared_lock.wrap(
     94            PropertyDeclarationBlock::with_one(
     95                PropertyDeclaration::Display(longhands::display::SpecifiedValue::Block),
     96                Importance::Normal,
     97            ),
     98        ))),
     99        CascadeLevel::UserNormal,
    100    ));
    101    test_insertion(rule_tree, rules)
    102 }
    103 
    104 #[bench]
    105 fn bench_insertion_basic(b: &mut Bencher) {
    106    let r = RuleTree::new();
    107    thread_state::initialize(ThreadState::SCRIPT);
    108 
    109    let rules_matched = parse_rules(
    110        ".foo { width: 200px; } \
    111         .bar { height: 500px; } \
    112         .baz { display: block; }",
    113    );
    114 
    115    b.iter(|| {
    116        let _gc = AutoGCRuleTree::new(&r);
    117 
    118        for _ in 0..(4000 + 400) {
    119            test::black_box(test_insertion(&r, rules_matched.clone()));
    120        }
    121    })
    122 }
    123 
    124 #[bench]
    125 fn bench_insertion_basic_per_element(b: &mut Bencher) {
    126    let r = RuleTree::new();
    127    thread_state::initialize(ThreadState::SCRIPT);
    128 
    129    let rules_matched = parse_rules(
    130        ".foo { width: 200px; } \
    131         .bar { height: 500px; } \
    132         .baz { display: block; }",
    133    );
    134 
    135    b.iter(|| {
    136        let _gc = AutoGCRuleTree::new(&r);
    137 
    138        test::black_box(test_insertion(&r, rules_matched.clone()));
    139    });
    140 }
    141 
    142 #[bench]
    143 fn bench_expensive_insertion(b: &mut Bencher) {
    144    let r = RuleTree::new();
    145    thread_state::initialize(ThreadState::SCRIPT);
    146 
    147    // This test case tests a case where you style a bunch of siblings
    148    // matching the same rules, with a different style attribute each
    149    // one.
    150    let rules_matched = parse_rules(
    151        ".foo { width: 200px; } \
    152         .bar { height: 500px; } \
    153         .baz { display: block; }",
    154    );
    155 
    156    let shared_lock = SharedRwLock::new();
    157    b.iter(|| {
    158        let _gc = AutoGCRuleTree::new(&r);
    159 
    160        for _ in 0..(4000 + 400) {
    161            test::black_box(test_insertion_style_attribute(
    162                &r,
    163                &rules_matched,
    164                &shared_lock,
    165            ));
    166        }
    167    });
    168 }
    169 
    170 #[bench]
    171 fn bench_insertion_basic_parallel(b: &mut Bencher) {
    172    let r = RuleTree::new();
    173    thread_state::initialize(ThreadState::SCRIPT);
    174 
    175    let rules_matched = parse_rules(
    176        ".foo { width: 200px; } \
    177         .bar { height: 500px; } \
    178         .baz { display: block; }",
    179    );
    180 
    181    b.iter(|| {
    182        let _gc = AutoGCRuleTree::new(&r);
    183 
    184        rayon::scope(|s| {
    185            for _ in 0..4 {
    186                s.spawn(|s| {
    187                    for _ in 0..1000 {
    188                        test::black_box(test_insertion(&r, rules_matched.clone()));
    189                    }
    190                    s.spawn(|_| {
    191                        for _ in 0..100 {
    192                            test::black_box(test_insertion(&r, rules_matched.clone()));
    193                        }
    194                    })
    195                })
    196            }
    197        });
    198    });
    199 }
    200 
    201 #[bench]
    202 fn bench_expensive_insertion_parallel(b: &mut Bencher) {
    203    let r = RuleTree::new();
    204    thread_state::initialize(ThreadState::SCRIPT);
    205 
    206    let rules_matched = parse_rules(
    207        ".foo { width: 200px; } \
    208         .bar { height: 500px; } \
    209         .baz { display: block; }",
    210    );
    211 
    212    let shared_lock = SharedRwLock::new();
    213    b.iter(|| {
    214        let _gc = AutoGCRuleTree::new(&r);
    215 
    216        rayon::scope(|s| {
    217            for _ in 0..4 {
    218                s.spawn(|s| {
    219                    for _ in 0..1000 {
    220                        test::black_box(test_insertion_style_attribute(
    221                            &r,
    222                            &rules_matched,
    223                            &shared_lock,
    224                        ));
    225                    }
    226                    s.spawn(|_| {
    227                        for _ in 0..100 {
    228                            test::black_box(test_insertion_style_attribute(
    229                                &r,
    230                                &rules_matched,
    231                                &shared_lock,
    232                            ));
    233                        }
    234                    })
    235                })
    236            }
    237        });
    238    });
    239 }