1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <mpi.h>
4 #include <pmix.h>
5
6 #define SIZE 20
7 #define POS 10
8 #define INITIAL_VALUE 10
9
10 static pmix_proc_t myproc;
11
12 /* this is the event notification function we pass down below
13 * when registering for general events - i.e.,, the default
14 * handler. We don't technically need to register one, but it
15 * is usually good practice to catch any events that occur */
notification_fn(size_t evhdlr_registration_id,pmix_status_t status,const pmix_proc_t * source,pmix_info_t info[],size_t ninfo,pmix_info_t results[],size_t nresults,pmix_event_notification_cbfunc_fn_t cbfunc,void * cbdata)16 static void notification_fn(size_t evhdlr_registration_id,
17 pmix_status_t status,
18 const pmix_proc_t *source,
19 pmix_info_t info[], size_t ninfo,
20 pmix_info_t results[], size_t nresults,
21 pmix_event_notification_cbfunc_fn_t cbfunc,
22 void *cbdata)
23 {
24 /* this example doesn't do anything with default events */
25 fprintf(stderr, "Default event handler called with status %s\n", PMIx_Error_string(status));
26
27 if (NULL != cbfunc) {
28 cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata);
29 }
30 }
31
32 /* this is an event notification function that we explicitly request
33 * be called when the PMIX_MODEL_DECLARED notification is issued.
34 * We could catch it in the general event notification function and test
35 * the status to see if the status matched, but it often is simpler
36 * to declare a use-specific notification callback point. In this case,
37 * we are asking to know whenever a programming model library is
38 * instantiated */
model_callback(size_t evhdlr_registration_id,pmix_status_t status,const pmix_proc_t * source,pmix_info_t info[],size_t ninfo,pmix_info_t results[],size_t nresults,pmix_event_notification_cbfunc_fn_t cbfunc,void * cbdata)39 static void model_callback(size_t evhdlr_registration_id,
40 pmix_status_t status,
41 const pmix_proc_t *source,
42 pmix_info_t info[], size_t ninfo,
43 pmix_info_t results[], size_t nresults,
44 pmix_event_notification_cbfunc_fn_t cbfunc,
45 void *cbdata)
46 {
47 size_t n;
48
49 fprintf(stderr, "Model event handler called with status %d(%s)\n", status, PMIx_Error_string(status));
50
51 /* check to see what model declared itself */
52 for (n=0; n < ninfo; n++) {
53 if (PMIX_STRING == info[n].value.type) {
54 fprintf(stderr, "\t%s:\t%s\n", info[n].key, info[n].value.data.string);
55 }
56 }
57
58 /* we must NOT tell the event handler state machine that we
59 * are the last step as that will prevent it from notifying
60 * anyone else that might be listening for declarations */
61 if (NULL != cbfunc) {
62 cbfunc(PMIX_SUCCESS, NULL, 0, NULL, NULL, cbdata);
63 }
64 }
65
66 /* event handler registration is done asynchronously because it
67 * may involve the PMIx server registering with the host RM for
68 * external events. So we provide a callback function that returns
69 * the status of the request (success or an error), plus a numerical index
70 * to the registered event. The index is used later on to deregister
71 * an event handler - if we don't explicitly deregister it, then the
72 * PMIx server will do so when it see us exit */
model_registration_callback(pmix_status_t status,size_t evhandler_ref,void * cbdata)73 static void model_registration_callback(pmix_status_t status,
74 size_t evhandler_ref,
75 void *cbdata)
76 {
77 volatile int *active = (volatile int*)cbdata;
78
79 if (PMIX_SUCCESS != status) {
80 fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n",
81 myproc.nspace, myproc.rank, status, (unsigned long)evhandler_ref);
82 }
83 *active = status;
84 }
85
main(int argc,char * argv[])86 int main(int argc, char *argv[])
87 {
88 int i, rank, size, next, prev, tag = 201;
89 int array_size = SIZE;
90 int pos = POS;
91 int *send_array;
92 int *recv_array;
93 pmix_info_t *info;
94 size_t ninfo;
95 pmix_status_t code = PMIX_MODEL_DECLARED;
96 pmix_status_t rc;
97 volatile int active;
98
99
100 if (1 < argc) {
101 fprintf(stderr, "Declaring ourselves\n");
102 /* declare ourselves as a non-MPI library prior to MPI_Init */
103 ninfo = 4;
104 PMIX_INFO_CREATE(info, ninfo);
105 PMIX_INFO_LOAD(&info[0], PMIX_PROGRAMMING_MODEL, "EXAMPLE", PMIX_STRING);
106 PMIX_INFO_LOAD(&info[1], PMIX_MODEL_LIBRARY_NAME, "FOOL", PMIX_STRING);
107 PMIX_INFO_LOAD(&info[2], PMIX_MODEL_LIBRARY_VERSION, "1.2.3", PMIX_STRING);
108 PMIX_INFO_LOAD(&info[3], PMIX_THREADING_MODEL, "NONE", PMIX_STRING);
109 if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, info, ninfo))) {
110 fprintf(stderr, "PMIx Init failed: %s\n", PMIx_Error_string(rc));
111 exit(1);
112 }
113 PMIX_INFO_FREE(info, ninfo);
114
115 /* register a handler specifically for when models declare */
116 active = -1;
117 ninfo = 1;
118 PMIX_INFO_CREATE(info, ninfo);
119 PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "APP-MODEL", PMIX_STRING);
120 PMIx_Register_event_handler(&code, 1, info, ninfo,
121 model_callback, model_registration_callback, (void*)&active);
122 while (-1 == active) {
123 usleep(10);
124 }
125 PMIX_INFO_FREE(info, ninfo);
126 if (0 != active) {
127 exit(active);
128 }
129 }
130
131 /* initialize the MPI library - it will declare itself */
132 MPI_Init(&argc, &argv);
133 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
134 MPI_Comm_size(MPI_COMM_WORLD, &size);
135 if (argc <= 1) {
136 fprintf(stderr, "Registering handler\n");
137 /* register a handler specifically for when models declare */
138 active = -1;
139 ninfo = 1;
140 PMIX_INFO_CREATE(info, ninfo);
141 PMIX_INFO_LOAD(&info[0], PMIX_EVENT_HDLR_NAME, "APP-MODEL", PMIX_STRING);
142
143 PMIx_Register_event_handler(&code, 1, info, ninfo,
144 model_callback, model_registration_callback, (void*)&active);
145 while (-1 == active) {
146 usleep(10);
147 }
148 PMIX_INFO_FREE(info, ninfo);
149 if (0 != active) {
150 exit(active);
151 }
152 }
153
154 fprintf(stderr, "Rank %d has cleared MPI_Init\n", rank);
155
156 next = (rank + 1) % size;
157 prev = (rank + size - 1) % size;
158 send_array = malloc(sizeof(int) * SIZE);
159 recv_array = malloc(sizeof(int) * SIZE);
160
161 for (i = 0; i < array_size; ++i) {
162 send_array[i] = 17;
163 recv_array[i] = -1;
164 }
165
166 if (0 == rank) {
167 send_array[pos] = INITIAL_VALUE;
168 MPI_Send(send_array, array_size, MPI_INT, next, tag,
169 MPI_COMM_WORLD);
170 }
171
172 /* if we didn't already do it, declare another model now */
173 if (argc <= 1) {
174 fprintf(stderr, "Declaring ourselves\n");
175 /* declare ourselves as a non-MPI library after MPI_Init */
176 ninfo = 4;
177 PMIX_INFO_CREATE(info, ninfo);
178 PMIX_INFO_LOAD(&info[0], PMIX_PROGRAMMING_MODEL, "EXAMPLE", PMIX_STRING);
179 PMIX_INFO_LOAD(&info[1], PMIX_MODEL_LIBRARY_NAME, "FOOL", PMIX_STRING);
180 PMIX_INFO_LOAD(&info[2], PMIX_MODEL_LIBRARY_VERSION, "1.2.3", PMIX_STRING);
181 PMIX_INFO_LOAD(&info[3], PMIX_THREADING_MODEL, "NONE", PMIX_STRING);
182
183 if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc, info, ninfo))) {
184 fprintf(stderr, "PMIx Init failed: %s\n", PMIx_Error_string(rc));
185 exit(1);
186 }
187 PMIX_INFO_FREE(info, ninfo);
188 }
189
190 while (1) {
191 recv_array[pos] = -1;
192 MPI_Recv(recv_array, array_size, MPI_INT, prev, tag,
193 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
194 send_array[pos] = recv_array[pos];
195 if (rank == 0) {
196 --send_array[pos];
197 }
198 MPI_Send(send_array, array_size, MPI_INT, next, tag, MPI_COMM_WORLD);
199 if (0 == send_array[pos]) {
200 break;
201 }
202 }
203
204 if (rank == 0) {
205 MPI_Recv(recv_array, array_size, MPI_INT, prev, tag,
206 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
207 }
208
209 fprintf(stderr, "Rank %d has completed ring\n", rank);
210 MPI_Barrier(MPI_COMM_WORLD);
211 fprintf(stderr, "Rank %d has completed MPI_Barrier\n", rank);
212
213 /* decrement the PMIx refcount */
214 PMIx_Finalize(NULL, 0);
215 MPI_Finalize();
216 return 0;
217 }
218