#include <stdio.h>
#include <string.h>
#include <string.h>
#ifdef _MSC_VER
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#else
#include <strings.h>
#endif
#include <stdlib.h>
#include <math.h>
#include "flp.h"
#include "npe.h"
#include "shape.h"
#include "util.h"
#include "temperature.h"
#include "temperature_block.h"
double flp_evaluate_metric(flp_t *flp, RC_model_t *model, double *power,
double lambdaA, double lambdaT, double lambdaW)
{
double tmax, area, wire_length;
double *temp;
temp = hotspot_vector(model);
populate_R_model(model, flp);
steady_state_temp(model, power, temp);
tmax = find_max_temp(model, temp);
area = get_total_area(flp);
wire_length = get_wire_metric(flp);
free_dvector(temp);
return (lambdaA * area + lambdaT * tmax + lambdaW * wire_length);
}
flp_config_t default_flp_config(void)
{
flp_config_t config;
config.wrap_l2 = TRUE;
strcpy(config.l2_label, "L2");
config.model_rim = FALSE;
config.rim_thickness = 50e-6;
config.compact_ratio = 0.005;
config.n_orients = 300;
config.P0 = 0.99;
config.Davg = 1.0;
config.Kmoves = 7.0;
config.Rcool = 0.99;
config.Rreject = 0.99;
config.Nmax = 1000;
config.lambdaA = 5.0e+6;
config.lambdaT = 1.0;
config.lambdaW = 350;
return config;
}
void flp_config_add_from_strs(flp_config_t *config, str_pair *table, int size)
{
int idx;
if ((idx = get_str_index(table, size, "wrap_l2")) >= 0)
if(sscanf(table[idx].value, "%d", &config->wrap_l2) != 1)
fatal("invalid format for configuration parameter wrap_l2\n");
if ((idx = get_str_index(table, size, "l2_label")) >= 0)
if(sscanf(table[idx].value, "%s", config->l2_label) != 1)
fatal("invalid format for configuration parameter l2_label\n");
if ((idx = get_str_index(table, size, "model_rim")) >= 0)
if(sscanf(table[idx].value, "%d", &config->model_rim) != 1)
fatal("invalid format for configuration parameter model_rim\n");
if ((idx = get_str_index(table, size, "rim_thickness")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->rim_thickness) != 1)
fatal("invalid format for configuration parameter rim_thickness\n");
if ((idx = get_str_index(table, size, "compact_ratio")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->compact_ratio) != 1)
fatal("invalid format for configuration parameter compact_ratio\n");
if ((idx = get_str_index(table, size, "n_orients")) >= 0)
if(sscanf(table[idx].value, "%d", &config->n_orients) != 1)
fatal("invalid format for configuration parameter n_orients\n");
if ((idx = get_str_index(table, size, "P0")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->P0) != 1)
fatal("invalid format for configuration parameter P0\n");
if ((idx = get_str_index(table, size, "Davg")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->Davg) != 1)
fatal("invalid format for configuration parameter Davg\n");
if ((idx = get_str_index(table, size, "Kmoves")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->Kmoves) != 1)
fatal("invalid format for configuration parameter Kmoves\n");
if ((idx = get_str_index(table, size, "Rcool")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->Rcool) != 1)
fatal("invalid format for configuration parameter Rcool\n");
if ((idx = get_str_index(table, size, "Rreject")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->Rreject) != 1)
fatal("invalid format for configuration parameter Rreject\n");
if ((idx = get_str_index(table, size, "Nmax")) >= 0)
if(sscanf(table[idx].value, "%d", &config->Nmax) != 1)
fatal("invalid format for configuration parameter Nmax\n");
if ((idx = get_str_index(table, size, "lambdaA")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->lambdaA) != 1)
fatal("invalid format for configuration parameter lambdaA\n");
if ((idx = get_str_index(table, size, "lambdaT")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->lambdaT) != 1)
fatal("invalid format for configuration parameter lambdaT\n");
if ((idx = get_str_index(table, size, "lambdaW")) >= 0)
if(sscanf(table[idx].value, "%lf", &config->lambdaW) != 1)
fatal("invalid format for configuration parameter lambdaW\n");
if (config->rim_thickness <= 0)
fatal("rim thickness should be greater than zero\n");
if ((config->compact_ratio < 0) || (config->compact_ratio > 1))
fatal("compact_ratio should be between 0 and 1\n");
if ((config->n_orients <= 1) || (config->n_orients & 1))
fatal("n_orients should be an even number greater than 1\n");
if (config->Kmoves < 0)
fatal("Kmoves should be non-negative\n");
if ((config->P0 < 0) || (config->P0 > 1))
fatal("P0 should be between 0 and 1\n");
if ((config->Rcool < 0) || (config->Rcool > 1))
fatal("Rcool should be between 0 and 1\n");
if ((config->Rreject < 0) || (config->Rreject > 1))
fatal("Rreject should be between 0 and 1\n");
if (config->Nmax < 0)
fatal("Nmax should be non-negative\n");
}
int flp_config_to_strs(flp_config_t *config, str_pair *table, int max_entries)
{
if (max_entries < 15)
fatal("not enough entries in table\n");
sprintf(table[0].name, "wrap_l2");
sprintf(table[1].name, "l2_label");
sprintf(table[2].name, "model_rim");
sprintf(table[3].name, "rim_thickness");
sprintf(table[4].name, "compact_ratio");
sprintf(table[5].name, "n_orients");
sprintf(table[6].name, "P0");
sprintf(table[7].name, "Davg");
sprintf(table[8].name, "Kmoves");
sprintf(table[9].name, "Rcool");
sprintf(table[10].name, "Rreject");
sprintf(table[11].name, "Nmax");
sprintf(table[12].name, "lambdaA");
sprintf(table[13].name, "lambdaT");
sprintf(table[14].name, "lambdaW");
sprintf(table[0].value, "%d", config->wrap_l2);
sprintf(table[1].value, "%s", config->l2_label);
sprintf(table[2].value, "%d", config->model_rim);
sprintf(table[3].value, "%lg", config->rim_thickness);
sprintf(table[4].value, "%lg", config->compact_ratio);
sprintf(table[5].value, "%d", config->n_orients);
sprintf(table[6].value, "%lg", config->P0);
sprintf(table[7].value, "%lg", config->Davg);
sprintf(table[8].value, "%lg", config->Kmoves);
sprintf(table[9].value, "%lg", config->Rcool);
sprintf(table[10].value, "%lg", config->Rreject);
sprintf(table[11].value, "%d", config->Nmax);
sprintf(table[12].value, "%lg", config->lambdaA);
sprintf(table[13].value, "%lg", config->lambdaT);
sprintf(table[14].value, "%lg", config->lambdaW);
return 15;
}
void copy_l2_info (flp_t *flp, int to, flp_desc_t *flp_desc, int from, int size)
{
int j, count;
for(count=0; count < L2_ARMS + 1; count++, to++) {
strcpy(flp->units[to].name, flp_desc->units[from].name);
for(j=0; j < size; j++) {
flp->wire_density[to][j] = flp_desc->wire_density[from][j];
flp->wire_density[j][to] = flp_desc->wire_density[j][from];
}
}
strcat(flp->units[to-L2_ARMS+L2_LEFT].name, L2_LEFT_STR);
strcat(flp->units[to-L2_ARMS+L2_RIGHT].name, L2_RIGHT_STR);
}
flp_t *flp_placeholder(flp_desc_t *flp_desc)
{
int i, j, count, n_dead;
flp_t *flp;
int wrap_l2 = FALSE;
if (flp_desc->config.wrap_l2 &&
!strcasecmp(flp_desc->units[flp_desc->n_units-1].name, flp_desc->config.l2_label))
wrap_l2 = TRUE;
flp = (flp_t *) calloc (1, sizeof(flp_t));
if(!flp)
fatal("memory allocation error\n");
n_dead = flp_desc->n_units - !!(wrap_l2) - 1;
flp->n_units = flp_desc->n_units + n_dead;
if (wrap_l2)
flp->n_units += L2_ARMS;
if (flp_desc->config.model_rim)
flp->n_units += (2*flp->n_units + 2);
flp->units = (unit_t *) calloc (flp->n_units, sizeof(unit_t));
flp->wire_density = (double **) calloc(flp->n_units, sizeof(double *));
if (!flp->units || !flp->wire_density)
fatal("memory allocation error\n");
for (i=0; i < flp->n_units; i++) {
flp->wire_density[i] = (double *) calloc(flp->n_units, sizeof(double));
if (!flp->wire_density[i])
fatal("memory allocation error\n");
}
for(i=0; i < flp_desc->n_units-!!(wrap_l2); i++) {
strcpy(flp->units[i].name, flp_desc->units[i].name);
for (j=0; j < flp_desc->n_units-!!(wrap_l2); j++) {
flp->wire_density[i][j] = flp_desc->wire_density[i][j];
}
}
for(count=0; count < n_dead; count++, i++)
sprintf(flp->units[i].name, DEAD_PREFIX"%d", count);
if (wrap_l2)
copy_l2_info(flp, i, flp_desc, flp_desc->n_units-1, flp_desc->n_units-1);
return flp;
}
void restore_dead_blocks(flp_t *flp, flp_desc_t *flp_desc,
int compacted, int wrap_l2,
int model_rim, int rim_blocks)
{
int i, j, idx=0;
if(model_rim)
flp->n_units -= rim_blocks;
if (wrap_l2)
flp->n_units -= (L2_ARMS+1);
flp->n_units += compacted;
for(i=0; i < flp_desc->n_units-1; i++) {
idx = flp_desc->n_units + i;
sprintf(flp->units[idx].name, DEAD_PREFIX"%d", i);
flp->units[idx].leftx = flp->units[idx].bottomy = 0;
flp->units[idx].width = flp->units[idx].height = 0;
for(j=0; j < flp->n_units; j++)
flp->wire_density[idx][j] = flp->wire_density[j][idx] = 0;
}
}
void flp_translate(flp_t *flp, double x, double y)
{
int i;
double minx = flp->units[0].leftx;
double miny = flp->units[0].bottomy;
for (i=1; i < flp->n_units; i++) {
if (minx > flp->units[i].leftx)
minx = flp->units[i].leftx;
if (miny > flp->units[i].bottomy)
miny = flp->units[i].bottomy;
}
for (i=0; i < flp->n_units; i++) {
flp->units[i].leftx += (x - minx);
flp->units[i].bottomy += (y - miny);
}
}
void flp_scale(flp_t *flp, double factor)
{
int i;
double minx = flp->units[0].leftx;
double miny = flp->units[0].bottomy;
for (i=1; i < flp->n_units; i++) {
if (minx > flp->units[i].leftx)
minx = flp->units[i].leftx;
if (miny > flp->units[i].bottomy)
miny = flp->units[i].bottomy;
}
for(i=0; i < flp->n_units; i++) {
flp->units[i].leftx = (flp->units[i].leftx - minx) * factor + minx;
flp->units[i].bottomy = (flp->units[i].bottomy - miny) * factor + miny;
flp->units[i].width *= factor;
flp->units[i].height *= factor;
}
}
void flp_change_orient(flp_t *flp, double xorig, double yorig,
double width, double height, orient_t target)
{
int i;
for(i=0; i < flp->n_units; i++) {
double leftx, bottomy, rightx, topy;
leftx = flp->units[i].leftx - (xorig + width / 2.0);
bottomy = flp->units[i].bottomy - (yorig + height / 2.0);
rightx = leftx + flp->units[i].width;
topy = bottomy + flp->units[i].height;
switch(target) {
case ROT_0:
flp->units[i].leftx = leftx;
flp->units[i].bottomy = bottomy;
break;
case ROT_90:
flp->units[i].leftx = -topy;
flp->units[i].bottomy = leftx;
swap_dval(&(flp->units[i].width), &(flp->units[i].height));
break;
case ROT_180:
flp->units[i].leftx = -rightx;
flp->units[i].bottomy = -topy;
break;
case ROT_270:
flp->units[i].leftx = bottomy;
flp->units[i].bottomy = -rightx;
swap_dval(&(flp->units[i].width), &(flp->units[i].height));
break;
case FLIP_0:
flp->units[i].leftx = -rightx;
flp->units[i].bottomy = bottomy;
break;
case FLIP_90:
flp->units[i].leftx = bottomy;
flp->units[i].bottomy = leftx;
swap_dval(&(flp->units[i].width), &(flp->units[i].height));
break;
case FLIP_180:
flp->units[i].leftx = leftx;
flp->units[i].bottomy = -topy;
break;
case FLIP_270:
flp->units[i].leftx = -topy;
flp->units[i].bottomy = -rightx;
swap_dval(&(flp->units[i].width), &(flp->units[i].height));
break;
default:
fatal("unknown orientation\n");
break;
}
flp->units[i].leftx += (xorig + width / 2.0);
flp->units[i].bottomy += (yorig + height / 2.0);
}
}
flp_t *flp_create_grid(flp_t *flp, int ***map)
{
double x[MAX_UNITS], y[MAX_UNITS];
int i, j, n, xsize=0, ysize=0, count=0, found, **ptr;
flp_t *grid;
for(i=0; i < flp->n_units; i++) {
double r, t;
r = flp->units[i].leftx + flp->units[i].width;
t = flp->units[i].bottomy + flp->units[i].height;
if(bsearch_insert_double(x, xsize, flp->units[i].leftx))
xsize++;
if(bsearch_insert_double(y, ysize, flp->units[i].bottomy))
ysize++;
if(bsearch_insert_double(x, xsize, r))
xsize++;
if(bsearch_insert_double(y, ysize, t))
ysize++;
}
grid = (flp_t *) calloc (1, sizeof(flp_t));
if(!grid)
fatal("memory allocation error\n");
grid->n_units = (xsize-1) * (ysize-1);
grid->units = (unit_t *) calloc (grid->n_units, sizeof(unit_t));
grid->wire_density = (double **) calloc(grid->n_units, sizeof(double *));
if (!grid->units || !grid->wire_density)
fatal("memory allocation error\n");
for (i=0; i < grid->n_units; i++) {
grid->wire_density[i] = (double *) calloc(grid->n_units, sizeof(double));
if (!grid->wire_density[i])
fatal("memory allocation error\n");
}
ptr = (int **) calloc(flp->n_units, sizeof(int *));
if (!ptr)
fatal("memory allocation error\n");
for(i=0; i < flp->n_units; i++) {
ptr[i] = (int *) calloc(grid->n_units+1, sizeof(int));
if(!ptr[i])
fatal("memory allocation error\n");
}
for(i=0; i < flp->n_units; i++) {
double *xstart, *xend, *ystart, *yend;
double *ptr1, *ptr2;
int grid_num=0;
if (!bsearch_double(x, xsize, flp->units[i].leftx, &xstart))
fatal("invalid sorted arrays\n");
if (!bsearch_double(x, xsize, flp->units[i].leftx+flp->units[i].width, &xend))
fatal("invalid sorted arrays\n");
if (!bsearch_double(y, ysize, flp->units[i].bottomy, &ystart))
fatal("invalid sorted arrays\n");
if (!bsearch_double(y, ysize, flp->units[i].bottomy+flp->units[i].height, ¥d))
fatal("invalid sorted arrays\n");
for(ptr1 = xstart; ptr1 < xend; ptr1++)
for(ptr2 = ystart; ptr2 < yend; ptr2++) {
for(n=0, found=FALSE; n < count; n++) {
if (grid->units[n].leftx == ptr1[0] && grid->units[n].bottomy == ptr2[0]) {
found = TRUE;
break;
}
}
if(!found) {
sprintf(grid->units[count].name, "%s_%d", flp->units[i].name, grid_num);
grid->units[count].leftx = ptr1[0];
grid->units[count].bottomy = ptr2[0];
grid->units[count].width = ptr1[1]-ptr1[0];
grid->units[count].height = ptr2[1]-ptr2[0];
ptr[i][++ptr[i][0]] = count;
grid_num++;
count++;
}
}
}
if(count != (xsize-1) * (ysize-1))
fatal("mismatch in the no. of units\n");
for(i=0; i < flp->n_units; i++)
for(j=0; j < flp->n_units; j++) {
int p, q;
for(p=1; p <= ptr[i][0]; p++)
for(q=1; q <= ptr[j][0]; q++)
grid->wire_density[ptr[i][p]][ptr[j][q]] = flp->wire_density[i][j];
}
if (map)
(*map) = ptr;
else
free_blkgrid_map(flp, ptr);
return grid;
}
void free_blkgrid_map(flp_t *flp, int **map)
{
int i;
for(i=0; i < flp->n_units; i++)
free(map[i]);
free(map);
}
void xlate_power_blkgrid(flp_t *flp, flp_t *grid, \
double *bpower, double *gpower, int **map)
{
int i, p;
for(i=0; i < flp->n_units; i++)
for(p=1; p <= map[i][0]; p++)
gpower[map[i][p]] = bpower[i] / (flp->units[i].width * flp->units[i].height) *\
grid->units[map[i][p]].width * grid->units[map[i][p]].height;
}
void flp_wrap_l2(flp_t *flp, flp_desc_t *flp_desc)
{
double x, y, core_width, core_height, total_side, core_area, l2_area;
unit_t *l2, *l2_left, *l2_right;
core_area = get_total_area(flp);
core_width = get_total_width(flp);
core_height = get_total_height(flp);
l2_area = flp_desc->units[flp_desc->n_units].area;
total_side = sqrt(core_area + l2_area);
x = (total_side - core_width) / 2.0;
y = total_side - core_height;
if ( x <= 0 || y <= 0.0) {
double sum;
if (core_width >= core_height) {
sum = WRAP_L2_RATIO * core_width + 2 * core_height;
x = (sqrt(sum*sum + 8*WRAP_L2_RATIO*l2_area) - sum) / (4*WRAP_L2_RATIO);
y = WRAP_L2_RATIO * x;
} else {
sum = core_width + 2 * WRAP_L2_RATIO * core_height;
y = (sqrt(sum*sum + 8*WRAP_L2_RATIO*l2_area) - sum) / (4*WRAP_L2_RATIO);
x = WRAP_L2_RATIO * y;
}
total_side = 2 * x + core_width;
}
flp_translate(flp, x, y);
flp->n_units += (L2_ARMS+1);
copy_l2_info(flp, flp->n_units-L2_ARMS-1, flp_desc,
flp_desc->n_units, flp_desc->n_units);
l2 = &flp->units[flp->n_units-1-L2_ARMS];
l2->width = total_side;
l2->height = y;
l2->leftx = l2->bottomy = 0;
l2_left = &flp->units[flp->n_units-L2_ARMS+L2_LEFT];
l2_left->width = x;
l2_left->height = core_height;
l2_left->leftx = 0;
l2_left->bottomy = y;
l2_right = &flp->units[flp->n_units-L2_ARMS+L2_RIGHT];
l2_right->width = x;
l2_right->height = core_height;
l2_right->leftx = x + core_width;
l2_right->bottomy = y;
}
int flp_wrap_rim(flp_t *flp, double rim_thickness)
{
double width, height;
int i, j = 0, k, n = flp->n_units;
unit_t *unit;
width = get_total_width(flp) + 2 * rim_thickness;
height = get_total_height(flp) + 2 * rim_thickness;
flp_translate(flp, rim_thickness, rim_thickness);
for (i = 0; i < n; i++) {
unit = &flp->units[i];
if (eq(unit->leftx, rim_thickness)) {
sprintf(flp->units[n+j].name, "%s_%s",
RIM_LEFT_STR, unit->name);
flp->units[n+j].width = rim_thickness;
flp->units[n+j].height = unit->height;
flp->units[n+j].leftx = 0;
flp->units[n+j].bottomy = unit->bottomy;
if (eq(unit->bottomy + unit->height, height-rim_thickness))
flp->units[n+j].height += rim_thickness;
j++;
}
if (eq(unit->leftx + unit->width, width-rim_thickness)) {
sprintf(flp->units[n+j].name, "%s_%s",
RIM_RIGHT_STR, unit->name);
flp->units[n+j].width = rim_thickness;
flp->units[n+j].height = unit->height;
flp->units[n+j].leftx = unit->leftx + unit->width;
flp->units[n+j].bottomy = unit->bottomy;
if (eq(unit->bottomy, rim_thickness)) {
flp->units[n+j].height += rim_thickness;
flp->units[n+j].bottomy = 0;
}
j++;
}
if (eq(unit->bottomy + unit->height, height-rim_thickness)) {
sprintf(flp->units[n+j].name, "%s_%s",
RIM_TOP_STR, unit->name);
flp->units[n+j].width = unit->width;
flp->units[n+j].height = rim_thickness;
flp->units[n+j].leftx = unit->leftx;
flp->units[n+j].bottomy = unit->bottomy + unit->height;
if (eq(unit->leftx + unit->width, width-rim_thickness))
flp->units[n+j].width += rim_thickness;
j++;
}
if (eq(unit->bottomy, rim_thickness)) {
sprintf(flp->units[n+j].name, "%s_%s",
RIM_BOTTOM_STR, unit->name);
flp->units[n+j].width = unit->width;
flp->units[n+j].height = rim_thickness;
flp->units[n+j].leftx = unit->leftx;
flp->units[n+j].bottomy = 0;
if (eq(unit->leftx, rim_thickness)) {
flp->units[n+j].width += rim_thickness;
flp->units[n+j].leftx = 0;
}
j++;
}
}
flp->n_units += j;
for(i=n; i < n+j; i++)
for(k=0; k <= i; k++)
flp->wire_density[i][k] = flp->wire_density[k][i] = 0;
return j;
}
int floorplan(flp_t *flp, flp_desc_t *flp_desc,
RC_model_t *model, double *power)
{
NPE_t *expr, *next, *best;
tree_node_stack_t *stack;
tree_node_t *root;
double cost, new_cost, best_cost, sum_cost, T, Tcold;
int i, steps, downs, n, rejects, compacted, rim_blocks = 0;
int original_n = flp->n_units;
int wrap_l2;
double *tpower = hotspot_vector(model);
flp_config_t cfg = flp_desc->config;
if (cfg.model_rim)
flp->n_units = (flp->n_units - 2) / 3;
wrap_l2 = FALSE;
if (cfg.wrap_l2 &&
!strcasecmp(flp_desc->units[flp_desc->n_units-1].name, cfg.l2_label)) {
wrap_l2 = TRUE;
flp_desc->n_units--;
flp->n_units -= (L2_ARMS+1);
}
expr = NPE_get_initial(flp_desc);
stack = new_tree_node_stack();
init_rand();
root = tree_from_NPE(flp_desc, stack, expr);
compacted = tree_to_flp(root, flp, TRUE, cfg.compact_ratio);
trim_hotspot_vector(model, tpower, power, flp->n_units, compacted);
free_tree(root);
if(wrap_l2)
flp_wrap_l2(flp, flp_desc);
if(cfg.model_rim)
rim_blocks = flp_wrap_rim(flp, cfg.rim_thickness);
resize_thermal_model(model, flp->n_units);
#if VERBOSE > 2
print_flp(flp, TRUE);
#endif
cost = flp_evaluate_metric(flp, model, tpower, cfg.lambdaA, cfg.lambdaT, cfg.lambdaW);
restore_dead_blocks(flp, flp_desc, compacted, wrap_l2, cfg.model_rim, rim_blocks);
best = NPE_duplicate(expr);
best_cost = cost;
steps = 0;
T = -cfg.Davg / log(cfg.P0);
Tcold = -cfg.Davg / log ((1.0 - cfg.Rreject) / 2.0);
#if VERBOSE > 0
fprintf(stdout, "initial cost: %g\tinitial T: %g\tfinal T: %g\n", cost, T, Tcold);
#endif
while (T >= Tcold && steps < cfg.Nmax) {
n = cfg.Kmoves * flp->n_units;
i = downs = rejects = 0;
sum_cost = 0;
while ((i < 2 * n) && (downs < n)) {
next = make_random_move(expr);
root = tree_from_NPE(flp_desc, stack, next);
compacted = tree_to_flp(root, flp, TRUE, cfg.compact_ratio);
trim_hotspot_vector(model, tpower, power, flp->n_units, compacted);
free_tree(root);
if(wrap_l2)
flp_wrap_l2(flp, flp_desc);
if(cfg.model_rim)
rim_blocks = flp_wrap_rim(flp, cfg.rim_thickness);
resize_thermal_model(model, flp->n_units);
#if VERBOSE > 2
print_flp(flp, TRUE);
#endif
new_cost = flp_evaluate_metric(flp, model, tpower, cfg.lambdaA, cfg.lambdaT, cfg.lambdaW);
restore_dead_blocks(flp, flp_desc, compacted, wrap_l2, cfg.model_rim, rim_blocks);
#if VERBOSE > 1
fprintf(stdout, "count: %d\tdowns: %d\tcost: %g\t",
i, downs, new_cost);
#endif
if (new_cost < cost ||
rand_fraction() < exp(-(new_cost-cost)/T)) {
free_NPE(expr);
expr = next;
if (new_cost < cost) {
downs++;
if (new_cost < best_cost) {
free_NPE(best);
best = NPE_duplicate(expr);
best_cost = new_cost;
}
}
#if VERBOSE > 1
fprintf(stdout, "accepted\n");
#endif
cost = new_cost;
sum_cost += cost;
} else {
rejects++;
free_NPE(next);
#if VERBOSE > 1
fprintf(stdout, "rejected\n");
#endif
}
i++;
}
#if VERBOSE > 0
fprintf(stdout, "step: %d\tT: %g\ttries: %d\taccepts: %d\trejects: %d\t",
steps, T, i, (i-rejects), rejects);
fprintf(stdout, "avg. cost: %g\tbest cost: %g\n",
(i-rejects)?(sum_cost / (i-rejects)):sum_cost, best_cost);
#endif
if(((double)rejects/i) > cfg.Rreject)
break;
T *= cfg.Rcool;
steps++;
}
root = tree_from_NPE(flp_desc, stack, best);
#if VERBOSE > 0
{
int pos = min_area_pos(root->curve);
print_tree_relevant(root, pos, flp_desc);
}
#endif
compacted = tree_to_flp(root, flp, TRUE, cfg.compact_ratio);
trim_hotspot_vector(model, power, power, flp->n_units, compacted);
free_tree(root);
if(wrap_l2) {
flp_wrap_l2(flp, flp_desc);
flp_desc->n_units++;
}
if(cfg.model_rim)
rim_blocks = flp_wrap_rim(flp, cfg.rim_thickness);
resize_thermal_model(model, flp->n_units);
#if VERBOSE > 2
print_flp(flp, TRUE);
#endif
free_NPE(expr);
free_NPE(best);
free_tree_node_stack(stack);
free_dvector(tpower);
return (original_n - flp->n_units);
}
int flp_count_units(FILE *fp)
{
char str1[LINE_SIZE], str2[LINE_SIZE];
char name[STR_SIZE];
double leftx, bottomy, width, height;
double cp, res;
char *ptr;
int count = 0;
fseek(fp, 0, SEEK_SET);
while(!feof(fp)) {
fgets(str1, LINE_SIZE, fp);
if (feof(fp))
break;
strcpy(str2, str1);
ptr = strtok(str1, " \r\t\n");
if (!ptr || ptr[0] == '#')
continue;
if (sscanf(str2, "%s%lf%lf%lf%lf%lf%lf", name, &leftx, &bottomy,
&width, &height, &cp, &res) > 4)
count++;
}
return count;
}
flp_t *flp_alloc_init_mem(int count, int use_wire_density)
{
int i;
flp_t *flp;
flp = (flp_t *) calloc (1, sizeof(flp_t));
if(!flp)
fatal("memory allocation error\n");
flp->units = (unit_t *) calloc(count, sizeof(unit_t));
if(!flp->units)
fatal("memory allocation error\n");
if(use_wire_density) {
flp->wire_density = (double **) calloc(count, sizeof(double *));
if (!flp->wire_density)
fatal("memory allocation error\n");
for (i=0; i < count; i++) {
flp->wire_density[i] = (double *) calloc(count, sizeof(double));
if (!flp->wire_density[i])
fatal("memory allocation error\n");
}
}
flp->n_units = count;
return flp;
}
void flp_populate_blks(flp_t *flp, FILE *fp)
{
int i=0;
char str[LINE_SIZE], copy[LINE_SIZE];
char name1[STR_SIZE], name2[STR_SIZE];
double width, height, leftx, bottomy, cp, res, temp;
double wire_density;
char *ptr;
fseek(fp, 0, SEEK_SET);
while(!feof(fp)) {
fgets(str, LINE_SIZE, fp);
if (feof(fp))
break;
strcpy(copy, str);
ptr = strtok(str, " \r\t\n");
if (!ptr || ptr[0] == '#')
continue;
cp = res = 0.0;
if (sscanf(copy, "%s%lf%lf%lf%lf%lf%lf%lf", name1, &width, &height,
&leftx, &bottomy, &cp, &res, &temp) > 7)
fatal("invalid floorplan file format\n");
else if (sscanf(copy, "%s%lf%lf%lf%lf%lf%lf", name1, &width, &height,
&leftx, &bottomy, &cp, &res) == 7)
{
strcpy(flp->units[i].name, name1);
flp->units[i].width = width;
flp->units[i].height = height;
flp->units[i].leftx = leftx;
flp->units[i].bottomy = bottomy;
flp->units[i].specificheat = cp;
flp->units[i].resistivity = res;
flp->units[i].hasRes = TRUE;
flp->units[i].hasSh = TRUE;
i++;
}
else if(sscanf(copy, "%s%lf%lf%lf%lf%lf%lf", name1, &width, &height,
&leftx, &bottomy, &cp, &res) == 5)
{
strcpy(flp->units[i].name, name1);
flp->units[i].width = width;
flp->units[i].height = height;
flp->units[i].leftx = leftx;
flp->units[i].bottomy = bottomy;
flp->units[i].specificheat = 0.0;
flp->units[i].resistivity = 0.0;
flp->units[i].hasRes = FALSE;
flp->units[i].hasSh = FALSE;
i++;
}
else if(sscanf(copy, "%s%s%lf", name1, name2, &wire_density) != 3)
fatal("invalid floorplan file format\n");
}
if (i != flp->n_units)
fatal("mismatch of number of units\n");
}
void flp_populate_connects(flp_t *flp, FILE *fp)
{
char str1[LINE_SIZE], str2[LINE_SIZE];
char name1[STR_SIZE], name2[STR_SIZE];
double f1, f2, f3, f4, f5, f6;
double wire_density;
char *ptr;
int x, y, temp;
for(x=0; x < flp->n_units; x++)
for(y=0; y < flp->n_units; y++)
flp->wire_density[x][y] = 0.0;
fseek(fp, 0, SEEK_SET);
while(!feof(fp)) {
fgets(str1, LINE_SIZE, fp);
if (feof(fp))
break;
strcpy(str2, str1);
ptr = strtok(str1, " \r\t\n");
if (!ptr || ptr[0] == '#')
continue;
if (sscanf(str2, "%s%lf%lf%lf%lf%lf%lf", name1, &f1, &f2, &f3, &f4, &f5, &f6) == 7 ||
sscanf(str2, "%s%lf%lf%lf%d", name1, &f1, &f2, &f3, &temp) == 5)
continue;
else if (sscanf(str2, "%s%s%lf", name1, name2, &wire_density) == 3) {
x = get_blk_index(flp, name1);
y = get_blk_index(flp, name2);
if (x == y)
fatal("block connected to itself?\n");
if (!flp->wire_density[x][y] && !flp->wire_density[y][x])
flp->wire_density[x][y] = flp->wire_density[y][x] = wire_density;
else if((flp->wire_density[x][y] != flp->wire_density[y][x]) ||
(flp->wire_density[x][y] != wire_density)) {
sprintf(str2, "wrong connectivity information for blocks %s and %s\n",
name1, name2);
fatal(str2);
}
} else
fatal("invalid floorplan file format\n");
}
}
flp_t *read_flp(char *file, int read_connects, int initialize_connects)
{
char str[STR_SIZE];
FILE *fp;
flp_t *flp;
int count, i, j;
if (!strcasecmp(file, "stdin"))
fp = stdin;
else
fp = fopen (file, "r");
if (!fp) {
sprintf(str, "error opening file %s\n", file);
fatal(str);
}
count = flp_count_units(fp);
if(!count)
fatal("no units specified in the floorplan file\n");
flp = flp_alloc_init_mem(count, read_connects || initialize_connects);
flp_populate_blks(flp, fp);
if (read_connects)
flp_populate_connects(flp, fp);
else if(initialize_connects)
for (i=0; i < flp->n_units; i++)
for (j=0; j < flp->n_units; j++)
flp->wire_density[i][j] = 1.0;
if(fp != stdin)
fclose(fp);
flp_translate(flp, 0, 0);
return flp;
}
void dump_flp(flp_t *flp, char *file, int dump_connects)
{
char str[STR_SIZE];
int i, j;
FILE *fp;
if (!strcasecmp(file, "stdout"))
fp = stdout;
else if (!strcasecmp(file, "stderr"))
fp = stderr;
else
fp = fopen (file, "w");
if (!fp) {
sprintf(str, "error opening file %s\n", file);
fatal(str);
}
for(i=0; i < flp->n_units; i++) {
fprintf(fp, "%s\t%.11f\t%.11f\t%.11f\t%.11f\n",
flp->units[i].name, flp->units[i].width, flp->units[i].height,
flp->units[i].leftx, flp->units[i].bottomy);
}
if (dump_connects) {
fprintf(fp, "\n");
for(i=1; i < flp->n_units; i++)
for(j=0; j < i; j++)
if (flp->wire_density[i][j])
fprintf(fp, "%s\t%s\t%.3f\n", flp->units[i].name,
flp->units[j].name, flp->wire_density[i][j]);
}
if(fp != stdout && fp != stderr)
fclose(fp);
}
void free_flp(flp_t *flp, int compacted, int free_connects)
{
int i;
if(free_connects) {
for (i=0; i < flp->n_units + compacted; i++) {
free(flp->wire_density[i]);
}
free(flp->wire_density);
}
free(flp->units);
free(flp);
}
void print_flp_fig (flp_t *flp)
{
int i;
double leftx, bottomy, rightx, topy;
fprintf(stdout, "FIG starts\n");
for (i=0; i< flp->n_units; i++) {
leftx = flp->units[i].leftx;
bottomy = flp->units[i].bottomy;
rightx = flp->units[i].leftx + flp->units[i].width;
topy = flp->units[i].bottomy + flp->units[i].height;
fprintf(stdout, "%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f\n",
leftx, bottomy, leftx, topy, rightx, topy, rightx, bottomy,
leftx, bottomy);
fprintf(stdout, "%s\n", flp->units[i].name);
}
fprintf(stdout, "FIG ends\n");
}
void print_flp (flp_t *flp, int print_connects)
{
int i, j;
fprintf(stdout, "printing floorplan information for %d blocks\n", flp->n_units);
fprintf(stdout, "name\tarea\twidth\theight\tleftx\tbottomy\trightx\ttopy\n");
for (i=0; i< flp->n_units; i++) {
double area, width, height, leftx, bottomy, rightx, topy;
char *name;
name = flp->units[i].name;
width = flp->units[i].width;
height = flp->units[i].height;
area = width * height;
leftx = flp->units[i].leftx;
bottomy = flp->units[i].bottomy;
rightx = flp->units[i].leftx + flp->units[i].width;
topy = flp->units[i].bottomy + flp->units[i].height;
fprintf(stdout, "%s\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\t%lg\n",
name, area, width, height, leftx, bottomy, rightx, topy);
}
if(print_connects) {
fprintf(stdout, "printing connections:\n");
for (i=0; i< flp->n_units; i++)
for (j=i+1; j < flp->n_units; j++)
if (flp->wire_density[i][j])
fprintf(stdout, "%s\t%s\t%lg\n", flp->units[i].name,
flp->units[j].name, flp->wire_density[i][j]);
}
}
void print_flp_stats(flp_t *flp, RC_model_t *model,
char *l2_label, char *power_file,
char *connects_file)
{
double core, total, occupied;
double width, height, aspect, total_w, total_h;
double wire_metric;
double peak, avg;
double *power, *temp;
FILE *fp = NULL;
char str[STR_SIZE];
if (connects_file) {
fp = fopen(connects_file, "r");
if (!fp) {
sprintf(str, "error opening file %s\n", connects_file);
fatal(str);
}
flp_populate_connects(flp, fp);
}
power = hotspot_vector(model);
temp = hotspot_vector(model);
read_power(model, power, power_file);
core = get_core_area(flp, l2_label);
total = get_total_area(flp);
total_w = get_total_width(flp);
total_h = get_total_height(flp);
occupied = get_core_occupied_area(flp, l2_label);
width = get_core_width(flp, l2_label);
height = get_core_height(flp, l2_label);
aspect = (height > width) ? (height/width) : (width/height);
wire_metric = get_wire_metric(flp);
populate_R_model(model, flp);
steady_state_temp(model, power, temp);
peak = find_max_temp(model, temp);
avg = find_avg_temp(model, temp);
fprintf(stdout, "printing summary statistics about the floorplan\n");
fprintf(stdout, "total area:\t%g\n", total);
fprintf(stdout, "total width:\t%g\n", total_w);
fprintf(stdout, "total height:\t%g\n", total_h);
fprintf(stdout, "core area:\t%g\n", core);
fprintf(stdout, "occupied area:\t%g\n", occupied);
fprintf(stdout, "area utilization:\t%.3f\n", occupied / core * 100.0);
fprintf(stdout, "core width:\t%g\n", width);
fprintf(stdout, "core height:\t%g\n", height);
fprintf(stdout, "core aspect ratio:\t%.3f\n", aspect);
fprintf(stdout, "wire length metric:\t%.3f\n", wire_metric);
fprintf(stdout, "peak temperature:\t%.3f\n", peak);
fprintf(stdout, "avg temperature:\t%.3f\n", avg);
free_dvector(power);
free_dvector(temp);
if (fp)
fclose(fp);
}
int get_blk_index(flp_t *flp, char *name)
{
int i;
char msg[STR_SIZE];
if (!flp)
fatal("null pointer in get_blk_index\n");
for (i = 0; i < flp->n_units; i++) {
if (!strcasecmp(name, flp->units[i].name)) {
return i;
}
}
sprintf(msg, "block %s not found\n", name);
fatal(msg);
return -1;
}
int is_horiz_adj(flp_t *flp, int i, int j)
{
double x1, x2, x3, x4;
double y1, y2, y3, y4;
if (i == j)
return FALSE;
x1 = flp->units[i].leftx;
x2 = x1 + flp->units[i].width;
x3 = flp->units[j].leftx;
x4 = x3 + flp->units[j].width;
y1 = flp->units[i].bottomy;
y2 = y1 + flp->units[i].height;
y3 = flp->units[j].bottomy;
y4 = y3 + flp->units[j].height;
if (eq(x2,x3) && eq(y2,y3))
return FALSE;
if (eq(x1,x4) && eq(y1,y4))
return FALSE;
if (eq(x2,x3) && eq(y1,y4))
return FALSE;
if (eq(x1,x4) && eq(y2,y3))
return FALSE;
if (eq(x1,x4) || eq(x2,x3))
if ((y3 >= y1 && y3 <= y2) || (y4 >= y1 && y4 <= y2) ||
(y1 >= y3 && y1 <= y4) || (y2 >= y3 && y2 <= y4))
return TRUE;
return FALSE;
}
int is_vert_adj (flp_t *flp, int i, int j)
{
double x1, x2, x3, x4;
double y1, y2, y3, y4;
if (i == j)
return FALSE;
x1 = flp->units[i].leftx;
x2 = x1 + flp->units[i].width;
x3 = flp->units[j].leftx;
x4 = x3 + flp->units[j].width;
y1 = flp->units[i].bottomy;
y2 = y1 + flp->units[i].height;
y3 = flp->units[j].bottomy;
y4 = y3 + flp->units[j].height;
if (eq(x2,x3) && eq(y2,y3))
return FALSE;
if (eq(x1,x4) && eq(y1,y4))
return FALSE;
if (eq(x2,x3) && eq(y1,y4))
return FALSE;
if (eq(x1,x4) && eq(y2,y3))
return FALSE;
if (eq(y1,y4) || eq(y2,y3))
if ((x3 >= x1 && x3 <= x2) || (x4 >= x1 && x4 <= x2) ||
(x1 >= x3 && x1 <= x4) || (x2 >= x3 && x2 <= x4))
return TRUE;
return FALSE;
}
double get_shared_len(flp_t *flp, int i, int j)
{
double p11, p12, p21, p22;
p11 = p12 = p21 = p22 = 0.0;
if (i==j)
return FALSE;
if (is_horiz_adj(flp, i, j)) {
p11 = flp->units[i].bottomy;
p12 = p11 + flp->units[i].height;
p21 = flp->units[j].bottomy;
p22 = p21 + flp->units[j].height;
}
if (is_vert_adj(flp, i, j)) {
p11 = flp->units[i].leftx;
p12 = p11 + flp->units[i].width;
p21 = flp->units[j].leftx;
p22 = p21 + flp->units[j].width;
}
return (MIN(p12, p22) - MAX(p11, p21));
}
double get_total_width(flp_t *flp)
{
int i;
double min_x = flp->units[0].leftx;
double max_x = flp->units[0].leftx + flp->units[0].width;
for (i=1; i < flp->n_units; i++) {
if (flp->units[i].leftx < min_x)
min_x = flp->units[i].leftx;
if (flp->units[i].leftx + flp->units[i].width > max_x)
max_x = flp->units[i].leftx + flp->units[i].width;
}
return (max_x - min_x);
}
double get_total_height(flp_t *flp)
{
int i;
double min_y = flp->units[0].bottomy;
double max_y = flp->units[0].bottomy + flp->units[0].height;
for (i=1; i < flp->n_units; i++) {
if (flp->units[i].bottomy < min_y)
min_y = flp->units[i].bottomy;
if (flp->units[i].bottomy + flp->units[i].height > max_y)
max_y = flp->units[i].bottomy + flp->units[i].height;
}
return (max_y - min_y);
}
double get_minx(flp_t *flp)
{
int i;
double min_x = flp->units[0].leftx;
for (i=1; i < flp->n_units; i++)
if (flp->units[i].leftx < min_x)
min_x = flp->units[i].leftx;
return min_x;
}
double get_miny(flp_t *flp)
{
int i;
double min_y = flp->units[0].bottomy;
for (i=1; i < flp->n_units; i++)
if (flp->units[i].bottomy < min_y)
min_y = flp->units[i].bottomy;
return min_y;
}
double get_core_width(flp_t *flp, char *l2_label)
{
int i;
double min_x = LARGENUM;
double max_x = -LARGENUM;
for (i=0; i < flp->n_units; i++) {
if (strstr(flp->units[i].name, l2_label) != flp->units[i].name &&
strstr(flp->units[i].name, RIM_PREFIX) != flp->units[i].name) {
if (flp->units[i].leftx < min_x)
min_x = flp->units[i].leftx;
if (flp->units[i].leftx + flp->units[i].width > max_x)
max_x = flp->units[i].leftx + flp->units[i].width;
}
}
return (max_x - min_x);
}
double get_core_height(flp_t *flp, char *l2_label)
{
int i;
double min_y = LARGENUM;
double max_y = -LARGENUM;
for (i=0; i < flp->n_units; i++) {
if (strstr(flp->units[i].name, l2_label) != flp->units[i].name &&
strstr(flp->units[i].name, RIM_PREFIX) != flp->units[i].name) {
if (flp->units[i].bottomy < min_y)
min_y = flp->units[i].bottomy;
if (flp->units[i].bottomy + flp->units[i].height > max_y)
max_y = flp->units[i].bottomy + flp->units[i].height;
}
}
return (max_y - min_y);
}
double get_total_area(flp_t *flp)
{
int i;
double area = 0.0;
for(i=0; i < flp->n_units; i++)
area += flp->units[i].width * flp->units[i].height;
return area;
}
double get_core_area(flp_t *flp, char *l2_label)
{
int i;
double area = 0.0;
for(i=0; i < flp->n_units; i++)
if (strstr(flp->units[i].name, l2_label) != flp->units[i].name &&
strstr(flp->units[i].name, RIM_PREFIX) != flp->units[i].name)
area += flp->units[i].width * flp->units[i].height;
return area;
}
double get_core_occupied_area(flp_t *flp, char *l2_label)
{
int i, num;
double dead_area = 0.0;
for(i=0; i < flp->n_units; i++) {
if ((sscanf(flp->units[i].name, DEAD_PREFIX"%d", &num) == 1) &&
(num < (flp->n_units-1) / 2))
dead_area += flp->units[i].width * flp->units[i].height;
}
return get_core_area(flp, l2_label) - dead_area;
}
double get_wire_metric(flp_t *flp)
{
int i, j;
double w = 0.0, dist;
for (i=0; i < flp->n_units; i++)
for (j=0; j < flp->n_units; j++)
if (flp->wire_density[i][j]) {
dist = get_manhattan_dist(flp, i, j);
w += flp->wire_density[i][j] * dist;
}
return w;
}
double get_manhattan_dist(flp_t *flp, int i, int j)
{
double x1 = flp->units[i].leftx + flp->units[i].width / 2.0;
double y1 = flp->units[i].bottomy + flp->units[i].height / 2.0;
double x2 = flp->units[j].leftx + flp->units[j].width / 2.0;
double y2 = flp->units[j].bottomy + flp->units[j].height / 2.0;
return (fabs(x2-x1) + fabs(y2-y1));
}