/* make a random move out of the above */ NPE_t *make_random_move(NPE_t *expr) { int i, move, count = 0, done = FALSE, m3_count; NPE_t *copy = NPE_duplicate(expr); while (!done && count < MAX_MOVES) { /* choose one of three moves */ move = rand_upto(3); switch(move) { case 0: /* swap adjacent units */ /* leave the unit last in the NPE */ i = rand_upto(expr->n_units-1); #if VERBOSE > 2 fprintf(stdout, "making M1 at %d\n", expr->unit_pos[i]); #endif NPE_swap_units(copy, expr->unit_pos[i]); done = TRUE; break; case 1: /* invert an arbitrary chain */ i = rand_upto(expr->n_chains); #if VERBOSE > 2 fprintf(stdout, "making M2 at %d\n", expr->chain_pos[i]); #endif NPE_invert_chain(copy, expr->chain_pos[i]); done = TRUE; break; case 2: /* swap a unit and an adjacent cut_type */ m3_count = 0; while (!done && m3_count < MAX_MOVES) { i = rand_upto(expr->n_flips); #if VERBOSE > 2 fprintf(stdout, "making M3 at %d\n", expr->flip_pos[i]); #endif done = NPE_swap_cut_unit(copy, expr->flip_pos[i]); m3_count++; } break; default: fatal("unknown move type\n"); break; } count++; } if (count == MAX_MOVES) { char msg[STR_SIZE]; sprintf(msg, "tried %d moves, now giving up\n", MAX_MOVES); fatal(msg); } return copy; }
/* * floorplanning using simulated annealing. * precondition: flp is a pre-allocated placeholder. * returns the number of compacted blocks in the selected * floorplan */ int floorplan(flp_t *flp, flp_desc_t *flp_desc, RC_model_t *model, double *power) { NPE_t *expr, *next, *best; /* Normalized Polish Expressions */ tree_node_stack_t *stack; /* for NPE evaluation */ tree_node_t *root; /* shape curve tree */ 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; /* to maintain the order of power values during * the compaction/shifting around of blocks */ double *tpower = hotspot_vector(model); /* shortcut */ flp_config_t cfg = flp_desc->config; /* * make the rim strips disappear for slicing tree * purposes. can be restored at the end */ if (cfg.model_rim) flp->n_units = (flp->n_units - 2) / 3; /* wrap L2 around? */ wrap_l2 = FALSE; if (cfg.wrap_l2 && !strcasecmp(flp_desc->units[flp_desc->n_units-1].name, cfg.l2_label)) { wrap_l2 = TRUE; /* make L2 disappear too */ flp_desc->n_units--; flp->n_units -= (L2_ARMS+1); } /* initialization */ expr = NPE_get_initial(flp_desc); stack = new_tree_node_stack(); init_rand(); /* convert NPE to flp */ root = tree_from_NPE(flp_desc, stack, expr); /* compacts too small dead blocks */ compacted = tree_to_flp(root, flp, TRUE, cfg.compact_ratio); /* update the tpower vector according to the compaction */ 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); #endif cost = flp_evaluate_metric(flp, model, tpower, cfg.lambdaA, cfg.lambdaT, cfg.lambdaW); /* restore the compacted blocks */ restore_dead_blocks(flp, flp_desc, compacted, wrap_l2, cfg.model_rim, rim_blocks); best = NPE_duplicate(expr); /* best till now */ best_cost = cost; /* simulated annealing */ steps = 0; /* initial annealing temperature */ T = -cfg.Davg / log(cfg.P0); /* * final annealing temperature - we stop when there * are fewer than (1-cfg.Rreject) accepts. * of those accepts, assuming half are uphill moves, * we want the temperature so that the probability * of accepting uphill moves is as low as * (1-cfg.Rreject)/2. */ 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 /* * stop annealing if temperature has cooled down enough or * max no. of iterations have been tried */ while (T >= Tcold && steps < cfg.Nmax) { /* shortcut */ n = cfg.Kmoves * flp->n_units; i = downs = rejects = 0; sum_cost = 0; /* try enough total or downhill moves per T */ while ((i < 2 * n) && (downs < n)) { next = make_random_move(expr); /* convert NPE to flp */ root = tree_from_NPE(flp_desc, stack, next); compacted = tree_to_flp(root, flp, TRUE, cfg.compact_ratio); /* update the tpower vector according to the compaction */ 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); #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 /* move accepted? */ if (new_cost < cost || /* downhill always accepted */ /* boltzmann probability function */ rand_fraction() < exp(-(new_cost-cost)/T)) { free_NPE(expr); expr = next; /* downhill move */ if (new_cost < cost) { downs++; /* found new best */ 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 { /* rejected move */ 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 /* stop annealing if there are too little accepts */ if(((double)rejects/i) > cfg.Rreject) break; /* annealing schedule */ T *= cfg.Rcool; steps++; } /* best floorplan found */ 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); /* update the power vector according to the compaction */ trim_hotspot_vector(model, power, power, flp->n_units, compacted); free_tree(root); /* restore L2 and rim */ 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); #endif free_NPE(expr); free_NPE(best); free_tree_node_stack(stack); free_dvector(tpower); /* * return the number of blocks compacted finally * so that any deallocator can take care of memory * accordingly. */ return (original_n - flp->n_units); }