forked from harrism/hemi
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Preliminary atomics implementation, with atomicAdd and atomicCAS supp…
…orted. Uses OpenMP locks as an example.
- Loading branch information
1 parent
6fa816f
commit 31e4b46
Showing
1 changed file
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
#ifndef __HEMI_ATOMIC_H__ | ||
#define __HEMI_ATOMIC_H__ | ||
|
||
#include "hemi/hemi.h" | ||
|
||
// Open-MP specifics | ||
#ifdef _OPENMP | ||
#include <omp.h> | ||
#else | ||
/* Typedef here is to let the compiler have something reasonable for when you | ||
* are not using OpenMP, so that it compiles. The functions do fall through | ||
* to the ones above, though, so it should be safe to pass 0 to that without | ||
* openmp defined and all should work. | ||
* We assume that the lock is initialized prior to calling any of these functions. | ||
*/ | ||
typedef unsigned int omp_lock_t; | ||
#endif // _OPENMP | ||
|
||
|
||
/* Straightforward atomic implementations for device or host code. Examples | ||
* use OpenMP. If you need something for your threading environment of choice, | ||
* then overload the function, put up whatever barriers are needed, and then | ||
* call this. | ||
* | ||
* The only real important thing is that the overload also be | ||
* HEMI_DEV_CALLABLE_INLINE and the basic ifdef/else/endif structure goes | ||
* there. | ||
* | ||
*/ | ||
|
||
namespace hemi | ||
{ | ||
// Basic functions, assumed sequentials. | ||
HEMI_DEV_CALLABLE_INLINE int atomicAdd(int* address, int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicAdd(address, val); | ||
#else | ||
float old = *address; | ||
*address = old + val; | ||
return old; | ||
#endif | ||
} | ||
|
||
HEMI_DEV_CALLABLE_INLINE unsigned int atomicAdd(unsigned int* address, unsigned int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicAdd(address, val); | ||
#else | ||
unsigned int old = *address; | ||
*address = old + val; | ||
return old; | ||
#endif | ||
} | ||
HEMI_DEV_CALLABLE_INLINE unsigned long long int atomicAdd(unsigned long long int* address, unsigned long long int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicAdd(address, val); | ||
#else | ||
unsigned long long int old = *address; | ||
*address = old + val; | ||
return old; | ||
#endif | ||
} | ||
|
||
HEMI_DEV_CALLABLE_INLINE float atomicAdd(float* address, float val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicAdd(address, val); | ||
#else | ||
float old = *address; | ||
*address = old + val; | ||
return old; | ||
#endif | ||
} | ||
|
||
HEMI_DEV_CALLABLE_INLINE int atomicCAS(int* address, int compare, int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
int old = *address; | ||
*address = (old == compare ? val : old); | ||
return old; | ||
#endif | ||
} | ||
HEMI_DEV_CALLABLE_INLINE unsigned int atomicCAS(unsigned int* address, unsigned int compare, unsigned int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
unsigned int old = *address; | ||
*address = (old == compare ? val : old); | ||
return old; | ||
#endif | ||
} | ||
HEMI_DEV_CALLABLE_INLINE unsigned long long int atomicCAS(unsigned long long int* address, unsigned long long int compare, unsigned long long int val) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
unsigned long long int old = *address; | ||
*address = (old == compare ? val : old); | ||
return old; | ||
#endif | ||
} | ||
|
||
/* OpenMP-supported functions. These functions lock/unlock instead of using | ||
* named critical sections, because the named critical sections are global in | ||
* scope. If the lock acquisition fails, the function immediately returns | ||
* with the current value of address. | ||
*/ | ||
|
||
|
||
|
||
HEMI_DEV_CALLABLE_INLINE int atomicCAS(int* address, int compare, int val, omp_lock_t* lock) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
#ifdef _OPENMP | ||
omp_set_lock(lock); | ||
int old = hemi::atomicCAS(address, compare, val); | ||
omp_unset_lock(lock); | ||
return old; | ||
#else | ||
return hemi::atomicCAS(address, compare, val); | ||
#endif // _OPENMP | ||
#endif // HEMI_DEV_CODE | ||
} | ||
|
||
HEMI_DEV_CALLABLE_INLINE unsigned int atomicCAS(unsigned int* address, unsigned int compare, unsigned int val, omp_lock_t* lock) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
#ifdef _OPENMP | ||
omp_set_lock(lock); | ||
unsigned int old = hemi::atomicCAS(address, compare, val); | ||
omp_unset_lock(lock); | ||
return old; | ||
#else | ||
return hemi::atomicCAS(address, compare, val); | ||
#endif // _OPENMP | ||
#endif // HEMI_DEV_CODE | ||
} | ||
|
||
HEMI_DEV_CALLABLE_INLINE unsigned long long int atomicCAS(unsigned long long int* address, unsigned long long int compare, unsigned long long int val, omp_lock_t* lock) | ||
{ | ||
#ifdef HEMI_DEV_CODE | ||
return atomicCAS(address, compare, val); | ||
#else | ||
#ifdef _OPENMP | ||
omp_set_lock(lock); | ||
unsigned long long int old = hemi::atomicCAS(address, compare, val); | ||
omp_unset_lock(lock); | ||
return old; | ||
#else | ||
return hemi::atomicCAS(address, compare, val); | ||
#endif // _OPENMP | ||
#endif // HEMI_DEV_CODE | ||
} | ||
|
||
} | ||
|
||
#endif |
31e4b46
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is reference to issue harrism#6. I figure people who want to use something other than OpenMP for their multithreading can overload the basic functions (calling ours as a subroutine after critical section stuff), using our OpenMP implementation as a guide.