VPR-6.0

vpr/SRC/base/stats.c

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <stdio.h>
00003 #include <math.h>
00004 #include "util.h"
00005 #include "vpr_types.h"
00006 #include "globals.h"
00007 #include "rr_graph_area.h"
00008 #include "segment_stats.h"
00009 #include "stats.h"
00010 #include "net_delay.h"
00011 #include "path_delay.h"
00012 #include "read_xml_arch_file.h"
00013 
00014 /********************** Subroutines local to this module *********************/
00015 
00016 static void load_channel_occupancies(int **chanx_occ,
00017                                      int **chany_occ);
00018 
00019 static void get_length_and_bends_stats(void);
00020 
00021 static void get_channel_occupancy_stats(void);
00022 
00023 
00024 
00025 /************************* Subroutine definitions ****************************/
00026 
00027 
00028 /** Prints out various statistics about the current routing.  Both a routing 
00029  * and an rr_graph must exist when you call this routine.                   
00030  */
00031 void
00032 routing_stats(boolean full_stats,
00033               enum e_route_type route_type,
00034               int num_switch,
00035               t_segment_inf * segment_inf,
00036               int num_segment,
00037               float R_minW_nmos,
00038               float R_minW_pmos,
00039               enum e_directionality directionality,
00040               boolean timing_analysis_enabled,
00041               float **net_slack,
00042               float **net_delay)
00043 {
00044     float T_crit;
00045         float area, used_area;
00046         int i, j;
00047 
00048     get_length_and_bends_stats();
00049     get_channel_occupancy_stats();
00050 
00051     printf("Logic Area (in minimum width transistor areas, excludes I/Os and empty grid tiles):\n");
00052 
00053         area = 0;
00054         for(i = 1; i <= nx; i++) {
00055                 for(j = 1; j <= ny; j++) {
00056                         if(grid[i][j].offset == 0) {
00057                                 if(grid[i][j].type->area == UNDEFINED) {
00058                                         area += grid_logic_tile_area * grid[i][j].type->height;
00059                                 } else {
00060                                         area += grid[i][j].type->area;
00061                                 }
00062                         }
00063                 }
00064         }
00065         /* Todo: need to add pitch of routing to blocks with height > 3 */
00066     printf("Total Logic Block Area (Warning, need to add pitch of routing to blocks with height > 3): %g \n", area);
00067 
00068         used_area = 0;
00069         for(i = 0; i < num_blocks; i++) {
00070                 if(block[i].type != IO_TYPE) {
00071                         if(block[i].type->area == UNDEFINED) {
00072                                 used_area += grid_logic_tile_area * block[i].type->height;
00073                         } else {
00074                                 used_area += block[i].type->area;
00075                         }
00076                 }
00077         }
00078     printf("Total Used Logic Block Area: %g \n", used_area);
00079 
00080     if(route_type == DETAILED)
00081         {
00082             count_routing_transistors(directionality, num_switch, segment_inf,
00083                                       R_minW_nmos, R_minW_pmos);
00084             get_segment_usage_stats(num_segment, segment_inf);
00085 
00086             if(timing_analysis_enabled)
00087                 {
00088                     load_net_delay_from_routing(net_delay, clb_net, num_nets);
00089 
00090 #ifdef CREATE_ECHO_FILES
00091                     print_net_delay(net_delay, "net_delay.echo", clb_net, num_nets);
00092 #endif /* CREATE_ECHO_FILES */
00093 
00094                     load_timing_graph_net_delays(net_delay);
00095                     T_crit = load_net_slack(net_slack, 0);
00096 
00097 #ifdef CREATE_ECHO_FILES
00098                     print_timing_graph("timing_graph.echo");
00099                     print_net_slack("net_slack.echo", net_slack);
00100                     print_critical_path("critical_path.echo");
00101 #endif /* CREATE_ECHO_FILES */
00102 
00103                     printf("\n");
00104                         if(pb_max_internal_delay == UNDEFINED || pb_max_internal_delay < T_crit) {
00105                                 printf("Critical Path: %g (s)\n", T_crit);
00106                         } else {
00107                                 printf("Critical Path: %g (s) - capped by fmax of block type %s\n", pb_max_internal_delay, pbtype_max_internal_delay->name);
00108                         }
00109                 }
00110         }
00111 
00112     if(full_stats == TRUE)
00113         print_wirelen_prob_dist();
00114 }
00115 
00116 
00117 /** Figures out maximum, minimum and average number of bends and net length   
00118  * in the routing.                                                           
00119  */
00120 void
00121 get_length_and_bends_stats(void)
00122 {
00123     int inet, bends, total_bends, max_bends;
00124     int length, total_length, max_length;
00125     int segments, total_segments, max_segments;
00126     float av_bends, av_length, av_segments;
00127     int num_global_nets, num_clb_opins_reserved;
00128 
00129 
00130     max_bends = 0;
00131     total_bends = 0;
00132     max_length = 0;
00133     total_length = 0;
00134     max_segments = 0;
00135     total_segments = 0;
00136     num_global_nets = 0;
00137         num_clb_opins_reserved = 0;
00138 
00139     for(inet = 0; inet < num_nets; inet++)
00140         {
00141                 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
00142                 {               /* Globals don't count. */
00143                     get_num_bends_and_length(inet, &bends, &length,
00144                                              &segments);
00145 
00146                     total_bends += bends;
00147                     max_bends = max(bends, max_bends);
00148 
00149                     total_length += length;
00150                     max_length = max(length, max_length);
00151 
00152                     total_segments += segments;
00153                     max_segments = max(segments, max_segments);
00154                 }
00155             else if (clb_net[inet].is_global)
00156                 {
00157                     num_global_nets++;
00158                 } else {
00159                         num_clb_opins_reserved++;
00160                 }
00161         }
00162 
00163 
00164     av_bends = (float)total_bends / (float)(num_nets - num_global_nets);
00165     printf
00166         ("\nAverage number of bends per net: %#g  Maximum # of bends: %d\n\n",
00167          av_bends, max_bends);
00168 
00169     av_length = (float)total_length / (float)(num_nets - num_global_nets);
00170     printf("\nThe number of routed nets (nonglobal): %d\n",
00171            num_nets - num_global_nets);
00172     printf("Wirelength results (all in units of 1 clb segments):\n");
00173     printf("\tTotal wirelength: %d   Average net length: %#g\n",
00174            total_length, av_length);
00175     printf("\tMaximum net length: %d\n\n", max_length);
00176 
00177     av_segments = (float)total_segments / (float)(num_nets - num_global_nets);
00178     printf("Wirelength results in terms of physical segments:\n");
00179     printf("\tTotal wiring segments used: %d   Av. wire segments per net: "
00180            "%#g\n", total_segments, av_segments);
00181     printf("\tMaximum segments used by a net: %d\n\n", max_segments);
00182         printf("\tTotal local nets with reserved CLB opins: %d\n\n", num_clb_opins_reserved);
00183 }
00184 
00185 
00186 /** Determines how many tracks are used in each channel.                    */
00187 static void
00188 get_channel_occupancy_stats(void)
00189 {
00190     int i, j, max_occ, total_x, total_y;
00191     float av_occ;
00192     int **chanx_occ;            /* [1..nx][0..ny] */
00193     int **chany_occ;            /* [0..nx][1..ny] */
00194 
00195 
00196     chanx_occ = (int **)alloc_matrix(1, nx, 0, ny, sizeof(int));
00197     chany_occ = (int **)alloc_matrix(0, nx, 1, ny, sizeof(int));
00198     load_channel_occupancies(chanx_occ, chany_occ);
00199 
00200     printf("\nX - Directed channels:\n\n");
00201     printf("j\tmax occ\tav_occ\t\tcapacity\n");
00202 
00203     total_x = 0;
00204 
00205     for(j = 0; j <= ny; j++)
00206         {
00207             total_x += chan_width_x[j];
00208             av_occ = 0.;
00209             max_occ = -1;
00210 
00211             for(i = 1; i <= nx; i++)
00212                 {
00213                     max_occ = max(chanx_occ[i][j], max_occ);
00214                     av_occ += chanx_occ[i][j];
00215                 }
00216             av_occ /= nx;
00217             printf("%d\t%d\t%-#9g\t%d\n", j, max_occ, av_occ,
00218                    chan_width_x[j]);
00219         }
00220 
00221 
00222     printf("\nY - Directed channels:\n\n");
00223     printf("i\tmax occ\tav_occ\t\tcapacity\n");
00224 
00225     total_y = 0;
00226 
00227     for(i = 0; i <= nx; i++)
00228         {
00229             total_y += chan_width_y[i];
00230             av_occ = 0.;
00231             max_occ = -1;
00232 
00233             for(j = 1; j <= ny; j++)
00234                 {
00235                     max_occ = max(chany_occ[i][j], max_occ);
00236                     av_occ += chany_occ[i][j];
00237                 }
00238             av_occ /= ny;
00239             printf("%d\t%d\t%-#9g\t%d\n", i, max_occ, av_occ,
00240                    chan_width_y[i]);
00241         }
00242 
00243     printf("\nTotal Tracks in X-direction: %d  in Y-direction: %d\n\n",
00244            total_x, total_y);
00245 
00246     free_matrix(chanx_occ, 1, nx, 0, sizeof(int));
00247     free_matrix(chany_occ, 0, nx, 1, sizeof(int));
00248 }
00249 
00250 
00251 /** Loads the two arrays passed in with the total occupancy at each of the  
00252  * channel segments in the FPGA.                                           
00253  */
00254 static void
00255 load_channel_occupancies(int **chanx_occ,
00256                          int **chany_occ)
00257 {
00258 
00259     int i, j, inode, inet;
00260     struct s_trace *tptr;
00261     t_rr_type rr_type;
00262 
00263 /* First set the occupancy of everything to zero. */
00264 
00265     for(i = 1; i <= nx; i++)
00266         for(j = 0; j <= ny; j++)
00267             chanx_occ[i][j] = 0;
00268 
00269     for(i = 0; i <= nx; i++)
00270         for(j = 1; j <= ny; j++)
00271             chany_occ[i][j] = 0;
00272 
00273 /* Now go through each net and count the tracks and pins used everywhere */
00274 
00275     for(inet = 0; inet < num_nets; inet++)
00276         {
00277 
00278                 if(clb_net[inet].is_global && clb_net[inet].num_sinks != 0)     /* Skip global and empty nets. */
00279                 continue;
00280 
00281             tptr = trace_head[inet];
00282             while(tptr != NULL)
00283                 {
00284                     inode = tptr->index;
00285                     rr_type = rr_node[inode].type;
00286 
00287                     if(rr_type == SINK)
00288                         {
00289                             tptr = tptr->next;  /* Skip next segment. */
00290                             if(tptr == NULL)
00291                                 break;
00292                         }
00293 
00294                     else if(rr_type == CHANX)
00295                         {
00296                             j = rr_node[inode].ylow;
00297                             for(i = rr_node[inode].xlow;
00298                                 i <= rr_node[inode].xhigh; i++)
00299                                 chanx_occ[i][j]++;
00300                         }
00301 
00302                     else if(rr_type == CHANY)
00303                         {
00304                             i = rr_node[inode].xlow;
00305                             for(j = rr_node[inode].ylow;
00306                                 j <= rr_node[inode].yhigh; j++)
00307                                 chany_occ[i][j]++;
00308                         }
00309 
00310                     tptr = tptr->next;
00311                 }
00312         }
00313 }
00314 
00315 
00316 /** Counts and returns the number of bends, wirelength, and number of routing 
00317  * resource segments in net inet's routing.                                  
00318  */
00319 void
00320 get_num_bends_and_length(int inet,
00321                          int *bends_ptr,
00322                          int *len_ptr,
00323                          int *segments_ptr)
00324 {
00325     struct s_trace *tptr, *prevptr;
00326     int inode;
00327     t_rr_type curr_type, prev_type;
00328     int bends, length, segments;
00329 
00330     bends = 0;
00331     length = 0;
00332     segments = 0;
00333 
00334     prevptr = trace_head[inet]; /* Should always be SOURCE. */
00335     if(prevptr == NULL)
00336         {
00337             printf
00338                 ("Error in get_num_bends_and_length:  net #%d has no traceback.\n",
00339                  inet);
00340             exit(1);
00341         }
00342     inode = prevptr->index;
00343     prev_type = rr_node[inode].type;
00344 
00345     tptr = prevptr->next;
00346 
00347     while(tptr != NULL)
00348         {
00349             inode = tptr->index;
00350             curr_type = rr_node[inode].type;
00351 
00352             if(curr_type == SINK)
00353                 {               /* Starting a new segment */
00354                     tptr = tptr->next;  /* Link to existing path - don't add to len. */
00355                     if(tptr == NULL)
00356                         break;
00357 
00358                     curr_type = rr_node[tptr->index].type;
00359                 }
00360 
00361             else if(curr_type == CHANX || curr_type == CHANY)
00362                 {
00363                     segments++;
00364                     length += 1 + rr_node[inode].xhigh - rr_node[inode].xlow +
00365                         rr_node[inode].yhigh - rr_node[inode].ylow;
00366 
00367                     if(curr_type != prev_type
00368                        && (prev_type == CHANX || prev_type == CHANY))
00369                         bends++;
00370                 }
00371 
00372             prev_type = curr_type;
00373             tptr = tptr->next;
00374         }
00375 
00376     *bends_ptr = bends;
00377     *len_ptr = length;
00378     *segments_ptr = segments;
00379 }
00380 
00381 
00382 /** Prints out the probability distribution of the wirelength / number   
00383  * input pins on a net -- i.e. simulates 2-point net length probability 
00384  * distribution.                                                        
00385  */
00386 void
00387 print_wirelen_prob_dist(void)
00388 {
00389 
00390     float *prob_dist;
00391     float norm_fac, two_point_length;
00392     int inet, bends, length, segments, index;
00393     float av_length;
00394     int prob_dist_size, i, incr;
00395 
00396     prob_dist_size = nx + ny + 10;
00397     prob_dist = (float *)my_calloc(prob_dist_size, sizeof(float));
00398     norm_fac = 0.;
00399 
00400     for(inet = 0; inet < num_nets; inet++)
00401         {
00402                 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
00403                 {
00404                     get_num_bends_and_length(inet, &bends, &length,
00405                                              &segments);
00406 
00407 /*  Assign probability to two integer lengths proportionately -- i.e.  *
00408  *  if two_point_length = 1.9, add 0.9 of the pins to prob_dist[2] and *
00409  *  only 0.1 to prob_dist[1].                                          */
00410 
00411                     two_point_length =
00412                         (float)length / (float)(clb_net[inet].num_sinks);
00413                     index = (int)two_point_length;
00414                     if(index >= prob_dist_size)
00415                         {
00416 
00417                             printf
00418                                 ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n",
00419                                  index, prob_dist_size);
00420                             printf
00421                                 ("Realloc'ing to increase 2-pin wirelen prob distribution array\n");
00422                             incr = index - prob_dist_size + 2;
00423                             prob_dist_size += incr;
00424                             prob_dist =
00425                                 my_realloc(prob_dist,
00426                                            prob_dist_size * sizeof(float));
00427                             for(i = prob_dist_size - incr; i < prob_dist_size;
00428                                 i++)
00429                                 prob_dist[i] = 0.0;
00430                         }
00431                     prob_dist[index] +=
00432                         (clb_net[inet].num_sinks) * (1 - two_point_length +
00433                                                  index);
00434 
00435                     index++;
00436                     if(index >= prob_dist_size)
00437                         {
00438 
00439                             printf
00440                                 ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n",
00441                                  index, prob_dist_size);
00442                             printf
00443                                 ("Realloc'ing to increase 2-pin wirelen prob distribution array\n");
00444                             incr = index - prob_dist_size + 2;
00445                             prob_dist_size += incr;
00446                             prob_dist =
00447                                 my_realloc(prob_dist,
00448                                            prob_dist_size * sizeof(float));
00449                             for(i = prob_dist_size - incr; i < prob_dist_size;
00450                                 i++)
00451                                 prob_dist[i] = 0.0;
00452                         }
00453                     prob_dist[index] += (clb_net[inet].num_sinks) * (1 - index +
00454                                                                  two_point_length);
00455 
00456                     norm_fac += clb_net[inet].num_sinks;
00457                 }
00458         }
00459 
00460 /* Normalize so total probability is 1 and print out. */
00461 
00462     printf("\nProbability distribution of 2-pin net lengths:\n\n");
00463     printf("Length    p(Lenth)\n");
00464 
00465     av_length = 0;
00466 
00467     for(index = 0; index < prob_dist_size; index++)
00468         {
00469             prob_dist[index] /= norm_fac;
00470             printf("%6d  %10.6f\n", index, prob_dist[index]);
00471             av_length += prob_dist[index] * index;
00472         }
00473 
00474     printf("\nThe number of 2-pin nets is ;%g;\n", norm_fac);
00475     printf("\nExpected value of 2-pin net length (R) is ;%g;\n", av_length);
00476     printf("\nTotal wire length is ;%g;\n", norm_fac * av_length);
00477 
00478     free(prob_dist);
00479 }
00480 
00481 
00482 /** Finds the average number of input pins used per clb.  Does not    
00483  * count inputs which are hooked to global nets (i.e. the clock     
00484  * when it is marked global).                                       
00485  */
00486 void
00487 print_lambda(void)
00488 {
00489     int bnum, ipin;
00490     int num_inputs_used = 0;
00491     int iclass, inet;
00492     float lambda;
00493     t_type_ptr type;
00494 
00495     for(bnum = 0; bnum < num_blocks; bnum++)
00496         {
00497             type = block[bnum].type;
00498             assert(type != NULL);
00499             if(type != IO_TYPE)
00500                 {
00501                     for(ipin = 0; ipin < type->num_pins; ipin++)
00502                         {
00503                             iclass = type->pin_class[ipin];
00504                             if(type->class_inf[iclass].type == RECEIVER)
00505                                 {
00506                                     inet = block[bnum].nets[ipin];
00507                                     if(inet != OPEN)    /* Pin is connected? */
00508                                         if(clb_net[inet].is_global == FALSE)    /* Not a global clock */
00509                                             num_inputs_used++;
00510                                 }
00511                         }
00512                 }
00513         }
00514 
00515     lambda = (float)num_inputs_used / (float)num_blocks;
00516     printf("Average lambda (input pins used per clb) is: %g\n", lambda);
00517 }