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 "util.h" 23#include "Command.h" 24#include "DbeSession.h" 25#include "MetricList.h" 26#include "StringBuilder.h" 27 28// Build a metric reference list 29MetricList::MetricList (Vector<BaseMetric*> *base_metrics, MetricType _mtype) 30{ 31 mtype = _mtype; 32 items = new Vector<Metric*>; 33 sort_ref_index = 0; 34 sort_reverse = false; 35 36 Metric *mitem; 37 // loop over the base_metrics, and add in all the appropriate subtypes 38 for (long i = 0, sz = base_metrics ? base_metrics->size () : 0; i < sz; i++) 39 { 40 BaseMetric *mtr = base_metrics->get (i); 41 if (mtr->is_internal ()) 42 continue; 43 switch (mtype) 44 { 45 case MET_DATA: 46 if ((mtr->get_flavors () & BaseMetric::DATASPACE) != 0) 47 { 48 mitem = new Metric (mtr, BaseMetric::DATASPACE); 49 items->append (mitem); 50 } 51 break; 52 53 case MET_INDX: 54 { 55 if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0 56 || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0) 57 { 58 int index2; 59 Metric *item2 = NULL; 60 bool found = false; 61 Vec_loop (Metric*, items, index2, item2) 62 { 63 if (item2->get_subtype () == BaseMetric::EXCLUSIVE 64 && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0) 65 { 66 found = true; 67 break; 68 } 69 } 70 if (found == false) 71 { 72 mitem = new Metric (mtr, BaseMetric::EXCLUSIVE); 73 items->append (mitem); 74 } 75 } 76 } 77 break; 78 79 case MET_CALL: 80 case MET_CALL_AGR: 81 if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) != 0) 82 { 83 mitem = new Metric (mtr, BaseMetric::ATTRIBUTED); 84 items->append (mitem); 85 } 86 // now fall through to add exclusive and inclusive 87 88 case MET_NORMAL: 89 case MET_COMMON: 90 if (mtr->get_flavors () & BaseMetric::EXCLUSIVE) 91 { 92 mitem = new Metric (mtr, BaseMetric::EXCLUSIVE); 93 items->append (mitem); 94 } 95 if (mtr->get_flavors () & BaseMetric::INCLUSIVE) 96 { 97 mitem = new Metric (mtr, BaseMetric::INCLUSIVE); 98 items->append (mitem); 99 } 100 break; 101 case MET_SRCDIS: 102 if (mtr->get_flavors () & BaseMetric::INCLUSIVE) 103 { 104 mitem = new Metric (mtr, BaseMetric::INCLUSIVE); 105 items->append (mitem); 106 } 107 break; 108 case MET_IO: 109 { 110 if (mtr->get_packet_type () == DATA_IOTRACE 111 && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0 112 || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0)) 113 { 114 int index2; 115 Metric *item2 = NULL; 116 bool found = false; 117 Vec_loop (Metric*, items, index2, item2) 118 { 119 if (item2->get_subtype () == BaseMetric::EXCLUSIVE 120 && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0) 121 { 122 found = true; 123 break; 124 } 125 } 126 if (found == false) 127 { 128 mitem = new Metric (mtr, BaseMetric::EXCLUSIVE); 129 items->append (mitem); 130 } 131 } 132 } 133 break; 134 case MET_HEAP: 135 { 136 if (mtr->get_packet_type () == DATA_HEAP 137 && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0 138 || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0)) 139 { 140 int index2; 141 Metric *item2 = NULL; 142 bool found = false; 143 Vec_loop (Metric*, items, index2, item2) 144 { 145 if ((item2->get_subtype () == BaseMetric::EXCLUSIVE) && 146 (dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0)) 147 { 148 found = true; 149 break; 150 } 151 } 152 if (found == false) 153 { 154 mitem = new Metric (mtr, BaseMetric::EXCLUSIVE); 155 items->append (mitem); 156 } 157 } 158 } 159 break; 160 } 161 162 // add the static 163 if (mtr->get_flavors () & BaseMetric::STATIC) 164 { 165 switch (mtype) 166 { 167 case MET_NORMAL: 168 case MET_COMMON: 169 case MET_CALL: 170 case MET_CALL_AGR: 171 case MET_SRCDIS: 172 mitem = new Metric (mtr, BaseMetric::STATIC); 173 items->append (mitem); 174 break; 175 default: 176 if (mtr->get_type () == BaseMetric::ONAME) 177 { 178 mitem = new Metric (mtr, BaseMetric::STATIC); 179 items->append (mitem); 180 } 181 break; 182 } 183 } 184 } 185 // set all metrics visible 186 for (long i = 0, sz = items ? items->size () : 0; i < sz; i++) 187 items->get (i)->enable_all_visbits (); 188} 189 190// Constructor for an empty list -- items will be added one at a time 191MetricList::MetricList (MetricType _mtype) 192{ 193 mtype = _mtype; 194 items = new Vector<Metric*>; 195 sort_ref_index = 0; 196 sort_reverse = false; 197} 198 199MetricList::~MetricList () 200{ 201 Destroy (items); 202} 203 204// Duplicate a metric list 205MetricList::MetricList (MetricList *old) 206{ 207 mtype = old->mtype; 208 209 // get an empty vector 210 items = new Vector<Metric*>; 211 Metric *item; 212 Metric *nitem; 213 int index; 214 sort_ref_index = old->get_sort_ref_index (); 215 sort_reverse = old->get_sort_rev (); 216 Vec_loop (Metric*, old->items, index, item) 217 { 218 nitem = new Metric (*item); 219 items->append (nitem); 220 } 221} 222 223// set_metrics: 224// Sets the particular metric list, according to the metric spec 225// If fromRcFile, updates dbeSession->get_reg_metrics_tree() with new defaults. 226char * 227MetricList::set_metrics (const char *mspec, bool fromRcFile, 228 DerivedMetrics * /* derived_metrics */) 229{ 230 BaseMetric::SubType subtypes[10]; 231 int nsubtypes; 232 int dmetrics_vis; // literal translation of metrics/dmetrics %.+ 233 bool parseOK = false; 234 char *errbuf; 235 Vector<Metric*> *old_items = items; 236 items = new Vector<Metric*>; 237 Vector<BaseMetric*> *base_items = dbeSession->get_base_reg_metrics (); 238 239 // and copy the input specification 240 char *buf = dbe_strdup (mspec); 241 242 // append metric items from parsing the string 243 for (char *mcmd = strtok (buf, NTXT (":")); mcmd != NULL; 244 mcmd = strtok (NULL, NTXT (":"))) 245 { 246 // parse the single metric_spec, based on the type of list being constructed, into: 247 // a vector of SubTypes (any of [iead] or STATIC) 248 // a integer mask for the visibility bits 249 // and the string name of the base metric 250 // it might be "all", "any", or "hwc" or it should match a metric in the list 251 // it might also be "bit", meaning any bit-computed metric 252 char *mname = parse_metric_spec (mcmd, subtypes, &nsubtypes, 253 &dmetrics_vis, &parseOK); 254 if (!parseOK) 255 { 256 // error parsing the metric specification 257 // not from an rc file, it's an error 258 if (!fromRcFile) 259 { 260 delete base_items; 261 items->destroy (); 262 delete items; 263 items = old_items; 264 free (buf); 265 return mname; 266 } 267 continue; 268 } 269 270 // loop over subtypes requested 271 // set the visibility of and sort order according to the vis bits, 272 // and the order of encounter in the processing 273 int ret = add_matching_dmetrics (base_items, mname, subtypes, nsubtypes, 274 dmetrics_vis, fromRcFile); 275 if (ret != 0 && !fromRcFile) 276 { 277 if (ret == 1) 278 errbuf = dbe_sprintf (GTXT ("No data recorded to support metric specification: %s\n"), 279 mcmd); 280 else 281 errbuf = dbe_sprintf (GTXT ("Metric specification for `%s' has appeared before in %s"), 282 mcmd, mspec); 283 delete base_items; 284 items->destroy (); 285 delete items; 286 items = old_items; 287 free (buf); 288 return errbuf; 289 } 290 } // we've processed the entire spec 291 292 // update metric defaults 293 if (fromRcFile) 294 { 295 for (long i = 0, sz = items->size (); i < sz; i++) 296 { 297 Metric *m = items->get (i); 298 int visbits = m->get_visbits (); 299 BaseMetric::SubType subtype = m->get_subtype (); 300 BaseMetric *reg_bm = m->get_base_metric (); 301 reg_bm->set_default_visbits (subtype, visbits); 302 BaseMetricTreeNode *mtree = dbeSession->get_reg_metrics_tree (); 303 BaseMetricTreeNode *bmtnode = mtree->register_metric (m); 304 BaseMetric *tree_bm = bmtnode->get_BaseMetric (); 305 tree_bm->set_default_visbits (subtype, visbits); 306 } 307 } 308 309 // ensure that name is present, remove hidden metrics 310 nsubtypes = 1; 311 for (long i = items->size () - 1; i >= 0; i--) 312 { 313 Metric *m = items->fetch (i); 314 if (!m->is_any_visible ()) 315 { 316 delete m; 317 items->remove (i); 318 continue; 319 } 320 if (m->get_type () == BaseMetric::ONAME) 321 nsubtypes = 0; 322 } 323 324 // did we get at least one valid match? 325 if (items->size () == 0 && !fromRcFile) 326 { 327 errbuf = dbe_sprintf (GTXT ("No valid metrics specified in `%s'\n"), mspec); 328 delete base_items; 329 items->destroy (); 330 delete items; 331 items = old_items; 332 free (buf); 333 return errbuf; 334 } 335 336 if (nsubtypes == 1) 337 { 338 subtypes[0] = BaseMetric::STATIC; 339 (void) add_matching_dmetrics (base_items, NTXT ("name"), subtypes, 1, VAL_VALUE, true); 340 } 341 342 // replace the old list of items, with the new set 343 if (old_items) 344 { 345 old_items->destroy (); 346 delete old_items; 347 } 348 set_fallback_sort (); 349 free (buf); 350 delete base_items; 351 return NULL; 352} 353 354void 355MetricList::set_fallback_sort () 356{ 357 // sort by first visible of the appropriate flavor 358 char *sortcmd = NULL; 359 switch (mtype) 360 { 361 case MET_NORMAL: 362 case MET_COMMON: 363 sortcmd = NTXT ("ei.any:name"); 364 break; 365 case MET_SRCDIS: 366 sortcmd = NTXT ("i.any:name"); 367 break; 368 case MET_CALL: 369 case MET_CALL_AGR: 370 sortcmd = NTXT ("a.any:name"); 371 break; 372 case MET_DATA: 373 sortcmd = NTXT ("d.any:name"); 374 break; 375 case MET_INDX: 376 sortcmd = NTXT ("e.any:name"); 377 break; 378 case MET_IO: 379 sortcmd = NTXT ("e.any:name"); 380 break; 381 case MET_HEAP: 382 sortcmd = NTXT ("e.any:name"); 383 break; 384 } 385 if (NULL != sortcmd) 386 (void) set_sort (sortcmd, true); 387} 388 389void 390MetricList::set_metrics (MetricList *mlist) 391{ 392 // verify that the type is appropriate for the call 393 if (mtype == MET_NORMAL || mtype == MET_COMMON 394 || (mlist->mtype != MET_NORMAL && mlist->mtype != MET_COMMON)) 395 abort (); 396 397 Vector<Metric*> *mlist_items = mlist->get_items (); 398 items->destroy (); 399 items->reset (); 400 401 int sort_ind = mlist->get_sort_ref_index (); 402 for (int i = 0, mlist_sz = mlist_items->size (); i < mlist_sz; i++) 403 { 404 Metric *mtr = mlist_items->fetch (i); 405 if (!mtr->is_any_visible ()) 406 continue; 407 408 // Add a new Metric with probably a new sub_type to this->items: 409 // for MET_CALL and MET_CALL_AGR the matching entry to an e. or i. is itself 410 // for MET_DATA, the matching entry to an e. or i. is the d. metric 411 // for MET_INDX, the matching entry to an e. or i. is the e. metric 412 // for MET_IO, the matching entry to an e. or i. is the e. metric 413 // for MET_HEAP, the matching entry to an e. or i. is the e. metric 414 // Save static entries (SIZES and ADDRESS) only for MET_NORMAL, MET_CALL, MET_CALL_AGR, MET_SRCDIS 415 switch (mtr->get_type ()) 416 { 417 case BaseMetric::SIZES: 418 case BaseMetric::ADDRESS: 419 switch (mtype) 420 { 421 case MET_NORMAL: 422 case MET_COMMON: 423 case MET_CALL: 424 case MET_CALL_AGR: 425 case MET_SRCDIS: 426 break; 427 default: 428 continue; 429 } 430 break; 431 default: 432 break; 433 } 434 435 BaseMetric::SubType st = mtr->get_subtype (); 436 if (st != BaseMetric::STATIC) 437 { 438 if (mtype == MET_CALL || mtype == MET_CALL_AGR) 439 { 440 if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) == 0) 441 continue; 442 st = BaseMetric::ATTRIBUTED; 443 } 444 else if (mtype == MET_DATA) 445 { 446 if ((mtr->get_flavors () & BaseMetric::DATASPACE) == 0) 447 continue; 448 st = BaseMetric::DATASPACE; 449 } 450 else if (mtype == MET_INDX) 451 { 452 if ((mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0) 453 continue; 454 st = BaseMetric::EXCLUSIVE; 455 } 456 else if (mtype == MET_IO) 457 { 458 if (mtr->get_packet_type () != DATA_IOTRACE || 459 (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0) 460 continue; 461 st = BaseMetric::EXCLUSIVE; 462 } 463 else if (mtype == MET_HEAP) 464 { 465 if (mtr->get_packet_type () != DATA_HEAP || 466 (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0) 467 continue; 468 st = BaseMetric::EXCLUSIVE; 469 } 470 else if (mtype == MET_SRCDIS) 471 { 472 if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) == 0) 473 continue; 474 st = BaseMetric::INCLUSIVE; 475 } 476 } 477 478 bool found = false; 479 for (int i1 = 0, items_sz = items->size (); i1 < items_sz; i1++) 480 { 481 Metric *m1 = items->fetch (i1); 482 if (mtr->get_id () == m1->get_id () && st == m1->get_subtype ()) 483 { 484 if (sort_ind == i) 485 sort_ind = i1; 486 found = true; 487 break; 488 } 489 } 490 if (found) 491 continue; 492 Metric *m = new Metric (*mtr); 493 m->set_subtype (st); 494 m->set_raw_visbits (mtr->get_visbits ()); 495 if (sort_ind == i) 496 sort_ind = items->size (); 497 items->append (m); 498 } 499 if (sort_ind >= items->size ()) 500 sort_ind = 0; 501 if (mtype == MET_IO) 502 sort_ind = 0; 503 if (mtype == MET_HEAP) 504 sort_ind = 0; 505 sort_ref_index = sort_ind; 506 507} 508 509 510// set_sort: 511// Sets the sort for the metric list to the first metric 512// in mspec that is present; if fromRcFile is false, then 513// only one metric may be specified. The requested sort 514// metric must be visible, or it won't be in the metric list 515 516char * 517MetricList::set_sort (const char *mspec, bool fromRcFile) 518{ 519 char *mcmd; 520 BaseMetric::SubType subtypes[10]; 521 int nsubtypes; 522 int vis; 523 bool parseOK = false; 524 bool reverse = false; 525 char buf[BUFSIZ]; 526 char *list = buf; 527 char *mname; 528 529 // copy the input specification 530 snprintf (buf, sizeof (buf), NTXT ("%s"), mspec); 531 char *listp = list; 532 if (*listp == '-') 533 { 534 // reverse sort specified 535 reverse = true; 536 listp++; 537 } 538 539 // search for metric items from parsing the string 540 while ((mcmd = strtok (listp, NTXT (":"))) != NULL) 541 { 542 listp = NULL; // let strtok keep track 543 544 // parse the single metric_spec, based on the type of list being constructed, into: 545 // a vector of SubTypes (any of [iead] or STATIC) 546 // a integer mask for the visibility bits 547 // and the string name of the base metric 548 mname = parse_metric_spec (mcmd, subtypes, &nsubtypes, &vis, &parseOK); 549 if (!parseOK) 550 { 551 // error parsing the metric specification 552 // not from an rc file, it's an error 553 if (!fromRcFile) 554 return (mname); 555 continue; 556 } 557 if (VAL_IS_HIDDEN (vis)) 558 continue; 559 560 // loop over subtypes requested to find metric 561 // add a metric of that subtype, with specified vis.bits 562 for (int i = 0; i < nsubtypes; i++) 563 { 564 // make sure the subtype is acceptable 565 if ((mtype == MET_CALL || mtype == MET_CALL_AGR) 566 && subtypes[i] != BaseMetric::ATTRIBUTED 567 && subtypes[i] != BaseMetric::STATIC) 568 return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Data metrics cannot be specified for caller-callee sort: %s\n"), 569 mcmd); 570 if (mtype == MET_DATA && subtypes[i] != BaseMetric::DATASPACE 571 && subtypes[i] != BaseMetric::STATIC) 572 return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Attributed metrics cannot be specified for data-derived sort: %s\n"), 573 mcmd); 574 if (mtype == MET_INDX && subtypes[i] != BaseMetric::EXCLUSIVE 575 && subtypes[i] != BaseMetric::STATIC) 576 return dbe_sprintf (GTXT ("Inclusive, Data or Attributed metrics cannot be specified for index sort: %s\n"), 577 mcmd); 578 if ((mtype == MET_NORMAL || mtype == MET_COMMON 579 || mtype == MET_SRCDIS) 580 && (subtypes[i] == BaseMetric::DATASPACE 581 || subtypes[i] == BaseMetric::ATTRIBUTED)) 582 return dbe_sprintf (GTXT ("Data or Attributed metrics cannot be specified for sort: %s\n"), mcmd); 583 if (set_sort_metric (mname, subtypes[i], reverse)) 584 return NULL; 585 } 586 // continue looking at entries 587 } 588 589 // not found on the list at all 590 switch (mtype) 591 { 592 case MET_NORMAL: 593 case MET_COMMON: 594 case MET_SRCDIS: 595 return dbe_sprintf (GTXT ("Invalid sort specification: %s\n"), mspec); 596 case MET_CALL: 597 case MET_CALL_AGR: 598 return dbe_sprintf (GTXT ("Invalid caller-callee sort specification: %s\n"), 599 mspec); 600 case MET_DATA: 601 return dbe_sprintf (GTXT ("Invalid data-derived sort specification: %s\n"), 602 mspec); 603 case MET_INDX: 604 return dbe_sprintf (GTXT ("Invalid index sort specification: %s\n"), 605 mspec); 606 case MET_IO: 607 return dbe_sprintf (GTXT ("Invalid I/O sort specification: %s\n"), mspec); 608 case MET_HEAP: 609 return dbe_sprintf (GTXT ("Invalid heap sort specification: %s\n"), 610 mspec); 611 } 612 return NULL; 613} 614 615// set_sort to the metric with the given visible index 616 617void 618MetricList::set_sort (int visindex, bool reverse) 619{ 620 Metric *mitem; 621 if (visindex < items->size ()) 622 { 623 mitem = items->fetch (visindex); 624 if (mitem->is_any_visible ()) 625 { 626 sort_ref_index = visindex; 627 sort_reverse = reverse; 628 return; 629 } 630 } 631 set_fallback_sort (); 632} 633 634bool 635MetricList::set_sort_metric (char *mname, BaseMetric::SubType mst, bool reverse) 636{ 637 bool any = false, hwc = false, bit = false; 638 639 // check keywords 'any', 'all', 'bit' and 'hwc' 640 if (!strcasecmp (mname, Command::ANY_CMD)) 641 any = true; 642 else if (!strcasecmp (mname, Command::ALL_CMD)) 643 any = true; 644 else if (!strcasecmp (mname, Command::HWC_CMD)) 645 hwc = true; 646 else if (!strcasecmp (mname, Command::BIT_CMD)) 647 bit = true; 648 649 for (int i = 0, items_sz = items->size (); i < items_sz; i++) 650 { 651 Metric *m = items->fetch (i); 652 if (mst == m->get_subtype () 653 && (any || (hwc && m->get_type () == BaseMetric::HWCNTR) 654 || (bit && m->get_cmd () 655 && strncmp (Command::BIT_CMD, m->get_cmd (), 656 strlen (Command::BIT_CMD)) == 0) 657 || dbe_strcmp (mname, m->get_cmd ()) == 0)) 658 { 659 sort_ref_index = i; 660 sort_reverse = reverse; 661 return true; 662 } 663 } 664 return false; 665} 666 667// Print to a file of a list of metrics from a supplied vector 668// Debug flag = 1, prints the short name and address of the list 669// Debug flag = 2, prints the details of the list 670void 671MetricList::print_metric_list (FILE *dis_file, char *leader, int debug) 672{ 673 Metric *item; 674 int index; 675 char fmt_name[64]; 676 fprintf (dis_file, NTXT ("%s"), leader); 677 if (items == NULL) 678 { 679 fprintf (dis_file, GTXT ("NULL metric list can not be printed; aborting")); 680 abort (); 681 } 682 683 if (items->size () == 0) 684 { 685 fprintf (dis_file, GTXT ("metric list is empty; aborting\n")); 686 abort (); 687 } 688 689 // if debugging, print list address and string, and sort name 690 if (debug != 0) 691 { 692 char *s = get_metrics (); 693 fprintf (dis_file, "\tmetriclist at 0x%lx: %s, %lld metrics; sort by %s\n", 694 (unsigned long) this, s, (long long) items->size (), 695 get_sort_name ()); 696 free (s); 697 if (debug == 1) 698 return; 699 } 700 701 // Find the longest metric name & command 702 size_t max_len = 0; 703 size_t max_len2 = 0; 704 705 Vec_loop (Metric*, items, index, item) 706 { 707 // get the name 708 char *mn = item->get_name (); 709 size_t len = strlen (mn); 710 if (max_len < len) 711 max_len = len; 712 713 mn = item->get_mcmd (true); 714 len = strlen (mn); 715 if (max_len2 < len) 716 max_len2 = len; 717 free (mn); 718 719 } 720 if (debug == 2) 721 snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%-%ds", (int) max_len, 722 (int) max_len2); 723 else 724 snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%s", (int) max_len); 725 726 Vec_loop (Metric*, items, index, item) 727 { 728 char *mcmd = item->get_mcmd (true); 729 fprintf (dis_file, fmt_name, item->get_name (), mcmd); 730 free (mcmd); 731 if (debug == 2) 732 fprintf (dis_file, "\t[st %2d, VT %d, vis = %4s, T=%d, sort = %c]", 733 item->get_subtype (), item->get_vtype (), 734 item->get_vis_str (), item->is_time_val (), 735 sort_ref_index == index ? 'Y' : 'N'); 736 fputc ('\n', dis_file); 737 } 738 739 fputc ('\n', dis_file); 740 fflush (dis_file); 741} 742 743// Return a string formatted from a vector of metrics 744// string is in the form suitable for a "metrics <string>" command 745char * 746MetricList::get_metrics () 747{ 748 Metric *item; 749 int index; 750 StringBuilder sb; 751 Vec_loop (Metric*, items, index, item) 752 { 753 if (sb.length () != 0) 754 sb.append (':'); 755 char *mcmd = item->get_mcmd (false); 756 sb.append (mcmd); 757 free (mcmd); 758 } 759 return sb.toString (); 760} 761 762int 763MetricList::get_listorder (Metric *mtr) 764{ 765 for (int i = 0, items_sz = items->size (); i < items_sz; i++) 766 { 767 Metric *m = items->fetch (i); 768 if (m->get_subtype () == mtr->get_subtype () 769 && m->get_id () == mtr->get_id ()) 770 return i; 771 } 772 return -1; 773} 774 775int 776MetricList::get_listorder (char *cmd, BaseMetric::SubType st, const char *expr) 777{ 778 for (long i = 0, items_sz = items->size (); i < items_sz; i++) 779 { 780 Metric *m = items->fetch (i); 781 if (m->get_subtype () == st && dbe_strcmp (m->get_cmd (), cmd) == 0 782 && dbe_strcmp (m->get_expr_spec (), expr) == 0) 783 return (int) i; 784 } 785 return -1; 786} 787 788Metric * 789MetricList::find_metric_by_name (char *cmd) 790{ 791 for (long i = 0, items_sz = items->size (); i < items_sz; i++) 792 { 793 Metric *m = items->fetch (i); 794 if (dbe_strcmp (m->get_cmd (), cmd) == 0) 795 return m; 796 } 797 return NULL; 798} 799 800// find a metric by name and subtype 801Metric * 802MetricList::find_metric (char *cmd, BaseMetric::SubType st) 803{ 804 int i = get_listorder (cmd, st); 805 if (i < 0) 806 return NULL; 807 return items->fetch (i); 808} 809 810// Get the sort metric from a list; forces sort by first if not set 811Metric * 812MetricList::get_sort_metric () 813{ 814 int i = get_sort_ref_index (); 815 return i >= 0 ? items->fetch (i) : NULL; 816} 817 818char * 819MetricList::get_sort_name () 820{ 821 Metric *item = get_sort_metric (); 822 if (item == NULL) 823 return dbe_strdup (NTXT ("")); 824 char *n = item->get_name (); 825 return sort_reverse ? dbe_sprintf ("-%s", n) : dbe_strdup (n); 826} 827 828char * 829MetricList::get_sort_cmd () 830{ 831 char *buf; 832 Metric *item = get_sort_metric (); 833 if (item == NULL) 834 return dbe_strdup (NTXT ("")); 835 char *n = item->get_mcmd (false); 836 if (sort_reverse) 837 { 838 buf = dbe_sprintf (NTXT ("-%s"), n); 839 free (n); 840 } 841 else 842 buf = n; 843 return buf; 844} 845 846Metric * 847MetricList::append (BaseMetric *bm, BaseMetric::SubType st, int visbits) 848{ 849 for (long i = 0, sz = items->size (); i < sz; i++) 850 { 851 Metric *m = items->get (i); 852 if (m->get_id () == bm->get_id () && m->get_subtype () == st) 853 return NULL; 854 } 855 Metric *met = new Metric (bm, st); 856 met->set_dmetrics_visbits (visbits); 857 items->append (met); 858 return met; 859} 860 861int 862MetricList::add_matching_dmetrics (Vector<BaseMetric*> *base_items, 863 char *mcmd, BaseMetric::SubType *_subtypes, 864 int nsubtypes, int dmetrics_visbits, 865 bool fromRcFile) 866{ 867 bool any = false, hwc = false, bit = false; 868 int got_metric = 1; 869 870 // check keywords 'any', 'all', 'bit', and 'hwc' 871 if (!strcasecmp (mcmd, Command::ANY_CMD)) 872 any = true; 873 else if (!strcasecmp (mcmd, Command::ALL_CMD)) 874 any = true; 875 else if (!strcasecmp (mcmd, Command::HWC_CMD)) 876 hwc = true; 877 else if (!strcasecmp (mcmd, Command::BIT_CMD)) 878 bit = true; 879 880 BaseMetric::SubType *subtypes = _subtypes; 881 BaseMetric::SubType all_subtypes[2] = 882 { BaseMetric::EXCLUSIVE, BaseMetric::INCLUSIVE }; 883 884 if (nsubtypes == 0 || (nsubtypes == 1 && subtypes[0] == BaseMetric::STATIC)) 885 { 886 // user did not specify ei; treat as wildcard and supply both. 887 subtypes = all_subtypes; 888 nsubtypes = 2; 889 } 890 891 // scan the metrics to find all matches 892 for (int i = 0, base_sz = base_items->size (); i < base_sz; i++) 893 { 894 BaseMetric *item = base_items->fetch (i); 895 if (!(any || (hwc && item->get_type () == BaseMetric::HWCNTR) 896 || (bit && item->get_cmd () 897 && strncmp (item->get_cmd (), Command::BIT_CMD, 898 strlen (Command::BIT_CMD)) == 0) 899 || dbe_strcmp (item->get_cmd (), mcmd) == 0)) 900 continue; 901 if (item->is_internal ()) 902 continue; 903 if (item->get_flavors () & BaseMetric::STATIC) 904 { 905 got_metric = 0; 906 int vis = item->get_type () != BaseMetric::ONAME ? 907 dmetrics_visbits : VAL_VALUE; 908 if (append (item, BaseMetric::STATIC, vis) == NULL && !fromRcFile) 909 return 2; 910 continue; 911 } 912 913 // special case for omp metrics: make visible only if 914 // omp data has been collected 915 if (!dbeSession->is_omp_available () 916 && (strcasecmp (mcmd, "ompwork") == 0 917 || strcasecmp (mcmd, "ompwait") == 0)) 918 continue; 919 920 for (int j = 0; j < nsubtypes; j++) 921 { 922 if (append (item, subtypes[j], dmetrics_visbits) == NULL 923 && !fromRcFile) 924 return 2; 925 } 926 got_metric = 0; 927 if (!(any || hwc || bit)) 928 break; 929 } 930 return got_metric; 931} 932 933// parse a single metric specification, to give: 934// a vector of subtypes, and a count of the number of them 935// an integer visibility 936// return the string for the metric name 937 938char * 939MetricList::parse_metric_spec (char *mcmd, BaseMetric::SubType *subtypes, 940 int *nsubtypes, int *dmetrics_visb, bool *isOK) 941{ 942 size_t len_vtype; 943 int index; 944 int vis; 945 bool got_e, got_i, got_a, got_d; 946 char *str = mcmd; 947 char *str2; 948 949 *isOK = true; 950 951 // For dynamic metrics, each keyword is of the form <flavor><visibility><metric-name> 952 // For static metrics, each keyword is of the form [<visibility>]<metric-name> 953 // <flavor> can be either "i" for inclusive or "e" for exclusive 954 // <visibility> can be any combination of "." (to show the metric as a time), 955 // "%" (to show it as a percentage), "+" (to show it as a count), and "!" (turn off the metric) 956 957 // find subtype 958 index = 0; 959 size_t len_subtype = strspn (str, NTXT ("eiad")); 960 str2 = str + len_subtype; 961 962 // find vis 963 if (len_subtype == 0) 964 { 965 // only a . or ! is possible if no subtypes 966 len_vtype = strspn (str2, NTXT (".!")); 967 vis = VAL_VALUE; 968 } 969 else 970 { 971 len_vtype = strspn (str2, NTXT (".+%!")); 972 vis = VAL_NA; 973 } 974 975 // if no visibility bits, there can't be a subtype 976 if (len_vtype == 0) 977 len_subtype = 0; 978 979 if (len_subtype == 0) 980 { 981 // must be a static metric 982 subtypes[index++] = BaseMetric::STATIC; 983 vis = VAL_VALUE; 984 } 985 else 986 { 987 // figure out which subtypes are specified 988 got_e = got_i = got_a = got_d = false; 989 for (size_t i = 0; i < len_subtype; i++) 990 { 991 str += len_subtype; 992 if (mcmd[i] == 'e') 993 { // exclusive 994 if (mtype == MET_DATA) 995 { 996 *isOK = false; 997 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"), 998 mcmd); 999 } 1000 if (!got_e) 1001 { 1002 got_e = true; 1003 subtypes[index++] = BaseMetric::EXCLUSIVE; 1004 } 1005 } 1006 else if (mcmd[i] == 'i') 1007 { // inclusive 1008 if (mtype == MET_DATA) 1009 { 1010 *isOK = false; 1011 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"), 1012 mcmd); 1013 } 1014 if (mtype == MET_INDX) 1015 { 1016 *isOK = false; 1017 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for index metrics\n"), 1018 mcmd); 1019 } 1020 if (!got_i) 1021 { 1022 got_i = true; 1023 subtypes[index++] = BaseMetric::INCLUSIVE; 1024 } 1025 } 1026 else if (mcmd[i] == 'a') 1027 { // attributed 1028 if (mtype != MET_CALL && mtype != MET_CALL_AGR) 1029 { 1030 *isOK = false; 1031 return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for caller-callee metrics only\n"), 1032 mcmd); 1033 } 1034 if (!got_a) 1035 { 1036 got_a = true; 1037 subtypes[index++] = BaseMetric::ATTRIBUTED; 1038 } 1039 } 1040 else if (mcmd[i] == 'd') 1041 { // data-space 1042 if (mtype != MET_DATA) 1043 { 1044 *isOK = false; 1045 return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for data-derived metrics only\n"), 1046 mcmd); 1047 } 1048 if (!got_d) 1049 { 1050 got_d = true; 1051 subtypes[index++] = BaseMetric::DATASPACE; 1052 } 1053 } 1054 } 1055 } 1056 *nsubtypes = index; 1057 1058 // now determine the visiblity bits 1059 if (len_vtype > 0) 1060 { 1061 for (size_t i = 0; i < len_vtype; i++) 1062 { 1063 if (str2[i] == '+') 1064 vis = (vis | VAL_VALUE); 1065 else if (str2[i] == '.') 1066 vis = (vis | VAL_TIMEVAL); 1067 else if (str2[i] == '%') 1068 vis = (vis | VAL_PERCENT); 1069 else if (str2[i] == '!') 1070 vis = (vis | VAL_HIDE_ALL); 1071 } 1072 } 1073 *dmetrics_visb = vis; 1074 return mcmd + len_subtype + len_vtype; 1075} 1076