Skip to content

Commit a3e58f1

Browse files
committed
Use a Version 1 CFRunLoopSource for faster task dispatch
https://bugs.webkit.org/show_bug.cgi?id=202874 Reviewed by Simon Fraser. Source/WTF: This performance bottleneck showed up in IndexedDB. We worked around it by switching to WorkQueueMessageReceiver. Now it's showing up again in the GPU Process. * wtf/RunLoop.h: Added a mach port. We use this for wake-up. * wtf/cf/RunLoopCF.cpp: (WTF::RunLoop::performWork): Use the standard declaration for a Version 1 run loop source callback. (WTF::RunLoop::RunLoop): Use a dummy mach port for wake-ups. The default wake-up mechanism uses pthread APIs, which cost hundreds of microseconds per invocation, even on the most modern hardware. In contrast, a mach message takes about nine microseconds. (WTF::RunLoop::~RunLoop): Free the mach port. (WTF::RunLoop::wakeUp): Copy-pasted code to signal a mach port. The message payload doesn't matter because we're just trying to achieve a wakeup, kind of like calling a void() function. Tools: Fixed a test incompatibiilty. * TestWebKitAPI/cocoa/UtilitiesCocoa.mm: (TestWebKitAPI::Util::spinRunLoop): Be sure to run the runloop until it runs out of sources to handle. The SuspendServiceWorkerProcessBasedOnClientProcesses test invokes spinRunLoop while adding items to the runloop. Under those conditions, whether a given source will fire or not in a single invocation of CFRunLoopRunInMode is undefined behavior. Canonical link: https://commits.webkit.org/231841@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@270132 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 5913ebf commit a3e58f1

5 files changed

Lines changed: 66 additions & 8 deletions

File tree

Source/WTF/ChangeLog

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
2020-11-20 Geoffrey Garen <ggaren@apple.com>
2+
3+
Use a Version 1 CFRunLoopSource for faster task dispatch
4+
https://bugs.webkit.org/show_bug.cgi?id=202874
5+
6+
Reviewed by Simon Fraser.
7+
8+
This performance bottleneck showed up in IndexedDB. We worked around it
9+
by switching to WorkQueueMessageReceiver. Now it's showing up again
10+
in the GPU Process.
11+
12+
* wtf/RunLoop.h: Added a mach port. We use this for wake-up.
13+
14+
* wtf/cf/RunLoopCF.cpp:
15+
(WTF::RunLoop::performWork): Use the standard declaration for a
16+
Version 1 run loop source callback.
17+
18+
(WTF::RunLoop::RunLoop): Use a dummy mach port for wake-ups. The default
19+
wake-up mechanism uses pthread APIs, which cost hundreds of microseconds
20+
per invocation, even on the most modern hardware. In contrast, a mach
21+
message takes about nine microseconds.
22+
23+
(WTF::RunLoop::~RunLoop): Free the mach port.
24+
25+
(WTF::RunLoop::wakeUp): Copy-pasted code to signal a mach port. The
26+
message payload doesn't matter because we're just trying to achieve
27+
a wakeup, kind of like calling a void() function.
28+
129
2020-11-20 Don Olmstead <don.olmstead@sony.com>
230

331
Remove quota module

Source/WTF/wtf/RunLoop.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,10 @@ class RunLoop final : public FunctionDispatcher {
225225

226226
Lock m_loopLock;
227227
#elif USE(COCOA_EVENT_LOOP)
228-
static void performWork(void*);
228+
static void performWork(CFMachPortRef, void* msg, CFIndex size, void* info);
229229
RetainPtr<CFRunLoopRef> m_runLoop;
230230
RetainPtr<CFRunLoopSourceRef> m_runLoopSource;
231+
RetainPtr<CFMachPortRef> m_port;
231232
#elif USE(GLIB_EVENT_LOOP)
232233
void notify(Event, const char*);
233234

Source/WTF/wtf/cf/RunLoopCF.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <CoreFoundation/CoreFoundation.h>
3030
#include <dispatch/dispatch.h>
31+
#include <mach/mach.h>
3132
#include <wtf/AutodrainedPool.h>
3233
#include <wtf/SchedulePair.h>
3334

@@ -40,29 +41,39 @@ static RetainPtr<CFRunLoopTimerRef> createTimer(Seconds interval, bool repeat, v
4041
return adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval.seconds(), repeatInterval.seconds(), 0, 0, timerFired, &context));
4142
}
4243

43-
void RunLoop::performWork(void* context)
44+
void RunLoop::performWork(CFMachPortRef, void*, CFIndex, void* info)
4445
{
4546
AutodrainedPool pool;
46-
static_cast<RunLoop*>(context)->performWork();
47+
static_cast<RunLoop*>(info)->performWork();
4748
}
4849

4950
RunLoop::RunLoop()
5051
: m_runLoop(CFRunLoopGetCurrent())
5152
{
52-
CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, performWork };
53-
m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));
53+
CFMachPortContext context = { 0, this, nullptr, nullptr, nullptr };
54+
m_port = adoptCF(CFMachPortCreate(kCFAllocatorDefault, performWork, &context, nullptr));
55+
m_runLoopSource = adoptCF(CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_port.get(), 0));
5456
CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopCommonModes);
5557
}
5658

5759
RunLoop::~RunLoop()
5860
{
61+
CFMachPortInvalidate(m_port.get());
5962
CFRunLoopSourceInvalidate(m_runLoopSource.get());
6063
}
6164

6265
void RunLoop::wakeUp()
6366
{
64-
CFRunLoopSourceSignal(m_runLoopSource.get());
65-
CFRunLoopWakeUp(m_runLoop.get());
67+
mach_msg_header_t header;
68+
header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
69+
header.msgh_size = sizeof(mach_msg_header_t);
70+
header.msgh_remote_port = CFMachPortGetPort(m_port.get());
71+
header.msgh_local_port = MACH_PORT_NULL;
72+
header.msgh_id = 0;
73+
mach_msg_return_t result = mach_msg(&header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, header.msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
74+
RELEASE_ASSERT(result == MACH_MSG_SUCCESS || result == MACH_SEND_TIMED_OUT);
75+
if (result == MACH_SEND_TIMED_OUT)
76+
mach_msg_destroy(&header);
6677
}
6778

6879
RunLoop::CycleResult RunLoop::cycle(RunLoopMode mode)

Tools/ChangeLog

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
2020-11-20 Geoffrey Garen <ggaren@apple.com>
2+
3+
Use a Version 1 CFRunLoopSource for faster task dispatch
4+
https://bugs.webkit.org/show_bug.cgi?id=202874
5+
6+
Reviewed by Simon Fraser.
7+
8+
Fixed a test incompatibiilty.
9+
10+
* TestWebKitAPI/cocoa/UtilitiesCocoa.mm:
11+
(TestWebKitAPI::Util::spinRunLoop): Be sure to run the runloop until
12+
it runs out of sources to handle.
13+
14+
The SuspendServiceWorkerProcessBasedOnClientProcesses test invokes
15+
spinRunLoop while adding items to the runloop. Under those conditions,
16+
whether a given source will fire or not in a single invocation of
17+
CFRunLoopRunInMode is undefined behavior.
18+
119
2020-11-20 Don Olmstead <don.olmstead@sony.com>
220

321
Remove quota module

Tools/TestWebKitAPI/cocoa/UtilitiesCocoa.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void run(bool* done)
3838
void spinRunLoop(uint64_t count)
3939
{
4040
for (uint64_t i = 0; i < count; ++i)
41-
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
41+
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) { }
4242
}
4343

4444
void sleep(double seconds)

0 commit comments

Comments
 (0)