1 /* Copyright (C) 2021-2023 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 ();