haikuwebkit/Source/WTF/wtf/ParallelHelperPool.h

218 lines
9.1 KiB
C
Raw Permalink Normal View History

VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +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
* Copyright (C) 2015-2017 Apple Inc. All rights reserved.
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +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.
*/
Use pragma once in WTF https://bugs.webkit.org/show_bug.cgi?id=190527 Reviewed by Chris Dumez. Source/WTF: We also need to consistently include wtf headers from within wtf so we can build wtf without symbol redefinition errors from including the copy in Source and the copy in the build directory. * wtf/ASCIICType.h: * wtf/Assertions.cpp: * wtf/Assertions.h: * wtf/Atomics.h: * wtf/AutomaticThread.cpp: * wtf/AutomaticThread.h: * wtf/BackwardsGraph.h: * wtf/Bag.h: * wtf/BagToHashMap.h: * wtf/BitVector.cpp: * wtf/BitVector.h: * wtf/Bitmap.h: * wtf/BloomFilter.h: * wtf/Box.h: * wtf/BubbleSort.h: * wtf/BumpPointerAllocator.h: * wtf/ByteOrder.h: * wtf/CPUTime.cpp: * wtf/CallbackAggregator.h: * wtf/CheckedArithmetic.h: * wtf/CheckedBoolean.h: * wtf/ClockType.cpp: * wtf/ClockType.h: * wtf/CommaPrinter.h: * wtf/CompilationThread.cpp: * wtf/CompilationThread.h: * wtf/Compiler.h: * wtf/ConcurrentPtrHashSet.cpp: * wtf/ConcurrentVector.h: * wtf/Condition.h: * wtf/CountingLock.cpp: * wtf/CrossThreadTaskHandler.cpp: * wtf/CryptographicUtilities.cpp: * wtf/CryptographicUtilities.h: * wtf/CryptographicallyRandomNumber.cpp: * wtf/CryptographicallyRandomNumber.h: * wtf/CurrentTime.cpp: * wtf/DataLog.cpp: * wtf/DataLog.h: * wtf/DateMath.cpp: * wtf/DateMath.h: * wtf/DecimalNumber.cpp: * wtf/DecimalNumber.h: * wtf/Deque.h: * wtf/DisallowCType.h: * wtf/Dominators.h: * wtf/DoublyLinkedList.h: * wtf/FastBitVector.cpp: * wtf/FastMalloc.cpp: * wtf/FastMalloc.h: * wtf/FeatureDefines.h: * wtf/FilePrintStream.cpp: * wtf/FilePrintStream.h: * wtf/FlipBytes.h: * wtf/FunctionDispatcher.cpp: * wtf/FunctionDispatcher.h: * wtf/GetPtr.h: * wtf/Gigacage.cpp: * wtf/GlobalVersion.cpp: * wtf/GraphNodeWorklist.h: * wtf/GregorianDateTime.cpp: * wtf/GregorianDateTime.h: * wtf/HashFunctions.h: * wtf/HashMap.h: * wtf/HashMethod.h: * wtf/HashSet.h: * wtf/HashTable.cpp: * wtf/HashTraits.h: * wtf/Indenter.h: * wtf/IndexSparseSet.h: * wtf/InlineASM.h: * wtf/Insertion.h: * wtf/IteratorAdaptors.h: * wtf/IteratorRange.h: * wtf/JSONValues.cpp: * wtf/JSValueMalloc.cpp: * wtf/LEBDecoder.h: * wtf/Language.cpp: * wtf/ListDump.h: * wtf/Lock.cpp: * wtf/Lock.h: * wtf/LockAlgorithm.h: * wtf/LockedPrintStream.cpp: * wtf/Locker.h: * wtf/MD5.cpp: * wtf/MD5.h: * wtf/MainThread.cpp: * wtf/MainThread.h: * wtf/MallocPtr.h: * wtf/MathExtras.h: * wtf/MediaTime.cpp: * wtf/MediaTime.h: * wtf/MemoryPressureHandler.cpp: * wtf/MessageQueue.h: * wtf/MetaAllocator.cpp: * wtf/MetaAllocator.h: * wtf/MetaAllocatorHandle.h: * wtf/MonotonicTime.cpp: * wtf/MonotonicTime.h: * wtf/NakedPtr.h: * wtf/NoLock.h: * wtf/NoTailCalls.h: * wtf/Noncopyable.h: * wtf/NumberOfCores.cpp: * wtf/NumberOfCores.h: * wtf/OSAllocator.h: * wtf/OSAllocatorPosix.cpp: * wtf/OSRandomSource.cpp: * wtf/OSRandomSource.h: * wtf/ObjcRuntimeExtras.h: * wtf/OrderMaker.h: * wtf/PackedIntVector.h: * wtf/PageAllocation.h: * wtf/PageBlock.cpp: * wtf/PageBlock.h: * wtf/PageReservation.h: * wtf/ParallelHelperPool.cpp: * wtf/ParallelHelperPool.h: * wtf/ParallelJobs.h: * wtf/ParallelJobsLibdispatch.h: * wtf/ParallelVectorIterator.h: * wtf/ParkingLot.cpp: * wtf/ParkingLot.h: * wtf/Platform.h: * wtf/PointerComparison.h: * wtf/Poisoned.cpp: * wtf/PrintStream.cpp: * wtf/PrintStream.h: * wtf/ProcessID.h: * wtf/ProcessPrivilege.cpp: * wtf/RAMSize.cpp: * wtf/RAMSize.h: * wtf/RandomDevice.cpp: * wtf/RandomNumber.cpp: * wtf/RandomNumber.h: * wtf/RandomNumberSeed.h: * wtf/RangeSet.h: * wtf/RawPointer.h: * wtf/ReadWriteLock.cpp: * wtf/RedBlackTree.h: * wtf/Ref.h: * wtf/RefCountedArray.h: * wtf/RefCountedLeakCounter.cpp: * wtf/RefCountedLeakCounter.h: * wtf/RefCounter.h: * wtf/RefPtr.h: * wtf/RetainPtr.h: * wtf/RunLoop.cpp: * wtf/RunLoop.h: * wtf/RunLoopTimer.h: * wtf/RunLoopTimerCF.cpp: * wtf/SHA1.cpp: * wtf/SHA1.h: * wtf/SaturatedArithmetic.h: (saturatedSubtraction): * wtf/SchedulePair.h: * wtf/SchedulePairCF.cpp: * wtf/SchedulePairMac.mm: * wtf/ScopedLambda.h: * wtf/Seconds.cpp: * wtf/Seconds.h: * wtf/SegmentedVector.h: * wtf/SentinelLinkedList.h: * wtf/SharedTask.h: * wtf/SimpleStats.h: * wtf/SingleRootGraph.h: * wtf/SinglyLinkedList.h: * wtf/SixCharacterHash.cpp: * wtf/SixCharacterHash.h: * wtf/SmallPtrSet.h: * wtf/Spectrum.h: * wtf/StackBounds.cpp: * wtf/StackBounds.h: * wtf/StackStats.cpp: * wtf/StackStats.h: * wtf/StackTrace.cpp: * wtf/StdLibExtras.h: * wtf/StreamBuffer.h: * wtf/StringHashDumpContext.h: * wtf/StringPrintStream.cpp: * wtf/StringPrintStream.h: * wtf/ThreadGroup.cpp: * wtf/ThreadMessage.cpp: * wtf/ThreadSpecific.h: * wtf/Threading.cpp: * wtf/Threading.h: * wtf/ThreadingPrimitives.h: * wtf/ThreadingPthreads.cpp: * wtf/TimeWithDynamicClockType.cpp: * wtf/TimeWithDynamicClockType.h: * wtf/TimingScope.cpp: * wtf/TinyLRUCache.h: * wtf/TinyPtrSet.h: * wtf/TriState.h: * wtf/TypeCasts.h: * wtf/UUID.cpp: * wtf/UnionFind.h: * wtf/VMTags.h: * wtf/ValueCheck.h: * wtf/Vector.h: * wtf/VectorTraits.h: * wtf/WallTime.cpp: * wtf/WallTime.h: * wtf/WeakPtr.h: * wtf/WeakRandom.h: * wtf/WordLock.cpp: * wtf/WordLock.h: * wtf/WorkQueue.cpp: * wtf/WorkQueue.h: * wtf/WorkerPool.cpp: * wtf/cf/LanguageCF.cpp: * wtf/cf/RunLoopCF.cpp: * wtf/cocoa/Entitlements.mm: * wtf/cocoa/MachSendRight.cpp: * wtf/cocoa/MainThreadCocoa.mm: * wtf/cocoa/MemoryFootprintCocoa.cpp: * wtf/cocoa/WorkQueueCocoa.cpp: * wtf/dtoa.cpp: * wtf/dtoa.h: * wtf/ios/WebCoreThread.cpp: * wtf/ios/WebCoreThread.h: * wtf/mac/AppKitCompatibilityDeclarations.h: * wtf/mac/DeprecatedSymbolsUsedBySafari.mm: * wtf/mbmalloc.cpp: * wtf/persistence/PersistentCoders.cpp: * wtf/persistence/PersistentDecoder.cpp: * wtf/persistence/PersistentEncoder.cpp: * wtf/spi/cf/CFBundleSPI.h: * wtf/spi/darwin/CommonCryptoSPI.h: * wtf/text/ASCIIFastPath.h: * wtf/text/ASCIILiteral.cpp: * wtf/text/AtomicString.cpp: * wtf/text/AtomicString.h: * wtf/text/AtomicStringHash.h: * wtf/text/AtomicStringImpl.cpp: * wtf/text/AtomicStringImpl.h: * wtf/text/AtomicStringTable.cpp: * wtf/text/AtomicStringTable.h: * wtf/text/Base64.cpp: * wtf/text/CString.cpp: * wtf/text/CString.h: * wtf/text/ConversionMode.h: * wtf/text/ExternalStringImpl.cpp: * wtf/text/IntegerToStringConversion.h: * wtf/text/LChar.h: * wtf/text/LineEnding.cpp: * wtf/text/StringBuffer.h: * wtf/text/StringBuilder.cpp: * wtf/text/StringBuilder.h: * wtf/text/StringBuilderJSON.cpp: * wtf/text/StringCommon.h: * wtf/text/StringConcatenate.h: * wtf/text/StringHash.h: * wtf/text/StringImpl.cpp: * wtf/text/StringImpl.h: * wtf/text/StringOperators.h: * wtf/text/StringView.cpp: * wtf/text/StringView.h: * wtf/text/SymbolImpl.cpp: * wtf/text/SymbolRegistry.cpp: * wtf/text/SymbolRegistry.h: * wtf/text/TextBreakIterator.cpp: * wtf/text/TextBreakIterator.h: * wtf/text/TextBreakIteratorInternalICU.h: * wtf/text/TextPosition.h: * wtf/text/TextStream.cpp: * wtf/text/UniquedStringImpl.h: * wtf/text/WTFString.cpp: * wtf/text/WTFString.h: * wtf/text/cocoa/StringCocoa.mm: * wtf/text/cocoa/StringViewCocoa.mm: * wtf/text/cocoa/TextBreakIteratorInternalICUCocoa.cpp: * wtf/text/icu/UTextProvider.cpp: * wtf/text/icu/UTextProvider.h: * wtf/text/icu/UTextProviderLatin1.cpp: * wtf/text/icu/UTextProviderLatin1.h: * wtf/text/icu/UTextProviderUTF16.cpp: * wtf/text/icu/UTextProviderUTF16.h: * wtf/threads/BinarySemaphore.cpp: * wtf/threads/BinarySemaphore.h: * wtf/threads/Signals.cpp: * wtf/unicode/CharacterNames.h: * wtf/unicode/Collator.h: * wtf/unicode/CollatorDefault.cpp: * wtf/unicode/UTF8.cpp: * wtf/unicode/UTF8.h: Tools: Put WorkQueue in namespace DRT so it does not conflict with WTF::WorkQueue. * DumpRenderTree/TestRunner.cpp: (TestRunner::queueLoadHTMLString): (TestRunner::queueLoadAlternateHTMLString): (TestRunner::queueBackNavigation): (TestRunner::queueForwardNavigation): (TestRunner::queueLoadingScript): (TestRunner::queueNonLoadingScript): (TestRunner::queueReload): * DumpRenderTree/WorkQueue.cpp: (WorkQueue::singleton): Deleted. (WorkQueue::WorkQueue): Deleted. (WorkQueue::queue): Deleted. (WorkQueue::dequeue): Deleted. (WorkQueue::count): Deleted. (WorkQueue::clear): Deleted. (WorkQueue::processWork): Deleted. * DumpRenderTree/WorkQueue.h: (WorkQueue::setFrozen): Deleted. * DumpRenderTree/WorkQueueItem.h: * DumpRenderTree/mac/DumpRenderTree.mm: (runTest): * DumpRenderTree/mac/FrameLoadDelegate.mm: (-[FrameLoadDelegate processWork:]): (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]): * DumpRenderTree/mac/TestRunnerMac.mm: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): * DumpRenderTree/win/DumpRenderTree.cpp: (runTest): * DumpRenderTree/win/FrameLoadDelegate.cpp: (FrameLoadDelegate::processWork): (FrameLoadDelegate::locationChangeDone): * DumpRenderTree/win/TestRunnerWin.cpp: (TestRunner::notifyDone): (TestRunner::forceImmediateCompletion): (TestRunner::queueLoad): Canonical link: https://commits.webkit.org/205473@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@237099 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-10-15 14:24:49 +00:00
#pragma once
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +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
#include <wtf/Box.h>
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
#include <wtf/Condition.h>
#include <wtf/Lock.h>
#include <wtf/RefPtr.h>
#include <wtf/SharedTask.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/Threading.h>
#include <wtf/Vector.h>
#include <wtf/WeakRandom.h>
#include <wtf/text/CString.h>
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
namespace WTF {
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
class AutomaticThread;
class AutomaticThreadCondition;
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
// A ParallelHelperPool is a shared pool of threads that can be asked to help with some finite-time
// parallel activity. It's designed to work well when there are multiple concurrent tasks that may
// all want parallel help. In that case, we don't want each task to start its own thread pool. It's
// also designed to work well for tasks that do their own load balancing and do not wish to
// participate in microtask-style load balancing.
//
// A pool can have many clients, and each client may have zero or one tasks. The pool will have up
// to some number of threads, configurable with ParallelHelperPool::addThreads(); usually you bound
// this by the number of CPUs. Whenever a thread is idle and it notices that some client has a
// task, it will run the task. A task may be run on anywhere between zero and N threads, where N is
// the number of threads in the pool. Tasks run to completion. It's expected that a task will have
// its own custom ideas about how to participate in some parallel activity's load balancing, and it
// will return when the parallel activity is done. For example, a parallel marking task will return
// when the mark phase is done.
//
// Threads may have a choice between many tasks, since there may be many clients and each client
// may have a task. For the marking example, that may happen if there are multiple VM instances and
// each instance decides to start parallel marking at the same time. In that case, threads choose
// a task at random. So long as any client has a task, all threads in the pool will continue
// running the available tasks. Threads go idle when no client has tasks to run.
class ParallelHelperClient;
class ParallelHelperPool : public ThreadSafeRefCounted<ParallelHelperPool> {
public:
WTF_EXPORT_PRIVATE ParallelHelperPool(CString&& threadName);
WTF_EXPORT_PRIVATE ~ParallelHelperPool();
WTF_EXPORT_PRIVATE void ensureThreads(unsigned numThreads);
unsigned numberOfThreads() const { return m_numThreads; }
WTF_EXPORT_PRIVATE void doSomeHelping();
private:
friend class ParallelHelperClient;
class Thread;
friend class Thread;
void didMakeWorkAvailable(const AbstractLocker&) WTF_REQUIRES_LOCK(m_lock);
bool hasClientWithTask() WTF_REQUIRES_LOCK(m_lock);
ParallelHelperClient* getClientWithTask() WTF_REQUIRES_LOCK(m_lock);
Box<Lock> m_lock; // AutomaticThread wants this in a box for safety.
Ref<AutomaticThreadCondition> m_workAvailableCondition;
Condition m_workCompleteCondition;
WeakRandom m_random;
Vector<ParallelHelperClient*> m_clients WTF_GUARDED_BY_LOCK(*m_lock);
Vector<RefPtr<AutomaticThread>> m_threads;
CString m_threadName;
unsigned m_numThreads { 0 }; // This can be larger than m_threads.size() because we start threads only once there is work.
bool m_isDying { false };
};
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
// A client is a placeholder for a parallel algorithm. A parallel algorithm will have a task that
// can be run concurrently. Whenever a client has a task set (you have called setTask() or
// setFunction()), threads in the pool may run that task. If a task returns on any thread, the
// client will assume that the task is done and will clear the task. If the task is cleared (the
// task runs to completion on any thread or you call finish()), any threads in the pool already
// running the last set task(s) will continue to run them. You can wait for all of them to finish
// by calling finish(). That method will clear the task and wait for any threads running the last
// set task to finish. There are two known-good patterns for using a client:
//
// 1) Tasks intrinsically know when the algorithm reaches termination, and simply returns when
// this happens. The main thread runs the task by doing:
//
// client->setFunction(
// [=] () {
// do things;
// });
// client->doSomeHelping();
// client->finish();
//
// Calling doSomeHelping() ensures that the algorithm runs on at least one thread (this one).
// Tasks will know when to complete, and will return when they are done. This will clear the
// task to ensure that no new threads will run the task. Then, finish() clears the current task
// and waits for any parallel tasks to finish after the main thread has finished. It's possible
// for threads to still be running the last set task (i.e. the one set by setFunction()) even
// after the task has been cleared. Waiting for idle ensures that no old tasks are running
// anymore.
//
// You can do this more easily by using the runFunctionInParallel() helper:
//
// clients->runFunctionInParallel(
// [=] () {
// do things;
// });
//
// 2) Tasks keep doing things until they are told to quit using some custom notification mechanism.
// The main thread runs the task by doing:
//
// bool keepGoing = true;
// client->setFunction(
// [=] () {
// while (keepGoing) {
// do things;
// }
// });
//
// When work runs out, the main thread will inform tasks that there is no more work, and then
// wait until no more tasks are running:
//
// keepGoing = false;
// client->finish();
//
// This works best when the main thread doesn't actually want to run the task that it set in the
// client. This happens for example in parallel marking. The main thread uses a somewhat
// different marking algorithm than the helpers. The main thread may provide work that the
// helpers steal. The main thread knows when termination is reached, and simply tells the
// helpers to stop upon termination.
//
// The known-good styles of using ParallelHelperClient all involve a parallel algorithm that has
// its own work distribution and load balancing.
//
// Note that it is not valid to use the same ParallelHelperClient instance from multiple threads.
// Each thread should have its own ParallelHelperClient in that case. Failure to follow this advice
// will lead to RELEASE_ASSERT's or worse.
class ParallelHelperClient {
WTF_MAKE_NONCOPYABLE(ParallelHelperClient);
WTF_MAKE_FAST_ALLOCATED;
public:
WTF_EXPORT_PRIVATE ParallelHelperClient(RefPtr<ParallelHelperPool>&&);
WTF_EXPORT_PRIVATE ~ParallelHelperClient();
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
WTF_EXPORT_PRIVATE void setTask(RefPtr<SharedTask<void ()>>&&);
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
template<typename Functor>
void setFunction(const Functor& functor)
{
setTask(createSharedTask<void ()>(functor));
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
}
WTF_EXPORT_PRIVATE void finish();
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
WTF_EXPORT_PRIVATE void doSomeHelping();
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
// Equivalent to:
// client->setTask(task);
// client->doSomeHelping();
// client->finish();
WTF_EXPORT_PRIVATE void runTaskInParallel(RefPtr<SharedTask<void ()>>&&);
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
// Equivalent to:
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
// client->setFunction(functor);
// client->doSomeHelping();
// client->finish();
template<typename Functor>
void runFunctionInParallel(const Functor& functor)
{
runTaskInParallel(createSharedTask<void ()>(functor));
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
}
ParallelHelperPool& pool() { return *m_pool; }
unsigned numberOfActiveThreads() const { return m_numActive; }
private:
friend class ParallelHelperPool;
void finishWithLock() WTF_REQUIRES_LOCK(*m_pool->m_lock);
RefPtr<SharedTask<void ()>> claimTask() WTF_REQUIRES_LOCK(*m_pool->m_lock);
void runTask(const RefPtr<SharedTask<void ()>>&);
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
RefPtr<ParallelHelperPool> m_pool;
RefPtr<SharedTask<void ()>> m_task;
VMs should share GC threads https://bugs.webkit.org/show_bug.cgi?id=149433 rdar://problem/12859344 Reviewed by Geoffrey Garen. Source/JavaScriptCore: This changes the GC to use a new WTF abstraction for parallelism called ParallelHelperPool. This allows us to remove GCThread and all of the GCPhase machinery. This kills a lot of code and also gives our GC magical thread sharing powers. If two GCs in two different VMs fire at the same time, then they will both get a random subset of the available shared GC threads. If one GC happens before the other, then it will probably get all of the available threads. If a GC happens while another VM already started GCing, then it will probably not get any helper threads. This is probably fine, since in multi-VM scenarios we have no reason to optimize for anything other than total throughput. The GC has one static helper pool. This pool is available via JSC::heapHelperPool(). It would be OK for other parts of JSC to use it in the future for parallel tasks. Each Heap instance has a helper client attached to the pool. The marking phase tells the ParallelHelperClient to asynchronously run a function that joins parallel marking and finishes once marking reaches termination. It uses the client.setFunction() idiom where the threads share work with each other using a specialized worklist. The ParallelHelperPool is not involved in deciding when threads should terminate. The copying phase tells the ParallelHelperClient to run a copying function in parallel. It uses the client.runFunctionInParallel() idiom. The copying function gets work from the m_blocksToCopy worklist inside Heap. To test that multiple VMs work properly, this adds a multi-VM test to testapi.mm. This test creates five concurrent VMs and has each of them allocate about 30MB of memory before doing a full GC. I've confirmed that this tests uses only 6 total GC threads on my 8-core computer (this is correct since we are currently configured for 7-way parallelism). This shouldn't affect performance on benchmarks, but it will sure help apps with a lot of VM instances. * CMakeLists.txt: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters: * JavaScriptCore.xcodeproj/project.pbxproj: * assembler/AbstractMacroAssembler.h: * heap/GCThread.cpp: Removed. * heap/GCThread.h: Removed. * heap/Heap.cpp: (JSC::Heap::Heap): (JSC::Heap::~Heap): (JSC::Heap::isPagedOut): (JSC::Heap::markRoots): (JSC::Heap::copyBackingStores): (JSC::Heap::resetVisitors): (JSC::Heap::threadVisitCount): (JSC::Heap::threadBytesVisited): (JSC::Heap::threadBytesCopied): (JSC::Heap::startNextPhase): Deleted. (JSC::Heap::endCurrentPhase): Deleted. * heap/Heap.h: * heap/HeapHelperPool.cpp: Added. (JSC::heapHelperPool): * heap/HeapHelperPool.h: Added. * heap/MarkStack.cpp: (JSC::MarkStackArray::stealSomeCellsFrom): * heap/SlotVisitor.cpp: (JSC::SlotVisitor::didStartMarking): (JSC::SlotVisitor::reset): (JSC::SlotVisitor::drainFromShared): * jit/BinarySwitch.h: * runtime/CodeCache.h: * runtime/VM.h: * runtime/WeakRandom.h: Removed. * API/tests/testapi.mm: Source/WTF: This adds two major things to WTF: WeakRandom and ParallelHelperPool. WeakRandom was already in JSC; we're just hoisting it into WTF. It's just a weak random number generator that's suitable for places where you need just a tiny bit of randomness. ParallelHelperPool is a new API that simplifies data-parallel algorithms like the JSC GC. In a data-parallel algorithm, we want to run one task on as many cores as possible and let the task worry about which subset of the input data to work on. In some cases, the algorithm will not need to do any load balancing - and if load balancing is required, it's up to the user. This is appropriate in contexts where the load balancing needs to be custom-tuned for performance, like the GC's marking phase. This new API has three concepts: task, client, and pool. A task is a reference counted object with a run() method, which may be run in parallel. It is usually used to wrap a functor. A pool is a pool of threads that can run things. A client is a placeholder for a task. A client can have zero or one tasks. A client must be registered with a pool. When a client has a task, the pool's threads may choose to run it. If a thread starts running a task, it will run it to completion. When the task returns on any thread, the client takes it to mean that the task should be removed. That means that any currently running instances of the task will finish but no new threads will attempt to run the task. You can easily ask a client to wait until a task finishes. You can also easily ask a client to run a task on the current thread in addition to possibly some helper threads from the pool. For some data-parallel algorithms, programming with ParallelHelperPool is as easy as: client.runFunctionInParallel( [=] () { do things; }); Note that you cannot tell ahead of time how many threads will join to help the task. Threads may become available after the task has already started running. Those threads may join after the other threads have already started. It's not advisable to make algorithmic decisions based on client.numberOfActiveThreads(), since that number may change. Usually the best way to use ParallelHelperPool is with an algorithm that has its own custom worklist. An example of a very simple custom worklist is the one in the JSC GC's copying phase - it's just a Vector and an index that indicates the next set of elements to process. This new API was initially designed to simplify how GCThread works, by replacing Phase with a callback that contains the phase's workload. I then realized that with a few tweaks, I could make this somewhat general enough that it might become interesting outside GC. I also realized that I could use this to enable thread sharing. So, although the API is kinda quirky, it's grounded in the reality of how the JSC GC does parallelism. * WTF.vcxproj/WTF.vcxproj: * WTF.vcxproj/WTF.vcxproj.filters: * WTF.xcodeproj/project.pbxproj: * wtf/CMakeLists.txt: * wtf/ParallelHelperPool.cpp: Added. (WTF::ParallelHelperClient::ParallelHelperClient): (WTF::ParallelHelperClient::~ParallelHelperClient): (WTF::ParallelHelperClient::setTask): (WTF::ParallelHelperClient::finish): (WTF::ParallelHelperClient::doSomeHelping): (WTF::ParallelHelperClient::runTaskInParallel): (WTF::ParallelHelperClient::claimTask): (WTF::ParallelHelperClient::runTask): (WTF::ParallelHelperPool::ParallelHelperPool): (WTF::ParallelHelperPool::~ParallelHelperPool): (WTF::ParallelHelperPool::addThreads): (WTF::ParallelHelperPool::ensureThreads): (WTF::ParallelHelperPool::doSomeHelping): (WTF::ParallelHelperPool::didMakeWorkAvailable): (WTF::ParallelHelperPool::helperThreadBody): (WTF::ParallelHelperPool::hasClientWithTask): (WTF::ParallelHelperPool::getClientWithTask): (WTF::ParallelHelperPool::waitForClientWithTask): * wtf/ParallelHelperPool.h: Added. (WTF::ParallelHelperClient::setFunction): (WTF::ParallelHelperClient::runFunctionInParallel): (WTF::ParallelHelperClient::pool): (WTF::ParallelHelperClient::numberOfActiveThreads): (WTF::ParallelHelperPool::numberOfThreads): * wtf/SharedTask.h: Added. (WTF::SharedTask::SharedTask): (WTF::SharedTask::~SharedTask): (WTF::SharedTaskFunctor::SharedTaskFunctor): (WTF::createSharedTask): * wtf/WeakRandom.h: Copied from Source/JavaScriptCore/runtime/WeakRandom.h. (WTF::WeakRandom::WeakRandom): (WTF::WeakRandom::initializeSeed): (WTF::WeakRandom::seedUnsafe): (WTF::WeakRandom::getUint32): (WTF::WeakRandom::advance): (JSC::WeakRandom::WeakRandom): Deleted. (JSC::WeakRandom::seedUnsafe): Deleted. (JSC::WeakRandom::getUint32): Deleted. (JSC::WeakRandom::advance): Deleted. (JSC::WeakRandom::initializeSeed): Deleted. Canonical link: https://commits.webkit.org/167685@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@190267 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2015-09-26 18:07:09 +00:00
unsigned m_numActive { 0 };
};
} // namespace WTF
using WTF::ParallelHelperClient;
using WTF::ParallelHelperPool;