]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprofng/src/MetricList.cc
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / gprofng / src / MetricList.cc
1 /* Copyright (C) 2021-2024 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
29 MetricList::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
191 MetricList::MetricList (MetricType _mtype)
192 {
193 mtype = _mtype;
194 items = new Vector<Metric*>;
195 sort_ref_index = 0;
196 sort_reverse = false;
197 }
198
199 MetricList::~MetricList ()
200 {
201 Destroy (items);
202 }
203
204 // Duplicate a metric list
205 MetricList::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.
226 char *
227 MetricList::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
354 void
355 MetricList::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
389 void
390 MetricList::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
516 char *
517 MetricList::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
617 void
618 MetricList::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
634 bool
635 MetricList::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
670 void
671 MetricList::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
745 char *
746 MetricList::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
762 int
763 MetricList::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
775 int
776 MetricList::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
788 Metric *
789 MetricList::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
801 Metric *
802 MetricList::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
811 Metric *
812 MetricList::get_sort_metric ()
813 {
814 int i = get_sort_ref_index ();
815 return i >= 0 ? items->fetch (i) : NULL;
816 }
817
818 char *
819 MetricList::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
828 char *
829 MetricList::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
846 Metric *
847 MetricList::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
861 int
862 MetricList::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
938 char *
939 MetricList::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 }