Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add teams spec tests to "spec-example" directory #918

Merged
merged 7 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions test/spec-example/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,13 @@ check_PROGRAMS += \
shmemx_test_any \
shmemx_test_some \
shmemx_team_split_strided \
shmem_team_split_2D \
shmemx_team_translate \
shmem_team_context \
shmemx_team_sync \
shmemx_team_broadcast \
shmemx_team_collect \
shmem_reduce_example \
shmemx_team_alltoall \
shmemx_team_alltoalls

Expand Down
55 changes: 55 additions & 0 deletions test/spec-example/shmem_reduce_example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* This test program is derived from an example program in the
* OpenSHMEM specification.
*/

#include <shmemx.h>
#include <shmem.h>
#include <stdio.h>
#include <stdlib.h>

#define NELEMS 32

int main(void) {
shmem_init();
int mype = shmem_my_pe();
int npes = shmem_n_pes();

int *values = shmem_malloc(NELEMS * sizeof(int));

unsigned char *value_is_maximal = shmem_malloc(NELEMS * sizeof(unsigned char));
unsigned char *value_is_maximal_all = shmem_malloc(NELEMS * sizeof(unsigned char));

static int maximal_values_count = 0;
static int maximal_values_total;

srand((unsigned)mype);

for (int i = 0; i < NELEMS; i++) {
values[i] = rand() % npes;

/* Track and count instances of maximal values (i.e., values equal to (npes-1)) */
value_is_maximal[i] = (values[i] == (npes - 1)) ? 1 : 0;
maximal_values_count += value_is_maximal[i];
}

/* Wait for all PEs to initialize reductions arrays */
shmemx_sync(SHMEMX_TEAM_WORLD);

shmemx_or_reduce(SHMEMX_TEAM_WORLD, value_is_maximal_all, value_is_maximal, NELEMS);
shmemx_sum_reduce(SHMEMX_TEAM_WORLD, &maximal_values_total, &maximal_values_count, 1);

if (mype == 0) {
printf("Found %d maximal random numbers across all PEs.\n", maximal_values_total);
printf("A maximal number occured (at least once) at the following indices:\n");
for (int i = 0; i < NELEMS; i++) {
if (value_is_maximal_all[i] == 1) {
printf("%d ", i);
}
}
printf("\n");
}

shmem_finalize();
return 0;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example makes no sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the upside, it looks like it will work now, which is great.

107 changes: 107 additions & 0 deletions test/spec-example/shmem_team_context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* This test program is derived from an example program in the
* OpenSHMEM specification.
*/

#include <shmemx.h>
#include <shmem.h>
#include <stdio.h>


int main(void)
{
static int sum = 0, val_2, val_3;
shmemx_team_t team_2, team_3;
shmem_ctx_t ctx_2, ctx_3;
shmemx_team_config_t conf;

shmem_init();

int npes = shmem_n_pes();
int mype = shmem_my_pe();
conf.num_contexts = 1;
long cmask = SHMEMX_TEAM_NUM_CONTEXTS;

/* Create team_2 with PEs numbered 0, 2, 4, ... */
int ret = shmemx_team_split_strided(SHMEMX_TEAM_WORLD, 0, 2, (npes + 1) / 2, &conf, cmask, &team_2);

if (ret != 0) {
printf("%d: Error creating team team_2 (%d)\n", mype, ret);
shmem_global_exit(ret);
}

/* Create team_3 with PEs numbered 0, 3, 6, ... */
ret = shmemx_team_split_strided(SHMEMX_TEAM_WORLD, 0, 3, (npes + 2) / 3, &conf, cmask, &team_3);

if (ret != 0) {
printf("%d: Error creating team team_3 (%d)\n", mype, ret);
shmem_global_exit(ret);
}

/* Create a context on team_2. */
ret = shmemx_team_create_ctx(team_2, 0, &ctx_2);

if (ret != 0 && team_2 != SHMEMX_TEAM_INVALID) {
printf("%d: Error creating context ctx_2 (%d)\n", mype, ret);
shmem_global_exit(ret);
}

/* Create a context on team_3. */
ret = shmemx_team_create_ctx(team_3, 0, &ctx_3);

if (ret != 0 && team_3 != SHMEMX_TEAM_INVALID) {
printf("%d: Error creating context ctx_3 (%d)\n", mype, ret);
shmem_global_exit(ret);
}

/* Within each team, put my PE number to my neighbor in a ring-based manner. */
if (ctx_2 != SHMEMX_CTX_INVALID) {
int pe = shmemx_team_my_pe(team_2);
shmem_ctx_int_put(ctx_2, &val_2, &pe, 1, (pe + 1) % shmemx_team_n_pes(team_2));
}

if (ctx_3 != SHMEMX_CTX_INVALID) {
int pe = shmemx_team_my_pe(team_3);
shmem_ctx_int_put(ctx_3, &val_3, &pe, 1, (pe + 1) % shmemx_team_n_pes(team_3));
}

/* Quiet both contexts and synchronize all PEs to complete the data transfers. */
shmem_ctx_quiet(ctx_2);
shmem_ctx_quiet(ctx_3);
shmemx_team_sync(SHMEMX_TEAM_WORLD);

/* Sum the values among PEs that are in both team_2 and team_3 on PE 0 with ctx_2. */
if (team_3 != SHMEMX_TEAM_INVALID && team_2 != SHMEMX_TEAM_INVALID)
shmem_ctx_int_atomic_add(ctx_2, &sum, val_2 + val_3, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unreliable way to check, since context creation failure is local (not global)...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops - right. So I just need to include a check for ctx_2 != SHMEM_CTX_INVALID right? The test only wants PEs that are in both teams to do this atomic.


/* Quiet the context and synchronize PEs to complete the operation. */
shmem_ctx_quiet(ctx_2);
shmemx_team_sync(SHMEMX_TEAM_WORLD);

/* Validate the result. */
if (mype == 0) {
int vsum = 0;
for (int i = 0; i < npes; i ++) {
if (i % 2 == 0 && i % 3 == 0) {
vsum += ((i - 2) < 0) ? shmemx_team_n_pes(team_2) - 1 :
shmemx_team_translate_pe(SHMEMX_TEAM_WORLD, i - 2, team_2);
vsum += ((i - 3) < 0) ? shmemx_team_n_pes(team_3) - 1 :
shmemx_team_translate_pe(SHMEMX_TEAM_WORLD, i - 3, team_3);
}
}
if (sum != vsum) {
fprintf(stderr, "Unexpected result, npes = %d, vsum = %d, sum = %d\n", shmem_n_pes(), vsum, sum);
shmem_global_exit(1);
}
}

/* Destroy contexts before teams. */
shmem_ctx_destroy(ctx_2);
shmemx_team_destroy(team_2);

shmem_ctx_destroy(ctx_3);
shmemx_team_destroy(team_3);

shmem_finalize();
return 0;
}
69 changes: 69 additions & 0 deletions test/spec-example/shmem_team_split_2D.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* This test program is derived from an example program in the
* OpenSHMEM specification.
*/

#include <shmemx.h>
#include <shmem.h>
#include <stdio.h>
#include <math.h>

/* Find x and y such that x * y == npes and abs(x - y) is minimized. */
static void find_xy_dims(int npes, int *x, int *y) {
for(int divider = ceil(sqrt(npes)); divider >= 1; divider--)
if (npes % divider == 0) {
*x = divider;
*y = npes / divider;
return;
}
}

/* Find x, y, and z such that x * y * z == npes and
* abs(x - y) + abs(x - z) + abs(y - z) is minimized. */
static void find_xyz_dims(int npes, int *x, int *y, int *z) {
for(int divider = ceil(cbrt(npes)); divider >= 1; divider--)
if (npes % divider == 0) {
*x = divider;
find_xy_dims(npes / divider, y, z);
return;
}
}

int main(void) {
int xdim, ydim, zdim;

shmem_init();
int mype = shmem_my_pe();
int npes = shmem_n_pes();

find_xyz_dims(npes, &xdim, &ydim, &zdim);

if (shmem_my_pe() == 0) printf("xdim = %d, ydim = %d, zdim = %d\n", xdim, ydim, zdim);

shmemx_team_t xteam, yzteam, yteam, zteam;

shmemx_team_split_2d(SHMEMX_TEAM_WORLD, xdim, NULL, 0, &xteam, NULL, 0, &yzteam);
// yzteam is immediately ready to be used in collectives
shmemx_team_split_2d(yzteam, ydim, NULL, 0, &yteam, NULL, 0, &zteam);

// We don't need the yzteam anymore
shmemx_team_destroy(yzteam);

int my_x = shmemx_team_my_pe(xteam);
int my_y = shmemx_team_my_pe(yteam);
int my_z = shmemx_team_my_pe(zteam);

for (int zdx = 0; zdx < zdim; zdx++) {
for (int ydx = 0; ydx < ydim; ydx++) {
for (int xdx = 0; xdx < xdim; xdx++) {
if ((my_x == xdx) && (my_y == ydx) && (my_z == zdx)) {
printf("(%d, %d, %d) is mype = %d\n", my_x, my_y, my_z, mype);
}
shmemx_team_sync(SHMEMX_TEAM_WORLD);
}
}
}

shmem_finalize();
return 0;
}