void truncated_radix_sort(unsigned long int *morton_codes, unsigned long int *sorted_morton_codes, unsigned int *permutation_vector, unsigned int *index, unsigned int *level_record, int N, int population_threshold, int sft, int lv){ int BinSizes[MAXBINS] = {0}; int BinCursor[MAXBINS] = {0}; unsigned int *tmp_ptr; unsigned long int *tmp_code; if(N<=0){ return; } else if(N<=population_threshold || sft < 0) { // Base case. The node is a leaf level_record[0] = lv; // record the level of the node memcpy(permutation_vector, index, N*sizeof(unsigned int)); // Copy the pernutation vector memcpy(sorted_morton_codes, morton_codes, N*sizeof(unsigned long int)); // Copy the Morton codes return; } else{ int i, j; level_record[0] = lv; // Find which child each point belongs to for(j=0; j<N; j++){ unsigned int ii = (morton_codes[j]>>sft) & 0x07; BinSizes[ii]++; } // scan prefix (must change this code) int offset = 0; for(i=0; i<MAXBINS; i++){ int ss = BinSizes[i]; BinCursor[i] = offset; offset += ss; BinSizes[i] = offset; } for(j=0; j<N; j++){ unsigned int ii = (morton_codes[j]>>sft) & 0x07; permutation_vector[BinCursor[ii]] = index[j]; sorted_morton_codes[BinCursor[ii]] = morton_codes[j]; BinCursor[ii]++; } //swap the index pointers swap(&index, &permutation_vector); //swap the code pointers swap_long(&morton_codes, &sorted_morton_codes); /* Call the function recursively to split the lower levels */ #ifdef CILK cilk_for(i=0; i<MAXBINS; i++) { #else for(i=0; i<MAXBINS; i++) { #endif int offset = (i>0) ? BinSizes[i-1] : 0; int size = BinSizes[i] - offset; truncated_radix_sort(&morton_codes[offset], &sorted_morton_codes[offset], &permutation_vector[offset], &index[offset], &level_record[offset], size, population_threshold, sft-3, lv+1); } } }
int main(int argc, char** argv){ // Time counting variables struct timeval startwtime, endwtime; double hashAvg=0, mortonAvg=0, sortingAvg=0, rearrangeAvg=0; extern int num_threads; if (argc != 7) { // Check if the command line arguments are correct printf("Usage: %s N dist pop rep L numThreads\n where\n N:number of points\n dist: distribution code (0-cube, 1-Plummer)\n pop: population threshold\n rep: repetitions\n L: maximum tree height.\n numThreads: number of threads to run this code with\n", argv[0]); return (1); } // Input command line arguments int N = atoi(argv[1]); // Number of points int dist = atoi(argv[2]); // Distribution identifier int population_threshold = atoi(argv[3]); // populatiton threshold int repeat = atoi(argv[4]); // number of independent runs int maxlev = atoi(argv[5]); // maximum tree height num_threads = atoi(argv[6]); //number of threads printf("Running for %d particles with maximum height: %d\n", N, maxlev); float *X = (float *) malloc(N*DIM*sizeof(float)); float *Y = (float *) malloc(N*DIM*sizeof(float)); unsigned int *hash_codes = (unsigned int *) malloc(DIM*N*sizeof(unsigned int)); unsigned long int *morton_codes = (unsigned long int *) malloc(N*sizeof(unsigned long int)); unsigned long int *sorted_morton_codes = (unsigned long int *) malloc(N*sizeof(unsigned long int)); unsigned int *permutation_vector = (unsigned int *) malloc(N*sizeof(unsigned int)); unsigned int *index = (unsigned int *) malloc(N*sizeof(unsigned int)); unsigned int *level_record = (unsigned int *) calloc(N,sizeof(unsigned int)); // record of the leaf of the tree and their level // initialize the index int i = 0; for(i=0; i<N; i++){ index[i] = i; } /* Generate a 3-dimensional data distribution */ create_dataset(X, N, dist); /* Find the boundaries of the space */ float max[DIM], min[DIM]; find_max(max, X, N); find_min(min, X, N); int nbins = (1 << maxlev); // maximum number of boxes at the leaf level int it = 0; // Independent runs for(it = 0; it<repeat; it++){ gettimeofday (&startwtime, NULL); compute_hash_codes(hash_codes, X, N, nbins, min, max); // compute the hash codes gettimeofday (&endwtime, NULL); double hash_time = (double)((endwtime.tv_usec - startwtime.tv_usec) /1.0e6 + endwtime.tv_sec - startwtime.tv_sec); hashAvg+=hash_time; printf("Time to compute the hash codes: %f\n", hash_time); gettimeofday (&startwtime, NULL); morton_encoding(morton_codes, hash_codes, N, maxlev); // computes the Morton codes of the particles gettimeofday (&endwtime, NULL); double morton_encoding_time = (double)((endwtime.tv_usec - startwtime.tv_usec) /1.0e6 + endwtime.tv_sec - startwtime.tv_sec); mortonAvg+=morton_encoding_time; printf("Time to compute the morton encoding: %f\n", morton_encoding_time); gettimeofday (&startwtime, NULL); // Truncated msd radix sort truncated_radix_sort(morton_codes, sorted_morton_codes, permutation_vector, index, level_record, N, population_threshold, 3*(maxlev-1), 0, num_threads); gettimeofday (&endwtime, NULL); double sort_time = (double)((endwtime.tv_usec - startwtime.tv_usec) /1.0e6 + endwtime.tv_sec - startwtime.tv_sec); sortingAvg+=sort_time; printf("Time for the truncated radix sort: %f\n", sort_time); gettimeofday (&startwtime, NULL); // Data rearrangement data_rearrangement(Y, X, permutation_vector, N); gettimeofday (&endwtime, NULL); double rearrange_time = (double)((endwtime.tv_usec - startwtime.tv_usec) /1.0e6 + endwtime.tv_sec - startwtime.tv_sec); rearrangeAvg+=rearrange_time; printf("Time to rearrange the particles in memory: %f\n", rearrange_time); /* The following code is for verification */ // Check if every point is assigned to one leaf of the tree int pass = check_index(permutation_vector, N); printf("%d of %d on INDEX TEST\n", pass, N); /* if(pass){ printf("Index test PASS\n"); } else{ printf("Index test FAIL\n"); } */ // Check is all particles that are in the same box have the same encoding. pass = check_codes(Y, sorted_morton_codes, level_record, N, maxlev); printf("%d of %d on ENCODING TEST\n", pass, N); /* if(pass){ printf("Encoding test PASS\n"); } else{ printf("Encoding test FAIL\n"); } */ } //compute and print average time for each stage hashAvg=hashAvg/repeat; printf("Average time for hashing: %f\n", hashAvg); mortonAvg=mortonAvg/repeat; printf("Average time for encoding: %f\n", mortonAvg); sortingAvg=sortingAvg/repeat; printf("Average time for sorting: %f\n", sortingAvg); rearrangeAvg=rearrangeAvg/repeat; printf("Average time for rearranging: %f\n", rearrangeAvg); /* clear memory */ free(X); free(Y); free(hash_codes); free(morton_codes); free(sorted_morton_codes); free(permutation_vector); free(index); free(level_record); }