Lesson 5: Atomic Functions
Atomic Functions like communication functions can only be applied to objects in the symmetric memory. Unlike reduction calls which includes all PEs in a group, atomic functions are one-sided. Actually, it is very similar to a put call with a destination PE; however, with atomic, as the name would suggest, only one PE can change the destination value at a time. (We will only be focusing on the non-fetching routines.)There are four operations which we will focus on: add, and, or, xor. These atomic operations are called via the following:
- shmem_<TYPENAME>_atomic_add(TYPE *dest, TYPE value, int dest_pe)
- shmem_<TYPENAME>_atomic_and(TYPE *dest, TYPE value, int dest_pe)
- shmem_<TYPENAME>_atomic_or(TYPE *dest, TYPE value, int dest_pe)
- shmem_<TYPENAME>_atomic_xor(TYPE *dest, TYPE value, int dest_pe)
A few things to note:
- only one value is changed - you are sending one value to be "added" to the content at the destination address.
- the caller is only accessing the data of only one PE (the dest_pe)
Approximating pi revisited:
Rather than sending each individual count to PE 0 and having PE 0 add up the values, each PE (including PE 0) will call an atomic add. As a result, the value total on PE0 will be the sum of all the individual counts.#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <inttypes.h>
#include <shmem.h>
#define NUM 100000
double circle(double x){
return 1 - pow(x,2);
}
int main(){
int me, npes;
shmem_init();
me = shmem_my_pe();
npes = shmem_n_pes();
static long count = 0;
double f_x;
//seed the randomizer
srand(time(0)+me);
for (int i = 0; i < NUM; i++){
//generate point(x,y) in first quadrant
//note: double is a 64 bit floating point
double x = (double) rand() / (double) RAND_MAX;
double y = (double) rand() / (double) RAND_MAX;
f_x = circle(x);
if (pow(y,2) <= f_x){
count += 1;
}
}
printf("%d: count %ld\n", me, count);
static long total = 0; //needs to be in symmetric memory
shmem_long_atomic_add(&total, count, 0);
shmem_barrier_all(); //making sure all of the counts have been done
if (me == 0){
printf("%d: count total: %ld\n", me, total);
printf("%d: ratio: %f\n", me, (double)total/((double)NUM * npes));
printf("%d: est of pi: %f\n", me, (double)total/((double)NUM * npes)*4);
}
return 0;
}
