diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-14 14:09:24 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-05-14 14:09:24 +0000 |
commit | 554875210043b34178f7ed6ac5bd682b1fad367b (patch) | |
tree | fdadeb167ef502f98784117a3c05378c72fceeec /src | |
parent | f105b109264f71dfb0bfd9977e6a5dd0a5a12f57 (diff) |
Add bench and test for SkRefCnt.
http://codereview.appspot.com/6195071/
This also adds a cross platform SkThread for testing purposes.
git-svn-id: http://skia.googlecode.com/svn/trunk@3921 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/ports/SkThread_none.cpp | 4 | ||||
-rw-r--r-- | src/utils/SkThreadUtils.h | 46 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_pthread.cpp | 105 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_pthread.h | 29 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_pthread_linux.cpp | 46 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_pthread_mach.cpp | 30 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_pthread_other.cpp | 12 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_win.cpp | 136 | ||||
-rw-r--r-- | src/utils/SkThreadUtils_win.h | 28 |
9 files changed, 435 insertions, 1 deletions
diff --git a/src/ports/SkThread_none.cpp b/src/ports/SkThread_none.cpp index 9e170cfb3d..a948a5410c 100644 --- a/src/ports/SkThread_none.cpp +++ b/src/ports/SkThread_none.cpp @@ -8,6 +8,7 @@ #include "SkThread.h" +#include "SkTLS.h" int32_t sk_atomic_inc(int32_t* addr) { int32_t value = *addr; @@ -25,9 +26,10 @@ SkMutex::SkMutex() {} SkMutex::~SkMutex() {} +#ifndef SK_USE_POSIX_THREADS void SkMutex::acquire() {} - void SkMutex::release() {} +#endif ////////////////////////////////////////////////////////////////////////// diff --git a/src/utils/SkThreadUtils.h b/src/utils/SkThreadUtils.h new file mode 100644 index 0000000000..b0c5044618 --- /dev/null +++ b/src/utils/SkThreadUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadUtils_DEFINED +#define SkThreadUtils_DEFINED + +#include "SkTypes.h" + +class SkThread : SkNoncopyable { +public: + typedef void (*entryPointProc)(void*); + + SkThread(entryPointProc entryPoint, void* data = NULL); + + /** + * Non-virtual, do not subclass. + */ + ~SkThread(); + + /** + * Starts the thread. Returns false if the thread could not be started. + */ + bool start(); + + /** + * Waits for the thread to finish. + * If the thread has not started, returns immediately. + */ + void join(); + + /** + * SkThreads with an affinity for the same processor will attempt to run cache + * locally with each other. SkThreads with an affinity for different processors + * will attempt to run on different cores. Returns false if the request failed. + */ + bool setProcessorAffinity(unsigned int processor); + +private: + void* fData; +}; + +#endif diff --git a/src/utils/SkThreadUtils_pthread.cpp b/src/utils/SkThreadUtils_pthread.cpp new file mode 100644 index 0000000000..17a2075ab0 --- /dev/null +++ b/src/utils/SkThreadUtils_pthread.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" + +#include "SkThreadUtils.h" +#include "SkThreadUtils_pthread.h" + +#include <pthread.h> +#include <signal.h> + +SkThread_PThreadData::SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data) + : fPThread() + , fValidPThread(false) + , fParam(data) + , fEntryPoint(entryPoint) + , fStarted(false) +{ + pthread_mutex_init(&fStartMutex, NULL); + + pthread_cond_init(&fStartCondition, NULL); + + pthread_attr_init(&fAttr); + pthread_attr_setdetachstate(&fAttr, PTHREAD_CREATE_JOINABLE); +} +SkThread_PThreadData::~SkThread_PThreadData() { + pthread_attr_destroy(&fAttr); + pthread_cond_destroy(&fStartCondition); + pthread_mutex_destroy(&fStartMutex); +} + +static void* thread_start(void* arg) { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(arg); + //Wait for start signal + pthread_mutex_lock(&(pthreadData->fStartMutex)); + while (!pthreadData->fStarted) { + pthread_cond_wait(&(pthreadData->fStartCondition), &(pthreadData->fStartMutex)); + } + pthread_mutex_unlock(&(pthreadData->fStartMutex)); + + //See if this thread was canceled before starting. + pthread_testcancel(); + + pthreadData->fEntryPoint(pthreadData->fParam); + return NULL; +} + +SkThread::SkThread(entryPointProc entryPoint, void* data) { + SkThread_PThreadData* pthreadData = new SkThread_PThreadData(entryPoint, data); + fData = pthreadData; + + int ret = pthread_create(&(pthreadData->fPThread), + &(pthreadData->fAttr), + thread_start, + pthreadData); + + pthreadData->fValidPThread = (0 == ret); +} + +SkThread::~SkThread() { + if (fData != NULL) { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); + // If created thread but start was never called, kill the thread. + if (pthreadData->fValidPThread && !pthreadData->fStarted) { + if (pthread_cancel(pthreadData->fPThread) == 0) { + if (this->start()) { + this->join(); + } + } else { + //kill with prejudice + pthread_kill(pthreadData->fPThread, SIGKILL); + } + } + delete pthreadData; + } +} + +bool SkThread::start() { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); + if (!pthreadData->fValidPThread) { + return false; + } + + if (pthreadData->fStarted) { + return false; + } + pthreadData->fStarted = true; + pthread_mutex_lock(&(pthreadData->fStartMutex)); + pthread_cond_signal(&(pthreadData->fStartCondition)); + pthread_mutex_unlock(&(pthreadData->fStartMutex)); + return true; +} + +void SkThread::join() { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); + if (!pthreadData->fValidPThread || !pthreadData->fStarted) { + return; + } + + pthread_join(pthreadData->fPThread, NULL); +} diff --git a/src/utils/SkThreadUtils_pthread.h b/src/utils/SkThreadUtils_pthread.h new file mode 100644 index 0000000000..52b398c2e2 --- /dev/null +++ b/src/utils/SkThreadUtils_pthread.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadUtils_PThreadData_DEFINED +#define SkThreadUtils_PThreadData_DEFINED + +#include "SkThreadUtils.h" +#include <pthread.h> + +class SkThread_PThreadData { +public: + SkThread_PThreadData(SkThread::entryPointProc entryPoint, void* data); + ~SkThread_PThreadData(); + pthread_t fPThread; + bool fValidPThread; + pthread_mutex_t fStartMutex; + pthread_cond_t fStartCondition; + pthread_attr_t fAttr; + + void* fParam; + SkThread::entryPointProc fEntryPoint; + bool fStarted; +}; + +#endif diff --git a/src/utils/SkThreadUtils_pthread_linux.cpp b/src/utils/SkThreadUtils_pthread_linux.cpp new file mode 100644 index 0000000000..4a03cb8276 --- /dev/null +++ b/src/utils/SkThreadUtils_pthread_linux.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE //for pthread_setaffinity_np +#endif + +#include "SkThreadUtils.h" +#include "SkThreadUtils_pthread.h" + +#include <pthread.h> + +static int nth_set_cpu(unsigned int n, cpu_set_t* cpuSet) { + n %= CPU_COUNT(cpuSet); + for (unsigned int setCpusSeen = 0, currentCpu = 0; true; ++currentCpu) { + if (CPU_ISSET(currentCpu, cpuSet)) { + ++setCpusSeen; + if (setCpusSeen > n) { + return currentCpu; + } + } + } +} + +bool SkThread::setProcessorAffinity(unsigned int processor) { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); + if (!pthreadData->fValidPThread) { + return false; + } + + cpu_set_t parentCpuset; + if (0 != pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &parentCpuset)) { + return false; + } + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(nth_set_cpu(processor, &parentCpuset), &cpuset); + return 0 == pthread_setaffinity_np(pthreadData->fPThread, + sizeof(cpu_set_t), + &cpuset); +} diff --git a/src/utils/SkThreadUtils_pthread_mach.cpp b/src/utils/SkThreadUtils_pthread_mach.cpp new file mode 100644 index 0000000000..0f6e263906 --- /dev/null +++ b/src/utils/SkThreadUtils_pthread_mach.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkThreadUtils.h" +#include "SkThreadUtils_pthread.h" + +#include <mach/mach.h> +#include <mach/thread_policy.h> +#include <pthread.h> + +bool SkThread::setProcessorAffinity(unsigned int processor) { + SkThread_PThreadData* pthreadData = static_cast<SkThread_PThreadData*>(fData); + if (!pthreadData->fValidPThread) { + return false; + } + + mach_port_t tid = pthread_mach_thread_np(pthreadData->fPThread); + + thread_affinity_policy_data_t policy; + policy.affinity_tag = processor; + + return 0 == thread_policy_set(tid, + THREAD_AFFINITY_POLICY, + (thread_policy_t) &policy, + THREAD_AFFINITY_POLICY_COUNT); +} diff --git a/src/utils/SkThreadUtils_pthread_other.cpp b/src/utils/SkThreadUtils_pthread_other.cpp new file mode 100644 index 0000000000..a3973f1d72 --- /dev/null +++ b/src/utils/SkThreadUtils_pthread_other.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkThreadUtils.h" + +bool SkThread::setProcessorAffinity(unsigned int processor) { + return false; +} diff --git a/src/utils/SkThreadUtils_win.cpp b/src/utils/SkThreadUtils_win.cpp new file mode 100644 index 0000000000..208ffded1b --- /dev/null +++ b/src/utils/SkThreadUtils_win.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkTypes.h" + +#include "SkThreadUtils.h" +#include "SkThreadUtils_win.h" + +SkThread_WinData::SkThread_WinData(SkThread::entryPointProc entryPoint, void* data) + : fHandle(NULL) + , fParam(data) + , fThreadId(0) + , fEntryPoint(entryPoint) + , fStarted(false) +{ + fCancelEvent = CreateEvent( + NULL, // default security attributes + false, //auto reset + false, //not signaled + NULL); //no name +} + +SkThread_WinData::~SkThread_WinData() { + CloseHandle(fCancelEvent); +} + +static DWORD WINAPI thread_start(LPVOID data) { + SkThread_WinData* winData = static_cast<SkThread_WinData*>(data); + + //See if this thread was canceled before starting. + if (WaitForSingleObject(winData->fCancelEvent, 0) == WAIT_OBJECT_0) { + return 0; + } + + winData->fEntryPoint(winData->fParam); + return 0; +} + +SkThread::SkThread(entryPointProc entryPoint, void* data) { + SkThread_WinData* winData = new SkThread_WinData(entryPoint, data); + fData = winData; + + if (NULL == winData->fCancelEvent) { + return; + } + + winData->fHandle = CreateThread( + NULL, // default security attributes + 0, // use default stack size + thread_start, // thread function name (proxy) + winData, // argument to thread function (proxy args) + CREATE_SUSPENDED, // create suspended so affinity can be set + &winData->fThreadId); // returns the thread identifier +} + +SkThread::~SkThread() { + if (fData != NULL) { + SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); + // If created thread but start was never called, kill the thread. + if (winData->fHandle != NULL && !winData->fStarted) { + if (SetEvent(winData->fCancelEvent) != 0) { + if (this->start()) { + this->join(); + } + } else { + //kill with prejudice + TerminateThread(winData->fHandle, -1); + } + } + delete winData; + } +} + +bool SkThread::start() { + SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); + if (NULL == winData->fHandle) { + return false; + } + + if (winData->fStarted) { + return false; + } + winData->fStarted = -1 != ResumeThread(winData->fHandle); + return winData->fStarted; +} + +void SkThread::join() { + SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); + if (NULL == winData->fHandle || !winData->fStarted) { + return; + } + + WaitForSingleObject(winData->fHandle, INFINITE); +} + +static unsigned int num_bits_set(DWORD_PTR mask) { + unsigned int count; + for (count = 0; mask; ++count) { + mask &= mask - 1; + } + return count; +} + +static unsigned int nth_set_bit(unsigned int n, DWORD_PTR mask) { + n %= num_bits_set(mask); + for (unsigned int setBitsSeen = 0, currentBit = 0; true; ++currentBit) { + if (mask & (1 << currentBit)) { + ++setBitsSeen; + if (setBitsSeen > n) { + return currentBit; + } + } + } +} + +bool SkThread::setProcessorAffinity(unsigned int processor) { + SkThread_WinData* winData = static_cast<SkThread_WinData*>(fData); + if (NULL == winData->fHandle) { + return false; + } + + DWORD_PTR processAffinityMask; + DWORD_PTR systemAffinityMask; + if (0 == GetProcessAffinityMask(GetCurrentProcess(), + &processAffinityMask, + &systemAffinityMask)) { + return false; + } + + DWORD_PTR threadAffinityMask = 1 << nth_set_bit(processor, processAffinityMask); + return 0 != SetThreadAffinityMask(winData->fHandle, threadAffinityMask); +} diff --git a/src/utils/SkThreadUtils_win.h b/src/utils/SkThreadUtils_win.h new file mode 100644 index 0000000000..5861e5d0db --- /dev/null +++ b/src/utils/SkThreadUtils_win.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkThreadUtils_WinData_DEFINED +#define SkThreadUtils_WinData_DEFINED + +#include "SkTypes.h" + +#include "SkThreadUtils.h" + +class SkThread_WinData { +public: + SkThread_WinData(SkThread::entryPointProc entryPoint, void* data); + ~SkThread_WinData(); + HANDLE fHandle; + HANDLE fCancelEvent; + + LPVOID fParam; + DWORD fThreadId; + SkThread::entryPointProc fEntryPoint; + bool fStarted; +}; + +#endif |