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
, char *mark
)
905 // Print only a list of user's metrics. ( nmetrics <= mlist->size() )
906 for (long i
= 0; i
< nmetrics
; i
++)
908 // Print only a list of user's metrics.
909 Metric
*m
= metrics
->get (i
);
910 if (!m
->is_any_visible ())
912 Metric::HistMetric
*hm
= hmp
+ i
;
913 int len
= sb
->length ();
914 if (m
->is_tvisible ())
916 TValue
*v
= get_value (&res
, hist_metrics
[i
].indTimeVal
, row
);
917 char *s
= v
->to_str (buf
, sizeof (buf
));
918 append_str (sb
, s
, hm
->maxtime_width
, m
->get_visbits ());
920 if (m
->is_visible ())
922 TValue
*v
= get_value (&res
, i
, row
);
923 char *s
= v
->to_str (buf
, sizeof (buf
));
924 if (m
->get_type () == BaseMetric::ONAME
)
927 if (i
+ 1 == nmetrics
)
928 sb
->appendf (NTXT ("%s"), s
);
930 sb
->appendf (NTXT ("%-*s "), (int) hm
->maxvalue_width
, s
);
935 if (len
!= sb
->length ())
937 append_str (sb
, s
, hm
->maxvalue_width
, m
->get_visbits ());
940 if (m
->is_pvisible ())
942 if (len
!= sb
->length ())
945 if (m
->is_tvisible () && !m
->is_visible ())
946 met_ind
= hist_metrics
[i
].indTimeVal
;
947 TValue
*v
= get_real_value (&res
, met_ind
, row
);
948 double percent
= get_percentage (v
->to_double (), met_ind
);
950 // adjust to change format from xx.yy%
951 sb
->append (NTXT (" 0. "));
953 // adjust format below to change format from xx.yy%
954 sb
->appendf (NTXT ("%6.2f"), (100.0 * percent
));
956 len
= sb
->length () - len
;
957 if (hm
->width
> len
&& i
+ 1 != nmetrics
)
958 sb
->appendf (NTXT ("%*s"), (int) (hm
->width
- len
), NTXT (" "));
963 Hist_data::get_real_value (TValue
*res
, int met_index
, int row
)
965 HistItem
*hi
= hist_items
->get (row
);
966 Metric
*m
= metrics
->get (met_index
);
967 if (m
->get_type () == BaseMetric::ONAME
)
969 res
->l
= dbe_strdup (hi
->obj
->get_name ());
973 return hi
->value
+ met_index
;
977 Hist_data::get_value (TValue
*res
, int met_index
, int row
)
979 HistItem
*hi
= hist_items
->get (row
);
980 Metric
*m
= metrics
->get (met_index
);
981 if ((m
->get_visbits () & (VAL_DELTA
| VAL_RATIO
)) != 0)
983 int ind
= hist_metrics
[met_index
].indFirstExp
;
984 if ((m
->get_visbits () & VAL_DELTA
) != 0)
985 res
->make_delta (hi
->value
+ met_index
, hi
->value
+ ind
);
987 res
->make_ratio (hi
->value
+ met_index
, hi
->value
+ ind
);
990 return get_real_value (res
, met_index
, row
);
994 Hist_data::get_value (TValue
*res
, int met_index
, HistItem
*hi
)
996 Metric
*m
= metrics
->get (met_index
);
997 if ((m
->get_visbits () & (VAL_DELTA
| VAL_RATIO
)) != 0)
999 int ind
= hist_metrics
[met_index
].indFirstExp
;
1000 if ((m
->get_visbits () & VAL_DELTA
) != 0)
1001 res
->make_delta (hi
->value
+ met_index
, hi
->value
+ ind
);
1003 res
->make_ratio (hi
->value
+ met_index
, hi
->value
+ ind
);
1006 if (m
->get_type () == BaseMetric::ONAME
)
1008 res
->l
= dbe_strdup (hi
->obj
->get_name ());
1009 res
->tag
= VT_LABEL
;
1012 return hi
->value
+ met_index
;
1015 Metric::HistMetric
*
1016 Hist_data::get_histmetrics ()
1018 // find the width for each column.
1019 for (long i
= 0, sz
= metrics
->size (); i
< sz
; i
++)
1021 Metric
*m
= metrics
->get (i
);
1022 Metric::HistMetric
*hm
= hist_metrics
+ i
;
1023 if (m
->is_value_visible ())
1026 for (long i1
= 0, sz1
= VecSize(hist_items
); i1
< sz1
; i1
++)
1028 TValue
*v
= get_value (&res
, i
, i1
);
1029 long len
= v
->get_len ();
1030 if (hm
->maxvalue_width
< len
)
1031 hm
->maxvalue_width
= len
;
1033 if ((m
->get_visbits () & VAL_RATIO
) != 0)
1034 hm
->maxvalue_width
+= 2; // "x "
1038 for (long i
= 0, sz
= metrics
->size (); i
< sz
; i
++)
1040 Metric
*m
= metrics
->get (i
);
1041 Metric::HistMetric
*hm
= hist_metrics
+ i
;
1042 if (m
->is_time_visible ())
1043 // take a value from depended metric
1044 hm
->maxtime_width
= hist_metrics
[hm
->indTimeVal
].maxvalue_width
;
1045 m
->legend_width (hm
, 2);
1047 return hist_metrics
;
1051 Hist_data::update_total (Hist_data::HistItem
*new_total
)
1053 for (long i
= 0, sz
= metrics
->size (); i
< sz
; i
++)
1054 total
->value
[i
] = new_total
->value
[i
];
1058 Hist_data::update_max (Metric::HistMetric
*hm_tmp
)
1060 Metric::HistMetric
*hms
= get_histmetrics ();
1061 for (int i
= 0; i
< nmetrics
; i
++)
1063 Metric::HistMetric
*hm
= hms
+ i
;
1064 Metric::HistMetric
*hm1
= hm_tmp
+ i
;
1065 if (hm1
->maxtime_width
< hm
->maxtime_width
)
1066 hm1
->maxtime_width
= hm
->maxtime_width
;
1067 if (hm1
->maxvalue_width
< hm
->maxvalue_width
)
1068 hm1
->maxvalue_width
= hm
->maxvalue_width
;
1073 Hist_data::update_legend_width (Metric::HistMetric
*hm_tmp
)
1075 for (int i
= 0; i
< nmetrics
; i
++)
1077 Metric
*m
= metrics
->get (i
);
1078 m
->legend_width (hm_tmp
+ i
, 2);
1083 Metric::HistMetric::update_max (Metric::HistMetric
*hm
)
1085 if (maxtime_width
< hm
->maxtime_width
)
1086 maxtime_width
= hm
->maxtime_width
;
1087 if (maxvalue_width
< hm
->maxvalue_width
)
1088 maxvalue_width
= hm
->maxvalue_width
;
1092 Metric::HistMetric::init ()
1105 Hist_data::value_maxlen (int mindex
)
1107 size_t maxlen
= maximum
->value
[mindex
].get_len ();
1108 size_t minlen
= minimum
->value
[mindex
].get_len ();
1109 // minlen can be bigger than maxlen only for negative value
1110 return minlen
> maxlen
? minlen
: maxlen
;
1114 Hist_data::time_len (TValue
*value
, int clock
)
1117 tm_value
.tag
= VT_DOUBLE
;
1118 tm_value
.sign
= value
->sign
;
1119 tm_value
.d
= 1.e
-6 * value
->ll
/ clock
;
1120 return tm_value
.get_len ();
1124 Hist_data::time_maxlen (int mindex
, int clock
)
1126 size_t maxlen
= time_len (&(maximum
->value
[mindex
]), clock
);
1127 size_t minlen
= time_len (&(minimum
->value
[mindex
]), clock
);
1128 // minlen can be bigger than maxlen only for negative value
1129 return minlen
> maxlen
? minlen
: maxlen
;
1133 Hist_data::name_len (HistItem
*item
)
1135 char *name
= item
->obj
->get_name ();
1136 return strlen (name
);
1140 Hist_data::name_maxlen ()
1143 for (long i
= 0; i
< size (); i
++)
1145 HistItem
*hi
= fetch (i
);
1146 size_t len
= name_len (hi
);
1153 // Returns vector of object ids for the vector of selections
1154 // returns NULL if no valid selections
1156 Hist_data::get_object_indices (Vector
<int> *selections
)
1158 // if no selections, return NULL
1159 if (selections
== NULL
|| selections
->size () == 0)
1162 Vector
<uint64_t> *indices
= new Vector
<uint64_t>;
1163 for (long i
= 0, sz
= selections
->size (); i
< sz
; i
++)
1165 int sel
= selections
->get (i
);
1166 HistItem
*hi
= hist_items
->get (sel
);
1167 if (hi
== NULL
|| hi
->obj
== NULL
)
1169 Vector
<Histable
*> *v
= hi
->obj
->get_comparable_objs ();
1170 for (long i1
= 0, sz1
= v
? v
->size () : 0; i1
< sz1
; i1
++)
1172 Histable
*h1
= v
->get (i1
);
1173 if (h1
&& (indices
->find_r (h1
->id
) < 0))
1174 indices
->append (h1
->id
);
1176 if (indices
->find_r (hi
->obj
->id
) < 0)
1177 indices
->append (hi
->obj
->id
);
1182 DbeInstr::DbeInstr (uint64_t _id
, int _flags
, Function
*_func
, uint64_t _addr
)
1188 img_offset
= addr
+ func
->img_offset
;
1191 current_name_format
= NA
;
1197 DbeInstr::pc_cmp (DbeInstr
*instr2
)
1203 // All PC's with the Line flag go to the
1204 // end of the list. See Module::init_index()
1205 if (flags
& PCLineFlag
)
1207 if (instr2
->flags
& PCLineFlag
)
1209 if (addr
< instr2
->addr
)
1211 else if (addr
> instr2
->addr
)
1219 else if (instr2
->flags
& PCLineFlag
)
1221 else if (func
== instr2
->func
)
1225 if (addr
< instr2
->addr
)
1227 else if (addr
== instr2
->addr
)
1229 else if (addr
>= instr2
->addr
+ instr2
->size
)
1234 else if (instr2
->size
== 0)
1236 if (addr
> instr2
->addr
)
1238 else if (addr
+ size
<= instr2
->addr
)
1243 else if (addr
< instr2
->addr
)
1245 else if (addr
> instr2
->addr
)
1252 if (flags
& PCTrgtFlag
)
1254 if (!(instr2
->flags
& PCTrgtFlag
))
1257 else if (instr2
->flags
& PCTrgtFlag
)
1262 result
= func
->func_cmp (instr2
->func
);
1267 DbeInstr::get_name (NameFormat nfmt
)
1269 if (name
&& (nfmt
== current_name_format
|| nfmt
== Histable::NA
))
1274 current_name_format
= nfmt
;
1275 char *fname
= func
->get_name (nfmt
);
1277 if (func
->flags
& FUNC_FLAG_NO_OFFSET
)
1278 name
= dbe_strdup (fname
);
1279 else if (addr
== (uint64_t) - 1
1280 && func
!= dbeSession
->get_JUnknown_Function ())
1281 // We use three heuristics above to recognize this special case.
1282 // Once the original problem with bci == -1 is fixed, we don't
1283 // need it any more.
1284 name
= dbe_sprintf (GTXT ("<Function %s: HotSpot-compiled leaf instructions>"),
1286 else if (addr
== (uint64_t) - 3)
1287 name
= dbe_sprintf (GTXT ("%s <Java native method>"), fname
);
1290 char buf
[64], *typetag
= NTXT (""), *alloc_typetag
= NULL
;
1293 if (func
!= dbeSession
->get_JUnknown_Function ())
1295 if (addr
<= 0xFFFFFFFFU
)
1296 snprintf (buf
, sizeof (buf
), " + 0x%08X", (unsigned int) addr
);
1298 snprintf (buf
, sizeof (buf
), " + 0x%016llX",
1299 (unsigned long long) addr
);
1304 switch ((long int) addr
)
1307 subname
= GTXT ("agent error");
1310 subname
= GTXT ("GC active");
1313 subname
= GTXT ("unknown non-Java frame");
1316 subname
= GTXT ("unwalkable non-Java frame");
1319 subname
= GTXT ("unknown Java frame");
1322 subname
= GTXT ("unwalkable Java frame");
1325 subname
= GTXT ("unknown thread state");
1328 subname
= GTXT ("thread in exit");
1331 subname
= GTXT ("deopt in process ticks");
1334 subname
= GTXT ("safepoint synchronizing ticks");
1337 subname
= GTXT ("unexpected error");
1340 snprintf (buf
, sizeof (buf
), "<%s (%d)>", subname
, (int) addr
);
1343 if (flags
& PCTrgtFlag
)
1344 // annotate synthetic instruction
1345 sb
.append ('*'); // special distinguishing marker
1347 DbeLine
*dbeline
= mapPCtoLine (NULL
);
1349 if (dbeline
&& dbeline
->lineno
> 0)
1350 str
= strrchr (dbeline
->get_name (nfmt
), ',');
1353 if (strlen (typetag
) > 0)
1354 { // include padding for alignment
1359 while (sb
.length () < 40);
1360 sb
.append (typetag
);
1361 delete alloc_typetag
;
1363 if (inlinedInd
>= 0)
1364 add_inlined_info (&sb
);
1365 name
= sb
.toString ();
1371 DbeInstr::mapPCtoLine (SourceFile
*sf
)
1373 if (inlinedInd
== -1)
1376 for (int i
= 0; i
< func
->inlinedSubrCnt
; i
++)
1378 InlinedSubr
*p
= func
->inlinedSubr
+ i
;
1381 if (addr
< p
->low_pc
)
1383 if (p
->contains (addr
))
1391 if (inlinedInd
>= 0)
1393 DbeLine
*dl
= func
->inlinedSubr
[inlinedInd
].dbeLine
;
1394 return dl
->sourceFile
->find_dbeline (func
, dl
->lineno
);
1396 return func
->mapPCtoLine (addr
, sf
);
1400 DbeInstr::add_inlined_info (StringBuilder
*sb
)
1406 while (sb
->length () < 40);
1407 sb
->append (NTXT ("<-- "));
1409 InlinedSubr
*last
= NULL
;
1410 for (int i
= inlinedInd
; i
< func
->inlinedSubrCnt
; i
++)
1412 InlinedSubr
*p
= func
->inlinedSubr
+ i
;
1413 if (p
->level
== 0 && i
> inlinedInd
)
1415 if (!p
->contains (addr
))
1421 sb
->append (last
->fname
);
1424 DbeLine
*dl
= p
->dbeLine
;
1425 sb
->appendf (NTXT ("%s:%lld <-- "), get_basename (dl
->sourceFile
->get_name ()), (long long) dl
->lineno
);
1433 sb
->append (last
->fname
);
1437 DbeLine
*dl
= func
->mapPCtoLine (addr
, NULL
);
1438 sb
->appendf ("%s:%lld ", get_basename (dl
->sourceFile
->get_name ()),
1439 (long long) dl
->lineno
);
1443 DbeInstr::get_descriptor ()
1445 char *typetag
= NTXT ("");
1446 if ((flags
& PCTrgtFlag
) == 0) // not synthetic instruction
1447 { // use memop descriptor, if available
1448 Module
*mod
= func
->module
;
1449 if (mod
->hwcprof
&& mod
->infoList
)
1452 inst_info_t
*info
= NULL
;
1453 Vec_loop (inst_info_t
*, mod
->infoList
, i
, info
)
1455 if (info
->offset
== func
->img_offset
+ addr
) break;
1460 datatype_t
*dtype
= NULL
;
1461 Vec_loop (datatype_t
*, mod
->datatypes
, t
, dtype
)
1463 if (dtype
->datatype_id
== info
->memop
->datatype_id
)
1466 if (dtype
&& dtype
->dobj
)
1467 typetag
= dtype
->dobj
->get_name ();
1471 return dbe_strdup (typetag
);
1475 DbeInstr::get_size ()
1477 // Function *func = (Function*)dbeSession->get_hobj( pc );
1478 // Module *mod = func ? func->module : NULL;
1479 // return mod ? mod->instrSize( func->img_offset + addr ) : 0;
1484 DbeInstr::get_addr ()
1486 return func
->get_addr () + addr
;
1490 DbeInstr::convertto (Type type
, Histable
*obj
)
1492 Histable
*res
= NULL
;
1493 SourceFile
*source
= (SourceFile
*) obj
;
1500 res
= mapPCtoLine (source
);
1503 res
= mapPCtoLine (source
);
1505 res
= ((DbeLine
*) res
)->sourceFile
;
1517 DbeEA::get_name (NameFormat
)
1521 name
= dbe_strdup (dbeSession
->localized_SP_UNKNOWN_NAME
);
1526 DbeEA::convertto (Type type
, Histable
*obj
)
1528 Histable
*res
= NULL
;
1529 assert (obj
== NULL
);
1544 DbeLine::DbeLine (Function
*_func
, SourceFile
*sf
, int _lineno
)
1549 id
= sf
->id
+ _lineno
;
1554 dbeline_func_next
= NULL
;
1555 dbeline_base
= this;
1556 current_name_format
= Histable::NA
;
1559 DbeLine::~DbeLine ()
1561 delete dbeline_func_next
;
1565 DbeLine::line_cmp (DbeLine
*dbl
)
1567 return lineno
- dbl
->lineno
;
1571 DbeLine::init_Offset (uint64_t p_offset
)
1575 if (dbeline_base
&& dbeline_base
->offset
== 0)
1576 dbeline_base
->offset
= p_offset
;
1580 DbeLine::get_name (NameFormat nfmt
)
1582 char *srcname
= NULL
, *basename
, *fname
;
1588 srcname
= sourceFile
->get_name ();
1589 basename
= get_basename (srcname
);
1590 name
= dbe_sprintf (GTXT ("line %u in \"%s\""), lineno
, basename
);
1594 if (name
&& (nfmt
== current_name_format
|| nfmt
== Histable::NA
))
1597 current_name_format
= nfmt
;
1599 fname
= func
->get_name (nfmt
);
1600 if (func
->flags
& (FUNC_FLAG_SIMULATED
| FUNC_FLAG_NO_OFFSET
))
1602 name
= dbe_strdup (fname
);
1607 srcname
= sourceFile
->get_name ();
1608 if (!srcname
|| strlen (srcname
) == 0)
1609 srcname
= func
->getDefSrcName ();
1610 basename
= get_basename (srcname
);
1614 if (sourceFile
== func
->getDefSrc ())
1615 name
= dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname
, lineno
,
1618 name
= dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""),
1619 fname
, lineno
, basename
);
1621 else if (sourceFile
== NULL
|| (sourceFile
->flags
& SOURCE_FLAG_UNKNOWN
) != 0)
1622 name
= dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"),
1625 name
= dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
1631 DbeLine::get_size ()
1637 DbeLine::get_addr ()
1639 if (func
== NULL
&& dbeline_func_next
== NULL
)
1640 return (uint64_t) 0;
1641 Function
*f
= func
? func
: dbeline_func_next
->func
;
1642 return f
->get_addr () + offset
;
1646 DbeLine::convertto (Type type
, Histable
*obj
)
1648 Histable
*res
= NULL
;
1653 Function
*f
= (Function
*) convertto (FUNCTION
, NULL
);
1655 res
= f
->find_dbeinstr (0, offset
);
1670 for (DbeLine
*dl
= dbeline_base
; dl
; dl
= dl
->dbeline_func_next
)
1672 Function
*f
= dl
->func
;
1673 not_found
= (obj
== NULL
// XXXX pass dbeview as Histable*
1674 || ((DbeView
*) obj
)->get_path_tree ()->get_func_nodeidx (f
) == 0);
1675 if (f
&& f
->def_source
== sourceFile
&& (!not_found
))
1681 if (res
== NULL
&& dbeline_func_next
)
1683 for (DbeLine
*dl
= dbeline_base
; dl
; dl
= dl
->dbeline_func_next
)
1685 Function
*f
= dl
->func
;
1686 if (f
&& f
->def_source
== sourceFile
)
1693 if (res
== NULL
&& dbeline_func_next
)
1694 res
= dbeline_func_next
->func
;
1698 res
= (include
) ? include
: sourceFile
;
1706 CStack_data::CStack_data (MetricList
*_metrics
)
1709 total
= new_cstack_item ();
1710 cstack_items
= new Vector
<CStack_item
*>;
1713 CStack_data::CStack_item::CStack_item (long n
)
1718 value
= new TValue
[n
];
1719 memset (value
, 0, sizeof (TValue
) * n
);
1722 CStack_data::CStack_item::~CStack_item ()
1728 CStack_data::CStack_item
*
1729 CStack_data::new_cstack_item ()
1731 int nmetrics
= metrics
->get_items ()->size ();
1732 CStack_item
*item
= new CStack_item (nmetrics
);
1734 // We precalculate all metrics as integer values
1735 // and convert them to appropriate types later.
1736 for (int i
= 0; i
< nmetrics
; i
++)
1737 item
->value
[i
].tag
= metrics
->get_items ()->fetch (i
)->get_vtype ();
1741 HistableFile::HistableFile ()
1747 Histable::Histable ()
1751 comparable_objs
= NULL
;
1752 phaseCompareIdx
= -1;
1755 Histable::~Histable ()
1757 delete_comparable_objs ();
1762 Histable::delete_comparable_objs ()
1764 if (comparable_objs
)
1766 Vector
<Histable
*> *v
= comparable_objs
;
1767 for (int i
= 0; i
< v
->size (); i
++)
1769 Histable
*h
= v
->fetch (i
);
1772 h
->comparable_objs
= NULL
;
1773 h
->phaseCompareIdx
= phaseCompareIdx
;
1781 Histable::update_comparable_objs ()
1783 if (phaseCompareIdx
!= ExpGroup::phaseCompareIdx
)
1785 phaseCompareIdx
= ExpGroup::phaseCompareIdx
;
1786 delete_comparable_objs ();
1791 Histable::get_comparable_objs ()
1793 return comparable_objs
;
1797 Histable::get_compare_obj ()
1799 Vector
<Histable
*> *v
= get_comparable_objs ();
1800 for (long i
= 0, sz
= VecSize (v
); i
< sz
; i
++)
1802 Histable
*h
= v
->get (i
);
1809 #define CASE_S(x) case x: return (char *) #x
1812 Histable::type_to_string ()
1814 switch (get_type ())
1820 CASE_S (LOADOBJECT
);
1826 CASE_S (SOURCEFILE
);
1827 CASE_S (EXPERIMENT
);
1832 return NTXT ("ERROR");
1836 Histable::dump_comparable_objs ()
1838 Dprintf (DEBUG_COMPARISON
,
1839 "# Histable::dump_comparable_objs type=%s(%d) 0x%lx id=%lld %s\n",
1840 type_to_string (), get_type (), (unsigned long) this, (long long) id
,
1842 for (int i
= 0, sz
= comparable_objs
? comparable_objs
->size () : 0; i
< sz
; i
++)
1844 Histable
*h
= comparable_objs
->fetch (i
);
1845 Dprintf (DEBUG_COMPARISON
, " %d type=%s(%d) 0x%lx id=%lld %s\n", i
,
1846 h
? h
->type_to_string () : "", h
? h
->get_type () : -1,
1847 (unsigned long) h
, (long long) (h
? h
->id
: 0),
1848 h
? STR (h
->get_name ()) : NTXT (""));
1856 sb
.appendf (sizeof (long) == 32
1857 ? " 0x%08lx : type=%s(%d) id=%lld %s"
1858 : " 0x%016lx : type=%s(%d) id=%lld %s",
1859 (unsigned long) this, type_to_string (), get_type (),
1860 (long long) id
, STR (get_name ()));
1861 switch (get_type ())
1865 DbeInstr
*o
= (DbeInstr
*) this;
1866 sb
.appendf (sizeof (long) == 32
1867 ? " func=0x%08lx lineno=%lld"
1868 : " func=0x%016lx lineno=%lld",
1869 (unsigned long) o
->func
, (long long) o
->lineno
);
1874 DbeLine
*o
= (DbeLine
*) this;
1875 sb
.appendf (sizeof (long) == 32
1876 ? " func=0x%08lx sourceFile=0x%08lx lineno=%lld"
1877 : " func=0x%016lx sourceFile=0x%016lx lineno=%lld",
1878 (unsigned long) o
->func
, (unsigned long) o
->sourceFile
,
1879 (long long) o
->lineno
);
1885 return sb
.toString ();