aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-05-14 14:09:24 +0000
committerGravatar bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-05-14 14:09:24 +0000
commit554875210043b34178f7ed6ac5bd682b1fad367b (patch)
treefdadeb167ef502f98784117a3c05378c72fceeec /src
parentf105b109264f71dfb0bfd9977e6a5dd0a5a12f57 (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.cpp4
-rw-r--r--src/utils/SkThreadUtils.h46
-rw-r--r--src/utils/SkThreadUtils_pthread.cpp105
-rw-r--r--src/utils/SkThreadUtils_pthread.h29
-rw-r--r--src/utils/SkThreadUtils_pthread_linux.cpp46
-rw-r--r--src/utils/SkThreadUtils_pthread_mach.cpp30
-rw-r--r--src/utils/SkThreadUtils_pthread_other.cpp12
-rw-r--r--src/utils/SkThreadUtils_win.cpp136
-rw-r--r--src/utils/SkThreadUtils_win.h28
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