#include extern "C"{ #include "structures.h" #include "lib_math.h" #include "defines.h" #include "lib_gpu.h" #include "lib_snake_2_gpu.h" } #include "lib_test_gpu.h" #include "lib_kernels_cumuls.cu" #include "lib_kernel_snake_2_gpu.cu" #define DEBUG_IMG_CUMUL 1 bool DISPLAY_ERR_IMG_CUMUL = 1; //#define DEBUG_POSITIONS //#define DEBUG_MOVE //#define DEBUG_CRST //#define DEBUG_MV //#define DEBUG_SOMSOM //#define DEBUG_SOMBLOCS //#define DEBUG_LISTES //#define DEBUG_STATS_REF inline unsigned int nextPow2( unsigned int x ) { --x; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return ++x; } void cuda_init_img_cumul(unsigned short ** img_in, int H, int L, int nb_nodes, unsigned short ** d_img, t_cumul_x ** d_img_x, t_cumul_x2 ** d_img_x2, int ** d_freemanDiDj, int ** d_codeNoeud, snake_node_gpu ** d_snake, uint32 ** d_nb_pix_max, uint4 ** d_positions, uint64 ** d_contribs_segments, uint4 ** d_freemans_centres, int ** d_codes_segments, int64 ** d_stats_snake, int64 ** d_stats, int64 ** d_stats_ref, double ** d_vrais, double ** d_vrais_snake, uint2 ** d_liste_pixels, uint64 ** d_contribs_segments_blocs, bool ** d_move ) { unsigned int taille = H*L; timeval chrono; //allocation cumuls en memoire GPU tic(&chrono, NULL); /* MAX_PIX 20000 MAX_NODES 10000 MAX_LISTE_PIX 10000000 */ cudaMalloc( (void**) d_snake, MAX_NODES*sizeof(snake_node_gpu) ); cudaMalloc( (void**) d_img, taille*sizeof(unsigned short) ); cudaMalloc( (void**) d_img_x, taille*sizeof(t_cumul_x) ); cudaMalloc( (void**) d_img_x2, taille*sizeof(t_cumul_x2) ); cudaMalloc( (void**) d_freemanDiDj, 9*sizeof(int) ); cudaMalloc( (void**) d_codeNoeud, 64*sizeof(int) ); cudaMalloc( (void**) d_stats_snake, 6*sizeof(int64)) ; cudaMalloc( (void**) d_positions, 8*MAX_NODES*sizeof(uint4)) ; cudaMalloc( (void**) d_contribs_segments, 3*16*MAX_NODES*sizeof(uint64)) ; cudaMalloc( (void**) d_contribs_segments_blocs, (3*MAX_LISTE_PIX/32)*sizeof(uint64)) ; cudaMalloc( (void**) d_freemans_centres, 16*MAX_NODES*sizeof(uint4)) ; cudaMalloc( (void**) d_codes_segments, 16*MAX_NODES*sizeof(int)) ; cudaMalloc( (void**) d_stats, 3*8*MAX_NODES*sizeof(int64)) ; cudaMalloc( (void**) d_stats_ref, 3*MAX_NODES*sizeof(int64)) ; cudaMalloc( (void**) d_vrais, 8*MAX_NODES*sizeof(double)) ; cudaMalloc( (void**) d_move, MAX_NODES*sizeof(bool)) ; cudaMalloc( (void**) d_nb_pix_max, sizeof(uint32)) ; cudaMalloc( (void**) d_vrais_snake, sizeof(double)) ; cudaMalloc( (void**) d_liste_pixels, 16*5*(MAX_NODES)*sizeof(uint2) ); printf("TOTAL MEM = %ld octets\n", (2*MAX_NODES*(sizeof(snake_node_gpu)+(8+16)*sizeof(uint4)+3*16*8+16*4+24*8+3*8+8*sizeof(double)+sizeof(bool)) +(MAX_LISTE_PIX)*(sizeof(uint2)+1) +taille*(8+sizeof(t_cumul_x)+sizeof(t_cumul_x2)) +9*4+64*4+6*8+4+sizeof(double)) ); int64 * h_stats_snake = new int64[6]; toc(chrono, "temps alloc mem GPU"); /*detection-choix-initialisation de la carte GPU*/ tic(&chrono, NULL) ; cudaDeviceProp deviceProp; deviceProp.major = 1; deviceProp.minor = 0; int desiredMinorRevision = 3; int dev; cudaChooseDevice(&dev, &deviceProp); cudaGetDeviceProperties(&deviceProp, dev); if(deviceProp.major > 1 || deviceProp.minor >= desiredMinorRevision) { printf("Using Device %d: \"%s\"\n", dev, deviceProp.name); cudaSetDevice(dev); } toc(chrono, "temps acces GPU") ; //copie tables correspondances freeman en mem GPU tic(&chrono, NULL) ; cudaMemcpy( *d_freemanDiDj, CORRESPONDANCE_Di_Dj_FREEMAN , 9*sizeof(int), cudaMemcpyHostToDevice); cudaMemcpy( *d_codeNoeud, TABLE_CODAGE , 64*sizeof(unsigned int), cudaMemcpyHostToDevice); toc(chrono, "temps transfert tables de codage") ; /*transfert image en global mem GPU*/ tic(&chrono, NULL); cudaMemcpy( *d_img, img_in[0], taille*sizeof(unsigned short), cudaMemcpyHostToDevice); toc(chrono, "transfert image vers GPU"); //calculs images cumulees sur GPU int blocs_max = 65536 ; int bs = 256 ; //arbitraire, d'apres les observations c'est souvent l'optimu unsigned int base = 0 ; unsigned int bl_l = (L+bs-1)/bs ; unsigned int nb_lines = blocs_max / bl_l ; unsigned int lines ; unsigned int tranches = ( 1 + H / nb_lines ) ; nb_lines = (H +tranches -1)/ tranches ; // equilibre la taille des tranches unsigned blocs = bl_l*nb_lines ; dim3 threads(bs,1,1); int smem = nextPow2(bl_l)*2; //smem pour le prefixscan des sommes de blocs (etape 2) smem += smem >> DEC; smem += smem >> DEC; int smem_size = smem*sizeof(uint64); uint64 * d_somblocs ; // sommes des cumuls par bloc de calcul if(DEBUG_IMG_CUMUL) { printf("--- CALCULS IMAGES CUMULEES+STATS GPU ----\n"); printf("\t%d threads par bloc -- %u blocs par ligne -- %u tranches -- %u lignes par tranche \n",bs, bl_l, tranches,nb_lines); printf(" Smem totale pour cumuls : %d\n", CFI(bs)*(sizeof(t_cumul_x)+sizeof(t_cumul_x2)) ); tic(&chrono, NULL); } //calculs cumuls generiques : necessitent 3 etapes / 3 kernels cudaMalloc( (void**) &d_somblocs, 2*bl_l*nb_lines*sizeof(uint64) ); cudaFuncSetCacheConfig(calcul_cumuls_gpu, cudaFuncCachePreferShared); do { if ( H-base < nb_lines ) lines = H - base ; else lines = nb_lines ; printf("base = ligne %d -- traitement de %d lignes \n", base, lines) ; dim3 grid(bl_l*lines,1,1) ; calcul_cumuls_gpu<<>>(*d_img, *d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; scan_somblocs<<<2*lines, nextPow2(bl_l)/2, smem_size>>>(d_somblocs, bl_l) ; add_soms_to_cumuls<<>>(*d_img_x, *d_img_x2, H, L, d_somblocs, bl_l, base, lines) ; base += lines ; } while (base < H) ; cudaFree(d_somblocs) ; //calcul des sommes totales N, sigX et sigX2 sur l'image calcul_stats_image<<<1, 1>>>( *d_img_x, *d_img_x2, H, L, (uint64*)*d_stats_snake); cudaThreadSynchronize() ; toc(chrono, "\tTemps GPU"); if(DEBUG_IMG_CUMUL) { //allocation memoire CPU t_cumul_x * img_x = new t_cumul_x [H*L]; t_cumul_x2 * img_x2 = new t_cumul_x2 [H*L]; /*pour test comparaison*/ t_cumul_x * img_xb = new t_cumul_x [H*L]; t_cumul_x2 * img_x2b = new t_cumul_x2 [H*L]; cudaMemcpy( img_xb, *d_img_x, taille*sizeof(t_cumul_x), cudaMemcpyDeviceToHost); cudaMemcpy( img_x2b, *d_img_x2, taille*sizeof(t_cumul_x2), cudaMemcpyDeviceToHost); //cumuls : etape 1 CPU /* for (int i=0; i>>(*d_snake, 140, H, L) ; else if (nb_nodes == 40) genere_snake_rectangle_Nnodes_gpu<<< 1, 1>>>(*d_snake, (H+L)/20, H, L) ; int nnodes = nb_nodes ; snake_node_gpu * h_snake = new snake_node_gpu[nnodes]; snake_node * h_snake_ll = new snake_node[nnodes] ; uint4 * h_liste_positions = new uint4[nnodes*8]; double * h_vrais_snake = new double ; //init les stats du snake uint2 * d_liste_temp ; t_sum_x2 * d_sompart ; int tpb, bps, npixmax ; //calcul nb threads par bloc npixmax = 2*(H+L-4*dist)/(nnodes-1) ; tpb = nextPow2(npixmax) ; if (tpb >= 256) tpb = 256 ;// /!\ le kernel <<< calcul_contrib...>>> ne supporte pas un bs>256 a cause de la shared-mem nécessaire if (tpb < 32 ) tpb = 32 ; tpb=128 ; bps = (npixmax+tpb-1)/tpb ; printf("PARAMS EXEC INIT : %d pix max, %d threads/bloc, %d blocs/seg, %d blocs/grille\n", npixmax, tpb, bps, nnodes*bps); //alloc cudaMalloc((void**) &d_liste_temp, nnodes*bps*tpb*sizeof(uint2)); cudaMalloc((void**) &d_sompart, 3*nnodes*bps*sizeof(t_sum_x2)); cudaMalloc((void**) &d_stats_ref, 3*nnodes*sizeof(int64)); //DEBUG : pour forcer la mise à zero du tableau intermediaire d_stats_ref int64 h_stats_ref[3*nnodes] ; for (int a=0; a<3*nnodes ; a++) h_stats_ref[a] = 0 ; cudaMemcpy( h_stats_ref, d_stats_ref, sizeof(int64), cudaMemcpyHostToDevice) ; //fin forçage a 0 //DEBUG : pour forcer la mise à zero du tableau intermediaire d_sompart t_sum_x2 h_sompart[ 3*nnodes*bps ] ; for (int a=0; a<3*nnodes*bps ; a++) h_sompart[a] = 0 ; cudaMemcpy( h_sompart, d_sompart, sizeof(t_sum_x2), cudaMemcpyHostToDevice) ; //fin forçage a 0 calcul_contribs_segments_snake<<< nnodes*bps, tpb, (CFI(tpb))*(3*sizeof(t_sum_x2))>>> (*d_snake, nnodes, *d_img_x, *d_img_x2, L, d_liste_temp, d_sompart, *d_freemanDiDj ); //TODO //parametrer pour ne pas appeler qd tpb=1 //oblige a modifier le kernel <<< calcul_contrib...>>> pour ecrire directement ds d_snake // au lieu de d_sompart somsom_snake<<< nnodes , 1 >>>(d_sompart, nnodes, bps, *d_snake); calcul_stats_snake<<< 1 , 1 >>>(*d_snake, nnodes, *d_stats_snake, *d_vrais_snake, *d_img_x, *d_img_x2, *d_codeNoeud, L ); cudaThreadSynchronize() ; toc(chrono, "\tTemps") ; /* verif stats initiales du snake */ cudaMemcpy( h_vrais_snake, *d_vrais_snake, sizeof(double), cudaMemcpyDeviceToHost) ; cudaMemcpy( h_stats_snake, *d_stats_snake, 6*sizeof(int64), cudaMemcpyDeviceToHost) ; printf("STATS SNAKE log vrais=%lf : c1=%lu - cx=%lu - cx2=%lu - N=%lu - SUMX=%lu - SUMX2=%lu\n", *h_vrais_snake, h_stats_snake[0], h_stats_snake[1], h_stats_snake[2], h_stats_snake[3], h_stats_snake[4], h_stats_snake[5] ); /* verif stats diminuees des contribs des 2 segments associes a chaque noeud */ #ifdef DEBUG_STATS_REF cudaMemcpy( h_stats_ref, d_stats_ref, 3*nnodes*sizeof(int64), cudaMemcpyDeviceToHost) ; cudaMemcpy( h_snake, *d_snake, nnodes*sizeof(snake_node_gpu), cudaMemcpyDeviceToHost) ; printf("******* STATS DIMINUEES\n"); for(int n=0; n0) ) { // /!\ penser a oter le test de prise en // compte pour les pix sur la même ligne dans // le kernel, sinon les comparaisons des // sommes par colonne seront fausses i = h_liste_pixels_segment[2*(b*bs + p)] ; j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; c1 += img_1[i][j] ; cx += img_x[i][j] ; cx2+= img_x2[i][j]; } } if ( ( c1 != h_sombloc[(16*n + s)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s)*nblocs_seg + b + grid.x] ) || ( cx2 != h_sombloc[ (16*n + s)*nblocs_seg + b + 2*grid.x] ) ) printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, c1, cx, cx2, h_sombloc[(16*n+s)*nblocs_seg + b], h_sombloc[(16*n+s)*nblocs_seg + b + grid.x], h_sombloc[(16*n+s)*nblocs_seg + b + 2*grid.x]) ; } } for(int s=0; s<8; s++) { int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, h_liste_pixels_segment, 0); for (int b=0; b0) ) { // /!\ penser a oter le test de prise en // compte pour les pix sur la même ligne dans // le kernel, sinon les comparaisons des // sommes par colonne seront fausses i = h_liste_pixels_segment[2*(b*bs + p)] ; j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; c1 += img_1[i][j] ; cx += img_x[i][j] ; cx2+= img_x2[i][j]; } } if ( ( c1 != h_sombloc[(16*n + s + 8)*nblocs_seg + b ] ) || ( cx != h_sombloc[(16*n + s + 8)*nblocs_seg + b + grid.x] ) || ( cx2 != h_sombloc[ (16*n + s + 8)*nblocs_seg + b + 2*grid.x] ) ) printf("seg %d - %d pix : bloc %d -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, b, c1, cx, cx2, h_sombloc[(16*n+s+8)*nblocs_seg + b], h_sombloc[(16*n+s+8)*nblocs_seg + b + grid.x], h_sombloc[(16*n+s+8)*nblocs_seg + b + 2*grid.x]) ; } } } #endif //DEBUG_SOMBLOCS /* Test du calcul des sommes totales 'somsom' faites par le kernel 'somsom_full' */ #ifdef DEBUG_SOMSOM printf("********* SOMMES TOTALES ***********\n"); printf("bs = %d - grid = %d - intervalles = %d - nblocs_seg = %d - pairs = %d \n", bs, grid.x, n_interval, nblocs_seg, pairs); for (int n=0; n< n_interval; n++) { idx_n = 2*n + !pairs ; if (idx_n == 0) idx_nprec = nnodes - 1 ; else idx_nprec = idx_n - 1 ; if (idx_n == nnodes-1) idx_nsuiv = 0 ; else idx_nsuiv = idx_n + 1 ; printf("******** node %d\n", idx_n) ; for(int s=0; s<8; s++) { int nb_pix = calcul_liste_pixel_segment(h_snake[idx_nprec].posi,h_snake[idx_nprec].posj, h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, h_liste_pixels_segment, 0); uint64 c1=0, cx=0, cx2=0 ; for (int b=0; b0) ) { // /!\ penser a oter le test de prise en // compte pour les pix sur la même ligne dans // le kernel, sinon les comparaisons des // sommes par colonne seront fausses i = h_liste_pixels_segment[2*(b*bs + p)] ; j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; c1 += img_1[i][j] ; cx += img_x[i][j] ; cx2+= img_x2[i][j]; } } } if ( ( c1 != h_somsom[3*(16*n + s)] ) || ( cx != h_somsom[3*(16*n + s) + 1] ) || ( cx2 != h_somsom[3*(16*n + s) + 2] ) ) printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, c1, cx, cx2, h_somsom[3*(16*n + s)], h_somsom[3*(16*n + s) + 1], h_somsom[3*(16*n + s) + 2]) ; } for(int s=0; s<8; s++) { int nb_pix = calcul_liste_pixel_segment( h_liste_positions[8*idx_n+s].x, h_liste_positions[8*idx_n+s].y, h_snake[idx_nsuiv].posi,h_snake[idx_nsuiv].posj, h_liste_pixels_segment, 0); uint64 c1=0, cx=0, cx2=0 ; for (int b=0; b0) ) { // /!\ penser a oter le test de prise en // compte pour les pix sur la même ligne dans // le kernel, sinon les comparaisons des // sommes par colonne seront fausses i = h_liste_pixels_segment[2*(b*bs + p)] ; j = h_liste_pixels_segment[2*(b*bs + p) + 1] ; c1 += img_1[i][j] ; cx += img_x[i][j] ; cx2+= img_x2[i][j]; } } } if ( ( c1 != h_somsom[3*(16*n + s + 8)] ) || ( cx != h_somsom[3*(16*n + s + 8) + 1] ) || ( cx2 != h_somsom[3*(16*n + s + 8) + 2] ) ) printf("seg %d - %d pix -> CPU : %lu - %lu - %lu \t|| GPU : %lu - %lu - %lu \n", s, nb_pix, c1, cx, cx2, h_somsom[3*(16*n + s + 8)], h_somsom[3*(16*n + s + 8) + 1], h_somsom[3*(16*n + s + 8) + 2]) ; } } #endif #ifdef DEBUG_MV printf("**** STATS - REF : %lf \n", *h_vrais_snake); for(int n=0; n