Skip to content

Coalesce ScrollView Messages #7260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
8 commits merged into from
Mar 4, 2021
Merged

Conversation

NickGerleman
Copy link
Contributor

@NickGerleman NickGerleman commented Mar 3, 2021

Fixes #7237
Fixes #7256

The overall goal of this change is to fix performance issues impacting FlatList. See the above issues for more details. See examples below for how we respond to synthetically bad React render performance.

Before

Lacks.coalescing.mp4

After

Fixed.coalescing.mp4

This is largely based on what Android does, where they wait until the end of a frame, then queue a message to JS to pump the batch (with coalescing).

This is exposed to the ABI, but is on the periphery instead of being added to ReactContext.

Microsoft Reviewers: Open in CodeFlow

Fixes microsoft#7237
Fixes microsoft#7256

The overall goal of this change is to fix performance issues impacting FlatList. See the above issues for more details.

This is largely based on what Android does, where they wait until the end of a frame, then queue a message to JS to pump the batch (with coalescing).

This is exposed to the ABI, but is on the periphery instead of being added to ReactContext.
- Move to emitter-per-viewmanager instead of emitter-per-instance. This helps with removing conflicts and keeping short queue length
- Remove coalesceKey in favor of automatically partitioning based on event name + tag
- Make friendlier to C++ non/ABI generated types
- Lots of renaming and documentation to make intent clearer
- A couple of internal changes
@NickGerleman
Copy link
Contributor Author

FYI @htpiv @asklar I just pushed out a new implementation. Some of the changes:

  • Move to emitter-per-viewmanager instead of emitter-per-instance. This helps with removing conflicts and keeping short queue length. Not doing per-shadownode to avoid being wasteful with the queues.
  • Remove coalesceKey in favor of automatically partitioning based on event name + tag. We may still want more control in the future though.
  • Make friendlier to C++ non/ABI generated types
  • Lots of renaming and documentation to make intent clearer
  • A couple of internal changes

Copy link
Member

@vmoroz vmoroz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@NickGerleman NickGerleman added the AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity) label Mar 4, 2021
@ghost
Copy link

ghost commented Mar 4, 2021

Hello @NickGerleman!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit c6b776e into microsoft:master Mar 4, 2021
// have a non-zero size queue, so we want to only trigger pumping when the
// first element is added to an empty queue.
if (queueSizeAfterInsert == 1) {
m_renderingRevoker = xaml::Media::CompositionTarget::Rendering(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you have a bug here... if you have just 1 coalesced event in the queue, if you add a second coalesced event with the same key, you'll remove the 1 event in the erase-remove bit, and then you'll add a new event, re-registering for Rendering. Probably want to check if m_renderingRevoker already has a valid token in it before registering? So, like:

bool shouldRegister = queueWasEmpty && !m_renderingRevoker;

(I think revokers have an operator bool for this?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it looks like there is a bug here. We cannot rely on the revoker though, just because it is possible we have an open batch with unregistered revoker. Seems like we can check the size before coalescing though.

void OnFrameJS() noexcept;

Mso::CntPtr<const Mso::React::IReactContext> m_context;
std::deque<implementation::BatchedEvent> m_eventQueue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that VC++'s deque is pretty much useless, I would use a list here so the behavior is more obvious to people who don't have dumb trivia about VC++ memorized

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deque is semantically the structure we want, even if the implementation isn't great.

I'm still holding out for an official C++ ABI break where everyone goes and optimizes their data structures 😉


implementation::BatchedEvent newEvent{std::move(emitterMethod), tag, std::move(eventName), std::move(eventObject)};

size_t queueSizeAfterInsert;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, I'd make this a bool named queueWasEmpty or something like that, since you don't really care about the size, just that it was previously empty.

NickGerleman added a commit to NickGerleman/react-native-windows that referenced this pull request Mar 5, 2021
ghost pushed a commit that referenced this pull request Mar 5, 2021
…queue (#7287)

* Avoid re-registering render callbacks when coalescing single element queue

Addresses a bug raised in #7260 (comment)

* Change files

* Crash if trying to register callback when one already registered
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: FlatList Area: Performance AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity)
Projects
None yet
5 participants