![]() |
Peano
|
Task enumerator for Swift 2. More...
#include <TaskEnumerator.h>
Public Member Functions | |
TaskEnumerator ()=default | |
void | reset () |
int | getNumber () |
Create a new task number. | |
void | releaseNumber (int value) |
Free task number. | |
int | size () const |
Number of numbers handed out so far. | |
std::string | toString () const |
Decorator for tarch::Enumerator::toString(). | |
Static Public Member Functions | |
static void | lockResources (const tarch::la::Vector< TwoPowerD, int > &numbers) |
Lock resources. | |
static void | unlockResources (const tarch::la::Vector< TwoPowerD, int > &numbers) |
Free resources. | |
Private Types | |
using | ResourcesSemaphore = tarch::multicore::MultiReadSingleWriteSemaphore |
Protect the _resources map. | |
Static Private Member Functions | |
static void | insertNumber (int number) |
Create a new number. | |
static void | insertNumbers (const tarch::la::Vector< TwoPowerD, int > &numbers) |
Static Private Attributes | |
static tarch::Enumerator | _globalEnumerator |
static std::map< int, tarch::multicore::BooleanSemaphore * > | _resources |
Each task is tied to a resource, i.e. | |
static ResourcesSemaphore | _resourcesSemaphore |
Task enumerator for Swift 2.
Every particle type (species) has a marker associate to the vertices and cells. So they are all unique numbers. Therefore, each of these markers is tied to one rank-global enumerator. These enumerators may not give out the same numbers even for different species. Therefore, we make the enumerator instances (of this type) all become a decorator for tarch::Enumerator which delegates all calls to a global instance. As a result, each marker type can work with its own instance of this TaskEnumerator, but behind the scenes, all requests are funneled through to one big number generator.
Besides the administration of the tasks, the type also maintains a big hash map of resources, which is really just a hash map to boolean semaphores plus some routines that manage access to them. These can be used to ensure that no two cells access the same vertex concurrently.
We can use objects of this type as proxy to access a big global table with one lock per global single task number. So if we have a cell with four neighbours where race conditions might occur, we can use lockResources() to ensure that we exclusively access those neighbours. In Swift's original terminology, these are the conflicts that we resolve at runtime.
The class is thread-safe as the underlying tarch::Enumerator object is thread-safe. However, we need an additional semaphore for the underlying map of resources.
Definition at line 53 of file TaskEnumerator.h.
|
private |
Protect the _resources map.
This map holds all the boolean semaphores. An arbitrary number of threads can hit this map at the same time and try to book some semaphores. This is technically a read access, as they do not write to the map. They only read from the map.
Contrary to this, we may not change the map, i.e. insert new semaphores, if others try to read it, as new inserts might change the underlying memory arrangement and hence mess everything up.
Definition at line 175 of file TaskEnumerator.h.
|
default |
int swift2::TaskEnumerator::getNumber | ( | ) |
Create a new task number.
Returns a unique non-zero number which is not yet used anywhere else on this rank.
Resources are tied to numbers in the way that each vertex and cell number plus its underlying even (touch vertex first, touch cell, touch vertex last) identifies one unique counter: In practice, each number that we create can yield up to three resource entries. We don't know the correlation at this point, so we cannot lock any resources at this point.
The tarch::Enumerator is thread safe, so we don't have to protect the actual result number generation. However, once we have a new number, we also check if the resource map is properly initialised. For this, we need a semaphore, as we might alter the container.
Definition at line 48 of file TaskEnumerator.cpp.
Create a new number.
This routine is robust, i.e. if the number does exist already, we do not do anything.
Definition at line 21 of file TaskEnumerator.cpp.
References assertionEquals1, and tarch::Enumerator::NoNumber.
|
staticprivate |
Definition at line 30 of file TaskEnumerator.cpp.
References tarch::Enumerator::NoNumber, and TwoPowerD.
|
static |
Lock resources.
This routine is used to lock a set of indices. This could be the \( 2^d \) adjacent vertices of a cell. This way, we ensure that noone else uses these vertices concurrently. It can also be used, obviously, to lock the \( 2^d \) adjacent cells of a vertex in case we know their indices.
The implementation is not a simple while loop: We loop over the entries of numbers and try to lock them. If one lock fails, we unlock all previous ones immediately again, yield, and then try again. This way, we avoid deadlocks if multiple cells next to each other each try to lock their adjacent vertices but actually only get around half of the locks they want.
Entries set to tarch::Enumerator::NoNumber are ignored.
At any point throughout the calculation, another thread might insert new resource identifiers into the _resources map through getNumber() calls. If such a call happens at exactly the same time as _resources.at( numbers[counter] ), we might end up with a seg fault. Therefore, the locking itself is protected until we get all resources.
getNumber() explains why there's no direct 1:1 match of numbers to resources. Therefore, we create indices lazily at this point through insertNumbers().
Definition at line 68 of file TaskEnumerator.cpp.
References assertion2, assertionEquals2, tarch::multicore::Lock::free(), tarch::multicore::Core::getInstance(), tarch::Enumerator::NoNumber, tarch::multicore::Lock::tryLock(), TwoPowerD, and tarch::multicore::Core::yield().
Free task number.
Free a number again. number has to be the result of a previous getNumber() call. While getNumber() can generate resources, we do not free them in releaseNumber().
Definition at line 53 of file TaskEnumerator.cpp.
void swift2::TaskEnumerator::reset | ( | ) |
Definition at line 16 of file TaskEnumerator.cpp.
References _globalEnumerator, and tarch::Enumerator::reset().
int swift2::TaskEnumerator::size | ( | ) | const |
Number of numbers handed out so far.
Decorator for tarch::Enumerator::size().
Definition at line 58 of file TaskEnumerator.cpp.
Referenced by peano4.visualisation.input.Patch.Patch::__repr__(), kernel_impl.Enumerator::fetch(), kernel_impl.Enumerator::lower(), and kernel_impl.Enumerator::upper().
std::string swift2::TaskEnumerator::toString | ( | ) | const |
Decorator for tarch::Enumerator::toString().
Definition at line 63 of file TaskEnumerator.cpp.
|
static |
Free resources.
Counterpart to lockResources().
Entries set to tarch::Enumerator::NoNumber are ignored.
Definition at line 120 of file TaskEnumerator.cpp.
References assertion1, tarch::multicore::Lock::free(), tarch::Enumerator::NoNumber, and TwoPowerD.
|
staticprivate |
Definition at line 155 of file TaskEnumerator.h.
Referenced by reset().
|
staticprivate |
Each task is tied to a resource, i.e.
a unique number, which we can lock and unlock again.
Definition at line 161 of file TaskEnumerator.h.
|
staticprivate |
Definition at line 177 of file TaskEnumerator.h.