QDP++
qdp_parscalar_global_sum.cc
Go to the documentation of this file.
1#include "qdp.h"
2#include <string.h>
3
4namespace QDPGlobalSums {
5
6 // Given an array x of length elements
7 // This routine will compute:
8 // y[i] = sum x[i] for each individual i
9 // ie the return value will also be an array of length element.
10 //
11 // Implementation note: I create a table all_data[nproc][length]
12 // I do all my message passing first, then I sum.
13 //
14 // Consider when no_of_procs in dim=3, length=1
15 //
16 // after the two communications the procs will have teh following all
17 // data
18 //
19 // proc0 proc1 proc2
20 // proc0_data proc1_data proc2_data
21 // proc2_data proc0_data proc1_data
22 // proc1_data proc2_data proc0_data
23 //
24 // where proci_data is the data originating from processor i.
25 // (receives are always done from the minus direction, sends to plus)
26 //
27 // I then sum on each processor, starting the sum from element i,
28 // where i is the index of the processor
29 // so on proc0 I start the sum from all_data element 0
30 // on proc1 from all_data element 1 (proc0_data)
31 // on proc2 from all_data element 2 (proc0_data)
32 // as the summation index becomes too big, I wrap it around.
33 //
34 // This way, all the processors carry out their sums in exactly the
35 // same order, which should yield binary exactness
36
37 template<typename T>
38 QMP_status_t sumTDirection(T* x, int length, int dim)
39 {
40 int blocksize = sizeof(T)*length;
41 if (blocksize % 8 != 0) {
42 blocksize += (8 - blocksize%8);
43 }
44 // Allocate space for message to send
45 // Communicate all the data at once (ie sizeof(T)*length bytes)
46 QMP_mem_t* send_mem = QMP_allocate_aligned_memory(blocksize,
47 8,
48 (QMP_MEM_COMMS|QMP_MEM_FAST));
49 if( send_mem == 0x0 ) {
50 return QMP_NOMEM_ERR;
51 }
52
53 QMP_mem_t* recv_mem = QMP_allocate_aligned_memory(blocksize,
54 8,
55 (QMP_MEM_COMMS|QMP_MEM_FAST));
56
57 if( recv_mem == 0x0 ) {
58 return QMP_NOMEM_ERR;
59 }
60
61 // In addition I need to send to PLUS dir and receive from
62 // Minus dir
63 void *sendmem_pointer = QMP_get_memory_pointer(send_mem);
64 void *recvmem_pointer = QMP_get_memory_pointer(recv_mem);
65
66 // (I leave the trailers full of junk)
67 // memset(sendmem_pointer, 0x0, blocksize);
68 // memset(recvmem_pointer, 0x0, blocksize);
69
70 QMP_msgmem_t send_msgmem = QMP_declare_msgmem( sendmem_pointer,
71 blocksize) ;
72
73 QMP_msgmem_t recv_msgmem = QMP_declare_msgmem( recvmem_pointer,
74 blocksize) ;
75 // Send to + dir
76 QMP_msghandle_t send_handle = QMP_declare_send_relative(send_msgmem, dim, +1, 0);
77
78 // Recv from -dir
79 QMP_msghandle_t recv_handle = QMP_declare_receive_relative(recv_msgmem, dim, -1, 0);
80
81 // Get the number of CPU-s in this direction
82 // Do I need to free these?
83 const int* logical_dimensions = QMP_get_logical_dimensions();
84 const int* logical_coordinates = QMP_get_logical_coordinates();
85
86 int procs_in_dimension = logical_dimensions[dim];
87
88 multi2d<T> all_data(length, procs_in_dimension);
89
90
91 // Copy my data to send buffer to stat with
92 memcpy(sendmem_pointer, x, sizeof(T)*length);
93
94 // Copy my data to all_data
95 for(int j=0; j < length; j++) {
96 all_data(j,0) = x[j];
97 }
98
99 for(int i=0; i < procs_in_dimension-1; i++) {
100 QMP_status_t status;
101
102 // Start receiving from -dir
103 status = QMP_start(recv_handle);
104 if( status != QMP_SUCCESS ) {
105 return status;
106 }
107
108 // Start sending to +dir
109 status = QMP_start(send_handle);
110 if( status != QMP_SUCCESS ) {
111 return status;
112 }
113
114 // Finish the send
115 status = QMP_wait(send_handle);
116 if( status != QMP_SUCCESS ) {
117 return status;
118 }
119
120 status = QMP_wait(recv_handle);
121 if( status != QMP_SUCCESS ) {
122 return status;
123 }
124
125 // Copy what I have received so I can send it on
126 memcpy(sendmem_pointer, recvmem_pointer, sizeof(T)*length);
127
128 for(int j=0; j < length; j++) {
129 all_data(j,i+1) = ((T *)recvmem_pointer)[j];
130 }
131 }
132
133
134 for(int j=0; j < length; j++) {
135 // The index of the data received from 0 in this dimension
136 int my_index = logical_coordinates[dim];
137 x[j] = all_data(j, my_index);
138 for(int i=0; i < procs_in_dimension-1; i++) {
139 // Increment pointer with wraparound
140 my_index = (my_index + 1) % procs_in_dimension;
141 x[j] += all_data(j, my_index);
142 }
143 }
144
145 // Free up the comms
146 QMP_free_msghandle(recv_handle);
147 QMP_free_msghandle(send_handle);
148 QMP_free_msgmem(recv_msgmem);
149 QMP_free_msgmem(send_msgmem);
150
151 QMP_free_memory(recv_mem);
152 QMP_free_memory(send_mem);
153 // free(logical_dimensions);
154 // free(logical_coordinates);
155 return QMP_SUCCESS;
156 }
157
158 // Global sum: call sumTDirection in all available directions
159 template<typename T>
160 QMP_status_t sumT(T* x, int length)
161 {
162 // Get the number of dimensions
163 int ndim = QMP_get_logical_number_of_dimensions();
164
165 for(int dim=0; dim < ndim; dim++) {
166 QMP_status_t status = sumTDirection<T>(x, length, dim);
167 if (status != QMP_SUCCESS ) {
168 return status;
169 }
170 }
171
172 return QMP_SUCCESS;
173 }
174
175 QMP_status_t QDP_sum_int(int *i) {
176#ifndef USE_QDP_QMP_GLOBAL_SUM
177 return QMP_sum_int(i);
178#else
179 return sumT<int>(i, 1);
180#endif
181 }
182
183 QMP_status_t QDP_sum_float_array(float *x, int length) {
184#ifndef USE_QDP_QMP_GLOBAL_SUM
185 return QMP_sum_float_array(x,length);
186#else
187 return sumT<float>(x,length);
188#endif
189 }
190
191 QMP_status_t QDP_sum_double_array(double *x, int length) {
192#ifndef USE_QDP_QMP_GLOBAL_SUM
193 return QMP_sum_double_array(x,length);
194#else
195 return sumT<double>(x,length);
196#endif
197 }
198
199}; // End namespace
QMP_status_t QDP_sum_float_array(float *x, int length)
QMP_status_t QDP_sum_double_array(double *x, int length)
QMP_status_t sumTDirection(T *x, int length, int dim)
QMP_status_t sumT(T *x, int length)
QMP_status_t QDP_sum_int(int *i)
Primary include file for QDP.