-
Notifications
You must be signed in to change notification settings - Fork 657
perf(rome_formatter): Add Buffer.elements
#3156
Conversation
✅ Deploy Preview for rometools canceled.
|
!bench_formatter |
PreambleBuffer
Buffer.elements
fd6e822
to
2b24bec
Compare
@@ -34,8 +34,7 @@ const m2 = module/* B1 */{ | |||
export { foo }; /*A5*/ | |||
/*A6*/ | |||
-}; /*A7*/ /*A8*/ | |||
+} /*A7*/ | |||
+/*A8*/ | |||
+} /*A7*/ /*A8*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a look at the comments as part of the comments refactoring (which is why this PR shouldn't be part of the 0.9 release)
2b24bec
to
0613914
Compare
!bench_formatter |
Formatter Benchmark Results
|
Comparing perf(rome_formatter): Add
1 page testedHomeBrowser previews
Most significant changes28 other significant changes: JS Parse & Compile on Chrome Desktop, First Contentful Paint on Motorola Moto G Power, 3G connection, Largest Contentful Paint on Motorola Moto G Power, 3G connection, Speed Index on Motorola Moto G Power, 3G connection, Total Page Size in Bytes on Chrome Desktop, Total Page Size in Bytes on iPhone, 4G LTE, Total Page Size in Bytes on Motorola Moto G Power, 3G connection, First Contentful Paint on Chrome Desktop, Number of Requests on Motorola Moto G Power, 3G connection, Time to Interactive on Motorola Moto G Power, 3G connection, Number of Requests on Chrome Desktop, Number of Requests on iPhone, 4G LTE, First Contentful Paint on iPhone, 4G LTE, Time to Interactive on Chrome Desktop, Speed Index on Chrome Desktop, Largest Contentful Paint on iPhone, 4G LTE, Speed Index on iPhone, 4G LTE, Time to Interactive on iPhone, 4G LTE, Total Blocking Time on Motorola Moto G Power, 3G connection, Largest Contentful Paint on Chrome Desktop, Total Image Size in Bytes on Chrome Desktop, Total Image Size in Bytes on iPhone, 4G LTE, Total Image Size in Bytes on Motorola Moto G Power, 3G connection, Total HTML Size in Bytes on Chrome Desktop, Total HTML Size in Bytes on iPhone, 4G LTE, Total HTML Size in Bytes on Motorola Moto G Power, 3G connection, Lighthouse Performance Score on Motorola Moto G Power, 3G connection, Lighthouse Performance Score on Chrome Desktop Calibre: Site dashboard | View this PR | Edit settings | View documentation |
match module_item { | ||
JsAnyModuleItem::JsAnyStatement(JsAnyStatement::JsEmptyStatement(empty)) => { | ||
join.entry_no_separator(&empty.format()); | ||
} | ||
_ => { | ||
join.entry(module_item.syntax(), &format_or_verbatim(&module_item)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What did we change/fix here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't want to insert empty lines if it is an empty statement because that will get removed. This was previously automatically handled inside of entry
but turns out to be rather expensive. So it's better to explicitly handle it where it is needed.
inner: BufferSnapshot, | ||
has_label: bool, | ||
} | ||
pub fn stop(self) -> Recorded<'buf> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we return a newtype here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No very specific reason. Felt more complete if stop
returns a Recorded
than a slice directly. The new type allows us to implement additional helpers in the future
Summary
It turns out, that using the
PreambleBuffer
in hot code paths is rather expensive. Or in general, nestingBuffer
s can be rather expensive.I discovered this after I implemented a prototype of a Flat IR for our formatter (#2571) where this problem becomes more prominent because
group
,indent
etc are no longer "breaking" the buffer chain by writing into a newVecBuffer
.This PR introduces a new
Buffer.elements()
method that gives access to a slice of all written elements (that are part of this buffer). This allows introspection of the written content very cheaply (may require iteration, but most inspections are only interested in the last element) and in a more natural way (writing custom buffers or even usingmemoized
often feels overly complicated). Another benefit ofelements
over usinginspect
or a custom buffer is that it guarantees that rewinding the buffer is correctly taken into account, something that most uses ofinspect
didn't.The new
elements
method allows removing most uses of thePreambleBuffer
by doing a simplelen
comparison or inspecting the slice content.This PR deletes the unused
WillBreakBuffer
andHaslLabelBuffer
buffers in favour of eitherMemoized.inspect
or usingbuffer.elements()
. We can re-introduce the buffers if it is indeed necessary for some logic to check if any element breaks.The downside of this is that it slightly leaks the
Buffer
extraction as it forces theBuffer
to now always keep hold of all written elements. For example, this prevents us from having a Printer that prints IR elements as they get formatted. I don't think this is a very practical use case with our current Formatter design as it would mean that the printer has to rewind every time the formatter rewinds... meaning that rewinding will result in more work that must the thrown out the window (and overhead for creating the snapshots).I even considered changing
Formatter
to always store aVecBuffer
but there are still a few use cases where a customBuffer
can be useful and we should continue supporting those. Buffers on their own aren't a problem, only if they get insanely stacked. For example, it would probably be better to apply aGroupsElementsBuffer
once in a world where we have a FlatIR rather than nesting it over and over again.Test Plan
cargo tetst
The performance win for our nested IR are less impressive. But it improves performance by roughly 20-25% for a flat IR and more improvements are possible once the
GroupsElementsBuffer
is no longer necessary.