VPR-6.0

vpr/SRC/base/stats.c File Reference

#include <assert.h>
#include <stdio.h>
#include <math.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "rr_graph_area.h"
#include "segment_stats.h"
#include "stats.h"
#include "net_delay.h"
#include "path_delay.h"
#include "read_xml_arch_file.h"
Include dependency graph for stats.c:

Go to the source code of this file.

Functions

static void load_channel_occupancies (int **chanx_occ, int **chany_occ)
static void get_length_and_bends_stats (void)
static void get_channel_occupancy_stats (void)
void routing_stats (boolean full_stats, enum e_route_type route_type, int num_switch, t_segment_inf *segment_inf, int num_segment, float R_minW_nmos, float R_minW_pmos, enum e_directionality directionality, boolean timing_analysis_enabled, float **net_slack, float **net_delay)
void get_num_bends_and_length (int inet, int *bends_ptr, int *len_ptr, int *segments_ptr)
void print_wirelen_prob_dist (void)
void print_lambda (void)

Function Documentation

static void get_channel_occupancy_stats ( void  ) [static]

Determines how many tracks are used in each channel.

Definition at line 188 of file stats.c.

{
    int i, j, max_occ, total_x, total_y;
    float av_occ;
    int **chanx_occ;            /* [1..nx][0..ny] */
    int **chany_occ;            /* [0..nx][1..ny] */


    chanx_occ = (int **)alloc_matrix(1, nx, 0, ny, sizeof(int));
    chany_occ = (int **)alloc_matrix(0, nx, 1, ny, sizeof(int));
    load_channel_occupancies(chanx_occ, chany_occ);

    printf("\nX - Directed channels:\n\n");
    printf("j\tmax occ\tav_occ\t\tcapacity\n");

    total_x = 0;

    for(j = 0; j <= ny; j++)
        {
            total_x += chan_width_x[j];
            av_occ = 0.;
            max_occ = -1;

            for(i = 1; i <= nx; i++)
                {
                    max_occ = max(chanx_occ[i][j], max_occ);
                    av_occ += chanx_occ[i][j];
                }
            av_occ /= nx;
            printf("%d\t%d\t%-#9g\t%d\n", j, max_occ, av_occ,
                   chan_width_x[j]);
        }


    printf("\nY - Directed channels:\n\n");
    printf("i\tmax occ\tav_occ\t\tcapacity\n");

    total_y = 0;

    for(i = 0; i <= nx; i++)
        {
            total_y += chan_width_y[i];
            av_occ = 0.;
            max_occ = -1;

            for(j = 1; j <= ny; j++)
                {
                    max_occ = max(chany_occ[i][j], max_occ);
                    av_occ += chany_occ[i][j];
                }
            av_occ /= ny;
            printf("%d\t%d\t%-#9g\t%d\n", i, max_occ, av_occ,
                   chan_width_y[i]);
        }

    printf("\nTotal Tracks in X-direction: %d  in Y-direction: %d\n\n",
           total_x, total_y);

    free_matrix(chanx_occ, 1, nx, 0, sizeof(int));
    free_matrix(chany_occ, 0, nx, 1, sizeof(int));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void get_length_and_bends_stats ( void  ) [static]

Figures out maximum, minimum and average number of bends and net length in the routing.

Definition at line 121 of file stats.c.

{
    int inet, bends, total_bends, max_bends;
    int length, total_length, max_length;
    int segments, total_segments, max_segments;
    float av_bends, av_length, av_segments;
    int num_global_nets, num_clb_opins_reserved;


    max_bends = 0;
    total_bends = 0;
    max_length = 0;
    total_length = 0;
    max_segments = 0;
    total_segments = 0;
    num_global_nets = 0;
        num_clb_opins_reserved = 0;

    for(inet = 0; inet < num_nets; inet++)
        {
                if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
                {               /* Globals don't count. */
                    get_num_bends_and_length(inet, &bends, &length,
                                             &segments);

                    total_bends += bends;
                    max_bends = max(bends, max_bends);

                    total_length += length;
                    max_length = max(length, max_length);

                    total_segments += segments;
                    max_segments = max(segments, max_segments);
                }
            else if (clb_net[inet].is_global)
                {
                    num_global_nets++;
                } else {
                        num_clb_opins_reserved++;
                }
        }


    av_bends = (float)total_bends / (float)(num_nets - num_global_nets);
    printf
        ("\nAverage number of bends per net: %#g  Maximum # of bends: %d\n\n",
         av_bends, max_bends);

    av_length = (float)total_length / (float)(num_nets - num_global_nets);
    printf("\nThe number of routed nets (nonglobal): %d\n",
           num_nets - num_global_nets);
    printf("Wirelength results (all in units of 1 clb segments):\n");
    printf("\tTotal wirelength: %d   Average net length: %#g\n",
           total_length, av_length);
    printf("\tMaximum net length: %d\n\n", max_length);

    av_segments = (float)total_segments / (float)(num_nets - num_global_nets);
    printf("Wirelength results in terms of physical segments:\n");
    printf("\tTotal wiring segments used: %d   Av. wire segments per net: "
           "%#g\n", total_segments, av_segments);
    printf("\tMaximum segments used by a net: %d\n\n", max_segments);
        printf("\tTotal local nets with reserved CLB opins: %d\n\n", num_clb_opins_reserved);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void get_num_bends_and_length ( int  inet,
int *  bends_ptr,
int *  len_ptr,
int *  segments_ptr 
)

Counts and returns the number of bends, wirelength, and number of routing resource segments in net inet's routing.

Definition at line 320 of file stats.c.

{
    struct s_trace *tptr, *prevptr;
    int inode;
    t_rr_type curr_type, prev_type;
    int bends, length, segments;

    bends = 0;
    length = 0;
    segments = 0;

    prevptr = trace_head[inet]; /* Should always be SOURCE. */
    if(prevptr == NULL)
        {
            printf
                ("Error in get_num_bends_and_length:  net #%d has no traceback.\n",
                 inet);
            exit(1);
        }
    inode = prevptr->index;
    prev_type = rr_node[inode].type;

    tptr = prevptr->next;

    while(tptr != NULL)
        {
            inode = tptr->index;
            curr_type = rr_node[inode].type;

            if(curr_type == SINK)
                {               /* Starting a new segment */
                    tptr = tptr->next;  /* Link to existing path - don't add to len. */
                    if(tptr == NULL)
                        break;

                    curr_type = rr_node[tptr->index].type;
                }

            else if(curr_type == CHANX || curr_type == CHANY)
                {
                    segments++;
                    length += 1 + rr_node[inode].xhigh - rr_node[inode].xlow +
                        rr_node[inode].yhigh - rr_node[inode].ylow;

                    if(curr_type != prev_type
                       && (prev_type == CHANX || prev_type == CHANY))
                        bends++;
                }

            prev_type = curr_type;
            tptr = tptr->next;
        }

    *bends_ptr = bends;
    *len_ptr = length;
    *segments_ptr = segments;
}

Here is the caller graph for this function:

static void load_channel_occupancies ( int **  chanx_occ,
int **  chany_occ 
) [static]

Loads the two arrays passed in with the total occupancy at each of the channel segments in the FPGA.

Definition at line 255 of file stats.c.

{

    int i, j, inode, inet;
    struct s_trace *tptr;
    t_rr_type rr_type;

/* First set the occupancy of everything to zero. */

    for(i = 1; i <= nx; i++)
        for(j = 0; j <= ny; j++)
            chanx_occ[i][j] = 0;

    for(i = 0; i <= nx; i++)
        for(j = 1; j <= ny; j++)
            chany_occ[i][j] = 0;

/* Now go through each net and count the tracks and pins used everywhere */

    for(inet = 0; inet < num_nets; inet++)
        {

                if(clb_net[inet].is_global && clb_net[inet].num_sinks != 0)     /* Skip global and empty nets. */
                continue;

            tptr = trace_head[inet];
            while(tptr != NULL)
                {
                    inode = tptr->index;
                    rr_type = rr_node[inode].type;

                    if(rr_type == SINK)
                        {
                            tptr = tptr->next;  /* Skip next segment. */
                            if(tptr == NULL)
                                break;
                        }

                    else if(rr_type == CHANX)
                        {
                            j = rr_node[inode].ylow;
                            for(i = rr_node[inode].xlow;
                                i <= rr_node[inode].xhigh; i++)
                                chanx_occ[i][j]++;
                        }

                    else if(rr_type == CHANY)
                        {
                            i = rr_node[inode].xlow;
                            for(j = rr_node[inode].ylow;
                                j <= rr_node[inode].yhigh; j++)
                                chany_occ[i][j]++;
                        }

                    tptr = tptr->next;
                }
        }
}

Here is the caller graph for this function:

void print_lambda ( void  )

Finds the average number of input pins used per clb. Does not count inputs which are hooked to global nets (i.e. the clock when it is marked global).

Definition at line 487 of file stats.c.

{
    int bnum, ipin;
    int num_inputs_used = 0;
    int iclass, inet;
    float lambda;
    t_type_ptr type;

    for(bnum = 0; bnum < num_blocks; bnum++)
        {
            type = block[bnum].type;
            assert(type != NULL);
            if(type != IO_TYPE)
                {
                    for(ipin = 0; ipin < type->num_pins; ipin++)
                        {
                            iclass = type->pin_class[ipin];
                            if(type->class_inf[iclass].type == RECEIVER)
                                {
                                    inet = block[bnum].nets[ipin];
                                    if(inet != OPEN)    /* Pin is connected? */
                                        if(clb_net[inet].is_global == FALSE)    /* Not a global clock */
                                            num_inputs_used++;
                                }
                        }
                }
        }

    lambda = (float)num_inputs_used / (float)num_blocks;
    printf("Average lambda (input pins used per clb) is: %g\n", lambda);
}
void print_wirelen_prob_dist ( void  )

Prints out the probability distribution of the wirelength / number input pins on a net -- i.e. simulates 2-point net length probability distribution.

Definition at line 387 of file stats.c.

{

    float *prob_dist;
    float norm_fac, two_point_length;
    int inet, bends, length, segments, index;
    float av_length;
    int prob_dist_size, i, incr;

    prob_dist_size = nx + ny + 10;
    prob_dist = (float *)my_calloc(prob_dist_size, sizeof(float));
    norm_fac = 0.;

    for(inet = 0; inet < num_nets; inet++)
        {
                if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0)
                {
                    get_num_bends_and_length(inet, &bends, &length,
                                             &segments);

/*  Assign probability to two integer lengths proportionately -- i.e.  *
 *  if two_point_length = 1.9, add 0.9 of the pins to prob_dist[2] and *
 *  only 0.1 to prob_dist[1].                                          */

                    two_point_length =
                        (float)length / (float)(clb_net[inet].num_sinks);
                    index = (int)two_point_length;
                    if(index >= prob_dist_size)
                        {

                            printf
                                ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n",
                                 index, prob_dist_size);
                            printf
                                ("Realloc'ing to increase 2-pin wirelen prob distribution array\n");
                            incr = index - prob_dist_size + 2;
                            prob_dist_size += incr;
                            prob_dist =
                                my_realloc(prob_dist,
                                           prob_dist_size * sizeof(float));
                            for(i = prob_dist_size - incr; i < prob_dist_size;
                                i++)
                                prob_dist[i] = 0.0;
                        }
                    prob_dist[index] +=
                        (clb_net[inet].num_sinks) * (1 - two_point_length +
                                                 index);

                    index++;
                    if(index >= prob_dist_size)
                        {

                            printf
                                ("Warning: index (%d) to prob_dist exceeds its allocated size (%d)\n",
                                 index, prob_dist_size);
                            printf
                                ("Realloc'ing to increase 2-pin wirelen prob distribution array\n");
                            incr = index - prob_dist_size + 2;
                            prob_dist_size += incr;
                            prob_dist =
                                my_realloc(prob_dist,
                                           prob_dist_size * sizeof(float));
                            for(i = prob_dist_size - incr; i < prob_dist_size;
                                i++)
                                prob_dist[i] = 0.0;
                        }
                    prob_dist[index] += (clb_net[inet].num_sinks) * (1 - index +
                                                                 two_point_length);

                    norm_fac += clb_net[inet].num_sinks;
                }
        }

/* Normalize so total probability is 1 and print out. */

    printf("\nProbability distribution of 2-pin net lengths:\n\n");
    printf("Length    p(Lenth)\n");

    av_length = 0;

    for(index = 0; index < prob_dist_size; index++)
        {
            prob_dist[index] /= norm_fac;
            printf("%6d  %10.6f\n", index, prob_dist[index]);
            av_length += prob_dist[index] * index;
        }

    printf("\nThe number of 2-pin nets is ;%g;\n", norm_fac);
    printf("\nExpected value of 2-pin net length (R) is ;%g;\n", av_length);
    printf("\nTotal wire length is ;%g;\n", norm_fac * av_length);

    free(prob_dist);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void routing_stats ( boolean  full_stats,
enum e_route_type  route_type,
int  num_switch,
t_segment_inf segment_inf,
int  num_segment,
float  R_minW_nmos,
float  R_minW_pmos,
enum e_directionality  directionality,
boolean  timing_analysis_enabled,
float **  net_slack,
float **  net_delay 
)

Prints out various statistics about the current routing. Both a routing and an rr_graph must exist when you call this routine.

Definition at line 32 of file stats.c.

{
    float T_crit;
        float area, used_area;
        int i, j;

    get_length_and_bends_stats();
    get_channel_occupancy_stats();

    printf("Logic Area (in minimum width transistor areas, excludes I/Os and empty grid tiles):\n");

        area = 0;
        for(i = 1; i <= nx; i++) {
                for(j = 1; j <= ny; j++) {
                        if(grid[i][j].offset == 0) {
                                if(grid[i][j].type->area == UNDEFINED) {
                                        area += grid_logic_tile_area * grid[i][j].type->height;
                                } else {
                                        area += grid[i][j].type->area;
                                }
                        }
                }
        }
        /* Todo: need to add pitch of routing to blocks with height > 3 */
    printf("Total Logic Block Area (Warning, need to add pitch of routing to blocks with height > 3): %g \n", area);

        used_area = 0;
        for(i = 0; i < num_blocks; i++) {
                if(block[i].type != IO_TYPE) {
                        if(block[i].type->area == UNDEFINED) {
                                used_area += grid_logic_tile_area * block[i].type->height;
                        } else {
                                used_area += block[i].type->area;
                        }
                }
        }
    printf("Total Used Logic Block Area: %g \n", used_area);

    if(route_type == DETAILED)
        {
            count_routing_transistors(directionality, num_switch, segment_inf,
                                      R_minW_nmos, R_minW_pmos);
            get_segment_usage_stats(num_segment, segment_inf);

            if(timing_analysis_enabled)
                {
                    load_net_delay_from_routing(net_delay, clb_net, num_nets);

#ifdef CREATE_ECHO_FILES
                    print_net_delay(net_delay, "net_delay.echo", clb_net, num_nets);
#endif /* CREATE_ECHO_FILES */

                    load_timing_graph_net_delays(net_delay);
                    T_crit = load_net_slack(net_slack, 0);

#ifdef CREATE_ECHO_FILES
                    print_timing_graph("timing_graph.echo");
                    print_net_slack("net_slack.echo", net_slack);
                    print_critical_path("critical_path.echo");
#endif /* CREATE_ECHO_FILES */

                    printf("\n");
                        if(pb_max_internal_delay == UNDEFINED || pb_max_internal_delay < T_crit) {
                                printf("Critical Path: %g (s)\n", T_crit);
                        } else {
                                printf("Critical Path: %g (s) - capped by fmax of block type %s\n", pb_max_internal_delay, pbtype_max_internal_delay->name);
                        }
                }
        }

    if(full_stats == TRUE)
        print_wirelen_prob_dist();
}

Here is the call graph for this function:

Here is the caller graph for this function: