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
45Hist_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
54Hist_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
62long
63Hist_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
70Hist_data::HistItem *
71Hist_data::fetch (long index)
72{
73  return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;
74}
75
76int
77Hist_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
209int
210Hist_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
274int
275Hist_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
330Hist_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
384Hist_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
433void
434Hist_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
494void
495Hist_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
542void
543Hist_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
556void
557Hist_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
670Hist_data::HistItem *
671Hist_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
687Hist_data::HistItem *
688Hist_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
701Hist_data::HistItem *
702Hist_data::find_hist_item (Histable *obj)
703{
704  if (obj == NULL)
705    return NULL;
706  return hi_map->get (obj);
707}
708
709Hist_data::HistItem *
710Hist_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
726void
727Hist_data::append_hist_item (HistItem *hi)
728{
729  hist_items->append (hi);
730}
731
732bool
733Hist_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
774void
775Hist_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
810double
811Hist_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
828int
829Hist_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
870void
871Hist_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
885static void
886append_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
900void
901Hist_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
963TValue *
964Hist_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
977TValue *
978Hist_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
994TValue *
995Hist_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
1016Metric::HistMetric *
1017Hist_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
1051void
1052Hist_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
1058void
1059Hist_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
1073void
1074Hist_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
1083void
1084Metric::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
1092void
1093Metric::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
1105size_t
1106Hist_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
1114size_t
1115Hist_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
1124size_t
1125Hist_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
1133size_t
1134Hist_data::name_len (HistItem *item)
1135{
1136  char *name = item->obj->get_name ();
1137  return strlen (name);
1138}
1139
1140size_t
1141Hist_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
1156Vector<uint64_t> *
1157Hist_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
1183DbeInstr::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
1197int
1198DbeInstr::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
1267char *
1268DbeInstr::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
1371DbeLine*
1372DbeInstr::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
1400void
1401DbeInstr::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
1443char *
1444DbeInstr::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
1475int64_t
1476DbeInstr::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
1484uint64_t
1485DbeInstr::get_addr ()
1486{
1487  return func->get_addr () + addr;
1488}
1489
1490Histable *
1491DbeInstr::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
1517char *
1518DbeEA::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
1526Histable *
1527DbeEA::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
1545DbeLine::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
1560DbeLine::~DbeLine ()
1561{
1562  delete dbeline_func_next;
1563}
1564
1565int
1566DbeLine::line_cmp (DbeLine *dbl)
1567{
1568  return lineno - dbl->lineno;
1569}
1570
1571void
1572DbeLine::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
1580char *
1581DbeLine::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
1631int64_t
1632DbeLine::get_size ()
1633{
1634  return size;
1635}
1636
1637uint64_t
1638DbeLine::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
1646Histable *
1647DbeLine::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
1707CStack_data::CStack_data (MetricList *_metrics)
1708{
1709  metrics = _metrics;
1710  total = new_cstack_item ();
1711  cstack_items = new Vector<CStack_item*>;
1712}
1713
1714CStack_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
1723CStack_data::CStack_item::~CStack_item ()
1724{
1725  delete stack;
1726  delete[] value;
1727}
1728
1729CStack_data::CStack_item *
1730CStack_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
1742HistableFile::HistableFile ()
1743{
1744  dbeFile = NULL;
1745  isUsed = false;
1746}
1747
1748Histable::Histable ()
1749{
1750  name = NULL;
1751  id = 0;
1752  comparable_objs = NULL;
1753  phaseCompareIdx = -1;
1754}
1755
1756Histable::~Histable ()
1757{
1758  delete_comparable_objs ();
1759  free (name);
1760}
1761
1762void
1763Histable::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
1781void
1782Histable::update_comparable_objs ()
1783{
1784  if (phaseCompareIdx != ExpGroup::phaseCompareIdx)
1785    {
1786      phaseCompareIdx = ExpGroup::phaseCompareIdx;
1787      delete_comparable_objs ();
1788    }
1789}
1790
1791Vector<Histable*> *
1792Histable::get_comparable_objs ()
1793{
1794  return comparable_objs;
1795}
1796
1797Histable *
1798Histable::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
1812char *
1813Histable::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
1836void
1837Histable::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
1853char *
1854Histable::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