Commit 17a66740 authored by Sujin Philip's avatar Sujin Philip
Browse files

Additions to SMP API

The following additions have been made to the vtk SMP framework
* Added GetEstimatedNumberOfThreads() to get an estimate on the number of threads used by the back-end.
* Added size() to thread local storage classes to get the number of thread local instances
* Improved thread local storage iterator API

Change-Id: Ic9925a0e856edfb14b78c175d94c9942df8478bf
parent 841bce74
......@@ -73,7 +73,9 @@
#ifndef vtkSMPThreadLocal_h
#define vtkSMPThreadLocal_h
#include "vtkAtomicInt.h"
#include "vtkSystemIncludes.h"
#include <vector>
#include <kaapic.h>
......@@ -88,7 +90,7 @@ class vtkSMPThreadLocal
public:
// Description:
// Default constructor. Creates a default exemplar.
vtkSMPThreadLocal() : Exemplar()
vtkSMPThreadLocal() : NumInitialized(0)
{
this->Initialize();
}
......@@ -97,9 +99,8 @@ public:
// Constructor that allows the specification of an exemplar object
// which is used when constructing objects when Local() is first called.
// Note that a copy of the exemplar is created using its copy constructor.
vtkSMPThreadLocal(const T& exemplar)
vtkSMPThreadLocal(const T& exemplar) : NumInitialized(0), Exemplar(exemplar)
{
this->Exemplar = exemplar;
this->Initialize();
}
......@@ -118,13 +119,21 @@ public:
{
this->Internal[tid] = this->Exemplar;
this->Initialized[tid] = true;
++this->NumInitialized;
}
return this->Internal[tid];
}
// Description:
// Return the number of thread local objects that have been initialized
size_t size() const
{
return this->NumInitialized.load();
}
// Description:
// Subset of the standard iterator API.
// The most common design patter is to use iterators in a sequential
// The most common design pattern is to use iterators in a sequential
// code block and to use only the thread local objects in parallel
// code blocks.
// It is thread safe to iterate over the thread local containers
......@@ -152,6 +161,18 @@ public:
return *this;
}
iterator operator++(int)
{
iterator copy = *this;
++(*this);
return copy;
}
bool operator==(const iterator& other)
{
return this->Iter == other.Iter;
}
bool operator!=(const iterator& other)
{
return this->Iter != other.Iter;
......@@ -162,6 +183,11 @@ public:
return *this->Iter;
}
T* operator->()
{
return &*this->Iter;
}
private:
friend class vtkSMPThreadLocal<T>;
std::vector<unsigned char>::iterator InitIter;
......@@ -212,6 +238,7 @@ public:
private:
TLS Internal;
std::vector<unsigned char> Initialized;
vtkAtomicInt<size_t> NumInitialized;
T Exemplar;
void Initialize()
......
......@@ -51,3 +51,8 @@ void vtkSMPTools::Initialize(int)
}
vtkSMPToolsCS.Unlock();
}
int vtkSMPTools::GetEstimatedNumberOfThreads()
{
return kaapic_get_concurrency();
}
......@@ -37,6 +37,7 @@
#define vtkSMPThreadLocal_h
#include "vtkSystemIncludes.h"
#include <vector>
template <typename T>
......@@ -47,7 +48,7 @@ class vtkSMPThreadLocal
public:
// Description:
// Default constructor. Creates a default exemplar.
vtkSMPThreadLocal()
vtkSMPThreadLocal() : NumInitialized(0)
{
this->Initialize();
}
......@@ -56,7 +57,7 @@ public:
// Constructor that allows the specification of an exemplar object
// which is used when constructing objects when Local() is first called.
// Note that a copy of the exemplar is created using its copy constructor.
vtkSMPThreadLocal(const T& exemplar) : Exemplar(exemplar)
vtkSMPThreadLocal(const T& exemplar) : NumInitialized(0), Exemplar(exemplar)
{
this->Initialize();
}
......@@ -76,13 +77,21 @@ public:
{
this->Internal[tid] = this->Exemplar;
this->Initialized[tid] = true;
++this->NumInitialized;
}
return this->Internal[tid];
}
// Description:
// Return the number of thread local objects that have been initialized
size_t size() const
{
return this->NumInitialized;
}
// Description:
// Subset of the standard iterator API.
// The most common design patter is to use iterators in a sequential
// The most common design pattern is to use iterators in a sequential
// code block and to use only the thread local objects in parallel
// code blocks.
// It is thread safe to iterate over the thread local containers
......@@ -110,6 +119,18 @@ public:
return *this;
}
iterator operator++(int)
{
iterator copy = *this;
++(*this);
return copy;
}
bool operator==(const iterator& other)
{
return this->Iter == other.Iter;
}
bool operator!=(const iterator& other)
{
return this->Iter != other.Iter;
......@@ -120,6 +141,11 @@ public:
return *this->Iter;
}
T* operator->()
{
return &*this->Iter;
}
private:
friend class vtkSMPThreadLocal<T>;
std::vector<bool>::iterator InitIter;
......@@ -170,6 +196,7 @@ public:
private:
TLS Internal;
std::vector<bool> Initialized;
size_t NumInitialized;
T Exemplar;
void Initialize()
......
......@@ -21,3 +21,8 @@
void vtkSMPTools::Initialize(int)
{
}
int vtkSMPTools::GetEstimatedNumberOfThreads()
{
return 1;
}
......@@ -78,8 +78,10 @@
#include "vtkCommonCoreModule.h" // For export macro
#include "vtkAtomicInt.h"
#include "vtkSystemIncludes.h"
#include "vtkMultiThreader.h"
#include <vector>
VTKCOMMONCORE_EXPORT int vtkSMPToolsGetNumberOfThreads();
......@@ -93,7 +95,7 @@ class vtkSMPThreadLocal
public:
// Description:
// Default constructor. Creates a default exemplar.
vtkSMPThreadLocal() : Exemplar()
vtkSMPThreadLocal() : NumInitialized(0)
{
this->Initialize();
}
......@@ -102,7 +104,7 @@ public:
// Constructor that allows the specification of an exemplar object
// which is used when constructing objects when Local() is first called.
// Note that a copy of the exemplar is created using its copy constructor.
vtkSMPThreadLocal(const T& exemplar) : Exemplar(exemplar)
vtkSMPThreadLocal(const T& exemplar) : NumInitialized(0), Exemplar(exemplar)
{
this->Initialize();
}
......@@ -122,10 +124,18 @@ public:
{
this->Internal[tid] = this->Exemplar;
this->Initialized[tid] = true;
++this->NumInitialized;
}
return this->Internal[tid];
}
// Description:
// Return the number of thread local objects that have been initialized
size_t size() const
{
return this->NumInitialized.load();
}
// Description:
// Subset of the standard iterator API.
// The most common design pattern is to use iterators in a sequential
......@@ -156,6 +166,18 @@ public:
return *this;
}
iterator operator++(int)
{
iterator copy = *this;
++(*this);
return copy;
}
bool operator==(const iterator& other)
{
return this->Iter == other.Iter;
}
bool operator!=(const iterator& other)
{
return this->Iter != other.Iter;
......@@ -166,6 +188,11 @@ public:
return *this->Iter;
}
T* operator->()
{
return &*this->Iter;
}
private:
friend class vtkSMPThreadLocal<T>;
std::vector<unsigned char>::iterator InitIter;
......@@ -216,6 +243,7 @@ public:
private:
TLS Internal;
std::vector<unsigned char> Initialized;
vtkAtomicInt<size_t> NumInitialized;
T Exemplar;
void Initialize()
......
......@@ -81,3 +81,8 @@ void vtkSMPTools::Initialize(int nThreads)
vtkSMPToolsThreadIds.resize(vtkSMPToolsNumberOfThreads);
vtkSMPToolsThreadIds[0] = vtkMultiThreader::GetCurrentThreadID();
}
int vtkSMPTools::GetEstimatedNumberOfThreads()
{
return vtkSMPToolsNumberOfThreads;
}
......@@ -108,9 +108,16 @@ public:
return this->Internal.local();
}
// Description:
// Return the number of thread local objects that have been initialized
size_t size() const
{
return this->Internal.size();
}
// Description:
// Subset of the standard iterator API.
// The most common design patter is to use iterators in a sequential
// The most common design pattern is to use iterators in a sequential
// code block and to use only the thread local objects in parallel
// code blocks.
// It is thread safe to iterate over the thread local containers
......@@ -125,6 +132,18 @@ public:
return *this;
}
iterator operator++(int)
{
iterator copy = *this;
++this->Iter;
return copy;
}
bool operator==(const iterator& other)
{
return this->Iter == other.Iter;
}
bool operator!=(const iterator& other)
{
return this->Iter != other.Iter;
......@@ -135,6 +154,11 @@ public:
return *this->Iter;
}
T* operator->()
{
return &*this->Iter;
}
private:
TLSIter Iter;
......
......@@ -29,6 +29,7 @@ struct vtkSMPToolsInit
};
static bool vtkSMPToolsInitialized = 0;
static int vtkTBBNumSpecifiedThreads = 0;
static vtkSimpleCriticalSection vtkSMPToolsCS;
//--------------------------------------------------------------------------------
......@@ -37,13 +38,20 @@ void vtkSMPTools::Initialize(int numThreads)
vtkSMPToolsCS.Lock();
if (!vtkSMPToolsInitialized)
{
// If numThreads == 0 (default num. threads), don't create a task_scheduler_init
// If numThreads <= 0, don't create a task_scheduler_init
// and let TBB do the default thing.
if (numThreads != 0)
if (numThreads > 0)
{
static vtkSMPToolsInit aInit(numThreads);
vtkTBBNumSpecifiedThreads = numThreads;
}
vtkSMPToolsInitialized = true;
}
vtkSMPToolsCS.Unlock();
}
int vtkSMPTools::GetEstimatedNumberOfThreads()
{
return vtkTBBNumSpecifiedThreads ? vtkTBBNumSpecifiedThreads
: tbb::task_scheduler_init::default_num_threads();
}
......@@ -125,9 +125,16 @@ public:
return vtkobject;
}
// Description:
// Return the number of thread local objects that have been initialized
size_t size() const
{
return this->Internal.size();
}
// Description:
// Subset of the standard iterator API.
// The most common design patter is to use iterators in a sequential
// The most common design pattern is to use iterators in a sequential
// code block and to use only the thread local objects in parallel
// code blocks.
class iterator
......@@ -139,6 +146,18 @@ public:
return *this;
}
iterator operator++(int)
{
iterator copy = *this;
++this->Iter;
return copy;
}
bool operator==(const iterator& other)
{
return this->Iter == other.Iter;
}
bool operator!=(const iterator& other)
{
return this->Iter != other.Iter;
......@@ -149,6 +168,11 @@ public:
return *this->Iter;
}
T** operator->()
{
return &*this->Iter;
}
private:
TLSIter Iter;
......
......@@ -206,6 +206,13 @@ public:
// When using Kaapi, use the KAAPI_CPUCOUNT env. variable to control
// the number of threads used in the thread pool.
static void Initialize(int numThreads=0);
// Description:
// Get the estimated number of threads being used by the backend.
// This should be used as just an estimate since the number of threads may
// vary dynamically and a particular task may not be executed on all the
// available threads.
static int GetEstimatedNumberOfThreads();
};
#endif
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment