1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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)
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.
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. */
25 #include "DefaultMap.h"
26 #include "DbeSession.h"
27 #include "Experiment.h"
28 #include "DataObject.h"
30 #include "Hist_data.h"
32 #include "MemObject.h"
33 #include "IndexObject.h"
34 #include "MetricList.h"
37 #include "LoadObject.h"
39 #include "StringBuilder.h"
45 Hist_data::HistItem::HistItem (long n)
50 value = new TValue[n];
51 memset (value, 0, sizeof (TValue) * n);
54 Hist_data::HistItem::~HistItem ()
56 for (long i = 0; i < size; i++)
57 if (value[i].tag == VT_LABEL)
65 // If the data values have not been computed, do so
66 // Return the total number of items
67 return hist_items->size ();
71 Hist_data::fetch (long index)
73 return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;
77 Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
78 long ind, Hist_data *hdata)
80 // Sort the data depending upon order and type
82 Histable::Type type = hi_1->obj->get_type ();
85 if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ
86 && type != Histable::IOACTVFD && type != Histable::IOACTFILE
87 && type != Histable::IOCALLSTACK)
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);
94 else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD
95 || type == Histable::IOACTFILE)
98 idx1 = ((FileData *) (hi_1->obj))->get_index ();
99 idx2 = ((FileData *) (hi_2->obj))->get_index ();
102 else if (idx1 > idx2)
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.
113 bool needsStringCompare = false;
114 if (type == Histable::MEMOBJ)
116 i1 = ((MemObj *) (hi_1->obj))->get_index ();
117 i2 = ((MemObj *) (hi_2->obj))->get_index ();
119 else if (type == Histable::INDEXOBJ)
121 i1 = ((IndexObject *) (hi_1->obj))->get_index ();
122 i2 = ((IndexObject *) (hi_2->obj))->get_index ();
124 ((IndexObject *) (hi_1->obj))->requires_string_sort ();
128 if (i1 == (uint64_t) - 2)
130 else if (i2 == (uint64_t) - 2)
132 else if (i1 == (uint64_t) - 1)
134 else if (i2 == (uint64_t) - 1)
136 else if (needsStringCompare)
138 char *nm1 = hi_1->obj->get_name ();
139 char *nm2 = hi_2->obj->get_name ();
140 if (nm1 != NULL && nm2 != NULL)
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)
147 else if (nm2_lead == '(' && nm1_lead != nm2_lead)
150 result = strcoll (nm1, nm2);
154 { // matches, resolve by index
162 else if (stype == AUX)
166 case Histable::INSTR:
168 DbeInstr *instr1 = (DbeInstr*) hi_1->obj;
169 DbeInstr *instr2 = (DbeInstr*) hi_2->obj;
170 result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0;
175 DbeLine *dbl1 = (DbeLine*) hi_1->obj;
176 DbeLine *dbl2 = (DbeLine*) hi_2->obj;
177 result = dbl1->line_cmp (dbl2);
184 else if (stype == VALUE)
186 Metric *m = hdata->get_metric_list ()->get (ind);
187 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
190 int first_ind = hdata->hist_metrics[ind].indFirstExp;
191 if ((m->get_visbits () & VAL_DELTA) != 0)
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);
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);
201 result = v1.compare (&v2);
204 result = hi_1->value[ind].compare (hi_2->value + ind);
210 Hist_data::sort_compare_all (const void *a, const void *b, const void *arg)
212 HistItem *hi_1 = *((HistItem **) a);
213 HistItem *hi_2 = *((HistItem **) b);
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)
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
225 result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL);
228 for (long i = 0, sz = hdata->metrics->size (); i < sz; i++)
230 Metric *m = hdata->metrics->get (i);
231 if (m->get_type () != Metric::ONAME)
233 result = sort_compare (hi_1, hi_2, VALUE, i, hdata);
236 if (hdata->sort_order == DESCEND)
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)
249 Function *f1 = (Function*) hi_1->obj;
250 Function *f2 = (Function*) hi_2->obj;
251 if (f1->get_addr () < f2->get_addr ())
253 else if (f1->get_addr () > f2->get_addr ())
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,
261 if (hi_1->obj->id < hi_2->obj->id)
263 else if (hi_1->obj->id > hi_2->obj->id)
268 return result; // shouldn't happen in most cases; line allows for breakpoint
275 Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg)
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;
286 Hist_data *hdata = (Hist_data*) arg;
288 // are the two items members of the same object?
289 if (parent1 == parent2)
294 // and they have real parents...
295 if (parent1->get_typename ())
297 // use dobj1/dobj2 offset for sorting
298 uint64_t off1 = dobj1->get_offset ();
299 uint64_t off2 = dobj2->get_offset ();
312 if (parent1 == dobj2)
313 // sorting an object and its parent: parent always first
319 if (parent2 == dobj1)
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);
330 Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type,
331 Hist_data::Mode _mode, bool _viewowned)
333 hist_items = new Vector<HistItem*>;
335 nmetrics = metrics->get_items ()->size ();
338 gprof_item = new_hist_item (NULL);
339 viewowned = _viewowned;
343 Histable *tobj = new Other;
344 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
345 minimum = new_hist_item (tobj);
348 tobj->name = dbe_strdup (NTXT (""));
349 maximum = new_hist_item (tobj);
352 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx"));
353 maximum_inc = new_hist_item (tobj);
356 tobj->name = dbe_strdup (NTXT ("<Total>"));
357 total = new_hist_item (tobj);
360 tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX"));
361 threshold = new_hist_item (tobj);
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++)
368 Metric::HistMetric *h = hist_metrics + i;
370 Metric *m = metrics->get (i);
371 if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO)))
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 ())
378 metrics->get_listorder (m->get_dependent_bm ()->get_cmd (),
379 m->get_subtype (), m->get_expr_spec ());
384 Hist_data::~Hist_data ()
386 delete[] hist_metrics;
389 hist_items->destroy ();
406 delete maximum_inc->obj;
424 delete threshold->obj;
430 delete callsite_mark;
434 Hist_data::dump (char *msg, FILE *f)
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++)
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)");
446 fprintf (f, NTXT (" HistItem listing\n"));
447 int n = hist_items->size ();
448 for (int j = -1; j < n; j++)
454 fprintf (f, NTXT (" total"));
458 hi = hist_items->fetch (j);
459 fprintf (f, NTXT ("%30s"), hi->obj->get_name ());
461 for (int i = 0; i < nmetrics; i++)
463 char *stmp = hi->value[i].l;
464 switch (hi->value[i].tag)
466 case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s);
468 case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i);
470 case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
472 case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f);
474 case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d);
476 case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
478 case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)");
480 case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
482 case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p);
484 case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
486 default: fprintf (f, NTXT (" "));
490 fprintf (f, NTXT ("\n"));
495 Hist_data::sort (long ind, bool reverse)
497 if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort)
498 // there's no change to the sorting
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) ?
518 if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
519 hist_items->sort ((CompareFunc) sort_compare_dlayout, this);
521 hist_items->sort ((CompareFunc) sort_compare_all, this);
523 // ensure that <Total> comes first/last
524 char *tname = NTXT ("<Total>");
525 for (int i = 0; i < hist_items->size (); ++i)
527 HistItem *hi = hist_items->fetch (i);
528 char *name = hi->obj->get_name ();
529 if (name != NULL && streq (name, tname))
531 int idx0 = rev_sort ? hist_items->size () - 1 : 0;
534 hist_items->remove (i);
535 hist_items->insert (idx0, hi);
543 Hist_data::resort (MetricList *mlist)
545 if (mlist->get_type () != metrics->get_type ())
546 if (metrics->get_type () == MET_CALL)
547 // wrong type of list -- internal error
550 // get the new sort order
551 int ind = mlist->get_sort_ref_index ();
552 bool reverse = mlist->get_sort_rev ();
557 Hist_data::compute_minmax ()
562 for (int mind = 0; mind < nmetrics; mind++)
564 Metric *mtr = metrics->get_items ()->fetch (mind);
565 if (mtr->get_subtype () == Metric::STATIC)
567 if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
569 ValueTag vtype = mtr->get_vtype2 ();
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;
581 Vec_loop (HistItem *, hist_items, index, hi)
583 if (metrics->get_type () == MET_SRCDIS
584 && callsite_mark->get (hi->obj))
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
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;
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)
605 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
607 if (hi->value[mind].d > maximum_inc->value[mind].d)
609 maximum_inc->value[mind].d = hi->value[mind].d;
610 maximum_inc->value[mind].sign = hi->value[mind].sign;
612 // ignore ones that has inclusive time for src/dis view
616 if (hi->value[mind].d > maximum->value[mind].d)
618 maximum->value[mind].d = hi->value[mind].d;
619 maximum->value[mind].sign = hi->value[mind].sign;
621 if (hi->value[mind].d < minimum->value[mind].d)
623 minimum->value[mind].d = hi->value[mind].d;
624 minimum->value[mind].sign = hi->value[mind].sign;
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)
640 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
642 if (hi->value[mind].ll > maximum_inc->value[mind].ll)
644 maximum_inc->value[mind].ll = hi->value[mind].ll;
645 maximum_inc->value[mind].sign = hi->value[mind].sign;
647 // ignore ones that has inclusive time for src/dis view
651 if (hi->value[mind].ll > maximum->value[mind].ll)
653 maximum->value[mind].ll = hi->value[mind].ll;
654 maximum->value[mind].sign = hi->value[mind].sign;
656 if (hi->value[mind].ll < minimum->value[mind].ll)
658 minimum->value[mind].ll = hi->value[mind].ll;
659 minimum->value[mind].sign = hi->value[mind].sign;
670 Hist_data::HistItem *
671 Hist_data::new_hist_item (Histable *obj)
673 long sz = get_metric_list ()->size ();
674 HistItem *hi = new HistItem (sz);
677 // We precalculate all metrics as integer values
678 // and convert them to appropriate types later.
679 for (long i = 0; i < sz; i++)
681 hi->value[i].tag = VT_INT;
687 Hist_data::HistItem *
688 Hist_data::new_hist_item (Histable *obj, int itype, TValue *value)
690 long sz = get_metric_list ()->size ();
691 HistItem *hi = new HistItem (sz);
695 for (long i = 0; i < sz; i++)
696 hi->value[i] = value[i];
701 Hist_data::HistItem *
702 Hist_data::find_hist_item (Histable *obj)
706 return hi_map->get (obj);
709 Hist_data::HistItem *
710 Hist_data::append_hist_item (Histable *obj)
714 HistItem *hi = hi_map->get (obj);
717 hi = new_hist_item (obj);
718 hist_items->append (hi);
719 hi_map->put (obj, hi);
721 if (status == NO_DATA)
727 Hist_data::append_hist_item (HistItem *hi)
729 hist_items->append (hi);
733 Hist_data::above_threshold (HistItem* hi)
739 Vec_loop (Metric*, metrics->get_items (), index, mitem)
741 if (mitem->get_subtype () == Metric::STATIC)
743 switch (hi->value[index].tag)
746 if (hi->value[index].d > threshold->value[index].d)
750 if (hi->value[index].i > threshold->value[index].i)
754 if (hi->value[index].ll > threshold->value[index].ll)
758 if (hi->value[index].ull > threshold->value[index].ull)
761 // ignoring the following cases (why?)
775 Hist_data::set_threshold (double proportion)
779 Vec_loop (Metric*, metrics->get_items (), index, mitem)
781 TValue *thresh = &threshold->value[index];
782 TValue *mtotal = &total->value[index];
783 thresh->tag = mitem->get_vtype ();
785 if (mitem->get_subtype () == Metric::STATIC)
790 thresh->i = (int) (proportion * (double) mtotal->i);
793 thresh->d = proportion * mtotal->d;
797 thresh->ull = (unsigned long long) (proportion * (double) mtotal->ll);
811 Hist_data::get_percentage (double value, int mindex)
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 ();
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)
825 return value / total_value;
829 Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric,
833 StringBuilder sb, sb1, sb2, sb3;
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 (""));
842 for (int i = 0; i < nmetrics; i++)
844 Metric *m = metrics->get (i);
845 Metric::HistMetric *hm = &hist_metric[i];
847 char *fmt = NTXT ("%-*s");
848 if ((i > 0) && (m->get_type () == Metric::ONAME))
850 name_offset = sb1.length ();
851 fmt = NTXT (" %-*s");
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);
860 if (sb.length () != 0)
862 sb.toFileLn (out_file);
864 sb1.toFileLn (out_file);
865 sb2.toFileLn (out_file);
866 sb3.toFileLn (out_file);
871 Hist_data::print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit)
874 int cnt = VecSize (hist_items);
875 if (cnt > limit && limit > 0)
877 for (int i = 0; i < cnt; i++)
880 print_row (&sb, i, hist_metric, NTXT (" "));
881 sb.toFileLn (out_file);
886 append_str (StringBuilder *sb, char *s, size_t len, int vis_bits)
888 if ((vis_bits & VAL_RATIO) != 0)
890 if (*s != 'N') // Nan
891 sb->appendf (NTXT ("x "));
893 sb->appendf (NTXT (" "));
894 sb->appendf (NTXT ("%*s"), (int) (len - 2), s);
897 sb->appendf (NTXT ("%*s"), (int) len, s);
901 Hist_data::print_row (StringBuilder *sb, int row, Metric::HistMetric *hmp,
906 // Print only a list of user's metrics. ( nmetrics <= mlist->size() )
907 for (long i = 0; i < nmetrics; i++)
909 // Print only a list of user's metrics.
910 Metric *m = metrics->get (i);
911 if (!m->is_any_visible ())
913 Metric::HistMetric *hm = hmp + i;
914 int len = sb->length ();
915 if (m->is_tvisible ())
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 ());
921 if (m->is_visible ())
923 TValue *v = get_value (&res, i, row);
924 char *s = v->to_str (buf, sizeof (buf));
925 if (m->get_type () == BaseMetric::ONAME)
928 if (i + 1 == nmetrics)
929 sb->appendf (NTXT ("%s"), s);
931 sb->appendf (NTXT ("%-*s "), (int) hm->maxvalue_width, s);
936 if (len != sb->length ())
938 append_str (sb, s, hm->maxvalue_width, m->get_visbits ());
941 if (m->is_pvisible ())
943 if (len != sb->length ())
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);
951 // adjust to change format from xx.yy%
952 sb->append (NTXT (" 0. "));
954 // adjust format below to change format from xx.yy%
955 sb->appendf (NTXT ("%6.2f"), (100.0 * percent));
957 len = sb->length () - len;
958 if (hm->width > len && i + 1 != nmetrics)
959 sb->appendf (NTXT ("%*s"), (int) (hm->width - len), NTXT (" "));
964 Hist_data::get_real_value (TValue *res, int met_index, int row)
966 HistItem *hi = hist_items->get (row);
967 Metric *m = metrics->get (met_index);
968 if (m->get_type () == BaseMetric::ONAME)
970 res->l = dbe_strdup (hi->obj->get_name ());
974 return hi->value + met_index;
978 Hist_data::get_value (TValue *res, int met_index, int row)
980 HistItem *hi = hist_items->get (row);
981 Metric *m = metrics->get (met_index);
982 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
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);
988 res->make_ratio (hi->value + met_index, hi->value + ind);
991 return get_real_value (res, met_index, row);
995 Hist_data::get_value (TValue *res, int met_index, HistItem *hi)
997 Metric *m = metrics->get (met_index);
998 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
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);
1004 res->make_ratio (hi->value + met_index, hi->value + ind);
1007 if (m->get_type () == BaseMetric::ONAME)
1009 res->l = dbe_strdup (hi->obj->get_name ());
1010 res->tag = VT_LABEL;
1013 return hi->value + met_index;
1016 Metric::HistMetric *
1017 Hist_data::get_histmetrics ()
1019 // find the width for each column.
1020 for (long i = 0, sz = metrics->size (); i < sz; i++)
1022 Metric *m = metrics->get (i);
1023 Metric::HistMetric *hm = hist_metrics + i;
1024 if (m->is_value_visible ())
1027 for (long i1 = 0, sz1 = VecSize(hist_items); i1 < sz1; i1++)
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;
1034 if ((m->get_visbits () & VAL_RATIO) != 0)
1035 hm->maxvalue_width += 2; // "x "
1039 for (long i = 0, sz = metrics->size (); i < sz; i++)
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);
1048 return hist_metrics;
1052 Hist_data::update_total (Hist_data::HistItem *new_total)
1054 for (long i = 0, sz = metrics->size (); i < sz; i++)
1055 total->value[i] = new_total->value[i];
1059 Hist_data::update_max (Metric::HistMetric *hm_tmp)
1061 Metric::HistMetric *hms = get_histmetrics ();
1062 for (int i = 0; i < nmetrics; i++)
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;
1074 Hist_data::update_legend_width (Metric::HistMetric *hm_tmp)
1076 for (int i = 0; i < nmetrics; i++)
1078 Metric *m = metrics->get (i);
1079 m->legend_width (hm_tmp + i, 2);
1084 Metric::HistMetric::update_max (Metric::HistMetric *hm)
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;
1093 Metric::HistMetric::init ()
1106 Hist_data::value_maxlen (int mindex)
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;
1115 Hist_data::time_len (TValue *value, int clock)
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 ();
1125 Hist_data::time_maxlen (int mindex, int clock)
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;
1134 Hist_data::name_len (HistItem *item)
1136 char *name = item->obj->get_name ();
1137 return strlen (name);
1141 Hist_data::name_maxlen ()
1144 for (long i = 0; i < size (); i++)
1146 HistItem *hi = fetch (i);
1147 size_t len = name_len (hi);
1154 // Returns vector of object ids for the vector of selections
1155 // returns NULL if no valid selections
1157 Hist_data::get_object_indices (Vector<int> *selections)
1159 // if no selections, return NULL
1160 if (selections == NULL || selections->size () == 0)
1163 Vector<uint64_t> *indices = new Vector<uint64_t>;
1164 for (long i = 0, sz = selections->size (); i < sz; i++)
1166 int sel = selections->get (i);
1167 HistItem *hi = hist_items->get (sel);
1168 if (hi == NULL || hi->obj == NULL)
1170 Vector<Histable*> *v = hi->obj->get_comparable_objs ();
1171 for (long i1 = 0, sz1 = v ? v->size () : 0; i1 < sz1; i1++)
1173 Histable *h1 = v->get (i1);
1174 if (h1 && (indices->find_r (h1->id) < 0))
1175 indices->append (h1->id);
1177 if (indices->find_r (hi->obj->id) < 0)
1178 indices->append (hi->obj->id);
1183 DbeInstr::DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr)
1189 img_offset = addr + func->img_offset;
1192 current_name_format = NA;
1198 DbeInstr::pc_cmp (DbeInstr *instr2)
1204 // All PC's with the Line flag go to the
1205 // end of the list. See Module::init_index()
1206 if (flags & PCLineFlag)
1208 if (instr2->flags & PCLineFlag)
1210 if (addr < instr2->addr)
1212 else if (addr > instr2->addr)
1220 else if (instr2->flags & PCLineFlag)
1222 else if (func == instr2->func)
1226 if (addr < instr2->addr)
1228 else if (addr == instr2->addr)
1230 else if (addr >= instr2->addr + instr2->size)
1235 else if (instr2->size == 0)
1237 if (addr > instr2->addr)
1239 else if (addr + size <= instr2->addr)
1244 else if (addr < instr2->addr)
1246 else if (addr > instr2->addr)
1253 if (flags & PCTrgtFlag)
1255 if (!(instr2->flags & PCTrgtFlag))
1258 else if (instr2->flags & PCTrgtFlag)
1263 result = func->func_cmp (instr2->func);
1268 DbeInstr::get_name (NameFormat nfmt)
1270 if (name && (nfmt == current_name_format || nfmt == Histable::NA))
1275 current_name_format = nfmt;
1276 char *fname = func->get_name (nfmt);
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>"),
1287 else if (addr == (uint64_t) - 3)
1288 name = dbe_sprintf (GTXT ("%s <Java native method>"), fname);
1291 char buf[64], *typetag = NTXT (""), *alloc_typetag = NULL;
1294 if (func != dbeSession->get_JUnknown_Function ())
1296 if (addr <= 0xFFFFFFFFU)
1297 snprintf (buf, sizeof (buf), " + 0x%08X", (unsigned int) addr);
1299 snprintf (buf, sizeof (buf), " + 0x%016llX",
1300 (unsigned long long) addr);
1305 switch ((long int) addr)
1308 subname = GTXT ("agent error");
1311 subname = GTXT ("GC active");
1314 subname = GTXT ("unknown non-Java frame");
1317 subname = GTXT ("unwalkable non-Java frame");
1320 subname = GTXT ("unknown Java frame");
1323 subname = GTXT ("unwalkable Java frame");
1326 subname = GTXT ("unknown thread state");
1329 subname = GTXT ("thread in exit");
1332 subname = GTXT ("deopt in process ticks");
1335 subname = GTXT ("safepoint synchronizing ticks");
1338 subname = GTXT ("unexpected error");
1341 snprintf (buf, sizeof (buf), "<%s (%d)>", subname, (int) addr);
1344 if (flags & PCTrgtFlag)
1345 // annotate synthetic instruction
1346 sb.append ('*'); // special distinguishing marker
1348 DbeLine *dbeline = mapPCtoLine (NULL);
1350 if (dbeline && dbeline->lineno > 0)
1351 str = strrchr (dbeline->get_name (nfmt), ',');
1354 if (strlen (typetag) > 0)
1355 { // include padding for alignment
1360 while (sb.length () < 40);
1361 sb.append (typetag);
1362 delete alloc_typetag;
1364 if (inlinedInd >= 0)
1365 add_inlined_info (&sb);
1366 name = sb.toString ();
1372 DbeInstr::mapPCtoLine (SourceFile *sf)
1374 if (inlinedInd == -1)
1377 for (int i = 0; i < func->inlinedSubrCnt; i++)
1379 InlinedSubr *p = func->inlinedSubr + i;
1382 if (addr < p->low_pc)
1384 if (p->contains (addr))
1392 if (inlinedInd >= 0)
1394 DbeLine *dl = func->inlinedSubr[inlinedInd].dbeLine;
1395 return dl->sourceFile->find_dbeline (func, dl->lineno);
1397 return func->mapPCtoLine (addr, sf);
1401 DbeInstr::add_inlined_info (StringBuilder *sb)
1407 while (sb->length () < 40);
1408 sb->append (NTXT ("<-- "));
1410 InlinedSubr *last = NULL;
1411 for (int i = inlinedInd; i < func->inlinedSubrCnt; i++)
1413 InlinedSubr *p = func->inlinedSubr + i;
1414 if (p->level == 0 && i > inlinedInd)
1416 if (!p->contains (addr))
1422 sb->append (last->fname);
1425 DbeLine *dl = p->dbeLine;
1426 sb->appendf (NTXT ("%s:%lld <-- "), get_basename (dl->sourceFile->get_name ()), (long long) dl->lineno);
1434 sb->append (last->fname);
1438 DbeLine *dl = func->mapPCtoLine (addr, NULL);
1439 sb->appendf ("%s:%lld ", get_basename (dl->sourceFile->get_name ()),
1440 (long long) dl->lineno);
1444 DbeInstr::get_descriptor ()
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)
1453 inst_info_t *info = NULL;
1454 Vec_loop (inst_info_t*, mod->infoList, i, info)
1456 if (info->offset == func->img_offset + addr) break;
1461 datatype_t *dtype = NULL;
1462 Vec_loop (datatype_t*, mod->datatypes, t, dtype)
1464 if (dtype->datatype_id == info->memop->datatype_id)
1467 if (dtype && dtype->dobj)
1468 typetag = dtype->dobj->get_name ();
1472 return dbe_strdup (typetag);
1476 DbeInstr::get_size ()
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;
1485 DbeInstr::get_addr ()
1487 return func->get_addr () + addr;
1491 DbeInstr::convertto (Type type, Histable *obj)
1493 Histable *res = NULL;
1494 SourceFile *source = (SourceFile*) obj;
1501 res = mapPCtoLine (source);
1504 res = mapPCtoLine (source);
1506 res = ((DbeLine*) res)->sourceFile;
1518 DbeEA::get_name (NameFormat)
1522 name = dbe_strdup (dbeSession->localized_SP_UNKNOWN_NAME);
1527 DbeEA::convertto (Type type, Histable *obj)
1529 Histable *res = NULL;
1530 assert (obj == NULL);
1545 DbeLine::DbeLine (Function *_func, SourceFile *sf, int _lineno)
1550 id = sf->id + _lineno;
1555 dbeline_func_next = NULL;
1556 dbeline_base = this;
1557 current_name_format = Histable::NA;
1560 DbeLine::~DbeLine ()
1562 delete dbeline_func_next;
1566 DbeLine::line_cmp (DbeLine *dbl)
1568 return lineno - dbl->lineno;
1572 DbeLine::init_Offset (uint64_t p_offset)
1576 if (dbeline_base && dbeline_base->offset == 0)
1577 dbeline_base->offset = p_offset;
1581 DbeLine::get_name (NameFormat nfmt)
1583 char *srcname = NULL, *basename, *fname;
1589 srcname = sourceFile->get_name ();
1590 basename = get_basename (srcname);
1591 name = dbe_sprintf (GTXT ("line %u in \"%s\""), lineno, basename);
1595 if (name && (nfmt == current_name_format || nfmt == Histable::NA))
1598 current_name_format = nfmt;
1600 fname = func->get_name (nfmt);
1601 if (func->flags & (FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET))
1603 name = dbe_strdup (fname);
1608 srcname = sourceFile->get_name ();
1609 if (!srcname || strlen (srcname) == 0)
1610 srcname = func->getDefSrcName ();
1611 basename = get_basename (srcname);
1615 if (sourceFile == func->getDefSrc ())
1616 name = dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname, lineno,
1619 name = dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""),
1620 fname, lineno, basename);
1622 else if (sourceFile == NULL || (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
1623 name = dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"),
1626 name = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
1632 DbeLine::get_size ()
1638 DbeLine::get_addr ()
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;
1647 DbeLine::convertto (Type type, Histable *obj)
1649 Histable *res = NULL;
1654 Function *f = (Function *) convertto (FUNCTION, NULL);
1656 res = f->find_dbeinstr (0, offset);
1671 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
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))
1682 if (res == NULL && dbeline_func_next)
1684 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
1686 Function *f = dl->func;
1687 if (f && f->def_source == sourceFile)
1694 if (res == NULL && dbeline_func_next)
1695 res = dbeline_func_next->func;
1699 res = (include) ? include : sourceFile;
1707 CStack_data::CStack_data (MetricList *_metrics)
1710 total = new_cstack_item ();
1711 cstack_items = new Vector<CStack_item*>;
1714 CStack_data::CStack_item::CStack_item (long n)
1719 value = new TValue[n];
1720 memset (value, 0, sizeof (TValue) * n);
1723 CStack_data::CStack_item::~CStack_item ()
1729 CStack_data::CStack_item *
1730 CStack_data::new_cstack_item ()
1732 int nmetrics = metrics->get_items ()->size ();
1733 CStack_item *item = new CStack_item (nmetrics);
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 ();
1742 HistableFile::HistableFile ()
1748 Histable::Histable ()
1752 comparable_objs = NULL;
1753 phaseCompareIdx = -1;
1756 Histable::~Histable ()
1758 delete_comparable_objs ();
1763 Histable::delete_comparable_objs ()
1765 if (comparable_objs)
1767 Vector<Histable*> *v = comparable_objs;
1768 for (int i = 0; i < v->size (); i++)
1770 Histable *h = v->fetch (i);
1773 h->comparable_objs = NULL;
1774 h->phaseCompareIdx = phaseCompareIdx;
1782 Histable::update_comparable_objs ()
1784 if (phaseCompareIdx != ExpGroup::phaseCompareIdx)
1786 phaseCompareIdx = ExpGroup::phaseCompareIdx;
1787 delete_comparable_objs ();
1792 Histable::get_comparable_objs ()
1794 return comparable_objs;
1798 Histable::get_compare_obj ()
1800 Vector<Histable*> *v = get_comparable_objs ();
1801 for (long i = 0, sz = VecSize (v); i < sz; i++)
1803 Histable *h = v->get (i);
1810 #define CASE_S(x) case x: return (char *) #x
1813 Histable::type_to_string ()
1815 switch (get_type ())
1821 CASE_S (LOADOBJECT);
1827 CASE_S (SOURCEFILE);
1828 CASE_S (EXPERIMENT);
1833 return NTXT ("ERROR");
1837 Histable::dump_comparable_objs ()
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,
1843 for (int i = 0, sz = comparable_objs ? comparable_objs->size () : 0; i < sz; i++)
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 (""));
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 ())
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);
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);
1886 return sb.toString ();