📄 dtpack.c
字号:
/* * This code may be used to test the performance of some of the * noncontiguous datatype operations, including vector and indexed * pack and unpack operations. To simplify the use of this code for * tuning an MPI implementation, it uses no communication, just the * MPI_Pack and MPI_Unpack routines. In addition, the individual tests are * in separate routines, making it easier to compare the compiler-generated * code for the user (manual) pack/unpack with the code used by * the MPI implementation. Further, to be fair to the MPI implementation, * the routines are passed the source and destination buffers; this ensures * that the compiler can't optimize for statically allocated buffers. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "mpi.h"/* Needed for restrict and const definitions */#include "mpitestconf.h"static int verbose = 0;#define N_REPS 1000#define THRESHOLD 0.10#define VARIANCE_THRESHOLD ((THRESHOLD * THRESHOLD) / 2)#define NTRIALS 10double mean(double *list, int count){ double retval; int i; retval = 0; for (i = 0; i < count; i++) retval += list[i]; retval /= count; return retval;}double noise(double *list, int count){ double *margin, retval; int i; if (!(margin = malloc(count * sizeof(double)))) { printf("Unable to allocate memory\n"); return -1; } for (i = 0; i < count; i++) margin[i] = list[i] / mean(list, count); retval = 0; for (i = 0; i < count; i++) { retval += ((margin[i] - 1) * (margin[i] - 1)); } retval /= count; if (retval < 0) retval = -retval; return retval;}/* Here are the tests *//* Test packing a vector of individual doubles */int TestVecPackDouble( int n, int stride, double *avgTimeUser, double *avgTimeMPI, double * restrict dest, const double * restrict src ){ double *restrict d_dest; const double *restrict d_src; register int i, j; int rep, position; double t1, t2, t[NTRIALS]; MPI_Datatype vectype; /* User code */ if (verbose) printf("TestVecPackDouble (USER): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { i = n; d_dest = dest; d_src = src; while (i--) { *d_dest++ = *d_src; d_src += stride; } } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeUser = mean(t, NTRIALS) / N_REPS; /* MPI Vector code */ MPI_Type_vector( n, 1, stride, MPI_DOUBLE, &vectype ); MPI_Type_commit( &vectype ); if (verbose) printf("TestVecPackDouble (MPI): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { position = 0; MPI_Pack( (void *)src, 1, vectype, dest, n*sizeof(double), &position, MPI_COMM_SELF ); } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeMPI = mean(t, NTRIALS) / N_REPS; MPI_Type_free( &vectype ); return 0;}/* Test unpacking a vector of individual doubles */int TestVecUnPackDouble( int n, int stride, double *avgTimeUser, double *avgTimeMPI, double * restrict dest, const double * restrict src ){ double *restrict d_dest; const double *restrict d_src; register int i, j; int rep, position; double t1, t2, t[NTRIALS]; MPI_Datatype vectype; /* User code */ if (verbose) printf("TestVecUnPackDouble (USER): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { i = n; d_dest = dest; d_src = src; while (i--) { *d_dest = *d_src++; d_dest += stride; } } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeUser = mean(t, NTRIALS) / N_REPS; /* MPI Vector code */ MPI_Type_vector( n, 1, stride, MPI_DOUBLE, &vectype ); MPI_Type_commit( &vectype ); if (verbose) printf("TestVecUnPackDouble (MPI): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { position = 0; MPI_Unpack( (void *)src, n*sizeof(double), &position, dest, 1, vectype, MPI_COMM_SELF ); } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeMPI = mean(t, NTRIALS) / N_REPS; MPI_Type_free( &vectype ); return 0;}/* Test packing a vector of 2-individual doubles */int TestVecPack2Double( int n, int stride, double *avgTimeUser, double *avgTimeMPI, double * restrict dest, const double * restrict src ){ double *restrict d_dest; const double *restrict d_src; register int i, j; int rep, position; double t1, t2, t[NTRIALS]; MPI_Datatype vectype; /* User code */ if (verbose) printf("TestVecPack2Double (USER): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { i = n; d_dest = dest; d_src = src; while (i--) { *d_dest++ = d_src[0]; *d_dest++ = d_src[1]; d_src += stride; } } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeUser = mean(t, NTRIALS) / N_REPS; /* MPI Vector code */ MPI_Type_vector( n, 2, stride, MPI_DOUBLE, &vectype ); MPI_Type_commit( &vectype ); if (verbose) printf("TestVecPack2Double (MPI): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { position = 0; MPI_Pack( (void *)src, 1, vectype, dest, 2*n*sizeof(double), &position, MPI_COMM_SELF ); } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeMPI = mean(t, NTRIALS) / N_REPS; MPI_Type_free( &vectype ); return 0;}/* This creates an indexed type that is like a vector (for simplicity of construction). There is a possibility that the MPI implementation will recognize and simplify this (e.g., in MPI_Type_commit); if so, let us know and we'll add a version that is not as regular */int TestIndexPackDouble( int n, int stride, double *avgTimeUser, double *avgTimeMPI, double * restrict dest, const double * restrict src ){ double *restrict d_dest; const double *restrict d_src; register int i, j; int rep, position; int *restrict displs = 0; double t1, t2, t[NTRIALS]; MPI_Datatype indextype; displs = (int *)malloc( n * sizeof(int) ); for (i=0; i<n; i++) displs[i] = i * stride; /* User code */ if (verbose) printf("TestIndexPackDouble (USER): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { i = n; d_dest = dest; d_src = src; for (i=0; i<n; i++) { *d_dest++ = d_src[displs[i]]; } } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeUser = mean(t, NTRIALS) / N_REPS; /* MPI Index code */ MPI_Type_create_indexed_block( n, 1, displs, MPI_DOUBLE, &indextype ); MPI_Type_commit( &indextype ); free( displs ); if (verbose) printf("TestIndexPackDouble (MPI): "); for (j = 0; j < NTRIALS; j++) { t1 = MPI_Wtime(); for (rep=0; rep<N_REPS; rep++) { position = 0; MPI_Pack( (void *)src, 1, indextype, dest, n*sizeof(double), &position, MPI_COMM_SELF ); } t2 = MPI_Wtime() - t1; t[j] = t2; if (verbose) printf("%.3f ", t[j]); } if (verbose) printf("[%.3f]\n", noise(t, NTRIALS)); /* If there is too much noise, discard the test */ if (noise(t, NTRIALS) > VARIANCE_THRESHOLD) { *avgTimeUser = 0; *avgTimeMPI = 0; if (verbose) printf("Too much noise; discarding measurement\n"); return 0; } *avgTimeMPI = mean(t, NTRIALS) / N_REPS; MPI_Type_free( &indextype ); return 0;}int Report( const char *name, const char *packname, double avgTimeMPI, double avgTimeUser ){ double diffTime, maxTime; int errs=0; /* Move this into a common routine */ diffTime = avgTimeMPI - avgTimeUser; if (diffTime < 0) diffTime = - diffTime; if (avgTimeMPI > avgTimeUser) maxTime = avgTimeMPI; else maxTime = avgTimeUser; if (verbose) { printf( "%-30s:\t%g\t%g\t(%g%%)\n", name, avgTimeMPI, avgTimeUser, 100 * (diffTime / maxTime) ); fflush(stdout); } if (avgTimeMPI > avgTimeUser && (diffTime > THRESHOLD * maxTime)) { errs++; printf( "%s:\tMPI %s code is too slow: MPI %g\t User %g\n", name, packname, avgTimeMPI, avgTimeUser ); } return errs;}/* Finally, here's the main program */int main( int argc, char *argv[] ){ int n, stride, err, errs = 0; void *dest, *src; double avgTimeUser, avgTimeMPI; MPI_Init( &argc, &argv ); if (getenv("MPITEST_VERBOSE")) verbose = 1; n = 30000; stride = 4; dest = (void *)malloc( n * sizeof(double) ); src = (void *)malloc( n * ((1+stride)*sizeof(double)) ); /* Touch the source and destination arrays */ memset( src, 0, n * (1+stride)*sizeof(double) ); memset( dest, 0, n * sizeof(double) ); err = TestVecPackDouble( n, stride, &avgTimeUser, &avgTimeMPI, dest, src ); errs += Report( "VecPackDouble", "Pack", avgTimeMPI, avgTimeUser ); err = TestVecUnPackDouble( n, stride, &avgTimeUser, &avgTimeMPI, src, dest ); errs += Report( "VecUnPackDouble", "Unpack", avgTimeMPI, avgTimeUser ); err = TestIndexPackDouble( n, stride, &avgTimeUser, &avgTimeMPI, dest, src ); errs += Report( "VecIndexDouble", "Pack", avgTimeMPI, avgTimeUser ); free(dest); free(src); dest = (void *)malloc( 2*n * sizeof(double) ); src = (void *)malloc( (1 + n) * ((1+stride)*sizeof(double)) ); memset( dest, 0, 2*n * sizeof(double) ); memset( src, 0, (1+n) * (1+stride)*sizeof(double) ); err = TestVecPack2Double( n, stride, &avgTimeUser, &avgTimeMPI, dest, src ); errs += Report( "VecPack2Double", "Pack", avgTimeMPI, avgTimeUser ); free(dest); free(src); if (errs == 0) { printf( " No Errors\n" ); } else { printf( " Found %d performance problems\n", errs ); } fflush(stdout); MPI_Finalize(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -