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