WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
/*
|
2020-05-07 19:49:37 +00:00
|
|
|
* Copyright (C) 2016-2020 Apple Inc. All rights reserved.
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2018-10-15 14:24:49 +00:00
|
|
|
#include <wtf/AutomaticThread.h>
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
|
2018-10-15 14:24:49 +00:00
|
|
|
#include <wtf/DataLog.h>
|
|
|
|
#include <wtf/Threading.h>
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
|
|
|
|
namespace WTF {
|
|
|
|
|
2019-09-18 00:36:19 +00:00
|
|
|
static constexpr bool verbose = false;
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
|
2018-06-23 09:59:04 +00:00
|
|
|
Ref<AutomaticThreadCondition> AutomaticThreadCondition::create()
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
2018-06-23 09:59:04 +00:00
|
|
|
return adoptRef(*new AutomaticThreadCondition);
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AutomaticThreadCondition::AutomaticThreadCondition()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AutomaticThreadCondition::~AutomaticThreadCondition()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThreadCondition::notifyOne(const AbstractLocker& locker)
|
2016-10-19 17:47:30 +00:00
|
|
|
{
|
2016-12-16 22:26:09 +00:00
|
|
|
for (AutomaticThread* thread : m_threads) {
|
|
|
|
if (thread->isWaiting(locker)) {
|
|
|
|
thread->notify(locker);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (AutomaticThread* thread : m_threads) {
|
|
|
|
if (!thread->hasUnderlyingThread(locker)) {
|
|
|
|
thread->start(locker);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_condition.notifyOne();
|
2016-10-19 17:47:30 +00:00
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThreadCondition::notifyAll(const AbstractLocker& locker)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
|
|
|
m_condition.notifyAll();
|
2016-12-16 22:26:09 +00:00
|
|
|
|
|
|
|
for (AutomaticThread* thread : m_threads) {
|
|
|
|
if (thread->isWaiting(locker))
|
|
|
|
thread->notify(locker);
|
|
|
|
else if (!thread->hasUnderlyingThread(locker))
|
|
|
|
thread->start(locker);
|
|
|
|
}
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 20:37:20 +00:00
|
|
|
void AutomaticThreadCondition::wait(Lock& lock)
|
|
|
|
{
|
|
|
|
m_condition.wait(lock);
|
|
|
|
}
|
|
|
|
|
2017-07-04 05:18:15 +00:00
|
|
|
bool AutomaticThreadCondition::waitFor(Lock& lock, Seconds time)
|
|
|
|
{
|
|
|
|
return m_condition.waitFor(lock, time);
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThreadCondition::add(const AbstractLocker&, AutomaticThread* thread)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
|
|
|
ASSERT(!m_threads.contains(thread));
|
|
|
|
m_threads.append(thread);
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThreadCondition::remove(const AbstractLocker&, AutomaticThread* thread)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
|
|
|
m_threads.removeFirst(thread);
|
|
|
|
ASSERT(!m_threads.contains(thread));
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
bool AutomaticThreadCondition::contains(const AbstractLocker&, AutomaticThread* thread)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
|
|
|
return m_threads.contains(thread);
|
|
|
|
}
|
|
|
|
|
2018-06-23 09:59:04 +00:00
|
|
|
AutomaticThread::AutomaticThread(const AbstractLocker& locker, Box<Lock> lock, Ref<AutomaticThreadCondition>&& condition, Seconds timeout)
|
2020-05-07 19:49:37 +00:00
|
|
|
: AutomaticThread(locker, lock, WTFMove(condition), ThreadType::Unknown, timeout)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
AutomaticThread::AutomaticThread(const AbstractLocker& locker, Box<Lock> lock, Ref<AutomaticThreadCondition>&& condition, ThreadType type, Seconds timeout)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
: m_lock(lock)
|
2018-06-23 09:59:04 +00:00
|
|
|
, m_condition(WTFMove(condition))
|
2018-06-08 08:47:06 +00:00
|
|
|
, m_timeout(timeout)
|
2020-05-07 19:49:37 +00:00
|
|
|
, m_threadType(type)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
if (verbose)
|
|
|
|
dataLog(RawPointer(this), ": Allocated AutomaticThread.\n");
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
m_condition->add(locker, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
AutomaticThread::~AutomaticThread()
|
|
|
|
{
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
if (verbose)
|
|
|
|
dataLog(RawPointer(this), ": Deleting AutomaticThread.\n");
|
2021-05-22 16:49:42 +00:00
|
|
|
Locker locker { *m_lock };
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
|
|
|
|
// It's possible that we're in a waiting state with the thread shut down. This is a goofy way to
|
|
|
|
// die, but it could happen.
|
|
|
|
m_condition->remove(locker, this);
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
bool AutomaticThread::tryStop(const AbstractLocker&)
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
{
|
|
|
|
if (!m_isRunning)
|
|
|
|
return true;
|
|
|
|
if (m_hasUnderlyingThread)
|
|
|
|
return false;
|
|
|
|
m_isRunning = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
bool AutomaticThread::isWaiting(const AbstractLocker& locker)
|
2016-12-16 22:26:09 +00:00
|
|
|
{
|
|
|
|
return hasUnderlyingThread(locker) && m_isWaiting;
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
bool AutomaticThread::notify(const AbstractLocker& locker)
|
2016-12-16 22:26:09 +00:00
|
|
|
{
|
|
|
|
ASSERT_UNUSED(locker, hasUnderlyingThread(locker));
|
|
|
|
m_isWaiting = false;
|
|
|
|
return m_waitCondition.notifyOne();
|
|
|
|
}
|
|
|
|
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
void AutomaticThread::join()
|
|
|
|
{
|
2021-05-22 16:49:42 +00:00
|
|
|
Locker locker { *m_lock };
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
while (m_isRunning)
|
|
|
|
m_isRunningCondition.wait(*m_lock);
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThread::start(const AbstractLocker&)
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
{
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
RELEASE_ASSERT(m_isRunning);
|
|
|
|
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
RefPtr<AutomaticThread> preserveThisForThread = this;
|
|
|
|
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
m_hasUnderlyingThread = true;
|
|
|
|
|
2017-12-12 10:35:39 +00:00
|
|
|
Thread::create(
|
2018-06-13 19:07:22 +00:00
|
|
|
name(),
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
[=] () {
|
|
|
|
if (verbose)
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
dataLog(RawPointer(this), ": Running automatic thread!\n");
|
2017-01-06 00:24:11 +00:00
|
|
|
|
|
|
|
RefPtr<AutomaticThread> thread = preserveThisForThread;
|
|
|
|
thread->threadDidStart();
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
|
PerformanceTests:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* JetStream2/wasm/HashSet.cpp:
* StitchMarker/wtf/Assertions.h:
* StitchMarker/wtf/DateMath.cpp:
(WTF::initializeDates):
* StitchMarker/wtf/HashTable.h:
* StitchMarker/wtf/Hasher.h:
(WTF::StringHasher::addCharacters):
* StitchMarker/wtf/NeverDestroyed.h:
(WTF::LazyNeverDestroyed::construct):
* StitchMarker/wtf/StackBounds.h:
(WTF::StackBounds::checkConsistency const):
* StitchMarker/wtf/ValueCheck.h:
* StitchMarker/wtf/Vector.h:
(WTF::minCapacity>::checkConsistency):
* StitchMarker/wtf/text/AtomicStringImpl.cpp:
* StitchMarker/wtf/text/AtomicStringImpl.h:
* StitchMarker/wtf/text/StringCommon.h:
(WTF::hasPrefixWithLettersIgnoringASCIICaseCommon):
* StitchMarker/wtf/text/StringImpl.h:
* StitchMarker/wtf/text/SymbolImpl.h:
* StitchMarker/wtf/text/UniquedStringImpl.h:
Source/JavaScriptCore:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* API/tests/testapi.c:
* assembler/ARM64Assembler.h:
(JSC::ARM64Assembler::replaceWithLoad):
(JSC::ARM64Assembler::replaceWithAddressComputation):
* assembler/AssemblerBuffer.h:
(JSC::AssemblerBuffer::LocalWriter::LocalWriter):
* assembler/LinkBuffer.cpp:
(JSC::LinkBuffer::copyCompactAndLinkCode):
* assembler/ProbeStack.cpp:
(JSC::Probe::Stack::Stack):
* assembler/ProbeStack.h:
* b3/B3FoldPathConstants.cpp:
* b3/B3LowerToAir.cpp:
* b3/B3MemoryValue.cpp:
(JSC::B3::MemoryValue::MemoryValue):
* b3/B3Opcode.cpp:
* b3/B3Type.h:
* b3/B3TypeMap.h:
* b3/B3Width.h:
* b3/air/AirAllocateRegistersAndStackAndGenerateCode.cpp:
(JSC::B3::Air::GenerateAndAllocateRegisters::prepareForGeneration):
(JSC::B3::Air::GenerateAndAllocateRegisters::generate):
* b3/air/AirAllocateRegistersAndStackAndGenerateCode.h:
* b3/air/AirAllocateRegistersByGraphColoring.cpp:
* b3/air/AirArg.cpp:
* b3/air/AirArg.h:
* b3/air/AirCode.h:
* b3/air/AirEmitShuffle.cpp:
(JSC::B3::Air::emitShuffle):
* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createExecutable):
* bytecode/AccessCase.cpp:
* bytecode/AccessCase.h:
* bytecode/CallVariant.cpp:
(JSC::variantListWithVariant):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::ensureCatchLivenessIsComputedForBytecodeIndex):
* bytecode/CodeBlockHash.cpp:
(JSC::CodeBlockHash::dump const):
* bytecode/StructureStubInfo.cpp:
* bytecode/StructureStubInfo.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionCallResolveNode::emitBytecode):
* bytecompiler/RegisterID.h:
(JSC::RegisterID::RegisterID):
(JSC::RegisterID::setIndex):
* debugger/Debugger.cpp:
(JSC::Debugger::removeBreakpoint):
* debugger/DebuggerEvalEnabler.h:
(JSC::DebuggerEvalEnabler::DebuggerEvalEnabler):
(JSC::DebuggerEvalEnabler::~DebuggerEvalEnabler):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::observeTransitions):
* dfg/DFGAbstractValue.cpp:
* dfg/DFGAbstractValue.h:
(JSC::DFG::AbstractValue::merge):
(JSC::DFG::AbstractValue::checkConsistency const):
(JSC::DFG::AbstractValue::assertIsRegistered const):
* dfg/DFGArithMode.h:
(JSC::DFG::doesOverflow):
* dfg/DFGBasicBlock.cpp:
(JSC::DFG::BasicBlock::BasicBlock):
* dfg/DFGBasicBlock.h:
(JSC::DFG::BasicBlock::didLink):
* dfg/DFGCFAPhase.cpp:
(JSC::DFG::CFAPhase::performBlockCFA):
* dfg/DFGCommon.h:
(JSC::DFG::validationEnabled):
* dfg/DFGCommonData.cpp:
(JSC::DFG::CommonData::finalizeCatchEntrypoints):
* dfg/DFGDesiredWatchpoints.h:
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGEdge.h:
(JSC::DFG::Edge::makeWord):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGJITCode.cpp:
(JSC::DFG::JITCode::finalizeOSREntrypoints):
* dfg/DFGObjectAllocationSinkingPhase.cpp:
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* dfg/DFGScoreBoard.h:
(JSC::DFG::ScoreBoard::assertClear):
* dfg/DFGSlowPathGenerator.h:
(JSC::DFG::SlowPathGenerator::generate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
(JSC::DFG::SpeculativeJIT::emitBinarySwitchStringRecurse):
(JSC::DFG::SpeculativeJIT::emitAllocateButterfly):
(JSC::DFG::SpeculativeJIT::compileAllocateNewArrayWithSize):
(JSC::DFG::SpeculativeJIT::compileMakeRope):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
* dfg/DFGStructureAbstractValue.cpp:
* dfg/DFGStructureAbstractValue.h:
(JSC::DFG::StructureAbstractValue::assertIsRegistered const):
* dfg/DFGVarargsForwardingPhase.cpp:
* dfg/DFGVirtualRegisterAllocationPhase.cpp:
(JSC::DFG::VirtualRegisterAllocationPhase::run):
* ftl/FTLLink.cpp:
(JSC::FTL::link):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::callPreflight):
(JSC::FTL::DFG::LowerDFGToB3::callCheck):
(JSC::FTL::DFG::LowerDFGToB3::crash):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* heap/BlockDirectory.cpp:
(JSC::BlockDirectory::assertNoUnswept):
* heap/GCSegmentedArray.h:
(JSC::GCArraySegment::GCArraySegment):
* heap/GCSegmentedArrayInlines.h:
(JSC::GCSegmentedArray<T>::clear):
(JSC::GCSegmentedArray<T>::expand):
(JSC::GCSegmentedArray<T>::validatePrevious):
* heap/HandleSet.cpp:
* heap/HandleSet.h:
* heap/Heap.cpp:
(JSC::Heap::updateAllocationLimits):
* heap/Heap.h:
* heap/MarkedBlock.cpp:
* heap/MarkedBlock.h:
(JSC::MarkedBlock::assertValidCell const):
(JSC::MarkedBlock::assertMarksNotStale):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::beginMarking):
(JSC::MarkedSpace::endMarking):
(JSC::MarkedSpace::assertNoUnswept):
* heap/PreciseAllocation.cpp:
* heap/PreciseAllocation.h:
(JSC::PreciseAllocation::assertValidCell const):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::appendJSCellOrAuxiliary):
* heap/SlotVisitor.h:
* inspector/InspectorProtocolTypes.h:
(Inspector::Protocol::BindingTraits<JSON::ArrayOf<T>>::assertValueHasExpectedType):
* inspector/scripts/codegen/generate_cpp_protocol_types_implementation.py:
(CppProtocolTypesImplementationGenerator._generate_assertion_for_object_declaration):
(CppProtocolTypesImplementationGenerator):
(CppProtocolTypesImplementationGenerator._generate_assertion_for_enum):
* inspector/scripts/tests/generic/expected/type-requiring-runtime-casts.json-result:
* interpreter/FrameTracers.h:
(JSC::JITOperationPrologueCallFrameTracer::JITOperationPrologueCallFrameTracer):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::Interpreter):
* interpreter/Interpreter.h:
* jit/AssemblyHelpers.cpp:
(JSC::AssemblyHelpers::emitStoreStructureWithTypeInfo):
* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::prepareCallOperation):
* jit/BinarySwitch.cpp:
(JSC::BinarySwitch::BinarySwitch):
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupStubArgs):
* jit/CallFrameShuffler.cpp:
(JSC::CallFrameShuffler::emitDeltaCheck):
(JSC::CallFrameShuffler::prepareAny):
* jit/JIT.cpp:
(JSC::JIT::assertStackPointerOffset):
(JSC::JIT::compileWithoutLinking):
* jit/JITOpcodes.cpp:
(JSC::JIT::emitSlow_op_loop_hint):
* jit/JITPropertyAccess.cpp:
(JSC::JIT::emit_op_get_from_scope):
* jit/JITPropertyAccess32_64.cpp:
(JSC::JIT::emit_op_get_from_scope):
* jit/Repatch.cpp:
(JSC::linkPolymorphicCall):
* jit/ThunkGenerators.cpp:
(JSC::emitPointerValidation):
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntOfflineAsmConfig.h:
* parser/Lexer.cpp:
* parser/Lexer.h:
(JSC::isSafeBuiltinIdentifier):
(JSC::Lexer<T>::lexExpectIdentifier):
* runtime/ArgList.h:
(JSC::MarkedArgumentBuffer::setNeedsOverflowCheck):
(JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck):
* runtime/Butterfly.h:
(JSC::ContiguousData::ContiguousData):
(JSC::ContiguousData::Data::Data):
* runtime/HashMapImpl.h:
(JSC::HashMapImpl::checkConsistency const):
(JSC::HashMapImpl::assertBufferIsEmpty const):
* runtime/JSCellInlines.h:
(JSC::JSCell::methodTable const):
* runtime/JSFunction.cpp:
* runtime/JSFunction.h:
(JSC::JSFunction::assertTypeInfoFlagInvariants):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObject.h:
* runtime/JSObject.cpp:
(JSC::JSObject::visitChildren):
(JSC::JSFinalObject::visitChildren):
* runtime/JSObjectInlines.h:
(JSC::JSObject::validatePutOwnDataProperty):
* runtime/JSSegmentedVariableObject.h:
(JSC::JSSegmentedVariableObject::assertVariableIsInThisObject):
* runtime/LiteralParser.cpp:
(JSC::LiteralParser<CharType>::Lexer::lex):
* runtime/LiteralParser.h:
* runtime/Operations.h:
(JSC::scribbleFreeCells):
* runtime/OptionsList.h:
* runtime/VM.cpp:
(JSC::VM::computeCanUseJIT):
* runtime/VM.h:
(JSC::VM::canUseJIT):
* runtime/VarOffset.h:
(JSC::VarOffset::checkSanity const):
* runtime/WeakMapImpl.h:
(JSC::WeakMapImpl::checkConsistency const):
(JSC::WeakMapImpl::assertBufferIsEmpty const):
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::validateInst):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::parseAndCompile):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser::validationFail const):
* wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::checkConsistency):
* wasm/WasmPlan.cpp:
(JSC::Wasm::Plan::tryRemoveContextAndCancelIfLast):
* wasm/WasmSectionParser.h:
* wasm/WasmSections.h:
* wasm/WasmSignatureInlines.h:
(JSC::Wasm::SignatureInformation::get):
* wasm/WasmWorklist.cpp:
(JSC::Wasm::Worklist::enqueue):
* wasm/js/JSToWasm.cpp:
(JSC::Wasm::createJSToWasmWrapper):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::WebAssemblyFunction::previousInstanceOffset const):
Source/WebCore:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* Modules/fetch/FetchBodySource.cpp:
(WebCore::FetchBodySource::close):
* Modules/fetch/FetchBodySource.h:
* Modules/webdatabase/DatabaseDetails.h:
(WebCore::DatabaseDetails::DatabaseDetails):
(WebCore::DatabaseDetails::operator=):
* Modules/webdatabase/DatabaseTask.cpp:
(WebCore::DatabaseTask::performTask):
* Modules/webdatabase/DatabaseTask.h:
* Modules/webdatabase/DatabaseThread.cpp:
(WebCore::DatabaseThread::terminationRequested const):
* Modules/webgpu/WHLSL/AST/WHLSLAddressSpace.h:
(WebCore::WHLSL::AST::TypeAnnotation::TypeAnnotation):
* Modules/webgpu/WHLSL/WHLSLHighZombieFinder.cpp:
(WebCore::WHLSL::findHighZombies):
* Modules/webgpu/WHLSL/WHLSLInferTypes.cpp:
(WebCore::WHLSL::matches):
* Modules/webgpu/WHLSL/WHLSLLiteralTypeChecker.cpp:
(WebCore::WHLSL::checkLiteralTypes):
* Modules/webgpu/WHLSL/WHLSLSynthesizeConstructors.cpp:
(WebCore::WHLSL::FindAllTypes::appendNamedType):
* bindings/js/JSCallbackData.h:
* bindings/js/JSLazyEventListener.cpp:
* bindings/js/JSLazyEventListener.h:
* contentextensions/ContentExtensionCompiler.cpp:
(WebCore::ContentExtensions::compileRuleList):
* css/CSSCalculationValue.cpp:
(WebCore::CSSCalcOperationNode::primitiveType const):
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
* css/CSSPrimitiveValue.cpp:
* css/CSSSelector.cpp:
(WebCore::CSSSelector::selectorText const):
* css/CSSStyleSheet.cpp:
* dom/ActiveDOMObject.cpp:
(WebCore::ActiveDOMObject::suspendIfNeeded):
(WebCore::ActiveDOMObject::assertSuspendIfNeededWasCalled const):
* dom/ActiveDOMObject.h:
* dom/ContainerNode.cpp:
* dom/ContainerNodeAlgorithms.cpp:
* dom/ContainerNodeAlgorithms.h:
* dom/CustomElementReactionQueue.cpp:
* dom/CustomElementReactionQueue.h:
(WebCore::CustomElementReactionDisallowedScope::CustomElementReactionDisallowedScope):
(WebCore::CustomElementReactionDisallowedScope::~CustomElementReactionDisallowedScope):
* dom/Document.cpp:
(WebCore::Document::hitTest):
* dom/Document.h:
(WebCore::Document::decrementReferencingNodeCount):
* dom/Element.cpp:
(WebCore::Element::addShadowRoot):
(WebCore::Element::getURLAttribute const):
(WebCore::Element::getNonEmptyURLAttribute const):
* dom/Element.h:
* dom/ElementAndTextDescendantIterator.h:
(WebCore::ElementAndTextDescendantIterator::ElementAndTextDescendantIterator):
(WebCore::ElementAndTextDescendantIterator::dropAssertions):
(WebCore::ElementAndTextDescendantIterator::popAncestorSiblingStack):
(WebCore::ElementAndTextDescendantIterator::traverseNextSibling):
(WebCore::ElementAndTextDescendantIterator::traversePreviousSibling):
* dom/ElementDescendantIterator.h:
(WebCore::ElementDescendantIterator::ElementDescendantIterator):
(WebCore::ElementDescendantIterator::dropAssertions):
(WebCore::ElementDescendantIterator::operator++):
(WebCore::ElementDescendantIterator::operator--):
(WebCore::ElementDescendantConstIterator::ElementDescendantConstIterator):
(WebCore::ElementDescendantConstIterator::dropAssertions):
(WebCore::ElementDescendantConstIterator::operator++):
* dom/ElementIterator.h:
(WebCore::ElementIterator<ElementType>::ElementIterator):
(WebCore::ElementIterator<ElementType>::traverseNext):
(WebCore::ElementIterator<ElementType>::traversePrevious):
(WebCore::ElementIterator<ElementType>::traverseNextSibling):
(WebCore::ElementIterator<ElementType>::traversePreviousSibling):
(WebCore::ElementIterator<ElementType>::traverseNextSkippingChildren):
(WebCore::ElementIterator<ElementType>::dropAssertions):
(WebCore::ElementIterator<ElementType>::traverseAncestor):
(WebCore::ElementConstIterator<ElementType>::ElementConstIterator):
(WebCore::ElementConstIterator<ElementType>::traverseNext):
(WebCore::ElementConstIterator<ElementType>::traversePrevious):
(WebCore::ElementConstIterator<ElementType>::traverseNextSibling):
(WebCore::ElementConstIterator<ElementType>::traversePreviousSibling):
(WebCore::ElementConstIterator<ElementType>::traverseNextSkippingChildren):
(WebCore::ElementConstIterator<ElementType>::traverseAncestor):
(WebCore::ElementConstIterator<ElementType>::dropAssertions):
* dom/EventContext.cpp:
* dom/EventContext.h:
* dom/EventListener.h:
* dom/EventPath.cpp:
* dom/EventSender.h:
* dom/EventTarget.cpp:
(WebCore::EventTarget::addEventListener):
(WebCore::EventTarget::setAttributeEventListener):
(WebCore::EventTarget::innerInvokeEventListeners):
* dom/Node.cpp:
(WebCore::Node::~Node):
(WebCore::Node::moveNodeToNewDocument):
(WebCore::Node::removedLastRef):
* dom/Node.h:
(WebCore::Node::deref const):
* dom/ScriptDisallowedScope.h:
(WebCore::ScriptDisallowedScope::InMainThread::isEventDispatchAllowedInSubtree):
* dom/ScriptExecutionContext.cpp:
(WebCore::ScriptExecutionContext::~ScriptExecutionContext):
* dom/ScriptExecutionContext.h:
* dom/SelectorQuery.cpp:
(WebCore::SelectorDataList::execute const):
* dom/SlotAssignment.cpp:
(WebCore::SlotAssignment::addSlotElementByName):
(WebCore::SlotAssignment::removeSlotElementByName):
(WebCore::SlotAssignment::resolveSlotsAfterSlotMutation):
(WebCore::SlotAssignment::findFirstSlotElement):
* dom/SlotAssignment.h:
* dom/TreeScopeOrderedMap.cpp:
(WebCore::TreeScopeOrderedMap::add):
(WebCore::TreeScopeOrderedMap::get const):
* dom/TreeScopeOrderedMap.h:
* fileapi/Blob.cpp:
* fileapi/Blob.h:
* history/BackForwardCache.cpp:
(WebCore::BackForwardCache::removeAllItemsForPage):
* history/BackForwardCache.h:
* html/CanvasBase.cpp:
(WebCore::CanvasBase::notifyObserversCanvasDestroyed):
* html/CanvasBase.h:
* html/HTMLCollection.h:
(WebCore::CollectionNamedElementCache::didPopulate):
* html/HTMLSelectElement.cpp:
(WebCore:: const):
* html/HTMLTableRowsCollection.cpp:
(WebCore::assertRowIsInTable):
* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::indexForPosition const):
* html/canvas/CanvasRenderingContext2DBase.cpp:
(WebCore::CanvasRenderingContext2DBase::~CanvasRenderingContext2DBase):
* html/parser/HTMLParserScheduler.cpp:
(WebCore::HTMLParserScheduler::HTMLParserScheduler):
(WebCore::HTMLParserScheduler::suspend):
(WebCore::HTMLParserScheduler::resume):
* html/parser/HTMLParserScheduler.h:
* html/parser/HTMLToken.h:
(WebCore::HTMLToken::beginStartTag):
(WebCore::HTMLToken::beginEndTag):
(WebCore::HTMLToken::endAttribute):
* html/parser/HTMLTreeBuilder.cpp:
(WebCore::HTMLTreeBuilder::HTMLTreeBuilder):
(WebCore::HTMLTreeBuilder::constructTree):
* html/parser/HTMLTreeBuilder.h:
(WebCore::HTMLTreeBuilder::~HTMLTreeBuilder):
* layout/FormattingContext.cpp:
(WebCore::Layout::FormattingContext::geometryForBox const):
* layout/blockformatting/BlockFormattingContext.cpp:
(WebCore::Layout::BlockFormattingContext::computeEstimatedVerticalPosition):
* layout/blockformatting/BlockFormattingContext.h:
* layout/displaytree/DisplayBox.cpp:
(WebCore::Display::Box::Box):
* layout/displaytree/DisplayBox.h:
(WebCore::Display::Box::setTopLeft):
(WebCore::Display::Box::setTop):
(WebCore::Display::Box::setLeft):
(WebCore::Display::Box::setContentBoxHeight):
(WebCore::Display::Box::setContentBoxWidth):
(WebCore::Display::Box::setHorizontalMargin):
(WebCore::Display::Box::setVerticalMargin):
(WebCore::Display::Box::setHorizontalComputedMargin):
(WebCore::Display::Box::setBorder):
(WebCore::Display::Box::setPadding):
* layout/displaytree/DisplayInlineRect.h:
(WebCore::Display::InlineRect::InlineRect):
(WebCore::Display::InlineRect::setTopLeft):
(WebCore::Display::InlineRect::setTop):
(WebCore::Display::InlineRect::setBottom):
(WebCore::Display::InlineRect::setLeft):
(WebCore::Display::InlineRect::setWidth):
(WebCore::Display::InlineRect::setHeight):
* layout/displaytree/DisplayLineBox.h:
(WebCore::Display::LineBox::LineBox):
(WebCore::Display::LineBox::setBaselineOffsetIfGreater):
(WebCore::Display::LineBox::resetBaseline):
(WebCore::Display::LineBox::Baseline::Baseline):
(WebCore::Display::LineBox::Baseline::setAscent):
(WebCore::Display::LineBox::Baseline::setDescent):
(WebCore::Display::LineBox::Baseline::reset):
* layout/displaytree/DisplayRect.h:
(WebCore::Display::Rect::Rect):
(WebCore::Display::Rect::setTopLeft):
(WebCore::Display::Rect::setTop):
(WebCore::Display::Rect::setLeft):
(WebCore::Display::Rect::setWidth):
(WebCore::Display::Rect::setHeight):
(WebCore::Display::Rect::setSize):
(WebCore::Display::Rect::clone const):
* layout/floats/FloatingContext.cpp:
* layout/inlineformatting/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::CollapsibleContent::collapse):
* layout/tableformatting/TableGrid.cpp:
(WebCore::Layout::TableGrid::Column::setWidthConstraints):
(WebCore::Layout::TableGrid::Column::setLogicalWidth):
(WebCore::Layout::TableGrid::Column::setLogicalLeft):
* layout/tableformatting/TableGrid.h:
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::continueAfterContentPolicy):
(WebCore::DocumentLoader::attachToFrame):
(WebCore::DocumentLoader::detachFromFrame):
(WebCore::DocumentLoader::addSubresourceLoader):
* loader/DocumentLoader.h:
* loader/ImageLoader.cpp:
* loader/cache/CachedResource.h:
* loader/cache/MemoryCache.cpp:
(WebCore::MemoryCache::lruListFor):
(WebCore::MemoryCache::removeFromLRUList):
* page/FrameView.cpp:
(WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive):
* page/FrameViewLayoutContext.cpp:
* page/FrameViewLayoutContext.h:
* page/Page.cpp:
* page/Page.h:
* page/ViewportConfiguration.cpp:
* page/ViewportConfiguration.h:
* page/mac/EventHandlerMac.mm:
(WebCore::CurrentEventScope::CurrentEventScope):
* platform/DateComponents.cpp:
(WebCore::DateComponents::toStringForTime const):
* platform/ScrollableArea.cpp:
* platform/SharedBuffer.cpp:
(WebCore::SharedBuffer::combineIntoOneSegment const):
* platform/SharedBuffer.h:
* platform/Supplementable.h:
* platform/Timer.cpp:
(WebCore::TimerBase::checkHeapIndex const):
(WebCore::TimerBase::updateHeapIfNeeded):
* platform/graphics/BitmapImage.cpp:
* platform/graphics/BitmapImage.h:
* platform/graphics/Image.h:
* platform/graphics/ShadowBlur.cpp:
(WebCore::ScratchBuffer::ScratchBuffer):
(WebCore::ScratchBuffer::getScratchBuffer):
(WebCore::ScratchBuffer::scheduleScratchBufferPurge):
* platform/graphics/ca/win/CACFLayerTreeHost.cpp:
(WebCore::CACFLayerTreeHost::setWindow):
* platform/graphics/ca/win/CACFLayerTreeHost.h:
* platform/graphics/cg/ImageBufferDataCG.cpp:
(WebCore::ImageBufferData::putData):
* platform/graphics/cocoa/FontCacheCoreText.cpp:
* platform/graphics/gstreamer/GstAllocatorFastMalloc.cpp:
(gstAllocatorFastMallocFree):
* platform/graphics/nicosia/cairo/NicosiaPaintingContextCairo.cpp:
(Nicosia::PaintingContextCairo::ForPainting::ForPainting):
* platform/graphics/nicosia/texmap/NicosiaBackingStoreTextureMapperImpl.cpp:
(Nicosia::BackingStoreTextureMapperImpl::createTile):
* platform/graphics/nicosia/texmap/NicosiaContentLayerTextureMapperImpl.cpp:
(Nicosia::ContentLayerTextureMapperImpl::~ContentLayerTextureMapperImpl):
* platform/graphics/win/GradientDirect2D.cpp:
(WebCore::Gradient::fill):
* platform/graphics/win/ImageBufferDataDirect2D.cpp:
(WebCore::ImageBufferData::putData):
* platform/graphics/win/PathDirect2D.cpp:
(WebCore::Path::appendGeometry):
(WebCore::Path::Path):
(WebCore::Path::operator=):
(WebCore::Path::strokeContains const):
(WebCore::Path::transform):
* platform/graphics/win/PlatformContextDirect2D.cpp:
(WebCore::PlatformContextDirect2D::setTags):
* platform/mediastream/MediaStreamTrackPrivate.h:
* platform/mediastream/RealtimeOutgoingAudioSource.cpp:
(WebCore::RealtimeOutgoingAudioSource::~RealtimeOutgoingAudioSource):
* platform/mediastream/RealtimeOutgoingVideoSource.cpp:
(WebCore::RealtimeOutgoingVideoSource::~RealtimeOutgoingVideoSource):
* platform/network/HTTPParsers.cpp:
(WebCore::isCrossOriginSafeHeader):
* platform/sql/SQLiteDatabase.cpp:
* platform/sql/SQLiteDatabase.h:
* platform/sql/SQLiteStatement.cpp:
(WebCore::SQLiteStatement::SQLiteStatement):
(WebCore::SQLiteStatement::prepare):
(WebCore::SQLiteStatement::finalize):
* platform/sql/SQLiteStatement.h:
* platform/win/COMPtr.h:
* rendering/ComplexLineLayout.cpp:
(WebCore::ComplexLineLayout::removeInlineBox const):
* rendering/FloatingObjects.cpp:
(WebCore::FloatingObject::FloatingObject):
(WebCore::FloatingObjects::addPlacedObject):
(WebCore::FloatingObjects::removePlacedObject):
* rendering/FloatingObjects.h:
* rendering/GridTrackSizingAlgorithm.cpp:
* rendering/GridTrackSizingAlgorithm.h:
* rendering/LayoutDisallowedScope.cpp:
* rendering/LayoutDisallowedScope.h:
* rendering/RenderBlock.cpp:
* rendering/RenderBlock.h:
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutBlockChild):
(WebCore::RenderBlockFlow::removeFloatingObject):
(WebCore::RenderBlockFlow::ensureLineBoxes):
* rendering/RenderBoxModelObject.cpp:
* rendering/RenderDeprecatedFlexibleBox.cpp:
(WebCore::RenderDeprecatedFlexibleBox::layoutBlock):
* rendering/RenderElement.cpp:
* rendering/RenderGeometryMap.cpp:
(WebCore::RenderGeometryMap::mapToContainer const):
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::placeItemsOnGrid const):
(WebCore::RenderGrid::baselinePosition const):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::willBeDestroyed):
* rendering/RenderLayer.cpp:
(WebCore::ClipRectsCache::ClipRectsCache):
(WebCore::RenderLayer::RenderLayer):
(WebCore::RenderLayer::paintList):
(WebCore::RenderLayer::hitTestLayer):
(WebCore::RenderLayer::updateClipRects):
(WebCore::RenderLayer::calculateClipRects const):
* rendering/RenderLayer.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::traverseVisibleNonCompositedDescendantLayers):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::computeCompositingRequirements):
(WebCore::RenderLayerCompositor::traverseUnchangedSubtree):
(WebCore::RenderLayerCompositor::updateBackingAndHierarchy):
(WebCore::RenderLayerCompositor::addDescendantsToOverlapMapRecursive const):
(WebCore::RenderLayerCompositor::recursiveRepaintLayer):
(WebCore::RenderLayerCompositor::layerHas3DContent const):
* rendering/RenderLayoutState.cpp:
(WebCore::RenderLayoutState::RenderLayoutState):
(WebCore::RenderLayoutState::computeOffsets):
(WebCore::RenderLayoutState::addLayoutDelta):
* rendering/RenderLayoutState.h:
(WebCore::RenderLayoutState::RenderLayoutState):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::RenderObject):
(WebCore::RenderObject::~RenderObject):
(WebCore::RenderObject::clearNeedsLayout):
* rendering/RenderObject.h:
* rendering/RenderQuote.cpp:
(WebCore::quotesForLanguage):
* rendering/RenderTableCell.h:
* rendering/RenderTableSection.cpp:
(WebCore::RenderTableSection::computeOverflowFromCells):
* rendering/RenderTextLineBoxes.cpp:
(WebCore::RenderTextLineBoxes::checkConsistency const):
* rendering/RenderTextLineBoxes.h:
* rendering/line/BreakingContext.h:
(WebCore::tryHyphenating):
* rendering/style/GridArea.h:
(WebCore::GridSpan::GridSpan):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::~RenderStyle):
* rendering/style/RenderStyle.h:
* rendering/updating/RenderTreeBuilderRuby.cpp:
(WebCore::RenderTreeBuilder::Ruby::detach):
* rendering/updating/RenderTreePosition.cpp:
(WebCore::RenderTreePosition::computeNextSibling):
* rendering/updating/RenderTreePosition.h:
* svg/SVGToOTFFontConversion.cpp:
(WebCore::SVGToOTFFontConverter::Placeholder::Placeholder):
(WebCore::SVGToOTFFontConverter::Placeholder::populate):
(WebCore::SVGToOTFFontConverter::appendCFFTable):
(WebCore::SVGToOTFFontConverter::firstGlyph const):
(WebCore::SVGToOTFFontConverter::appendKERNTable):
* svg/SVGTransformDistance.cpp:
(WebCore::SVGTransformDistance::SVGTransformDistance):
(WebCore::SVGTransformDistance::scaledDistance const):
(WebCore::SVGTransformDistance::addSVGTransforms):
(WebCore::SVGTransformDistance::addToSVGTransform const):
(WebCore::SVGTransformDistance::distance const):
* svg/graphics/SVGImage.cpp:
(WebCore::SVGImage::nativeImage):
* testing/InternalSettings.cpp:
* workers/service/ServiceWorkerJob.h:
* worklets/PaintWorkletGlobalScope.h:
(WebCore::PaintWorkletGlobalScope::~PaintWorkletGlobalScope):
* xml/XPathStep.cpp:
Source/WebKit:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::invalidateAndCancel):
* NetworkProcess/NetworkSession.h:
* NetworkProcess/cache/NetworkCacheStorage.cpp:
(WebKit::NetworkCache::Storage::setCapacity):
* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(toNSURLSessionResponseDisposition):
(WebKit::NetworkSessionCocoa::NetworkSessionCocoa):
* Platform/IPC/Connection.cpp:
(IPC::Connection::waitForMessage):
* Platform/IPC/MessageReceiver.h:
(IPC::MessageReceiver::willBeAddedToMessageReceiverMap):
(IPC::MessageReceiver::willBeRemovedFromMessageReceiverMap):
* Platform/IPC/cocoa/ConnectionCocoa.mm:
(IPC::readFromMachPort):
* Platform/mac/MachUtilities.cpp:
(setMachExceptionPort):
* Shared/API/APIClient.h:
(API::Client::Client):
* Shared/API/Cocoa/WKRemoteObjectCoder.mm:
* Shared/Cocoa/ArgumentCodersCocoa.h:
* Shared/SharedStringHashTableReadOnly.cpp:
* UIProcess/BackingStore.cpp:
(WebKit::BackingStore::incorporateUpdate):
* UIProcess/GenericCallback.h:
* UIProcess/Launcher/mac/ProcessLauncherMac.mm:
(WebKit::ProcessLauncher::launchProcess):
* UIProcess/PageLoadState.h:
(WebKit::PageLoadState::Transaction::Token::Token):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::~WebPageProxy):
* WebProcess/Network/WebResourceLoader.cpp:
(WebKit::WebResourceLoader::didReceiveResponse):
* WebProcess/Network/WebResourceLoader.h:
* WebProcess/Plugins/Netscape/NetscapePluginStream.cpp:
(WebKit::NetscapePluginStream::NetscapePluginStream):
(WebKit::NetscapePluginStream::notifyAndDestroyStream):
* WebProcess/Plugins/Netscape/NetscapePluginStream.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::runModal):
* WebProcess/WebProcess.cpp:
(WebKit::checkDocumentsCaptureStateConsistency):
* WebProcess/cocoa/WebProcessCocoa.mm:
(WebKit::WebProcess::updateProcessName):
Source/WebKitLegacy:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* Storage/StorageAreaImpl.cpp:
(WebKit::StorageAreaImpl::StorageAreaImpl):
(WebKit::StorageAreaImpl::close):
* Storage/StorageAreaImpl.h:
Source/WebKitLegacy/mac:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* History/WebHistory.mm:
(-[WebHistoryPrivate removeItemForURLString:]):
* WebView/WebFrame.mm:
Source/WebKitLegacy/win:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
* WebKitQuartzCoreAdditions/CAD3DRenderer.cpp:
(WKQCA::CAD3DRenderer::swapChain):
(WKQCA::CAD3DRenderer::initialize):
* WebKitQuartzCoreAdditions/CAD3DRenderer.h:
* WebView.cpp:
(WebView::Release):
* WebView.h:
Source/WTF:
Convert ASSERT_DISABLED to ASSERT_ENABLED, and fix some tests of NDEBUG that should actually test for ASSERT_ENABLED.
https://bugs.webkit.org/show_bug.cgi?id=205776
Reviewed by Saam Barati.
This patch did the following changes:
1. Replaced ASSERT_DISABLED with ASSERT_ENABLED. This change does away
with the need for the double negative !ASSERT_DISABLED test that is commonly
used all over the code, thereby improving code readability.
In Assertions.h, there is also BACKTRACE_DISABLED, ASSERT_MSG_DISABLED,
ASSERT_ARG_DISABLED, FATAL_DISABLED, ERROR_DISABLED, LOG_DISABLED, and
RELEASE_LOG_DISABLED. We should replace those with ..._ENABLED equivalents
as well. We'll do that in another patch. For now, they are left as is to
minimize the size of this patch.
See https://bugs.webkit.org/show_bug.cgi?id=205780.
2. Fixed some code was guarded with "#ifndef NDEBUG" that should actually be
guarded by "#if ASSERT_ENABLED" instead.
3. In cases where the change is minimal, we move some code around so that we can
test for "#if ASSERT_ENABLED" instead of "#if !ASSERT_ENABLED".
* wtf/Assertions.h:
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThread::start):
* wtf/BitVector.h:
* wtf/BlockObjCExceptions.mm:
(ReportBlockedObjCException):
* wtf/BloomFilter.h:
* wtf/CallbackAggregator.h:
(WTF::CallbackAggregator::CallbackAggregator):
* wtf/CheckedArithmetic.h:
(WTF::observesOverflow<AssertNoOverflow>):
* wtf/CheckedBoolean.h:
(CheckedBoolean::CheckedBoolean):
(CheckedBoolean::operator bool):
* wtf/CompletionHandler.h:
(WTF::CompletionHandler<Out):
* wtf/DateMath.cpp:
(WTF::initializeDates):
* wtf/Gigacage.cpp:
(Gigacage::tryAllocateZeroedVirtualPages):
* wtf/HashTable.h:
(WTF::KeyTraits>::checkKey):
(WTF::KeyTraits>::checkTableConsistencyExceptSize const):
* wtf/LoggerHelper.h:
* wtf/NaturalLoops.h:
(WTF::NaturalLoops::headerOf const):
* wtf/NeverDestroyed.h:
(WTF::LazyNeverDestroyed::construct):
* wtf/OptionSet.h:
(WTF::OptionSet::OptionSet):
* wtf/Platform.h:
* wtf/PtrTag.h:
* wtf/RefCounted.h:
(WTF::RefCountedBase::disableThreadingChecks):
(WTF::RefCountedBase::enableThreadingChecksGlobally):
(WTF::RefCountedBase::RefCountedBase):
(WTF::RefCountedBase::applyRefDerefThreadingCheck const):
* wtf/SingleRootGraph.h:
(WTF::SingleRootGraph::assertIsConsistent const):
* wtf/SizeLimits.cpp:
* wtf/StackBounds.h:
(WTF::StackBounds::checkConsistency const):
* wtf/URLParser.cpp:
(WTF::URLParser::URLParser):
(WTF::URLParser::domainToASCII):
* wtf/ValueCheck.h:
* wtf/Vector.h:
(WTF::Malloc>::checkConsistency):
* wtf/WeakHashSet.h:
* wtf/WeakPtr.h:
(WTF::WeakPtrImpl::WeakPtrImpl):
(WTF::WeakPtrFactory::WeakPtrFactory):
* wtf/text/AtomStringImpl.cpp:
* wtf/text/AtomStringImpl.h:
* wtf/text/StringBuilder.cpp:
(WTF::StringBuilder::reifyString const):
* wtf/text/StringBuilder.h:
* wtf/text/StringCommon.h:
(WTF::hasPrefixWithLettersIgnoringASCIICaseCommon):
* wtf/text/StringHasher.h:
(WTF::StringHasher::addCharacters):
* wtf/text/StringImpl.h:
* wtf/text/SymbolImpl.h:
* wtf/text/UniquedStringImpl.h:
Tools:
Remove WebsiteDataStore::setServiceWorkerRegistrationDirectory
https://bugs.webkit.org/show_bug.cgi?id=205754
Patch by Alex Christensen <achristensen@webkit.org> on 2020-01-06
Reviewed by Youenn Fablet.
* TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::websiteDataStore):
(WTR::TestController::platformAdjustContext):
* WebKitTestRunner/cocoa/TestControllerCocoa.mm:
(WTR::initializeWebViewConfiguration):
Canonical link: https://commits.webkit.org/218957@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@254087 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2020-01-06 22:24:50 +00:00
|
|
|
if (ASSERT_ENABLED) {
|
2021-05-22 16:49:42 +00:00
|
|
|
Locker locker { *m_lock };
|
2016-12-16 22:26:09 +00:00
|
|
|
ASSERT(m_condition->contains(locker, this));
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
auto stopImpl = [&] (const AbstractLocker& locker) {
|
2017-01-06 00:24:11 +00:00
|
|
|
thread->threadIsStopping(locker);
|
|
|
|
thread->m_hasUnderlyingThread = false;
|
|
|
|
};
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
auto stopPermanently = [&] (const AbstractLocker& locker) {
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
m_isRunning = false;
|
|
|
|
m_isRunningCondition.notifyAll();
|
2017-01-06 00:24:11 +00:00
|
|
|
stopImpl(locker);
|
|
|
|
};
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
auto stopForTimeout = [&] (const AbstractLocker& locker) {
|
2017-01-06 00:24:11 +00:00
|
|
|
stopImpl(locker);
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
{
|
2021-05-22 16:49:42 +00:00
|
|
|
Locker locker { *m_lock };
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
for (;;) {
|
|
|
|
PollResult result = poll(locker);
|
|
|
|
if (result == PollResult::Work)
|
|
|
|
break;
|
|
|
|
if (result == PollResult::Stop)
|
2017-01-06 00:24:11 +00:00
|
|
|
return stopPermanently(locker);
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
RELEASE_ASSERT(result == PollResult::Wait);
|
2017-05-18 18:56:15 +00:00
|
|
|
|
|
|
|
// Shut the thread down after a timeout.
|
2016-12-16 22:26:09 +00:00
|
|
|
m_isWaiting = true;
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
bool awokenByNotify =
|
2018-06-08 08:47:06 +00:00
|
|
|
m_waitCondition.waitFor(*m_lock, m_timeout);
|
2016-12-16 22:26:09 +00:00
|
|
|
if (verbose && !awokenByNotify && !m_isWaiting)
|
|
|
|
dataLog(RawPointer(this), ": waitFor timed out, but notified via m_isWaiting flag!\n");
|
2018-06-08 08:47:06 +00:00
|
|
|
if (m_isWaiting && shouldSleep(locker)) {
|
2016-12-16 22:26:09 +00:00
|
|
|
m_isWaiting = false;
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
if (verbose)
|
The GC should be in a thread
https://bugs.webkit.org/show_bug.cgi?id=163562
Reviewed by Geoffrey Garen and Andreas Kling.
Source/JavaScriptCore:
In a concurrent GC, the work of collecting happens on a separate thread. This patch
implements this, and schedules the thread the way that a concurrent GC thread would be
scheduled. But, the GC isn't actually concurrent yet because it calls stopTheWorld() before
doing anything and calls resumeTheWorld() after it's done with everything. The next step will
be to make it really concurrent by basically calling stopTheWorld()/resumeTheWorld() around
bounded snippets of work while making most of the work happen with the world running. Our GC
will probably always have stop-the-world phases because the semantics of JSC weak references
call for it.
This implements concurrent GC scheduling. This means that there is no longer a
Heap::collect() API. Instead, you can call collectAsync() which makes sure that a GC is
scheduled (it will do nothing if one is scheduled or ongoing) or you can call collectSync()
to schedule a GC and wait for it to happen. I made our debugging stuff call collectSync().
It should be a goal to never call collectSync() except for debugging or benchmark harness
hacks.
The collector thread is an AutomaticThread, so it won't linger when not in use. It works on
a ticket-based system, like you would see at the DMV. A ticket is a 64-bit integer. There are
two ticket counters: last granted and last served. When you request a collection, last
granted is incremented and its new value given to you. When a collection completes, last
served is incremented. collectSync() waits until last served catches up to what last granted
had been at the time you requested a GC. This means that if you request a sync GC in the
middle of an async GC, you will wait for that async GC to finish and then you will request
and wait for your sync GC.
The synchronization between the collector thread and the main threads is complex. The
collector thread needs to be able to ask the main thread to stop. It needs to be able to do
some post-GC clean-up, like the synchronous CodeBlock and LargeAllocation sweeps, on the main
thread. The collector needs to be able to ask the main thread to execute a cross-modifying
code fence before running any JIT code, since the GC might aid the JIT worklist and run JIT
finalization. It's possible for the GC to want the main thread to run something at the same
time that the main thread wants to wait for the GC. The main thread needs to be able to run
non-JSC stuff without causing the GC to completely stall. The main thread needs to be able
to query its own state (is there a request to stop?) and change it (running JSC versus not)
quickly, since this may happen on hot paths. This kind of intertwined system of requests,
notifications, and state changes requires a combination of lock-free algorithms and waiting.
So, this is all implemented using a Atomic<unsigned> Heap::m_worldState, which has bits to
represent things being requested by the collector and the heap access state of the mutator. I
am borrowing a lot of terms that I've seen in other VMs that I've worked on. Here's what they
mean:
- Stop the world: make sure that either the mutator is not running, or that it's not running
code that could mess with the heap.
- Heap access: the mutator is said to have heap access if it could mess with the heap.
If you stop the world and the mutator doesn't have heap access, all you're doing is making
sure that it will block when it tries to acquire heap access. This means that our GC is
already fully concurrent in cases where the GC is requested while the mutator has no heap
access. This probably won't happen, but if it did then it should just work. Usually, stopping
the world means that we state our shouldStop request with m_worldState, and a future call
to Heap::stopIfNecessary() will go to slow path and stop. The act of stopping or waiting to
acquire heap access is managed by using ParkingLot API directly on m_worldState. This works
out great because it would be very awkward to get the same functionality using locks and
condition variables, since we want stopIfNecessary/acquireAccess/requestAccess fast paths
that are single atomic instructions (load/CAS/CAS, respectively). The mutator will call these
things frequently. Currently we have Heap::stopIfNecessary() polling on every allocator slow
path, but we may want to make it even more frequent than that.
Currently only JSC API clients benefit from the heap access optimization. The DOM forces us
to assume that heap access is permanently on, since DOM manipulation doesn't always hold the
JSLock. We could still allow the GC to proceed when the runloop is idle by having the GC put
a task on the runloop that just calls stopIfNecessary().
This is perf neutral. The only behavior change that clients ought to observe is that marking
and the weak fixpoint happen on a separate thread. Marking was already parallel so it already
handled multiple threads, but now it _never_ runs on the main thread. The weak fixpoint
needed some help to be able to run on another thread - mostly because there was some code in
IndexedDB that was using thread specifics in the weak fixpoint.
* API/JSBase.cpp:
(JSSynchronousEdenCollectForDebugging):
* API/JSManagedValue.mm:
(-[JSManagedValue initWithValue:]):
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::doCollection):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::markRoots):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::deleteUnmarkedCompiledCode):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInThread):
(JSC::Heap::collectInThread):
(JSC::Heap::stopTheWorld):
(JSC::Heap::resumeTheWorld):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::handleDidJIT):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::setDidJIT):
(JSC::Heap::setNeedFinalize):
(JSC::Heap::waitWhileNeedFinalize):
(JSC::Heap::finalize):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::didFinishCollection):
(JSC::Heap::canCollect):
(JSC::Heap::shouldCollectHeuristic):
(JSC::Heap::shouldCollect):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::collectAccordingToDeferGCProbability):
(JSC::Heap::collect): Deleted.
(JSC::Heap::collectWithoutAnySweep): Deleted.
(JSC::Heap::collectImpl): Deleted.
* heap/Heap.h:
(JSC::Heap::ReleaseAccessScope::ReleaseAccessScope):
(JSC::Heap::ReleaseAccessScope::~ReleaseAccessScope):
* heap/HeapInlines.h:
(JSC::Heap::acquireAccess):
(JSC::Heap::releaseAccess):
(JSC::Heap::stopIfNecessary):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::MachineThreads::gatherFromCurrentThread): Deleted.
* heap/MachineStackMarker.h:
* jit/JITWorklist.cpp:
(JSC::JITWorklist::completeAllForVM):
* jit/JITWorklist.h:
* jsc.cpp:
(functionFullGC):
(functionEdenGC):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
(JSC::JSLock::unlock):
(JSC::JSLock::willReleaseLock):
* tools/JSDollarVMPrototype.cpp:
(JSC::JSDollarVMPrototype::edenGC):
Source/WebCore:
No new tests because existing tests cover this.
We now need to be more careful about using JSLock. This fixes some places that were not
holding it. New assertions in the GC are more likely to catch this than before.
* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
Source/WTF:
This fixes some bugs and adds a few features.
* wtf/Atomics.h: The GC may do work on behalf of the JIT. If it does, the main thread needs to execute a cross-modifying code fence. This is cpuid on x86 and I believe it's isb on ARM. It would have been an isync on PPC and I think that isb is the ARM equivalent.
(WTF::arm_isb):
(WTF::crossModifyingCodeFence):
(WTF::x86_ortop):
(WTF::x86_cpuid):
* wtf/AutomaticThread.cpp: I accidentally had AutomaticThreadCondition inherit from ThreadSafeRefCounted<AutomaticThread> [sic]. This never crashed before because all of our prior AutomaticThreadConditions were immortal.
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h:
* wtf/MainThread.cpp: Need to allow initializeGCThreads() to be called separately because it's now more than just a debugging thing.
(WTF::initializeGCThreads):
Canonical link: https://commits.webkit.org/182065@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-02 22:01:04 +00:00
|
|
|
dataLog(RawPointer(this), ": Going to sleep!\n");
|
2017-01-06 00:24:11 +00:00
|
|
|
// It's important that we don't release the lock until we have completely
|
|
|
|
// indicated that the thread is kaput. Otherwise we'll have a a notify
|
|
|
|
// race that manifests as a deadlock on VM shutdown.
|
|
|
|
return stopForTimeout(locker);
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WorkResult result = work();
|
|
|
|
if (result == WorkResult::Stop) {
|
2021-05-22 16:49:42 +00:00
|
|
|
Locker locker { *m_lock };
|
2017-01-06 00:24:11 +00:00
|
|
|
return stopPermanently(locker);
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
RELEASE_ASSERT(result == WorkResult::Continue);
|
|
|
|
}
|
2020-05-07 19:49:37 +00:00
|
|
|
}, m_threadType)->detach();
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 17:47:30 +00:00
|
|
|
void AutomaticThread::threadDidStart()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737
Reviewed by Keith Miller.
JSTests:
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.
* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
Source/JavaScriptCore:
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
In this new world, "stopping the world" means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term "conn" to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator<->collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):
Source/WebCore:
Added new tests in JSTests.
The WebCore changes involve:
- Refactoring around new header discipline.
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:
Source/WTF:
Extend the use of AbstractLocker so that we can use more locking idioms.
* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:
Tools:
Make more tests collect continuously.
* Scripts/run-jsc-stress-tests:
Canonical link: https://commits.webkit.org/185692@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@212778 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2017-02-22 00:58:15 +00:00
|
|
|
void AutomaticThread::threadIsStopping(const AbstractLocker&)
|
2016-10-19 17:47:30 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
WTF should make it easier to create threads that die automatically after inactivity
https://bugs.webkit.org/show_bug.cgi?id=163576
Reviewed by Andreas Kling.
Source/JavaScriptCore:
Added a sleepSeconds() function, which made it easier for me to test this change.
The WTF changes in this patch change how the JSC GC manages threads: the GC threads will now
shut down automatically after 1 second of inactivity. Maybe this will save some memory.
* jsc.cpp:
(GlobalObject::finishCreation):
(functionSleepSeconds):
Source/WTF:
For a long time now, I've been adding threads to WTF/JSC and each time I do this, I feel
guilty because those threads don't shut down when they are inactive. For example, in bug
163562, I need to add a new GC thread. There will be one of them per VM. This means that a
JSC API client that starts a lot of VMs will have a lot of threads. I don't think that's
good.
A common pattern for all of these threads is that they have some well-defined trigger that
causes them to run. This trigger has a lock, a condition variable, some logic that determines
if there is work to do, and then of course the logic for the thread's actual work. The thread
bodies usually look like this:
void Thingy::runThread()
{
for (;;) {
Work work;
{
LockHolder locker(m_lock);
while (!hasWork())
m_cond.wait(m_lock);
work = takeWork();
}
doWork(work);
}
}
If you look at ParallelHelperPool (the GC's threads) and DFG::Worklist (some of the JIT's
threads), you will see this pattern.
This change adds a new kind of thread, called AutomaticThread, that lets you write threads to
this pattern while getting automatic thread shutdown for free: instead of just waiting on a
condition variable, AutomaticThread will have a timeout that causes the thread to die. The
condition variable associated with AutomaticThread, called AutomaticThreadCondition, is smart
enough to restart any threads that have decided to stop due to inactivity. The inactivity
threshold is current just 1 second.
In this patch I only adopt AutomaticThread for ParallelHelperPool. I plan to adopt it in more
places soon.
* WTF.xcodeproj/project.pbxproj:
* wtf/AutomaticThread.cpp: Added.
(WTF::AutomaticThreadCondition::create):
(WTF::AutomaticThreadCondition::AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::~AutomaticThreadCondition):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::~AutomaticThread):
(WTF::AutomaticThread::join):
(WTF::AutomaticThread::start):
* wtf/AutomaticThread.h: Added.
* wtf/CMakeLists.txt:
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::ParallelHelperClient):
(WTF::ParallelHelperClient::~ParallelHelperClient):
(WTF::ParallelHelperClient::setTask):
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::doSomeHelping):
(WTF::ParallelHelperClient::runTask):
(WTF::ParallelHelperPool::ParallelHelperPool):
(WTF::ParallelHelperPool::~ParallelHelperPool):
(WTF::ParallelHelperPool::ensureThreads):
(WTF::ParallelHelperPool::doSomeHelping):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::helperThreadBody): Deleted.
(WTF::ParallelHelperPool::waitForClientWithTask): Deleted.
* wtf/ParallelHelperPool.h:
Canonical link: https://commits.webkit.org/181393@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207480 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-10-18 20:17:10 +00:00
|
|
|
} // namespace WTF
|
|
|
|
|