From bc44da49e64230c795d9634ad7dce3b58a9954b5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 27 Sep 2016 10:50:38 +0100 Subject: [PATCH] Introduced new OpenThreads::Affinity class to wrap up specification of thread affinity. Simplified the OpenThreads::SetProcessorAffinityOfCurrentThread/Thread::SetProcessorAffinity() to utilize the new Affinity class --- include/OpenThreads/Affinity | 65 ++++++++++++++ include/OpenThreads/Thread | 31 ++----- src/OpenThreads/CMakeLists.txt | 1 + src/OpenThreads/pthreads/PThread.cpp | 90 ++++++++----------- src/OpenThreads/pthreads/PThreadPrivateData.h | 4 +- 5 files changed, 108 insertions(+), 83 deletions(-) create mode 100644 include/OpenThreads/Affinity diff --git a/include/OpenThreads/Affinity b/include/OpenThreads/Affinity new file mode 100644 index 000000000..27fc2a546 --- /dev/null +++ b/include/OpenThreads/Affinity @@ -0,0 +1,65 @@ +/* -*-c++-*- OpenThreads library, Copyright (C) 2016 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. +*/ + + +// +// Affinity - C++ Affinity class +// ~~~~~~~~ +// + +#ifndef _OPENTHREADS_AFFINITY_ +#define _OPENTHREADS_AFFINITY_ + +#include +#include + +namespace OpenThreads { + +/** + * @class Affinity + * @brief Simple container for specifying which CPU a thread should have affinity with. + * An empty Affinity.activeCPUs/default constructed Affinity signifies that a thread should not have any specific affinity and be able to run on all available CPUs. + */ +class Affinity +{ +public: + + Affinity() {} + + Affinity(unsigned int cpuNumber) { activeCPUs.insert(cpuNumber); } + + Affinity(unsigned int cpuNumber, unsigned int cpuCount) { while(cpuCount>0) { activeCPUs.insert(cpuNumber++); --cpuCount; } } + + Affinity(const Affinity& rhs) : activeCPUs(rhs.activeCPUs) {} + + Affinity& operator = (const Affinity& rhs) { if (&rhs!=this) { activeCPUs = rhs.activeCPUs; } return *this; } + + + /** add a specfied cpu core from the list to have affinity to. */ + void add(unsigned int cpuNmber) { activeCPUs.insert(cpuNmber); } + + /** remove a specfied cpu core from the list to have affinity to. */ + void remove(unsigned int cpuNmber) { activeCPUs.erase(cpuNmber); } + + /** return true if affinity has been provided for specific CPU cores.*/ + operator bool () const { return !activeCPUs.empty(); } + + typedef std::set ActiveCPUs; + + /** Set of CPUs that a thread should have affinity to.*/ + ActiveCPUs activeCPUs; +}; + +} + +#endif // !_OPENTHREADS_THREAD_ diff --git a/include/OpenThreads/Thread b/include/OpenThreads/Thread index c525cec8b..80bf75cdf 100644 --- a/include/OpenThreads/Thread +++ b/include/OpenThreads/Thread @@ -23,6 +23,7 @@ #include #include +#include namespace OpenThreads { @@ -34,19 +35,11 @@ namespace OpenThreads { */ extern OPENTHREAD_EXPORT_DIRECTIVE int GetNumberOfProcessors(); -/** - * Set the processor affinity mask of current thread. If you want to allow thread to run on any processor core use ~0ul for the cpumask - */ -extern OPENTHREAD_EXPORT_DIRECTIVE int SetProcessorAffinityMaskOfCurrentThread(unsigned long cpumask); - /** * Set the processor affinity of current thread. */ -inline int SetProcessorAffinityOfCurrentThread(unsigned int cpunum) -{ - unsigned long cpumask = 1ul << cpunum; - return SetProcessorAffinityMaskOfCurrentThread(cpumask); -} +int SetProcessorAffinityOfCurrentThread(const Affinity& affinity); + /** * @class Thread @@ -338,27 +331,13 @@ public: void* getImplementation(){ return _prvData; }; - /** Set the Thread's processor affinity to a single CPU. + /** Set the Thread's processor affinity to all, a single CPU or multiple CPU's * This call must be made before * start() or startThread() and has no effect after the thread * has been running. Returns 0 on success, implementation's * error on failure, or -1 if ignored. */ - int setProcessorAffinity( unsigned int cpunum ) - { - unsigned long cpumask = 1ul << cpunum; - return setProcessorAffinityMask(cpumask); - } - - - /** Set the Thread's processor affinity to a one or more CPU's using mask. - * If you want this threadd to run on any processor core then use a cpumask of ~0ul - * This call must be made before - * start() or startThread() and has no effect after the thread - * has been running. Returns 0 on success, implementation's - * error on failure, or -1 if ignored. - */ - int setProcessorAffinityMask( unsigned long cpumask); + int setProcessorAffinity( const Affinity& affinity); /** microSleep method, equivalent to the posix usleep(microsec). diff --git a/src/OpenThreads/CMakeLists.txt b/src/OpenThreads/CMakeLists.txt index 2ffa7eaf2..8e204c38a 100644 --- a/src/OpenThreads/CMakeLists.txt +++ b/src/OpenThreads/CMakeLists.txt @@ -59,6 +59,7 @@ ENDIF() SET(HEADER_PATH ${OpenThreads_SOURCE_DIR}/include/OpenThreads) SET(OpenThreads_PUBLIC_HEADERS ${HEADER_PATH}/Atomic + ${HEADER_PATH}/Affinity ${HEADER_PATH}/Barrier ${HEADER_PATH}/Block ${HEADER_PATH}/Condition diff --git a/src/OpenThreads/pthreads/PThread.cpp b/src/OpenThreads/pthreads/PThread.cpp index 0a72ca168..6c55862a5 100644 --- a/src/OpenThreads/pthreads/PThread.cpp +++ b/src/OpenThreads/pthreads/PThread.cpp @@ -108,19 +108,35 @@ void thread_cleanup_handler(void *arg) namespace OpenThreads { -static void setCPUMask(cpu_set_t* cpumask, unsigned long in_cpumask) +static void setCPUMask(cpu_set_t* cpumask, const Affinity& affinity) { + std::cout<<"setCPUMask : "<< affinity.activeCPUs.size() <>=1; - ++cpunum; } } @@ -146,45 +162,18 @@ private: PThreadPrivateData *pd = static_cast(thread->_prvData); - if (pd->cpumask>=0) - { -#if defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) - cpu_set_t cpumask; - setCPUMask( &cpumask, pd->cpumask ); + // set up processor affinity + cpu_set_t cpumask; + setCPUMask( &cpumask, pd->affinity ); #if defined(HAVE_PTHREAD_SETAFFINITY_NP) - pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); + pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); #elif defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) - sched_setaffinity( 0, sizeof(cpumask), &cpumask ); + sched_setaffinity( 0, sizeof(cpumask), &cpumask ); #elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) - sched_setaffinity( 0, &cpumask ); + sched_setaffinity( 0, &cpumask ); #endif -#endif - } -#if defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) - else - { - // BUG-fix for linux: - // Each thread inherits the processor affinity mask from its parent thread. - // We need to explicitly set it to all CPUs, if no affinity was specified. - cpu_set_t cpumask; - CPU_ZERO( &cpumask ); - - for (int i = 0; i < OpenThreads::GetNumberOfProcessors(); ++i) - { - CPU_SET( i, &cpumask ); - } - -#if defined(HAVE_PTHREAD_SETAFFINITY_NP) - pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); -#elif defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) - sched_setaffinity( 0, sizeof(cpumask), &cpumask ); -#elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) - sched_setaffinity( 0, &cpumask ); -#endif - } -#endif ThreadCleanupStruct tcs; tcs.thread = thread; @@ -548,20 +537,20 @@ size_t Thread::getProcessId() return (size_t)(pd->tid); } -int OpenThreads::SetProcessorAffinityMaskOfCurrentThread(unsigned long in_cpumask) +int OpenThreads::SetProcessorAffinityOfCurrentThread(const Affinity& affinity) { Thread::Init(); Thread* thread = Thread::CurrentThread(); if (thread) { - return thread->setProcessorAffinityMask(in_cpumask); + return thread->setProcessorAffinity(affinity); } else { -#if defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + // set up processor affinity cpu_set_t cpumask; - setCPUMask(&cpumask, in_cpumask); + setCPUMask( &cpumask, affinity ); #if defined(HAVE_PTHREAD_SETAFFINITY_NP) pthread_setaffinity_np( pthread_self(), sizeof(cpumask), &cpumask); @@ -572,7 +561,6 @@ int OpenThreads::SetProcessorAffinityMaskOfCurrentThread(unsigned long in_cpumas #elif defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) sched_setaffinity( 0, &cpumask ); return 0; -#endif #endif } @@ -585,18 +573,15 @@ int OpenThreads::SetProcessorAffinityMaskOfCurrentThread(unsigned long in_cpumas // // Use: public // -int Thread::setProcessorAffinityMask(unsigned long in_cpumask) +int Thread::setProcessorAffinity(const Affinity& affinity) { PThreadPrivateData *pd = static_cast (_prvData); - pd->cpumask = in_cpumask; - if (pd->cpumask==0) return -1; - -#if defined(HAVE_PTHREAD_SETAFFINITY_NP) || defined(HAVE_THREE_PARAM_SCHED_SETAFFINITY) || defined(HAVE_TWO_PARAM_SCHED_SETAFFINITY) + pd->affinity = affinity; if (pd->isRunning() && Thread::CurrentThread()==this) { cpu_set_t cpumask; - setCPUMask(&cpumask, in_cpumask); + setCPUMask(&cpumask, affinity); #if defined(HAVE_PTHREAD_SETAFFINITY_NP) return pthread_setaffinity_np (pthread_self(), sizeof(cpumask), &cpumask); @@ -608,9 +593,6 @@ int Thread::setProcessorAffinityMask(unsigned long in_cpumask) } return -1; -#else - return -1; -#endif } diff --git a/src/OpenThreads/pthreads/PThreadPrivateData.h b/src/OpenThreads/pthreads/PThreadPrivateData.h index 6df369bd4..bbbe535cb 100644 --- a/src/OpenThreads/pthreads/PThreadPrivateData.h +++ b/src/OpenThreads/pthreads/PThreadPrivateData.h @@ -53,7 +53,6 @@ private: nextId++; threadPriority = Thread::THREAD_PRIORITY_DEFAULT; threadPolicy = Thread::THREAD_SCHEDULE_DEFAULT; - cpumask = ~0ul; }; virtual ~PThreadPrivateData() {}; @@ -81,8 +80,7 @@ private: volatile int uniqueId; - volatile unsigned long cpumask; - + Affinity affinity; static int nextId;