Reviewed by Csaba Osztrogonác.
Speeding up SVG filters with multicore (SMP) support
https://bugs.webkit.org/show_bug.cgi?id=43903
Some SVG filters execute a huge number of pixel manipulations, which
cannot be sped up by graphics accelerators, since their algorithm is
too complex. Using the power of Symmetric Multi Processing (SMP) we
can split up a task to smaller (data independent) tasks, which can be
executed independently.
The ParallelJobs framework provides a simple way for distributed
programming. The framework is based on WebKit's threading infrastructure,
Open Multi-Processing's (OpenMP) API, and libdispatch API.
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/WTF/WTF.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* wtf/CMakeLists.txt:
* wtf/ParallelJobs.h: Added.
(WTF::ParallelJobs::ParallelJobs):
(WTF::ParallelJobs::numberOfJobs):
(WTF::ParallelJobs::parameterForJob):
(WTF::ParallelJobs::executeJobs):
* wtf/ParallelJobsGeneric.cpp: Added.
(WTF::ParallelEnvironment::ThreadPrivate::tryLockFor):
(WTF::ParallelEnvironment::ThreadPrivate::executeJob):
(WTF::ParallelEnvironment::ThreadPrivate::waitForFinish):
(WTF::ParallelEnvironment::ThreadPrivate::workerThread):
* wtf/ParallelJobsGeneric.h: Added.
(WTF::ParallelEnvironment::ParallelEnvironment):
(WTF::ParallelEnvironment::numberOfJobs):
(WTF::ParallelEnvironment::parameterForJob):
(WTF::ParallelEnvironment::executeJobs):
(WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate):
(WTF::ParallelEnvironment::ThreadPrivate::create):
* wtf/ParallelJobsLibdispatch.h: Added.
(WTF::ParallelEnvironment::ParallelEnvironment):
(WTF::ParallelEnvironment::numberOfJobs):
(WTF::ParallelEnvironment::parameterForJob):
(WTF::ParallelEnvironment::executeJobs):
* wtf/ParallelJobsOpenMP.h: Added.
(WTF::ParallelEnvironment::ParallelEnvironment):
(WTF::ParallelEnvironment::numberOfJobs):
(WTF::ParallelEnvironment::parameterForJob):
(WTF::ParallelEnvironment::executeJobs):
* wtf/Platform.h:
* wtf/wtf.pri:
2011-04-26 Gabor Loki <loki@webkit.org>
Reviewed by Csaba Osztrogonác.
Speeding up SVG filters with multicore (SMP) support
https://bugs.webkit.org/show_bug.cgi?id=43903
Some SVG filters execute a huge number of pixel manipulations, which
cannot be sped up by graphics accelerators, since their algorithm is
too complex. Using the power of Symmetric Multi Processing (SMP) we
can split up a task to smaller (data independent) tasks, which can be
executed independently.
The ParallelJobs framework provides a simple way for distributed
programming. The framework is based on WebKit's threading infrastructure,
Open Multi-Processing's (OpenMP) API, and libdispatch API.
* ForwardingHeaders/wtf/ParallelJobs.h: Added.
* platform/graphics/filters/FETurbulence.cpp:
(WebCore::FETurbulence::PaintingData::PaintingData):
(WebCore::FETurbulence::noise2D):
(WebCore::FETurbulence::calculateTurbulenceValueForPoint):
(WebCore::FETurbulence::fillRegion):
(WebCore::FETurbulence::fillRegionWorker):
(WebCore::FETurbulence::apply):
* platform/graphics/filters/FETurbulence.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@84911
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-04-26 Gabor Loki <loki@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Speeding up SVG filters with multicore (SMP) support
+ https://bugs.webkit.org/show_bug.cgi?id=43903
+
+ Some SVG filters execute a huge number of pixel manipulations, which
+ cannot be sped up by graphics accelerators, since their algorithm is
+ too complex. Using the power of Symmetric Multi Processing (SMP) we
+ can split up a task to smaller (data independent) tasks, which can be
+ executed independently.
+
+ The ParallelJobs framework provides a simple way for distributed
+ programming. The framework is based on WebKit's threading infrastructure,
+ Open Multi-Processing's (OpenMP) API, and libdispatch API.
+
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/WTF/WTF.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * wtf/CMakeLists.txt:
+ * wtf/ParallelJobs.h: Added.
+ (WTF::ParallelJobs::ParallelJobs):
+ (WTF::ParallelJobs::numberOfJobs):
+ (WTF::ParallelJobs::parameterForJob):
+ (WTF::ParallelJobs::executeJobs):
+ * wtf/ParallelJobsGeneric.cpp: Added.
+ (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor):
+ (WTF::ParallelEnvironment::ThreadPrivate::executeJob):
+ (WTF::ParallelEnvironment::ThreadPrivate::waitForFinish):
+ (WTF::ParallelEnvironment::ThreadPrivate::workerThread):
+ * wtf/ParallelJobsGeneric.h: Added.
+ (WTF::ParallelEnvironment::ParallelEnvironment):
+ (WTF::ParallelEnvironment::numberOfJobs):
+ (WTF::ParallelEnvironment::parameterForJob):
+ (WTF::ParallelEnvironment::executeJobs):
+ (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate):
+ (WTF::ParallelEnvironment::ThreadPrivate::create):
+ * wtf/ParallelJobsLibdispatch.h: Added.
+ (WTF::ParallelEnvironment::ParallelEnvironment):
+ (WTF::ParallelEnvironment::numberOfJobs):
+ (WTF::ParallelEnvironment::parameterForJob):
+ (WTF::ParallelEnvironment::executeJobs):
+ * wtf/ParallelJobsOpenMP.h: Added.
+ (WTF::ParallelEnvironment::ParallelEnvironment):
+ (WTF::ParallelEnvironment::numberOfJobs):
+ (WTF::ParallelEnvironment::parameterForJob):
+ (WTF::ParallelEnvironment::executeJobs):
+ * wtf/Platform.h:
+ * wtf/wtf.pri:
+
2011-04-26 Mihai Parparita <mihaip@chromium.org>
Reviewed by Adam Barth.
Source/JavaScriptCore/wtf/PassOwnArrayPtr.h \
Source/JavaScriptCore/wtf/PassOwnPtr.h \
Source/JavaScriptCore/wtf/PassRefPtr.h \
+ Source/JavaScriptCore/wtf/ParallelJobs.h \
+ Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp \
+ Source/JavaScriptCore/wtf/ParallelJobsGeneric.h \
+ Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h \
+ Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h \
Source/JavaScriptCore/wtf/Platform.h \
Source/JavaScriptCore/wtf/PossiblyNull.h \
Source/JavaScriptCore/wtf/RandomNumber.cpp \
RelativePath="..\..\wtf\PassRefPtr.h"
>
</File>
+ <File
+ RelativePath="..\..\wtf\ParallelJobs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\ParallelJobsGeneric.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\ParallelJobsGeneric.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\ParallelJobsLibdispatch.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\ParallelJobsOpenMP.h"
+ >
+ </File>
<File
RelativePath="..\..\wtf\Platform.h"
>
7186A6EC13100BA5004479E1 /* HexNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 7186A6E813100B57004479E1 /* HexNumber.h */; settings = {ATTRIBUTES = (Private, ); }; };
76FB9F0F12E851860051A2EB /* SHA1.h in Headers */ = {isa = PBXBuildFile; fileRef = 76FB9F0E12E851860051A2EB /* SHA1.h */; settings = {ATTRIBUTES = (Private, ); }; };
76FB9F1112E851960051A2EB /* SHA1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76FB9F1012E851960051A2EB /* SHA1.cpp */; };
+ 7934BB7B1361979300CB99A1 /* ParallelJobs.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB761361979300CB99A1 /* ParallelJobs.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 7934BB7C1361979400CB99A1 /* ParallelJobsGeneric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */; };
+ 7934BB7D1361979400CB99A1 /* ParallelJobsGeneric.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 7934BB7E1361979400CB99A1 /* ParallelJobsLibdispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 7934BB7F1361979400CB99A1 /* ParallelJobsOpenMP.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */; settings = {ATTRIBUTES = (Private, ); }; };
7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E4EE7080EBB7963005934AA /* StructureChain.h */; settings = {ATTRIBUTES = (Private, ); }; };
7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */; };
7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */; };
7186A6E813100B57004479E1 /* HexNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexNumber.h; sourceTree = "<group>"; };
76FB9F0E12E851860051A2EB /* SHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHA1.h; sourceTree = "<group>"; };
76FB9F1012E851960051A2EB /* SHA1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SHA1.cpp; sourceTree = "<group>"; };
+ 7934BB761361979300CB99A1 /* ParallelJobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobs.h; sourceTree = "<group>"; };
+ 7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParallelJobsGeneric.cpp; sourceTree = "<group>"; };
+ 7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsGeneric.h; sourceTree = "<group>"; };
+ 7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsLibdispatch.h; sourceTree = "<group>"; };
+ 7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsOpenMP.h; sourceTree = "<group>"; };
7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopeChainMark.h; sourceTree = "<group>"; };
7E4EE7080EBB7963005934AA /* StructureChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureChain.h; sourceTree = "<group>"; };
7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureChain.cpp; sourceTree = "<group>"; };
BCFBE695122560E800309E9D /* PassOwnArrayPtr.h */,
44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */,
6580F795094070560082C219 /* PassRefPtr.h */,
+ 7934BB761361979300CB99A1 /* ParallelJobs.h */,
+ 7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */,
+ 7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */,
+ 7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */,
+ 7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */,
65D6D87E09B5A32E0002E4D7 /* Platform.h */,
A7D649A91015224E009B2E1B /* PossiblyNull.h */,
E4D8CE9B12FC42E100BC9F5A /* BloomFilter.h */,
A1D764521354448B00C5C7C0 /* Alignment.h in Headers */,
86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */,
86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */,
+ 7934BB7B1361979300CB99A1 /* ParallelJobs.h in Headers */,
+ 7934BB7D1361979400CB99A1 /* ParallelJobsGeneric.h in Headers */,
+ 7934BB7E1361979400CB99A1 /* ParallelJobsLibdispatch.h in Headers */,
+ 7934BB7F1361979400CB99A1 /* ParallelJobsOpenMP.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
142D6F1113539A4100B02E86 /* MarkStack.cpp in Sources */,
142D6F1313539A4100B02E86 /* MarkStackPosix.cpp in Sources */,
86AE64A8135E5E1C00963012 /* MacroAssemblerSH4.cpp in Sources */,
+ 7934BB7C1361979400CB99A1 /* ParallelJobsGeneric.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
PassOwnArrayPtr.h
PassOwnPtr.h
PassRefPtr.h
+ ParallelJobs.h
+ ParallelJobsGeneric.h
+ ParallelJobsLibdispatch.h
+ ParallelJobsOpenMP.h
Platform.h
PossiblyNull.h
RandomNumber.h
MainThread.cpp
MD5.cpp
OSRandomSource.cpp
+ ParallelJobsGeneric.cpp
RandomNumber.cpp
RefCountedLeakCounter.cpp
SHA1.cpp
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ */
+
+#ifndef ParallelJobs_h
+#define ParallelJobs_h
+
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "RefPtr.h"
+#include <wtf/Vector.h>
+
+#if ENABLE(PARALLEL_JOBS)
+
+// Usage:
+//
+// #if ENABLE(PARALLEL_JOBS)
+//
+// // Initialize parallel jobs
+// ParallelJobs<TypeOfParameter> parallelJobs(&worker [, requestedNumberOfJobs]);
+//
+// // Fill the parameter array
+// for(i = 0; i < parallelJobs.numberOfJobs(); ++i) {
+// TypeOfParameter& params = parallelJobs.parameter(i);
+// params.attr1 = localVars ...
+// ...
+// }
+//
+// // Execute parallel jobs
+// parallelJobs.execute();
+//
+// #else
+//
+// inlineFunction(args...);
+//
+// #endif // ENABLE(PARALLEL_JOBS)
+
+#if ENABLE(THREADING_GENERIC)
+#include "ParallelJobsGeneric.h"
+
+#elif ENABLE(THREADING_OPENMP)
+#include "ParallelJobsOpenMP.h"
+
+#elif ENABLE(THREADING_LIBDISPATCH)
+#include "ParallelJobsLibdispatch.h"
+
+#else
+#error "No parallel processing API for ParallelJobs"
+
+#endif
+
+namespace WTF {
+
+template<typename Type>
+class ParallelJobs {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*WorkerFunction)(Type*);
+
+ ParallelJobs(WorkerFunction func, int requestedJobNumber = 0) :
+ m_parallelEnvironment(reinterpret_cast<ParallelEnvironment::ThreadFunction>(func), sizeof(Type), requestedJobNumber)
+ {
+ m_parameters.grow(m_parallelEnvironment.numberOfJobs());
+ ASSERT(numberOfJobs() == m_parameters.size());
+ }
+
+ size_t numberOfJobs()
+ {
+ return m_parameters.size();
+ }
+
+ Type& parameter(size_t i)
+ {
+ return m_parameters[i];
+ }
+
+ void execute()
+ {
+ m_parallelEnvironment.execute(reinterpret_cast<unsigned char*>(m_parameters.data()));
+ }
+
+private:
+ ParallelEnvironment m_parallelEnvironment;
+ Vector<Type> m_parameters;
+};
+
+} // namespace WTF
+
+using WTF::ParallelJobs;
+
+#endif // ENABLE(PARALLEL_JOBS)
+
+#endif // ParallelJobs_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
+
+#include "ParallelJobs.h"
+
+namespace WTF {
+
+Vector< RefPtr<ParallelEnvironment::ThreadPrivate> >* ParallelEnvironment::s_threadPool = 0;
+
+bool ParallelEnvironment::ThreadPrivate::tryLockFor(ParallelEnvironment* parent)
+{
+ bool locked = m_mutex.tryLock();
+
+ if (!locked)
+ return false;
+
+ if (m_parent) {
+ m_mutex.unlock();
+ return false;
+ }
+
+ if (!m_threadID)
+ m_threadID = createThread(&ParallelEnvironment::ThreadPrivate::workerThread, this, "Parallel worker");
+
+ if (m_threadID)
+ m_parent = parent;
+
+ m_mutex.unlock();
+ return m_threadID;
+}
+
+void ParallelEnvironment::ThreadPrivate::execute(ThreadFunction threadFunction, void* parameters)
+{
+ MutexLocker lock(m_mutex);
+
+ m_threadFunction = threadFunction;
+ m_parameters = parameters;
+ m_running = true;
+ m_threadCondition.signal();
+}
+
+void ParallelEnvironment::ThreadPrivate::waitForFinish()
+{
+ MutexLocker lock(m_mutex);
+
+ while (m_running)
+ m_threadCondition.wait(m_mutex);
+}
+
+void* ParallelEnvironment::ThreadPrivate::workerThread(void* threadData)
+{
+ ThreadPrivate* sharedThread = reinterpret_cast<ThreadPrivate*>(threadData);
+ MutexLocker lock(sharedThread->m_mutex);
+
+ while (sharedThread->m_threadID) {
+ if (sharedThread->m_running) {
+ (*sharedThread->m_threadFunction)(sharedThread->m_parameters);
+ sharedThread->m_running = false;
+ sharedThread->m_parent = 0;
+ sharedThread->m_threadCondition.signal();
+ }
+
+ sharedThread->m_threadCondition.wait(sharedThread->m_mutex);
+ }
+ return 0;
+}
+
+} // namespace WTF
+
+#endif // ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ */
+
+#ifndef ParallelJobsGeneric_h
+#define ParallelJobsGeneric_h
+
+#if ENABLE(THREADING_GENERIC)
+
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+static const unsigned int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, unsigned int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+ requestedJobNumber = maxParallelThreads;
+
+ if (!s_threadPool)
+ s_threadPool = new Vector< RefPtr<ThreadPrivate> >();
+
+ // The main thread should be also a worker.
+ unsigned int maxNewThreads = requestedJobNumber - 1;
+
+ for (unsigned int i = 0; i < maxParallelThreads && m_threads.size() < maxNewThreads; ++i) {
+ if (s_threadPool->size() < i + 1)
+ s_threadPool->append(ThreadPrivate::create());
+
+ if ((*s_threadPool)[i]->tryLockFor(this))
+ m_threads.append((*s_threadPool)[i]);
+ }
+
+ m_numberOfJobs = m_threads.size() + 1;
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ size_t i;
+ for (i = 0; i < m_threads.size(); ++i) {
+ m_threads[i]->execute(m_threadFunction, parameters);
+ parameters += m_sizeOfParameter;
+ }
+
+ // The work for the main thread
+ (*m_threadFunction)(parameters);
+
+ // Wait until all jobs are done.
+ for (i = 0; i < m_threads.size(); ++i)
+ m_threads[i]->waitForFinish();
+ }
+
+ class ThreadPrivate : public RefCounted<ThreadPrivate> {
+ public:
+ ThreadPrivate()
+ : m_threadID(0)
+ , m_running(false)
+ , m_parent(0)
+ {
+ }
+
+ bool tryLockFor(ParallelEnvironment*);
+
+ void execute(ThreadFunction, void*);
+
+ void waitForFinish();
+
+ static PassRefPtr<ThreadPrivate> create()
+ {
+ return adoptRef(new ThreadPrivate());
+ }
+
+ static void* workerThread(void*);
+
+ private:
+ ThreadIdentifier m_threadID;
+ bool m_running;
+ ParallelEnvironment* m_parent;
+
+ mutable Mutex m_mutex;
+ ThreadCondition m_threadCondition;
+
+ ThreadFunction m_threadFunction;
+ void* m_parameters;
+ };
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+
+ Vector< RefPtr<ThreadPrivate> > m_threads;
+ static Vector< RefPtr<ThreadPrivate> >* s_threadPool;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_GENERIC)
+
+
+#endif // ParallelJobsGeneric_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ */
+
+#ifndef ParallelJobsLibdispatch_h
+#define ParallelJobsLibdispatch_h
+
+#if ENABLE(THREADING_LIBDISPATCH)
+
+#include <dispatch/dispatch.h>
+
+namespace WTF {
+
+static const int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+ requestedJobNumber = maxParallelThreads;
+
+ ASSERT(requestedJobNumber > 0);
+
+ m_numberOfJobs = requestedJobNumber;
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ // libdispatch is NOT supported inside a template
+ dispatch_queue_t parallelJobsQueue = dispatch_queue_create("ParallelJobs", 0);
+
+ for (int i = 0; i < m_numberOfJobs - 1; ++i) {
+ dispatch_async(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+ parameters += m_sizeOfParameter;
+ }
+
+ // The work for the main thread. Wait until all jobs are done.
+ dispatch_sync(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_LIBDISPATCH)
+
+#endif // ParallelJobsLibdispatch_h
--- /dev/null
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * All rights reserved.
+ *
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED 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.
+ */
+
+#ifndef ParallelJobsOpenMP_h
+#define ParallelJobsOpenMP_h
+
+#if ENABLE(THREADING_OPENMP)
+
+#include <omp.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+ WTF_MAKE_NONCOPYABLE(ParallelEnvironment);
+public:
+ typedef void (*ThreadFunction)(void*);
+
+ ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+ m_threadFunction(threadFunction),
+ m_sizeOfParameter(sizeOfParameter)
+ {
+ int maxNumberOfThreads = omp_get_max_threads();
+
+ if (!requestedJobNumber || requestedJobNumber > maxNumberOfThreads)
+ requestedJobNumber = maxNumberOfThreads;
+
+ ASSERT(requestedJobNumber > 0);
+
+ m_numberOfJobs = requestedJobNumber;
+
+ }
+
+ int numberOfJobs()
+ {
+ return m_numberOfJobs;
+ }
+
+ void execute(unsigned char* parameters)
+ {
+ omp_set_num_threads(m_numberOfJobs);
+
+#pragma omp parallel for
+ for (int i = 0; i < m_numberOfJobs; ++i)
+ (*m_threadFunction)(parameters + i * m_sizeOfParameter);
+ }
+
+private:
+ ThreadFunction m_threadFunction;
+ size_t m_sizeOfParameter;
+ int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_OPENMP)
+
+#endif // ParallelJobsOpenMP_h
#define ENABLE_BRANCH_COMPACTION 1
#endif
+#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE(SINGLE_THREADED) && (ENABLE(THREADING_GENERIC) || ENABLE(THREADING_LIBDISPATCH) || ENABLE(THREADING_OPENMP))
+#define ENABLE_PARALLEL_JOBS 1
+#endif
+
#if ENABLE(GLIB_SUPPORT)
#include "GTypedefs.h"
#endif
wtf/qt/ThreadingQt.cpp \
wtf/PageAllocationAligned.cpp \
wtf/PageBlock.cpp \
+ wtf/ParallelJobsGeneric.cpp \
wtf/RandomNumber.cpp \
wtf/RefCountedLeakCounter.cpp \
wtf/SHA1.cpp \
+2011-04-26 Gabor Loki <loki@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Speeding up SVG filters with multicore (SMP) support
+ https://bugs.webkit.org/show_bug.cgi?id=43903
+
+ Some SVG filters execute a huge number of pixel manipulations, which
+ cannot be sped up by graphics accelerators, since their algorithm is
+ too complex. Using the power of Symmetric Multi Processing (SMP) we
+ can split up a task to smaller (data independent) tasks, which can be
+ executed independently.
+
+ The ParallelJobs framework provides a simple way for distributed
+ programming. The framework is based on WebKit's threading infrastructure,
+ Open Multi-Processing's (OpenMP) API, and libdispatch API.
+
+ * ForwardingHeaders/wtf/ParallelJobs.h: Added.
+ * platform/graphics/filters/FETurbulence.cpp:
+ (WebCore::FETurbulence::PaintingData::PaintingData):
+ (WebCore::FETurbulence::noise2D):
+ (WebCore::FETurbulence::calculateTurbulenceValueForPoint):
+ (WebCore::FETurbulence::fillRegion):
+ (WebCore::FETurbulence::fillRegionWorker):
+ (WebCore::FETurbulence::apply):
+ * platform/graphics/filters/FETurbulence.h:
+
2011-04-26 Pavel Feldman <pfeldman@google.com>
Reviewed by Yury Semikhatsky.
--- /dev/null
+#ifndef WebCore_FWD_ParallelJobs_h
+#define WebCore_FWD_ParallelJobs_h
+#include <JavaScriptCore/ParallelJobs.h>
+#endif
* Copyright (C) 2005 Eric Seidel <eric@webkit.org>
* Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
* Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
#include <wtf/ByteArray.h>
#include <wtf/MathExtras.h>
+#include <wtf/ParallelJobs.h>
namespace WebCore {
, height(0)
, wrapX(0)
, wrapY(0)
- , channel(0)
, filterSize(paintingSize)
{
}
noiseValue -= newValue - 1;
}
-float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseVector)
+float FETurbulence::noise2D(int channel, PaintingData& paintingData, const FloatPoint& noiseVector)
{
struct Noise {
int noisePositionIntegerValue;
// This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
- q = paintingData.gradient[paintingData.channel][temp];
+ q = paintingData.gradient[channel][temp];
u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
- q = paintingData.gradient[paintingData.channel][temp];
+ q = paintingData.gradient[channel][temp];
v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
a = linearInterpolation(sx, u, v);
temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
- q = paintingData.gradient[paintingData.channel][temp];
+ q = paintingData.gradient[channel][temp];
u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
- q = paintingData.gradient[paintingData.channel][temp];
+ q = paintingData.gradient[channel][temp];
v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
b = linearInterpolation(sx, u, v);
return linearInterpolation(sy, a, b);
}
-unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paintingData, const FloatPoint& point)
+unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point)
{
float tileWidth = paintingData.filterSize.width();
ASSERT(tileWidth > 0);
float ratio = 1;
for (int octave = 0; octave < m_numOctaves; ++octave) {
if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
- turbulenceFunctionResult += noise2D(paintingData, noiseVector) / ratio;
+ turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio;
else
- turbulenceFunctionResult += fabsf(noise2D(paintingData, noiseVector)) / ratio;
+ turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio;
noiseVector.setX(noiseVector.x() * 2);
noiseVector.setY(noiseVector.y() * 2);
ratio *= 2;
return static_cast<unsigned char>(turbulenceFunctionResult * 255);
}
+inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& paintingData, int startY, int endY)
+{
+ IntRect filterRegion = absolutePaintRect();
+ IntPoint point(0, filterRegion.y() + startY);
+ int indexOfPixelChannel = startY * (filterRegion.width() << 2);
+ int channel;
+
+ for (int y = startY; y < endY; ++y) {
+ point.setY(point.y() + 1);
+ point.setX(filterRegion.x());
+ for (int x = 0; x < filterRegion.width(); ++x) {
+ point.setX(point.x() + 1);
+ for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
+ pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
+ }
+ }
+}
+
+#if ENABLE(PARALLEL_JOBS)
+void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
+{
+ parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY);
+}
+#endif // ENABLE(PARALLEL_JOBS)
+
void FETurbulence::apply()
{
if (hasResult())
PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
initPaint(paintingData);
- FloatRect filterRegion = absolutePaintRect();
- FloatPoint point;
- point.setY(filterRegion.y());
- int indexOfPixelChannel = 0;
- for (int y = 0; y < absolutePaintRect().height(); ++y) {
- point.setY(point.y() + 1);
- point.setX(filterRegion.x());
- for (int x = 0; x < absolutePaintRect().width(); ++x) {
- point.setX(point.x() + 1);
- for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
- pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
+#if ENABLE(PARALLEL_JOBS)
+
+ int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
+ if (optimalThreadNumber > 1) {
+ // Initialize parallel jobs
+ ParallelJobs<FillRegionParameters> parallelJobs(&WebCore::FETurbulence::fillRegionWorker, optimalThreadNumber);
+
+ // Fill the parameter array
+ int i = parallelJobs.numberOfJobs();
+ if (i > 1) {
+ int startY = 0;
+ int stepY = absolutePaintRect().height() / i;
+ for (; i > 0; --i) {
+ FillRegionParameters& params = parallelJobs.parameter(i-1);
+ params.filter = this;
+ params.pixelArray = pixelArray;
+ params.paintingData = &paintingData;
+ params.startY = startY;
+ if (i != 1) {
+ params.endY = startY + stepY;
+ startY = startY + stepY;
+ } else
+ params.endY = absolutePaintRect().height();
+ }
+
+ // Execute parallel jobs
+ parallelJobs.execute();
+
+ return;
}
}
+ // Fallback to sequential mode if there is no room for a new thread or the paint area is too small
+
+#endif // ENABLE(PARALLEL_JOBS)
+
+ fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height());
}
void FETurbulence::dump()
bool stitchTiles() const;
bool setStitchTiles(bool);
+#if ENABLE(PARALLEL_JOBS)
+ static void fillRegionWorker(void*);
+#endif
+
virtual void apply();
virtual void dump();
private:
static const int s_blockSize = 256;
static const int s_blockMask = s_blockSize - 1;
+#if ENABLE(PARALLEL_JOBS)
+ static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs
+#endif
struct PaintingData {
long seed;
int height;
int wrapX; // Minimum value to wrap.
int wrapY;
- int channel;
IntSize filterSize;
PaintingData(long paintingSeed, const IntSize& paintingSize);
inline long random();
};
+#if ENABLE(PARALLEL_JOBS)
+ template<typename Type>
+ friend class ParallelJobs;
+
+ struct FillRegionParameters {
+ FETurbulence* filter;
+ ByteArray* pixelArray;
+ PaintingData* paintingData;
+ int startY;
+ int endY;
+ };
+
+ static void fillRegionWorker(FillRegionParameters*);
+#endif
+
FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool);
inline void initPaint(PaintingData&);
- float noise2D(PaintingData&, const FloatPoint&);
- unsigned char calculateTurbulenceValueForPoint(PaintingData&, const FloatPoint&);
+ float noise2D(int channel, PaintingData&, const FloatPoint&);
+ unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, const FloatPoint&);
+ inline void fillRegion(ByteArray*, PaintingData&, int, int);
TurbulenceType m_type;
float m_baseFrequencyX;