Changeset 251261 in webkit


Ignore:
Timestamp:
Oct 17, 2019 3:05:24 PM (5 years ago)
Author:
sihui_liu@apple.com
Message:

Using version 1 CFRunloopSource for faster task dispatch
https://bugs.webkit.org/show_bug.cgi?id=202874

Reviewed by Geoffrey Garen.

Source/WTF:

We used CFRunLoopWakeUp to wake up runloop to process source, which seems to be slow according to profiling. To
avoid calling CFRunLoopWakeUp, we should use version 1 CFRunloopSource instead of version 0. This patch brings
about 15% speedup for test PerformanceTests/IndexedDB/basic/objectstore-get.html.

  • wtf/RunLoop.cpp:

(WTF::RunLoop::initializeWebRunLoop):
(WTF::RunLoop::web):

  • wtf/RunLoop.h:
  • wtf/cf/RunLoopCF.cpp:

(WTF::RunLoop::performWork):
(WTF::RunLoop::RunLoop):
(WTF::RunLoop::~RunLoop):
(WTF::RunLoop::wakeUp):

  • wtf/cocoa/MainThreadCocoa.mm:

(WTF::initializeMainThreadPlatform):
(WTF::scheduleDispatchFunctionsOnMainThread):
(WTF::initializeWebThread):
(-[JSWTFMainThreadCaller call]): Deleted.

Tools:

Fix a flaky test.

  • TestWebKitAPI/Tests/WebKit/getUserMedia.html:

LayoutTests:

Fix a flaky test.

  • inspector/css/pseudo-creation-expected.txt:
  • inspector/css/pseudo-creation.html:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r251258 r251261  
     12019-10-17  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Using version 1 CFRunloopSource for faster task dispatch
     4        https://bugs.webkit.org/show_bug.cgi?id=202874
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Fix a flaky test.
     9
     10        * inspector/css/pseudo-creation-expected.txt:
     11        * inspector/css/pseudo-creation.html:
     12
    1132019-10-17  Ryosuke Niwa  <rniwa@webkit.org>
    214
  • trunk/LayoutTests/inspector/css/pseudo-creation-expected.txt

    r241189 r251261  
    1313Calling "createElementWithClass("test-pseudo-with-content")"...
    1414Checking for nodes with class ".test-pseudo-with-content"...
     15PASS: There should be 1 node with the class ".test-pseudo-with-content".
    1516PASS: Created ::before pseudo element
    16 PASS: There should be 1 node with the class ".test-pseudo-with-content".
    1717
    1818Calling "removeElementWithClass("test-pseudo-with-content")"...
    1919Checking for nodes with class ".test-pseudo-with-content"...
     20PASS: There should be 0 node with the class ".test-pseudo-with-content".
    2021PASS: Removed ::before pseudo element
    21 PASS: There should be 0 node with the class ".test-pseudo-with-content".
    2222
  • trunk/LayoutTests/inspector/css/pseudo-creation.html

    r249504 r251261  
    2727function test() {
    2828    let documentNode = null;
    29     let pseudoElement = null;
     29    let pseudoElementAdded = null;
     30    let pseudoElementRemoved = null;
    3031
    3132    function handlePromiseReject(error) {
     
    5758    }
    5859
    59     function createElementWithClass(className) {
     60    function createElementWithClass(className, shouldCheckElement) {
    6061        return evaluateWithLog(`createElementWithClass("${className}")`)
    6162        .then(() => checkElementsWithClass(className, 1))
     63        .then(() => {
     64            if (shouldCheckElement) {
     65                if (pseudoElementAdded)
     66                    ProtocolTest.pass(`Created ::${pseudoElementAdded.pseudoType} pseudo element`);
     67                else
     68                    return pseudoElementAddedPromise.then(() => { ProtocolTest.pass(`Created ::${pseudoElementAdded.pseudoType} pseudo element`); });
     69            }
     70        })
    6271        .catch(handlePromiseReject);
    6372    }
    6473
    65     function removeElementWithClass(className) {
     74    function removeElementWithClass(className, shouldCheckElement) {
    6675        return evaluateWithLog(`removeElementWithClass("${className}")`)
    6776        .then(() => checkElementsWithClass(className, 0))
     77        .then(() => {
     78            if (shouldCheckElement) {
     79                if (pseudoElementRemoved)
     80                    ProtocolTest.expectEqual(pseudoElementRemoved.pseudoElementId, pseudoElementAdded.nodeId, `Removed ::${pseudoElementAdded.pseudoType} pseudo element`);
     81                else
     82                    return pseudoElementRemovedPromise.then(() => { ProtocolTest.expectEqual(pseudoElementRemoved.pseudoElementId, pseudoElementAdded.nodeId, `Removed ::${pseudoElementAdded.pseudoType} pseudo element`); });
     83            }
     84        })
    6885        .catch(handlePromiseReject);
    6986    }
    7087
    71     InspectorProtocol.eventHandler["DOM.pseudoElementAdded"] = (response) => {
    72         pseudoElement = response.params.pseudoElement;
     88    let pseudoElementAddedPromise = InspectorProtocol.awaitEvent({event: "DOM.pseudoElementAdded"}).then((event) => { pseudoElementAdded = event.params.pseudoElement});
     89    let pseudoElementRemovedPromise = InspectorProtocol.awaitEvent({event: "DOM.pseudoElementRemoved"}).then((event) => { pseudoElementRemoved = event.params});
    7390
    74         ProtocolTest.pass(`Created ::${pseudoElement.pseudoType} pseudo element`);
    75     };
    76 
    77     InspectorProtocol.eventHandler["DOM.pseudoElementRemoved"] = (response) => {
    78         ProtocolTest.expectEqual(response.params.pseudoElementId, pseudoElement.nodeId, `Removed ::${pseudoElement.pseudoType} pseudo element`);
    79     };
    8091
    8192    ProtocolTest.log("Requesting document...");
     
    8697
    8798        Promise.resolve()
    88         .then(() => createElementWithClass("test-pseudo-without-content"))
    89         .then(() => removeElementWithClass("test-pseudo-without-content"))
    90         .then(() => createElementWithClass("test-pseudo-with-content"))
    91         .then(() => removeElementWithClass("test-pseudo-with-content"))
     99        .then(() => createElementWithClass("test-pseudo-without-content"), false)
     100        .then(() => removeElementWithClass("test-pseudo-without-content"), false)
     101        .then(() => createElementWithClass("test-pseudo-with-content", true))
     102        .then(() => removeElementWithClass("test-pseudo-with-content", true))
    92103        .then(() => ProtocolTest.completeTest())
    93104        .catch(handlePromiseReject);
  • trunk/Source/WTF/ChangeLog

    r251190 r251261  
     12019-10-17  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Using version 1 CFRunloopSource for faster task dispatch
     4        https://bugs.webkit.org/show_bug.cgi?id=202874
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        We used CFRunLoopWakeUp to wake up runloop to process source, which seems to be slow according to profiling. To
     9        avoid calling CFRunLoopWakeUp, we should use version 1 CFRunloopSource instead of version 0. This patch brings
     10        about 15% speedup for test PerformanceTests/IndexedDB/basic/objectstore-get.html.
     11
     12        * wtf/RunLoop.cpp:
     13        (WTF::RunLoop::initializeWebRunLoop):
     14        (WTF::RunLoop::web):
     15        * wtf/RunLoop.h:
     16        * wtf/cf/RunLoopCF.cpp:
     17        (WTF::RunLoop::performWork):
     18        (WTF::RunLoop::RunLoop):
     19        (WTF::RunLoop::~RunLoop):
     20        (WTF::RunLoop::wakeUp):
     21        * wtf/cocoa/MainThreadCocoa.mm:
     22        (WTF::initializeMainThreadPlatform):
     23        (WTF::scheduleDispatchFunctionsOnMainThread):
     24        (WTF::initializeWebThread):
     25        (-[JSWTFMainThreadCaller call]): Deleted.
     26
    1272019-10-16  Wenson Hsieh  <wenson_hsieh@apple.com>
    228
  • trunk/Source/WTF/wtf/RunLoop.cpp

    r248546 r251261  
    3434
    3535static RunLoop* s_mainRunLoop;
     36#if USE(WEB_THREAD)
     37static RunLoop* s_webRunLoop;
     38#endif
    3639
    3740// Helper class for ThreadSpecificData.
     
    6972    return *s_mainRunLoop;
    7073}
     74
     75#if USE(WEB_THREAD)
     76void RunLoop::initializeWebRunLoop()
     77{
     78    s_webRunLoop = &RunLoop::current();
     79}
     80
     81RunLoop& RunLoop::web()
     82{
     83    ASSERT(s_webRunLoop);
     84    return *s_webRunLoop;
     85}
     86#endif
    7187
    7288bool RunLoop::isMain()
  • trunk/Source/WTF/wtf/RunLoop.h

    r251036 r251261  
    5050    // can be called from any thread).
    5151    WTF_EXPORT_PRIVATE static void initializeMainRunLoop();
     52#if USE(WEB_THREAD)
     53    WTF_EXPORT_PRIVATE static void initializeWebRunLoop();
     54#endif
    5255
    5356    WTF_EXPORT_PRIVATE static RunLoop& current();
    5457    WTF_EXPORT_PRIVATE static RunLoop& main();
     58#if USE(WEB_THREAD)
     59    WTF_EXPORT_PRIVATE static RunLoop& web();
     60#endif
    5561    WTF_EXPORT_PRIVATE static bool isMain();
    5662    ~RunLoop();
     
    179185    Lock m_loopLock;
    180186#elif USE(COCOA_EVENT_LOOP)
    181     static void performWork(void*);
     187    static void performWork(CFMachPortRef, void* msg, CFIndex size, void* info);
    182188    RetainPtr<CFRunLoopRef> m_runLoop;
    183189    RetainPtr<CFRunLoopSourceRef> m_runLoopSource;
     190    RetainPtr<CFMachPortRef> m_port;
    184191#elif USE(GLIB_EVENT_LOOP)
    185192    GRefPtr<GMainContext> m_mainContext;
  • trunk/Source/WTF/wtf/cf/RunLoopCF.cpp

    r251036 r251261  
    2929#include <CoreFoundation/CoreFoundation.h>
    3030#include <dispatch/dispatch.h>
     31#include <mach/mach.h>
    3132#include <wtf/AutodrainedPool.h>
    3233
    3334namespace WTF {
    3435
    35 void RunLoop::performWork(void* context)
     36void RunLoop::performWork(CFMachPortRef, void*, CFIndex, void* info)
    3637{
    3738    AutodrainedPool pool;
    38     static_cast<RunLoop*>(context)->performWork();
     39    static_cast<RunLoop*>(info)->performWork();
    3940}
    4041
     
    4243    : m_runLoop(CFRunLoopGetCurrent())
    4344{
    44     CFRunLoopSourceContext context = { 0, this, 0, 0, 0, 0, 0, 0, 0, performWork };
    45     m_runLoopSource = adoptCF(CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context));
     45    CFMachPortContext context = { 0, this, nullptr, nullptr, nullptr };
     46    m_port = adoptCF(CFMachPortCreate(kCFAllocatorDefault, performWork, &context, nullptr));
     47    m_runLoopSource = adoptCF(CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_port.get(), 0));
    4648    CFRunLoopAddSource(m_runLoop.get(), m_runLoopSource.get(), kCFRunLoopCommonModes);
    4749}
     
    4951RunLoop::~RunLoop()
    5052{
     53    CFMachPortInvalidate(m_port.get());
    5154    CFRunLoopSourceInvalidate(m_runLoopSource.get());
    5255}
     
    5962void RunLoop::wakeUp()
    6063{
    61     CFRunLoopSourceSignal(m_runLoopSource.get());
    62     CFRunLoopWakeUp(m_runLoop.get());
     64    mach_msg_header_t header;
     65    header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
     66    header.msgh_size = sizeof(mach_msg_header_t);
     67    header.msgh_remote_port = CFMachPortGetPort(m_port.get());
     68    header.msgh_local_port = MACH_PORT_NULL;
     69    header.msgh_id = 0;
     70    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);
     71    RELEASE_ASSERT(result == MACH_MSG_SUCCESS || result == MACH_SEND_TIMED_OUT);
     72    if (result == MACH_SEND_TIMED_OUT)
     73        mach_msg_destroy(&header);
    6374}
    6475
  • trunk/Source/WTF/wtf/cocoa/MainThreadCocoa.mm

    r251164 r251261  
    3737#import <wtf/HashSet.h>
    3838#import <wtf/RetainPtr.h>
     39#import <wtf/RunLoop.h>
    3940#import <wtf/SchedulePair.h>
    4041#import <wtf/Threading.h>
     
    4344#include <wtf/ios/WebCoreThread.h>
    4445#endif
    45 
    46 @interface JSWTFMainThreadCaller : NSObject
    47 - (void)call;
    48 @end
    49 
    50 @implementation JSWTFMainThreadCaller
    51 
    52 - (void)call
    53 {
    54     WTF::dispatchFunctionsFromMainThread();
    55 }
    56 
    57 @end
    5846
    5947#define LOG_CHANNEL_PREFIX Log
     
    6755#endif
    6856
    69 
    70 static JSWTFMainThreadCaller* staticMainThreadCaller;
    7157static bool isTimerPosted; // This is only accessed on the main thread.
    7258
     
    8571        RELEASE_LOG_FAULT(Threading, "WebKit Threading Violation - initial use of WebKit from a secondary thread.");
    8672    ASSERT(pthread_main_np());
    87 
    88     ASSERT(!staticMainThreadCaller);
    89     staticMainThreadCaller = [[JSWTFMainThreadCaller alloc] init];
    9073}
    9174
     
    11396void scheduleDispatchFunctionsOnMainThread()
    11497{
    115     ASSERT(staticMainThreadCaller);
    116    
    11798#if USE(WEB_THREAD)
    11899    if (isWebThread()) {
     
    122103
    123104    if (mainThreadPthread) {
    124         [staticMainThreadCaller performSelector:@selector(call) onThread:mainThreadNSThread withObject:nil waitUntilDone:NO];
     105        RunLoop::web().dispatch([] {
     106            WTF::dispatchFunctionsFromMainThread();
     107        });
    125108        return;
    126109    }
     
    132115#endif
    133116
    134     [staticMainThreadCaller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:NO];
     117    RunLoop::main().dispatch([] {
     118        WTF::dispatchFunctionsFromMainThread();
     119    });
    135120}
    136121
     
    197182        mainThreadNSThread = [NSThread currentThread];
    198183        sWebThread = &Thread::current();
     184        RunLoop::initializeWebRunLoop();
    199185    });
    200186}
  • trunk/Tools/ChangeLog

    r251259 r251261  
     12019-10-17  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Using version 1 CFRunloopSource for faster task dispatch
     4        https://bugs.webkit.org/show_bug.cgi?id=202874
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Fix a flaky test.
     9
     10        * TestWebKitAPI/Tests/WebKit/getUserMedia.html:
     11
    1122019-10-17  Jonathan Bedard  <jbedard@apple.com>
    213
  • trunk/Tools/TestWebKitAPI/Tests/WebKit/getUserMedia.html

    r250774 r251261  
    33    <head>
    44        <script>
    5 
    6             let stream = null;
     5            let streamPromise = Promise.resolve();
    76
    87            function promptForCapture()
    98            {
    10                 navigator.mediaDevices.enumerateDevices().then(() => {
     9                streamPromise = navigator.mediaDevices.enumerateDevices().then(() => {
    1110                    return navigator.mediaDevices.getUserMedia({ audio: false, video: true })
    12                 }).then((s) => {
     11                });
     12
     13                streamPromise.then((stream) => {
    1314                    stream = s;
    1415                    video.srcObject = stream;
     
    1920            function stop(kind)
    2021            {
    21                 let activeTracks = [];
    22                 stream.getTracks().forEach(track => {
    23                     if (!kind || track.kind == kind)
    24                         track.stop();
    25                     else
    26                         activeTracks.push(track);
     22                streamPromise.then((stream) => {
     23                    let activeTracks = [];
     24                    stream.getTracks().forEach(track => {
     25                        if (!kind || track.kind == kind)
     26                            track.stop();
     27                        else
     28                            activeTracks.push(track);
     29                    });
     30 
     31                    if (!activeTracks.length) {
     32                        streamPromiseDidResolve = false;
     33                        video.srcObject = null;
     34                    }
    2735                });
     36            }
    2837
    29                 if (!activeTracks.length) {
    30                     stream = null;
    31                     video.srcObject = null;
    32                 }
    33             }
     38            let streamPromiseDidResolve = false;
    3439
    3540            function haveStream()
    3641            {
    37                 return stream !== null;
     42                // Our caller polls repeatedly until our promise resolves.
     43                streamPromise.then((stream) => streamPromiseDidResolve = !!stream);
     44                return streamPromiseDidResolve;
    3845            }
    3946
     
    5461            function captureAudio()
    5562            {
    56                 navigator.mediaDevices.getUserMedia({audio: true}).then(s => stream = s);
     63                streamPromise = navigator.mediaDevices.getUserMedia({audio: true});
    5764            }
    5865
    5966            function captureAudioAndVideo()
    6067            {
    61                 navigator.mediaDevices.getUserMedia({audio: true, video: true}).then(s => stream = s);
     68                streamPromise = navigator.mediaDevices.getUserMedia({audio: true, video: true});
    6269            }
    6370        </script>
Note: See TracChangeset for help on using the changeset viewer.