Skip to content

Commit 20be3fc

Browse files
committed
A better test for MPI_OP performance.
The test now has the ability to add a shift to all or to any of the input and output buffers to assess the impact of unaligned operations. Signed-off-by: George Bosilca <bosilca@icl.utk.edu>
1 parent fcf2766 commit 20be3fc

File tree

1 file changed

+104
-57
lines changed

1 file changed

+104
-57
lines changed

test/datatype/reduce_local.c

Lines changed: 104 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ static int total_errors = 0;
5959
_a < _b ? _a : _b; })
6060

6161
static void print_status(char* op, char* type, int type_size,
62-
int count, double duration,
62+
int count, int max_shift, double *duration, int repeats,
6363
int correct )
6464
{
6565
if(correct) {
@@ -68,7 +68,15 @@ static void print_status(char* op, char* type, int type_size,
6868
printf("%-10s %s [\033[1;31mfail\033[0m]", op, type);
6969
total_errors++;
7070
}
71-
printf(" count %-10d time %.6f seconds\n", count, duration);
71+
if( 1 == max_shift ) {
72+
printf(" count %-10d time (seconds) %.8f seconds\n", count, duration[0] / repeats);
73+
} else {
74+
printf(" count %-10d time (seconds / shifts) ", count);
75+
for( int i = 0; i < max_shift; i++ ) {
76+
printf("%.8f ", duration[i] / repeats );
77+
}
78+
printf("\n");
79+
}
7280
}
7381

7482
static int do_ops_built = 0;
@@ -115,19 +123,23 @@ do { \
115123
const TYPE *_p1 = ((TYPE*)(INBUF)), *_p3 = ((TYPE*)(CHECK_BUF)); \
116124
TYPE *_p2 = ((TYPE*)(INOUT_BUF)); \
117125
skip_op_type = 0; \
118-
for(int _k = 0; _k < min((COUNT), 4); +_k++ ) { \
119-
memcpy(_p2, _p3, sizeof(TYPE) * (COUNT)); \
120-
tstart = MPI_Wtime(); \
121-
MPI_Reduce_local(_p1+_k, _p2+_k, (COUNT)-_k, (MPITYPE), (MPIOP)); \
122-
tend = MPI_Wtime(); \
123-
if( check ) { \
124-
for( i = 0; i < (COUNT)-_k; i++ ) { \
125-
if(((_p2+_k)[i]) == (((_p1+_k)[i]) OPNAME ((_p3+_k)[i]))) \
126-
continue; \
127-
printf("First error at alignment %d position %d (%" TYPE_PREFIX " %s %" TYPE_PREFIX " != %" TYPE_PREFIX ")\n", \
128-
_k, i, (_p1+_k)[i], (#OPNAME), (_p3+_k)[i], (_p2+_k)[i]); \
129-
correctness = 0; \
130-
break; \
126+
for(int _k = 0; _k < min((COUNT), max_shift); +_k++ ) { \
127+
duration[_k] = 0.0; \
128+
for(int _r = repeats; _r > 0; _r--) { \
129+
memcpy(_p2, _p3, sizeof(TYPE) * (COUNT)); \
130+
tstart = MPI_Wtime(); \
131+
MPI_Reduce_local(_p1+_k, _p2+_k, (COUNT)-_k, (MPITYPE), (MPIOP)); \
132+
tend = MPI_Wtime(); \
133+
duration[_k] += (tend - tstart); \
134+
if( check ) { \
135+
for( i = 0; i < (COUNT)-_k; i++ ) { \
136+
if(((_p2+_k)[i]) == (((_p1+_k)[i]) OPNAME ((_p3+_k)[i]))) \
137+
continue; \
138+
printf("First error at alignment %d position %d (%" TYPE_PREFIX " %s %" TYPE_PREFIX " != %" TYPE_PREFIX ")\n", \
139+
_k, i, (_p1+_k)[i], (#OPNAME), (_p3+_k)[i], (_p2+_k)[i]); \
140+
correctness = 0; \
141+
break; \
142+
} \
131143
} \
132144
} \
133145
} \
@@ -139,20 +151,24 @@ do { \
139151
const TYPE *_p1 = ((TYPE*)(INBUF)), *_p3 = ((TYPE*)(CHECK_BUF)); \
140152
TYPE *_p2 = ((TYPE*)(INOUT_BUF)); \
141153
skip_op_type = 0; \
142-
for(int _k = 0; _k < min((COUNT), 4); +_k++ ) { \
143-
memcpy(_p2, _p3, sizeof(TYPE) * (COUNT)); \
144-
tstart = MPI_Wtime(); \
145-
MPI_Reduce_local(_p1+_k, _p2+_k, (COUNT), (MPITYPE), (MPIOP)); \
146-
tend = MPI_Wtime(); \
147-
if( check ) { \
148-
for( i = 0; i < (COUNT); i++ ) { \
149-
TYPE _v1 = *(_p1+_k), _v2 = *(_p2+_k), _v3 = *(_p3+_k); \
150-
if(_v2 == OPNAME(_v1, _v3)) \
151-
continue; \
152-
printf("First error at alignment %d position %d (%" TYPE_PREFIX " != %s(%" TYPE_PREFIX ", %" TYPE_PREFIX ")\n", \
153-
_k, i, _v1, (#OPNAME), _v3, _v2); \
154-
correctness = 0; \
155-
break; \
154+
for(int _k = 0; _k < min((COUNT), max_shift); +_k++ ) { \
155+
duration[_k] = 0.0; \
156+
for(int _r = repeats; _r > 0; _r--) { \
157+
memcpy(_p2, _p3, sizeof(TYPE) * (COUNT)); \
158+
tstart = MPI_Wtime(); \
159+
MPI_Reduce_local(_p1+_k, _p2+_k, (COUNT), (MPITYPE), (MPIOP)); \
160+
tend = MPI_Wtime(); \
161+
duration[_k] += (tend - tstart); \
162+
if( check ) { \
163+
for( i = 0; i < (COUNT); i++ ) { \
164+
TYPE _v1 = *(_p1+_k), _v2 = *(_p2+_k), _v3 = *(_p3+_k); \
165+
if(_v2 == OPNAME(_v1, _v3)) \
166+
continue; \
167+
printf("First error at alignment %d position %d (%" TYPE_PREFIX " != %s(%" TYPE_PREFIX ", %" TYPE_PREFIX ")\n", \
168+
_k, i, _v1, (#OPNAME), _v3, _v2); \
169+
correctness = 0; \
170+
break; \
171+
} \
156172
} \
157173
} \
158174
} \
@@ -163,24 +179,36 @@ int main(int argc, char **argv)
163179
{
164180
static void *in_buf = NULL, *inout_buf = NULL, *inout_check_buf = NULL;
165181
int count, type_size = 8, rank, size, provided, correctness = 1;
166-
int repeats = 1, i, c;
167-
double tstart, tend;
182+
int repeats = 1, i, c, op1_alignment = 0, res_alignment = 0;
183+
int max_shift = 4;
184+
double *duration, tstart, tend;
168185
bool check = true;
169186
char type[5] = "uifd", *op = "sum", *mpi_type;
170187
int lower = 1, upper = 1000000, skip_op_type;
171188
MPI_Op mpi_op;
172189

173-
while( -1 != (c = getopt(argc, argv, "l:u:t:o:s:n:vfh")) ) {
190+
while( -1 != (c = getopt(argc, argv, "l:u:r:t:o:i:s:n:1:2:vfh")) ) {
174191
switch(c) {
175192
case 'l':
176193
lower = atoi(optarg);
177194
if( lower <= 0 ) {
178-
fprintf(stderr, "The number of elements must be positive\n");
195+
fprintf(stderr, "The lower number of elements must be positive\n");
179196
exit(-1);
180197
}
181198
break;
182199
case 'u':
183200
upper = atoi(optarg);
201+
if( lower <= 0 ) {
202+
fprintf(stderr, "The upper number of elements must be positive\n");
203+
exit(-1);
204+
}
205+
break;
206+
case 'i':
207+
max_shift = atoi(optarg);
208+
if( max_shift <= 0 ) {
209+
fprintf(stderr, "The max shift must be positive\n");
210+
exit(-1);
211+
}
184212
break;
185213
case 'f':
186214
check = false;
@@ -216,14 +244,32 @@ int main(int argc, char **argv)
216244
exit(-1);
217245
}
218246
break;
247+
case '1':
248+
op1_alignment = atoi(optarg);
249+
if( op1_alignment < 0 ) {
250+
fprintf(stderr, "alignment for the first operand must be positive\n");
251+
exit(-1);
252+
}
253+
break;
254+
case '2':
255+
res_alignment = atoi(optarg);
256+
if( res_alignment < 0 ) {
257+
fprintf(stderr, "alignment for the result must be positive\n");
258+
exit(-1);
259+
}
260+
break;
219261
case 'h':
220262
fprintf(stdout, "%s options are:\n"
221263
" -l <number> : lower number of elements\n"
222264
" -u <number> : upper number of elements\n"
223265
" -s <type_size> : 8, 16, 32 or 64 bits elements\n"
224266
" -t [i,u,f,d] : type of the elements to apply the operations on\n"
267+
" -r <number> : number of repetitions for each test\n"
225268
" -o <op> : comma separated list of operations to execute among\n"
226269
" sum, min, max, prod, bor, bxor, band\n"
270+
" -i <number> : shift on all buffers to check alignment\n"
271+
" -1 <number> : (mis)alignment in elements for the first op\n"
272+
" -2 <number> : (mis)alignment in elements for the result\n"
227273
" -v: increase the verbosity level\n"
228274
" -h: this help message\n", argv[0]);
229275
exit(0);
@@ -233,9 +279,10 @@ int main(int argc, char **argv)
233279
if( !do_ops_built ) { /* not yet done, take the default */
234280
build_do_ops( "all", do_ops);
235281
}
236-
in_buf = malloc(upper * sizeof(double));
237-
inout_buf = malloc(upper * sizeof(double));
238-
inout_check_buf = malloc(upper * sizeof(double));
282+
posix_memalign( &in_buf, 64, (upper + op1_alignment) * sizeof(double));
283+
posix_memalign( &inout_buf, 64, (upper + res_alignment) * sizeof(double));
284+
posix_memalign( &inout_check_buf, 64, upper * sizeof(double));
285+
duration = (double*)malloc(max_shift * sizeof(double));
239286

240287
ompi_mpi_init(argc, argv, MPI_THREAD_SERIALIZED, &provided, false);
241288

@@ -253,8 +300,8 @@ int main(int argc, char **argv)
253300
correctness = 1;
254301
if('i' == type[type_idx]) {
255302
if( 8 == type_size ) {
256-
int8_t *in_int8 = (int8_t*)in_buf,
257-
*inout_int8 = (int8_t*)inout_buf,
303+
int8_t *in_int8 = (int8_t*)((char*)in_buf + op1_alignment * sizeof(int8_t)),
304+
*inout_int8 = (int8_t*)((char*)inout_buf + res_alignment * sizeof(int8_t)),
258305
*inout_int8_for_check = (int8_t*)inout_check_buf;
259306
for( i = 0; i < count; i++ ) {
260307
in_int8[i] = 5;
@@ -299,8 +346,8 @@ int main(int argc, char **argv)
299346
}
300347
}
301348
if( 16 == type_size ) {
302-
int16_t *in_int16 = (int16_t*)in_buf,
303-
*inout_int16 = (int16_t*)inout_buf,
349+
int16_t *in_int16 = (int16_t*)((char*)in_buf + op1_alignment * sizeof(int16_t)),
350+
*inout_int16 = (int16_t*)((char*)inout_buf + res_alignment * sizeof(int16_t)),
304351
*inout_int16_for_check = (int16_t*)inout_check_buf;
305352
for( i = 0; i < count; i++ ) {
306353
in_int16[i] = 5;
@@ -345,8 +392,8 @@ int main(int argc, char **argv)
345392
}
346393
}
347394
if( 32 == type_size ) {
348-
int32_t *in_int32 = (int32_t*)in_buf,
349-
*inout_int32 = (int32_t*)inout_buf,
395+
int32_t *in_int32 = (int32_t*)((char*)in_buf + op1_alignment * sizeof(int32_t)),
396+
*inout_int32 = (int32_t*)((char*)inout_buf + res_alignment * sizeof(int32_t)),
350397
*inout_int32_for_check = (int32_t*)inout_check_buf;
351398
for( i = 0; i < count; i++ ) {
352399
in_int32[i] = 5;
@@ -391,8 +438,8 @@ int main(int argc, char **argv)
391438
}
392439
}
393440
if( 64 == type_size ) {
394-
int64_t *in_int64 = (int64_t*)in_buf,
395-
*inout_int64 = (int64_t*)inout_buf,
441+
int64_t *in_int64 = (int64_t*)((char*)in_buf + op1_alignment * sizeof(int64_t)),
442+
*inout_int64 = (int64_t*)((char*)inout_buf + res_alignment * sizeof(int64_t)),
396443
*inout_int64_for_check = (int64_t*)inout_check_buf;
397444
for( i = 0; i < count; i++ ) {
398445
in_int64[i] = 5;
@@ -440,8 +487,8 @@ int main(int argc, char **argv)
440487

441488
if( 'u' == type[type_idx] ) {
442489
if( 8 == type_size ) {
443-
uint8_t *in_uint8 = (uint8_t*)in_buf,
444-
*inout_uint8 = (uint8_t*)inout_buf,
490+
uint8_t *in_uint8 = (uint8_t*)((char*)in_buf + op1_alignment * sizeof(uint8_t)),
491+
*inout_uint8 = (uint8_t*)((char*)inout_buf + res_alignment * sizeof(uint8_t)),
445492
*inout_uint8_for_check = (uint8_t*)inout_check_buf;
446493
for( i = 0; i < count; i++ ) {
447494
in_uint8[i] = 5;
@@ -486,8 +533,8 @@ int main(int argc, char **argv)
486533
}
487534
}
488535
if( 16 == type_size ) {
489-
uint16_t *in_uint16 = (uint16_t*)in_buf,
490-
*inout_uint16 = (uint16_t*)inout_buf,
536+
uint16_t *in_uint16 = (uint16_t*)((char*)in_buf + op1_alignment * sizeof(uint16_t)),
537+
*inout_uint16 = (uint16_t*)((char*)inout_buf + res_alignment * sizeof(uint16_t)),
491538
*inout_uint16_for_check = (uint16_t*)inout_check_buf;
492539
for( i = 0; i < count; i++ ) {
493540
in_uint16[i] = 5;
@@ -532,8 +579,8 @@ int main(int argc, char **argv)
532579
}
533580
}
534581
if( 32 == type_size ) {
535-
uint32_t *in_uint32 = (uint32_t*)in_buf,
536-
*inout_uint32 = (uint32_t*)inout_buf,
582+
uint32_t *in_uint32 = (uint32_t*)((char*)in_buf + op1_alignment * sizeof(uint32_t)),
583+
*inout_uint32 = (uint32_t*)((char*)inout_buf + res_alignment * sizeof(uint32_t)),
537584
*inout_uint32_for_check = (uint32_t*)inout_check_buf;
538585
for( i = 0; i < count; i++ ) {
539586
in_uint32[i] = 5;
@@ -578,8 +625,8 @@ int main(int argc, char **argv)
578625
}
579626
}
580627
if( 64 == type_size ) {
581-
uint64_t *in_uint64 = (uint64_t*)in_buf,
582-
*inout_uint64 = (uint64_t*)inout_buf,
628+
uint64_t *in_uint64 = (uint64_t*)((char*)in_buf + op1_alignment * sizeof(uint64_t)),
629+
*inout_uint64 = (uint64_t*)((char*)inout_buf + res_alignment * sizeof(uint64_t)),
583630
*inout_uint64_for_check = (uint64_t*)inout_check_buf;
584631
for( i = 0; i < count; i++ ) {
585632
in_uint64[i] = 5;
@@ -626,8 +673,8 @@ int main(int argc, char **argv)
626673
}
627674

628675
if( 'f' == type[type_idx] ) {
629-
float *in_float = (float*)in_buf,
630-
*inout_float = (float*)inout_buf,
676+
float *in_float = (float*)((char*)in_buf + op1_alignment * sizeof(float)),
677+
*inout_float = (float*)((char*)inout_buf + res_alignment * sizeof(float)),
631678
*inout_float_for_check = (float*)inout_check_buf;
632679
for( i = 0; i < count; i++ ) {
633680
in_float[i] = 1000.0+1;
@@ -658,8 +705,8 @@ int main(int argc, char **argv)
658705
}
659706

660707
if( 'd' == type[type_idx] ) {
661-
double *in_double = (double*)in_buf,
662-
*inout_double = (double*)inout_buf,
708+
double *in_double = (double*)((char*)in_buf + op1_alignment * sizeof(double)),
709+
*inout_double = (double*)((char*)inout_buf + res_alignment * sizeof(double)),
663710
*inout_double_for_check = (double*)inout_check_buf;
664711
for( i = 0; i < count; i++ ) {
665712
in_double[i] = 10.0+1;
@@ -691,7 +738,7 @@ int main(int argc, char **argv)
691738
check_and_continue:
692739
if( !skip_op_type )
693740
print_status(array_of_ops[do_ops[op_idx]].mpi_op_name,
694-
mpi_type, type_size, count, tend-tstart, correctness);
741+
mpi_type, type_size, count, max_shift, duration, repeats, correctness);
695742
}
696743
if( !skip_op_type )
697744
printf("\n");

0 commit comments

Comments
 (0)