1 /* Copyright (C) 2021 Free Software Foundation, Inc. 2 Contributed by Oracle. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 #include "config.h" 22 #include <stdlib.h> 23 #include <ctype.h> 24 #include <string.h> 25 #include <math.h> 26 #include <assert.h> 27 #include <libintl.h> 28 #include <unistd.h> 29 #include <stdio.h> 30 #include <fcntl.h> 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 34 #include "util.h" 35 #include "Dbe.h" 36 #include "StringBuilder.h" 37 #include "DbeSession.h" 38 #include "DbeView.h" 39 #include "Settings.h" 40 #include "Print.h" 41 #include "DbeView.h" 42 #include "Experiment.h" 43 #include "MetricList.h" 44 #include "Module.h" 45 #include "Function.h" 46 #include "DataSpace.h" 47 #include "DataObject.h" 48 #include "FilterExp.h" 49 #include "LoadObject.h" 50 #include "Emsg.h" 51 #include "Table.h" 52 #include "DbeFile.h" 53 #include "CallStack.h" 54 55 int 56 er_print_common_display::open (Print_params *params) 57 { 58 pr_params = *params; 59 pr_params.name = dbe_strdup (params->name); 60 if (params->dest == DEST_PRINTER) 61 { 62 tmp_file = dbeSession->get_tmp_file_name (NTXT ("print"), false); 63 dbeSession->tmp_files->append (strdup (tmp_file)); 64 out_file = fopen (tmp_file, NTXT ("w")); 65 } 66 else if (params->dest == DEST_OPEN_FILE) 67 out_file = pr_params.openfile; 68 else 69 out_file = fopen (pr_params.name, NTXT ("w")); 70 71 if (out_file == NULL) 72 // Failure 73 return 1; 74 return 0; 75 } 76 77 bool 78 er_print_common_display::print_output () 79 { 80 char *sys_call; 81 bool ret = true; 82 if (pr_params.dest != DEST_OPEN_FILE) 83 fclose (out_file); 84 85 if (pr_params.dest == DEST_PRINTER) 86 { 87 if (streq ((char *) pr_params.name, NTXT (""))) 88 sys_call = dbe_sprintf ("(/usr/bin/lp -c -n%d %s) 2>/dev/null 1>&2", 89 pr_params.ncopies, tmp_file); 90 else 91 sys_call = dbe_sprintf ("(/usr/bin/lp -c -d%s -n%d %s) 2>/dev/null 1>&2", 92 pr_params.name, pr_params.ncopies, tmp_file); 93 if (system (sys_call) != 0) 94 ret = false; 95 unlink (tmp_file); 96 free (sys_call); 97 } 98 99 return ret; 100 } 101 102 // Return the report. If the report size is greater than max, return truncated report 103 // Allocates memory, so the caller should free this memory. 104 105 char * 106 er_print_common_display::get_output (int maxsize) 107 { 108 off_t max = (off_t) maxsize; 109 if (out_file != (FILE *) NULL) 110 { 111 fclose (out_file); // close tmp_file 112 out_file = (FILE *) NULL; 113 } 114 struct stat sbuf; 115 int st = stat (tmp_file, &sbuf); 116 if (st == 0) 117 { 118 off_t sz = sbuf.st_size; 119 if (sz > max) 120 return dbe_sprintf (GTXT ("Error: report is too long.\n")); 121 if (sz <= 0) 122 return dbe_sprintf (GTXT ("Error: empty temporary file: %s\n"), 123 tmp_file); 124 max = sz; 125 } 126 127 FILE *f = fopen (tmp_file, "r"); 128 if (f == NULL) 129 return dbe_sprintf (GTXT ("Error: cannot open temporary file: %s\n"), 130 tmp_file); 131 char *report = (char *) malloc (max); 132 if (report) 133 { 134 if (1 != fread (report, max - 1, 1, f)) 135 { 136 fclose (f); 137 free (report); 138 return dbe_sprintf (GTXT ("Error: cannot read temporary file: %s\n"), 139 tmp_file); 140 } 141 report[max - 1] = 0; 142 } 143 fclose (f); 144 return report; 145 } 146 147 void 148 er_print_common_display::header_dump (int exp_idx) 149 { 150 if (load && (exp_idx == exp_idx1)) 151 { 152 load = false; 153 print_load_object (out_file); 154 } 155 print_header (dbeSession->get_exp (exp_idx), out_file); 156 } 157 158 char * 159 pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead) 160 { 161 int size, i; 162 LoadObject *lo; 163 Emsg *m; 164 char *msg; 165 StringBuilder sb; 166 char *lo_name; 167 size = loadobjects->size (); 168 for (i = 0; i < size; i++) 169 { 170 lo = loadobjects->fetch (i); 171 lo_name = lo->get_name (); 172 if (lo_name != NULL) 173 { 174 size_t len = strlen (lo_name); 175 if (len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) 176 continue; 177 } 178 179 // print the segment name 180 sb.append (lead); 181 sb.append (NTXT (" ")); 182 sb.append (lo->get_name ()); 183 sb.append (NTXT (" (")); 184 sb.append (lo->get_pathname ()); 185 sb.append (NTXT (")\n")); 186 187 // and any warnings 188 m = lo->fetch_warnings (); 189 if (m != NULL) 190 { 191 msg = pr_mesgs (m, NULL, NTXT (" ")); 192 sb.append (msg); 193 free (msg); 194 } 195 } 196 return sb.toString (); 197 } 198 199 char * 200 pr_mesgs (Emsg *msg, const char *null_str, const char *lead) 201 { 202 Emsg *m; 203 StringBuilder sb; 204 if (msg == NULL) 205 return dbe_strdup (null_str); 206 for (m = msg; m; m = m->next) 207 { 208 sb.append (lead); 209 sb.append (m->get_msg ()); 210 sb.append (NTXT ("\n")); 211 } 212 return sb.toString (); 213 } 214 215 void 216 print_load_object (FILE *out_file) 217 { 218 Vector<LoadObject*> *loadobjects = dbeSession->get_text_segments (); 219 char *msg = pr_load_objects (loadobjects, NTXT ("\t")); 220 fprintf (out_file, GTXT ("Load Object Coverage:\n")); 221 fprintf (out_file, NTXT ("%s"), msg); 222 fprintf (out_file, 223 "----------------------------------------------------------------\n"); 224 free (msg); 225 delete loadobjects; 226 } 227 228 void 229 print_header (Experiment *exp, FILE *out_file) 230 { 231 fprintf (out_file, GTXT ("Experiment: %s\n"), exp->get_expt_name ()); 232 char *msg = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT ("")); 233 fprintf (out_file, NTXT ("%s"), msg); 234 free (msg); 235 236 msg = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT ("")); 237 fprintf (out_file, NTXT ("%s"), msg); 238 free (msg); 239 240 msg = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT ("")); 241 fprintf (out_file, NTXT ("%s"), msg); 242 free (msg); 243 244 msg = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT ("")); 245 fprintf (out_file, NTXT ("%s"), msg); 246 free (msg); 247 248 msg = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT ("")); 249 fprintf (out_file, NTXT ("%s"), msg); 250 free (msg); 251 } 252 253 static char * 254 delTrailingBlanks (char *s) 255 { 256 for (int i = (int) strlen (s) - 1; i >= 0 && s[i] == ' '; i--) 257 s[i] = 0; 258 return s; 259 } 260 261 /** 262 * Print the 3-line header with column heads for the metrics 263 * Return offset of "Name" column (this is needed to print Callers-Callees) 264 */ 265 int 266 print_label (FILE *out_file, MetricList *metrics_list, 267 Metric::HistMetric *hist_metric, int space) 268 { 269 char line0[2 * MAX_LEN], line1[2 * MAX_LEN]; 270 char line2[2 * MAX_LEN], line3[2 * MAX_LEN]; 271 int name_offset = 0; 272 *line0 = *line1 = *line2 = *line3 = '\0'; 273 Vector<Metric*> *mlist = metrics_list->get_items (); 274 for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++) 275 { 276 Metric *mitem = mlist->fetch (index); 277 if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ()) 278 { 279 Metric::HistMetric *hitem = hist_metric + index; 280 const char *s; 281 if (index > 0 && mitem->get_type () == Metric::ONAME) 282 { 283 s = " "; 284 name_offset = strlen (line1); 285 } 286 else 287 s = ""; 288 int width = (int) hitem->width; 289 size_t len = strlen (line1); 290 snprintf (line1 + len, sizeof (line1) - len, "%s%-*s", s, width, 291 hitem->legend1); 292 len = strlen (line2); 293 snprintf (line2 + len, sizeof (line2) - len, "%s%-*s", s, width, 294 hitem->legend2); 295 len = strlen (line3); 296 snprintf (line3 + len, sizeof (line3) - len, "%s%-*s", s, width, 297 hitem->legend3); 298 len = strlen (line0); 299 snprintf (line0 + len, sizeof (line0) - len, "%s%-*s", s, width, 300 mitem->legend ? mitem->legend : NTXT ("")); 301 } 302 } 303 char *s = delTrailingBlanks (line0); 304 if (*s) 305 fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), s); 306 fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line1)); 307 fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line2)); 308 fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line3)); 309 return name_offset; 310 } 311 312 er_print_histogram::er_print_histogram (DbeView *_dbev, Hist_data *data, 313 MetricList *metrics_list, 314 Print_mode disp_type, int limit, 315 char *sort_name, Histable *sobj, 316 bool show_load, bool show_header) 317 { 318 hist_data = data; 319 mlist = metrics_list; 320 type = disp_type; 321 number_entries = limit; 322 sort_metric = sort_name; 323 sel_obj = sobj; 324 dbev = _dbev; 325 exp_idx1 = 0; 326 exp_idx2 = dbeSession->nexps () - 1; 327 load = show_load; 328 header = show_header; 329 } 330 331 void 332 er_print_histogram::dump_list (int limit) 333 { 334 Histable::NameFormat nfmt = dbev->get_name_format (); 335 StringBuilder sb; 336 char *title = NULL; // No title for some formats 337 enum PrintMode pm = dbev->get_printmode (); 338 339 // create a header line, except for delimiter-separated list output 340 if (pm != PM_DELIM_SEP_LIST) 341 { 342 if (hist_data->type == Histable::FUNCTION) 343 sb.append (GTXT ("Functions sorted by metric: ")); 344 else if (hist_data->type == Histable::INSTR) 345 sb.append (GTXT ("PCs sorted by metric: ")); 346 else if (hist_data->type == Histable::LINE) 347 sb.append (GTXT ("Lines sorted by metric: ")); 348 else if (hist_data->type == Histable::DOBJECT) 349 sb.append (GTXT ("Dataobjects sorted by metric: ")); 350 else 351 sb.append (GTXT ("Objects sorted by metric: ")); 352 sb.append (sort_metric); 353 title = sb.toString (); 354 } 355 356 switch (pm) 357 { 358 case PM_TEXT: 359 { 360 Metric::HistMetric *hist_metric = hist_data->get_histmetrics (); 361 fprintf (out_file, NTXT ("%s\n\n"), title); //print title 362 hist_data->print_label (out_file, hist_metric, 0); 363 hist_data->print_content (out_file, hist_metric, limit); 364 fprintf (out_file, nl); 365 break; 366 } 367 case PM_HTML: 368 { 369 print_html_title (out_file, title); 370 print_html_label (out_file, mlist); 371 print_html_content (out_file, hist_data, mlist, limit, nfmt); 372 print_html_trailer (out_file); 373 break; 374 } 375 case PM_DELIM_SEP_LIST: 376 { 377 char delim = dbev->get_printdelimiter (); 378 print_delim_label (out_file, mlist, delim); 379 print_delim_content (out_file, hist_data, mlist, limit, nfmt, delim); 380 print_delim_trailer (out_file, delim); 381 break; 382 } 383 } 384 free (title); 385 } 386 387 void 388 er_print_histogram::dump_annotated_dataobjects (Vector<int> *marks, 389 int ithreshold) 390 { 391 if (!dbeSession->is_datamode_available ()) 392 fprintf (out_file, 393 GTXT ("No dataspace information recorded in experiments\n\n")); 394 395 Hist_data *layout_data = dbev->get_data_space ()->get_layout_data (hist_data, marks, ithreshold); 396 Metric::HistMetric *hist_metric = layout_data->get_histmetrics (); 397 398 // snprintf (hist_metric[name_index].legend2, MAX_LEN, GTXT ("* +offset .element")); 399 layout_data->print_label (out_file, hist_metric, 3); 400 fprintf (out_file, nl); 401 StringBuilder sb; 402 403 for (long i = 0; i < layout_data->size (); i++) 404 { 405 sb.setLength (0); 406 if (marks->find (i) != -1) 407 sb.append ("## "); 408 else 409 sb.append (" "); 410 layout_data->print_row (&sb, i, hist_metric, " "); 411 sb.toFileLn (out_file); 412 } 413 fprintf (out_file, nl); 414 delete layout_data; 415 } 416 417 static int 418 max_length(size_t len, size_t str_len) 419 { 420 if (str_len > len) 421 return str_len; 422 return len; 423 } 424 425 void 426 er_print_histogram::dump_detail (int limit) 427 { 428 Histable *obj; 429 Hist_data *current_data; 430 Histable::Type htype; 431 TValue *values; 432 double dvalue, percent; 433 MetricList *prop_mlist = new MetricList (mlist); 434 Metric *mitem; 435 int index, i; 436 Module *module; 437 LoadObject *loadobject; 438 char *sname, *oname, *lname, *alias, *mangle; 439 440 Histable::NameFormat nfmt = dbev->get_name_format (); 441 442 // Check max. length of metrics names 443 size_t len = 0, slen = 0; 444 Vec_loop (Metric*, prop_mlist->get_items (), index, mitem) 445 { 446 mitem->set_vvisible (true); 447 if (mitem->get_vtype () == VT_LABEL) 448 continue; 449 450 if (mitem->get_subtype () != Metric::STATIC) 451 { 452 mitem->set_pvisible (true); 453 len = max_length (len, hist_data->value_maxlen (index)); 454 slen = max_length (slen, strlen (mitem->get_name ())); 455 } 456 } 457 458 // now get the length of the other (non-performance-data) messages 459 if (hist_data->type == Histable::FUNCTION) 460 { 461 slen = max_length (slen, strlen (GTXT ("Source File"))); 462 slen = max_length (slen, strlen (GTXT ("Object File"))); 463 slen = max_length (slen, strlen (GTXT ("Load Object"))); 464 slen = max_length (slen, strlen (GTXT ("Mangled Name"))); 465 slen = max_length (slen, strlen (GTXT ("Aliases"))); 466 } 467 else if (hist_data->type == Histable::DOBJECT) 468 { 469 slen = max_length (slen, strlen (GTXT ("Scope"))); 470 slen = max_length (slen, strlen (GTXT ("Type"))); 471 slen = max_length (slen, strlen (GTXT ("Member of"))); 472 slen = max_length (slen, strlen (GTXT ("Offset (bytes)"))); 473 slen = max_length (slen, strlen (GTXT ("Size (bytes)"))); 474 slen = max_length (slen, strlen (GTXT ("Elements"))); 475 } 476 int max_len = (int) len; 477 int smax_len = (int) slen; 478 479 #define PR_TITLE(t) fprintf (out_file, "\t%*s:", smax_len, t) 480 #define PR(title, nm) PR_TITLE(title); \ 481 if (nm) \ 482 fprintf (out_file, " %s", nm); \ 483 fprintf (out_file, "\n") 484 485 // now loop over the objects 486 int num_printed_items = 0; 487 for (i = 0; i < hist_data->size (); i++) 488 { 489 if (hist_data->type == Histable::FUNCTION) 490 { 491 if (num_printed_items >= limit) 492 break; 493 obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj; 494 htype = obj->get_type (); 495 496 // ask the view for all the data for the object 497 // xxxxx may be expensive to rescan all packets via get_hist_data() 498 current_data = dbev->get_hist_data (prop_mlist, 499 htype, 0, Hist_data::SELF, obj); 500 if (current_data->size () == 0) 501 continue; 502 values = current_data->fetch (0)->value; 503 } 504 else 505 { 506 obj = hist_data->fetch (i)->obj; 507 DataObject *dobj = (DataObject*) obj; 508 if (sel_obj) 509 { 510 // print selected item and its members 511 if (sel_obj != obj 512 && (DataObject*) sel_obj != dobj->get_parent ()) 513 // not a match, advance to next item 514 continue; 515 } 516 else if (num_printed_items >= limit) 517 break; 518 htype = obj->get_type (); 519 values = hist_data->fetch (i)->value; 520 current_data = hist_data; 521 } 522 523 if (num_printed_items) 524 // if this isn't the first one, add a blank line 525 fprintf (out_file, NTXT ("\n")); 526 num_printed_items++; 527 528 // Print full object name 529 if (htype != Histable::DOBJECT) 530 fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt)); 531 else 532 { 533 DataObject *dobj = (DataObject*) obj; 534 if (!dobj->get_parent ()) 535 fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt)); 536 else 537 fprintf (out_file, NTXT (" %s\n"), obj->get_name (nfmt)); 538 } 539 540 Vec_loop (Metric*, prop_mlist->get_items (), index, mitem) 541 { 542 if (mitem->get_vtype () == VT_LABEL) 543 continue; 544 if (mitem->get_subtype () == Metric::STATIC 545 && htype == Histable::DOBJECT) 546 continue; 547 PR_TITLE (mitem->get_name ()); 548 549 char buf[128]; 550 char *s = values[index].to_str (buf, sizeof (buf)); 551 if (mitem->get_value_styles () & VAL_PERCENT) 552 { 553 dvalue = values[index].to_double (); 554 percent = 100.0 * current_data->get_percentage (dvalue, index); 555 if (!mitem->is_time_val ()) 556 { 557 fprintf (out_file, " %*s", max_len, s); 558 if (dvalue == 0.) 559 fprintf (out_file, " ( 0. %%)\n"); 560 else 561 fprintf (out_file, " (%5.1f%%)\n", percent); 562 continue; 563 } 564 565 TValue v; 566 v.tag = VT_DOUBLE; 567 v.sign = false; 568 v.d = dvalue / (1.e+6 * dbeSession->get_clock (-1)); 569 char buf1[128]; 570 char *s1 = v.to_str (buf1, sizeof (buf1)); 571 fprintf (out_file, " %*s", max_len, s1); 572 if (dvalue == 0.) 573 fprintf (out_file, " ( 0. %%)\n"); 574 else 575 fprintf (out_file, " (%5.1f%%)\n", percent); 576 PR_TITLE (GTXT ("Count")); 577 } 578 579 int max_len1 = max_len; 580 for (int j = (int) strlen (s) - 1; j >= 0 && s[j] == ' '; j--) 581 { 582 s[j] = 0; 583 max_len1--; 584 } 585 fprintf (out_file, " %*s\n", max_len1, s); 586 } 587 588 // now add the descriptive information about the object 589 if (htype != Histable::DOBJECT) 590 { 591 Function *func = (Function*) obj->convertto (Histable::FUNCTION); 592 if (func && func->get_type () == Histable::FUNCTION) 593 { 594 // Print the source/object/load-object files & aliases 595 oname = lname = alias = NULL; 596 sname = func->getDefSrcName (); 597 mangle = func->get_mangled_name (); 598 if (mangle && streq (func->get_name (), mangle)) 599 mangle = NULL; 600 module = func->module; 601 if (module) 602 { 603 oname = module->get_name (); 604 loadobject = module->loadobject; 605 if (loadobject) 606 { 607 lname = loadobject->get_pathname (); 608 alias = loadobject->get_alias (func); 609 } 610 } 611 612 if (htype == Histable::INSTR && dbeSession->is_datamode_available ()) 613 alias = ((DbeInstr*) obj)->get_descriptor (); 614 615 PR (GTXT ("Source File"), sname); 616 PR (GTXT ("Object File"), oname); 617 PR (GTXT ("Load Object"), lname); 618 PR (GTXT ("Mangled Name"), mangle); 619 PR (GTXT ("Aliases"), alias); 620 } 621 } 622 else 623 { 624 // Print the dataobject information 625 DataObject *dobj = (DataObject*) obj; 626 Histable *scope = dobj->get_scope (); 627 628 // print the scope 629 PR_TITLE (GTXT ("Scope")); 630 if (!scope) 631 fprintf (out_file, GTXT ("(Global)\n")); 632 else switch (scope->get_type ()) 633 { 634 case Histable::FUNCTION: 635 fprintf (out_file, NTXT ("%s(%s)\n"), 636 ((Function*) scope)->module->get_name (), 637 scope->get_name ()); 638 break; 639 case Histable::LOADOBJECT: 640 case Histable::MODULE: 641 default: 642 fprintf (out_file, NTXT ("%s\n"), scope->get_name ()); 643 } 644 645 // print the type name 646 PR_TITLE (GTXT ("Type")); 647 if (dobj->get_typename ()) 648 fprintf (out_file, NTXT ("%s\n"), dobj->get_typename ()); 649 else 650 fprintf (out_file, GTXT ("(Synthetic)\n")); 651 652 // print the offset 653 if (dobj->get_offset () != -1) 654 { 655 if (dobj->get_parent ()) 656 { 657 PR_TITLE (GTXT ("Member of")); 658 fprintf (out_file, NTXT ("%s\n"), dobj->get_parent ()->get_name ()); 659 } 660 PR_TITLE (GTXT ("Offset (bytes)")); 661 fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_offset ()); 662 } 663 // print the size 664 if (dobj->get_size ()) 665 { 666 PR_TITLE (GTXT ("Size (bytes)")); 667 fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_size ()); 668 } 669 } 670 if (hist_data->type == Histable::FUNCTION) 671 delete current_data; 672 } 673 if (num_printed_items == 0 && sel_obj) 674 fprintf (stderr, 675 GTXT ("Error: Specified item `%s' had no recorded metrics.\n"), 676 sel_obj->get_name ()); 677 delete prop_mlist; 678 } 679 680 static Metric::HistMetric * 681 allocateHistMetric (int no_metrics) 682 { 683 Metric::HistMetric *hist_metric = new Metric::HistMetric[no_metrics]; 684 for (int i = 0; i < no_metrics; i++) 685 { 686 Metric::HistMetric *hm = &hist_metric[i]; 687 hm->init (); 688 } 689 return hist_metric; 690 } 691 692 void 693 er_print_histogram::dump_gprof (int limit) 694 { 695 StringBuilder sb; 696 Histable *obj; 697 Hist_data *callers; 698 Hist_data *callees; 699 Hist_data *center; 700 701 int no_metrics = mlist->get_items ()->size (); 702 Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics); 703 for (int i = 0; i < limit; i++) 704 { 705 obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj; 706 callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 707 Hist_data::CALLERS, obj); 708 callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 709 Hist_data::CALLEES, obj); 710 center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 711 Hist_data::SELF, obj); 712 callers->update_max (hist_metric); 713 callees->update_max (hist_metric); 714 center->update_max (hist_metric); 715 callers->update_legend_width (hist_metric); 716 callers->print_label (out_file, hist_metric, 0); 717 callers->print_content (out_file, hist_metric, callers->size ()); 718 719 if (center->size () > 0) 720 { 721 center->update_total (callers->get_totals ()); 722 sb.setLength (0); 723 center->print_row (&sb, 0, hist_metric, NTXT ("*")); 724 sb.toFileLn (out_file); 725 } 726 callees->print_content (out_file, hist_metric, callees->size ()); 727 fprintf (out_file, nl); 728 delete callers; 729 delete callees; 730 delete center; 731 } 732 delete[] hist_metric; 733 } 734 735 // dump an annotated file 736 void 737 dump_anno_file (FILE *fp, Histable::Type type, Module *module, DbeView *dbev, 738 MetricList *mlist, TValue *ftotal, const char *srcFile, 739 Function *func, Vector<int> *marks, int threshold, int vis_bits, 740 int src_visible, bool hex_visible, bool src_only) 741 { 742 int lspace, mspace, tspace, remain, mindex, next_mark, hidx, index; 743 Metric *mitem; 744 char buf[MAX_LEN]; 745 Hist_data::HistItem *item; 746 747 SourceFile *srcContext = NULL; 748 bool func_scope = dbev == NULL ? false : dbev->get_func_scope (); 749 if (srcFile) 750 { 751 srcContext = module->findSource (srcFile, false); 752 if (srcContext == NULL) 753 { 754 Vector<SourceFile*> *includes = module->includes; 755 char *bname = get_basename (srcFile); 756 for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++) 757 { 758 SourceFile *sf = includes->fetch (i); 759 if (streq (get_basename (sf->get_name ()), bname)) 760 { 761 srcContext = sf; 762 break; 763 } 764 } 765 } 766 if (func) 767 func_scope = true; 768 } 769 else if (func) 770 srcContext = func->getDefSrc (); 771 772 Hist_data *hdata = module->get_data (dbev, mlist, type, ftotal, srcContext, 773 func, marks, threshold, vis_bits, 774 src_visible, hex_visible, 775 func_scope, src_only); 776 777 if (hdata == NULL) 778 return; 779 780 // force the name metric to be invisible 781 MetricList *nmlist = hdata->get_metric_list (); 782 nmlist->find_metric (GTXT ("name"), Metric::STATIC)->clear_all_visbits (); 783 Metric::HistMetric *hist_metric = hdata->get_histmetrics (); 784 785 // lspace is for max line number that's inserted; use to set width 786 int max_lineno = 0; 787 Vec_loop (Hist_data::HistItem*, hdata, hidx, item) 788 { 789 if (!item->obj) 790 continue; 791 if (item->obj->get_type () == Histable::LINE 792 && ((DbeLine*) item->obj)->lineno > max_lineno) 793 max_lineno = ((DbeLine*) item->obj)->lineno; 794 else if (item->obj->get_type () == Histable::INSTR 795 && ((DbeInstr*) item->obj)->lineno > max_lineno) 796 max_lineno = ((DbeInstr*) item->obj)->lineno; 797 } 798 799 lspace = snprintf (buf, sizeof (buf), NTXT ("%d"), max_lineno); 800 801 // mspace is the space needed for all metrics, and the mark, if any 802 mspace = 0; 803 if (nmlist->get_items ()->size () > 0) 804 { 805 mspace = 3; // mark "## " 806 Vec_loop (Metric*, nmlist->get_items (), index, mitem) 807 { 808 if (mitem->is_visible () || mitem->is_tvisible () 809 || mitem->is_pvisible ()) 810 mspace += (int) hist_metric[index].width; 811 } 812 } 813 tspace = 0; 814 remain = (mspace + lspace + 3) % 8; // " " before, ". " after line# 815 if (remain) 816 { // tab alignment 817 tspace = 8 - remain; 818 mspace += tspace; 819 } 820 mindex = 0; 821 next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1; 822 823 // Print the header for this list 824 SourceFile *sf = srcContext ? srcContext : module->getMainSrc (); 825 char *src_name = sf->dbeFile->get_location_info (); 826 DbeFile *df = module->dbeFile; 827 if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0) 828 df = module->loadobject->dbeFile; 829 char *lo_name = df->get_location_info (); 830 char *dot_o_name = lo_name; 831 if (module->dot_o_file) 832 dot_o_name = module->dot_o_file->dbeFile->get_location_info (); 833 fprintf (fp, GTXT ("Source file: %s\nObject file: %s\nLoad Object: %s\n\n"), 834 src_name, dot_o_name, lo_name); 835 836 // Print metric labels 837 if (nmlist->get_items ()->size () != 0) 838 print_label (fp, nmlist, hist_metric, 3); 839 840 // determine the name metric (not printed as a metric, though) 841 int lind = nmlist->get_listorder (GTXT ("name"), Metric::STATIC); 842 843 // now loop over the data rows -- the lines in the annotated source/disasm, 844 // including index lines, compiler commentary, etc. 845 StringBuilder sb; 846 Vec_loop (Hist_data::HistItem*, hdata, hidx, item) 847 { 848 sb.setLength (0); 849 if (item->type == Module::AT_DIS || item->type == Module::AT_QUOTE 850 || item->type == Module::AT_SRC) 851 { 852 // does this line get a high-metric mark? 853 if (hidx == next_mark) 854 { 855 sb.append (NTXT ("## ")); 856 mindex++; 857 next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1; 858 } 859 else 860 sb.append (NTXT (" ")); 861 862 hdata->print_row (&sb, hidx, hist_metric, NTXT (" ")); 863 sb.toFile (fp); 864 for (int i = sb.length (); i < mspace; i++) 865 { 866 fputc (' ', fp); 867 } 868 } 869 else 870 // this line does not get any metrics; insert blanks in lieu of them 871 for (int i = 0; i < mspace; i++) 872 fputc (' ', fp); 873 874 switch (item->type) 875 { 876 case Module::AT_SRC_ONLY: 877 if (item->obj == NULL) 878 fprintf (fp, NTXT ("%*s. "), lspace + 1, "?"); 879 else 880 fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno); 881 break; 882 883 case Module::AT_SRC: 884 fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno); 885 break; 886 case Module::AT_FUNC: 887 case Module::AT_QUOTE: 888 fprintf (fp, NTXT ("%*c"), lspace + 3, ' '); 889 break; 890 case Module::AT_DIS: 891 case Module::AT_DIS_ONLY: 892 if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1) 893 fprintf (fp, "%*c[%*s] ", lspace + 3, ' ', lspace, "?"); 894 else 895 fprintf (fp, "%*c[%*d] ", lspace + 3, ' ', lspace, 896 ((DbeInstr*) item->obj)->lineno); 897 break; 898 case Module::AT_COM: 899 case Module::AT_EMPTY: 900 break; 901 902 } 903 if (item->value[lind].l == NULL) 904 item->value[lind].l = dbe_strdup (GTXT ("INTERNAL ERROR: missing line text")); 905 fprintf (fp, NTXT ("%s\n"), item->value[lind].l); 906 } 907 delete hdata; 908 } 909 910 void 911 er_print_histogram::dump_annotated () 912 { 913 Vector<int> *marks = new Vector<int>; 914 Function *anno_func = (Function *) sel_obj; 915 Module *module = anno_func ? anno_func->module : NULL; 916 917 if (hist_data->type == Histable::DOBJECT) 918 dump_annotated_dataobjects (marks, number_entries); // threshold 919 else if (number_entries == 0) 920 // Annotated source 921 dump_anno_file (out_file, Histable::LINE, module, dbev, mlist, 922 hist_data->get_totals ()->value, NULL, anno_func, marks, 923 dbev->get_thresh_src (), dbev->get_src_compcom (), 924 dbev->get_src_visible (), dbev->get_hex_visible (), true); 925 else 926 // Annotated disassembly 927 dump_anno_file (out_file, Histable::INSTR, module, dbev, mlist, 928 hist_data->get_totals ()->value, NULL, anno_func, marks, 929 dbev->get_thresh_dis (), dbev->get_dis_compcom (), 930 dbev->get_src_visible (), dbev->get_hex_visible (), true); 931 } 932 933 void 934 er_print_histogram::data_dump () 935 { 936 int limit; 937 if (hist_data->get_status () == Hist_data::SUCCESS) 938 { 939 if (sort_metric[0] == '\n') 940 { // csingle Callers-Callees entry 941 sort_metric++; 942 fprintf (out_file, NTXT ("%s\n\n"), sort_metric); 943 } 944 else if (!sel_obj && type != MODE_LIST) 945 { 946 if (hist_data->type == Histable::FUNCTION) 947 fprintf (out_file, 948 GTXT ("Functions sorted by metric: %s\n\n"), sort_metric); 949 else if (hist_data->type == Histable::DOBJECT) 950 fprintf (out_file, GTXT ("Dataobjects sorted by metric: %s\n\n"), 951 sort_metric); 952 else 953 fprintf (out_file, 954 GTXT ("Objects sorted by metric: %s\n\n"), sort_metric); 955 } 956 limit = hist_data->size (); 957 if ((number_entries > 0) && (number_entries < limit)) 958 limit = number_entries; 959 960 switch (type) 961 { 962 case MODE_LIST: 963 dump_list (limit); 964 break; 965 case MODE_DETAIL: 966 dump_detail (limit); 967 break; 968 case MODE_GPROF: 969 dump_gprof (limit); 970 break; 971 case MODE_ANNOTATED: 972 dump_annotated (); 973 break; 974 } 975 } 976 else 977 fprintf (out_file, GTXT ("Get_Hist_data call failed %d\n"), 978 (int) hist_data->get_status ()); 979 } 980 981 /* 982 * Class er_print_ctree to print functions call tree 983 */ 984 er_print_ctree::er_print_ctree (DbeView *_dbev, Vector<Histable*> *_cstack, 985 Histable *_sobj, int _limit) 986 { 987 dbev = _dbev; 988 cstack = _cstack; 989 sobj = _sobj; 990 limit = _limit; 991 print_row = 0; 992 exp_idx1 = 0; 993 exp_idx2 = dbeSession->nexps () - 1; 994 load = false; 995 header = false; 996 } 997 998 void 999 er_print_ctree::data_dump () 1000 { 1001 StringBuilder sb; 1002 Hist_data::HistItem *total; 1003 sb.append (GTXT ("Functions Call Tree. Metric: ")); 1004 char *s = dbev->getSort (MET_CALL_AGR); 1005 sb.append (s); 1006 free (s); 1007 sb.toFileLn (out_file); 1008 fprintf (out_file, NTXT ("\n")); 1009 mlist = dbev->get_metric_list (MET_CALL_AGR); 1010 1011 // Change cstack: add sobj to the end of cstack 1012 cstack->append (sobj); 1013 Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1014 Hist_data::SELF, cstack); 1015 Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1016 Hist_data::CALLERS, cstack); 1017 Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1018 Hist_data::CALLEES, cstack); 1019 1020 // Restore cstack 1021 int last = cstack->size () - 1; 1022 cstack->remove (last); 1023 1024 // Prepare formats 1025 int no_metrics = mlist->size (); 1026 1027 // calculate max. width using data from callers, callees, center 1028 hist_metric = allocateHistMetric (no_metrics); 1029 callers->update_max (hist_metric); 1030 callees->update_max (hist_metric); 1031 center->update_max (hist_metric); 1032 callers->update_legend_width (hist_metric); 1033 callers->print_label (out_file, hist_metric, 0); // returns Name column offset 1034 1035 print_row = 0; 1036 // Pass real total to print_children() 1037 total = center->get_totals (); 1038 print_children (center, 0, sobj, NTXT (" "), total); 1039 1040 // Free memory 1041 cstack->reset (); 1042 delete callers; 1043 delete callees; 1044 delete center; 1045 delete[] hist_metric; 1046 } 1047 1048 /* 1049 * Recursive method print_children prints Call Tree elements. 1050 */ 1051 void 1052 er_print_ctree::print_children (Hist_data *data, int index, Histable *my_obj, 1053 char * prefix, Hist_data::HistItem *total) 1054 { 1055 StringBuilder buf; 1056 const char *P0 = "+-"; 1057 const char *P2 = " |"; 1058 const char *P1 = " "; 1059 1060 // If limit exceeded - return 1061 ++print_row; 1062 if (limit > 0 && print_row > limit) 1063 return; 1064 1065 if (my_obj == NULL) 1066 return; // should never happen 1067 1068 // Prepare prefix 1069 buf.append (prefix); 1070 if (buf.endsWith (P2)) 1071 { 1072 int len = buf.length () - 1; 1073 buf.setLength (len); 1074 } 1075 buf.append (P0); 1076 1077 // Change cstack: add my_obj to the end of cstack 1078 cstack->append (my_obj); 1079 1080 // Print current node info 1081 char * my_prefix = buf.toString (); 1082 1083 // Replace parent's total values with real total values 1084 data->update_total (total); // Needed to to calculate percentage only 1085 buf.setLength (0); 1086 data->print_row (&buf, index, hist_metric, my_prefix); 1087 buf.toFileLn (out_file); 1088 free (my_prefix); 1089 1090 // Get children 1091 Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1092 Hist_data::CALLEES, cstack); 1093 int nc = callees->size (); 1094 if (nc > 0) 1095 { 1096 // Print children 1097 Hist_data::HistItem *item; 1098 Histable *ch_obj; 1099 char *ch_prefix; 1100 buf.setLength (0); 1101 buf.append (prefix); 1102 buf.append (P2); 1103 ch_prefix = buf.toString (); 1104 for (int i = 0; i < nc - 1; i++) 1105 { 1106 item = callees->fetch (i); 1107 ch_obj = item->obj; 1108 print_children (callees, i, ch_obj, ch_prefix, total); 1109 } 1110 free (ch_prefix); 1111 buf.setLength (0); 1112 buf.append (prefix); 1113 buf.append (P1); 1114 ch_prefix = buf.toString (); 1115 item = callees->fetch (nc - 1); 1116 ch_obj = item->obj; 1117 print_children (callees, nc - 1, ch_obj, ch_prefix, total); 1118 free (ch_prefix); 1119 } 1120 1121 // Restore cstack 1122 int last = cstack->size () - 1; 1123 cstack->remove (last); 1124 delete callees; 1125 return; 1126 } 1127 1128 er_print_gprof::er_print_gprof (DbeView *_dbev, Vector<Histable*> *_cstack) 1129 { 1130 dbev = _dbev; 1131 cstack = _cstack; 1132 exp_idx1 = 0; 1133 exp_idx2 = dbeSession->nexps () - 1; 1134 load = false; 1135 header = false; 1136 } 1137 1138 void 1139 er_print_gprof::data_dump () 1140 { 1141 StringBuilder sb; 1142 sb.append (GTXT ("Callers and callees sorted by metric: ")); 1143 char *s = dbev->getSort (MET_CALL); 1144 sb.append (s); 1145 free (s); 1146 sb.toFileLn (out_file); 1147 fprintf (out_file, NTXT ("\n")); 1148 1149 MetricList *mlist = dbev->get_metric_list (MET_CALL); 1150 Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1151 Hist_data::SELF, cstack); 1152 Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1153 Hist_data::CALLERS, cstack); 1154 Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, 1155 Hist_data::CALLEES, cstack); 1156 1157 mlist = center->get_metric_list (); 1158 int no_metrics = mlist->get_items ()->size (); 1159 1160 // update max. width for callers/callees/center function item 1161 Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics); 1162 callers->update_max (hist_metric); 1163 callees->update_max (hist_metric); 1164 center->update_max (hist_metric); 1165 1166 callers->update_legend_width (hist_metric); 1167 int name_offset = callers->print_label (out_file, hist_metric, 0); // returns Name column offset 1168 // Print Callers 1169 sb.setLength (0); 1170 for (int i = 0; i < name_offset; i++) 1171 sb.append (NTXT ("=")); 1172 if (name_offset > 0) 1173 sb.append (NTXT (" ")); 1174 char *line1 = sb.toString (); 1175 char *line2; 1176 if (callers->size () > 0) 1177 line2 = GTXT ("Callers"); 1178 else 1179 line2 = GTXT ("No Callers"); 1180 fprintf (out_file, NTXT ("%s%s\n"), line1, line2); 1181 callers->print_content (out_file, hist_metric, callers->size ()); 1182 1183 // Print Stack Fragment 1184 line2 = GTXT ("Stack Fragment"); 1185 fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2); 1186 1187 for (long i = 0, last = cstack->size () - 1; i <= last; ++i) 1188 { 1189 sb.setLength (0); 1190 if (i == last && center->size () > 0) 1191 { 1192 center->update_total (callers->get_totals ()); // Needed to to calculate percentage only 1193 center->print_row (&sb, center->size () - 1, hist_metric, NTXT (" ")); 1194 } 1195 else 1196 { 1197 for (int n = name_offset; n > 0; n--) 1198 sb.append (NTXT (" ")); 1199 if (name_offset > 0) 1200 sb.append (NTXT (" ")); 1201 sb.append (cstack->get (i)->get_name ()); 1202 } 1203 sb.toFileLn (out_file); 1204 } 1205 1206 // Print Callees 1207 if (callees->size () > 0) 1208 line2 = GTXT ("Callees"); 1209 else 1210 line2 = GTXT ("No Callees"); 1211 fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2); 1212 callees->print_content (out_file, hist_metric, callees->size ()); 1213 fprintf (out_file, nl); 1214 free (line1); 1215 delete callers; 1216 delete callees; 1217 delete center; 1218 delete[] hist_metric; 1219 } 1220 1221 er_print_leaklist::er_print_leaklist (DbeView *_dbev, bool show_leak, 1222 bool show_alloca, int _limit) 1223 { 1224 dbev = _dbev; 1225 leak = show_leak; 1226 alloca = show_alloca; 1227 limit = _limit; 1228 } 1229 1230 // Output routine for leak list only 1231 void 1232 er_print_leaklist::data_dump () 1233 { 1234 CStack_data *lam; 1235 CStack_data::CStack_item *lae; 1236 int index; 1237 if (!dbeSession->is_leaklist_available ()) 1238 fprintf (out_file, GTXT ("No leak or allocation information recorded in experiments\n\n")); 1239 1240 MetricList *origmlist = dbev->get_metric_list (MET_NORMAL); 1241 if (leak) 1242 { 1243 // make a copy of the metric list, and set metrics for leaks 1244 MetricList *nmlist = new MetricList (origmlist); 1245 nmlist->set_metrics ("e.heapleakbytes:e.heapleakcnt:name", true, 1246 dbev->get_derived_metrics ()); 1247 1248 // now make a compacted version of it to get the right indices 1249 MetricList *mlist = new MetricList (nmlist); 1250 delete nmlist; 1251 1252 // fetch the callstack data 1253 lam = dbev->get_cstack_data (mlist); 1254 1255 // now print it 1256 if (lam && lam->size () != 0) 1257 { 1258 fprintf (out_file, GTXT ("Summary Results: Distinct Leaks = %d, Total Instances = %lld, Total Bytes Leaked = %lld\n\n"), 1259 (int) lam->size (), lam->total->value[1].ll, 1260 lam->total->value[0].ll); 1261 1262 Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae) 1263 { 1264 fprintf (out_file, 1265 GTXT ("Leak #%d, Instances = %lld, Bytes Leaked = %lld\n"), 1266 index + 1, lae->value[1].ll, lae->value[0].ll); 1267 if (lae->stack != NULL) 1268 for (int i = lae->stack->size () - 1; i >= 0; i--) 1269 { 1270 DbeInstr *instr = lae->stack->fetch (i); 1271 fprintf (out_file, NTXT (" %s\n"), instr->get_name ()); 1272 } 1273 fprintf (out_file, NTXT ("\n")); 1274 if (index + 1 == limit) break; 1275 } 1276 } 1277 else 1278 fprintf (out_file, GTXT ("No leak information\n\n")); 1279 delete lam; 1280 delete mlist; 1281 } 1282 1283 if (alloca) 1284 { 1285 // make a copy of the metric list, and set metrics for leaks 1286 MetricList *nmlist = new MetricList (origmlist); 1287 nmlist->set_metrics ("e.heapallocbytes:e.heapalloccnt:name", 1288 true, dbev->get_derived_metrics ()); 1289 1290 // now make a compacted version of it to get the right indices 1291 MetricList *mlist = new MetricList (nmlist); 1292 delete nmlist; 1293 1294 // fetch the callstack data 1295 lam = dbev->get_cstack_data (mlist); 1296 1297 // now print it 1298 if (lam && lam->size () != 0) 1299 { 1300 fprintf (out_file, GTXT ("Summary Results: Distinct Allocations = %d, Total Instances = %lld, Total Bytes Allocated = %lld\n\n"), 1301 (int) lam->size (), lam->total->value[1].ll, 1302 lam->total->value[0].ll); 1303 Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae) 1304 { 1305 fprintf (out_file, GTXT ("Allocation #%d, Instances = %lld, Bytes Allocated = %lld\n"), 1306 index + 1, lae->value[1].ll, lae->value[0].ll); 1307 if (lae->stack != NULL) 1308 for (int i = lae->stack->size () - 1; i >= 0; i--) 1309 { 1310 DbeInstr *instr = lae->stack->fetch (i); 1311 fprintf (out_file, NTXT (" %s\n"), instr->get_name ()); 1312 } 1313 fprintf (out_file, NTXT ("\n")); 1314 if (index + 1 == limit) break; 1315 } 1316 } 1317 else 1318 fprintf (out_file, GTXT ("No allocation information\n\n")); 1319 delete lam; 1320 delete mlist; 1321 } 1322 } 1323 1324 er_print_heapactivity::er_print_heapactivity (DbeView *_dbev, 1325 Histable::Type _type, 1326 bool _printStat, int _limit) 1327 { 1328 dbev = _dbev; 1329 type = _type; 1330 printStat = _printStat; 1331 limit = _limit; 1332 } 1333 1334 void 1335 er_print_heapactivity::printCallStacks (Hist_data *hist_data) 1336 { 1337 Hist_data::HistItem *hi; 1338 HeapData *hData; 1339 long stackId; 1340 int size = hist_data->size (); 1341 if (limit > 0 && limit < size) 1342 size = limit; 1343 1344 Histable::NameFormat fmt = dbev->get_name_format (); 1345 for (int i = 0; i < size; i++) 1346 { 1347 hi = hist_data->fetch (i); 1348 hData = (HeapData*) hi->obj; 1349 stackId = hData->id; 1350 if (i != 0) 1351 fprintf (out_file, NTXT ("\n")); 1352 1353 fprintf (out_file, NTXT ("%s\n"), hData->get_name (fmt)); 1354 if (hData->getAllocCnt () > 0) 1355 { 1356 fprintf (out_file, GTXT ("Instances = %d "), 1357 (int) (hData->getAllocCnt ())); 1358 fprintf (out_file, GTXT ("Bytes Allocated = %lld\n"), 1359 (long long) hData->getAllocBytes ()); 1360 } 1361 1362 if (hData->getLeakCnt () > 0) 1363 { 1364 fprintf (out_file, GTXT ("Instances = %d "), 1365 (int) (hData->getLeakCnt ())); 1366 fprintf (out_file, GTXT ("Bytes Leaked = %lld\n"), 1367 (long long) hData->getLeakBytes ()); 1368 } 1369 1370 // There is no stack trace for <Total> 1371 if (i == 0) 1372 continue; 1373 1374 // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack 1375 Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId); 1376 if (instrs != NULL) 1377 { 1378 int stSize = instrs->size (); 1379 for (int j = 0; j < stSize; j++) 1380 { 1381 Histable *instr = instrs->fetch (j); 1382 if (instr != NULL) 1383 fprintf (out_file, NTXT (" %s\n"), instr->get_name ()); 1384 } 1385 delete instrs; 1386 } 1387 } 1388 } 1389 1390 void 1391 er_print_heapactivity::printStatistics (Hist_data *hist_data) 1392 { 1393 Hist_data::HistItem *hi; 1394 HeapData *hDataTotal; 1395 hi = hist_data->fetch (0); 1396 hDataTotal = (HeapData*) hi->obj; 1397 Vector<hrtime_t> *pTimestamps; 1398 if (hDataTotal->getPeakMemUsage () > 0) 1399 { 1400 fprintf (out_file, GTXT ("\nProcess With Highest Peak Memory Usage\n")); 1401 fprintf (out_file, 1402 "-------------------------------------------------------\n"); 1403 fprintf (out_file, GTXT ("Heap size bytes %lld\n"), 1404 (long long) hDataTotal->getPeakMemUsage ()); 1405 fprintf (out_file, GTXT ("Experiment Id %d\n"), 1406 (int) (hDataTotal->getUserExpId ())); 1407 fprintf (out_file, GTXT ("Process Id %d\n"), 1408 (int) (hDataTotal->getPid ())); 1409 pTimestamps = hDataTotal->getPeakTimestamps (); 1410 if (pTimestamps != NULL) 1411 for (int i = 0; i < pTimestamps->size (); i++) 1412 fprintf (out_file, 1413 GTXT ("Time of peak %.3f (secs.)\n"), 1414 (double) (pTimestamps->fetch (i) / (double) NANOSEC)); 1415 } 1416 1417 if (hDataTotal->getAllocCnt () > 0) 1418 { 1419 fprintf (out_file, GTXT ("\nMemory Allocations Statistics\n")); 1420 fprintf (out_file, 1421 GTXT ("Allocation Size Range Allocations \n")); 1422 fprintf (out_file, 1423 "-------------------------------------------------------\n"); 1424 if (hDataTotal->getA0KB1KBCnt () > 0) 1425 fprintf (out_file, NTXT (" 0KB - 1KB %d\n"), 1426 hDataTotal->getA0KB1KBCnt ()); 1427 if (hDataTotal->getA1KB8KBCnt () > 0) 1428 fprintf (out_file, NTXT (" 1KB - 8KB %d\n"), 1429 hDataTotal->getA1KB8KBCnt ()); 1430 if (hDataTotal->getA8KB32KBCnt () > 0) 1431 fprintf (out_file, NTXT (" 8KB - 32KB %d\n"), 1432 hDataTotal->getA8KB32KBCnt ()); 1433 if (hDataTotal->getA32KB128KBCnt () > 0) 1434 fprintf (out_file, NTXT (" 32KB - 128KB %d\n"), 1435 hDataTotal->getA32KB128KBCnt ()); 1436 if (hDataTotal->getA128KB256KBCnt () > 0) 1437 fprintf (out_file, NTXT (" 128KB - 256KB %d\n"), 1438 hDataTotal->getA128KB256KBCnt ()); 1439 if (hDataTotal->getA256KB512KBCnt () > 0) 1440 fprintf (out_file, NTXT (" 256KB - 512KB %d\n"), 1441 hDataTotal->getA256KB512KBCnt ()); 1442 if (hDataTotal->getA512KB1000KBCnt () > 0) 1443 fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"), 1444 hDataTotal->getA512KB1000KBCnt ()); 1445 if (hDataTotal->getA1000KB10MBCnt () > 0) 1446 fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"), 1447 hDataTotal->getA1000KB10MBCnt ()); 1448 if (hDataTotal->getA10MB100MBCnt () > 0) 1449 fprintf (out_file, NTXT (" 10MB - 100MB %d\n"), 1450 hDataTotal->getA10MB100MBCnt ()); 1451 if (hDataTotal->getA100MB1GBCnt () > 0) 1452 fprintf (out_file, NTXT (" 100MB - 1GB %d\n"), 1453 hDataTotal->getA100MB1GBCnt ()); 1454 if (hDataTotal->getA1GB10GBCnt () > 0) 1455 fprintf (out_file, NTXT (" 1GB - 10GB %d\n"), 1456 hDataTotal->getA1GB10GBCnt ()); 1457 if (hDataTotal->getA10GB100GBCnt () > 0) 1458 fprintf (out_file, NTXT (" 10GB - 100GB %d\n"), 1459 hDataTotal->getA10GB100GBCnt ()); 1460 if (hDataTotal->getA100GB1TBCnt () > 0) 1461 fprintf (out_file, NTXT (" 100GB - 1TB %d\n"), 1462 hDataTotal->getA100GB1TBCnt ()); 1463 if (hDataTotal->getA1TB10TBCnt () > 0) 1464 fprintf (out_file, NTXT (" 1TB - 10TB %d\n"), 1465 hDataTotal->getA1TB10TBCnt ()); 1466 fprintf (out_file, GTXT ("\nSmallest allocation bytes %lld\n"), 1467 (long long) hDataTotal->getASmallestBytes ()); 1468 fprintf (out_file, GTXT ("Largest allocation bytes %lld\n"), 1469 (long long) hDataTotal->getALargestBytes ()); 1470 fprintf (out_file, GTXT ("Total allocations %d\n"), 1471 hDataTotal->getAllocCnt ()); 1472 fprintf (out_file, GTXT ("Total bytes %lld\n"), 1473 (long long) hDataTotal->getAllocBytes ()); 1474 } 1475 1476 if (hDataTotal->getLeakCnt () > 0) 1477 { 1478 fprintf (out_file, GTXT ("\nMemory Leaks Statistics\n")); 1479 fprintf (out_file, 1480 GTXT ("Leak Size Range Leaks \n")); 1481 fprintf (out_file, 1482 "-------------------------------------------------------\n"); 1483 if (hDataTotal->getL0KB1KBCnt () > 0) 1484 fprintf (out_file, NTXT (" 0KB - 1KB %d\n"), 1485 hDataTotal->getL0KB1KBCnt ()); 1486 if (hDataTotal->getL1KB8KBCnt () > 0) 1487 fprintf (out_file, NTXT (" 1KB - 8KB %d\n"), 1488 hDataTotal->getL1KB8KBCnt ()); 1489 if (hDataTotal->getL8KB32KBCnt () > 0) 1490 fprintf (out_file, NTXT (" 8KB - 32KB %d\n"), 1491 hDataTotal->getL8KB32KBCnt ()); 1492 if (hDataTotal->getL32KB128KBCnt () > 0) 1493 fprintf (out_file, NTXT (" 32KB - 128KB %d\n"), 1494 hDataTotal->getL32KB128KBCnt ()); 1495 if (hDataTotal->getL128KB256KBCnt () > 0) 1496 fprintf (out_file, NTXT (" 128KB - 256KB %d\n"), 1497 hDataTotal->getL128KB256KBCnt ()); 1498 if (hDataTotal->getL256KB512KBCnt () > 0) 1499 fprintf (out_file, NTXT (" 256KB - 512KB %d\n"), 1500 hDataTotal->getL256KB512KBCnt ()); 1501 if (hDataTotal->getL512KB1000KBCnt () > 0) 1502 fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"), 1503 hDataTotal->getL512KB1000KBCnt ()); 1504 if (hDataTotal->getL1000KB10MBCnt () > 0) 1505 fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"), 1506 hDataTotal->getL1000KB10MBCnt ()); 1507 if (hDataTotal->getL10MB100MBCnt () > 0) 1508 fprintf (out_file, NTXT (" 10MB - 100MB %d\n"), 1509 hDataTotal->getL10MB100MBCnt ()); 1510 if (hDataTotal->getL100MB1GBCnt () > 0) 1511 fprintf (out_file, NTXT (" 100MB - 1GB %d\n"), 1512 hDataTotal->getL100MB1GBCnt ()); 1513 if (hDataTotal->getL1GB10GBCnt () > 0) 1514 fprintf (out_file, NTXT (" 1GB - 10GB %d\n"), 1515 hDataTotal->getL1GB10GBCnt ()); 1516 if (hDataTotal->getL10GB100GBCnt () > 0) 1517 fprintf (out_file, NTXT (" 10GB - 100GB %d\n"), 1518 hDataTotal->getL10GB100GBCnt ()); 1519 if (hDataTotal->getL100GB1TBCnt () > 0) 1520 fprintf (out_file, NTXT (" 100GB - 1TB %d\n"), 1521 hDataTotal->getL100GB1TBCnt ()); 1522 if (hDataTotal->getL1TB10TBCnt () > 0) 1523 fprintf (out_file, NTXT (" 1TB - 10TB %d\n"), 1524 hDataTotal->getL1TB10TBCnt ()); 1525 fprintf (out_file, GTXT ("\nSmallest leaked bytes %lld\n"), 1526 (long long) hDataTotal->getLSmallestBytes ()); 1527 fprintf (out_file, GTXT ("Largest leaked bytes %lld\n"), 1528 (long long) hDataTotal->getLLargestBytes ()); 1529 fprintf (out_file, GTXT ("Total leaked %d \n"), 1530 hDataTotal->getLeakCnt ()); 1531 fprintf (out_file, GTXT ("Total bytes %lld\n"), 1532 (long long) hDataTotal->getLeakBytes ()); 1533 } 1534 fprintf (out_file, NTXT ("\n")); 1535 } 1536 1537 void 1538 er_print_heapactivity::data_dump () 1539 { 1540 // get the list of heap events from DbeView 1541 int numExps = dbeSession->nexps (); 1542 if (!numExps) 1543 { 1544 fprintf (out_file, 1545 GTXT ("There is no heap event information in the experiments\n")); 1546 return; 1547 } 1548 MetricList *mlist = dbev->get_metric_list (MET_HEAP); 1549 Hist_data *hist_data; 1550 hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL); 1551 if (printStat) 1552 printStatistics (hist_data); 1553 else 1554 printCallStacks (hist_data); 1555 } 1556 1557 er_print_ioactivity::er_print_ioactivity (DbeView *_dbev, Histable::Type _type, 1558 bool _printStat, int _limit) 1559 { 1560 dbev = _dbev; 1561 type = _type; 1562 printStat = _printStat; 1563 limit = _limit; 1564 } 1565 1566 void 1567 er_print_ioactivity::printCallStacks (Hist_data *hist_data) 1568 { 1569 Hist_data::HistItem *hi; 1570 FileData *fData; 1571 long stackId; 1572 int size = hist_data->size (); 1573 if (limit > 0 && limit < size) 1574 size = limit; 1575 1576 for (int i = 0; i < size; i++) 1577 { 1578 hi = hist_data->fetch (i); 1579 fData = (FileData*) hi->obj; 1580 stackId = fData->id; 1581 if (i != 0) 1582 fprintf (out_file, NTXT ("\n")); 1583 fprintf (out_file, NTXT ("%s\n"), fData->getFileName ()); 1584 if (fData->getWriteCnt () > 0) 1585 { 1586 fprintf (out_file, GTXT ("Write Time=%.6f (secs.) "), 1587 (double) (fData->getWriteTime () / (double) NANOSEC)); 1588 fprintf (out_file, GTXT ("Write Bytes=%lld "), 1589 (long long) fData->getWriteBytes ()); 1590 fprintf (out_file, GTXT ("Write Count=%d\n"), 1591 (int) (fData->getWriteCnt ())); 1592 } 1593 if (fData->getReadCnt () > 0) 1594 { 1595 fprintf (out_file, GTXT ("Read Time=%.6f (secs.) "), 1596 (double) (fData->getReadTime () / (double) NANOSEC)); 1597 fprintf (out_file, GTXT ("Read Bytes=%lld "), 1598 (long long) fData->getReadBytes ()); 1599 fprintf (out_file, GTXT ("Read Count=%d\n"), 1600 (int) fData->getReadCnt ()); 1601 } 1602 if (fData->getOtherCnt () > 0) 1603 { 1604 fprintf (out_file, GTXT ("Other I/O Time=%.6f (secs.) "), 1605 (double) (fData->getOtherTime () / (double) NANOSEC)); 1606 fprintf (out_file, GTXT ("Other I/O Count=%d\n"), 1607 (int) (fData->getOtherCnt ())); 1608 } 1609 if (fData->getErrorCnt () > 0) 1610 { 1611 fprintf (out_file, GTXT ("I/O Error Time=%.6f (secs.) "), 1612 (double) (fData->getErrorTime () / (double) NANOSEC)); 1613 fprintf (out_file, GTXT ("I/O Error Count=%d\n"), 1614 (int) (fData->getErrorCnt ())); 1615 } 1616 1617 // There is no stack trace for <Total> 1618 if (i == 0) 1619 continue; 1620 1621 // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack 1622 Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId); 1623 if (instrs != NULL) 1624 { 1625 int stSize = instrs->size (); 1626 for (int j = 0; j < stSize; j++) 1627 { 1628 Histable *instr = instrs->fetch (j); 1629 if (instr != NULL) 1630 fprintf (out_file, " %s\n", instr->get_name ()); 1631 } 1632 delete instrs; 1633 } 1634 } 1635 } 1636 1637 void 1638 er_print_ioactivity::printStatistics (Hist_data *hist_data) 1639 { 1640 Hist_data::HistItem *hi; 1641 FileData *fDataTotal; 1642 1643 hi = hist_data->fetch (0); 1644 fDataTotal = (FileData*) hi->obj; 1645 1646 if (fDataTotal->getWriteCnt () > 0) 1647 { 1648 fprintf (out_file, 1649 GTXT ("\nWrite Statistics\n")); 1650 fprintf (out_file, 1651 GTXT ("I/O Size Range Write Calls \n")); 1652 fprintf (out_file, 1653 "-------------------------------------------------------\n"); 1654 if (fDataTotal->getW0KB1KBCnt () > 0) 1655 fprintf (out_file, NTXT (" 0KB - 1KB %d\n"), 1656 fDataTotal->getW0KB1KBCnt ()); 1657 if (fDataTotal->getW1KB8KBCnt () > 0) 1658 fprintf (out_file, NTXT (" 1KB - 8KB %d\n"), 1659 fDataTotal->getW1KB8KBCnt ()); 1660 if (fDataTotal->getW8KB32KBCnt () > 0) 1661 fprintf (out_file, NTXT (" 8KB - 32KB %d\n"), 1662 fDataTotal->getW8KB32KBCnt ()); 1663 if (fDataTotal->getW32KB128KBCnt () > 0) 1664 fprintf (out_file, NTXT (" 32KB - 128KB %d\n"), 1665 fDataTotal->getW32KB128KBCnt ()); 1666 if (fDataTotal->getW128KB256KBCnt () > 0) 1667 fprintf (out_file, NTXT (" 128KB - 256KB %d\n"), 1668 fDataTotal->getW128KB256KBCnt ()); 1669 if (fDataTotal->getW256KB512KBCnt () > 0) 1670 fprintf (out_file, NTXT (" 256KB - 512KB %d\n"), 1671 fDataTotal->getW256KB512KBCnt ()); 1672 if (fDataTotal->getW512KB1000KBCnt () > 0) 1673 fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"), 1674 fDataTotal->getW512KB1000KBCnt ()); 1675 if (fDataTotal->getW1000KB10MBCnt () > 0) 1676 fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"), 1677 fDataTotal->getW1000KB10MBCnt ()); 1678 if (fDataTotal->getW10MB100MBCnt () > 0) 1679 fprintf (out_file, NTXT (" 10MB - 100MB %d\n"), 1680 fDataTotal->getW10MB100MBCnt ()); 1681 if (fDataTotal->getW100MB1GBCnt () > 0) 1682 fprintf (out_file, NTXT (" 100MB - 1GB %d\n"), 1683 fDataTotal->getW100MB1GBCnt ()); 1684 if (fDataTotal->getW1GB10GBCnt () > 0) 1685 fprintf (out_file, NTXT (" 1GB - 10GB %d\n"), 1686 fDataTotal->getW1GB10GBCnt ()); 1687 if (fDataTotal->getW10GB100GBCnt () > 0) 1688 fprintf (out_file, NTXT (" 10GB - 100GB %d\n"), 1689 fDataTotal->getW10GB100GBCnt ()); 1690 if (fDataTotal->getW100GB1TBCnt () > 0) 1691 fprintf (out_file, NTXT (" 100GB - 1TB %d\n"), 1692 fDataTotal->getW100GB1TBCnt ()); 1693 if (fDataTotal->getW1TB10TBCnt () > 0) 1694 fprintf (out_file, NTXT (" 1TB - 10TB %d\n"), 1695 fDataTotal->getW1TB10TBCnt ()); 1696 fprintf (out_file, 1697 GTXT ("\nLongest write %.6f (secs.)\n"), 1698 (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC)); 1699 fprintf (out_file, GTXT ("Smallest write bytes %lld\n"), 1700 (long long) fDataTotal->getWSmallestBytes ()); 1701 fprintf (out_file, GTXT ("Largest write bytes %lld\n"), 1702 (long long) fDataTotal->getWLargestBytes ()); 1703 fprintf (out_file, 1704 GTXT ("Total time %.6f (secs.)\n"), 1705 (double) (fDataTotal->getWriteTime () / (double) NANOSEC)); 1706 fprintf (out_file, GTXT ("Total calls %d\n"), 1707 fDataTotal->getWriteCnt ()); 1708 fprintf (out_file, GTXT ("Total bytes %lld\n"), 1709 (long long) fDataTotal->getWriteBytes ()); 1710 } 1711 1712 if (fDataTotal->getReadCnt () > 0) 1713 { 1714 fprintf (out_file, 1715 GTXT ("\nRead Statistics\n")); 1716 fprintf (out_file, 1717 GTXT ("I/O Size Range Read Calls \n")); 1718 fprintf (out_file, 1719 "------------------------------------------------------\n"); 1720 if (fDataTotal->getR0KB1KBCnt () > 0) 1721 fprintf (out_file, NTXT (" 0KB - 1KB %d\n"), 1722 fDataTotal->getR0KB1KBCnt ()); 1723 if (fDataTotal->getR1KB8KBCnt () > 0) 1724 fprintf (out_file, NTXT (" 1KB - 8KB %d\n"), 1725 fDataTotal->getR1KB8KBCnt ()); 1726 if (fDataTotal->getR8KB32KBCnt () > 0) 1727 fprintf (out_file, NTXT (" 8KB - 32KB %d\n"), 1728 fDataTotal->getR8KB32KBCnt ()); 1729 if (fDataTotal->getR32KB128KBCnt () > 0) 1730 fprintf (out_file, NTXT (" 32KB - 128KB %d\n"), 1731 fDataTotal->getR32KB128KBCnt ()); 1732 if (fDataTotal->getR128KB256KBCnt () > 0) 1733 fprintf (out_file, NTXT (" 128KB - 256KB %d\n"), 1734 fDataTotal->getR128KB256KBCnt ()); 1735 if (fDataTotal->getR256KB512KBCnt () > 0) 1736 fprintf (out_file, NTXT (" 256KB - 512KB %d\n"), 1737 fDataTotal->getR256KB512KBCnt ()); 1738 if (fDataTotal->getR512KB1000KBCnt () > 0) 1739 fprintf (out_file, NTXT (" 512KB - 1000KB %d\n"), 1740 fDataTotal->getR512KB1000KBCnt ()); 1741 if (fDataTotal->getR1000KB10MBCnt () > 0) 1742 fprintf (out_file, NTXT (" 1000KB - 10MB %d\n"), 1743 fDataTotal->getR1000KB10MBCnt ()); 1744 if (fDataTotal->getR10MB100MBCnt () > 0) 1745 fprintf (out_file, NTXT (" 10MB - 100MB %d\n"), 1746 fDataTotal->getR10MB100MBCnt ()); 1747 if (fDataTotal->getR100MB1GBCnt () > 0) 1748 fprintf (out_file, NTXT (" 100MB - 1GB %d\n"), 1749 fDataTotal->getR100MB1GBCnt ()); 1750 if (fDataTotal->getR1GB10GBCnt () > 0) 1751 fprintf (out_file, NTXT (" 1GB - 10GB %d\n"), 1752 fDataTotal->getR1GB10GBCnt ()); 1753 if (fDataTotal->getR10GB100GBCnt () > 0) 1754 fprintf (out_file, NTXT (" 10GB - 100GB %d\n"), 1755 fDataTotal->getR10GB100GBCnt ()); 1756 if (fDataTotal->getR100GB1TBCnt () > 0) 1757 fprintf (out_file, NTXT (" 100GB - 1TB %d\n"), 1758 fDataTotal->getR100GB1TBCnt ()); 1759 if (fDataTotal->getR1TB10TBCnt () > 0) 1760 fprintf (out_file, NTXT (" 1TB - 10TB %d\n"), 1761 fDataTotal->getR1TB10TBCnt ()); 1762 fprintf (out_file, 1763 GTXT ("\nLongest time %.6f (secs.)\n"), 1764 (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC)); 1765 fprintf (out_file, GTXT ("Smallest read bytes %lld\n"), 1766 (long long) fDataTotal->getRSmallestBytes ()); 1767 fprintf (out_file, GTXT ("Largest read bytes %lld\n"), 1768 (long long) fDataTotal->getRLargestBytes ()); 1769 fprintf (out_file, 1770 GTXT ("Total time %.6f (secs.)\n"), 1771 (double) (fDataTotal->getReadTime () / (double) NANOSEC)); 1772 fprintf (out_file, GTXT ("Total calls %d\n"), 1773 fDataTotal->getReadCnt ()); 1774 fprintf (out_file, GTXT ("Total bytes %lld\n"), 1775 (long long) fDataTotal->getReadBytes ()); 1776 } 1777 1778 if (fDataTotal->getOtherCnt () > 0) 1779 { 1780 fprintf (out_file, GTXT ("\nOther I/O Statistics\n")); 1781 fprintf (out_file, 1782 "-----------------------------------------------------\n"); 1783 fprintf (out_file, 1784 GTXT ("Total time %.6f (secs.)\n"), 1785 (double) (fDataTotal->getOtherTime () / (double) NANOSEC)); 1786 fprintf (out_file, GTXT ("Total calls %d \n"), 1787 fDataTotal->getOtherCnt ()); 1788 } 1789 if (fDataTotal->getErrorCnt () > 0) 1790 { 1791 fprintf (out_file, GTXT ("\nI/O Error Statistics\n")); 1792 fprintf (out_file, 1793 "-----------------------------------------------------\n"); 1794 fprintf (out_file, 1795 GTXT ("Total time %.6f (secs.)\n"), 1796 (double) (fDataTotal->getErrorTime () / (double) NANOSEC)); 1797 fprintf (out_file, GTXT ("Total calls %d \n"), 1798 fDataTotal->getErrorCnt ()); 1799 } 1800 fprintf (out_file, NTXT ("\n")); 1801 } 1802 1803 void 1804 er_print_ioactivity::data_dump () 1805 { 1806 // get the list of io events from DbeView 1807 int numExps = dbeSession->nexps (); 1808 if (!numExps) 1809 { 1810 fprintf (out_file, 1811 GTXT ("There is no IO event information in the experiments\n")); 1812 return; 1813 } 1814 1815 MetricList *mlist = dbev->get_metric_list (MET_IO); 1816 Hist_data *hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL); 1817 if (type == Histable::IOCALLSTACK) 1818 printCallStacks (hist_data); 1819 else if (printStat) 1820 printStatistics (hist_data); 1821 else 1822 { 1823 Metric::HistMetric *hist_metric = hist_data->get_histmetrics (); 1824 hist_data->print_label (out_file, hist_metric, 0); 1825 hist_data->print_content (out_file, hist_metric, limit); 1826 fprintf (out_file, nl); 1827 } 1828 } 1829 1830 er_print_experiment::er_print_experiment (DbeView *_dbev, int bgn_idx, 1831 int end_idx, bool show_load, 1832 bool show_header, bool show_stat, 1833 bool show_over, bool show_odetail) 1834 { 1835 dbev = _dbev; 1836 exp_idx1 = bgn_idx; 1837 exp_idx2 = end_idx; 1838 load = show_load; 1839 header = show_header; 1840 stat = show_stat; 1841 over = show_over; 1842 odetail = show_odetail; 1843 } 1844 1845 void 1846 er_print_experiment::data_dump () 1847 { 1848 int index, maxlen; 1849 1850 maxlen = 0; 1851 1852 if (stat) 1853 { 1854 max_len1 = 50; 1855 if (exp_idx2 > exp_idx1) 1856 { 1857 statistics_sum (maxlen); 1858 fprintf (out_file, nl); 1859 } 1860 1861 for (index = exp_idx1; index <= exp_idx2; index++) 1862 statistics_dump (index, maxlen); 1863 } 1864 else if (over) 1865 { 1866 max_len1 = 50; 1867 if (exp_idx2 > exp_idx1) 1868 { 1869 overview_sum (maxlen); 1870 fprintf (out_file, nl); 1871 } 1872 1873 for (index = exp_idx1; index <= exp_idx2; index++) 1874 overview_dump (index, maxlen); 1875 } 1876 else if (header) 1877 for (index = exp_idx1; index <= exp_idx2; index++) 1878 { 1879 if (index != exp_idx1) 1880 fprintf (out_file, 1881 "----------------------------------------------------------------\n"); 1882 header_dump (index); 1883 } 1884 } 1885 1886 void 1887 er_print_experiment::overview_sum (int &maxlen) 1888 { 1889 int index; 1890 Ovw_data *sum_data = new Ovw_data (); 1891 for (index = exp_idx1; index <= exp_idx2; index++) 1892 { 1893 Ovw_data *ovw_data = dbev->get_ovw_data (index); 1894 if (ovw_data == NULL) 1895 continue; 1896 sum_data->sum (ovw_data); 1897 delete ovw_data; 1898 } 1899 1900 fprintf (out_file, GTXT ("<Sum across selected experiments>")); 1901 fprintf (out_file, nl); 1902 overview_summary (sum_data, maxlen); 1903 fprintf (out_file, nl); 1904 delete sum_data; 1905 } 1906 1907 void 1908 er_print_experiment::overview_dump (int exp_idx, int &maxlen) 1909 { 1910 Ovw_data *ovw_data; 1911 Ovw_data::Ovw_item ovw_item_labels; 1912 Ovw_data::Ovw_item ovw_item; 1913 int index; 1914 int size; 1915 1916 ovw_data = dbev->get_ovw_data (exp_idx); 1917 if (ovw_data == NULL) 1918 return; 1919 if (pr_params.header) 1920 header_dump (exp_idx); 1921 else if (odetail) 1922 fprintf (out_file, GTXT ("Experiment: %s\n"), 1923 dbeSession->get_exp (exp_idx)->get_expt_name ()); 1924 1925 overview_summary (ovw_data, maxlen); 1926 if (!odetail) 1927 { 1928 delete ovw_data; 1929 return; 1930 } 1931 1932 //Get the collection params for the sample selection and display them. 1933 fprintf (out_file, "\n\n%*s\n\n", max_len1, GTXT ("Individual samples")); 1934 1935 size = ovw_data->size (); 1936 ovw_item_labels = ovw_data->get_labels (); 1937 1938 for (index = 0; index < size; index++) 1939 { 1940 ovw_item = ovw_data->fetch (index); 1941 fprintf (out_file, "%*s: %d\n\n", max_len1, GTXT ("Sample Number"), 1942 ovw_item.number); 1943 overview_item (&ovw_item, &ovw_item_labels); 1944 fprintf (out_file, nl); 1945 } 1946 1947 delete ovw_data; 1948 } 1949 1950 void 1951 er_print_experiment::overview_summary (Ovw_data *ovw_data, int &maxlen) 1952 { 1953 char buf[128]; 1954 int len; 1955 Ovw_data::Ovw_item totals; 1956 Ovw_data::Ovw_item ovw_item_labels; 1957 totals = ovw_data->get_totals (); 1958 len = snprintf (buf, sizeof (buf), "%.3lf", tstodouble (totals.total.t)); 1959 if (maxlen < len) 1960 maxlen = len; 1961 max_len2 = maxlen; 1962 max_len3 = maxlen; 1963 fprintf (out_file, "%*s\n\n", max_len1, 1964 GTXT ("Aggregated statistics for selected samples")); 1965 1966 ovw_item_labels = ovw_data->get_labels (); 1967 overview_item (&totals, &ovw_item_labels); 1968 } 1969 1970 void 1971 er_print_experiment::overview_item (Ovw_data::Ovw_item *ovw_item, 1972 Ovw_data::Ovw_item *ovw_item_labels) 1973 { 1974 double start, end, total_value; 1975 int index, size; 1976 timestruc_t total_time = {0, 0}; 1977 1978 start = tstodouble (ovw_item->start); 1979 end = tstodouble (ovw_item->end); 1980 1981 fprintf (out_file, "%*s: %s\n", max_len1, GTXT ("Start Label"), 1982 ovw_item->start_label); 1983 fprintf (out_file, "%*s: %s\n", max_len1, GTXT ("End Label"), 1984 ovw_item->end_label); 1985 1986 fprintf (out_file, "%*s: ", max_len1, GTXT ("Start Time (sec.)")); 1987 if (start == -1.0) 1988 fprintf (out_file, GTXT ("N/A")); 1989 else 1990 fprintf (out_file, "%*.3f", max_len2, start); 1991 fprintf (out_file, nl); 1992 fprintf (out_file, "%*s: ", max_len1, GTXT ("End Time (sec.)")); 1993 if (end == -1.0) 1994 fprintf (out_file, GTXT ("N/A")); 1995 else 1996 fprintf (out_file, "%*.3f", max_len2, end); 1997 fprintf (out_file, nl); 1998 fprintf (out_file, "%*s: ", max_len1, GTXT ("Duration (sec.)")); 1999 fprintf (out_file, "%*.3f", max_len2, tstodouble (ovw_item->duration)); 2000 fprintf (out_file, NTXT ("\n")); 2001 2002 size = ovw_item->size; 2003 for (index = 0; index < size; index++) 2004 tsadd (&total_time, &ovw_item->values[index].t); 2005 2006 total_value = tstodouble (total_time); 2007 fprintf (out_file, "%*s: %*.3f", max_len1, GTXT ("Total Thread Time (sec.)"), 2008 max_len2, tstodouble (ovw_item->tlwp)); 2009 fprintf (out_file, NTXT ("\n")); 2010 fprintf (out_file, "%*s: ", max_len1, GTXT ("Average number of Threads")); 2011 if (tstodouble (ovw_item->duration) != 0) 2012 fprintf (out_file, "%*.3f", max_len2, ovw_item->nlwp); 2013 else 2014 fprintf (out_file, GTXT ("N/A")); 2015 fprintf (out_file, NTXT ("\n\n")); 2016 fprintf (out_file, "%*s:\n", max_len1, GTXT ("Process Times (sec.)")); 2017 for (index = 1; index < size; index++) 2018 { 2019 overview_value (&ovw_item_labels->values[index], ovw_item_labels->type, 2020 total_value); 2021 overview_value (&ovw_item->values[index], ovw_item->type, 2022 total_value); 2023 fprintf (out_file, NTXT ("\n")); 2024 } 2025 } 2026 2027 void 2028 er_print_experiment::overview_value (Value *value, ValueTag value_tag, 2029 double total_value) 2030 { 2031 double dvalue; 2032 switch (value_tag) 2033 { 2034 case VT_LABEL: 2035 fprintf (out_file, "%*s: ", max_len1, value->l); 2036 break; 2037 case VT_HRTIME: 2038 dvalue = tstodouble (value->t); 2039 if (dvalue == 0.0) 2040 fprintf (out_file, "%*s ( 0. %%)", max_len3, "0. "); 2041 else 2042 fprintf (out_file, "%*.3f (%5.1f%%)", max_len3, dvalue, 2043 100.0 * dvalue / total_value); 2044 break; 2045 case VT_INT: 2046 fprintf (out_file, NTXT ("%d"), value->i); 2047 break; 2048 default: 2049 fprintf (out_file, "%*.3f", max_len3, total_value); 2050 } 2051 } 2052 2053 void 2054 er_print_experiment::statistics_sum (int &maxlen) 2055 { 2056 int index; 2057 int size, len; 2058 Stats_data *sum_data = new Stats_data (); 2059 for (index = exp_idx1; index <= exp_idx2; index++) 2060 { 2061 Stats_data *stats_data = dbev->get_stats_data (index); 2062 if (stats_data == NULL) 2063 continue; 2064 sum_data->sum (stats_data); 2065 delete stats_data; 2066 } 2067 2068 // get the maximum width of values 2069 size = sum_data->size (); 2070 for (index = 0; index < size; index++) 2071 { 2072 len = (int) sum_data->fetch (index).value.get_len (); 2073 if (maxlen < len) 2074 maxlen = len; 2075 } 2076 2077 // print overview average 2078 overview_sum (maxlen); 2079 2080 // print statistics data 2081 max_len2 = maxlen; 2082 statistics_item (sum_data); 2083 delete sum_data; 2084 } 2085 2086 void 2087 er_print_experiment::statistics_dump (int exp_idx, int &maxlen) 2088 { 2089 Stats_data *stats_data; 2090 int index; 2091 int size, len; 2092 stats_data = dbev->get_stats_data (exp_idx); 2093 if (stats_data == NULL) 2094 return; 2095 if (pr_params.header) 2096 { 2097 header_dump (exp_idx); 2098 fprintf (out_file, nl); 2099 } 2100 else 2101 fprintf (out_file, GTXT ("Experiment: %s\n"), 2102 dbeSession->get_exp (exp_idx)->get_expt_name ()); 2103 2104 // get the maximum width of values 2105 size = stats_data->size (); 2106 for (index = 0; index < size; index++) 2107 { 2108 len = (int) stats_data->fetch (index).value.get_len (); 2109 if (maxlen < len) 2110 maxlen = len; 2111 } 2112 2113 // print overview average 2114 overview_dump (exp_idx, maxlen); 2115 fprintf (out_file, nl); 2116 2117 // print statistics data 2118 max_len2 = maxlen; 2119 statistics_item (stats_data); 2120 delete stats_data; 2121 } 2122 2123 void 2124 er_print_experiment::statistics_item (Stats_data *stats_data) 2125 { 2126 int size, index; 2127 Stats_data::Stats_item stats_item; 2128 char buf[256]; 2129 size = stats_data->size (); 2130 for (index = 0; index < size; index++) 2131 { 2132 stats_item = stats_data->fetch (index); 2133 fprintf (out_file, "%*s: %*s\n", max_len1, stats_item.label, 2134 max_len2, stats_item.value.to_str (buf, sizeof (buf))); 2135 } 2136 fprintf (out_file, nl); 2137 } 2138 2139 // Print annotated source or disassembly -- called by er_print only 2140 void 2141 print_anno_file (char *name, const char *sel, const char *srcFile, 2142 bool isDisasm, FILE *dis_file, FILE *inp_file, FILE *out_file, 2143 DbeView *dbev, bool xdefault) 2144 { 2145 Histable *obj; 2146 Function *func; 2147 Module *module; 2148 Vector<int> *marks; 2149 Hist_data *hist_data; 2150 char *errstr; 2151 int index; 2152 SourceFile *fitem; 2153 int threshold; 2154 int compcom_bits; 2155 int src_visible; 2156 bool hex_visible; 2157 bool srcmetrics_visible; 2158 2159 if ((name == NULL) || (strlen (name) == 0)) 2160 { 2161 fprintf (stderr, GTXT ("Error: No function or file has been specified.\n")); 2162 return; 2163 } 2164 2165 // find the function from the name 2166 if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel, 2167 Histable::FUNCTION, xdefault)) 2168 return; 2169 2170 if (obj != NULL) 2171 { 2172 // source or disassembly for <Total>, <Unknown>, or @plt 2173 if (obj->get_type () != Histable::FUNCTION) 2174 { 2175 fprintf (stderr, 2176 GTXT ("Error: %s is not a real function; no source or disassembly available.\n"), 2177 name); 2178 return; 2179 } 2180 2181 func = (Function *) obj; 2182 if (func->flags & FUNC_FLAG_SIMULATED) 2183 { 2184 fprintf (stderr, 2185 GTXT ("Error: %s is not a real function; no source or disassembly available.\n"), 2186 name); 2187 return; 2188 } 2189 else if (dbev != NULL && isDisasm) 2190 dbev->set_func_scope (true); 2191 2192 // function found, set module 2193 module = func->module; 2194 int ix = module->loadobject->seg_idx; 2195 if (dbev->get_lo_expand (ix) == LIBEX_HIDE) 2196 { 2197 char *lo_name = module->loadobject->get_name (); 2198 fprintf (stderr, 2199 GTXT ("Error: No source or disassembly available for hidden object %s.\n"), 2200 lo_name); 2201 return; 2202 } 2203 2204 if (srcFile) 2205 { 2206 Vector<SourceFile*> *sources = func->get_sources (); 2207 bool found = false; 2208 if (sources == NULL) 2209 { 2210 fitem = func->getDefSrc (); 2211 found = (func->line_first > 0) 2212 && strcmp (basename (srcFile), 2213 basename (fitem->get_name ())) == 0; 2214 } 2215 else 2216 { 2217 Vec_loop (SourceFile*, sources, index, fitem) 2218 { 2219 if (strcmp (basename (srcFile), basename (fitem->get_name ())) == 0) 2220 { 2221 found = true; 2222 break; 2223 } 2224 } 2225 } 2226 if (!found) 2227 { 2228 fprintf (stderr, GTXT ("Error: Source file context %s does not contribute to function `%s'.\n"), 2229 srcFile, name); 2230 return; 2231 } 2232 } 2233 } 2234 else 2235 { 2236 // function not found 2237 if (sel && strrchr (sel, ':')) 2238 { 2239 // 'sel' was "@seg_num:address" or "file_name:address" 2240 fprintf (stderr, 2241 GTXT ("Error: No function with given name `%s %s' found.\n"), 2242 name, sel); 2243 return; 2244 } 2245 // search for a file of that name 2246 if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel, 2247 Histable::MODULE, xdefault)) 2248 return; 2249 2250 if (obj == NULL) 2251 { // neither function nor file found 2252 fprintf (stderr, GTXT ("Error: No function or file with given name `%s' found.\n"), 2253 name); 2254 return; 2255 } 2256 2257 func = NULL; 2258 module = (Module *) obj; 2259 int ix = module->loadobject->seg_idx; 2260 if (dbev->get_lo_expand (ix) == LIBEX_HIDE) 2261 { 2262 char *lo_name = module->loadobject->get_name (); 2263 fprintf (stderr, GTXT ("Error: No source or disassembly available for hidden object %s.\n"), 2264 lo_name); 2265 return; 2266 } 2267 if (name) 2268 srcFile = name; 2269 } 2270 2271 if (module == NULL || module->get_name () == NULL) 2272 { 2273 fprintf (stderr, GTXT ("Error: Object name not recorded in experiment\n")); 2274 return; 2275 } 2276 module->read_stabs (); 2277 2278 if (!isDisasm && (module->file_name == NULL 2279 || (module->flags & MOD_FLAG_UNKNOWN) != 0 2280 || *module->file_name == 0)) 2281 { 2282 fprintf (stderr, GTXT ("Error: Source location not recorded in experiment\n")); 2283 return; 2284 } 2285 2286 MetricList *metric_list = dbev->get_metric_list (MET_NORMAL); 2287 int sort_ref_index = metric_list->get_sort_ref_index (); 2288 if (isDisasm) 2289 metric_list->set_sort_ref_index (-1); 2290 2291 // Ask DbeView to generate function-level data 2292 // MSI: I think this is used only to get totals to compute percentages 2293 hist_data = dbev->get_hist_data (metric_list, Histable::FUNCTION, 0, 2294 Hist_data::ALL); 2295 MetricList *nmlist = hist_data->get_metric_list (); 2296 metric_list->set_sort_ref_index (sort_ref_index); 2297 if (nmlist->get_items ()->size () != 0 2298 && hist_data->get_status () != Hist_data::SUCCESS) 2299 { 2300 errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); 2301 if (errstr) 2302 { 2303 fprintf (stderr, GTXT ("Error: %s\n"), errstr); 2304 free (errstr); 2305 } 2306 return; 2307 } 2308 2309 marks = new Vector<int>; 2310 if (isDisasm) 2311 { 2312 threshold = dbev->get_thresh_dis (); 2313 compcom_bits = dbev->get_dis_compcom (); 2314 src_visible = dbev->get_src_visible (); 2315 hex_visible = dbev->get_hex_visible (); 2316 srcmetrics_visible = dbev->get_srcmetric_visible (); 2317 } 2318 else 2319 { 2320 threshold = dbev->get_thresh_src (); 2321 compcom_bits = dbev->get_src_compcom (); 2322 src_visible = SRC_NA; 2323 hex_visible = false; 2324 srcmetrics_visible = false; 2325 } 2326 2327 dump_anno_file (out_file, isDisasm ? Histable::INSTR : Histable::LINE, 2328 module, dbev, nmlist, hist_data->get_totals ()->value, 2329 srcFile, func, marks, threshold, compcom_bits, 2330 src_visible, hex_visible, srcmetrics_visible); 2331 2332 delete marks; 2333 2334 errstr = module->anno_str (); 2335 if (errstr) 2336 { 2337 fprintf (stderr, GTXT ("Error: %s\n"), errstr); 2338 free (errstr); 2339 } 2340 delete hist_data; 2341 } 2342 2343 void 2344 print_html_title (FILE *out_file, char *title) 2345 { 2346 // This will print a header row for the report 2347 fprintf (out_file, "<html><title>%s</title>\n", title); 2348 fprintf (out_file, "<center><h3>%s</h3></center>\n", title); 2349 } 2350 2351 void 2352 print_html_label (FILE *out_file, MetricList *metrics_list) 2353 { 2354 int mlist_sz; 2355 2356 // This will print a header row for the metrics 2357 Vector<Metric*> *mlist = metrics_list->get_items (); 2358 mlist_sz = mlist->size (); 2359 2360 fprintf (out_file, "<style type=\"text/css\">\n"); 2361 fprintf (out_file, "<!--\nBODY\n"); 2362 fprintf (out_file, ".th_C { text-align:center; background-color:lightgoldenrodyellow; }\n"); 2363 fprintf (out_file, ".th_CG { text-align:center; background-color:#ffff33; }\n"); 2364 fprintf (out_file, ".th_L { text-align:left; background-color:lightgoldenrodyellow; }\n"); 2365 fprintf (out_file, ".th_LG { text-align:left; background-color:#ffff33; }\n"); 2366 fprintf (out_file, ".td_R { text-align:right; }\n"); 2367 fprintf (out_file, ".td_RG { text-align:right; background-color:#ffff33; }\n"); 2368 fprintf (out_file, ".td_L { text-align:left; }\n"); 2369 fprintf (out_file, ".td_LG { text-align:left; background-color:#ffff33; }\n"); 2370 fprintf (out_file, "-->\n</style>"); 2371 fprintf (out_file, "<center><table border=1 cellspacing=2>\n<tr>"); 2372 2373 for (int index = 0; index < mlist_sz; index++) 2374 { 2375 Metric *mitem = mlist->fetch (index); 2376 int ncols = 0; 2377 if (mitem->is_visible ()) 2378 ncols++; 2379 if (mitem->is_tvisible ()) 2380 ncols++; 2381 if (mitem->is_pvisible ()) 2382 ncols++; 2383 if (ncols == 0) 2384 continue; 2385 char *name = strdup (mitem->get_name ()); 2386 char *name2 = split_metric_name (name); 2387 const char *style = index == metrics_list->get_sort_ref_index () ? "G" : ""; 2388 2389 // start the column, with colspan setting, legend, and sort metric indicator 2390 if (ncols == 1) 2391 { 2392 if (mitem->get_vtype () == VT_LABEL) 2393 // left-adjust the name metric 2394 fprintf (out_file, 2395 "<th class=\"th_L%s\">%s <br>%s %s <br>%s </th>", 2396 style, mitem->legend == NULL ? " " : mitem->legend, 2397 (index == metrics_list->get_sort_ref_index ()) ? "∇" : " ", 2398 name, name2 == NULL ? " " : name2); 2399 else 2400 // but center the others 2401 fprintf (out_file, 2402 "<th class=\"th_C%s\">%s <br>%s %s <br>%s </th>", 2403 style, mitem->legend == NULL ? " " : mitem->legend, 2404 (index == metrics_list->get_sort_ref_index ()) ? 2405 "∇" : " ", 2406 name, name2 == NULL ? NTXT (" ") : name2); 2407 } 2408 else 2409 // name metric can't span columns 2410 fprintf (out_file, 2411 "<th colspan=%d class=\"th_C%s\">%s <br>%s %s <br>%s </th>", 2412 ncols, style, 2413 mitem->legend == NULL ? " " : mitem->legend, 2414 index == metrics_list->get_sort_ref_index () ? 2415 "∇" : " ", 2416 name, name2 == NULL ? " " : name2); 2417 2418 free (name); 2419 } 2420 2421 // end this row, start the units row 2422 fprintf (out_file, NTXT ("</tr>\n<tr>")); 2423 2424 // now do the units row 2425 for (int index = 0; index < mlist_sz; index++) 2426 { 2427 Metric *mitem = mlist->fetch (index); 2428 const char *style = index == metrics_list->get_sort_ref_index () ? "G" : ""; 2429 2430 if (mitem->is_tvisible ()) 2431 fprintf (out_file, "<th class=\"th_C%s\"> (%s)</th>", style, 2432 GTXT ("sec.")); 2433 if (mitem->is_visible ()) 2434 { 2435 if (mitem->get_abbr_unit () == NULL) 2436 fprintf (out_file, "<th class=\"th_C%s\"> </th>", style); 2437 else 2438 fprintf (out_file, "<th class=\"th_C%s\">(%s)</th>", style, 2439 mitem->get_abbr_unit () == NULL ? " " 2440 : mitem->get_abbr_unit ()); 2441 } 2442 if (mitem->is_pvisible ()) 2443 fprintf (out_file, "<th class=\"th_C%s\"> (%%)</th>", style); 2444 } 2445 fprintf (out_file, NTXT ("</tr>\n")); 2446 } 2447 2448 void 2449 print_html_content (FILE *out_file, Hist_data *data, MetricList *metrics_list, 2450 int limit, Histable::NameFormat nfmt) 2451 { 2452 Hist_data::HistItem *item; 2453 2454 // printing contents. 2455 for (int i = 0; i < limit; i++) 2456 { 2457 item = data->fetch (i); 2458 print_html_one (out_file, data, item, metrics_list, nfmt); 2459 } 2460 } 2461 2462 void 2463 print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item, 2464 MetricList *metrics_list, Histable::NameFormat nfmt) 2465 { 2466 Metric *mitem; 2467 int index; 2468 int visible, tvisible, pvisible; 2469 TValue *value; 2470 double percent; 2471 2472 fprintf (out_file, NTXT ("<tr>")); 2473 Vec_loop (Metric*, metrics_list->get_items (), index, mitem) 2474 { 2475 visible = mitem->is_visible (); 2476 tvisible = mitem->is_tvisible (); 2477 pvisible = mitem->is_pvisible (); 2478 const char *style = index == metrics_list->get_sort_ref_index () ? "G" : ""; 2479 2480 if (tvisible) 2481 { 2482 value = &(item->value[index]); 2483 if (value->ll == 0LL) 2484 fprintf (out_file, 2485 "<td class=\"td_R%s\"><tt>0. </tt></td>", 2486 style); 2487 else 2488 fprintf (out_file, "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>", 2489 style, 1.e-6 * value->ll / dbeSession->get_clock (-1)); 2490 } 2491 2492 if (visible) 2493 { 2494 if (mitem->get_vtype () == VT_LABEL) 2495 { 2496 value = &(item->value[index]); 2497 char *r; 2498 if (value->tag == VT_OFFSET) 2499 r = ((DataObject*) (item->obj))->get_offset_name (); 2500 else 2501 r = item->obj->get_name (nfmt); 2502 char *n = html_ize_name (r); 2503 fprintf (out_file, NTXT ("<td class=\"td_L%s\">%s</td>"), style, n); 2504 free (n); 2505 } 2506 else 2507 { 2508 value = &(item->value[index]); 2509 switch (value->tag) 2510 { 2511 case VT_DOUBLE: 2512 if (value->d == 0.0) 2513 fprintf (out_file, 2514 "<td class=\"td_R%s\"><tt>0. </tt></td>", 2515 style); 2516 else 2517 fprintf (out_file, 2518 "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>", style, 2519 value->d); 2520 break; 2521 case VT_INT: 2522 fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>", 2523 style, value->i); 2524 break; 2525 case VT_LLONG: 2526 fprintf (out_file, "<td class=\"td_R%s\"><tt>%lld</td></tt>", 2527 style, value->ll); 2528 break; 2529 case VT_ULLONG: 2530 fprintf (out_file, "<td class=\"td_R%s\"><tt>%llu</td></tt>", 2531 style, value->ull); 2532 break; 2533 case VT_ADDRESS: 2534 fprintf (out_file, 2535 "<td class=\"td_R%s\"><tt>%u:0x%08x</tt></td>", style, 2536 ADDRESS_SEG (value->ll), ADDRESS_OFF (value->ll)); 2537 break; 2538 case VT_FLOAT: 2539 if (value->f == 0.0) 2540 fprintf (out_file, 2541 "<td class=\"td_R%s\"><tt>0. </tt></td>", 2542 style); 2543 else 2544 fprintf (out_file, 2545 "<td class=\"td_R%s\"><tt>%4.3f</tt></td>", 2546 style, value->f); 2547 break; 2548 case VT_SHORT: 2549 fprintf (out_file, "<td class=\"td_R%s\"><tt>%d</tt></td>", 2550 style, value->s); 2551 break; 2552 // ignoring the following cases (why?) 2553 case VT_HRTIME: 2554 case VT_LABEL: 2555 case VT_OFFSET: 2556 break; 2557 } 2558 } 2559 } 2560 2561 if (pvisible) 2562 { 2563 percent = data->get_percentage (item->value[index].to_double (), index); 2564 if (percent == 0.0) 2565 // adjust to change format from xx.yy% 2566 fprintf (out_file, "<td class=\"td_R%s\">0. </td>", 2567 style); 2568 else 2569 // adjust format below to change format from xx.yy% 2570 fprintf (out_file, "<td class=\"td_R%s\">%3.2f</td>", style, 2571 (100.0 * percent)); 2572 } 2573 } 2574 fprintf (out_file, NTXT ("</tr>\n")); 2575 } 2576 2577 void 2578 print_html_trailer (FILE *out_file) 2579 { 2580 fprintf (out_file, NTXT ("</table></center></html>\n")); 2581 } 2582 2583 static char * 2584 del_delim (char *s) 2585 { 2586 size_t len = strlen (s); 2587 if (len > 0) 2588 s[len - 1] = 0; 2589 return s; 2590 } 2591 2592 void 2593 print_delim_label (FILE *out_file, MetricList *metrics_list, char delim) 2594 { 2595 char line0[2 * MAX_LEN], line1[2 * MAX_LEN]; 2596 char line2[2 * MAX_LEN], line3[2 * MAX_LEN]; 2597 size_t len; 2598 2599 // This will print four header rows for the metrics 2600 line0[0] = 0; 2601 line1[0] = 0; 2602 line2[0] = 0; 2603 line3[0] = 0; 2604 Vector<Metric*> *mlist = metrics_list->get_items (); 2605 for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++) 2606 { 2607 Metric *mitem = mlist->fetch (index); 2608 if (!(mitem->is_visible () || mitem->is_tvisible () 2609 || mitem->is_pvisible ())) 2610 continue; 2611 char *name = strdup (mitem->get_name ()); 2612 char *name2 = split_metric_name (name); 2613 2614 if (mitem->is_tvisible ()) 2615 { 2616 len = strlen (line0); 2617 snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"), 2618 mitem->legend == NULL ? NTXT ("") : mitem->legend, delim); 2619 len = strlen (line1); 2620 snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"), 2621 name, delim); 2622 len = strlen (line2); 2623 snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"), 2624 name2 == NULL ? NTXT ("") : name2, delim); 2625 len = strlen (line3); 2626 if (index == metrics_list->get_sort_ref_index ()) 2627 snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"), 2628 GTXT ("(sec.)"), delim); 2629 else 2630 snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"), 2631 GTXT ("(sec.)"), delim); 2632 } 2633 if (mitem->is_visible ()) 2634 { 2635 len = strlen (line0); 2636 snprintf (line0 + len, sizeof (line0) - len, "\"%s\"%c", 2637 mitem->legend == NULL ? "" : mitem->legend, delim); 2638 2639 len = strlen (line1); 2640 snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c", 2641 name, delim); 2642 2643 len = strlen (line2); 2644 snprintf (line2 + len, sizeof (line2) - len, "\"%s\"%c", 2645 name2 == NULL ? NTXT ("") : name2, delim); 2646 2647 len = strlen (line3); 2648 char *au = mitem->get_abbr_unit (); 2649 2650 if (index == metrics_list->get_sort_ref_index ()) 2651 { 2652 if (au == NULL) 2653 snprintf (line3 + len, sizeof (line3) - len, "\"V \"%c", delim); 2654 else 2655 snprintf (line3 + len, sizeof (line3) - len, "\"V (%s)\"%c", 2656 au, delim); 2657 } 2658 else 2659 { 2660 if (au == NULL) 2661 snprintf (line3 + len, sizeof (line3) - len, "\" \"%c", 2662 delim); 2663 else 2664 snprintf (line3 + len, sizeof (line3) - len, "\" (%s)\"%c", 2665 au, delim); 2666 } 2667 } 2668 if (mitem->is_pvisible ()) 2669 { 2670 len = strlen (line0); 2671 snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"), 2672 mitem->legend == NULL ? NTXT ("") : mitem->legend, delim); 2673 2674 len = strlen (line1); 2675 snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"), 2676 name, delim); 2677 2678 len = strlen (line2); 2679 snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"), 2680 name2 == NULL ? NTXT ("") : name2, delim); 2681 2682 len = strlen (line3); 2683 if (index == metrics_list->get_sort_ref_index ()) 2684 snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V %s\"%c"), 2685 NTXT ("%%"), delim); 2686 else 2687 snprintf (line3 + len, sizeof (line3) - len, NTXT ("\" %s\"%c"), 2688 NTXT ("%%"), delim); 2689 } 2690 free (name); 2691 } 2692 // now remove the trailing delimiter, and print the four lines 2693 fprintf (out_file, NTXT ("%s\n"), del_delim (line0)); 2694 fprintf (out_file, NTXT ("%s\n"), del_delim (line1)); 2695 fprintf (out_file, NTXT ("%s\n"), del_delim (line2)); 2696 fprintf (out_file, NTXT ("%s\n"), del_delim (line3)); 2697 } 2698 2699 void 2700 print_delim_content (FILE *out_file, Hist_data *data, MetricList *metrics_list, 2701 int limit, Histable::NameFormat nfmt, char delim) 2702 { 2703 Hist_data::HistItem *item; 2704 int i; 2705 2706 // printing contents. 2707 for (i = 0; i < limit; i++) 2708 { 2709 item = data->fetch (i); 2710 print_delim_one (out_file, data, item, metrics_list, nfmt, delim); 2711 } 2712 } 2713 2714 void 2715 print_delim_trailer (FILE */*out_file*/, char /*delim*/) { } 2716 2717 // EUGENE does this function work properly when "-compare ratio" is used? 2718 // how about when the ratio is nonzero-divided-by-zero? 2719 // EUGENE actually, review this entire file 2720 2721 void 2722 print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item, 2723 MetricList *metrics_list, Histable::NameFormat nfmt, 2724 char delim) 2725 { 2726 Metric *mitem; 2727 int index; 2728 int visible, tvisible, pvisible; 2729 TValue *value; 2730 double percent; 2731 size_t len; 2732 2733 char line1[2 * MAX_LEN]; 2734 *line1 = 0; 2735 Vec_loop (Metric*, metrics_list->get_items (), index, mitem) 2736 { 2737 visible = mitem->is_visible (); 2738 tvisible = mitem->is_tvisible (); 2739 pvisible = mitem->is_pvisible (); 2740 if (tvisible) 2741 { 2742 value = &(item->value[index]); 2743 len = strlen (line1); 2744 if (value->ll == 0LL) 2745 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim); 2746 else 2747 snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c", 2748 1.e-6 * value->ll / dbeSession->get_clock (-1), 2749 delim); 2750 } 2751 2752 if (visible) 2753 { 2754 len = strlen (line1); 2755 if (mitem->get_vtype () == VT_LABEL) 2756 { 2757 value = &(item->value[index]); 2758 char *r; 2759 if (value->tag == VT_OFFSET) 2760 r = ((DataObject*) (item->obj))->get_offset_name (); 2761 else 2762 r = item->obj->get_name (nfmt); 2763 char *p = csv_ize_name (r, delim); 2764 snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c", p, delim); 2765 free (p); 2766 } 2767 else 2768 { 2769 value = &(item->value[index]); 2770 switch (value->tag) 2771 { 2772 case VT_DOUBLE: 2773 if (value->d == 0.0) 2774 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", 2775 delim); 2776 else 2777 snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c", 2778 value->d, delim); 2779 break; 2780 case VT_INT: 2781 snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c", 2782 value->i, delim); 2783 break; 2784 case VT_LLONG: 2785 snprintf (line1 + len, sizeof (line1) - len, "\"%lld\"%c", 2786 value->ll, delim); 2787 break; 2788 case VT_ULLONG: 2789 snprintf (line1 + len, sizeof (line1) - len, "\"%llu\"%c", 2790 value->ull, delim); 2791 break; 2792 case VT_ADDRESS: 2793 snprintf (line1 + len, sizeof (line1) - len, "\"%u:0x%08x\"%c", 2794 ADDRESS_SEG (value->ll), 2795 ADDRESS_OFF (value->ll), delim); 2796 break; 2797 case VT_FLOAT: 2798 if (value->f == 0.0) 2799 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", 2800 delim); 2801 else 2802 snprintf (line1 + len, sizeof (line1) - len, "\"%4.3f\"%c", 2803 value->f, delim); 2804 break; 2805 case VT_SHORT: 2806 snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c", 2807 value->s, delim); 2808 break; 2809 // ignoring the following cases (why?) 2810 case VT_HRTIME: 2811 case VT_LABEL: 2812 case VT_OFFSET: 2813 break; 2814 } 2815 } 2816 } 2817 2818 if (pvisible) 2819 { 2820 len = strlen (line1); 2821 percent = data->get_percentage (item->value[index].to_double (), index); 2822 if (percent == 0.0) 2823 // adjust to change format from xx.yy% 2824 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim); 2825 else 2826 // adjust format below to change format from xx.yy% 2827 snprintf (line1 + len, sizeof (line1) - len, "\"%3.2f\"%c", 2828 (100.0 * percent), delim); 2829 } 2830 } 2831 fprintf (out_file, NTXT ("%s\n"), del_delim (line1)); 2832 } 2833 2834 char * 2835 html_ize_name (char *name) 2836 { 2837 StringBuilder sb; 2838 for (size_t i = 0; i < strlen (name); i++) 2839 { 2840 switch (name[i]) 2841 { 2842 case ' ': sb.append (NTXT (" ")); 2843 break; 2844 case '"': sb.append (NTXT (""")); 2845 break; 2846 case '&': sb.append (NTXT ("&")); 2847 break; 2848 case '<': sb.append (NTXT ("<")); 2849 break; 2850 case '>': sb.append (NTXT (">")); 2851 break; 2852 default: sb.append (name[i]); 2853 break; 2854 } 2855 } 2856 char *ret = sb.toString (); 2857 return ret; 2858 } 2859 2860 char * 2861 csv_ize_name (char *name, char /*delim*/) 2862 { 2863 StringBuilder sb; 2864 for (size_t i = 0; i < strlen (name); i++) 2865 sb.append (name[i]); 2866 char *ret = sb.toString (); 2867 return ret; 2868 } 2869 2870 // Split a metric name into two parts, replacing a blank with 2871 // a zero and returning pointer to the rest of the string, or 2872 // leaving the string unchanged, and returning NULL; 2873 2874 char * 2875 split_metric_name (char *name) 2876 { 2877 // figure out the most even split of the name 2878 size_t len = strlen (name); 2879 char *middle = &name[len / 2]; 2880 2881 // find the first blank 2882 char *first = strchr (name, (int) ' '); 2883 if (first == NULL) // no blanks 2884 return NULL; 2885 char *last = first; 2886 char *p = first; 2887 for (;;) 2888 { 2889 p = strchr (p + 1, (int) ' '); 2890 if (p == NULL) 2891 break; 2892 if (p < middle) 2893 { 2894 first = p; 2895 last = p; 2896 } 2897 else 2898 { 2899 last = p; 2900 break; 2901 } 2902 } 2903 // pick the better of the two 2904 char *ret; 2905 int f = (int) (middle - first); 2906 int l = (int) (last - middle); 2907 if ((first == last) || (f <= l)) 2908 { 2909 *first = '\0'; 2910 ret = first + 1; 2911 } 2912 else 2913 { 2914 *last = '\0'; 2915 ret = last + 1; 2916 } 2917 return ret; 2918 } 2919