|
Packit Service |
c5cf8c |
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* (C) 2003 by Argonne National Laboratory.
|
|
Packit Service |
c5cf8c |
* See COPYRIGHT in top-level directory.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* MPI-3 distributed linked list construction example
|
|
Packit Service |
c5cf8c |
* --------------------------------------------------
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Construct a distributed shared linked list using proposed MPI-3 dynamic
|
|
Packit Service |
c5cf8c |
* windows. Initially process 0 creates the head of the list, attaches it to
|
|
Packit Service |
c5cf8c |
* the window, and broadcasts the pointer to all processes. All processes then
|
|
Packit Service |
c5cf8c |
* concurrently append N new elements to the list. When a process attempts to
|
|
Packit Service |
c5cf8c |
* attach its element to the tail of list it may discover that its tail pointer
|
|
Packit Service |
c5cf8c |
* is stale and it must chase ahead to the new tail before the element can be
|
|
Packit Service |
c5cf8c |
* attached.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#include <stdio.h>
|
|
Packit Service |
c5cf8c |
#include <stdlib.h>
|
|
Packit Service |
c5cf8c |
#include <mpi.h>
|
|
Packit Service |
c5cf8c |
#include <assert.h>
|
|
Packit Service |
c5cf8c |
#include "mpitest.h"
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#ifdef HAVE_UNISTD_H
|
|
Packit Service |
c5cf8c |
#include <unistd.h>
|
|
Packit Service |
c5cf8c |
#endif
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#define NUM_ELEMS 32
|
|
Packit Service |
c5cf8c |
#define NPROBE 100
|
|
Packit Service |
c5cf8c |
#define ELEM_PER_ROW 16
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Linked list pointer */
|
|
Packit Service |
c5cf8c |
typedef struct {
|
|
Packit Service |
c5cf8c |
int rank;
|
|
Packit Service |
c5cf8c |
MPI_Aint disp;
|
|
Packit Service |
c5cf8c |
} llist_ptr_t;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Linked list element */
|
|
Packit Service |
c5cf8c |
typedef struct {
|
|
Packit Service |
c5cf8c |
int value;
|
|
Packit Service |
c5cf8c |
llist_ptr_t next;
|
|
Packit Service |
c5cf8c |
} llist_elem_t;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
static const llist_ptr_t nil = { -1, (MPI_Aint) MPI_BOTTOM };
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
static const int verbose = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* List of locally allocated list elements. */
|
|
Packit Service |
c5cf8c |
static llist_elem_t **my_elems = NULL;
|
|
Packit Service |
c5cf8c |
static int my_elems_size = 0;
|
|
Packit Service |
c5cf8c |
static int my_elems_count = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Allocate a new shared linked list element */
|
|
Packit Service |
c5cf8c |
MPI_Aint alloc_elem(int value, MPI_Win win)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
MPI_Aint disp;
|
|
Packit Service |
c5cf8c |
llist_elem_t *elem_ptr;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Allocate the new element and register it with the window */
|
|
Packit Service |
c5cf8c |
MPI_Alloc_mem(sizeof(llist_elem_t), MPI_INFO_NULL, &elem_ptr);
|
|
Packit Service |
c5cf8c |
elem_ptr->value = value;
|
|
Packit Service |
c5cf8c |
elem_ptr->next = nil;
|
|
Packit Service |
c5cf8c |
MPI_Win_attach(win, elem_ptr, sizeof(llist_elem_t));
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Add the element to the list of local elements so we can free it later. */
|
|
Packit Service |
c5cf8c |
if (my_elems_size == my_elems_count) {
|
|
Packit Service |
c5cf8c |
my_elems_size += 100;
|
|
Packit Service |
c5cf8c |
my_elems = realloc(my_elems, my_elems_size * sizeof(void *));
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
my_elems[my_elems_count] = elem_ptr;
|
|
Packit Service |
c5cf8c |
my_elems_count++;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Get_address(elem_ptr, &disp;;
|
|
Packit Service |
c5cf8c |
return disp;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
int main(int argc, char **argv)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
int procid, nproc, i;
|
|
Packit Service |
c5cf8c |
MPI_Win llist_win;
|
|
Packit Service |
c5cf8c |
llist_ptr_t head_ptr, tail_ptr;
|
|
Packit Service |
c5cf8c |
int errs = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MTest_Init(&argc, &argv);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Comm_rank(MPI_COMM_WORLD, &procid);
|
|
Packit Service |
c5cf8c |
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_create_dynamic(MPI_INFO_NULL, MPI_COMM_WORLD, &llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Process 0 creates the head node */
|
|
Packit Service |
c5cf8c |
if (procid == 0)
|
|
Packit Service |
c5cf8c |
head_ptr.disp = alloc_elem(-1, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Broadcast the head pointer to everyone */
|
|
Packit Service |
c5cf8c |
head_ptr.rank = 0;
|
|
Packit Service |
c5cf8c |
MPI_Bcast(&head_ptr.disp, 1, MPI_AINT, 0, MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
tail_ptr = head_ptr;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* All processes concurrently append NUM_ELEMS elements to the list */
|
|
Packit Service |
c5cf8c |
for (i = 0; i < NUM_ELEMS; i++) {
|
|
Packit Service |
c5cf8c |
llist_ptr_t new_elem_ptr;
|
|
Packit Service |
c5cf8c |
int success;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Create a new list element and register it with the window */
|
|
Packit Service |
c5cf8c |
new_elem_ptr.rank = procid;
|
|
Packit Service |
c5cf8c |
new_elem_ptr.disp = alloc_elem(procid, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Append the new node to the list. This might take multiple attempts if
|
|
Packit Service |
c5cf8c |
* others have already appended and our tail pointer is stale. */
|
|
Packit Service |
c5cf8c |
do {
|
|
Packit Service |
c5cf8c |
llist_ptr_t next_tail_ptr = nil;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Compare_and_swap((void *) &new_elem_ptr.rank, (void *) &nil.rank,
|
|
Packit Service |
c5cf8c |
(void *) &next_tail_ptr.rank, MPI_INT, tail_ptr.rank,
|
|
Packit Service |
c5cf8c |
(MPI_Aint) & (((llist_elem_t *) tail_ptr.disp)->next.rank),
|
|
Packit Service |
c5cf8c |
llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_unlock(tail_ptr.rank, llist_win);
|
|
Packit Service |
c5cf8c |
success = (next_tail_ptr.rank == nil.rank);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (success) {
|
|
Packit Service |
c5cf8c |
int i, flag;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Put(&new_elem_ptr.disp, 1, MPI_AINT, tail_ptr.rank,
|
|
Packit Service |
c5cf8c |
(MPI_Aint) & (((llist_elem_t *) tail_ptr.disp)->next.disp), 1,
|
|
Packit Service |
c5cf8c |
MPI_AINT, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_unlock(tail_ptr.rank, llist_win);
|
|
Packit Service |
c5cf8c |
tail_ptr = new_elem_ptr;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* For implementations that use pt-to-pt messaging, force progress for other threads'
|
|
Packit Service |
c5cf8c |
* RMA operations. */
|
|
Packit Service |
c5cf8c |
for (i = 0; i < NPROBE; i++)
|
|
Packit Service |
c5cf8c |
MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag,
|
|
Packit Service |
c5cf8c |
MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
/* Tail pointer is stale, fetch the displacement. May take multiple tries
|
|
Packit Service |
c5cf8c |
* if it is being updated. */
|
|
Packit Service |
c5cf8c |
do {
|
|
Packit Service |
c5cf8c |
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Get(&next_tail_ptr.disp, 1, MPI_AINT, tail_ptr.rank,
|
|
Packit Service |
c5cf8c |
(MPI_Aint) & (((llist_elem_t *) tail_ptr.disp)->next.disp),
|
|
Packit Service |
c5cf8c |
1, MPI_AINT, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_unlock(tail_ptr.rank, llist_win);
|
|
Packit Service |
c5cf8c |
} while (next_tail_ptr.disp == nil.disp);
|
|
Packit Service |
c5cf8c |
tail_ptr = next_tail_ptr;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
} while (!success);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Barrier(MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Traverse the list and verify that all processes inserted exactly the correct
|
|
Packit Service |
c5cf8c |
* number of elements. */
|
|
Packit Service |
c5cf8c |
if (procid == 0) {
|
|
Packit Service |
c5cf8c |
int have_root = 0;
|
|
Packit Service |
c5cf8c |
int *counts, count = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
counts = (int *) malloc(sizeof(int) * nproc);
|
|
Packit Service |
c5cf8c |
assert(counts != NULL);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
for (i = 0; i < nproc; i++)
|
|
Packit Service |
c5cf8c |
counts[i] = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
tail_ptr = head_ptr;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Walk the list and tally up the number of elements inserted by each rank */
|
|
Packit Service |
c5cf8c |
while (tail_ptr.disp != nil.disp) {
|
|
Packit Service |
c5cf8c |
llist_elem_t elem;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Get(&elem, sizeof(llist_elem_t), MPI_BYTE,
|
|
Packit Service |
c5cf8c |
tail_ptr.rank, tail_ptr.disp, sizeof(llist_elem_t), MPI_BYTE, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_unlock(tail_ptr.rank, llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
tail_ptr = elem.next;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* This is not the root */
|
|
Packit Service |
c5cf8c |
if (have_root) {
|
|
Packit Service |
c5cf8c |
assert(elem.value >= 0 && elem.value < nproc);
|
|
Packit Service |
c5cf8c |
counts[elem.value]++;
|
|
Packit Service |
c5cf8c |
count++;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (verbose) {
|
|
Packit Service |
c5cf8c |
int last_elem = tail_ptr.disp == nil.disp;
|
|
Packit Service |
c5cf8c |
printf("%2d%s", elem.value, last_elem ? "" : " -> ");
|
|
Packit Service |
c5cf8c |
if (count % ELEM_PER_ROW == 0 && !last_elem)
|
|
Packit Service |
c5cf8c |
printf("\n");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* This is the root */
|
|
Packit Service |
c5cf8c |
else {
|
|
Packit Service |
c5cf8c |
assert(elem.value == -1);
|
|
Packit Service |
c5cf8c |
have_root = 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("\n\n");
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Verify the counts we collected */
|
|
Packit Service |
c5cf8c |
for (i = 0; i < nproc; i++) {
|
|
Packit Service |
c5cf8c |
int expected = NUM_ELEMS;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (counts[i] != expected) {
|
|
Packit Service |
c5cf8c |
printf("Error: Rank %d inserted %d elements, expected %d\n", i, counts[i],
|
|
Packit Service |
c5cf8c |
expected);
|
|
Packit Service |
c5cf8c |
errs++;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
free(counts);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Win_free(&llist_win);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Free all the elements in the list */
|
|
Packit Service |
c5cf8c |
for (; my_elems_count > 0; my_elems_count--)
|
|
Packit Service |
c5cf8c |
MPI_Free_mem(my_elems[my_elems_count - 1]);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MTest_Finalize(errs);
|
|
Packit Service |
c5cf8c |
return MTestReturnValue(errs);
|
|
Packit Service |
c5cf8c |
}
|