Skip to content

Commit

Permalink
perf(css/parser): Reduce clones and allocations (#6585)
Browse files Browse the repository at this point in the history
**Description:**

 - We use `(BytePos, BytePos)` instead of `Box<Span>`.
 - We use `Cow` for `Input`.
  • Loading branch information
kdy1 committed Dec 6, 2022
1 parent 79b2279 commit 6479670
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 55 deletions.
32 changes: 22 additions & 10 deletions crates/swc_css_parser/benches/lexer.rs
Expand Up @@ -20,18 +20,30 @@ fn bench_stylesheet(b: &mut Bencher, src: &'static str) {
});
}

fn bench_files(c: &mut Criterion) {
c.bench_function("css/lexer/bootstrap_5_1_3", |b| {
bench_stylesheet(b, include_str!("./files/bootstrap_5_1_3.css"))
});

c.bench_function("css/lexer/foundation_6_7_4", |b| {
bench_stylesheet(b, include_str!("./files/foundation_6_7_4.css"))
fn run(c: &mut Criterion, id: &str, src: &'static str) {
c.bench_function(&format!("css/parser/{}", id), |b| {
bench_stylesheet(b, src);
});
}

c.bench_function("css/lexer/tailwind_3_1_1", |b| {
bench_stylesheet(b, include_str!("./files/tailwind_3_1_1.css"))
});
fn bench_files(c: &mut Criterion) {
run(
c,
"bootstrap_5_1_3",
include_str!("./files/bootstrap_5_1_3.css"),
);

run(
c,
"foundation_6_7_4",
include_str!("./files/foundation_6_7_4.css"),
);

run(
c,
"tailwind_3_1_1",
include_str!("./files/tailwind_3_1_1.css"),
);
}

criterion_group!(benches, bench_files);
Expand Down
32 changes: 22 additions & 10 deletions crates/swc_css_parser/benches/parser.rs
Expand Up @@ -21,18 +21,30 @@ fn bench_stylesheet(b: &mut Bencher, src: &'static str) {
});
}

fn bench_files(c: &mut Criterion) {
c.bench_function("css/parser/bootstrap_5_1_3", |b| {
bench_stylesheet(b, include_str!("./files/bootstrap_5_1_3.css"))
});

c.bench_function("css/parser/foundation_6_7_4", |b| {
bench_stylesheet(b, include_str!("./files/foundation_6_7_4.css"))
fn run(c: &mut Criterion, id: &str, src: &'static str) {
c.bench_function(&format!("css/parser/{}", id), |b| {
bench_stylesheet(b, src);
});
}

c.bench_function("css/parser/tailwind_3_1_1", |b| {
bench_stylesheet(b, include_str!("./files/tailwind_3_1_1.css"))
});
fn bench_files(c: &mut Criterion) {
run(
c,
"bootstrap_5_1_3",
include_str!("./files/bootstrap_5_1_3.css"),
);

run(
c,
"foundation_6_7_4",
include_str!("./files/foundation_6_7_4.css"),
);

run(
c,
"tailwind_3_1_1",
include_str!("./files/tailwind_3_1_1.css"),
);
}

criterion_group!(benches, bench_files);
Expand Down
4 changes: 2 additions & 2 deletions crates/swc_css_parser/scripts/instruemnt/bench-parser.sh
Expand Up @@ -2,6 +2,6 @@
set -eu

export RUST_LOG=off
export MIMALLOC_SHOW_STATS=1
# export MIMALLOC_SHOW_STATS=1

cargo profile instruments --release -t time --features swc_common/concurrent --bench parser -- --bench --color $@
cargo profile instruments --release -t time --features swc_common/concurrent --bench parser -- $@
78 changes: 45 additions & 33 deletions crates/swc_css_parser/src/parser/input.rs
@@ -1,4 +1,4 @@
use std::{fmt::Debug, mem::take};
use std::{borrow::Cow, fmt::Debug, mem::take};

use swc_atoms::{Atom, JsWord};
use swc_common::{BytePos, Span, Spanned, SyntaxContext};
Expand Down Expand Up @@ -219,16 +219,18 @@ pub enum InputType<'a> {
ListOfComponentValues(&'a ListOfComponentValues),
}

type SpanLike = (BytePos, BytePos);

#[derive(Debug)]
enum TokenOrBlock {
Token(Box<TokenAndSpan>),
enum TokenOrBlock<'a> {
Token(&'a TokenAndSpan),
Function(Box<(Span, JsWord, Atom)>),
LBracket(Box<Span>),
LParen(Box<Span>),
LBrace(Box<Span>),
RParen(Box<Span>),
RBracket(Box<Span>),
RBrace(Box<Span>),
LBracket(SpanLike),
LParen(SpanLike),
LBrace(SpanLike),
RParen(SpanLike),
RBracket(SpanLike),
RBrace(SpanLike),
}

impl<'a> Input<'a> {
Expand Down Expand Up @@ -259,15 +261,15 @@ impl<'a> Input<'a> {
&mut self,
list: &'a [ComponentValue],
deep: usize,
) -> Option<TokenOrBlock> {
) -> Option<TokenOrBlock<'a>> {
let index = match self.idx.get(deep) {
Some(index) => index,
_ => return None,
};

match list.get(*index) {
Some(ComponentValue::PreservedToken(token_and_span)) => {
Some(TokenOrBlock::Token(token_and_span.clone()))
Some(TokenOrBlock::Token(token_and_span))
}
Some(ComponentValue::Function(function)) => {
if self.idx.len() - 1 == deep {
Expand All @@ -288,21 +290,29 @@ impl<'a> Input<'a> {
let res = self.get_component_value(&function.value, deep + 1);

if res.is_none() {
return Some(TokenOrBlock::RParen(Box::new(Span::new(
return Some(TokenOrBlock::RParen((
function.span_hi() - BytePos(1),
function.span_hi(),
Default::default(),
))));
)));
}

res
}
Some(ComponentValue::SimpleBlock(simple_block)) => {
if self.idx.len() - 1 == deep {
let close = match simple_block.name.token {
Token::LBracket => TokenOrBlock::LBracket(Box::new(simple_block.name.span)),
Token::LParen => TokenOrBlock::LParen(Box::new(simple_block.name.span)),
Token::LBrace => TokenOrBlock::LBrace(Box::new(simple_block.name.span)),
Token::LBracket => TokenOrBlock::LBracket((
simple_block.name.span.lo,
simple_block.name.span.hi,
)),
Token::LParen => TokenOrBlock::LParen((
simple_block.name.span.lo,
simple_block.name.span.hi,
)),
Token::LBrace => TokenOrBlock::LBrace((
simple_block.name.span.lo,
simple_block.name.span.hi,
)),
_ => {
unreachable!();
}
Expand All @@ -320,9 +330,9 @@ impl<'a> Input<'a> {
Default::default(),
);
let close = match simple_block.name.token {
Token::LBracket => TokenOrBlock::RBracket(Box::new(span)),
Token::LParen => TokenOrBlock::RParen(Box::new(span)),
Token::LBrace => TokenOrBlock::RBrace(Box::new(span)),
Token::LBracket => TokenOrBlock::RBracket((span.lo, span.hi)),
Token::LParen => TokenOrBlock::RParen((span.lo, span.hi)),
Token::LBrace => TokenOrBlock::RBrace((span.lo, span.hi)),
_ => {
unreachable!();
}
Expand All @@ -340,7 +350,7 @@ impl<'a> Input<'a> {
}
}

fn cur(&mut self) -> PResult<TokenAndSpan> {
fn cur(&mut self) -> PResult<Cow<TokenAndSpan>> {
match self.input {
InputType::Tokens(input) => {
let idx = match self.idx.last() {
Expand All @@ -354,7 +364,7 @@ impl<'a> Input<'a> {
};

let token_and_span = match input.tokens.get(*idx) {
Some(token_and_span) => token_and_span.clone(),
Some(token_and_span) => token_and_span,
None => {
let bp = input.span.hi;
let span = Span::new(bp, bp, SyntaxContext::empty());
Expand All @@ -363,12 +373,14 @@ impl<'a> Input<'a> {
}
};

Ok(token_and_span)
Ok(Cow::Borrowed(token_and_span))
}
InputType::ListOfComponentValues(input) => {
let token_and_span = match self.get_component_value(&input.children, 0) {
Some(token_or_block) => match token_or_block {
TokenOrBlock::Token(token_and_span) => *token_and_span,
TokenOrBlock::Token(token_and_span) => {
return Ok(Cow::Borrowed(token_and_span))
}
TokenOrBlock::Function(function) => TokenAndSpan {
span: function.0,
token: Token::Function {
Expand All @@ -377,27 +389,27 @@ impl<'a> Input<'a> {
},
},
TokenOrBlock::LBracket(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::LBracket,
},
TokenOrBlock::LBrace(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::LBrace,
},
TokenOrBlock::LParen(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::LParen,
},
TokenOrBlock::RBracket(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::RBracket,
},
TokenOrBlock::RBrace(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::RBrace,
},
TokenOrBlock::RParen(span) => TokenAndSpan {
span: *span,
span: Span::new(span.0, span.1, Default::default()),
token: Token::RParen,
},
},
Expand All @@ -409,7 +421,7 @@ impl<'a> Input<'a> {
}
};

Ok(token_and_span)
Ok(Cow::Owned(token_and_span))
}
}
}
Expand Down Expand Up @@ -447,7 +459,7 @@ impl<'a> ParserInput for Input<'a> {
while let Ok(TokenAndSpan {
token: tok!(" "),
span,
}) = self.cur()
}) = self.cur().as_deref()
{
last_pos = Some(span.hi);

Expand All @@ -465,7 +477,7 @@ impl<'a> Iterator for Input<'a> {

fn next(&mut self) -> Option<Self::Item> {
let token_and_span = match self.cur() {
Ok(token_and_span) => token_and_span,
Ok(token_and_span) => token_and_span.into_owned(),
_ => return None,
};

Expand Down

0 comments on commit 6479670

Please sign in to comment.