random123

Counter-based Random Number Generators
git clone git://git.meso-star.com/random123.git
Log | Files | Refs | README | LICENSE

time_cuda.cu (6466B)


      1 /*
      2 Copyright 2010-2011, D. E. Shaw Research.
      3 All rights reserved.
      4 
      5 Redistribution and use in source and binary forms, with or without
      6 modification, are permitted provided that the following conditions are
      7 met:
      8 
      9 * Redistributions of source code must retain the above copyright
     10   notice, this list of conditions, and the following disclaimer.
     11 
     12 * 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 
     16 * Neither the name of D. E. Shaw Research nor the names of its
     17   contributors may be used to endorse or promote products derived from
     18   this software without specific prior written permission.
     19 
     20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 */
     32 /*
     33  * CUDA test and timing harness for Random123 RNGs.  Uses macros
     34  * and util_expandtpl.h to "templatize" over all the different
     35  * permutations of RNGs and NxW and R.
     36  */
     37 
     38 #include "util_cuda.h"
     39 
     40 #include "Random123/philox.h"
     41 #include "Random123/threefry.h"
     42 
     43 #include "time_misc.h"
     44 #include "util_print.h"
     45 
     46 #define KERNEL __global__
     47 #define get_global_id(i) (blockDim.x * blockIdx.x + threadIdx.x)
     48 #include "time_random123.h"
     49 
     50 #define TEST_TPL(NAME, N, W, R) \
     51 void NAME##N##x##W##_##R(NAME##N##x##W##_ctr_t ctr, NAME##N##x##W##_ukey_t ukey, NAME##N##x##W##_ctr_t kactr, unsigned count, CUDAInfo *tp) \
     52 { \
     53     const char *kernelname = PREFIX #NAME #N "x" #W "_" #R; \
     54     NAME##N##x##W##_ctr_t *hC, *dC; \
     55     int n, niterations = numtrials; /* we make niterations + 2 (warmup, overhead) calls to the kernel */ \
     56     double cur_time; \
     57     size_t i; \
     58     const size_t nworkitems = tp->blocks_per_grid * tp->threads_per_block; \
     59     const size_t szC = nworkitems*sizeof(hC[0]); \
     60     \
     61     /* allocate vector of counters in device memory, initialize to zero */ \
     62     CHECKCALL(cudaMalloc(&dC, szC)); \
     63     CHECKCALL(cudaMemset((void *)dC, 0, szC)); \
     64     /* allocate and initialize vector of counters in host memory */ \
     65     CHECKNOTZERO(hC = (NAME##N##x##W##_ctr_t *)malloc(szC)); \
     66     for (i = 0; i < nworkitems; i++) { \
     67 	size_t xi; \
     68 	for (xi = 0; xi < N; xi++) { \
     69 	    hC[i].v[xi] = 0; \
     70 	} \
     71     } \
     72     unsigned kcount = 0; \
     73     double basetime = 0., dt = 0., mindt = 0.; \
     74     for (n = -2; n < niterations; n++) { \
     75 	if (n == -2) { \
     76 	    if (count == 0) { \
     77 		/* try to set a good guess for count */ \
     78 		count = (unsigned)(tp->cycles ? tp->cycles * 1e-8 : 10000); \
     79 		dprintf(("starting with count = %u\n", count)); \
     80 	    } \
     81 	    kcount = count; \
     82 	} else if (n == -1) { \
     83 	    /* use first iteration time to calibrate count to get approximately sec_per_trial */ \
     84 	    if (count > 1) { \
     85 		count = (unsigned)(count * sec_per_trial / dt); \
     86 		dprintf(("scaled count = %u\n", count)); \
     87 	    } \
     88 	    /* second iteration is to calculate overhead after warmup */ \
     89 	    kcount = 1; \
     90 	} else if (n == 0) { \
     91 	    int xj; \
     92 	    /* Check that we got the expected value */ \
     93 	    for (xj = 0; xj < N; xj++) { \
     94 		if (kactr.v[xj] != hC[0].v[xj]) { \
     95 		    printf("%s mismatch: xj = %d, expected\n", kernelname, xj); \
     96 		    printline_##NAME##N##x##W##_##R(ukey, ctr, &kactr, 1); \
     97 		    printf("    but got\n"); \
     98 		    printline_##NAME##N##x##W##_##R(ukey, ctr, hC, 1); \
     99                     if(!debug) exit(1); \
    100                     else break; \
    101 		} else { \
    102 		    dprintf(("%s matched word %d\n", kernelname, xj)); \
    103 		} \
    104 	    } \
    105 	    basetime = dt; \
    106 	    if (debug||verbose) { \
    107 		dprintf(("%s %.3f secs for %lu workitems test on device %d (%s)\n", \
    108 		       kernelname, basetime, (unsigned long) nworkitems, \
    109 		       tp->devnum, tp->dev.name)); \
    110 		printline_##NAME##N##x##W##_##R(ukey, ctr, hC, (verbose < 2) ? 1 : nworkitems); \
    111 	    } \
    112 	    kcount = count + 1; \
    113 	} \
    114 	dprintf(("launch %s\n", kernelname)); \
    115 	(void)timer(&cur_time); \
    116 	test_##NAME##N##x##W##_##R<<<tp->blocks_per_grid, tp->threads_per_block>>>(kcount, ctr, ukey, dC); \
    117 	dprintf(("synchronize\n")); \
    118 	CHECKCALL(cudaDeviceSynchronize()); \
    119 	dprintf(("copy results back from device to host\n")); \
    120 	CHECKCALL(cudaMemcpy(hC, dC, szC, cudaMemcpyDeviceToHost)); \
    121 	dt = timer(&cur_time); \
    122 	dprintf(("iteration %d took %.3f secs\n", n, dt)); \
    123 	ALLZEROS(hC, nworkitems, N); \
    124 	if (n == 0 || dt < mindt) mindt = dt; \
    125     } \
    126     if (count > 1) { \
    127 	double tpB = (mindt - basetime) / ( (kcount - 1.) * nworkitems * (N * W / 8.) ); \
    128 	printf("%-17s %#5.3g cpB, %#5.3g GB/s on dev %d %u B granularity (best %u in %.3f s - %.6f s)\n", \
    129 	       kernelname + sizeof(PREFIX) - 1, \
    130 	       tpB * tp->cycles , 1e-9/tpB, \
    131 	       tp->devnum, (unsigned)(N*W/8), kcount, mindt, basetime ); \
    132 	fflush(stdout); \
    133     } \
    134     /* free host and device memory */ \
    135     free(hC); \
    136     CHECKCALL(cudaFree(dC)); \
    137 }
    138 
    139 #include "util_expandtpl.h"
    140 
    141 int main(int argc, char **argv)
    142 {
    143     char *cp;
    144     unsigned count = 0;
    145     CUDAInfo *infop;
    146     int keyctroffset = 0;
    147     
    148     progname = argv[0];
    149     if (argc > 3|| (argv[1] && argv[1][0] == '-')) {
    150 	fprintf(stderr, "Usage: %s [COUNT [DEVICESTRING]]\n", progname);
    151 	exit(1);
    152     }
    153     if (argc  > 1)
    154 	count = atoi(argv[1]);
    155     if ((cp = getenv("TIME_CUDA_VERBOSE")) != NULL) {
    156 	verbose = atoi(cp);
    157     }
    158     if ((cp = getenv("TIME_CUDA_DEBUG")) != NULL) {
    159 	debug = atoi(cp);
    160     }
    161     if ((cp = getenv("TIME_CUDA_OFFSET")) != NULL) {
    162 	keyctroffset = atoi(cp);
    163     }
    164     if ((cp = getenv("TIME_CUDA_NUMTRIALS")) != NULL) {
    165         numtrials = atoi(cp);
    166     }
    167     if ((cp = getenv("TIME_CUDA_SEC_PER_TRIAL")) != NULL) {
    168         sec_per_trial = atof(cp);
    169     }
    170     infop = cuda_init(argc > 2 ? argv[2] : NULL);
    171     /* define macro to initialize and call the kernels */
    172 #   include "time_initkeyctr.h"
    173     cuda_done(infop);
    174     return 0;
    175 }