Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / gmxlib / thread_mpi / scan.c
1 /*
2    This source code file is part of thread_mpi.
3    Written by Sander Pronk, Erik Lindahl, and possibly others.
4
5    Copyright (c) 2009, Sander Pronk, Erik Lindahl.
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions are met:
10    1) Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15    3) Neither the name of the copyright holders nor the
16    names of its contributors may be used to endorse or promote products
17    derived from this software without specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30    If you want to redistribute modifications, please consider that
31    scientific software is very special. Version control is crucial -
32    bugs must be traceable. We will be happy to consider code for
33    inclusion in the official distribution, but derived work should not
34    be called official thread_mpi. Details are found in the README & COPYING
35    files.
36  */
37
38 #ifdef HAVE_TMPI_CONFIG_H
39 #include "tmpi_config.h"
40 #endif
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <stdarg.h>
55 #include <string.h>
56
57 #include "impl.h"
58 #include "collective.h"
59
60
61
62 int tMPI_Scan(void* sendbuf, void* recvbuf, int count,
63               tMPI_Datatype datatype, tMPI_Op op, tMPI_Comm comm)
64 {
65     struct tmpi_thread *cur    = tMPI_Get_current();
66     int                 myrank = tMPI_Comm_seek_rank(comm, cur);
67     int                 N      = tMPI_Comm_N(comm);
68     int                 prev   = myrank - 1; /* my previous neighbor */
69     int                 next   = myrank + 1; /* my next neighbor */
70
71 #ifdef TMPI_PROFILE
72     tMPI_Profile_count_start(cur);
73 #endif
74 #ifdef TMPI_TRACE
75     tMPI_Trace_print("tMPI_Scan(%p, %p, %d, %p, %p, %p)",
76                      sendbuf, recvbuf, count, datatype, op, comm);
77 #endif
78     if (count == 0)
79     {
80         return TMPI_SUCCESS;
81     }
82     if (!recvbuf)
83     {
84         return tMPI_Error(comm, TMPI_ERR_BUF);
85     }
86     if (sendbuf == TMPI_IN_PLACE)
87     {
88         sendbuf = recvbuf;
89     }
90
91     /* we set our send and recv buffers */
92     tMPI_Atomic_ptr_set(&(comm->reduce_sendbuf[myrank]), sendbuf);
93     tMPI_Atomic_ptr_set(&(comm->reduce_recvbuf[myrank]), recvbuf);
94
95     /* now wait for the previous rank to finish */
96     if (myrank > 0)
97     {
98         void *a, *b;
99         int   ret;
100
101 #if defined(TMPI_PROFILE) && defined(TMPI_CYCLE_COUNT)
102         tMPI_Profile_wait_start(cur);
103 #endif
104         /* wait for the previous neighbor's data to be ready */
105         tMPI_Event_wait( &(comm->csync[myrank].events[prev]) );
106         tMPI_Event_process( &(comm->csync[myrank].events[prev]), 1);
107 #if defined(TMPI_PROFILE) && defined(TMPI_CYCLE_COUNT)
108         tMPI_Profile_wait_stop(cur, TMPIWAIT_Reduce);
109 #endif
110 #ifdef TMPI_DEBUG
111         printf("%d: scanning with %d \n", myrank, prev, iteration);
112         fflush(stdout);
113 #endif
114         /* now do the reduction */
115         if (prev > 0)
116         {
117             a = (void*)tMPI_Atomic_ptr_get(&(comm->reduce_recvbuf[prev]));
118         }
119         else
120         {
121             a = (void*)tMPI_Atomic_ptr_get(&(comm->reduce_sendbuf[prev]));
122         }
123         b = sendbuf;
124
125         if ((ret = tMPI_Reduce_run_op(recvbuf, a, b, datatype,
126                                       count, op, comm)) != TMPI_SUCCESS)
127         {
128             return ret;
129         }
130
131         /* signal to my previous neighbor that I'm done with the data */
132         tMPI_Event_signal( &(comm->csync[prev].events[prev]) );
133     }
134     else
135     {
136         if (sendbuf != recvbuf)
137         {
138             /* copy the data if this is rank 0, and not MPI_IN_PLACE */
139             memcpy(recvbuf, sendbuf, count*datatype->size);
140         }
141     }
142
143     if (myrank < N-1)
144     {
145         /* signal to my next neighbor that I have the data */
146         tMPI_Event_signal( &(comm->csync[next].events[myrank]) );
147         /* and wait for my next neighbor to finish */
148         tMPI_Event_wait( &(comm->csync[myrank].events[myrank]) );
149         tMPI_Event_process( &(comm->csync[myrank].events[myrank]), 1);
150     }
151
152
153 #if defined(TMPI_PROFILE) && defined(TMPI_CYCLE_COUNT)
154     tMPI_Profile_wait_start(cur);
155 #endif
156     /*tMPI_Barrier_wait( &(comm->barrier));*/
157 #if defined(TMPI_PROFILE)
158     /*tMPI_Profile_wait_stop(cur, TMPIWAIT_Reduce);*/
159     tMPI_Profile_count_stop(cur, TMPIFN_Scan);
160 #endif
161     return TMPI_SUCCESS;
162 }