Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of https://github.com/mpoquet/simgrid
[simgrid.git] / teshsuite / smpi / mpich3-test / rma / linked_list.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *
4  *  (C) 2003 by Argonne National Laboratory.
5  *      See COPYRIGHT in top-level directory.
6  */
7
8 /*            MPI-3 distributed linked list construction example
9  *            --------------------------------------------------
10  * 
11  * Construct a distributed shared linked list using proposed MPI-3 dynamic
12  * windows.  Initially process 0 creates the head of the list, attaches it to
13  * the window, and broadcasts the pointer to all processes.  All processes then
14  * concurrently append N new elements to the list.  When a process attempts to
15  * attach its element to the tail of list it may discover that its tail pointer
16  * is stale and it must chase ahead to the new tail before the element can be
17  * attached.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <mpi.h>
23 #include <assert.h>
24 #include "mpitest.h"
25
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #define NUM_ELEMS 32
31 #define NPROBE    100
32 #define ELEM_PER_ROW 16
33
34 /* Linked list pointer */
35 typedef struct {
36     int      rank;
37     MPI_Aint disp;
38 } llist_ptr_t;
39
40 /* Linked list element */
41 typedef struct {
42     int value;
43     llist_ptr_t next;
44 } llist_elem_t;
45
46 static const llist_ptr_t nil = { -1, (MPI_Aint) MPI_BOTTOM };
47 static const int verbose = 0;
48
49 /* List of locally allocated list elements. */
50 static llist_elem_t **my_elems = NULL;
51 static int my_elems_size  = 0;
52 static int my_elems_count = 0;
53
54 /* Allocate a new shared linked list element */
55 MPI_Aint alloc_elem(int value, MPI_Win win) {
56     MPI_Aint disp;
57     llist_elem_t *elem_ptr;
58
59     /* Allocate the new element and register it with the window */
60     MPI_Alloc_mem(sizeof(llist_elem_t), MPI_INFO_NULL, &elem_ptr);
61     elem_ptr->value = value;
62     elem_ptr->next  = nil;
63     MPI_Win_attach(win, elem_ptr, sizeof(llist_elem_t));
64
65     /* Add the element to the list of local elements so we can free it later. */
66     if (my_elems_size == my_elems_count) {
67         my_elems_size += 100;
68         my_elems = realloc(my_elems, my_elems_size*sizeof(void*));
69     }
70     my_elems[my_elems_count] = elem_ptr;
71     my_elems_count++;
72
73     MPI_Get_address(elem_ptr, &disp);
74     return disp;
75 }
76
77 int main(int argc, char **argv) {
78     int           procid, nproc, i;
79     MPI_Win       llist_win;
80     llist_ptr_t   head_ptr, tail_ptr;
81
82     MPI_Init(&argc, &argv);
83
84     MPI_Comm_rank(MPI_COMM_WORLD, &procid);
85     MPI_Comm_size(MPI_COMM_WORLD, &nproc);
86
87     MPI_Win_create_dynamic(MPI_INFO_NULL, MPI_COMM_WORLD, &llist_win);
88
89     /* Process 0 creates the head node */
90     if (procid == 0)
91         head_ptr.disp = alloc_elem(-1, llist_win);
92
93     /* Broadcast the head pointer to everyone */
94     head_ptr.rank = 0;
95     MPI_Bcast(&head_ptr.disp, 1, MPI_AINT, 0, MPI_COMM_WORLD);
96     tail_ptr = head_ptr;
97
98     /* All processes concurrently append NUM_ELEMS elements to the list */
99     for (i = 0; i < NUM_ELEMS; i++) {
100         llist_ptr_t new_elem_ptr;
101         int success;
102
103         /* Create a new list element and register it with the window */
104         new_elem_ptr.rank = procid;
105         new_elem_ptr.disp = alloc_elem(procid, llist_win);
106
107         /* Append the new node to the list.  This might take multiple attempts if
108            others have already appended and our tail pointer is stale. */
109         do {
110             llist_ptr_t next_tail_ptr = nil;
111
112             MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
113
114             MPI_Compare_and_swap((void*) &new_elem_ptr.rank, (void*) &nil.rank,
115                                   (void*) &next_tail_ptr.rank, MPI_INT, tail_ptr.rank,
116                                   (MPI_Aint) &(((llist_elem_t*)tail_ptr.disp)->next.rank), llist_win);
117
118             MPI_Win_unlock(tail_ptr.rank, llist_win);
119             success = (next_tail_ptr.rank == nil.rank);
120
121             if (success) {
122                 int i, flag;
123
124                 MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
125
126                 MPI_Put(&new_elem_ptr.disp, 1, MPI_AINT, tail_ptr.rank,
127                         (MPI_Aint) &(((llist_elem_t*)tail_ptr.disp)->next.disp), 1,
128                         MPI_AINT, llist_win);
129
130                 MPI_Win_unlock(tail_ptr.rank, llist_win);
131                 tail_ptr = new_elem_ptr;
132
133                 /* For implementations that use pt-to-pt messaging, force progress for other threads'
134                    RMA operations. */
135                 for (i = 0; i < NPROBE; i++)
136                     MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, MPI_STATUS_IGNORE);
137
138             } else {
139                 /* Tail pointer is stale, fetch the displacement.  May take multiple tries
140                    if it is being updated. */
141                 do {
142                     MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
143
144                     MPI_Get( &next_tail_ptr.disp, 1, MPI_AINT, tail_ptr.rank,
145                              (MPI_Aint) &(((llist_elem_t*)tail_ptr.disp)->next.disp),
146                              1, MPI_AINT, llist_win);
147
148                     MPI_Win_unlock(tail_ptr.rank, llist_win);
149                 } while (next_tail_ptr.disp == nil.disp);
150                 tail_ptr = next_tail_ptr;
151             }
152         } while (!success);
153     }
154
155     MPI_Barrier(MPI_COMM_WORLD);
156
157     /* Traverse the list and verify that all processes inserted exactly the correct
158        number of elements. */
159     if (procid == 0) {
160         int  have_root = 0;
161         int  errors    = 0;
162         int *counts, count = 0;
163
164         counts = (int*) malloc(sizeof(int) * nproc);
165         assert(counts != NULL);
166
167         for (i = 0; i < nproc; i++)
168             counts[i] = 0;
169
170         tail_ptr = head_ptr;
171
172         /* Walk the list and tally up the number of elements inserted by each rank */
173         while (tail_ptr.disp != nil.disp) {
174             llist_elem_t elem;
175
176             MPI_Win_lock(MPI_LOCK_EXCLUSIVE, tail_ptr.rank, 0, llist_win);
177
178             MPI_Get(&elem, sizeof(llist_elem_t), MPI_BYTE,
179                     tail_ptr.rank, tail_ptr.disp, sizeof(llist_elem_t), MPI_BYTE, llist_win);
180
181             MPI_Win_unlock(tail_ptr.rank, llist_win);
182
183             tail_ptr = elem.next;
184
185             /* This is not the root */
186             if (have_root) {
187                 assert(elem.value >= 0 && elem.value < nproc);
188                 counts[elem.value]++;
189                 count++;
190
191                 if (verbose) {
192                     int last_elem = tail_ptr.disp == nil.disp;
193                     printf("%2d%s", elem.value, last_elem ? "" : " -> ");
194                     if (count % ELEM_PER_ROW == 0 && !last_elem)
195                         printf("\n");
196                 }
197             }
198
199             /* This is the root */
200             else {
201                 assert(elem.value == -1);
202                 have_root = 1;
203             }
204         }
205
206         if (verbose)
207           printf("\n\n");
208
209         /* Verify the counts we collected */
210         for (i = 0; i < nproc; i++) {
211             int expected = NUM_ELEMS;
212
213             if (counts[i] != expected) {
214                 printf("Error: Rank %d inserted %d elements, expected %d\n", i, counts[i], expected);
215                 errors++;
216             }
217         }
218
219         printf("%s\n", errors == 0 ? " No Errors" : "FAIL");
220         free(counts);
221     }
222
223     MPI_Win_free(&llist_win);
224
225     /* Free all the elements in the list */
226     for ( ; my_elems_count > 0; my_elems_count--)
227         MPI_Free_mem(my_elems[my_elems_count-1]);
228
229     MPI_Finalize();
230     return 0;
231 }