/* $Source: bitbucket.org:berkeleylab/gasnet.git/tests/testslice.c $ * Description: GASNet randomized get/put correctness validation test * Copyright 2007, Parry Husbands and Dan Bonachea * Terms of use are as specified in license.txt */ #include #include #include #include #include #include #include #include size_t arenasz = 0; int doforeign = 0; #ifndef TEST_SEGSZ #define TEST_SEGSZ_EXPR ((uintptr_t)arenasz*(doforeign?4:2)) #endif #include "test.h" static gex_Client_t myclient; static gex_EP_t myep; static gex_TM_t myteam; static gex_Segment_t mysegment; static gex_Rank_t peerproc; #define OUTPUT_SUCCESS 0 uint64_t failures = 0; void assert_eq(char *x, char *y, int len, int start, int i, int j, const char *msg) { int k; int error = 0; for(k=0;k < len;k++) { if(x[k] != y[k]) { error=1; break; } } if(error) { ERR("FAILURE %s outer iteration %d inner iteration %d starting point = %d length = %d",msg,i,j,start,len); failures++; } else { #if OUTPUT_SUCCESS MSG("SUCCESS %s outer iteration %d inner iteration %d starting point = %d length = %d",msg,i,j,start,len); #endif } } void do_put(void *dst, void *src, size_t len) { switch(TEST_RAND(0,6)) { case 0: gex_RMA_PutBlocking(myteam, peerproc, dst, src, len, 0); break; case 1: gex_Event_Wait(gex_RMA_PutNB(myteam, peerproc, dst, src, len, GEX_EVENT_NOW, 0)); break; case 2: gex_Event_Wait(gex_RMA_PutNB(myteam, peerproc, dst, src, len, GEX_EVENT_DEFER, 0)); break; case 3: { gex_Event_t lc_ev; gex_Event_Wait(gex_RMA_PutNB(myteam, peerproc, dst, src, len, &lc_ev, 0)); break; } case 4: gex_RMA_PutNBI(myteam, peerproc, dst, src, len, GEX_EVENT_NOW, 0); gex_NBI_Wait(GEX_EC_PUT, 0); break; case 5: gex_RMA_PutNBI(myteam, peerproc, dst, src, len, GEX_EVENT_DEFER, 0); gex_NBI_Wait(GEX_EC_PUT, 0); break; case 6: gex_RMA_PutNBI(myteam, peerproc, dst, src, len, GEX_EVENT_GROUP, 0); gex_NBI_Wait(GEX_EC_PUT|GEX_EC_LC, 0); break; } } void do_get(void *dst, void *src, size_t len) { switch(TEST_RAND(0,2)) { case 0: gex_RMA_GetBlocking(myteam, dst, peerproc, src, len, 0); break; case 1: gex_Event_Wait(gex_RMA_GetNB(myteam, dst, peerproc, src, len, 0)); break; case 2: gex_RMA_GetNBI(myteam, dst, peerproc, src, len, 0); gex_NBI_Wait(GEX_EC_GET, 0); break; } } int main(int argc, char **argv) { int outer_iterations = 0; int inner_iterations = 0; int seedoffset = 0; gex_Rank_t numprocs, myproc; int crossmachinemode = 0; int help = 0; /* call startup */ GASNET_Safe(gex_Client_Init(&myclient, &myep, &myteam, "testslice", &argc, &argv, 0)); /* get SPMD info */ myproc = gex_TM_QueryRank(myteam); numprocs = gex_TM_QuerySize(myteam); // Parse cmdline args int arg = 1; while (argc > arg) { if (!strcmp(argv[arg], "-c")) { crossmachinemode = 1; ++arg; } else if (!strcmp(argv[arg], "-f")) { doforeign = 1; ++arg; } else if (argv[arg][0] == '-') { help = 1; ++arg; } else break; } if (argc > arg) { arenasz = gasnett_parse_int(argv[arg], 1); ++arg; } if (!arenasz) arenasz = 1024*1024*16; if (argc > arg) { outer_iterations = atoi(argv[arg]); ++arg; } if (!outer_iterations) outer_iterations = 10; if (argc > arg) { inner_iterations = atoi(argv[arg]); ++arg; } if (!inner_iterations) inner_iterations = 10; if (argc > arg) { seedoffset = atoi(argv[arg]); ++arg; } if (doforeign) { gex_Rank_t nbrhd_set_size; gex_System_QueryMyPosition(&nbrhd_set_size, NULL, NULL, NULL); if (nbrhd_set_size == numprocs) { // all nbrhs are single-process MSG0("WARNING: Ignoring '-f' since there are no foreign segments."); doforeign = 0; } } GASNET_Safe(gex_Segment_Attach(&mysegment, myteam, TEST_SEGSZ)); test_init("testslice",0, "[options] (arena size) (iterations) (# of sizes per iteration) (seed)\n" " The -c option enables cross-machine pairing, default is nearest neighbor.\n" " The -f option enables use of a 'foreign' GASNet segment (one cross-mapped\n" " from another process) as the 'local' address for communications."); if (help || argc > arg) test_usage(); if (crossmachinemode) { if ((numprocs%2) && (myproc == numprocs-1)) { peerproc = myproc; } else { gex_Rank_t half = numprocs / 2; peerproc = (myproc < half) ? (myproc + half) : (myproc - half); } } else { peerproc = (myproc + 1) % numprocs; } if (seedoffset == 0) { seedoffset = (((unsigned int)TIME()) & 0xFFFF); TEST_BCAST(&seedoffset, 0, &seedoffset, sizeof(seedoffset)); } TEST_SRAND(myproc+seedoffset); MSG0("Running %s%stest with arena size=%"PRIuSZ" outer iterations=%d inner iterations=%d seed=%d", (crossmachinemode ? "cross-machine ": ""), (doforeign ? "foreign-segment ": ""), arenasz,outer_iterations, inner_iterations, seedoffset); // Allocate two shadow regions the same size as the arena char *shadow_region_1, *shadow_region_2; if (doforeign) { // Use cross-mapped (localized) segment of a neighbor if possible gex_RankInfo_t *nbrhdinfo = NULL; gex_Rank_t nbrhdsize, nbrhdrank; gex_System_QueryNbrhdInfo(&nbrhdinfo, &nbrhdsize, &nbrhdrank); // Using segment of "left" (-1) neighbor to avoid (when possible) using same as peerproc gex_Rank_t nbrproc = nbrhdinfo[(nbrhdrank + nbrhdsize - 1) % nbrhdsize].gex_jobrank; char *nbr_seg_local_addr = NULL; gex_Event_Wait( gex_EP_QueryBoundSegmentNB(myteam, nbrproc, NULL, (void**)&nbr_seg_local_addr, NULL, 0) ); assert_always(nbr_seg_local_addr != NULL); shadow_region_1 = nbr_seg_local_addr + 2*arenasz; } else { // Just plain local memory shadow_region_1 = (char *) test_malloc(2*arenasz); } shadow_region_2 = shadow_region_1 + arenasz; // Initialize the two shadow regions with random bytes and zeros, respectively // We take care to ensure "owner writes" even for foreign segments { uint32_t *tmp1 = (uint32_t *) (doforeign ? ((char *)TEST_MYSEG() + 2*arenasz) : shadow_region_1); for(size_t k=0;k < arenasz / sizeof(uint32_t);k++) { tmp1[k] = TEST_RAND(0, UINT32_MAX); } char *tmp2 = (doforeign ? ((char *)TEST_MYSEG() + 3*arenasz) : shadow_region_2); memset(tmp2,0,arenasz); } char *local_base = (char *)TEST_MYSEG(); char *target_base = (char *)TEST_SEG(peerproc) + arenasz; BARRIER(); /* Big loop performing the following */ for(int i=0;i < outer_iterations;i++) { /* Pick a starting point anywhere in the segment */ size_t starting_point = TEST_RAND(0,(arenasz-1)); for(int j=0;j < inner_iterations;j++) { /* Pick a length */ size_t len = TEST_RAND(1,arenasz-starting_point); size_t remote_starting_point = TEST_RAND(0,arenasz-len); size_t local_starting_point_1 = TEST_RAND(0,arenasz-len); size_t local_starting_point_2 = TEST_RAND(0,arenasz-len); char *remote = target_base + remote_starting_point; char *local = local_base + local_starting_point_1; char *shadow1 = shadow_region_1 + starting_point; char *shadow2 = shadow_region_2 + local_starting_point_2;; /* Perform operations */ /* Out of segment put from shadow_region 1 to remote */ do_put(remote, shadow1, len); /* In segment get from remote to local segment */ do_get(local, remote, len); /* Verify */ assert_eq(shadow1, local, len, starting_point, i, j, "Out of segment put + in segment get"); /* Out of segment get from remote to shadow_region_2 (starting from 0) */ do_get(shadow2, remote, len); /* Verify */ assert_eq(shadow2, shadow1, len, starting_point, i, j, "Out of segment get"); } TEST_PROGRESS_BAR(i,outer_iterations); BARRIER(); } if (!doforeign) test_free(shadow_region_1); if(!failures) { MSG("testslice PASSED"); } gasnet_exit(0); return 0; } /* ------------------------------------------------------------------------------------ */