1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2 Contributed by Oracle.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
20
21 #include "config.h"
22 #include <assert.h>
23
24 #include "util.h"
25 #include "DefaultMap.h"
26 #include "DbeSession.h"
27 #include "Experiment.h"
28 #include "DataObject.h"
29 #include "Function.h"
30 #include "Hist_data.h"
31 #include "Histable.h"
32 #include "MemObject.h"
33 #include "IndexObject.h"
34 #include "MetricList.h"
35 #include "Metric.h"
36 #include "Module.h"
37 #include "LoadObject.h"
38 #include "Settings.h"
39 #include "StringBuilder.h"
40 #include "ExpGroup.h"
41 #include "PathTree.h"
42 #include "DbeView.h"
43 #include "FileData.h"
44
HistItem(long n)45 Hist_data::HistItem::HistItem (long n)
46 {
47 obj = NULL;
48 type = 0;
49 size = n;
50 value = new TValue[n];
51 memset (value, 0, sizeof (TValue) * n);
52 }
53
~HistItem()54 Hist_data::HistItem::~HistItem ()
55 {
56 for (long i = 0; i < size; i++)
57 if (value[i].tag == VT_LABEL)
58 free (value[i].l);
59 delete[] value;
60 }
61
62 long
size()63 Hist_data::size ()
64 {
65 // If the data values have not been computed, do so
66 // Return the total number of items
67 return hist_items->size ();
68 }
69
70 Hist_data::HistItem *
fetch(long index)71 Hist_data::fetch (long index)
72 {
73 return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;
74 }
75
76 int
sort_compare(HistItem * hi_1,HistItem * hi_2,Sort_type stype,long ind,Hist_data * hdata)77 Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
78 long ind, Hist_data *hdata)
79 {
80 // Sort the data depending upon order and type
81 int result = 0;
82 Histable::Type type = hi_1->obj->get_type ();
83 if (stype == ALPHA)
84 {
85 if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ
86 && type != Histable::IOACTVFD && type != Histable::IOACTFILE
87 && type != Histable::IOCALLSTACK)
88 {
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);
93 }
94 else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD
95 || type == Histable::IOACTFILE)
96 {
97 uint64_t idx1, idx2;
98 idx1 = ((FileData *) (hi_1->obj))->get_index ();
99 idx2 = ((FileData *) (hi_2->obj))->get_index ();
100 if (idx1 < idx2)
101 result = -1;
102 else if (idx1 > idx2)
103 result = 1;
104 else
105 result = 0;
106 }
107 else
108 {
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.
112 uint64_t i1, i2;
113 bool needsStringCompare = false;
114 if (type == Histable::MEMOBJ)
115 {
116 i1 = ((MemObj *) (hi_1->obj))->get_index ();
117 i2 = ((MemObj *) (hi_2->obj))->get_index ();
118 }
119 else if (type == Histable::INDEXOBJ)
120 {
121 i1 = ((IndexObject *) (hi_1->obj))->get_index ();
122 i2 = ((IndexObject *) (hi_2->obj))->get_index ();
123 needsStringCompare =
124 ((IndexObject *) (hi_1->obj))->requires_string_sort ();
125 }
126 else
127 abort ();
128 if (i1 == (uint64_t) - 2)
129 result = -1;
130 else if (i2 == (uint64_t) - 2)
131 result = 1;
132 else if (i1 == (uint64_t) - 1)
133 result = -1;
134 else if (i2 == (uint64_t) - 1)
135 result = 1;
136 else if (needsStringCompare)
137 {
138 char *nm1 = hi_1->obj->get_name ();
139 char *nm2 = hi_2->obj->get_name ();
140 if (nm1 != NULL && nm2 != NULL)
141 {
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)
146 result = 1;
147 else if (nm2_lead == '(' && nm1_lead != nm2_lead)
148 result = -1;
149 else
150 result = strcoll (nm1, nm2);
151 }
152 }
153 if (result == 0)
154 { // matches, resolve by index
155 if (i1 < i2)
156 result = -1;
157 else if (i1 > i2)
158 result = 1;
159 }
160 }
161 }
162 else if (stype == AUX)
163 {
164 switch (type)
165 {
166 case Histable::INSTR:
167 {
168 DbeInstr *instr1 = (DbeInstr*) hi_1->obj;
169 DbeInstr *instr2 = (DbeInstr*) hi_2->obj;
170 result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0;
171 break;
172 }
173 case Histable::LINE:
174 {
175 DbeLine *dbl1 = (DbeLine*) hi_1->obj;
176 DbeLine *dbl2 = (DbeLine*) hi_2->obj;
177 result = dbl1->line_cmp (dbl2);
178 }
179 break;
180 default:
181 assert (0);
182 }
183 }
184 else if (stype == VALUE)
185 {
186 Metric *m = hdata->get_metric_list ()->get (ind);
187 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
188 {
189 TValue v1, v2;
190 int first_ind = hdata->hist_metrics[ind].indFirstExp;
191 if ((m->get_visbits () & VAL_DELTA) != 0)
192 {
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);
195 }
196 else
197 {
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);
200 }
201 result = v1.compare (&v2);
202 }
203 else
204 result = hi_1->value[ind].compare (hi_2->value + ind);
205 }
206 return result;
207 }
208
209 int
sort_compare_all(const void * a,const void * b,const void * arg)210 Hist_data::sort_compare_all (const void *a, const void *b, const void *arg)
211 {
212 HistItem *hi_1 = *((HistItem **) a);
213 HistItem *hi_2 = *((HistItem **) b);
214
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)
218 result = -result;
219
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
223 if (result == 0)
224 {
225 result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL);
226 if (result == 0)
227 {
228 for (long i = 0, sz = hdata->metrics->size (); i < sz; i++)
229 {
230 Metric *m = hdata->metrics->get (i);
231 if (m->get_type () != Metric::ONAME)
232 {
233 result = sort_compare (hi_1, hi_2, VALUE, i, hdata);
234 if (result != 0)
235 {
236 if (hdata->sort_order == DESCEND)
237 result = -result;
238 break;
239 }
240 }
241 }
242 }
243 }
244
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)
248 {
249 Function *f1 = (Function*) hi_1->obj;
250 Function *f2 = (Function*) hi_2->obj;
251 if (f1->get_addr () < f2->get_addr ())
252 result = -1;
253 else if (f1->get_addr () > f2->get_addr ())
254 result = 1;
255 }
256
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,
259 if (result == 0)
260 {
261 if (hi_1->obj->id < hi_2->obj->id)
262 result = -1;
263 else if (hi_1->obj->id > hi_2->obj->id)
264 result = 1;
265 }
266
267 if (result == 0)
268 return result; // shouldn't happen in most cases; line allows for breakpoint
269 if (hdata->rev_sort)
270 result = -result;
271 return result;
272 }
273
274 int
sort_compare_dlayout(const void * a,const void * b,const void * arg)275 Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg)
276 {
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;
285
286 Hist_data *hdata = (Hist_data*) arg;
287
288 // are the two items members of the same object?
289 if (parent1 == parent2)
290 {
291 // yes
292 if (parent1)
293 {
294 // and they have real parents...
295 if (parent1->get_typename ())
296 { // element
297 // use dobj1/dobj2 offset for sorting
298 uint64_t off1 = dobj1->get_offset ();
299 uint64_t off2 = dobj2->get_offset ();
300 if (off1 < off2)
301 return -1;
302 if (off1 > off2)
303 return 1;
304 return 0;
305 }
306 }
307 }
308 else
309 { // parents differ
310 if (parent1)
311 {
312 if (parent1 == dobj2)
313 // sorting an object and its parent: parent always first
314 return 1;
315 dobj1 = parent1;
316 }
317 if (parent2)
318 {
319 if (parent2 == dobj1)
320 return -1;
321 dobj2 = parent2;
322 }
323 }
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);
328 }
329
Hist_data(MetricList * _metrics,Histable::Type _type,Hist_data::Mode _mode,bool _viewowned)330 Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type,
331 Hist_data::Mode _mode, bool _viewowned)
332 {
333 hist_items = new Vector<HistItem*>;
334 metrics = _metrics;
335 nmetrics = metrics->get_items ()->size ();
336 type = _type;
337 mode = _mode;
338 gprof_item = new_hist_item (NULL);
339 viewowned = _viewowned;
340 sort_ind = -1;
341 rev_sort = false;
342
343 Histable *tobj = new Other;
344 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
345 minimum = new_hist_item (tobj);
346
347 tobj = new Other;
348 tobj->name = dbe_strdup (NTXT (""));
349 maximum = new_hist_item (tobj);
350
351 tobj = new Other;
352 tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx"));
353 maximum_inc = new_hist_item (tobj);
354
355 tobj = new Other;
356 tobj->name = dbe_strdup (NTXT ("<Total>"));
357 total = new_hist_item (tobj);
358
359 tobj = new Other;
360 tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX"));
361 threshold = new_hist_item (tobj);
362
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++)
367 {
368 Metric::HistMetric *h = hist_metrics + i;
369 h->init ();
370 Metric *m = metrics->get (i);
371 if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO)))
372 h->indFirstExp =
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 ())
377 h->indTimeVal =
378 metrics->get_listorder (m->get_dependent_bm ()->get_cmd (),
379 m->get_subtype (), m->get_expr_spec ());
380 }
381 status = NO_DATA;
382 }
383
~Hist_data()384 Hist_data::~Hist_data ()
385 {
386 delete[] hist_metrics;
387 if (hist_items)
388 {
389 hist_items->destroy ();
390 delete hist_items;
391 hist_items = NULL;
392 }
393 if (gprof_item)
394 {
395 delete gprof_item;
396 gprof_item = NULL;
397 }
398 if (maximum)
399 {
400 delete maximum->obj;
401 delete maximum;
402 maximum = NULL;
403 }
404 if (maximum_inc)
405 {
406 delete maximum_inc->obj;
407 delete maximum_inc;
408 maximum_inc = NULL;
409 }
410 if (minimum)
411 {
412 delete minimum->obj;
413 delete minimum;
414 minimum = NULL;
415 }
416 if (total)
417 {
418 delete total->obj;
419 delete total;
420 total = NULL;
421 }
422 if (threshold)
423 {
424 delete threshold->obj;
425 delete threshold;
426 threshold = NULL;
427 }
428 delete metrics;
429 delete hi_map;
430 delete callsite_mark;
431 }
432
433 void
dump(char * msg,FILE * f)434 Hist_data::dump (char *msg, FILE *f)
435 {
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++)
439 {
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)");
444 }
445
446 fprintf (f, NTXT (" HistItem listing\n"));
447 int n = hist_items->size ();
448 for (int j = -1; j < n; j++)
449 {
450 HistItem *hi;
451 if (j < 0)
452 {
453 hi = total;
454 fprintf (f, NTXT (" total"));
455 }
456 else
457 {
458 hi = hist_items->fetch (j);
459 fprintf (f, NTXT ("%30s"), hi->obj->get_name ());
460 }
461 for (int i = 0; i < nmetrics; i++)
462 {
463 char *stmp = hi->value[i].l;
464 switch (hi->value[i].tag)
465 {
466 case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s);
467 break;
468 case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i);
469 break;
470 case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
471 break;
472 case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f);
473 break;
474 case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d);
475 break;
476 case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
477 break;
478 case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)");
479 break;
480 case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
481 break;
482 case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p);
483 break;
484 case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
485 break;
486 default: fprintf (f, NTXT (" "));
487 break;
488 }
489 }
490 fprintf (f, NTXT ("\n"));
491 }
492 }
493
494 void
sort(long ind,bool reverse)495 Hist_data::sort (long ind, bool reverse)
496 {
497 if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort)
498 // there's no change to the sorting
499 return;
500
501 if (mode == MODL)
502 {
503 sort_type = AUX;
504 sort_order = ASCEND;
505 }
506 else
507 {
508 if (ind == -1)
509 return;
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) ?
513 ASCEND : DESCEND;
514 sort_ind = ind;
515 rev_sort = reverse;
516 }
517
518 if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
519 hist_items->sort ((CompareFunc) sort_compare_dlayout, this);
520 else
521 hist_items->sort ((CompareFunc) sort_compare_all, this);
522
523 // ensure that <Total> comes first/last
524 char *tname = NTXT ("<Total>");
525 for (int i = 0; i < hist_items->size (); ++i)
526 {
527 HistItem *hi = hist_items->fetch (i);
528 char *name = hi->obj->get_name ();
529 if (name != NULL && streq (name, tname))
530 {
531 int idx0 = rev_sort ? hist_items->size () - 1 : 0;
532 if (i != idx0)
533 {
534 hist_items->remove (i);
535 hist_items->insert (idx0, hi);
536 }
537 break;
538 }
539 }
540 }
541
542 void
resort(MetricList * mlist)543 Hist_data::resort (MetricList *mlist)
544 {
545 if (mlist->get_type () != metrics->get_type ())
546 if (metrics->get_type () == MET_CALL)
547 // wrong type of list -- internal error
548 abort ();
549
550 // get the new sort order
551 int ind = mlist->get_sort_ref_index ();
552 bool reverse = mlist->get_sort_rev ();
553 sort (ind, reverse);
554 }
555
556 void
compute_minmax()557 Hist_data::compute_minmax ()
558 {
559 HistItem *hi;
560 int index;
561
562 for (int mind = 0; mind < nmetrics; mind++)
563 {
564 Metric *mtr = metrics->get_items ()->fetch (mind);
565 if (mtr->get_subtype () == Metric::STATIC)
566 continue;
567 if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
568 continue;
569 ValueTag vtype = mtr->get_vtype2 ();
570
571 switch (vtype)
572 {
573 case VT_INT:
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;
580
581 Vec_loop (HistItem *, hist_items, index, hi)
582 {
583 if (metrics->get_type () == MET_SRCDIS
584 && callsite_mark->get (hi->obj))
585 {
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
589 }
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;
594 }
595 break;
596 case VT_DOUBLE:
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)
604 {
605 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
606 {
607 if (hi->value[mind].d > maximum_inc->value[mind].d)
608 {
609 maximum_inc->value[mind].d = hi->value[mind].d;
610 maximum_inc->value[mind].sign = hi->value[mind].sign;
611 }
612 // ignore ones that has inclusive time for src/dis view
613 }
614 else
615 {
616 if (hi->value[mind].d > maximum->value[mind].d)
617 {
618 maximum->value[mind].d = hi->value[mind].d;
619 maximum->value[mind].sign = hi->value[mind].sign;
620 }
621 if (hi->value[mind].d < minimum->value[mind].d)
622 {
623 minimum->value[mind].d = hi->value[mind].d;
624 minimum->value[mind].sign = hi->value[mind].sign;
625 }
626 }
627 }
628 break;
629 case VT_LLONG:
630 case VT_ULLONG:
631 case VT_ADDRESS:
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)
639 {
640 if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
641 {
642 if (hi->value[mind].ll > maximum_inc->value[mind].ll)
643 {
644 maximum_inc->value[mind].ll = hi->value[mind].ll;
645 maximum_inc->value[mind].sign = hi->value[mind].sign;
646 }
647 // ignore ones that has inclusive time for src/dis view
648 }
649 else
650 {
651 if (hi->value[mind].ll > maximum->value[mind].ll)
652 {
653 maximum->value[mind].ll = hi->value[mind].ll;
654 maximum->value[mind].sign = hi->value[mind].sign;
655 }
656 if (hi->value[mind].ll < minimum->value[mind].ll)
657 {
658 minimum->value[mind].ll = hi->value[mind].ll;
659 minimum->value[mind].sign = hi->value[mind].sign;
660 }
661 }
662 }
663 break;
664 default:
665 break;
666 }
667 }
668 }
669
670 Hist_data::HistItem *
new_hist_item(Histable * obj)671 Hist_data::new_hist_item (Histable *obj)
672 {
673 long sz = get_metric_list ()->size ();
674 HistItem *hi = new HistItem (sz);
675 hi->obj = obj;
676
677 // We precalculate all metrics as integer values
678 // and convert them to appropriate types later.
679 for (long i = 0; i < sz; i++)
680 {
681 hi->value[i].tag = VT_INT;
682 hi->value[i].i = 0;
683 }
684 return hi;
685 }
686
687 Hist_data::HistItem *
new_hist_item(Histable * obj,int itype,TValue * value)688 Hist_data::new_hist_item (Histable *obj, int itype, TValue *value)
689 {
690 long sz = get_metric_list ()->size ();
691 HistItem *hi = new HistItem (sz);
692 hi->obj = obj;
693 hi->type = itype;
694 if (value)
695 for (long i = 0; i < sz; i++)
696 hi->value[i] = value[i];
697
698 return hi;
699 }
700
701 Hist_data::HistItem *
find_hist_item(Histable * obj)702 Hist_data::find_hist_item (Histable *obj)
703 {
704 if (obj == NULL)
705 return NULL;
706 return hi_map->get (obj);
707 }
708
709 Hist_data::HistItem *
append_hist_item(Histable * obj)710 Hist_data::append_hist_item (Histable *obj)
711 {
712 if (obj == NULL)
713 return NULL;
714 HistItem *hi = hi_map->get (obj);
715 if (hi == NULL)
716 {
717 hi = new_hist_item (obj);
718 hist_items->append (hi);
719 hi_map->put (obj, hi);
720 }
721 if (status == NO_DATA)
722 status = SUCCESS;
723 return hi;
724 }
725
726 void
append_hist_item(HistItem * hi)727 Hist_data::append_hist_item (HistItem *hi)
728 {
729 hist_items->append (hi);
730 }
731
732 bool
above_threshold(HistItem * hi)733 Hist_data::above_threshold (HistItem* hi)
734 {
735 bool mark = false;
736 int index;
737 Metric *mitem;
738
739 Vec_loop (Metric*, metrics->get_items (), index, mitem)
740 {
741 if (mitem->get_subtype () == Metric::STATIC)
742 continue;
743 switch (hi->value[index].tag)
744 {
745 case VT_DOUBLE:
746 if (hi->value[index].d > threshold->value[index].d)
747 mark = true;
748 break;
749 case VT_INT:
750 if (hi->value[index].i > threshold->value[index].i)
751 mark = true;
752 break;
753 case VT_LLONG:
754 if (hi->value[index].ll > threshold->value[index].ll)
755 mark = true;
756 break;
757 case VT_ULLONG:
758 if (hi->value[index].ull > threshold->value[index].ull)
759 mark = true;
760 break;
761 // ignoring the following cases (why?)
762 case VT_SHORT:
763 case VT_FLOAT:
764 case VT_HRTIME:
765 case VT_LABEL:
766 case VT_ADDRESS:
767 case VT_OFFSET:
768 break;
769 }
770 }
771 return mark;
772 }
773
774 void
set_threshold(double proportion)775 Hist_data::set_threshold (double proportion)
776 {
777 int index;
778 Metric *mitem;
779 Vec_loop (Metric*, metrics->get_items (), index, mitem)
780 {
781 TValue *thresh = &threshold->value[index];
782 TValue *mtotal = &total->value[index];
783 thresh->tag = mitem->get_vtype ();
784
785 if (mitem->get_subtype () == Metric::STATIC)
786 continue;
787 switch (thresh->tag)
788 {
789 case VT_INT:
790 thresh->i = (int) (proportion * (double) mtotal->i);
791 break;
792 case VT_DOUBLE:
793 thresh->d = proportion * mtotal->d;
794 break;
795 case VT_LLONG:
796 case VT_ULLONG:
797 thresh->ull = (unsigned long long) (proportion * (double) mtotal->ll);
798 break;
799 case VT_SHORT:
800 case VT_FLOAT:
801 case VT_HRTIME:
802 case VT_LABEL:
803 case VT_ADDRESS:
804 case VT_OFFSET:
805 break;
806 }
807 }
808 }
809
810 double
get_percentage(double value,int mindex)811 Hist_data::get_percentage (double value, int mindex)
812 {
813 double total_value;
814 if (value == 0.0)
815 return 0.0;
816
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 ();
820
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)
824 return 0.0;
825 return value / total_value;
826 }
827
828 int
print_label(FILE * out_file,Metric::HistMetric * hist_metric,int space)829 Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric,
830 int space)
831 {
832 int name_offset = 0;
833 StringBuilder sb, sb1, sb2, sb3;
834 if (space > 0)
835 {
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 (""));
841 }
842 for (int i = 0; i < nmetrics; i++)
843 {
844 Metric *m = metrics->get (i);
845 Metric::HistMetric *hm = &hist_metric[i];
846 int len = hm->width;
847 char *fmt = NTXT ("%-*s");
848 if ((i > 0) && (m->get_type () == Metric::ONAME))
849 {
850 name_offset = sb1.length ();
851 fmt = NTXT (" %-*s");
852 len--;
853 }
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);
858 }
859 sb.trim ();
860 if (sb.length () != 0)
861 {
862 sb.toFileLn (out_file);
863 }
864 sb1.toFileLn (out_file);
865 sb2.toFileLn (out_file);
866 sb3.toFileLn (out_file);
867 return name_offset;
868 }
869
870 void
print_content(FILE * out_file,Metric::HistMetric * hist_metric,int limit)871 Hist_data::print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit)
872 {
873 StringBuilder sb;
874 int cnt = VecSize (hist_items);
875 if (cnt > limit && limit > 0)
876 cnt = limit;
877 for (int i = 0; i < cnt; i++)
878 {
879 sb.setLength (0);
880 print_row (&sb, i, hist_metric, NTXT (" "));
881 sb.toFileLn (out_file);
882 }
883 }
884
885 static void
append_str(StringBuilder * sb,char * s,size_t len,int vis_bits)886 append_str (StringBuilder *sb, char *s, size_t len, int vis_bits)
887 {
888 if ((vis_bits & VAL_RATIO) != 0)
889 {
890 if (*s != 'N') // Nan
891 sb->appendf (NTXT ("x "));
892 else
893 sb->appendf (NTXT (" "));
894 sb->appendf (NTXT ("%*s"), (int) (len - 2), s);
895 }
896 else
897 sb->appendf (NTXT ("%*s"), (int) len, s);
898 }
899
900 void
print_row(StringBuilder * sb,int row,Metric::HistMetric * hmp,const char * mark)901 Hist_data::print_row (StringBuilder *sb, int row, Metric::HistMetric *hmp,
902 const char *mark)
903 {
904 TValue res;
905 char buf[256];
906 // Print only a list of user's metrics. ( nmetrics <= mlist->size() )
907 for (long i = 0; i < nmetrics; i++)
908 {
909 // Print only a list of user's metrics.
910 Metric *m = metrics->get (i);
911 if (!m->is_any_visible ())
912 continue;
913 Metric::HistMetric *hm = hmp + i;
914 int len = sb->length ();
915 if (m->is_tvisible ())
916 {
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 ());
920 }
921 if (m->is_visible ())
922 {
923 TValue *v = get_value (&res, i, row);
924 char *s = v->to_str (buf, sizeof (buf));
925 if (m->get_type () == BaseMetric::ONAME)
926 {
927 sb->append (mark);
928 if (i + 1 == nmetrics)
929 sb->appendf (NTXT ("%s"), s);
930 else
931 sb->appendf (NTXT ("%-*s "), (int) hm->maxvalue_width, s);
932 continue;
933 }
934 else
935 {
936 if (len != sb->length ())
937 sb->append (' ');
938 append_str (sb, s, hm->maxvalue_width, m->get_visbits ());
939 }
940 }
941 if (m->is_pvisible ())
942 {
943 if (len != sb->length ())
944 sb->append (' ');
945 long met_ind = i;
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);
950 if (percent == 0.0)
951 // adjust to change format from xx.yy%
952 sb->append (NTXT (" 0. "));
953 else
954 // adjust format below to change format from xx.yy%
955 sb->appendf (NTXT ("%6.2f"), (100.0 * percent));
956 }
957 len = sb->length () - len;
958 if (hm->width > len && i + 1 != nmetrics)
959 sb->appendf (NTXT ("%*s"), (int) (hm->width - len), NTXT (" "));
960 }
961 }
962
963 TValue *
get_real_value(TValue * res,int met_index,int row)964 Hist_data::get_real_value (TValue *res, int met_index, int row)
965 {
966 HistItem *hi = hist_items->get (row);
967 Metric *m = metrics->get (met_index);
968 if (m->get_type () == BaseMetric::ONAME)
969 {
970 res->l = dbe_strdup (hi->obj->get_name ());
971 res->tag = VT_LABEL;
972 return res;
973 }
974 return hi->value + met_index;
975 }
976
977 TValue *
get_value(TValue * res,int met_index,int row)978 Hist_data::get_value (TValue *res, int met_index, int row)
979 {
980 HistItem *hi = hist_items->get (row);
981 Metric *m = metrics->get (met_index);
982 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
983 {
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);
987 else
988 res->make_ratio (hi->value + met_index, hi->value + ind);
989 return res;
990 }
991 return get_real_value (res, met_index, row);
992 }
993
994 TValue *
get_value(TValue * res,int met_index,HistItem * hi)995 Hist_data::get_value (TValue *res, int met_index, HistItem *hi)
996 {
997 Metric *m = metrics->get (met_index);
998 if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
999 {
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);
1003 else
1004 res->make_ratio (hi->value + met_index, hi->value + ind);
1005 return res;
1006 }
1007 if (m->get_type () == BaseMetric::ONAME)
1008 {
1009 res->l = dbe_strdup (hi->obj->get_name ());
1010 res->tag = VT_LABEL;
1011 return res;
1012 }
1013 return hi->value + met_index;
1014 }
1015
1016 Metric::HistMetric *
get_histmetrics()1017 Hist_data::get_histmetrics ()
1018 {
1019 // find the width for each column.
1020 for (long i = 0, sz = metrics->size (); i < sz; i++)
1021 {
1022 Metric *m = metrics->get (i);
1023 Metric::HistMetric *hm = hist_metrics + i;
1024 if (m->is_value_visible ())
1025 {
1026 TValue res;
1027 for (long i1 = 0, sz1 = VecSize(hist_items); i1 < sz1; i1++)
1028 {
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;
1033 }
1034 if ((m->get_visbits () & VAL_RATIO) != 0)
1035 hm->maxvalue_width += 2; // "x "
1036 }
1037 }
1038
1039 for (long i = 0, sz = metrics->size (); i < sz; i++)
1040 {
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);
1047 }
1048 return hist_metrics;
1049 }
1050
1051 void
update_total(Hist_data::HistItem * new_total)1052 Hist_data::update_total (Hist_data::HistItem *new_total)
1053 {
1054 for (long i = 0, sz = metrics->size (); i < sz; i++)
1055 total->value[i] = new_total->value[i];
1056 }
1057
1058 void
update_max(Metric::HistMetric * hm_tmp)1059 Hist_data::update_max (Metric::HistMetric *hm_tmp)
1060 {
1061 Metric::HistMetric *hms = get_histmetrics ();
1062 for (int i = 0; i < nmetrics; i++)
1063 {
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;
1070 }
1071 }
1072
1073 void
update_legend_width(Metric::HistMetric * hm_tmp)1074 Hist_data::update_legend_width (Metric::HistMetric *hm_tmp)
1075 {
1076 for (int i = 0; i < nmetrics; i++)
1077 {
1078 Metric *m = metrics->get (i);
1079 m->legend_width (hm_tmp + i, 2);
1080 }
1081 }
1082
1083 void
update_max(Metric::HistMetric * hm)1084 Metric::HistMetric::update_max (Metric::HistMetric *hm)
1085 {
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;
1090 }
1091
1092 void
init()1093 Metric::HistMetric::init ()
1094 {
1095 width = 0;
1096 maxvalue_width = 0;
1097 maxtime_width = 0;
1098 legend1[0] = 0;
1099 legend2[0] = 0;
1100 legend3[0] = 0;
1101 indFirstExp = -1;
1102 indTimeVal = -1;
1103 }
1104
1105 size_t
value_maxlen(int mindex)1106 Hist_data::value_maxlen (int mindex)
1107 {
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;
1112 }
1113
1114 size_t
time_len(TValue * value,int clock)1115 Hist_data::time_len (TValue *value, int clock)
1116 {
1117 TValue tm_value;
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 ();
1122 }
1123
1124 size_t
time_maxlen(int mindex,int clock)1125 Hist_data::time_maxlen (int mindex, int clock)
1126 {
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;
1131 }
1132
1133 size_t
name_len(HistItem * item)1134 Hist_data::name_len (HistItem *item)
1135 {
1136 char *name = item->obj->get_name ();
1137 return strlen (name);
1138 }
1139
1140 size_t
name_maxlen()1141 Hist_data::name_maxlen ()
1142 {
1143 size_t res = 0;
1144 for (long i = 0; i < size (); i++)
1145 {
1146 HistItem *hi = fetch (i);
1147 size_t len = name_len (hi);
1148 if (res < len)
1149 res = len;
1150 }
1151 return res;
1152 }
1153
1154 // Returns vector of object ids for the vector of selections
1155 // returns NULL if no valid selections
1156 Vector<uint64_t> *
get_object_indices(Vector<int> * selections)1157 Hist_data::get_object_indices (Vector<int> *selections)
1158 {
1159 // if no selections, return NULL
1160 if (selections == NULL || selections->size () == 0)
1161 return NULL;
1162
1163 Vector<uint64_t> *indices = new Vector<uint64_t>;
1164 for (long i = 0, sz = selections->size (); i < sz; i++)
1165 {
1166 int sel = selections->get (i);
1167 HistItem *hi = hist_items->get (sel);
1168 if (hi == NULL || hi->obj == NULL)
1169 continue;
1170 Vector<Histable*> *v = hi->obj->get_comparable_objs ();
1171 for (long i1 = 0, sz1 = v ? v->size () : 0; i1 < sz1; i1++)
1172 {
1173 Histable *h1 = v->get (i1);
1174 if (h1 && (indices->find_r (h1->id) < 0))
1175 indices->append (h1->id);
1176 }
1177 if (indices->find_r (hi->obj->id) < 0)
1178 indices->append (hi->obj->id);
1179 }
1180 return indices;
1181 }
1182
DbeInstr(uint64_t _id,int _flags,Function * _func,uint64_t _addr)1183 DbeInstr::DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr)
1184 {
1185 id = _id;
1186 flags = _flags;
1187 addr = _addr;
1188 func = _func;
1189 img_offset = addr + func->img_offset;
1190 lineno = -1;
1191 size = 0;
1192 current_name_format = NA;
1193 isUsed = false;
1194 inlinedInd = -1;
1195 }
1196
1197 int
pc_cmp(DbeInstr * instr2)1198 DbeInstr::pc_cmp (DbeInstr *instr2)
1199 {
1200 int result = 0;
1201 if (instr2 == NULL)
1202 return -1;
1203
1204 // All PC's with the Line flag go to the
1205 // end of the list. See Module::init_index()
1206 if (flags & PCLineFlag)
1207 {
1208 if (instr2->flags & PCLineFlag)
1209 {
1210 if (addr < instr2->addr)
1211 result = -1;
1212 else if (addr > instr2->addr)
1213 result = 1;
1214 else
1215 result = 0;
1216 }
1217 else
1218 result = 1;
1219 }
1220 else if (instr2->flags & PCLineFlag)
1221 result = -1;
1222 else if (func == instr2->func)
1223 {
1224 if (size == 0)
1225 {
1226 if (addr < instr2->addr)
1227 result = -1;
1228 else if (addr == instr2->addr)
1229 result = 0;
1230 else if (addr >= instr2->addr + instr2->size)
1231 result = 1;
1232 else
1233 result = 0;
1234 }
1235 else if (instr2->size == 0)
1236 {
1237 if (addr > instr2->addr)
1238 result = 1;
1239 else if (addr + size <= instr2->addr)
1240 result = -1;
1241 else
1242 result = 0;
1243 }
1244 else if (addr < instr2->addr)
1245 result = -1;
1246 else if (addr > instr2->addr)
1247 result = 1;
1248 else
1249 result = 0;
1250
1251 if (result == 0)
1252 {
1253 if (flags & PCTrgtFlag)
1254 {
1255 if (!(instr2->flags & PCTrgtFlag))
1256 result = -1;
1257 }
1258 else if (instr2->flags & PCTrgtFlag)
1259 result = 1;
1260 }
1261 }
1262 else
1263 result = func->func_cmp (instr2->func);
1264 return result;
1265 }
1266
1267 char *
get_name(NameFormat nfmt)1268 DbeInstr::get_name (NameFormat nfmt)
1269 {
1270 if (name && (nfmt == current_name_format || nfmt == Histable::NA))
1271 return name;
1272
1273 free (name);
1274 name = NULL;
1275 current_name_format = nfmt;
1276 char *fname = func->get_name (nfmt);
1277
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>"),
1286 fname);
1287 else if (addr == (uint64_t) - 3)
1288 name = dbe_sprintf (GTXT ("%s <Java native method>"), fname);
1289 else
1290 {
1291 char buf[64], *typetag = NTXT (""), *alloc_typetag = NULL;
1292 StringBuilder sb;
1293 sb.append (fname);
1294 if (func != dbeSession->get_JUnknown_Function ())
1295 {
1296 if (addr <= 0xFFFFFFFFU)
1297 snprintf (buf, sizeof (buf), " + 0x%08X", (unsigned int) addr);
1298 else
1299 snprintf (buf, sizeof (buf), " + 0x%016llX",
1300 (unsigned long long) addr);
1301 }
1302 else
1303 {
1304 char *subname;
1305 switch ((long int) addr)
1306 {
1307 case -1:
1308 subname = GTXT ("agent error");
1309 break;
1310 case -2:
1311 subname = GTXT ("GC active");
1312 break;
1313 case -3:
1314 subname = GTXT ("unknown non-Java frame");
1315 break;
1316 case -4:
1317 subname = GTXT ("unwalkable non-Java frame");
1318 break;
1319 case -5:
1320 subname = GTXT ("unknown Java frame");
1321 break;
1322 case -6:
1323 subname = GTXT ("unwalkable Java frame");
1324 break;
1325 case -7:
1326 subname = GTXT ("unknown thread state");
1327 break;
1328 case -8:
1329 subname = GTXT ("thread in exit");
1330 break;
1331 case -9:
1332 subname = GTXT ("deopt in process ticks");
1333 break;
1334 case -10:
1335 subname = GTXT ("safepoint synchronizing ticks");
1336 break;
1337 default:
1338 subname = GTXT ("unexpected error");
1339 break;
1340 }
1341 snprintf (buf, sizeof (buf), "<%s (%d)>", subname, (int) addr);
1342 }
1343 sb.append (buf);
1344 if (flags & PCTrgtFlag)
1345 // annotate synthetic instruction
1346 sb.append ('*'); // special distinguishing marker
1347
1348 DbeLine *dbeline = mapPCtoLine (NULL);
1349 char *str = NULL;
1350 if (dbeline && dbeline->lineno > 0)
1351 str = strrchr (dbeline->get_name (nfmt), ',');
1352 if (str)
1353 sb.append (str);
1354 if (strlen (typetag) > 0)
1355 { // include padding for alignment
1356 do
1357 {
1358 sb.append (' ');
1359 }
1360 while (sb.length () < 40);
1361 sb.append (typetag);
1362 delete alloc_typetag;
1363 }
1364 if (inlinedInd >= 0)
1365 add_inlined_info (&sb);
1366 name = sb.toString ();
1367 }
1368 return name;
1369 }
1370
1371 DbeLine*
mapPCtoLine(SourceFile * sf)1372 DbeInstr::mapPCtoLine (SourceFile *sf)
1373 {
1374 if (inlinedInd == -1)
1375 {
1376 inlinedInd = -2;
1377 for (int i = 0; i < func->inlinedSubrCnt; i++)
1378 {
1379 InlinedSubr *p = func->inlinedSubr + i;
1380 if (p->level == 0)
1381 {
1382 if (addr < p->low_pc)
1383 break;
1384 if (p->contains (addr))
1385 {
1386 inlinedInd = i;
1387 break;
1388 }
1389 }
1390 }
1391 }
1392 if (inlinedInd >= 0)
1393 {
1394 DbeLine *dl = func->inlinedSubr[inlinedInd].dbeLine;
1395 return dl->sourceFile->find_dbeline (func, dl->lineno);
1396 }
1397 return func->mapPCtoLine (addr, sf);
1398 }
1399
1400 void
add_inlined_info(StringBuilder * sb)1401 DbeInstr::add_inlined_info (StringBuilder *sb)
1402 {
1403 do
1404 {
1405 sb->append (' ');
1406 }
1407 while (sb->length () < 40);
1408 sb->append (NTXT ("<-- "));
1409
1410 InlinedSubr *last = NULL;
1411 for (int i = inlinedInd; i < func->inlinedSubrCnt; i++)
1412 {
1413 InlinedSubr *p = func->inlinedSubr + i;
1414 if (p->level == 0 && i > inlinedInd)
1415 break;
1416 if (!p->contains (addr))
1417 continue;
1418 if (last)
1419 {
1420 if (last->fname)
1421 {
1422 sb->append (last->fname);
1423 sb->append (' ');
1424 }
1425 DbeLine *dl = p->dbeLine;
1426 sb->appendf (NTXT ("%s:%lld <-- "), get_basename (dl->sourceFile->get_name ()), (long long) dl->lineno);
1427 }
1428 last = p;
1429 }
1430 if (last)
1431 {
1432 if (last->fname)
1433 {
1434 sb->append (last->fname);
1435 sb->append (' ');
1436 }
1437 }
1438 DbeLine *dl = func->mapPCtoLine (addr, NULL);
1439 sb->appendf ("%s:%lld ", get_basename (dl->sourceFile->get_name ()),
1440 (long long) dl->lineno);
1441 }
1442
1443 char *
get_descriptor()1444 DbeInstr::get_descriptor ()
1445 {
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)
1451 {
1452 long i;
1453 inst_info_t *info = NULL;
1454 Vec_loop (inst_info_t*, mod->infoList, i, info)
1455 {
1456 if (info->offset == func->img_offset + addr) break;
1457 }
1458 if (info)
1459 {
1460 long t;
1461 datatype_t *dtype = NULL;
1462 Vec_loop (datatype_t*, mod->datatypes, t, dtype)
1463 {
1464 if (dtype->datatype_id == info->memop->datatype_id)
1465 break;
1466 }
1467 if (dtype && dtype->dobj)
1468 typetag = dtype->dobj->get_name ();
1469 }
1470 }
1471 }
1472 return dbe_strdup (typetag);
1473 }
1474
1475 int64_t
get_size()1476 DbeInstr::get_size ()
1477 {
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;
1481 return size;
1482 }
1483
1484 uint64_t
get_addr()1485 DbeInstr::get_addr ()
1486 {
1487 return func->get_addr () + addr;
1488 }
1489
1490 Histable *
convertto(Type type,Histable * obj)1491 DbeInstr::convertto (Type type, Histable *obj)
1492 {
1493 Histable *res = NULL;
1494 SourceFile *source = (SourceFile*) obj;
1495 switch (type)
1496 {
1497 case INSTR:
1498 res = this;
1499 break;
1500 case LINE:
1501 res = mapPCtoLine (source);
1502 break;
1503 case SOURCEFILE:
1504 res = mapPCtoLine (source);
1505 if (res)
1506 res = ((DbeLine*) res)->sourceFile;
1507 break;
1508 case FUNCTION:
1509 res = func;
1510 break;
1511 default:
1512 assert (0);
1513 }
1514 return res;
1515 }
1516
1517 char *
get_name(NameFormat)1518 DbeEA::get_name (NameFormat)
1519 {
1520 if (name == NULL)
1521 // generate one
1522 name = dbe_strdup (dbeSession->localized_SP_UNKNOWN_NAME);
1523 return name;
1524 }
1525
1526 Histable *
convertto(Type type,Histable * obj)1527 DbeEA::convertto (Type type, Histable *obj)
1528 {
1529 Histable *res = NULL;
1530 assert (obj == NULL);
1531 switch (type)
1532 {
1533 case EADDR:
1534 res = this;
1535 break;
1536 case DOBJECT:
1537 res = dobj;
1538 break;
1539 default:
1540 assert (0);
1541 }
1542 return res;
1543 }
1544
DbeLine(Function * _func,SourceFile * sf,int _lineno)1545 DbeLine::DbeLine (Function *_func, SourceFile *sf, int _lineno)
1546 {
1547 func = _func;
1548 lineno = _lineno;
1549 sourceFile = sf;
1550 id = sf->id + _lineno;
1551 offset = 0;
1552 size = 0;
1553 flags = 0;
1554 include = NULL;
1555 dbeline_func_next = NULL;
1556 dbeline_base = this;
1557 current_name_format = Histable::NA;
1558 }
1559
~DbeLine()1560 DbeLine::~DbeLine ()
1561 {
1562 delete dbeline_func_next;
1563 }
1564
1565 int
line_cmp(DbeLine * dbl)1566 DbeLine::line_cmp (DbeLine *dbl)
1567 {
1568 return lineno - dbl->lineno;
1569 }
1570
1571 void
init_Offset(uint64_t p_offset)1572 DbeLine::init_Offset (uint64_t p_offset)
1573 {
1574 if (offset == 0)
1575 offset = p_offset;
1576 if (dbeline_base && dbeline_base->offset == 0)
1577 dbeline_base->offset = p_offset;
1578 }
1579
1580 char *
get_name(NameFormat nfmt)1581 DbeLine::get_name (NameFormat nfmt)
1582 {
1583 char *srcname = NULL, *basename, *fname;
1584
1585 if (func == NULL)
1586 {
1587 if (name)
1588 return name;
1589 srcname = sourceFile->get_name ();
1590 basename = get_basename (srcname);
1591 name = dbe_sprintf (GTXT ("line %u in \"%s\""), lineno, basename);
1592 return name;
1593 }
1594
1595 if (name && (nfmt == current_name_format || nfmt == Histable::NA))
1596 return name;
1597
1598 current_name_format = nfmt;
1599 free (name);
1600 fname = func->get_name (nfmt);
1601 if (func->flags & (FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET))
1602 {
1603 name = dbe_strdup (fname);
1604 return name;
1605 }
1606
1607 if (sourceFile)
1608 srcname = sourceFile->get_name ();
1609 if (!srcname || strlen (srcname) == 0)
1610 srcname = func->getDefSrcName ();
1611 basename = get_basename (srcname);
1612
1613 if (lineno != 0)
1614 {
1615 if (sourceFile == func->getDefSrc ())
1616 name = dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname, lineno,
1617 basename);
1618 else
1619 name = dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""),
1620 fname, lineno, basename);
1621 }
1622 else if (sourceFile == NULL || (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
1623 name = dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"),
1624 fname);
1625 else
1626 name = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
1627 fname, basename);
1628 return name;
1629 }
1630
1631 int64_t
get_size()1632 DbeLine::get_size ()
1633 {
1634 return size;
1635 }
1636
1637 uint64_t
get_addr()1638 DbeLine::get_addr ()
1639 {
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;
1644 }
1645
1646 Histable *
convertto(Type type,Histable * obj)1647 DbeLine::convertto (Type type, Histable *obj)
1648 {
1649 Histable *res = NULL;
1650 switch (type)
1651 {
1652 case INSTR:
1653 {
1654 Function *f = (Function *) convertto (FUNCTION, NULL);
1655 if (f)
1656 res = f->find_dbeinstr (0, offset);
1657 break;
1658 }
1659 case LINE:
1660 res = dbeline_base;
1661 break;
1662 case FUNCTION:
1663 if (func)
1664 {
1665 res = func;
1666 break;
1667 }
1668 else
1669 {
1670 int not_found = 1;
1671 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
1672 {
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))
1677 {
1678 res = f;
1679 break;
1680 }
1681 }
1682 if (res == NULL && dbeline_func_next)
1683 {
1684 for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
1685 {
1686 Function *f = dl->func;
1687 if (f && f->def_source == sourceFile)
1688 {
1689 res = f;
1690 break;
1691 }
1692 }
1693 }
1694 if (res == NULL && dbeline_func_next)
1695 res = dbeline_func_next->func;
1696 }
1697 break;
1698 case SOURCEFILE:
1699 res = (include) ? include : sourceFile;
1700 break;
1701 default:
1702 assert (0);
1703 }
1704 return res;
1705 }
1706
CStack_data(MetricList * _metrics)1707 CStack_data::CStack_data (MetricList *_metrics)
1708 {
1709 metrics = _metrics;
1710 total = new_cstack_item ();
1711 cstack_items = new Vector<CStack_item*>;
1712 }
1713
CStack_item(long n)1714 CStack_data::CStack_item::CStack_item (long n)
1715 {
1716 stack = NULL;
1717 count = 0;
1718 val = 0;
1719 value = new TValue[n];
1720 memset (value, 0, sizeof (TValue) * n);
1721 }
1722
~CStack_item()1723 CStack_data::CStack_item::~CStack_item ()
1724 {
1725 delete stack;
1726 delete[] value;
1727 }
1728
1729 CStack_data::CStack_item *
new_cstack_item()1730 CStack_data::new_cstack_item ()
1731 {
1732 int nmetrics = metrics->get_items ()->size ();
1733 CStack_item *item = new CStack_item (nmetrics);
1734
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 ();
1739 return item;
1740 }
1741
HistableFile()1742 HistableFile::HistableFile ()
1743 {
1744 dbeFile = NULL;
1745 isUsed = false;
1746 }
1747
Histable()1748 Histable::Histable ()
1749 {
1750 name = NULL;
1751 id = 0;
1752 comparable_objs = NULL;
1753 phaseCompareIdx = -1;
1754 }
1755
~Histable()1756 Histable::~Histable ()
1757 {
1758 delete_comparable_objs ();
1759 free (name);
1760 }
1761
1762 void
delete_comparable_objs()1763 Histable::delete_comparable_objs ()
1764 {
1765 if (comparable_objs)
1766 {
1767 Vector<Histable*> *v = comparable_objs;
1768 for (int i = 0; i < v->size (); i++)
1769 {
1770 Histable *h = v->fetch (i);
1771 if (h)
1772 {
1773 h->comparable_objs = NULL;
1774 h->phaseCompareIdx = phaseCompareIdx;
1775 }
1776 }
1777 delete v;
1778 }
1779 }
1780
1781 void
update_comparable_objs()1782 Histable::update_comparable_objs ()
1783 {
1784 if (phaseCompareIdx != ExpGroup::phaseCompareIdx)
1785 {
1786 phaseCompareIdx = ExpGroup::phaseCompareIdx;
1787 delete_comparable_objs ();
1788 }
1789 }
1790
1791 Vector<Histable*> *
get_comparable_objs()1792 Histable::get_comparable_objs ()
1793 {
1794 return comparable_objs;
1795 }
1796
1797 Histable *
get_compare_obj()1798 Histable::get_compare_obj ()
1799 {
1800 Vector<Histable*> *v = get_comparable_objs ();
1801 for (long i = 0, sz = VecSize (v); i < sz; i++)
1802 {
1803 Histable *h = v->get (i);
1804 if (h)
1805 return h;
1806 }
1807 return this;
1808 }
1809
1810 #define CASE_S(x) case x: return (char *) #x
1811
1812 char *
type_to_string()1813 Histable::type_to_string ()
1814 {
1815 switch (get_type ())
1816 {
1817 CASE_S (INSTR);
1818 CASE_S (LINE);
1819 CASE_S (FUNCTION);
1820 CASE_S (MODULE);
1821 CASE_S (LOADOBJECT);
1822 CASE_S (EADDR);
1823 CASE_S (MEMOBJ);
1824 CASE_S (INDEXOBJ);
1825 CASE_S (PAGE);
1826 CASE_S (DOBJECT);
1827 CASE_S (SOURCEFILE);
1828 CASE_S (EXPERIMENT);
1829 CASE_S (OTHER);
1830 default:
1831 break;
1832 }
1833 return NTXT ("ERROR");
1834 }
1835
1836 void
dump_comparable_objs()1837 Histable::dump_comparable_objs ()
1838 {
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,
1842 STR (get_name ()));
1843 for (int i = 0, sz = comparable_objs ? comparable_objs->size () : 0; i < sz; i++)
1844 {
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 (""));
1850 }
1851 }
1852
1853 char *
dump()1854 Histable::dump ()
1855 {
1856 StringBuilder sb;
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 ())
1863 {
1864 case INSTR:
1865 {
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);
1871 break;
1872 }
1873 case LINE:
1874 {
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);
1881 break;
1882 }
1883 default:
1884 break;
1885 }
1886 return sb.toString ();
1887 }
1888