/* populate connectivity info */ void flp_populate_connects(flp_t *flp, FILE *fp) { char str1[LINE_SIZE], str2[LINE_SIZE]; char name1[STR_SIZE], name2[STR_SIZE]; /* dummy fields */ double f1, f2, f3, f4, f5, f6; double wire_density; char *ptr; int x, y, temp; /* initialize wire_density */ 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); /* ignore comments and empty lines */ ptr = strtok(str1, " \r\t\n"); if (!ptr || ptr[0] == '#') continue; /* lines with unit positions */ if (sscanf(str2, "%s%lf%lf%lf%lf%lf%lf", name1, &f1, &f2, &f3, &f4, &f5, &f6) == 7 || /* flp_desc like lines. ignore them */ sscanf(str2, "%s%lf%lf%lf%d", name1, &f1, &f2, &f3, &temp) == 5) continue; /* lines with connectivity info */ 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"); } /* end while */ }
/* * read temperature vector alloced using 'hotspot_vector' from 'file' * which was dumped using 'dump_vector'. values are clipped to thermal * threshold based on 'clip' */ void read_temp(flp_t *flp, double *temp, char *file, int clip) { int i, idx; double max=0, val; char str[STR_SIZE], name[STR_SIZE]; FILE *fp = fopen (file, "r"); if (!fp) { sprintf (str,"error: %s could not be opened for reading\n", file); fatal(str); } /* find max temp on the chip */ for (i=0; i < flp->n_units; i++) { fgets(str, STR_SIZE, fp); if (feof(fp)) fatal("not enough lines in temperature file\n"); if (sscanf(str, "%s%lf", name, &val) != 2) fatal("invalid temperature file format\n"); idx = get_blk_index(flp, name); if (idx >= 0) temp[idx] = val; else /* since get_blk_index calls fatal, the line below cannot be reached */ fatal ("unit in temperature file not found in floorplan\n"); if (temp[idx] > max) max = temp[idx]; } /* internal node temperatures */ for (i=0; i < EXTRA; i++) { fgets(str, STR_SIZE, fp); if (feof(fp)) fatal("not enough lines in temperature file\n"); if (sscanf(str, "%s%lf", name, &val) != 2) fatal("invalid temperature file format\n"); sprintf(str, "inode_%d", i); if (strcasecmp(str, name)) fatal("invalid temperature file format\n"); temp[i+flp->n_units] = val; } fclose(fp); /* clipping */ if (clip && (max > thermal_threshold)) { /* if max has to be brought down to thermal_threshold, * (w.r.t the ambient) what is the scale down factor? */ double factor = (thermal_threshold - ambient) / (max - ambient); /* scale down all temperature differences (from ambient) by the same factor */ for (i=0; i < flp->n_units + EXTRA; i++) temp[i] = (temp[i]-ambient)*factor + ambient; } }
/* * read power vector alloced using 'hotspot_vector' from 'file' * which was dumped using 'dump_power'. */ void read_power_block (block_model_t *model, double *power, char *file) { flp_t *flp = model->flp; int idx; double val; char *ptr, str1[LINE_SIZE], str2[LINE_SIZE], name[STR_SIZE]; FILE *fp; if (!strcasecmp(file, "stdin")) fp = stdin; else fp = fopen (file, "r"); if (!fp) { sprintf (str1,"error: %s could not be opened for reading\n", file); fatal(str1); } while(!feof(fp)) { fgets(str1, LINE_SIZE, fp); if (feof(fp)) break; strcpy(str2, str1); /* ignore comments and empty lines */ ptr = strtok(str1, " \r\t\n"); if (!ptr || ptr[0] == '#') continue; if (sscanf(str2, "%s%lf", name, &val) != 2) fatal("invalid power file format\n"); idx = get_blk_index(flp, name); if (idx >= 0) power[idx] = val; else /* since get_blk_index calls fatal, the line below cannot be reached */ fatal ("unit in power file not found in floorplan\n"); } if(fp != stdin) fclose(fp); }
/* * main function - reads instantaneous power values (in W) from a trace * file (e.g. "gcc.ptrace") and outputs instantaneous temperature values (in C) to * a trace file("gcc.ttrace"). also outputs steady state temperature values * (including those of the internal nodes of the model) onto stdout. the * trace files are 2-d matrices with each column representing a functional * functional block and each row representing a time unit(sampling_intvl). * columns are tab-separated and each row is a separate line. the first * line contains the names of the functional blocks. the order in which * the columns are specified doesn't have to match that of the floorplan * file. */ int main(int argc, char **argv) { int i, j, idx, base = 0, count = 0, n = 0; int num, size, lines = 0, do_transient = TRUE; char **names; double *vals; /* trace file pointers */ FILE *pin, *tout = NULL; /* floorplan */ flp_t *flp; /* hotspot temperature model */ RC_model_t *model; /* instantaneous temperature and power values */ double *temp = NULL, *power; double total_power = 0.0; /* steady state temperature and power values */ double *overall_power, *steady_temp; /* thermal model configuration parameters */ thermal_config_t thermal_config; /* global configuration parameters */ global_config_t global_config; /* table to hold options and configuration */ str_pair table[MAX_ENTRIES]; /* variables for natural convection iterations */ int natural = 0; double avg_sink_temp = 0; int natural_convergence = 0; double r_convec_old; if (!(argc >= 5 && argc % 2)) { usage(argc, argv); return 1; } size = parse_cmdline(table, MAX_ENTRIES, argc, argv); global_config_from_strs(&global_config, table, size); /* no transient simulation, only steady state */ if(!strcmp(global_config.t_outfile, NULLFILE)) do_transient = FALSE; /* read configuration file */ if (strcmp(global_config.config, NULLFILE)) size += read_str_pairs(&table[size], MAX_ENTRIES, global_config.config); /* * earlier entries override later ones. so, command line options * have priority over config file */ size = str_pairs_remove_duplicates(table, size); /* get defaults */ thermal_config = default_thermal_config(); /* modify according to command line / config file */ thermal_config_add_from_strs(&thermal_config, table, size); /* if package model is used, run package model */ if (((idx = get_str_index(table, size, "package_model_used")) >= 0) && !(table[idx].value==0)) { if (thermal_config.package_model_used) { avg_sink_temp = thermal_config.ambient + SMALL_FOR_CONVEC; natural = package_model(&thermal_config, table, size, avg_sink_temp); if (thermal_config.r_convec<R_CONVEC_LOW || thermal_config.r_convec>R_CONVEC_HIGH) printf("Warning: Heatsink convection resistance is not realistic, double-check your package settings...\n"); } } /* dump configuration if specified */ if (strcmp(global_config.dump_config, NULLFILE)) { size = global_config_to_strs(&global_config, table, MAX_ENTRIES); size += thermal_config_to_strs(&thermal_config, &table[size], MAX_ENTRIES-size); /* prefix the name of the variable with a '-' */ dump_str_pairs(table, size, global_config.dump_config, "-"); } /* initialization: the flp_file global configuration * parameter is overridden by the layer configuration * file in the grid model when the latter is specified. */ flp = read_flp(global_config.flp_file, FALSE); /* allocate and initialize the RC model */ model = alloc_RC_model(&thermal_config, flp); populate_R_model(model, flp); if (do_transient) populate_C_model(model, flp); #if VERBOSE > 2 debug_print_model(model); #endif /* allocate the temp and power arrays */ /* using hotspot_vector to internally allocate any extra nodes needed */ if (do_transient) temp = hotspot_vector(model); power = hotspot_vector(model); steady_temp = hotspot_vector(model); overall_power = hotspot_vector(model); /* set up initial instantaneous temperatures */ if (do_transient && strcmp(model->config->init_file, NULLFILE)) { if (!model->config->dtm_used) /* initial T = steady T for no DTM */ read_temp(model, temp, model->config->init_file, FALSE); else /* initial T = clipped steady T with DTM */ read_temp(model, temp, model->config->init_file, TRUE); } else if (do_transient) /* no input file - use init_temp as the common temperature */ set_temp(model, temp, model->config->init_temp); /* n is the number of functional blocks in the block model * while it is the sum total of the number of functional blocks * of all the floorplans in the power dissipating layers of the * grid model. */ if (model->type == BLOCK_MODEL) n = model->block->flp->n_units; else if (model->type == GRID_MODEL) { for(i=0; i < model->grid->n_layers; i++) if (model->grid->layers[i].has_power) n += model->grid->layers[i].flp->n_units; } else fatal("unknown model type\n"); if(!(pin = fopen(global_config.p_infile, "r"))) fatal("unable to open power trace input file\n"); if(do_transient && !(tout = fopen(global_config.t_outfile, "w"))) fatal("unable to open temperature trace file for output\n"); /* names of functional units */ names = alloc_names(MAX_UNITS, STR_SIZE); if(read_names(pin, names) != n) fatal("no. of units in floorplan and trace file differ\n"); /* header line of temperature trace */ if (do_transient) write_names(tout, names, n); /* read the instantaneous power trace */ vals = dvector(MAX_UNITS); while ((num=read_vals(pin, vals)) != 0) { if(num != n) fatal("invalid trace file format\n"); /* permute the power numbers according to the floorplan order */ if (model->type == BLOCK_MODEL) for(i=0; i < n; i++) power[get_blk_index(flp, names[i])] = vals[i]; else for(i=0, base=0, count=0; i < model->grid->n_layers; i++) { if(model->grid->layers[i].has_power) { for(j=0; j < model->grid->layers[i].flp->n_units; j++) { idx = get_blk_index(model->grid->layers[i].flp, names[count+j]); power[base+idx] = vals[count+j]; } count += model->grid->layers[i].flp->n_units; } base += model->grid->layers[i].flp->n_units; } /* compute temperature */ if (do_transient) { /* if natural convection is considered, update transient convection resistance first */ if (natural) { avg_sink_temp = calc_sink_temp(model, temp); natural = package_model(model->config, table, size, avg_sink_temp); populate_R_model(model, flp); } /* for the grid model, only the first call to compute_temp * passes a non-null 'temp' array. if 'temp' is NULL, * compute_temp remembers it from the last non-null call. * this is used to maintain the internal grid temperatures * across multiple calls of compute_temp */ if (model->type == BLOCK_MODEL || lines == 0) compute_temp(model, power, temp, model->config->sampling_intvl); else compute_temp(model, power, NULL, model->config->sampling_intvl); /* permute back to the trace file order */ if (model->type == BLOCK_MODEL) for(i=0; i < n; i++) vals[i] = temp[get_blk_index(flp, names[i])]; else for(i=0, base=0, count=0; i < model->grid->n_layers; i++) { if(model->grid->layers[i].has_power) { for(j=0; j < model->grid->layers[i].flp->n_units; j++) { idx = get_blk_index(model->grid->layers[i].flp, names[count+j]); vals[count+j] = temp[base+idx]; } count += model->grid->layers[i].flp->n_units; } base += model->grid->layers[i].flp->n_units; } /* output instantaneous temperature trace */ write_vals(tout, vals, n); } /* for computing average */ if (model->type == BLOCK_MODEL) for(i=0; i < n; i++) overall_power[i] += power[i]; else for(i=0, base=0; i < model->grid->n_layers; i++) { if(model->grid->layers[i].has_power) for(j=0; j < model->grid->layers[i].flp->n_units; j++) overall_power[base+j] += power[base+j]; base += model->grid->layers[i].flp->n_units; } lines++; } if(!lines) fatal("no power numbers in trace file\n"); /* for computing average */ if (model->type == BLOCK_MODEL) for(i=0; i < n; i++) { overall_power[i] /= lines; //overall_power[i] /=150; //reduce input power for natural convection total_power += overall_power[i]; } else for(i=0, base=0; i < model->grid->n_layers; i++) { if(model->grid->layers[i].has_power) for(j=0; j < model->grid->layers[i].flp->n_units; j++) { overall_power[base+j] /= lines; total_power += overall_power[base+j]; } base += model->grid->layers[i].flp->n_units; } /* natural convection r_convec iteration, for steady-state only */ natural_convergence = 0; if (natural) { /* natural convection is used */ while (!natural_convergence) { r_convec_old = model->config->r_convec; /* steady state temperature */ steady_state_temp(model, overall_power, steady_temp); avg_sink_temp = calc_sink_temp(model, steady_temp) + SMALL_FOR_CONVEC; natural = package_model(model->config, table, size, avg_sink_temp); populate_R_model(model, flp); if (avg_sink_temp > MAX_SINK_TEMP) fatal("too high power for a natural convection package -- possible thermal runaway\n"); if (fabs(model->config->r_convec-r_convec_old)<NATURAL_CONVEC_TOL) natural_convergence = 1; } } else /* natural convection is not used, no need for iterations */ /* steady state temperature */ steady_state_temp(model, overall_power, steady_temp); /* print steady state results */ fprintf(stdout, "Unit\tSteady(Kelvin)\n"); dump_temp(model, steady_temp, "stdout"); /* dump steady state temperatures on to file if needed */ if (strcmp(model->config->steady_file, NULLFILE)) dump_temp(model, steady_temp, model->config->steady_file); /* for the grid model, optionally dump the most recent * steady state temperatures of the grid cells */ if (model->type == GRID_MODEL && strcmp(model->config->grid_steady_file, NULLFILE)) dump_steady_temp_grid(model->grid, model->config->grid_steady_file); #if VERBOSE > 2 if (model->type == BLOCK_MODEL) { if (do_transient) { fprintf(stdout, "printing temp...\n"); dump_dvector(temp, model->block->n_nodes); } fprintf(stdout, "printing steady_temp...\n"); dump_dvector(steady_temp, model->block->n_nodes); } else { if (do_transient) { fprintf(stdout, "printing temp...\n"); dump_dvector(temp, model->grid->total_n_blocks + EXTRA); } fprintf(stdout, "printing steady_temp...\n"); dump_dvector(steady_temp, model->grid->total_n_blocks + EXTRA); } #endif /* cleanup */ fclose(pin); if (do_transient) fclose(tout); delete_RC_model(model); free_flp(flp, FALSE); if (do_transient) free_dvector(temp); free_dvector(power); free_dvector(steady_temp); free_dvector(overall_power); free_names(names); free_dvector(vals); return 0; }
/* * read temperature vector alloced using 'hotspot_vector' from 'file' * which was dumped using 'dump_temp'. values are clipped to thermal * threshold based on 'clip' */ void read_temp_block(block_model_t *model, double *temp, char *file, int clip) { /* shortcuts */ flp_t *flp = model->flp; double thermal_threshold = model->config.thermal_threshold; double ambient = model->config.ambient; int i, n, idx; double max=0, val; char *ptr, str1[LINE_SIZE], str2[LINE_SIZE]; char name[STR_SIZE], format[STR_SIZE]; FILE *fp; if (!strcasecmp(file, "stdin")) fp = stdin; else fp = fopen (file, "r"); if (!fp) { sprintf (str1,"error: %s could not be opened for reading\n", file); fatal(str1); } /* temperatures of the different layers */ for (n=0; n < NL; n++) { switch(n) { case 0: strcpy(format,"%s%lf"); break; case IFACE: strcpy(format,"iface_%s%lf"); break; case HSP: strcpy(format,"hsp_%s%lf"); break; case HSINK: strcpy(format,"hsink_%s%lf"); break; default: fatal("unknown layer\n"); break; } for (i=0; i < flp->n_units; i++) { fgets(str1, LINE_SIZE, fp); if (feof(fp)) fatal("not enough lines in temperature file\n"); strcpy(str2, str1); /* ignore comments and empty lines */ ptr = strtok(str1, " \r\t\n"); if (!ptr || ptr[0] == '#') { i--; continue; } if (sscanf(str2, format, name, &val) != 2) fatal("invalid temperature file format\n"); idx = get_blk_index(flp, name); if (idx >= 0) temp[idx + n*flp->n_units] = val; else /* since get_blk_index calls fatal, the line below cannot be reached */ fatal ("unit in temperature file not found in floorplan\n"); /* find max temp on the chip */ if (n == 0 && temp[idx] > max) max = temp[idx]; } } /* internal node temperatures */ for (i=0; i < EXTRA; i++) { fgets(str1, LINE_SIZE, fp); if (feof(fp)) fatal("not enough lines in temperature file\n"); strcpy(str2, str1); /* ignore comments and empty lines */ ptr = strtok(str1, " \r\t\n"); if (!ptr || ptr[0] == '#') { i--; continue; } if (sscanf(str2, "%s%lf", name, &val) != 2) fatal("invalid temperature file format\n"); sprintf(str1, "inode_%d", i); if (strcasecmp(str1, name)) fatal("invalid temperature file format\n"); temp[i+NL*flp->n_units] = val; } fgets(str1, LINE_SIZE, fp); if (!feof(fp)) fatal("too many lines in temperature file\n"); if(fp != stdin) fclose(fp); /* clipping */ if (clip && (max > thermal_threshold)) { /* if max has to be brought down to thermal_threshold, * (w.r.t the ambient) what is the scale down factor? */ double factor = (thermal_threshold - ambient) / (max - ambient); /* scale down all temperature differences (from ambient) by the same factor */ for (i=0; i < NL*flp->n_units + EXTRA; i++) temp[i] = (temp[i]-ambient)*factor + ambient; } }