Build handler payloads without extra cross-thread calls for IGeckoBackChannel bulk fetch methods
Categories
(Core :: Disability Access APIs, enhancement, P3)
Tracking
()
Tracking | Status | |
---|---|---|
firefox77 | --- | fixed |
People
(Reporter: Jamie, Assigned: Jamie)
References
Details
(Keywords: perf)
Attachments
(4 files)
HandlerProvider currently implements two methods on IGeckoBackChannel which bulk fetch objects to avoid extra cross-process calls: get_AllTextInfo and get_AllChildren.
- These methods are called on an MTA thread, but dispatch most of their work to the main thread.
- In the main thread, any objects to be returned must be (and are) wrapped in Interceptors.
- Back in the MTA thread, when COM marshals the result of these calls back to the client, it marshals each returned object, but that requires building handler payloads for each one.
- Since handler payloads have to be built on the main thread, that means we make a separate cross-thread call for each object.
If there are a lot of objects, this means quite a lot of cross-thread calls, incurring unnecessary overhead.
Instead, we can build the payload for the object as we wrap it in the Interceptor (step 2 above). That means these bulk fetch calls only require one cross-thread call.
Refreshing the NVDA buffer for a simple 7000 item list takes ~4.3 sec on Nightly. With my WIP patch for this, it takes ~3.9 sec, a ~9.3% decrease.
This is tricky to get right for a couple of reasons:
- There's currently no way to get a HandlerProvider from an Interceptor. In my WIP patch, I've added methods to do this, but it's somewhat ugly with a few static_casts.
- If multiple callers simultaneously access the same object, I think we might run into race conditions. We have a mutex on the serializer, but I don't think we can use that here because of potential deadlocks.
Assignee | ||
Comment 1•5 years ago
|
||
Here's why I don't think we can use HandlerProvider::mMutex for the pre-built payload:
- MTA thread 1 makes a bulk fetch call. It gets dispatched to the main thread.
- MTA thread 2 retrieves object o. It needs the payload for o, so it acquires the mutex. It then queues a call to the main thread to build the payload.
- In the main thread, the bulk fetch call needs to build a payload for o. It tries to acquire the mutex.
- Unfortunately, the mutex is already being held by MTA thread 2, which is waiting on the main thread to process its request to build the payload. Deadlock!
Assignee | ||
Comment 2•5 years ago
|
||
Because MainThreadHandoff sits between the Interceptor and the HandlerProvider, the caller must:
- Get the event sink (the MainThreadhandoff) from the Interceptor; and
- Get the HandlerProvider from the MainThreadHandoff.
Because IInterceptorSink has no knowledge of HandlerProviders, the caller has to static_cast the IInterceptorSink from step 1 to MainThreadHandoff.
Assignee | ||
Comment 3•5 years ago
|
||
This avoids separate cross-thread calls when marshaling each object returned from an IGeckoBackChannel bulk fetch method.
Assignee | ||
Comment 4•5 years ago
|
||
We need to define INITGUID here in a subsequent patch, which is incompatible with unified mode.
Updated•5 years ago
|
Updated•5 years ago
|
Assignee | ||
Comment 5•5 years ago
|
||
- CleanupStaticIA2Data just called ReleaseStaticIA2DataInterfaces and zeroed memory.
We don't need it to zero memory, since we're going to delete the data anyway.
So, just call ReleaseStaticIA2DataInterfaces directly and get rid of CleanupStaticIA2Data. - CleanupDynamicIA2Data had a aZeroMemory argument, but no caller ever set it to true.
Therefore, get rid of the argument.
Comment 7•5 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/269ca6f2610c
https://hg.mozilla.org/mozilla-central/rev/24936cdfa320
https://hg.mozilla.org/mozilla-central/rev/927287985117
https://hg.mozilla.org/mozilla-central/rev/13b01a46138c
Description
•