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 <assert.h> 23 24#include "util.h" 25#include "DefaultMap.h" 26#include "DbeSession.h" 27#include "Experiment.h" 28#include "DataObject.h" 29#include "Function.h" 30#include "Hist_data.h" 31#include "Histable.h" 32#include "MemObject.h" 33#include "IndexObject.h" 34#include "MetricList.h" 35#include "Metric.h" 36#include "Module.h" 37#include "LoadObject.h" 38#include "Settings.h" 39#include "StringBuilder.h" 40#include "ExpGroup.h" 41#include "PathTree.h" 42#include "DbeView.h" 43#include "FileData.h" 44 45Hist_data::HistItem::HistItem (long n) 46{ 47 obj = NULL; 48 type = 0; 49 size = n; 50 value = new TValue[n]; 51 memset (value, 0, sizeof (TValue) * n); 52} 53 54Hist_data::HistItem::~HistItem () 55{ 56 for (long i = 0; i < size; i++) 57 if (value[i].tag == VT_LABEL) 58 free (value[i].l); 59 delete[] value; 60} 61 62long 63Hist_data::size () 64{ 65 // If the data values have not been computed, do so 66 // Return the total number of items 67 return hist_items->size (); 68} 69 70Hist_data::HistItem * 71Hist_data::fetch (long index) 72{ 73 return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL; 74} 75 76int 77Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype, 78 long ind, Hist_data *hdata) 79{ 80 // Sort the data depending upon order and type 81 int result = 0; 82 Histable::Type type = hi_1->obj->get_type (); 83 if (stype == ALPHA) 84 { 85 if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ 86 && type != Histable::IOACTVFD && type != Histable::IOACTFILE 87 && type != Histable::IOCALLSTACK) 88 { 89 char *nm1 = hi_1->obj->get_name (); 90 char *nm2 = hi_2->obj->get_name (); 91 if (nm1 != NULL && nm2 != NULL) 92 result = strcoll (nm1, nm2); 93 } 94 else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD 95 || type == Histable::IOACTFILE) 96 { 97 uint64_t idx1, idx2; 98 idx1 = ((FileData *) (hi_1->obj))->get_index (); 99 idx2 = ((FileData *) (hi_2->obj))->get_index (); 100 if (idx1 < idx2) 101 result = -1; 102 else if (idx1 > idx2) 103 result = 1; 104 else 105 result = 0; 106 } 107 else 108 { 109 // for memory and index objects, "alphabetic" is really by index 110 // <Total> has index -2, and always comes first 111 // <Unknown> has index -1, and always comes second. 112 uint64_t i1, i2; 113 bool needsStringCompare = false; 114 if (type == Histable::MEMOBJ) 115 { 116 i1 = ((MemObj *) (hi_1->obj))->get_index (); 117 i2 = ((MemObj *) (hi_2->obj))->get_index (); 118 } 119 else if (type == Histable::INDEXOBJ) 120 { 121 i1 = ((IndexObject *) (hi_1->obj))->get_index (); 122 i2 = ((IndexObject *) (hi_2->obj))->get_index (); 123 needsStringCompare = 124 ((IndexObject *) (hi_1->obj))->requires_string_sort (); 125 } 126 else 127 abort (); 128 if (i1 == (uint64_t) - 2) 129 result = -1; 130 else if (i2 == (uint64_t) - 2) 131 result = 1; 132 else if (i1 == (uint64_t) - 1) 133 result = -1; 134 else if (i2 == (uint64_t) - 1) 135 result = 1; 136 else if (needsStringCompare) 137 { 138 char *nm1 = hi_1->obj->get_name (); 139 char *nm2 = hi_2->obj->get_name (); 140 if (nm1 != NULL && nm2 != NULL) 141 { 142 char nm1_lead = nm1[0]; 143 char nm2_lead = nm2[0]; 144 // put "(unknown)" and friends at end of list 145 if (nm1_lead == '(' && nm1_lead != nm2_lead) 146 result = 1; 147 else if (nm2_lead == '(' && nm1_lead != nm2_lead) 148 result = -1; 149 else 150 result = strcoll (nm1, nm2); 151 } 152 } 153 if (result == 0) 154 { // matches, resolve by index 155 if (i1 < i2) 156 result = -1; 157 else if (i1 > i2) 158 result = 1; 159 } 160 } 161 } 162 else if (stype == AUX) 163 { 164 switch (type) 165 { 166 case Histable::INSTR: 167 { 168 DbeInstr *instr1 = (DbeInstr*) hi_1->obj; 169 DbeInstr *instr2 = (DbeInstr*) hi_2->obj; 170 result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0; 171 break; 172 } 173 case Histable::LINE: 174 { 175 DbeLine *dbl1 = (DbeLine*) hi_1->obj; 176 DbeLine *dbl2 = (DbeLine*) hi_2->obj; 177 result = dbl1->line_cmp (dbl2); 178 } 179 break; 180 default: 181 assert (0); 182 } 183 } 184 else if (stype == VALUE) 185 { 186 Metric *m = hdata->get_metric_list ()->get (ind); 187 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0) 188 { 189 TValue v1, v2; 190 int first_ind = hdata->hist_metrics[ind].indFirstExp; 191 if ((m->get_visbits () & VAL_DELTA) != 0) 192 { 193 v1.make_delta (hi_1->value + ind, hi_1->value + first_ind); 194 v2.make_delta (hi_2->value + ind, hi_2->value + first_ind); 195 } 196 else 197 { 198 v1.make_ratio (hi_1->value + ind, hi_1->value + first_ind); 199 v2.make_ratio (hi_2->value + ind, hi_2->value + first_ind); 200 } 201 result = v1.compare (&v2); 202 } 203 else 204 result = hi_1->value[ind].compare (hi_2->value + ind); 205 } 206 return result; 207} 208 209int 210Hist_data::sort_compare_all (const void *a, const void *b, const void *arg) 211{ 212 HistItem *hi_1 = *((HistItem **) a); 213 HistItem *hi_2 = *((HistItem **) b); 214 215 Hist_data *hdata = (Hist_data*) arg; 216 int result = sort_compare (hi_1, hi_2, hdata->sort_type, hdata->sort_ind, hdata); 217 if (hdata->sort_order == DESCEND) 218 result = -result; 219 220 // Use the name as the 2d sort key (always ASCEND) 221 // except for MemoryObjects and IndexObjects, where the index is used 222 // For the Alphabetic sort 223 if (result == 0) 224 { 225 result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL); 226 if (result == 0) 227 { 228 for (long i = 0, sz = hdata->metrics->size (); i < sz; i++) 229 { 230 Metric *m = hdata->metrics->get (i); 231 if (m->get_type () != Metric::ONAME) 232 { 233 result = sort_compare (hi_1, hi_2, VALUE, i, hdata); 234 if (result != 0) 235 { 236 if (hdata->sort_order == DESCEND) 237 result = -result; 238 break; 239 } 240 } 241 } 242 } 243 } 244 245 // Use the address as the 3d sort key 246 // ( FUNCTION only, always ASCEND ) 247 if (result == 0 && hi_1->obj->get_type () == Histable::FUNCTION) 248 { 249 Function *f1 = (Function*) hi_1->obj; 250 Function *f2 = (Function*) hi_2->obj; 251 if (f1->get_addr () < f2->get_addr ()) 252 result = -1; 253 else if (f1->get_addr () > f2->get_addr ()) 254 result = 1; 255 } 256 257 // Use the Histable id (ID of function, line, etc.) as the 4th sort key 258 // Note that IDs are not guaranteed to be stable, 259 if (result == 0) 260 { 261 if (hi_1->obj->id < hi_2->obj->id) 262 result = -1; 263 else if (hi_1->obj->id > hi_2->obj->id) 264 result = 1; 265 } 266 267 if (result == 0) 268 return result; // shouldn't happen in most cases; line allows for breakpoint 269 if (hdata->rev_sort) 270 result = -result; 271 return result; 272} 273 274int 275Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg) 276{ 277 assert ((a != (const void *) NULL)); 278 assert ((b != (const void *) NULL)); 279 HistItem *hi_1 = *((HistItem **) a); 280 HistItem *hi_2 = *((HistItem **) b); 281 DataObject * dobj1 = (DataObject *) (hi_1->obj); 282 DataObject * dobj2 = (DataObject *) (hi_2->obj); 283 DataObject * parent1 = dobj1->parent; 284 DataObject * parent2 = dobj2->parent; 285 286 Hist_data *hdata = (Hist_data*) arg; 287 288 // are the two items members of the same object? 289 if (parent1 == parent2) 290 { 291 // yes 292 if (parent1) 293 { 294 // and they have real parents... 295 if (parent1->get_typename ()) 296 { // element 297 // use dobj1/dobj2 offset for sorting 298 uint64_t off1 = dobj1->get_offset (); 299 uint64_t off2 = dobj2->get_offset (); 300 if (off1 < off2) 301 return -1; 302 if (off1 > off2) 303 return 1; 304 return 0; 305 } 306 } 307 } 308 else 309 { // parents differ 310 if (parent1) 311 { 312 if (parent1 == dobj2) 313 // sorting an object and its parent: parent always first 314 return 1; 315 dobj1 = parent1; 316 } 317 if (parent2) 318 { 319 if (parent2 == dobj1) 320 return -1; 321 dobj2 = parent2; 322 } 323 } 324 // Either two unknowns, or two scalars, or two parents 325 hi_1 = hdata->hi_map->get (dobj1); 326 hi_2 = hdata->hi_map->get (dobj2); 327 return sort_compare_all ((const void*) &hi_1, (const void*) &hi_2, hdata); 328} 329 330Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type, 331 Hist_data::Mode _mode, bool _viewowned) 332{ 333 hist_items = new Vector<HistItem*>; 334 metrics = _metrics; 335 nmetrics = metrics->get_items ()->size (); 336 type = _type; 337 mode = _mode; 338 gprof_item = new_hist_item (NULL); 339 viewowned = _viewowned; 340 sort_ind = -1; 341 rev_sort = false; 342 343 Histable *tobj = new Other; 344 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); 345 minimum = new_hist_item (tobj); 346 347 tobj = new Other; 348 tobj->name = dbe_strdup (NTXT ("")); 349 maximum = new_hist_item (tobj); 350 351 tobj = new Other; 352 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx")); 353 maximum_inc = new_hist_item (tobj); 354 355 tobj = new Other; 356 tobj->name = dbe_strdup (NTXT ("<Total>")); 357 total = new_hist_item (tobj); 358 359 tobj = new Other; 360 tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX")); 361 threshold = new_hist_item (tobj); 362 363 hi_map = new HashMap<Histable*, HistItem*>; 364 callsite_mark = new DefaultMap<Histable*, int>; 365 hist_metrics = new Metric::HistMetric[metrics->size ()]; 366 for (long i = 0, sz = metrics->size (); i < sz; i++) 367 { 368 Metric::HistMetric *h = hist_metrics + i; 369 h->init (); 370 Metric *m = metrics->get (i); 371 if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO))) 372 h->indFirstExp = 373 metrics->get_listorder (m->get_cmd (), 374 m->get_subtype (), "EXPGRID==1"); 375 if (m->is_tvisible () && m->get_type () == BaseMetric::HWCNTR 376 && m->get_dependent_bm ()) 377 h->indTimeVal = 378 metrics->get_listorder (m->get_dependent_bm ()->get_cmd (), 379 m->get_subtype (), m->get_expr_spec ()); 380 } 381 status = NO_DATA; 382} 383 384Hist_data::~Hist_data () 385{ 386 delete[] hist_metrics; 387 if (hist_items) 388 { 389 hist_items->destroy (); 390 delete hist_items; 391 hist_items = NULL; 392 } 393 if (gprof_item) 394 { 395 delete gprof_item; 396 gprof_item = NULL; 397 } 398 if (maximum) 399 { 400 delete maximum->obj; 401 delete maximum; 402 maximum = NULL; 403 } 404 if (maximum_inc) 405 { 406 delete maximum_inc->obj; 407 delete maximum_inc; 408 maximum_inc = NULL; 409 } 410 if (minimum) 411 { 412 delete minimum->obj; 413 delete minimum; 414 minimum = NULL; 415 } 416 if (total) 417 { 418 delete total->obj; 419 delete total; 420 total = NULL; 421 } 422 if (threshold) 423 { 424 delete threshold->obj; 425 delete threshold; 426 threshold = NULL; 427 } 428 delete metrics; 429 delete hi_map; 430 delete callsite_mark; 431} 432 433void 434Hist_data::dump (char *msg, FILE *f) 435{ 436 fprintf (f, " Hist_data dump: %s\n", msg); 437 fprintf (f, " %d=%d metrics\n", (int) nmetrics, (int) metrics->size ()); 438 for (int i = 0; i < nmetrics; i++) 439 { 440 Metric *m = metrics->get_items ()->fetch (i); 441 char *s = m->get_expr_spec (); 442 fprintf (f, " %4d %15s %4d %15s\n", i, m->get_mcmd (0), 443 m->get_id (), s ? s : "(NULL)"); 444 } 445 446 fprintf (f, NTXT (" HistItem listing\n")); 447 int n = hist_items->size (); 448 for (int j = -1; j < n; j++) 449 { 450 HistItem *hi; 451 if (j < 0) 452 { 453 hi = total; 454 fprintf (f, NTXT (" total")); 455 } 456 else 457 { 458 hi = hist_items->fetch (j); 459 fprintf (f, NTXT ("%30s"), hi->obj->get_name ()); 460 } 461 for (int i = 0; i < nmetrics; i++) 462 { 463 char *stmp = hi->value[i].l; 464 switch (hi->value[i].tag) 465 { 466 case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s); 467 break; 468 case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i); 469 break; 470 case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); 471 break; 472 case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f); 473 break; 474 case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d); 475 break; 476 case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); 477 break; 478 case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)"); 479 break; 480 case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll); 481 break; 482 case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p); 483 break; 484 case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull); 485 break; 486 default: fprintf (f, NTXT (" ")); 487 break; 488 } 489 } 490 fprintf (f, NTXT ("\n")); 491 } 492} 493 494void 495Hist_data::sort (long ind, bool reverse) 496{ 497 if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort) 498 // there's no change to the sorting 499 return; 500 501 if (mode == MODL) 502 { 503 sort_type = AUX; 504 sort_order = ASCEND; 505 } 506 else 507 { 508 if (ind == -1) 509 return; 510 Metric::Type mtype = metrics->get_items ()->fetch (ind)->get_type (); 511 sort_type = mtype == Metric::ONAME ? ALPHA : VALUE; 512 sort_order = (mtype == Metric::ONAME || mtype == Metric::ADDRESS) ? 513 ASCEND : DESCEND; 514 sort_ind = ind; 515 rev_sort = reverse; 516 } 517 518 if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL) 519 hist_items->sort ((CompareFunc) sort_compare_dlayout, this); 520 else 521 hist_items->sort ((CompareFunc) sort_compare_all, this); 522 523 // ensure that <Total> comes first/last 524 char *tname = NTXT ("<Total>"); 525 for (int i = 0; i < hist_items->size (); ++i) 526 { 527 HistItem *hi = hist_items->fetch (i); 528 char *name = hi->obj->get_name (); 529 if (name != NULL && streq (name, tname)) 530 { 531 int idx0 = rev_sort ? hist_items->size () - 1 : 0; 532 if (i != idx0) 533 { 534 hist_items->remove (i); 535 hist_items->insert (idx0, hi); 536 } 537 break; 538 } 539 } 540} 541 542void 543Hist_data::resort (MetricList *mlist) 544{ 545 if (mlist->get_type () != metrics->get_type ()) 546 if (metrics->get_type () == MET_CALL) 547 // wrong type of list -- internal error 548 abort (); 549 550 // get the new sort order 551 int ind = mlist->get_sort_ref_index (); 552 bool reverse = mlist->get_sort_rev (); 553 sort (ind, reverse); 554} 555 556void 557Hist_data::compute_minmax () 558{ 559 HistItem *hi; 560 int index; 561 562 for (int mind = 0; mind < nmetrics; mind++) 563 { 564 Metric *mtr = metrics->get_items ()->fetch (mind); 565 if (mtr->get_subtype () == Metric::STATIC) 566 continue; 567 if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ()) 568 continue; 569 ValueTag vtype = mtr->get_vtype2 (); 570 571 switch (vtype) 572 { 573 case VT_INT: 574 minimum->value[mind].tag = VT_INT; 575 minimum->value[mind].i = 0; 576 maximum->value[mind].tag = VT_INT; 577 maximum->value[mind].i = 0; 578 maximum_inc->value[mind].tag = VT_INT; 579 maximum_inc->value[mind].i = 0; 580 581 Vec_loop (HistItem *, hist_items, index, hi) 582 { 583 if (metrics->get_type () == MET_SRCDIS 584 && callsite_mark->get (hi->obj)) 585 { 586 if (hi->value[mind].i > maximum_inc->value[mind].i) 587 maximum_inc->value[mind].i = hi->value[mind].i; 588 // ignore ones that has inclusive time for src/dis view 589 } 590 else if (hi->value[mind].i > maximum->value[mind].i) 591 maximum->value[mind].i = hi->value[mind].i; 592 if (hi->value[mind].i < minimum->value[mind].i) 593 minimum->value[mind].i = hi->value[mind].i; 594 } 595 break; 596 case VT_DOUBLE: 597 minimum->value[mind].tag = VT_DOUBLE; 598 minimum->value[mind].d = 0.0; 599 maximum->value[mind].tag = VT_DOUBLE; 600 maximum->value[mind].d = 0.0; 601 maximum_inc->value[mind].tag = VT_DOUBLE; 602 maximum_inc->value[mind].d = 0.0; 603 Vec_loop (HistItem*, hist_items, index, hi) 604 { 605 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj)) 606 { 607 if (hi->value[mind].d > maximum_inc->value[mind].d) 608 { 609 maximum_inc->value[mind].d = hi->value[mind].d; 610 maximum_inc->value[mind].sign = hi->value[mind].sign; 611 } 612 // ignore ones that has inclusive time for src/dis view 613 } 614 else 615 { 616 if (hi->value[mind].d > maximum->value[mind].d) 617 { 618 maximum->value[mind].d = hi->value[mind].d; 619 maximum->value[mind].sign = hi->value[mind].sign; 620 } 621 if (hi->value[mind].d < minimum->value[mind].d) 622 { 623 minimum->value[mind].d = hi->value[mind].d; 624 minimum->value[mind].sign = hi->value[mind].sign; 625 } 626 } 627 } 628 break; 629 case VT_LLONG: 630 case VT_ULLONG: 631 case VT_ADDRESS: 632 minimum->value[mind].tag = vtype; 633 minimum->value[mind].ll = 0; 634 maximum->value[mind].tag = vtype; 635 maximum->value[mind].ll = 0; 636 maximum_inc->value[mind].tag = vtype; 637 maximum_inc->value[mind].ll = 0; 638 Vec_loop (HistItem*, hist_items, index, hi) 639 { 640 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj)) 641 { 642 if (hi->value[mind].ll > maximum_inc->value[mind].ll) 643 { 644 maximum_inc->value[mind].ll = hi->value[mind].ll; 645 maximum_inc->value[mind].sign = hi->value[mind].sign; 646 } 647 // ignore ones that has inclusive time for src/dis view 648 } 649 else 650 { 651 if (hi->value[mind].ll > maximum->value[mind].ll) 652 { 653 maximum->value[mind].ll = hi->value[mind].ll; 654 maximum->value[mind].sign = hi->value[mind].sign; 655 } 656 if (hi->value[mind].ll < minimum->value[mind].ll) 657 { 658 minimum->value[mind].ll = hi->value[mind].ll; 659 minimum->value[mind].sign = hi->value[mind].sign; 660 } 661 } 662 } 663 break; 664 default: 665 break; 666 } 667 } 668} 669 670Hist_data::HistItem * 671Hist_data::new_hist_item (Histable *obj) 672{ 673 long sz = get_metric_list ()->size (); 674 HistItem *hi = new HistItem (sz); 675 hi->obj = obj; 676 677 // We precalculate all metrics as integer values 678 // and convert them to appropriate types later. 679 for (long i = 0; i < sz; i++) 680 { 681 hi->value[i].tag = VT_INT; 682 hi->value[i].i = 0; 683 } 684 return hi; 685} 686 687Hist_data::HistItem * 688Hist_data::new_hist_item (Histable *obj, int itype, TValue *value) 689{ 690 long sz = get_metric_list ()->size (); 691 HistItem *hi = new HistItem (sz); 692 hi->obj = obj; 693 hi->type = itype; 694 if (value) 695 for (long i = 0; i < sz; i++) 696 hi->value[i] = value[i]; 697 698 return hi; 699} 700 701Hist_data::HistItem * 702Hist_data::find_hist_item (Histable *obj) 703{ 704 if (obj == NULL) 705 return NULL; 706 return hi_map->get (obj); 707} 708 709Hist_data::HistItem * 710Hist_data::append_hist_item (Histable *obj) 711{ 712 if (obj == NULL) 713 return NULL; 714 HistItem *hi = hi_map->get (obj); 715 if (hi == NULL) 716 { 717 hi = new_hist_item (obj); 718 hist_items->append (hi); 719 hi_map->put (obj, hi); 720 } 721 if (status == NO_DATA) 722 status = SUCCESS; 723 return hi; 724} 725 726void 727Hist_data::append_hist_item (HistItem *hi) 728{ 729 hist_items->append (hi); 730} 731 732bool 733Hist_data::above_threshold (HistItem* hi) 734{ 735 bool mark = false; 736 int index; 737 Metric *mitem; 738 739 Vec_loop (Metric*, metrics->get_items (), index, mitem) 740 { 741 if (mitem->get_subtype () == Metric::STATIC) 742 continue; 743 switch (hi->value[index].tag) 744 { 745 case VT_DOUBLE: 746 if (hi->value[index].d > threshold->value[index].d) 747 mark = true; 748 break; 749 case VT_INT: 750 if (hi->value[index].i > threshold->value[index].i) 751 mark = true; 752 break; 753 case VT_LLONG: 754 if (hi->value[index].ll > threshold->value[index].ll) 755 mark = true; 756 break; 757 case VT_ULLONG: 758 if (hi->value[index].ull > threshold->value[index].ull) 759 mark = true; 760 break; 761 // ignoring the following cases (why?) 762 case VT_SHORT: 763 case VT_FLOAT: 764 case VT_HRTIME: 765 case VT_LABEL: 766 case VT_ADDRESS: 767 case VT_OFFSET: 768 break; 769 } 770 } 771 return mark; 772} 773 774void 775Hist_data::set_threshold (double proportion) 776{ 777 int index; 778 Metric *mitem; 779 Vec_loop (Metric*, metrics->get_items (), index, mitem) 780 { 781 TValue *thresh = &threshold->value[index]; 782 TValue *mtotal = &total->value[index]; 783 thresh->tag = mitem->get_vtype (); 784 785 if (mitem->get_subtype () == Metric::STATIC) 786 continue; 787 switch (thresh->tag) 788 { 789 case VT_INT: 790 thresh->i = (int) (proportion * (double) mtotal->i); 791 break; 792 case VT_DOUBLE: 793 thresh->d = proportion * mtotal->d; 794 break; 795 case VT_LLONG: 796 case VT_ULLONG: 797 thresh->ull = (unsigned long long) (proportion * (double) mtotal->ll); 798 break; 799 case VT_SHORT: 800 case VT_FLOAT: 801 case VT_HRTIME: 802 case VT_LABEL: 803 case VT_ADDRESS: 804 case VT_OFFSET: 805 break; 806 } 807 } 808} 809 810double 811Hist_data::get_percentage (double value, int mindex) 812{ 813 double total_value; 814 if (value == 0.0) 815 return 0.0; 816 817 // Get the total value of this sample set. 818 // The value must be greater than 0. 819 total_value = total->value[mindex].to_double (); 820 821 // Find out what percentage of the total value this item is. 822 // Make sure we don't divide by zero. 823 if (total_value == 0.0) 824 return 0.0; 825 return value / total_value; 826} 827 828int 829Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric, 830 int space) 831{ 832 int name_offset = 0; 833 StringBuilder sb, sb1, sb2, sb3; 834 if (space > 0) 835 { 836 char *fmt = NTXT ("%*s"); 837 sb.appendf (fmt, space, NTXT ("")); 838 sb1.appendf (fmt, space, NTXT ("")); 839 sb2.appendf (fmt, space, NTXT ("")); 840 sb3.appendf (fmt, space, NTXT ("")); 841 } 842 for (int i = 0; i < nmetrics; i++) 843 { 844 Metric *m = metrics->get (i); 845 Metric::HistMetric *hm = &hist_metric[i]; 846 int len = hm->width; 847 char *fmt = NTXT ("%-*s"); 848 if ((i > 0) && (m->get_type () == Metric::ONAME)) 849 { 850 name_offset = sb1.length (); 851 fmt = NTXT (" %-*s"); 852 len--; 853 } 854 sb.appendf (fmt, len, m->legend ? m->legend : NTXT ("")); 855 sb1.appendf (fmt, len, hm->legend1); 856 sb2.appendf (fmt, len, hm->legend2); 857 sb3.appendf (fmt, len, hm->legend3); 858 } 859 sb.trim (); 860 if (sb.length () != 0) 861 { 862 sb.toFileLn (out_file); 863 } 864 sb1.toFileLn (out_file); 865 sb2.toFileLn (out_file); 866 sb3.toFileLn (out_file); 867 return name_offset; 868} 869 870void 871Hist_data::print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit) 872{ 873 StringBuilder sb; 874 int cnt = VecSize (hist_items); 875 if (cnt > limit && limit > 0) 876 cnt = limit; 877 for (int i = 0; i < cnt; i++) 878 { 879 sb.setLength (0); 880 print_row (&sb, i, hist_metric, NTXT (" ")); 881 sb.toFileLn (out_file); 882 } 883} 884 885static void 886append_str (StringBuilder *sb, char *s, size_t len, int vis_bits) 887{ 888 if ((vis_bits & VAL_RATIO) != 0) 889 { 890 if (*s != 'N') // Nan 891 sb->appendf (NTXT ("x ")); 892 else 893 sb->appendf (NTXT (" ")); 894 sb->appendf (NTXT ("%*s"), (int) (len - 2), s); 895 } 896 else 897 sb->appendf (NTXT ("%*s"), (int) len, s); 898} 899 900void 901Hist_data::print_row (StringBuilder *sb, int row, Metric::HistMetric *hmp, 902 const char *mark) 903{ 904 TValue res; 905 char buf[256]; 906 // Print only a list of user's metrics. ( nmetrics <= mlist->size() ) 907 for (long i = 0; i < nmetrics; i++) 908 { 909 // Print only a list of user's metrics. 910 Metric *m = metrics->get (i); 911 if (!m->is_any_visible ()) 912 continue; 913 Metric::HistMetric *hm = hmp + i; 914 int len = sb->length (); 915 if (m->is_tvisible ()) 916 { 917 TValue *v = get_value (&res, hist_metrics[i].indTimeVal, row); 918 char *s = v->to_str (buf, sizeof (buf)); 919 append_str (sb, s, hm->maxtime_width, m->get_visbits ()); 920 } 921 if (m->is_visible ()) 922 { 923 TValue *v = get_value (&res, i, row); 924 char *s = v->to_str (buf, sizeof (buf)); 925 if (m->get_type () == BaseMetric::ONAME) 926 { 927 sb->append (mark); 928 if (i + 1 == nmetrics) 929 sb->appendf (NTXT ("%s"), s); 930 else 931 sb->appendf (NTXT ("%-*s "), (int) hm->maxvalue_width, s); 932 continue; 933 } 934 else 935 { 936 if (len != sb->length ()) 937 sb->append (' '); 938 append_str (sb, s, hm->maxvalue_width, m->get_visbits ()); 939 } 940 } 941 if (m->is_pvisible ()) 942 { 943 if (len != sb->length ()) 944 sb->append (' '); 945 long met_ind = i; 946 if (m->is_tvisible () && !m->is_visible ()) 947 met_ind = hist_metrics[i].indTimeVal; 948 TValue *v = get_real_value (&res, met_ind, row); 949 double percent = get_percentage (v->to_double (), met_ind); 950 if (percent == 0.0) 951 // adjust to change format from xx.yy% 952 sb->append (NTXT (" 0. ")); 953 else 954 // adjust format below to change format from xx.yy% 955 sb->appendf (NTXT ("%6.2f"), (100.0 * percent)); 956 } 957 len = sb->length () - len; 958 if (hm->width > len && i + 1 != nmetrics) 959 sb->appendf (NTXT ("%*s"), (int) (hm->width - len), NTXT (" ")); 960 } 961} 962 963TValue * 964Hist_data::get_real_value (TValue *res, int met_index, int row) 965{ 966 HistItem *hi = hist_items->get (row); 967 Metric *m = metrics->get (met_index); 968 if (m->get_type () == BaseMetric::ONAME) 969 { 970 res->l = dbe_strdup (hi->obj->get_name ()); 971 res->tag = VT_LABEL; 972 return res; 973 } 974 return hi->value + met_index; 975} 976 977TValue * 978Hist_data::get_value (TValue *res, int met_index, int row) 979{ 980 HistItem *hi = hist_items->get (row); 981 Metric *m = metrics->get (met_index); 982 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0) 983 { 984 int ind = hist_metrics[met_index].indFirstExp; 985 if ((m->get_visbits () & VAL_DELTA) != 0) 986 res->make_delta (hi->value + met_index, hi->value + ind); 987 else 988 res->make_ratio (hi->value + met_index, hi->value + ind); 989 return res; 990 } 991 return get_real_value (res, met_index, row); 992} 993 994TValue * 995Hist_data::get_value (TValue *res, int met_index, HistItem *hi) 996{ 997 Metric *m = metrics->get (met_index); 998 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0) 999 { 1000 int ind = hist_metrics[met_index].indFirstExp; 1001 if ((m->get_visbits () & VAL_DELTA) != 0) 1002 res->make_delta (hi->value + met_index, hi->value + ind); 1003 else 1004 res->make_ratio (hi->value + met_index, hi->value + ind); 1005 return res; 1006 } 1007 if (m->get_type () == BaseMetric::ONAME) 1008 { 1009 res->l = dbe_strdup (hi->obj->get_name ()); 1010 res->tag = VT_LABEL; 1011 return res; 1012 } 1013 return hi->value + met_index; 1014} 1015 1016Metric::HistMetric * 1017Hist_data::get_histmetrics () 1018{ 1019 // find the width for each column. 1020 for (long i = 0, sz = metrics->size (); i < sz; i++) 1021 { 1022 Metric *m = metrics->get (i); 1023 Metric::HistMetric *hm = hist_metrics + i; 1024 if (m->is_value_visible ()) 1025 { 1026 TValue res; 1027 for (long i1 = 0, sz1 = VecSize(hist_items); i1 < sz1; i1++) 1028 { 1029 TValue *v = get_value (&res, i, i1); 1030 long len = v->get_len (); 1031 if (hm->maxvalue_width < len) 1032 hm->maxvalue_width = len; 1033 } 1034 if ((m->get_visbits () & VAL_RATIO) != 0) 1035 hm->maxvalue_width += 2; // "x " 1036 } 1037 } 1038 1039 for (long i = 0, sz = metrics->size (); i < sz; i++) 1040 { 1041 Metric *m = metrics->get (i); 1042 Metric::HistMetric *hm = hist_metrics + i; 1043 if (m->is_time_visible ()) 1044 // take a value from depended metric 1045 hm->maxtime_width = hist_metrics[hm->indTimeVal].maxvalue_width; 1046 m->legend_width (hm, 2); 1047 } 1048 return hist_metrics; 1049} 1050 1051void 1052Hist_data::update_total (Hist_data::HistItem *new_total) 1053{ 1054 for (long i = 0, sz = metrics->size (); i < sz; i++) 1055 total->value[i] = new_total->value[i]; 1056} 1057 1058void 1059Hist_data::update_max (Metric::HistMetric *hm_tmp) 1060{ 1061 Metric::HistMetric *hms = get_histmetrics (); 1062 for (int i = 0; i < nmetrics; i++) 1063 { 1064 Metric::HistMetric *hm = hms + i; 1065 Metric::HistMetric *hm1 = hm_tmp + i; 1066 if (hm1->maxtime_width < hm->maxtime_width) 1067 hm1->maxtime_width = hm->maxtime_width; 1068 if (hm1->maxvalue_width < hm->maxvalue_width) 1069 hm1->maxvalue_width = hm->maxvalue_width; 1070 } 1071} 1072 1073void 1074Hist_data::update_legend_width (Metric::HistMetric *hm_tmp) 1075{ 1076 for (int i = 0; i < nmetrics; i++) 1077 { 1078 Metric *m = metrics->get (i); 1079 m->legend_width (hm_tmp + i, 2); 1080 } 1081} 1082 1083void 1084Metric::HistMetric::update_max (Metric::HistMetric *hm) 1085{ 1086 if (maxtime_width < hm->maxtime_width) 1087 maxtime_width = hm->maxtime_width; 1088 if (maxvalue_width < hm->maxvalue_width) 1089 maxvalue_width = hm->maxvalue_width; 1090} 1091 1092void 1093Metric::HistMetric::init () 1094{ 1095 width = 0; 1096 maxvalue_width = 0; 1097 maxtime_width = 0; 1098 legend1[0] = 0; 1099 legend2[0] = 0; 1100 legend3[0] = 0; 1101 indFirstExp = -1; 1102 indTimeVal = -1; 1103} 1104 1105size_t 1106Hist_data::value_maxlen (int mindex) 1107{ 1108 size_t maxlen = maximum->value[mindex].get_len (); 1109 size_t minlen = minimum->value[mindex].get_len (); 1110 // minlen can be bigger than maxlen only for negative value 1111 return minlen > maxlen ? minlen : maxlen; 1112} 1113 1114size_t 1115Hist_data::time_len (TValue *value, int clock) 1116{ 1117 TValue tm_value; 1118 tm_value.tag = VT_DOUBLE; 1119 tm_value.sign = value->sign; 1120 tm_value.d = 1.e-6 * value->ll / clock; 1121 return tm_value.get_len (); 1122} 1123 1124size_t 1125Hist_data::time_maxlen (int mindex, int clock) 1126{ 1127 size_t maxlen = time_len (&(maximum->value[mindex]), clock); 1128 size_t minlen = time_len (&(minimum->value[mindex]), clock); 1129 // minlen can be bigger than maxlen only for negative value 1130 return minlen > maxlen ? minlen : maxlen; 1131} 1132 1133size_t 1134Hist_data::name_len (HistItem *item) 1135{ 1136 char *name = item->obj->get_name (); 1137 return strlen (name); 1138} 1139 1140size_t 1141Hist_data::name_maxlen () 1142{ 1143 size_t res = 0; 1144 for (long i = 0; i < size (); i++) 1145 { 1146 HistItem *hi = fetch (i); 1147 size_t len = name_len (hi); 1148 if (res < len) 1149 res = len; 1150 } 1151 return res; 1152} 1153 1154// Returns vector of object ids for the vector of selections 1155// returns NULL if no valid selections 1156Vector<uint64_t> * 1157Hist_data::get_object_indices (Vector<int> *selections) 1158{ 1159 // if no selections, return NULL 1160 if (selections == NULL || selections->size () == 0) 1161 return NULL; 1162 1163 Vector<uint64_t> *indices = new Vector<uint64_t>; 1164 for (long i = 0, sz = selections->size (); i < sz; i++) 1165 { 1166 int sel = selections->get (i); 1167 HistItem *hi = hist_items->get (sel); 1168 if (hi == NULL || hi->obj == NULL) 1169 continue; 1170 Vector<Histable*> *v = hi->obj->get_comparable_objs (); 1171 for (long i1 = 0, sz1 = v ? v->size () : 0; i1 < sz1; i1++) 1172 { 1173 Histable *h1 = v->get (i1); 1174 if (h1 && (indices->find_r (h1->id) < 0)) 1175 indices->append (h1->id); 1176 } 1177 if (indices->find_r (hi->obj->id) < 0) 1178 indices->append (hi->obj->id); 1179 } 1180 return indices; 1181} 1182 1183DbeInstr::DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr) 1184{ 1185 id = _id; 1186 flags = _flags; 1187 addr = _addr; 1188 func = _func; 1189 img_offset = addr + func->img_offset; 1190 lineno = -1; 1191 size = 0; 1192 current_name_format = NA; 1193 isUsed = false; 1194 inlinedInd = -1; 1195} 1196 1197int 1198DbeInstr::pc_cmp (DbeInstr *instr2) 1199{ 1200 int result = 0; 1201 if (instr2 == NULL) 1202 return -1; 1203 1204 // All PC's with the Line flag go to the 1205 // end of the list. See Module::init_index() 1206 if (flags & PCLineFlag) 1207 { 1208 if (instr2->flags & PCLineFlag) 1209 { 1210 if (addr < instr2->addr) 1211 result = -1; 1212 else if (addr > instr2->addr) 1213 result = 1; 1214 else 1215 result = 0; 1216 } 1217 else 1218 result = 1; 1219 } 1220 else if (instr2->flags & PCLineFlag) 1221 result = -1; 1222 else if (func == instr2->func) 1223 { 1224 if (size == 0) 1225 { 1226 if (addr < instr2->addr) 1227 result = -1; 1228 else if (addr == instr2->addr) 1229 result = 0; 1230 else if (addr >= instr2->addr + instr2->size) 1231 result = 1; 1232 else 1233 result = 0; 1234 } 1235 else if (instr2->size == 0) 1236 { 1237 if (addr > instr2->addr) 1238 result = 1; 1239 else if (addr + size <= instr2->addr) 1240 result = -1; 1241 else 1242 result = 0; 1243 } 1244 else if (addr < instr2->addr) 1245 result = -1; 1246 else if (addr > instr2->addr) 1247 result = 1; 1248 else 1249 result = 0; 1250 1251 if (result == 0) 1252 { 1253 if (flags & PCTrgtFlag) 1254 { 1255 if (!(instr2->flags & PCTrgtFlag)) 1256 result = -1; 1257 } 1258 else if (instr2->flags & PCTrgtFlag) 1259 result = 1; 1260 } 1261 } 1262 else 1263 result = func->func_cmp (instr2->func); 1264 return result; 1265} 1266 1267char * 1268DbeInstr::get_name (NameFormat nfmt) 1269{ 1270 if (name && (nfmt == current_name_format || nfmt == Histable::NA)) 1271 return name; 1272 1273 free (name); 1274 name = NULL; 1275 current_name_format = nfmt; 1276 char *fname = func->get_name (nfmt); 1277 1278 if (func->flags & FUNC_FLAG_NO_OFFSET) 1279 name = dbe_strdup (fname); 1280 else if (addr == (uint64_t) - 1 1281 && func != dbeSession->get_JUnknown_Function ()) 1282 // We use three heuristics above to recognize this special case. 1283 // Once the original problem with bci == -1 is fixed, we don't 1284 // need it any more. 1285 name = dbe_sprintf (GTXT ("<Function %s: HotSpot-compiled leaf instructions>"), 1286 fname); 1287 else if (addr == (uint64_t) - 3) 1288 name = dbe_sprintf (GTXT ("%s <Java native method>"), fname); 1289 else 1290 { 1291 char buf[64], *typetag = NTXT (""), *alloc_typetag = NULL; 1292 StringBuilder sb; 1293 sb.append (fname); 1294 if (func != dbeSession->get_JUnknown_Function ()) 1295 { 1296 if (addr <= 0xFFFFFFFFU) 1297 snprintf (buf, sizeof (buf), " + 0x%08X", (unsigned int) addr); 1298 else 1299 snprintf (buf, sizeof (buf), " + 0x%016llX", 1300 (unsigned long long) addr); 1301 } 1302 else 1303 { 1304 char *subname; 1305 switch ((long int) addr) 1306 { 1307 case -1: 1308 subname = GTXT ("agent error"); 1309 break; 1310 case -2: 1311 subname = GTXT ("GC active"); 1312 break; 1313 case -3: 1314 subname = GTXT ("unknown non-Java frame"); 1315 break; 1316 case -4: 1317 subname = GTXT ("unwalkable non-Java frame"); 1318 break; 1319 case -5: 1320 subname = GTXT ("unknown Java frame"); 1321 break; 1322 case -6: 1323 subname = GTXT ("unwalkable Java frame"); 1324 break; 1325 case -7: 1326 subname = GTXT ("unknown thread state"); 1327 break; 1328 case -8: 1329 subname = GTXT ("thread in exit"); 1330 break; 1331 case -9: 1332 subname = GTXT ("deopt in process ticks"); 1333 break; 1334 case -10: 1335 subname = GTXT ("safepoint synchronizing ticks"); 1336 break; 1337 default: 1338 subname = GTXT ("unexpected error"); 1339 break; 1340 } 1341 snprintf (buf, sizeof (buf), "<%s (%d)>", subname, (int) addr); 1342 } 1343 sb.append (buf); 1344 if (flags & PCTrgtFlag) 1345 // annotate synthetic instruction 1346 sb.append ('*'); // special distinguishing marker 1347 1348 DbeLine *dbeline = mapPCtoLine (NULL); 1349 char *str = NULL; 1350 if (dbeline && dbeline->lineno > 0) 1351 str = strrchr (dbeline->get_name (nfmt), ','); 1352 if (str) 1353 sb.append (str); 1354 if (strlen (typetag) > 0) 1355 { // include padding for alignment 1356 do 1357 { 1358 sb.append (' '); 1359 } 1360 while (sb.length () < 40); 1361 sb.append (typetag); 1362 delete alloc_typetag; 1363 } 1364 if (inlinedInd >= 0) 1365 add_inlined_info (&sb); 1366 name = sb.toString (); 1367 } 1368 return name; 1369} 1370 1371DbeLine* 1372DbeInstr::mapPCtoLine (SourceFile *sf) 1373{ 1374 if (inlinedInd == -1) 1375 { 1376 inlinedInd = -2; 1377 for (int i = 0; i < func->inlinedSubrCnt; i++) 1378 { 1379 InlinedSubr *p = func->inlinedSubr + i; 1380 if (p->level == 0) 1381 { 1382 if (addr < p->low_pc) 1383 break; 1384 if (p->contains (addr)) 1385 { 1386 inlinedInd = i; 1387 break; 1388 } 1389 } 1390 } 1391 } 1392 if (inlinedInd >= 0) 1393 { 1394 DbeLine *dl = func->inlinedSubr[inlinedInd].dbeLine; 1395 return dl->sourceFile->find_dbeline (func, dl->lineno); 1396 } 1397 return func->mapPCtoLine (addr, sf); 1398} 1399 1400void 1401DbeInstr::add_inlined_info (StringBuilder *sb) 1402{ 1403 do 1404 { 1405 sb->append (' '); 1406 } 1407 while (sb->length () < 40); 1408 sb->append (NTXT ("<-- ")); 1409 1410 InlinedSubr *last = NULL; 1411 for (int i = inlinedInd; i < func->inlinedSubrCnt; i++) 1412 { 1413 InlinedSubr *p = func->inlinedSubr + i; 1414 if (p->level == 0 && i > inlinedInd) 1415 break; 1416 if (!p->contains (addr)) 1417 continue; 1418 if (last) 1419 { 1420 if (last->fname) 1421 { 1422 sb->append (last->fname); 1423 sb->append (' '); 1424 } 1425 DbeLine *dl = p->dbeLine; 1426 sb->appendf (NTXT ("%s:%lld <-- "), get_basename (dl->sourceFile->get_name ()), (long long) dl->lineno); 1427 } 1428 last = p; 1429 } 1430 if (last) 1431 { 1432 if (last->fname) 1433 { 1434 sb->append (last->fname); 1435 sb->append (' '); 1436 } 1437 } 1438 DbeLine *dl = func->mapPCtoLine (addr, NULL); 1439 sb->appendf ("%s:%lld ", get_basename (dl->sourceFile->get_name ()), 1440 (long long) dl->lineno); 1441} 1442 1443char * 1444DbeInstr::get_descriptor () 1445{ 1446 char *typetag = NTXT (""); 1447 if ((flags & PCTrgtFlag) == 0) // not synthetic instruction 1448 { // use memop descriptor, if available 1449 Module *mod = func->module; 1450 if (mod->hwcprof && mod->infoList) 1451 { 1452 long i; 1453 inst_info_t *info = NULL; 1454 Vec_loop (inst_info_t*, mod->infoList, i, info) 1455 { 1456 if (info->offset == func->img_offset + addr) break; 1457 } 1458 if (info) 1459 { 1460 long t; 1461 datatype_t *dtype = NULL; 1462 Vec_loop (datatype_t*, mod->datatypes, t, dtype) 1463 { 1464 if (dtype->datatype_id == info->memop->datatype_id) 1465 break; 1466 } 1467 if (dtype && dtype->dobj) 1468 typetag = dtype->dobj->get_name (); 1469 } 1470 } 1471 } 1472 return dbe_strdup (typetag); 1473} 1474 1475int64_t 1476DbeInstr::get_size () 1477{ 1478 // Function *func = (Function*)dbeSession->get_hobj( pc ); 1479 // Module *mod = func ? func->module : NULL; 1480 // return mod ? mod->instrSize( func->img_offset + addr ) : 0; 1481 return size; 1482} 1483 1484uint64_t 1485DbeInstr::get_addr () 1486{ 1487 return func->get_addr () + addr; 1488} 1489 1490Histable * 1491DbeInstr::convertto (Type type, Histable *obj) 1492{ 1493 Histable *res = NULL; 1494 SourceFile *source = (SourceFile*) obj; 1495 switch (type) 1496 { 1497 case INSTR: 1498 res = this; 1499 break; 1500 case LINE: 1501 res = mapPCtoLine (source); 1502 break; 1503 case SOURCEFILE: 1504 res = mapPCtoLine (source); 1505 if (res) 1506 res = ((DbeLine*) res)->sourceFile; 1507 break; 1508 case FUNCTION: 1509 res = func; 1510 break; 1511 default: 1512 assert (0); 1513 } 1514 return res; 1515} 1516 1517char * 1518DbeEA::get_name (NameFormat) 1519{ 1520 if (name == NULL) 1521 // generate one 1522 name = dbe_strdup (dbeSession->localized_SP_UNKNOWN_NAME); 1523 return name; 1524} 1525 1526Histable * 1527DbeEA::convertto (Type type, Histable *obj) 1528{ 1529 Histable *res = NULL; 1530 assert (obj == NULL); 1531 switch (type) 1532 { 1533 case EADDR: 1534 res = this; 1535 break; 1536 case DOBJECT: 1537 res = dobj; 1538 break; 1539 default: 1540 assert (0); 1541 } 1542 return res; 1543} 1544 1545DbeLine::DbeLine (Function *_func, SourceFile *sf, int _lineno) 1546{ 1547 func = _func; 1548 lineno = _lineno; 1549 sourceFile = sf; 1550 id = sf->id + _lineno; 1551 offset = 0; 1552 size = 0; 1553 flags = 0; 1554 include = NULL; 1555 dbeline_func_next = NULL; 1556 dbeline_base = this; 1557 current_name_format = Histable::NA; 1558} 1559 1560DbeLine::~DbeLine () 1561{ 1562 delete dbeline_func_next; 1563} 1564 1565int 1566DbeLine::line_cmp (DbeLine *dbl) 1567{ 1568 return lineno - dbl->lineno; 1569} 1570 1571void 1572DbeLine::init_Offset (uint64_t p_offset) 1573{ 1574 if (offset == 0) 1575 offset = p_offset; 1576 if (dbeline_base && dbeline_base->offset == 0) 1577 dbeline_base->offset = p_offset; 1578} 1579 1580char * 1581DbeLine::get_name (NameFormat nfmt) 1582{ 1583 char *srcname = NULL, *basename, *fname; 1584 1585 if (func == NULL) 1586 { 1587 if (name) 1588 return name; 1589 srcname = sourceFile->get_name (); 1590 basename = get_basename (srcname); 1591 name = dbe_sprintf (GTXT ("line %u in \"%s\""), lineno, basename); 1592 return name; 1593 } 1594 1595 if (name && (nfmt == current_name_format || nfmt == Histable::NA)) 1596 return name; 1597 1598 current_name_format = nfmt; 1599 free (name); 1600 fname = func->get_name (nfmt); 1601 if (func->flags & (FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET)) 1602 { 1603 name = dbe_strdup (fname); 1604 return name; 1605 } 1606 1607 if (sourceFile) 1608 srcname = sourceFile->get_name (); 1609 if (!srcname || strlen (srcname) == 0) 1610 srcname = func->getDefSrcName (); 1611 basename = get_basename (srcname); 1612 1613 if (lineno != 0) 1614 { 1615 if (sourceFile == func->getDefSrc ()) 1616 name = dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname, lineno, 1617 basename); 1618 else 1619 name = dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""), 1620 fname, lineno, basename); 1621 } 1622 else if (sourceFile == NULL || (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0) 1623 name = dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"), 1624 fname); 1625 else 1626 name = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"), 1627 fname, basename); 1628 return name; 1629} 1630 1631int64_t 1632DbeLine::get_size () 1633{ 1634 return size; 1635} 1636 1637uint64_t 1638DbeLine::get_addr () 1639{ 1640 if (func == NULL && dbeline_func_next == NULL) 1641 return (uint64_t) 0; 1642 Function *f = func ? func : dbeline_func_next->func; 1643 return f->get_addr () + offset; 1644} 1645 1646Histable * 1647DbeLine::convertto (Type type, Histable *obj) 1648{ 1649 Histable *res = NULL; 1650 switch (type) 1651 { 1652 case INSTR: 1653 { 1654 Function *f = (Function *) convertto (FUNCTION, NULL); 1655 if (f) 1656 res = f->find_dbeinstr (0, offset); 1657 break; 1658 } 1659 case LINE: 1660 res = dbeline_base; 1661 break; 1662 case FUNCTION: 1663 if (func) 1664 { 1665 res = func; 1666 break; 1667 } 1668 else 1669 { 1670 int not_found = 1; 1671 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next) 1672 { 1673 Function *f = dl->func; 1674 not_found = (obj == NULL // XXXX pass dbeview as Histable* 1675 || ((DbeView*) obj)->get_path_tree ()->get_func_nodeidx (f) == 0); 1676 if (f && f->def_source == sourceFile && (!not_found)) 1677 { 1678 res = f; 1679 break; 1680 } 1681 } 1682 if (res == NULL && dbeline_func_next) 1683 { 1684 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next) 1685 { 1686 Function *f = dl->func; 1687 if (f && f->def_source == sourceFile) 1688 { 1689 res = f; 1690 break; 1691 } 1692 } 1693 } 1694 if (res == NULL && dbeline_func_next) 1695 res = dbeline_func_next->func; 1696 } 1697 break; 1698 case SOURCEFILE: 1699 res = (include) ? include : sourceFile; 1700 break; 1701 default: 1702 assert (0); 1703 } 1704 return res; 1705} 1706 1707CStack_data::CStack_data (MetricList *_metrics) 1708{ 1709 metrics = _metrics; 1710 total = new_cstack_item (); 1711 cstack_items = new Vector<CStack_item*>; 1712} 1713 1714CStack_data::CStack_item::CStack_item (long n) 1715{ 1716 stack = NULL; 1717 count = 0; 1718 val = 0; 1719 value = new TValue[n]; 1720 memset (value, 0, sizeof (TValue) * n); 1721} 1722 1723CStack_data::CStack_item::~CStack_item () 1724{ 1725 delete stack; 1726 delete[] value; 1727} 1728 1729CStack_data::CStack_item * 1730CStack_data::new_cstack_item () 1731{ 1732 int nmetrics = metrics->get_items ()->size (); 1733 CStack_item *item = new CStack_item (nmetrics); 1734 1735 // We precalculate all metrics as integer values 1736 // and convert them to appropriate types later. 1737 for (int i = 0; i < nmetrics; i++) 1738 item->value[i].tag = metrics->get_items ()->fetch (i)->get_vtype (); 1739 return item; 1740} 1741 1742HistableFile::HistableFile () 1743{ 1744 dbeFile = NULL; 1745 isUsed = false; 1746} 1747 1748Histable::Histable () 1749{ 1750 name = NULL; 1751 id = 0; 1752 comparable_objs = NULL; 1753 phaseCompareIdx = -1; 1754} 1755 1756Histable::~Histable () 1757{ 1758 delete_comparable_objs (); 1759 free (name); 1760} 1761 1762void 1763Histable::delete_comparable_objs () 1764{ 1765 if (comparable_objs) 1766 { 1767 Vector<Histable*> *v = comparable_objs; 1768 for (int i = 0; i < v->size (); i++) 1769 { 1770 Histable *h = v->fetch (i); 1771 if (h) 1772 { 1773 h->comparable_objs = NULL; 1774 h->phaseCompareIdx = phaseCompareIdx; 1775 } 1776 } 1777 delete v; 1778 } 1779} 1780 1781void 1782Histable::update_comparable_objs () 1783{ 1784 if (phaseCompareIdx != ExpGroup::phaseCompareIdx) 1785 { 1786 phaseCompareIdx = ExpGroup::phaseCompareIdx; 1787 delete_comparable_objs (); 1788 } 1789} 1790 1791Vector<Histable*> * 1792Histable::get_comparable_objs () 1793{ 1794 return comparable_objs; 1795} 1796 1797Histable * 1798Histable::get_compare_obj () 1799{ 1800 Vector<Histable*> *v = get_comparable_objs (); 1801 for (long i = 0, sz = VecSize (v); i < sz; i++) 1802 { 1803 Histable *h = v->get (i); 1804 if (h) 1805 return h; 1806 } 1807 return this; 1808} 1809 1810#define CASE_S(x) case x: return (char *) #x 1811 1812char * 1813Histable::type_to_string () 1814{ 1815 switch (get_type ()) 1816 { 1817 CASE_S (INSTR); 1818 CASE_S (LINE); 1819 CASE_S (FUNCTION); 1820 CASE_S (MODULE); 1821 CASE_S (LOADOBJECT); 1822 CASE_S (EADDR); 1823 CASE_S (MEMOBJ); 1824 CASE_S (INDEXOBJ); 1825 CASE_S (PAGE); 1826 CASE_S (DOBJECT); 1827 CASE_S (SOURCEFILE); 1828 CASE_S (EXPERIMENT); 1829 CASE_S (OTHER); 1830 default: 1831 break; 1832 } 1833 return NTXT ("ERROR"); 1834} 1835 1836void 1837Histable::dump_comparable_objs () 1838{ 1839 Dprintf (DEBUG_COMPARISON, 1840 "# Histable::dump_comparable_objs type=%s(%d) 0x%lx id=%lld %s\n", 1841 type_to_string (), get_type (), (unsigned long) this, (long long) id, 1842 STR (get_name ())); 1843 for (int i = 0, sz = comparable_objs ? comparable_objs->size () : 0; i < sz; i++) 1844 { 1845 Histable *h = comparable_objs->fetch (i); 1846 Dprintf (DEBUG_COMPARISON, " %d type=%s(%d) 0x%lx id=%lld %s\n", i, 1847 h ? h->type_to_string () : "", h ? h->get_type () : -1, 1848 (unsigned long) h, (long long) (h ? h->id : 0), 1849 h ? STR (h->get_name ()) : NTXT ("")); 1850 } 1851} 1852 1853char * 1854Histable::dump () 1855{ 1856 StringBuilder sb; 1857 sb.appendf (sizeof (long) == 32 1858 ? " 0x%08lx : type=%s(%d) id=%lld %s" 1859 : " 0x%016lx : type=%s(%d) id=%lld %s", 1860 (unsigned long) this, type_to_string (), get_type (), 1861 (long long) id, STR (get_name ())); 1862 switch (get_type ()) 1863 { 1864 case INSTR: 1865 { 1866 DbeInstr *o = (DbeInstr *) this; 1867 sb.appendf (sizeof (long) == 32 1868 ? " func=0x%08lx lineno=%lld" 1869 : " func=0x%016lx lineno=%lld", 1870 (unsigned long) o->func, (long long) o->lineno); 1871 break; 1872 } 1873 case LINE: 1874 { 1875 DbeLine *o = (DbeLine *) this; 1876 sb.appendf (sizeof (long) == 32 1877 ? " func=0x%08lx sourceFile=0x%08lx lineno=%lld" 1878 : " func=0x%016lx sourceFile=0x%016lx lineno=%lld", 1879 (unsigned long) o->func, (unsigned long) o->sourceFile, 1880 (long long) o->lineno); 1881 break; 1882 } 1883 default: 1884 break; 1885 } 1886 return sb.toString (); 1887} 1888