forked from uvahotspot/HotSpot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhotspot.c
596 lines (531 loc) · 22.7 KB
/
hotspot.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
/*
* This is a trace-level thermal simulator. It reads power values
* from an input trace file and outputs the corresponding instantaneous
* temperature values to an output trace file. It also outputs the steady
* state temperature values to stdout.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "flp.h"
#include "package.h"
#include "temperature.h"
#include "temperature_block.h"
#include "temperature_grid.h"
#include "util.h"
#include "hotspot.h"
/* HotSpot thermal model is offered in two flavours - the block
* version and the grid version. The block model models temperature
* per functional block of the floorplan while the grid model
* chops the chip up into a matrix of grid cells and models the
* temperature of each cell. It is also capable of modeling a
* 3-d chip with multiple floorplans stacked on top of each
* other. The choice of which model to choose is done through
* a command line or configuration file parameter model_type.
* "-model_type block" chooses the block model while "-model_type grid"
* chooses the grid model.
*/
/* Guidelines for choosing the block or the grid model */
/**************************************************************************/
/* HotSpot contains two methods for solving temperatures: */
/* 1) Block Model -- the same as HotSpot 2.0 */
/* 2) Grid Model -- the die is divided into regular grid cells */
/**************************************************************************/
/* How the grid model works: */
/* The grid model first reads in floorplan and maps block-based power */
/* to each grid cell, then solves the temperatures for all the grid cells,*/
/* finally, converts the resulting grid temperatures back to block-based */
/* temperatures. */
/**************************************************************************/
/* The grid model is useful when */
/* 1) More detailed temperature distribution inside a functional unit */
/* is desired. */
/* 2) Too many functional units are included in the floorplan, resulting */
/* in extremely long computation time if using the Block Model */
/* 3) If temperature information is desired for many tiny units, */
/* such as individual register file entry. */
/**************************************************************************/
/* Comparisons between Grid Model and Block Model: */
/* In general, the grid model is more accurate, because it can deal */
/* with various floorplans and it provides temperature gradient across */
/* each functional unit. The block model models essentially the center */
/* temperature of each functional unit. But the block model is typically */
/* faster because there are less nodes to solve. */
/* Therefore, unless it is the case where the grid model is */
/* definitely needed, we suggest using the block model for computation */
/* efficiency. */
/**************************************************************************/
void usage(int argc, char **argv)
{
fprintf(stdout, "Usage: %s -f <file> -p <file> [-o <file>] [-c <file>] [-d <file>] [options]\n", argv[0]);
fprintf(stdout, "A thermal simulator that reads power trace from a file and outputs temperatures.\n");
fprintf(stdout, "Options:(may be specified in any order, within \"[]\" means optional)\n");
fprintf(stdout, " -f <file>\tfloorplan input file (e.g. ev6.flp) - overridden by the\n");
fprintf(stdout, " \tlayer configuration file (e.g. layer.lcf) when the\n");
fprintf(stdout, " \tlatter is specified\n");
fprintf(stdout, " -p <file>\tpower trace input file (e.g. gcc.ptrace)\n");
fprintf(stdout, " [-o <file>]\ttransient temperature trace output file - if not provided, only\n");
fprintf(stdout, " \tsteady state temperatures are output to stdout\n");
fprintf(stdout, " [-c <file>]\tinput configuration parameters from file (e.g. hotspot.config)\n");
fprintf(stdout, " [-d <file>]\toutput configuration parameters to file\n");
fprintf(stdout, " [options]\tzero or more options of the form \"-<name> <value>\",\n");
fprintf(stdout, " \toverride the options from config file. e.g. \"-model_type block\" selects\n");
fprintf(stdout, " \tthe block model while \"-model_type grid\" selects the grid model\n");
fprintf(stdout, " [-detailed_3D <on/off]>\tHeterogeneous R-C assignments for specified layers. Requires a .lcf file to be specified\n"); //BU_3D: added detailed_3D option
}
/*
* parse a table of name-value string pairs and add the configuration
* parameters to 'config'
*/
void global_config_from_strs(global_config_t *config, str_pair *table, int size)
{
int idx;
if ((idx = get_str_index(table, size, "f")) >= 0) {
if(sscanf(table[idx].value, "%s", config->flp_file) != 1)
fatal("invalid format for configuration parameter flp_file\n");
} else {
fatal("required parameter flp_file missing. check usage\n");
}
if ((idx = get_str_index(table, size, "p")) >= 0) {
if(sscanf(table[idx].value, "%s", config->p_infile) != 1)
fatal("invalid format for configuration parameter p_infile\n");
} else {
fatal("required parameter p_infile missing. check usage\n");
}
if ((idx = get_str_index(table, size, "o")) >= 0) {
if(sscanf(table[idx].value, "%s", config->t_outfile) != 1)
fatal("invalid format for configuration parameter t_outfile\n");
} else {
strcpy(config->t_outfile, NULLFILE);
}
if ((idx = get_str_index(table, size, "c")) >= 0) {
if(sscanf(table[idx].value, "%s", config->config) != 1)
fatal("invalid format for configuration parameter config\n");
} else {
strcpy(config->config, NULLFILE);
}
if ((idx = get_str_index(table, size, "d")) >= 0) {
if(sscanf(table[idx].value, "%s", config->dump_config) != 1)
fatal("invalid format for configuration parameter dump_config\n");
} else {
strcpy(config->dump_config, NULLFILE);
}
if ((idx = get_str_index(table, size, "detailed_3D")) >= 0) {
if(sscanf(table[idx].value, "%s", config->detailed_3D) != 1)
fatal("invalid format for configuration parameter lc\n");
} else {
strcpy(config->detailed_3D, "off");
}
}
/*
* convert config into a table of name-value pairs. returns the no.
* of parameters converted
*/
int global_config_to_strs(global_config_t *config, str_pair *table, int max_entries)
{
if (max_entries < 6)
fatal("not enough entries in table\n");
sprintf(table[0].name, "f");
sprintf(table[1].name, "p");
sprintf(table[2].name, "o");
sprintf(table[3].name, "c");
sprintf(table[4].name, "d");
sprintf(table[5].name, "detailed_3D");
sprintf(table[0].value, "%s", config->flp_file);
sprintf(table[1].value, "%s", config->p_infile);
sprintf(table[2].value, "%s", config->t_outfile);
sprintf(table[3].value, "%s", config->config);
sprintf(table[4].value, "%s", config->dump_config);
sprintf(table[5].value, "%s", config->detailed_3D);
return 6;
}
/*
* read a single line of trace file containing names
* of functional blocks
*/
int read_names(FILE *fp, char **names)
{
char line[LINE_SIZE], temp[LINE_SIZE], *src;
int i;
/* skip empty lines */
do {
/* read the entire line */
fgets(line, LINE_SIZE, fp);
if (feof(fp))
fatal("not enough names in trace file\n");
strcpy(temp, line);
src = strtok(temp, " \r\t\n");
} while (!src);
/* new line not read yet */
if(line[strlen(line)-1] != '\n')
fatal("line too long\n");
/* chop the names from the line read */
for(i=0,src=line; *src && i < MAX_UNITS; i++) {
if(!sscanf(src, "%s", names[i]))
fatal("invalid format of names\n");
src += strlen(names[i]);
while (isspace((int)*src))
src++;
}
if(*src && i == MAX_UNITS)
fatal("no. of units exceeded limit\n");
return i;
}
/* read a single line of power trace numbers */
int read_vals(FILE *fp, double *vals)
{
char line[LINE_SIZE], temp[LINE_SIZE], *src;
int i;
/* skip empty lines */
do {
/* read the entire line */
fgets(line, LINE_SIZE, fp);
if (feof(fp))
return 0;
strcpy(temp, line);
src = strtok(temp, " \r\t\n");
} while (!src);
/* new line not read yet */
if(line[strlen(line)-1] != '\n')
fatal("line too long\n");
/* chop the power values from the line read */
for(i=0,src=line; *src && i < MAX_UNITS; i++) {
if(!sscanf(src, "%s", temp) || !sscanf(src, "%lf", &vals[i]))
fatal("invalid format of values\n");
src += strlen(temp);
while (isspace((int)*src))
src++;
}
if(*src && i == MAX_UNITS)
fatal("no. of entries exceeded limit\n");
return i;
}
/* write a single line of functional unit names */
void write_names(FILE *fp, char **names, int size)
{
int i;
for(i=0; i < size-1; i++)
fprintf(fp, "%s\t", names[i]);
fprintf(fp, "%s\n", names[i]);
}
/* write a single line of temperature trace(in degree C) */
void write_vals(FILE *fp, double *vals, int size)
{
int i;
for(i=0; i < size-1; i++)
fprintf(fp, "%.2f\t", vals[i]-273.15);
fprintf(fp, "%.2f\n", vals[i]-273.15);
}
char **alloc_names(int nr, int nc)
{
int i;
char **m;
m = (char **) calloc (nr, sizeof(char *));
assert(m != NULL);
m[0] = (char *) calloc (nr * nc, sizeof(char));
assert(m[0] != NULL);
for (i = 1; i < nr; i++)
m[i] = m[0] + nc * i;
return m;
}
void free_names(char **m)
{
free(m[0]);
free(m);
}
/*
* 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;
/*BU_3D: variable for heterogenous R-C model */
int do_detailed_3D = FALSE; //BU_3D: do_detailed_3D, false by default
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);
/* BU_3D: check if heterogenous R-C modeling is on */
if(!strcmp(global_config.detailed_3D, "on")){
do_detailed_3D = TRUE;
}
else if(strcmp(global_config.detailed_3D, "off")){
fatal("detailed_3D parameter should be either \'on\' or \'off\'\n");
}//end->BU_3D
/* 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);
//BU_3D: added do_detailed_3D to alloc_RC_model. Detailed 3D modeling can only be used with grid-level modeling.
/* allocate and initialize the RC model */
model = alloc_RC_model(&thermal_config, flp, do_detailed_3D);
if (model->type == BLOCK_MODEL && do_detailed_3D)
fatal("Detailed 3D option can only be used with grid model\n"); //end->BU_3D
if ((model->type == GRID_MODEL) && !model->grid->has_lcf && do_detailed_3D)
fatal("Detailed 3D option can only be used in 3D mode\n");
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;
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 */
//BU_3D: Only print steady state results to stdout when DEBUG3D flag is not set
#if DEBUG3D < 1
fprintf(stdout, "Unit\tSteady(Kelvin)\n");
dump_temp(model, steady_temp, "stdout");
#endif //end->BU_3D
/* 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;
}