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 "util.h"
23#include "Application.h"
24#include "DbeSession.h"
25#include "CallStack.h"
26#include "Command.h"
27#include "DataObject.h"
28#include "Experiment.h"
29#include "ExpGroup.h"
30#include "FilterExp.h"
31#include "FilterSet.h"
32#include "Function.h"
33#include "DbeView.h"
34#include "PathTree.h"
35#include "DataSpace.h"
36#include "MemorySpace.h"
37#include "IOActivity.h"
38#include "HeapActivity.h"
39#include "Print.h"
40#include "MetricList.h"
41#include "Module.h"
42#include "Filter.h"
43#include "LoadObject.h"
44#include "dbe_types.h"
45#include "StringBuilder.h"
46
47DbeView::DbeView (Application *_app, Settings *_settings, int _vindex)
48{
49  init ();
50  phaseIdx = 0;
51  settings = new Settings (_settings);
52  ptree = new PathTree (this);
53  dspace = new DataSpace (this);
54  memspaces = new Vector<MemorySpace*>;
55  iospace = new IOActivity (this);
56  heapspace = new HeapActivity (this);
57  filters = new Vector<FilterSet*>;
58  lo_expands = new Vector<enum LibExpand>;
59  cur_filter_str = NULL;
60  prev_filter_str = NULL;
61  cur_filter_expr = NULL;
62  filter_active = false;
63  noParFilter = false;
64  dataViews = new Vector<Vector<DataView*>*>;
65  names_src[0] = NULL;
66  names_src[1] = NULL;
67  names_src[2] = NULL;
68  names_dis[0] = NULL;
69  names_dis[1] = NULL;
70  names_dis[2] = NULL;
71  marks = new Vector<int>;
72  marks2dsrc = new Vector<int_pair_t>;
73  marks2dsrc_inc = new Vector<int_pair_t>;
74  marks2ddis = new Vector<int_pair_t>;
75  marks2ddis_inc = new Vector<int_pair_t>;
76  app = _app;
77
78  // set the view's index
79  vindex = _vindex;
80
81  // clear the precomputed data
82  func_data = NULL;
83  line_data = NULL;
84  pc_data = NULL;
85  src_data = NULL;
86  dis_data = NULL;
87  fitem_data = NULL;
88  callers = NULL;
89  callees = NULL;
90  dobj_data = NULL;
91  dlay_data = NULL;
92  iofile_data = NULL;
93  iovfd_data = NULL;
94  iocs_data = NULL;
95  heapcs_data = NULL;
96
97  // and clear the selections
98  sel_obj = NULL;
99  sel_dobj = NULL;
100  sel_binctx = NULL;
101  func_scope = false;
102  lastSelInstr = NULL;
103  lastSelFunc = NULL;
104
105  // Initialize index spaces
106  int sz = settings->get_IndxTabState ()->size ();
107  indxspaces = new Vector<PathTree*>(sz);
108  indx_data = new Vector<Hist_data*>(sz);
109  sel_idxobj = new Vector<Histable*>(sz);
110  for (int i = 0; i < sz; i++)
111    {
112      PathTree *is = new PathTree (this, i);
113      indxspaces->store (i, is);
114      indx_data->store (i, NULL);
115      sel_idxobj->store (i, NULL);
116    }
117  reset ();
118
119  lobjectsNoJava = NULL;
120
121  // set lo_expands for already existing LoadObjects
122  int idx;
123  LoadObject *lo;
124  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
125  Vec_loop (LoadObject*, lobjs, idx, lo)
126  {
127    lo_expands->store (lo->seg_idx, LIBEX_SHOW);
128    set_lo_expand (lo->seg_idx, LIBEX_SHOW);
129  }
130  delete lobjs;
131}
132
133DbeView::DbeView (DbeView *dbev, int _vindex)
134{
135  init ();
136  phaseIdx = 0;
137  settings = new Settings (dbev->settings);
138  ptree = new PathTree (this);
139  dspace = new DataSpace (this);
140  iospace = new IOActivity (this);
141  heapspace = new HeapActivity (this);
142  memspaces = new Vector<MemorySpace*>;
143  filters = new Vector<FilterSet*>;
144  lo_expands = new Vector<enum LibExpand>;
145  cur_filter_str = NULL;
146  prev_filter_str = NULL;
147  cur_filter_expr = NULL;
148  noParFilter = false;
149  dataViews = new Vector<Vector<DataView*>*>;
150  names_src[0] = NULL;
151  names_src[1] = NULL;
152  names_src[2] = NULL;
153  names_dis[0] = NULL;
154  names_dis[1] = NULL;
155  names_dis[2] = NULL;
156  marks = new Vector<int>;
157  marks2dsrc = new Vector<int_pair_t>;
158  marks2dsrc_inc = new Vector<int_pair_t>;
159  marks2ddis = new Vector<int_pair_t>;
160  marks2ddis_inc = new Vector<int_pair_t>;
161  app = dbev->app;
162
163  // set the view's index
164  vindex = _vindex;
165
166  // clear the precomputed data
167  func_data = NULL;
168  line_data = NULL;
169  pc_data = NULL;
170  src_data = NULL;
171  dis_data = NULL;
172  fitem_data = NULL;
173  callers = NULL;
174  callees = NULL;
175  dobj_data = NULL;
176  dlay_data = NULL;
177  iofile_data = NULL;
178  iovfd_data = NULL;
179  iocs_data = NULL;
180  heapcs_data = NULL;
181
182  // and clear the selections
183  sel_obj = NULL;
184  sel_dobj = NULL;
185  sel_binctx = NULL;
186  func_scope = false;
187  lastSelInstr = NULL;
188  lastSelFunc = NULL;
189
190  // create the vector of IndexSpaces
191  int sz = dbev->indxspaces->size ();
192  indxspaces = new Vector<PathTree*>(sz);
193  indx_data = new Vector<Hist_data*>(sz);
194  sel_idxobj = new Vector<Histable*>(sz);
195  for (int i = 0; i < sz; i++)
196    {
197      PathTree *is = new PathTree (this, i);
198      indxspaces->store (i, is);
199      indx_data->store (i, NULL);
200      sel_idxobj->store (i, NULL);
201    }
202  reset ();
203
204  // now copy the relevant information from the original view
205  for (int i = 0; i < dbeSession->nexps (); i++)
206    add_experiment (i, dbev->get_exp_enable (i));
207  update_advanced_filter ();
208  delete lo_expands;
209  lo_expands = dbev->lo_expands->copy ();
210  lobjectsNoJava = NULL;
211}
212
213DbeView::~DbeView ()
214{
215  delete settings;
216  delete ptree;
217  delete dspace;
218  delete iospace;
219  delete heapspace;
220  Destroy (memspaces);
221  Destroy (filters);
222  delete lo_expands;
223  free (cur_filter_str);
224  free (prev_filter_str);
225  delete cur_filter_expr;
226  for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
227    {
228      Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
229      Destroy (expDataViewList);
230    }
231  delete dataViews;
232  delete reg_metrics;
233  metrics_lists->destroy ();
234  delete metrics_lists;
235  metrics_ref_lists->destroy ();
236  delete metrics_ref_lists;
237  delete derived_metrics;
238  delete marks;
239  delete marks2dsrc;
240  delete marks2dsrc_inc;
241  delete marks2ddis;
242  delete marks2ddis_inc;
243
244  // Index spaces
245  indxspaces->destroy ();
246  delete indxspaces;
247
248  indx_data->destroy ();
249  delete indx_data;
250  delete sel_idxobj;
251  delete lobjectsNoJava;
252}
253
254void
255DbeView::init ()
256{
257  phaseIdx = 0;
258  reg_metrics = new Vector<BaseMetric*>;
259  metrics_lists = new Vector<MetricList*>;
260  metrics_ref_lists = new Vector<MetricList*>;
261  for (int i = 0; i <= MET_HEAP; i++)
262    {
263      metrics_lists->append (NULL);
264      metrics_ref_lists->append (NULL);
265    }
266  derived_metrics = new DerivedMetrics;
267  derived_metrics->add_definition (GTXT ("CPI"), GTXT ("Cycles Per Instruction"), GTXT ("cycles/insts"));
268  derived_metrics->add_definition (GTXT ("IPC"), GTXT ("Instructions Per Cycle"), GTXT ("insts/cycles"));
269  derived_metrics->add_definition (GTXT ("K_CPI"), GTXT ("Kernel Cycles Per Instruction"), GTXT ("K_cycles/K_insts"));
270  derived_metrics->add_definition (GTXT ("K_IPC"), GTXT ("Kernel Instructions Per Cycle"), GTXT ("K_insts/K_cycles"));
271}
272
273bool
274DbeView::set_libexpand (char *liblist, enum LibExpand flag)
275{
276  bool changed = settings->set_libexpand (liblist, flag, false);
277  // Show/hide performance optimization:
278  // No need to call update_lo_expand for every library because dbev->set_libexpand()
279  // is called from a loop in Dbe.cc SetLoadObjectState for every load object.
280  // It is sufficient to call update_lo_expand() just once at the end of the loop.
281  //  At all other places such as er_print.cc which calls specific set_libexpand()
282  //  explicitly call update_lo_expands();
283  return changed;
284}
285
286bool
287DbeView::set_libdefaults ()
288{
289  bool changed = settings->set_libdefaults ();
290  if (changed == true)
291    update_lo_expands ();
292  return changed;
293}
294
295void
296DbeView::update_lo_expands ()
297{
298  int index;
299  LoadObject *lo;
300
301  // search all load objects
302  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
303  Vec_loop (LoadObject*, lobjs, index, lo)
304  {
305    // now search the settings list for this one
306    enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
307    set_lo_expand (lo->seg_idx, flag);
308  }
309  delete lobjs;
310}
311
312enum LibExpand
313DbeView::get_lo_expand (int idx)
314{
315  if (idx < lo_expands->size ())
316    return lo_expands->get (idx);
317  return LIBEX_SHOW;
318}
319
320bool
321DbeView::set_lo_expand (int idx, enum LibExpand flag)
322{
323  // LIBRARY_VISIBILITY
324  if (flag == LIBEX_HIDE)
325    {
326      resetShowAll ();
327      dbeSession->set_lib_visibility_used ();
328    }
329  // if no change
330  if (idx < lo_expands->size () && flag == get_lo_expand (idx))
331    return false;
332  setShowHideChanged (); // this is necessary if called from er_print
333
334  // change the flag
335  lo_expands->store (idx, flag);
336
337  // and reset the data
338  fflush (stderr);
339  purge_events ();
340  reset_data (true);
341  return true;
342}
343
344void
345DbeView::reset ()
346{
347  phaseIdx++;
348
349  // reset all the per-experiment arrays
350  filters->destroy ();
351  lo_expands->reset ();
352  free (cur_filter_str);
353  cur_filter_str = NULL;
354  free (prev_filter_str);
355  prev_filter_str = NULL;
356  delete cur_filter_expr;
357  cur_filter_expr = NULL;
358  noParFilter = false;
359  for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
360    {
361      Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
362      if (expDataViewList)
363	expDataViewList->destroy ();
364    }
365  dataViews->destroy ();
366  reset_metrics ();
367
368  // now reset any cached data
369  reset_data (true);
370  ompDisMode = false;
371  showAll = true;
372  showHideChanged = false;
373  newViewMode = false;
374}
375
376void
377DbeView::reset_data (bool all)
378{
379  // clear the precomputed data
380  if (func_data != NULL)
381    {
382      delete func_data;
383      func_data = NULL;
384    }
385  if (line_data != NULL)
386    {
387      delete line_data;
388      line_data = NULL;
389    }
390  if (pc_data != NULL)
391    {
392      delete pc_data;
393      pc_data = NULL;
394    }
395  if (src_data != NULL)
396    {
397      delete src_data;
398      src_data = NULL;
399    }
400  if (dis_data != NULL)
401    {
402      delete dis_data;
403      dis_data = NULL;
404    }
405  if (fitem_data != NULL)
406    {
407      delete fitem_data;
408      fitem_data = NULL;
409    }
410  if (callers != NULL)
411    {
412      delete callers;
413      callers = NULL;
414    }
415  if (callees != NULL)
416    {
417      delete callees;
418      callees = NULL;
419    }
420  if (dobj_data != NULL)
421    {
422      delete dobj_data;
423      dobj_data = NULL;
424    }
425  if (dlay_data != NULL)
426    {
427      delete dlay_data;
428      dlay_data = NULL;
429    }
430  if (iofile_data != NULL)
431    {
432      delete iofile_data;
433      iofile_data = NULL;
434    }
435  if (iovfd_data != NULL)
436    {
437      delete iovfd_data;
438      iovfd_data = NULL;
439    }
440  if (iocs_data != NULL)
441    {
442      delete iocs_data;
443      iocs_data = NULL;
444    }
445  if (heapcs_data != NULL)
446    {
447      delete heapcs_data;
448      heapcs_data = NULL;
449    }
450
451  // and reset the selections
452  if (all)
453    {
454      sel_obj = NULL;
455      sel_dobj = NULL;
456      lastSelInstr = NULL;
457      lastSelFunc = NULL;
458      // Set selected object <Total> if possible
459      Function * ft = dbeSession->get_Total_Function ();
460      set_sel_obj (ft);
461    }
462  sel_binctx = NULL;
463
464  dspace->reset ();
465  iospace->reset ();
466  heapspace->reset ();
467
468  // loop over MemorySpaces, resetting each one
469  for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
470    {
471      MemorySpace *ms = memspaces->get (i);
472      ms->reset ();
473    }
474
475  // loop over IndexSpaces, resetting cached data
476  indx_data->destroy ();
477  for (long i = 0, sz = VecSize (indxspaces); i < sz; i++)
478    {
479      indx_data->store (i, NULL);
480      sel_idxobj->store (i, NULL);
481    }
482}
483
484Vector<BaseMetric*> *
485DbeView::get_all_reg_metrics ()
486{
487  Vector<BaseMetric*> *mlist = dbeSession->get_all_reg_metrics ();
488  return mlist;
489}
490
491BaseMetric *
492DbeView::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
493{
494  BaseMetric *bm = dbeSession->register_metric_expr (type, cmd, expr_spec);
495  return bm;
496}
497
498Metric *
499DbeView::get_compare_metric (Metric *mtr, int groupNum)
500{
501  if (groupNum == 0 || !mtr->comparable ())
502    return new Metric (*mtr);
503  ExpGroup *gr = dbeSession->expGroups->get (groupNum - 1);
504  char buf[128];
505  snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
506  BaseMetric *bm = register_metric_expr (mtr->get_type (), mtr->get_cmd (), buf);
507  Metric *m = new Metric (bm, mtr->get_subtype ());
508  m->set_raw_visbits (mtr->get_visbits ());
509  if (m->legend == NULL)
510    m->legend = dbe_strdup (get_basename (gr->name));
511  return m;
512}
513
514MetricList *
515DbeView::get_metric_ref (MetricType mtype)
516{
517  if (metrics_ref_lists->fetch (MET_COMMON) == NULL)
518    {
519      Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
520      metrics_ref_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
521      metrics_ref_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
522      metrics_ref_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
523      metrics_ref_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
524      metrics_ref_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
525      metrics_ref_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
526      metrics_ref_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
527      metrics_ref_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
528      metrics_ref_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
529      delete base_metrics;
530    }
531  return metrics_ref_lists->fetch (mtype);
532}
533
534// logically, the function list must be created first, and it
535//	will create the other two;
536MetricList *
537DbeView::get_metric_list (MetricType mtype)
538{
539  if (metrics_lists->fetch (MET_COMMON) == NULL)
540    {
541      Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
542      metrics_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
543      metrics_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
544      metrics_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
545      metrics_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
546      metrics_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
547      metrics_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
548      metrics_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
549      metrics_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
550      metrics_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
551      delete base_metrics;
552
553      // set the defaults
554      if (settings->str_dmetrics == NULL)
555	settings->str_dmetrics = strdup (Command::DEFAULT_METRICS);
556      char *status = setMetrics (settings->str_dmetrics, true);
557      if (status != NULL)
558	{
559	  fprintf (stderr, "XXX setMetrics(\"%s\") failed: %s\n", settings->str_dmetrics, status);
560	  abort ();
561	}
562
563      // set the default sort
564      setSort (settings->str_dsort, MET_NORMAL, true);
565    }
566  return metrics_lists->fetch (mtype);
567}
568
569MetricList *
570DbeView::get_metric_list (int dsptype, int subtype)
571{
572  MetricList *mlist;
573  switch (dsptype)
574    {
575    case DSP_DISASM:
576    case DSP_SOURCE:
577    case DSP_SOURCE_DISASM:
578      mlist = get_metric_list (MET_COMMON);
579      mlist = new MetricList (mlist);
580      if (subtype != 0)
581	{
582	  for (long i = 0, sz = mlist->size (); i < sz; i++)
583	    {
584	      Metric *m = mlist->get (i);
585	      if (m->comparable ())
586		{
587		  Metric *m1 = get_compare_metric (m, subtype);
588		  mlist->put (i, m1);
589		  delete m;
590		}
591	    }
592	}
593      break;
594    default:
595      mlist = get_metric_list (MET_NORMAL);
596      mlist = new MetricList (mlist);
597      break;
598    }
599  return mlist;
600}
601
602void
603DbeView::reset_metrics ()
604{
605  for (int i = 0, sz = metrics_lists->size (); i < sz; i++)
606    {
607      delete metrics_lists->fetch (i);
608      metrics_lists->store (i, NULL);
609    }
610  for (int i = 0, sz = metrics_ref_lists->size (); i < sz; i++)
611    {
612      delete metrics_ref_lists->fetch (i);
613      metrics_ref_lists->store (i, NULL);
614    }
615}
616
617bool
618DbeView::comparingExperiments ()
619{
620  if (dbeSession->expGroups->size () <= 1)
621    return false;
622  return 0 != (settings->get_compare_mode () & (CMP_DELTA | CMP_ENABLE | CMP_RATIO));
623}
624
625void
626DbeView::set_compare_mode (int mode)
627{
628  if (mode == get_compare_mode ())
629    return;
630  settings->set_compare_mode (mode);
631  if (comparingExperiments ())
632    {
633      Vector<BaseMetric*> *bm_list = dbeSession->get_base_reg_metrics ();
634      for (int i = 0, sz = bm_list->size (); i < sz; i++)
635	{
636	  BaseMetric *m = bm_list->fetch (i);
637	  if (m->get_expr_spec () || !m->comparable ())
638	    continue;
639	  for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
640	    {
641	      ExpGroup *gr = dbeSession->expGroups->fetch (i1);
642	      char buf[128];
643	      snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
644	      register_metric_expr (m->get_type (), m->get_cmd (), buf);
645	    }
646	}
647    }
648  MetricList *mlist = get_metric_list (MET_NORMAL);
649  MetricList *gmlist = get_metric_list (MET_CALL);
650  MetricList *dmlist = get_metric_list (MET_DATA);
651  MetricList *imlist = get_metric_list (MET_INDX);
652  if (comparingExperiments ())
653    {
654      add_compare_metrics (mlist);
655      add_compare_metrics (gmlist);
656      add_compare_metrics (dmlist);
657      add_compare_metrics (imlist);
658    }
659  else
660    {
661      remove_compare_metrics (mlist);
662      remove_compare_metrics (gmlist);
663      remove_compare_metrics (dmlist);
664      remove_compare_metrics (imlist);
665    }
666}
667
668void
669DbeView::ifreq (FILE *outfile)
670{
671  if (!dbeSession->is_ifreq_available ())
672    {
673      fprintf (outfile, GTXT ("No instruction frequency data available\n"));
674      return;
675    }
676  for (int index = 0; index < filters->size (); index++)
677    {
678      Experiment *exp = dbeSession->get_exp (index);
679      if (exp->broken || !get_exp_enable (index) || !exp->ifreqavail)
680	continue;
681
682      // this experiment has the data; print it
683      fprintf (outfile,
684	       GTXT ("Instruction frequency data from experiment %s\n\n"),
685	       exp->get_expt_name ());
686      fprintf (outfile, NTXT ("%s"), pr_mesgs (exp->fetch_ifreq (), "", ""));
687    }
688}
689
690// When adding multiple sub-experiments of an experiment, it is
691// not necessary to do the following every-time. It is sufficient to call reset_metrics()
692// and call get_metric_ref() and get_metric_list() in the end after all the sub-experiments
693// have been added
694void
695DbeView::add_experiment_epilogue ()
696{
697  bool flag_LIBEX_HIDE = false;
698  bool flag_ShowHideChanged = false;
699  Vector<LoadObject*> *lobjs = dbeSession->get_LoadObjects ();
700  for (long i = lo_expands->size (), sz = lobjs ? lobjs->size () : 0; i < sz; i++)
701    {
702      flag_ShowHideChanged = true;
703      LoadObject *lo = lobjs->get (i);
704      enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
705      if (flag == LIBEX_HIDE)
706	flag_LIBEX_HIDE = true;
707      lo_expands->store (lo->seg_idx, flag);
708    }
709  if (flag_LIBEX_HIDE)
710    {
711      resetShowAll ();
712      dbeSession->set_lib_visibility_used ();
713    }
714  if (flag_ShowHideChanged)
715    {
716      setShowHideChanged (); // this is necessary if called from er_print
717      purge_events ();
718      reset_data (true);
719    }
720  reset_metrics ();
721  (void) get_metric_ref (MET_NORMAL);
722  (void) get_metric_ref (MET_CALL);
723  (void) get_metric_ref (MET_CALL_AGR);
724  (void) get_metric_ref (MET_DATA);
725  (void) get_metric_ref (MET_INDX);
726  (void) get_metric_ref (MET_IO);
727  (void) get_metric_ref (MET_HEAP);
728  (void) get_metric_list (MET_NORMAL);
729  (void) get_metric_list (MET_CALL);
730  (void) get_metric_list (MET_CALL_AGR);
731  (void) get_metric_list (MET_DATA);
732  (void) get_metric_list (MET_INDX);
733  (void) get_metric_list (MET_IO);
734  (void) get_metric_list (MET_HEAP);
735}
736
737// When adding multiple sub-experiments of an experiment, avoid invoking the steps in
738// add_experiment_epilogue() every time and instead call it separately in the end
739// after all sub-experiments have been added
740void
741DbeView::add_subexperiment (int index, bool enabled)
742{
743  // phaseIdx doesn't change, PathTree can handle adding
744  // new experiments without reset
745
746  // Set up the FilterSet for the experiments
747  Experiment *exp = dbeSession->get_exp (index);
748  FilterSet *filterset = new FilterSet (this, exp);
749  filterset->set_enabled (enabled);
750  filters->store (index, filterset);
751
752  assert (index == dataViews->size ());
753  Vector<DataView*> *expDataViewList = new Vector<DataView*>;
754  for (int data_id = 0; data_id < DATA_LAST; ++data_id)
755    expDataViewList->append (NULL); //experiment data_id's are not known yet
756  dataViews->store (index, expDataViewList);
757}
758
759void
760DbeView::add_experiment (int index, bool enabled)
761{
762  // phaseIdx doesn't change, PathTree can handle adding
763  // new experiments without reset
764
765  // delete any cached data
766  reset_data (true);
767
768  // Set up the FilterSet for the experiments
769  Experiment *exp = dbeSession->get_exp (index);
770  FilterSet *filterset = new FilterSet (this, exp);
771  filterset->set_enabled (enabled);
772  filters->store (index, filterset);
773
774  assert (index == dataViews->size ());
775  Vector<DataView*> *expDataViewList = new Vector<DataView*>;
776  for (int data_id = 0; data_id < DATA_LAST; ++data_id)
777    expDataViewList->append (NULL); //experiment data_id's are not known yet
778  dataViews->store (index, expDataViewList);
779
780  reset_metrics ();
781  (void) get_metric_ref (MET_NORMAL);
782  (void) get_metric_ref (MET_CALL);
783  (void) get_metric_ref (MET_CALL_AGR);
784  (void) get_metric_ref (MET_DATA);
785  (void) get_metric_ref (MET_INDX);
786  (void) get_metric_ref (MET_IO);
787  (void) get_metric_ref (MET_HEAP);
788  (void) get_metric_list (MET_NORMAL);
789  (void) get_metric_list (MET_CALL);
790  (void) get_metric_list (MET_CALL_AGR);
791  (void) get_metric_list (MET_DATA);
792  (void) get_metric_list (MET_INDX);
793  (void) get_metric_list (MET_IO);
794  (void) get_metric_list (MET_HEAP);
795}
796
797void
798DbeView::drop_experiment (int index)
799{
800  phaseIdx++;
801  filters->remove (index);
802
803  // reset any cached data
804  reset_data (true);
805
806  Vector<DataView*> *expDataViewList = dataViews->remove (index);
807  if (expDataViewList)
808    {
809      expDataViewList->destroy ();
810      delete expDataViewList;
811    }
812}
813
814bool
815DbeView::get_exp_enable (int n)
816{
817  return filters ? filters->fetch (n)->get_enabled () : true;
818}
819
820void
821DbeView::set_exp_enable (int n, bool e)
822{
823  FilterSet *fs = filters->fetch (n);
824  if (fs->get_enabled () != e)
825    {
826      fs->set_enabled (e);
827      purge_events (n);
828      phaseIdx++;
829    }
830}
831
832void
833DbeView::reset_metric_list (MetricList *mlist, int cmp_mode)
834{
835  MetricType mtype = mlist->get_type ();
836  switch (mtype)
837    {
838    case MET_NORMAL:
839    case MET_COMMON:
840      delete metrics_lists->fetch (MET_COMMON);
841      metrics_lists->store (MET_COMMON, new MetricList (mlist));
842      remove_compare_metrics (metrics_lists->fetch (MET_COMMON));
843      break;
844      // ignoring the following cases (why?)
845    case MET_SRCDIS:
846    case MET_CALL:
847    case MET_DATA:
848    case MET_INDX:
849    case MET_CALL_AGR:
850    case MET_IO:
851    case MET_HEAP:
852      break;
853    }
854
855  if (cmp_mode != -1)
856    {
857      settings->set_compare_mode (cmp_mode);
858      if (comparingExperiments ())
859	add_compare_metrics (mlist);
860    }
861
862  switch (mtype)
863    {
864    case MET_NORMAL:
865      delete metrics_lists->fetch (mtype);
866      metrics_lists->store (mtype, mlist);
867      // fall through to next case
868    case MET_COMMON:
869      metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
870      metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
871      metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
872      remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
873      metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
874      metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
875      metrics_lists->fetch (MET_IO)->set_metrics (mlist);
876      metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
877      break;
878    case MET_CALL_AGR:
879      delete metrics_lists->fetch (MET_CALL_AGR);
880      metrics_lists->store (MET_CALL_AGR, mlist);
881      remove_compare_metrics (mlist);
882      break;
883    case MET_SRCDIS:
884    case MET_CALL:
885    case MET_DATA:
886    case MET_INDX:
887    case MET_IO:
888    case MET_HEAP:
889      delete metrics_lists->fetch (mtype);
890      metrics_lists->store (mtype, mlist);
891      break;
892    default:
893      abort ();
894    }
895  reset_data (false);
896}
897
898void
899DbeView::add_compare_metrics (MetricList *mlist)
900{
901  if (mlist == NULL || !comparingExperiments ())
902    return;
903  int sort_ref_index = mlist->get_sort_ref_index ();
904  Vector<Metric*> *items = mlist->get_items ();
905  Vector<Metric*> *newItems = new Vector<Metric*>();
906  int mode = get_compare_mode ();
907  int cmp_vbits = 0;
908  if ((mode & CMP_DELTA) != 0)
909    cmp_vbits = VAL_DELTA;
910  else if ((mode & CMP_RATIO) != 0)
911    cmp_vbits = VAL_RATIO;
912  for (long i = 0, sz = items->size (); i < sz; i++)
913    {
914      Metric *mtr = items->get (i);
915      if (sort_ref_index == i)
916	mlist->set_sort_ref_index (newItems->size ());
917      int vbits = mtr->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
918      mtr->set_raw_visbits (vbits);
919      if (!mtr->comparable ())
920	{
921	  newItems->append (mtr);
922	  continue;
923	}
924      if (mtr->get_expr_spec ())
925	{
926	  if (strcmp (mtr->get_expr_spec (), NTXT ("EXPGRID==1")) != 0)
927	    {
928	      if ((cmp_vbits & VAL_RATIO) != 0)
929		// for ratios, make sure VAL_TIMEVAL is off and VAL_VALUE is on
930		mtr->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
931	      else
932		{
933		  int ind = mlist->get_listorder (mtr->get_cmd (), mtr->get_subtype (), NTXT ("EXPGRID==1"));
934		  if (ind >= 0)
935		    // take VAL_VALUE and VAL_TIMEVAL from base experiment
936		    mtr->set_raw_visbits (cmp_vbits
937					  | (vbits & ~(VAL_VALUE | VAL_TIMEVAL))
938					  | (mlist->get (ind)->get_visbits ()
939					     & (VAL_VALUE | VAL_TIMEVAL)));
940		  else
941		    mtr->set_raw_visbits (cmp_vbits | vbits);
942		}
943	    }
944	  newItems->append (mtr);
945	  continue;
946	}
947      for (long i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
948	{
949	  Metric *m = get_compare_metric (mtr, i1 + 1);
950	  switch (m->get_vtype ())
951	    {
952	    case VT_LABEL:
953	    case VT_ADDRESS:
954	    case VT_OFFSET:
955	      m->set_raw_visbits (vbits);
956	      break;
957	    default:
958	      if (i1 == 0)
959		m->set_raw_visbits (vbits);
960	      else if (cmp_vbits == VAL_RATIO
961		       && ((vbits & (VAL_VALUE | VAL_TIMEVAL))
962			   == (VAL_VALUE | VAL_TIMEVAL)))
963		// make ratios for VAL_VALUE only
964		m->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
965	      else
966		m->set_raw_visbits (vbits | cmp_vbits);
967	      break;
968	    }
969	  newItems->append (m);
970	}
971    }
972  items->reset ();
973  items->addAll (newItems);
974  delete newItems;
975  phaseIdx++;
976  reset_data (false);
977}
978
979MetricList *
980DbeView::get_compare_mlist (MetricList *met_list, int grInd)
981{
982  MetricList *mlist = new MetricList (met_list->get_type ());
983  mlist->set_sort_ref_index (met_list->get_sort_ref_index ());
984  mlist->set_sort_rev (met_list->get_sort_rev ());
985
986  Vector<Metric*> *items_old = met_list->get_items ();
987  for (int i = 0, sz = items_old->size (); i < sz; i++)
988    {
989      Metric *m = get_compare_metric (items_old->get (i), grInd + 1);
990      mlist->append (m);
991    }
992  return mlist;
993}
994
995void
996DbeView::remove_compare_metrics (MetricList *mlist)
997{
998  Vector<Metric*> *items = mlist->get_items ();
999  Vector<Metric*> *items_old = items->copy ();
1000  items->reset ();
1001  int sort_index = mlist->get_sort_ref_index ();
1002  mlist->set_sort_ref_index (0);
1003  for (int i = 0, sz = items_old->size (); i < sz; i++)
1004    {
1005      Metric *m = items_old->fetch (i);
1006      if (m->get_expr_spec () == NULL)
1007	{
1008	  // this is a 'non-compare' metric; add it
1009	  items->append (m);
1010	  if (sort_index == i)
1011	    mlist->set_sort_ref_index (items->size () - 1);
1012	  continue;
1013	}
1014      // is the 'non-compare' version of the metric already in the list?
1015      int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype ());
1016      if (ind == -1)
1017	{
1018	  // not in the list; add it
1019	  BaseMetric *bm = dbeSession->find_metric (m->get_type (), m->get_cmd (), NULL);
1020	  Metric *new_met = new Metric (bm, m->get_subtype ());
1021	  new_met->set_raw_visbits (m->get_visbits () & ~(CMP_DELTA | CMP_RATIO));
1022	  items->append (new_met);
1023	  if (sort_index == i)
1024	    mlist->set_sort_ref_index (items->size () - 1);
1025	}
1026      delete m;
1027    }
1028  delete items_old;
1029  reset_data (false);
1030}
1031
1032// setMetrics -- set the metric list according to specification
1033//	The previous sort is preserved, if possible
1034//	Otherwise, the default sort setting is used
1035//	Returns NULL if OK, or an error string if not
1036//YXXX only MET_NORMAL appears to be used... code could be simplified
1037char *
1038DbeView::setMetrics (char *mspec, bool fromRcFile)
1039{
1040  char *ret;
1041  MetricType mtype = MET_NORMAL;
1042  // note that setting the default is done here, while all else is in MetricList
1043  if (mspec == NULL) abort ();
1044  if (strcasecmp (mspec, Command::DEFAULT_CMD) == 0)
1045    {
1046      mspec = settings->get_default_metrics ();
1047      fromRcFile = true;
1048    }
1049  MetricList *mlist = get_metric_list (mtype);
1050  mlist = new MetricList (mlist);
1051  ret = mlist->set_metrics (mspec, fromRcFile, derived_metrics);
1052  if (ret == NULL)
1053    {
1054      switch (mtype)
1055	{
1056	case MET_NORMAL:
1057	case MET_COMMON:
1058	  delete metrics_lists->fetch (MET_COMMON);
1059	  metrics_lists->store (MET_COMMON, new MetricList (mlist));
1060	  break;
1061	  // ignoring the following cases (why?)
1062	case MET_SRCDIS:
1063	case MET_CALL:
1064	case MET_DATA:
1065	case MET_INDX:
1066	case MET_CALL_AGR:
1067	case MET_IO:
1068	case MET_HEAP:
1069	  break;
1070	}
1071      add_compare_metrics (mlist);
1072
1073      //YXXX looks like cut/paste code here, see reset_metric_list()
1074      switch (mtype)
1075	{
1076	case MET_NORMAL:
1077	  delete metrics_lists->fetch (mtype);
1078	  metrics_lists->store (mtype, mlist);
1079	  //YXXX is lack of break intentional?  If so, add comment...
1080	case MET_COMMON:
1081	  metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
1082	  metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
1083	  metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
1084	  remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
1085	  metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
1086	  metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
1087	  metrics_lists->fetch (MET_IO)->set_metrics (mlist);
1088	  metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
1089	  break;
1090	case MET_CALL_AGR:
1091	  delete metrics_lists->fetch (MET_CALL_AGR);
1092	  metrics_lists->store (MET_CALL_AGR, mlist);
1093	  remove_compare_metrics (mlist);
1094	  break;
1095	case MET_SRCDIS:
1096	case MET_CALL:
1097	case MET_DATA:
1098	case MET_INDX:
1099	case MET_IO:
1100	case MET_HEAP:
1101	  delete metrics_lists->fetch (mtype);
1102	  metrics_lists->store (mtype, mlist);
1103	  break;
1104	default:
1105	  abort ();
1106	}
1107      reset_data (false);
1108    }
1109  else
1110    delete mlist;
1111  return ret;
1112}
1113
1114
1115// Set Sort by name (er_print)
1116char *
1117DbeView::setSort (char * sort_list, MetricType mtype, bool fromRcFile)
1118{
1119  MetricList *mlist = NULL;
1120
1121  // note that setting the default is done here, while all else is in MetricList
1122  if ((sort_list == NULL) || (strcmp (sort_list, Command::DEFAULT_CMD) == 0))
1123    {
1124      if (settings->str_dsort == NULL)
1125	settings->str_dsort = strdup (Command::DEFAULT_METRICS);
1126      sort_list = settings->get_default_sort ();
1127    }
1128  mlist = get_metric_list (mtype);
1129
1130  if (mlist == NULL)
1131    abort ();
1132
1133  // set the new sort
1134  char *ret = mlist->set_sort (sort_list, fromRcFile);
1135  if (ret != NULL)
1136    return ret;
1137
1138  // now resort all cached data
1139  resortData (mtype);
1140  return NULL;
1141}
1142
1143// Set sort from the visible index (Analyzer)
1144void
1145DbeView::setSort (int visindex, MetricType mtype, bool reverse)
1146{
1147  MetricList *mlist = get_metric_list (mtype);
1148  Vector<Metric*> *items = mlist->get_items ();
1149  if (visindex >= items->size ())
1150    return;
1151  mlist->set_sort (visindex, reverse);
1152  resortData (mtype);
1153  if (mtype == MET_NORMAL)
1154    {
1155      int idx_cc = -1;
1156      MetricList *mlist_cc = get_metric_list (MET_CALL);
1157      Vector<Metric*> *items_cc = mlist_cc->get_items ();
1158      for (int i = 0; i < items_cc->size (); i++)
1159	{
1160	  char * name_cc = items_cc->fetch (i)->get_username ();
1161	  char * name_normal = items->fetch (visindex)->get_username ();
1162	  if (0 == strncmp (name_cc, name_normal, strlen (name_cc)))
1163	    {
1164	      idx_cc = i;
1165	      break;
1166	    }
1167	}
1168      if (idx_cc != -1)
1169	{
1170	  mlist_cc->set_sort (idx_cc, reverse);
1171	  resortData (MET_CALL);
1172	  // Change a sort metric for MET_CALL_AGR
1173	  Metric *m = items_cc->fetch (idx_cc);
1174	  MetricList *cList = get_metric_list (MET_CALL_AGR);
1175	  Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
1176	  if (m1)
1177	    cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
1178	}
1179    }
1180  if (mtype == MET_CALL)
1181    {
1182      int idx_norm = -1;
1183      MetricList *mlist_norm = get_metric_list (MET_NORMAL);
1184      Vector<Metric*> *items_norm = mlist_norm->get_items ();
1185      for (int i = 0; i < items_norm->size (); i++)
1186	{
1187	  char * name_norm = items_norm->fetch (i)->get_username ();
1188	  char * name_cc = items->fetch (visindex)->get_username ();
1189	  if (mlist_norm->get_sort_ref_index () == i
1190	      && 0 == strncmp (name_norm, name_cc, strlen (name_norm)))
1191	    {
1192	      idx_norm = i;
1193	      break;
1194	    }
1195	}
1196      if (idx_norm == -1)
1197	{
1198	  for (int i = 0; i < items_norm->size (); i++)
1199	    {
1200	      char * name_norm = items_norm->fetch (i)->get_username ();
1201	      char * name_cc = items->fetch (visindex)->get_username ();
1202	      if (0 == strncmp (name_norm, name_cc, strlen (name_norm)))
1203		{
1204		  idx_norm = i;
1205		  break;
1206		}
1207	    }
1208	}
1209      if (idx_norm != -1)
1210	{
1211	  mlist_norm->set_sort (idx_norm, reverse);
1212	  resortData (MET_NORMAL);
1213	}
1214      // Change a sort metric for MET_CALL_AGR
1215      Metric *m = items->fetch (visindex);
1216      MetricList *cList = get_metric_list (MET_CALL_AGR);
1217      Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
1218      if (m1)
1219	cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
1220    }
1221}
1222
1223void
1224DbeView::resortData (MetricType mtype)
1225{
1226  int idx;
1227  Hist_data *data;
1228
1229  MetricList *mlist = get_metric_list (mtype);
1230  switch (mtype)
1231    {
1232    case MET_NORMAL:
1233      if (func_data != NULL)
1234	func_data->resort (mlist);
1235      if (line_data != NULL)
1236	line_data->resort (mlist);
1237      if (pc_data != NULL)
1238	pc_data->resort (mlist);
1239      break;
1240    case MET_CALL:
1241    case MET_CALL_AGR:
1242      if (fitem_data != NULL)
1243	fitem_data->resort (mlist);
1244      if (callers != NULL)
1245	  callers->resort (mlist);
1246      if (callees != NULL)
1247	callees->resort (mlist);
1248      break;
1249    case MET_DATA:
1250      if (dobj_data != NULL)
1251	dobj_data->resort (mlist);
1252      if (dlay_data != NULL)
1253	{
1254	  delete dlay_data;
1255	  dlay_data = NULL;
1256	}
1257      break;
1258    case MET_INDX:
1259      Vec_loop (Hist_data*, indx_data, idx, data)
1260      {
1261	if (data)
1262	  data->resort (mlist);
1263      }
1264      break;
1265    case MET_IO:
1266      if (iofile_data != NULL)
1267	iofile_data->resort (mlist);
1268      if (iovfd_data != NULL)
1269	iovfd_data->resort (mlist);
1270      if (iocs_data != NULL)
1271	  iocs_data->resort (mlist);
1272      break;
1273    case MET_HEAP:
1274      if (heapcs_data != NULL)
1275	heapcs_data->resort (mlist);
1276      break;
1277    case MET_COMMON:
1278    case MET_SRCDIS:
1279      break;
1280    }
1281}
1282
1283// Get the sort metric name
1284char *
1285DbeView::getSort (MetricType mtype)
1286{
1287  MetricList *mlist = get_metric_list (mtype);
1288  return mlist->get_sort_name ();
1289}
1290
1291// Get the sort command (to use for resetting)
1292char *
1293DbeView::getSortCmd (MetricType mtype)
1294{
1295  MetricList *mlist = get_metric_list (mtype);
1296  return mlist->get_sort_cmd ();
1297}
1298
1299int
1300DbeView::get_sel_ind (Histable *selObj, int type, int subtype)
1301{
1302  Hist_data *data;
1303  switch (type)
1304    {
1305    case DSP_FUNCTION:
1306      data = func_data;
1307      break;
1308    case DSP_LINE:
1309      data = line_data;
1310      break;
1311    case DSP_PC:
1312      data = pc_data;
1313      break;
1314    case DSP_SOURCE:
1315    case DSP_SOURCE_V2:
1316      data = src_data;
1317      break;
1318    case DSP_DISASM:
1319    case DSP_DISASM_V2:
1320      data = dis_data;
1321      break;
1322    case DSP_DLAYOUT:
1323      data = dlay_data;
1324      break;
1325    case DSP_DATAOBJ:
1326      data = dobj_data;
1327      break;
1328    case DSP_IOACTIVITY:
1329      data = iofile_data;
1330      break;
1331    case DSP_IOVFD:
1332      data = iovfd_data;
1333      break;
1334    case DSP_IOCALLSTACK:
1335      data = iocs_data;
1336      break;
1337    case DSP_HEAPCALLSTACK:
1338      data = heapcs_data;
1339      break;
1340    case DSP_MEMOBJ:
1341    case DSP_INDXOBJ:
1342      data = get_indxobj_data (subtype);
1343      break;
1344    default:
1345      data = NULL;
1346      break;
1347    }
1348  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
1349    return -1;
1350  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
1351  for (int i = 0, sz = hi_data->size (); i < sz; i++)
1352    {
1353      Hist_data::HistItem *hi = hi_data->fetch (i);
1354      if (hi->obj == selObj)
1355	return i;
1356    }
1357  return -1;
1358}
1359
1360MetricList *
1361DbeView::get_metric_list (MetricType mtype, bool compare, int gr_num)
1362{
1363  MetricList *mlist;
1364  switch (mtype)
1365    {
1366    case MET_COMMON:// comparison mode, src & disasm views
1367      if (gr_num == 0)
1368	{// signifies same src file (or load obj) used by all groups
1369	  // show compare metrics in columns (not in separate source panels)
1370	  mlist = get_metric_list (MET_NORMAL);
1371	  break;
1372	}
1373      // once source panel per group; get metrics for this group
1374      mlist = get_metric_list (mtype);
1375      if (compare)
1376	{
1377	  mlist = get_compare_mlist (mlist, gr_num - 1);
1378	  int mode = get_compare_mode ();
1379	  if ((mode & (CMP_DELTA | CMP_RATIO)) != 0)
1380	    {
1381	      for (long i = 0, sz = mlist->size (); i < sz; i++)
1382		{
1383		  Metric *m = mlist->get (i);
1384		  char *expr_spec = m->get_expr_spec ();
1385		  if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
1386		    {
1387		      int vbits = m->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
1388		      if ((mode & CMP_RATIO) != 0)
1389			vbits |= VAL_RATIO;
1390		      else if ((mode & CMP_DELTA) != 0)
1391			vbits |= VAL_DELTA;
1392		      m->set_raw_visbits (vbits);
1393		    }
1394		}
1395	    }
1396	}
1397      break;
1398    default:
1399      mlist = get_metric_list (mtype);
1400      break;
1401    }
1402  return mlist;
1403}
1404
1405Hist_data *
1406DbeView::get_data (MetricList *mlist, Histable *selObj, int type, int subtype)
1407{
1408  Hist_data *data;
1409  switch (type)
1410    {
1411    case DSP_FUNCTION:
1412      delete func_data;
1413      mlist = new MetricList (mlist);
1414      func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
1415      return func_data;
1416    case DSP_LINE:
1417      delete line_data;
1418      mlist = new MetricList (mlist);
1419      line_data = get_hist_data (mlist, Histable::LINE, subtype, Hist_data::ALL);
1420      return line_data;
1421    case DSP_PC:
1422      delete pc_data;
1423      mlist = new MetricList (mlist);
1424      pc_data = get_hist_data (mlist, Histable::INSTR, subtype, Hist_data::ALL);
1425      return pc_data;
1426    case DSP_DATAOBJ:
1427      delete dobj_data;
1428      dobj_data = get_hist_data (mlist, Histable::DOBJECT, subtype,
1429				 Hist_data::ALL);
1430      break;
1431    case DSP_MEMOBJ:
1432      return get_hist_data (mlist, Histable::MEMOBJ, subtype, Hist_data::ALL);
1433    case DSP_INDXOBJ:
1434      data = get_hist_data (mlist, Histable::INDEXOBJ, subtype, Hist_data::ALL);
1435      indx_data->store (subtype, data);
1436      return data;
1437    case DSP_DLAYOUT:
1438      delete dlay_data;
1439      marks->reset ();
1440      data = get_hist_data (mlist, Histable::DOBJECT, subtype,
1441			    Hist_data::LAYOUT);
1442      // .. provides metric data for layout
1443      dlay_data = get_data_space ()->get_layout_data (data, marks,
1444						      get_thresh_dis ());
1445      return dlay_data;
1446    case DSP_CALLER:
1447      delete callers;
1448      callers = get_hist_data (mlist, Histable::FUNCTION, subtype,
1449			       Hist_data::CALLERS, selObj);
1450      return callers;
1451    case DSP_CALLEE:
1452      delete callees;
1453      callees = get_hist_data (mlist, Histable::FUNCTION, subtype,
1454			       Hist_data::CALLEES, selObj);
1455      return callees;
1456    case DSP_SELF:
1457      // Center Function item
1458      delete fitem_data;
1459      fitem_data = get_hist_data (mlist, Histable::FUNCTION, subtype,
1460				  Hist_data::SELF, selObj);
1461      return fitem_data;
1462    case DSP_SOURCE_V2:
1463    case DSP_DISASM_V2:
1464    case DSP_SOURCE:
1465    case DSP_DISASM:
1466      {
1467	// Source or disassembly
1468	if (selObj == NULL)
1469	  {
1470	    error_msg = status_str (DBEVIEW_NO_SEL_OBJ);
1471	    return NULL;
1472	  }
1473	Function *func = (Function *) selObj->convertto (Histable::FUNCTION);
1474	if (func == NULL)
1475	  {
1476	    error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
1477	    return NULL;
1478	  }
1479	if (func->flags & FUNC_FLAG_SIMULATED)
1480	  {
1481	    error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
1482	    return NULL;
1483	  }
1484	if (func->get_name () == NULL)
1485	  {
1486	    error_msg = dbe_strdup (GTXT ("Source location not recorded in experiment"));
1487	    return NULL;
1488	  }
1489	Module *module = func->module;
1490	if (module == NULL || module->get_name () == NULL)
1491	  {
1492	    error_msg = dbe_strdup (GTXT ("Object name not recorded in experiment"));
1493	    return NULL;
1494	  }
1495	marks->reset ();
1496	SourceFile *srcContext = (SourceFile *) selObj->convertto (Histable::SOURCEFILE);
1497	sel_binctx = func;
1498
1499	if (func_data == NULL)
1500	  func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
1501
1502	// for source and disassembly the name needs to be invisible,
1503	//	but that's handled in the module code
1504	if (type == DSP_SOURCE || type == DSP_SOURCE_V2)
1505	  {
1506	    marks2dsrc->reset ();
1507	    marks2dsrc_inc->reset ();
1508	    delete src_data;
1509	    data = src_data = module->get_data (this, mlist, Histable::LINE,
1510			      func_data->get_totals ()->value, srcContext, func,
1511			      marks, get_thresh_src (), get_src_compcom (),
1512			      get_src_visible (), get_hex_visible (),
1513			      false, false, marks2dsrc, marks2dsrc_inc);
1514	  }
1515	else
1516	  { /* type == DSP_DISASM */
1517	    marks2ddis->reset ();
1518	    marks2ddis_inc->reset ();
1519	    delete dis_data;
1520	    data = dis_data = module->get_data (this, mlist, Histable::INSTR,
1521			      func_data->get_totals ()->value, srcContext, func,
1522			      marks, get_thresh_dis (), get_dis_compcom (),
1523			      get_src_visible (), get_hex_visible (),
1524			      get_func_scope (), false, marks2ddis,
1525			      marks2ddis_inc);
1526	  }
1527	return data;
1528      }
1529    default:
1530      abort ();
1531    }
1532  return NULL;
1533}
1534
1535Histable *
1536DbeView::get_compare_obj (Histable *obj)
1537{
1538  char *nm;
1539  switch (obj->get_type ())
1540    {
1541    case Histable::LINE:
1542      nm = obj->get_name ();
1543      if (nm == NULL)
1544	break;
1545      if (dbeSession->comp_dbelines == NULL)
1546	dbeSession->comp_dbelines = new HashMap<char*, DbeLine*>;
1547      return dbeSession->comp_dbelines->get (nm, (DbeLine*) obj);
1548    case Histable::SOURCEFILE:
1549      nm = obj->get_name ();
1550      if (nm == NULL)
1551	break;
1552      nm = get_basename (nm);
1553      if (dbeSession->comp_sources == NULL)
1554	dbeSession->comp_sources = new HashMap<char*, SourceFile*>;
1555      return dbeSession->comp_sources->get (nm, (SourceFile*) obj);
1556    default:
1557      return obj->get_compare_obj ();
1558    }
1559  return obj;
1560}
1561
1562//
1563//   get_hist_data() creates a new Hist_data object;
1564//   it's caller's responsibility to delete it.
1565Hist_data *
1566DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
1567			int subtype, Hist_data::Mode mode, Histable *obj,
1568			Histable *context, Vector<Histable*> *sel_objs,
1569			PathTree::PtreeComputeOption flag)
1570{
1571  Vector<Histable*> *objs = NULL;
1572  if (obj != NULL)
1573    {
1574      objs = new Vector<Histable*>();
1575      objs->append (obj);
1576    }
1577  Hist_data *res = get_hist_data (mlist_orig, type, subtype, mode, objs, context, sel_objs, flag);
1578  delete objs;
1579  return res;
1580}
1581
1582Hist_data *
1583DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
1584			int subtype, Hist_data::Mode mode,
1585			Vector<Histable*> *objs,
1586			Histable *context, Vector<Histable*> *sel_objs,
1587			PathTree::PtreeComputeOption flag)
1588{
1589  MetricList *mlist = new MetricList (mlist_orig);
1590  /*
1591   * mlist differs from mlist_orig in two ways:
1592   * - extra metrics have been added as needed to compute derived metrics
1593   * - extra metrics have been added as needed to compute time for HWC (time converted) metrics
1594   *     (We don't drop those extra metrics but we don't display they to user.)
1595   * - visibility bits have been added for compare mode (e.g., VAL_DELTA or VAL_RATIO)
1596   *     (We want to preserve those visbits.)
1597   */
1598  // loop over mlist to add missing dependencies for derived metrics
1599  for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
1600    {
1601      Metric *m = mlist->get_items ()->fetch (i);
1602      char *expr_spec = m->get_expr_spec ();
1603      if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
1604	{
1605	  int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype (), NTXT ("EXPGRID==1"));
1606	  if (ind < 0)
1607	    {
1608	      BaseMetric *bm1 = dbeSession->find_metric (m->get_type (), m->get_cmd (), NTXT ("EXPGRID==1"));
1609	      Metric *m1 = new Metric (bm1, m->get_subtype ());
1610	      m1->set_dmetrics_visbits (VAL_VALUE);
1611	      mlist->append (m1);
1612	    }
1613	}
1614    }
1615
1616  for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
1617    {
1618      Metric *m = mlist->get_items ()->fetch (i);
1619      if (m->get_type () == BaseMetric::DERIVED)
1620	{
1621	  Definition *def = m->get_definition ();
1622	  Vector<BaseMetric*> *dependencies = def->get_dependencies ();
1623	  long *map = def->get_map ();
1624	  for (long i1 = 0, sz1 = dependencies ? dependencies->size () : 0; i1 < sz1; i1++)
1625	    {
1626	      BaseMetric *bm = dependencies->fetch (i1);
1627	      int ind = mlist->get_listorder (bm->get_cmd (), m->get_subtype (), m->get_expr_spec ());
1628	      if (ind < 0)
1629		{
1630		  BaseMetric *bm1 = dbeSession->find_metric (bm->get_type (), bm->get_cmd (), m->get_expr_spec ());
1631		  assert (bm1 != NULL);
1632		  Metric *m1 = new Metric (bm1, m->get_subtype ());
1633		  m1->set_dmetrics_visbits (VAL_VALUE);
1634		  ind = mlist->size ();
1635		  mlist->append (m1);
1636		}
1637	      map[i1] = ind;
1638	    }
1639	}
1640      else if (m->get_type () == BaseMetric::HWCNTR)
1641	{
1642	  if (m->is_tvisible () && m->get_dependent_bm ())
1643	    {
1644	      int ii = mlist->get_listorder (m->get_dependent_bm ()->get_cmd (),
1645					m->get_subtype (), m->get_expr_spec ());
1646	      if (ii < 0)
1647		{
1648		  BaseMetric *bm1 = dbeSession->find_metric (m->get_type (),
1649					     m->get_dependent_bm ()->get_cmd (),
1650					     m->get_expr_spec ());
1651		  assert (bm1 != NULL);
1652		  Metric *m1 = new Metric (bm1, m->get_subtype ());
1653		  m1->set_dmetrics_visbits ((m->get_visbits ()
1654					     & ~VAL_VALUE) | VAL_TIMEVAL);
1655		  mlist->append (m1);
1656		}
1657	    }
1658	}
1659    }
1660
1661  // compute Hist_data
1662  Hist_data *data;
1663  switch (type)
1664    {
1665    case Histable::INSTR:
1666    case Histable::LINE:
1667      data = ptree->compute_metrics (mlist, type, mode, objs, context, sel_objs);
1668      break;
1669    case Histable::FUNCTION:
1670    case Histable::MODULE:
1671    case Histable::LOADOBJECT:
1672      data = ptree->compute_metrics (mlist, type, mode, objs, NULL,
1673				     sel_objs, flag);
1674      break;
1675    case Histable::DOBJECT:
1676      data = dspace->compute_metrics (mlist, type, mode,
1677				      objs ? objs->fetch (0) : NULL);
1678      break;
1679    case Histable::MEMOBJ:
1680    case Histable::INDEXOBJ:
1681      data = indxspaces->get (subtype)->compute_metrics (mlist, type, mode,
1682							 objs, NULL);
1683      break;
1684    case Histable::IOACTFILE:
1685      if (objs == NULL)
1686	{
1687	  data = iofile_data = iospace->compute_metrics (mlist, type, mode,
1688							 NULL);
1689	  break;
1690	}
1691      else
1692	{
1693	  data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
1694	  break;
1695	}
1696    case Histable::IOACTVFD:
1697      if (objs == NULL)
1698	data = iovfd_data = iospace->compute_metrics (mlist, type, mode, NULL);
1699      else
1700	data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
1701      break;
1702    case Histable::IOCALLSTACK:
1703      if (objs == NULL)
1704	data = iocs_data = iospace->compute_metrics (mlist, type, mode, NULL);
1705      else
1706	data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
1707      break;
1708    case Histable::HEAPCALLSTACK:
1709      if (objs == NULL)
1710	data = heapcs_data = heapspace->compute_metrics (mlist, type, mode, NULL);
1711      else
1712	data = heapspace->compute_metrics (mlist, type, mode, objs->fetch (0));
1713      break;
1714    default:
1715      data = NULL;
1716      break;
1717    }
1718  for (long i = mlist_orig->get_items ()->size (),
1719	  sz = mlist->get_items ()->size (); i < sz; i++)
1720    {
1721      Metric *m = mlist->get_items ()->get (i);
1722      m->set_dmetrics_visbits (VAL_HIDE_ALL | m->get_visbits ());
1723    }
1724  if (data)
1725    data->nmetrics = mlist_orig->size ();
1726  return data;
1727}
1728
1729char *
1730DbeView::get_mobj_name (int subtype)
1731{
1732  MemorySpace *ms = getMemorySpace (subtype);
1733  if (ms == NULL)
1734    ms = addMemorySpace (subtype);
1735  return ms->getMemObjTypeName ();
1736}
1737
1738MemorySpace *
1739DbeView::getMemorySpace (int subtype)
1740{
1741  for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
1742    {
1743      MemorySpace *ms = memspaces->get (i);
1744      if (subtype == ms->getMemObjType ())
1745	return ms;
1746    }
1747  return NULL;
1748}
1749
1750MemorySpace *
1751DbeView::addMemorySpace (int subtype)
1752{
1753  MemorySpace *ms = new MemorySpace (this, subtype);
1754  memspaces->append (ms);
1755  return ms;
1756}
1757
1758Hist_data *
1759DbeView::get_indxobj_data (int subtype)
1760{
1761  if (subtype < 0 || subtype >= indx_data->size ())
1762    return NULL;
1763  return indx_data->fetch (subtype);
1764}
1765
1766void
1767DbeView::set_indxobj_sel (int subtype, int sel_ind)
1768{
1769  Hist_data *data = get_indxobj_data (subtype);
1770  if (data == NULL)
1771    return;
1772  if (sel_ind >= 0 && sel_ind < data->size ())
1773    {
1774      Histable *obj = data->fetch (sel_ind)->obj;
1775      sel_idxobj->store (subtype, obj);
1776    }
1777}
1778
1779Histable *
1780DbeView::get_indxobj_sel (int subtype)
1781{
1782  return sel_idxobj->fetch (subtype);
1783}
1784
1785void
1786DbeView::addIndexSpace (int subtype)
1787{
1788  PathTree *is = new PathTree (this, subtype);
1789  indxspaces->store (subtype, is);
1790  indx_data->store (subtype, NULL);
1791  sel_idxobj->store (subtype, NULL);
1792  settings->indxobj_define (subtype, false);
1793}
1794
1795Histable *
1796DbeView::get_sel_obj_io (uint64_t id, Histable::Type type)
1797{
1798  if (iospace == NULL)
1799    return NULL;
1800  Histable *obj = NULL;
1801  Hist_data *data = NULL;
1802  switch (type)
1803    {
1804    case Histable::IOACTFILE:
1805      data = iofile_data;
1806      break;
1807    case Histable::IOACTVFD:
1808      data = iovfd_data;
1809      break;
1810    case Histable::IOCALLSTACK:
1811      data = iocs_data;
1812      break;
1813    default:
1814      break;
1815    }
1816  if (data == NULL)
1817    return NULL;
1818
1819  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
1820  int size = hi_data->size ();
1821  for (int i = 0; i < size; i++)
1822    {
1823      Hist_data::HistItem *hi = hi_data->fetch (i);
1824      if (hi->obj != NULL && (uint64_t) hi->obj->id == id)
1825	{
1826	  obj = hi->obj;
1827	  break;
1828	}
1829    }
1830  return obj;
1831}
1832
1833Histable *
1834DbeView::get_sel_obj_heap (uint64_t id)
1835{
1836  if (heapspace == NULL || heapcs_data == NULL)
1837    return NULL;
1838  Histable *obj = NULL;
1839  Hist_data *data = heapcs_data;
1840  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
1841  int size = hi_data->size ();
1842  for (int i = 0; i < size; i++)
1843    {
1844      Hist_data::HistItem *hi = hi_data->fetch (i);
1845      if ((hi->obj != NULL) && ((uint64_t) hi->obj->id) == id)
1846	{
1847	  obj = hi->obj;
1848	  break;
1849	}
1850    }
1851  return obj;
1852}
1853
1854CStack_data *
1855DbeView::get_cstack_data (MetricList *mlist)
1856{
1857  return ptree->get_cstack_data (mlist);
1858}
1859
1860Stats_data *
1861DbeView::get_stats_data (int index)
1862{
1863  DataView *packets = get_filtered_events (index, DATA_SAMPLE);
1864  if (packets == NULL)
1865    return NULL;
1866  return new Stats_data (packets);
1867}
1868
1869Ovw_data *
1870DbeView::get_ovw_data (int index)
1871{
1872  DataView *packets = get_filtered_events (index, DATA_SAMPLE);
1873  Experiment* exp = dbeSession->get_exp (index);
1874  hrtime_t starttime = 0;
1875  if (exp != NULL)
1876    starttime = exp->getStartTime ();
1877  if (packets == NULL)
1878    return NULL;
1879  return new Ovw_data (packets, starttime);
1880}
1881
1882char *
1883DbeView::set_filter (const char *filter_spec)
1884{
1885  if (dbe_strcmp (filter_spec, cur_filter_str) == 0)  // Nothing was changed
1886    return NULL;
1887
1888  // if string is NULL, delete the filter
1889  if (filter_spec == NULL)
1890    {
1891      if (cur_filter_str)
1892	{
1893	  free (cur_filter_str);
1894	  cur_filter_str = NULL;
1895	}
1896      if (cur_filter_expr)
1897	{
1898	  delete cur_filter_expr;
1899	  cur_filter_expr = NULL;
1900	}
1901      noParFilter = false;
1902      purge_events ();
1903      reset_data (false);
1904      return NULL;
1905    }
1906
1907  // process the filter
1908  Expression *expr = dbeSession->ql_parse (filter_spec);
1909  if (expr == NULL)
1910    return dbe_sprintf (GTXT ("Invalid filter specification `%s'\n"), filter_spec);
1911
1912  if (dbe_strcmp (filter_spec, "1") == 0)
1913    noParFilter = false;
1914  else if (sel_obj != NULL)
1915    if (sel_obj->get_type () == Histable::LINE)
1916      if (expr->verifyObjectInExpr (sel_obj))
1917	noParFilter = true;
1918
1919  // valid new filter
1920  if (cur_filter_str != NULL)
1921    {
1922      free (prev_filter_str);
1923      prev_filter_str = dbe_strdup (cur_filter_str);
1924    }
1925  free (cur_filter_str);
1926  cur_filter_str = dbe_strdup (filter_spec);
1927  delete cur_filter_expr;
1928  cur_filter_expr = expr;
1929  purge_events ();
1930  reset_data (false);
1931  return NULL;
1932}
1933
1934FilterExp *
1935DbeView::get_FilterExp (Experiment *exp)
1936{
1937  if (cur_filter_expr == NULL)
1938    return NULL;
1939  Expression::Context *ctx = new Expression::Context (this, exp);
1940  return new FilterExp (cur_filter_expr, ctx, noParFilter);
1941}
1942
1943char *
1944DbeView::get_filter ()
1945{
1946  return dbe_strdup (cur_filter_str);
1947}
1948
1949FilterSet *
1950DbeView::get_filter_set (int n)
1951{
1952  fflush (stderr);
1953  if (n >= filters->size ())
1954    return NULL;
1955  return ( filters->fetch (n));
1956}
1957
1958Vector<FilterNumeric*> *
1959DbeView::get_all_filters (int nexp)
1960{
1961  FilterSet *fs = get_filter_set (nexp);
1962  return fs ? fs->get_all_filters () : NULL;
1963}
1964
1965FilterNumeric *
1966DbeView::get_FilterNumeric (int nexp, int idx)
1967{
1968  FilterSet *fs = get_filter_set (nexp);
1969  return fs ? fs->get_filter (idx) : NULL;
1970}
1971
1972void
1973DbeView::backtrack_filter()
1974{
1975    if (prev_filter_str != NULL)
1976       set_filter(prev_filter_str);
1977    else set_filter("1"); // reset
1978
1979}
1980
1981void
1982DbeView::update_advanced_filter ()
1983{
1984  char *s = get_advanced_filter ();
1985  if (dbe_strcmp (s, cur_filter_str))
1986    {
1987      phaseIdx++;
1988      char *err_msg = set_filter (s);
1989      if (err_msg)
1990	{
1991#ifdef DEBUG
1992	  fprintf (stderr, NTXT ("ERROR: Advanced Filter: '%s'\n"), err_msg);
1993#endif
1994	}
1995    }
1996  free (s);
1997}
1998
1999bool
2000DbeView::set_pattern (int n, Vector<char *> *pattern_str, bool *error)
2001{
2002  Vector<FilterNumeric*> *filts = get_all_filters (n);
2003
2004  bool ret = false;
2005  *error = false;
2006  int imax = pattern_str->size ();
2007  if (imax > filts->size ())
2008    imax = filts->size ();
2009  for (int i = 0; i < imax; i++)
2010    {
2011      FilterNumeric *f = filts->fetch (i);
2012      char *s = pattern_str->fetch (i);
2013      if (s == NULL)
2014	continue;
2015      if (f->set_pattern (s, error))
2016	ret = true;
2017    }
2018
2019  if (ret || cur_filter_expr)
2020    {
2021      update_advanced_filter ();
2022      filter_active = true;
2023    }
2024  return ret;
2025}
2026
2027static void
2028append_experiments (StringBuilder *sb, int first, int last)
2029{
2030  if (first == -1)
2031    return;
2032  if (sb->length () != 0)
2033    sb->append (NTXT (" || "));
2034  sb->append ('(');
2035  if (first == last)
2036    {
2037      sb->append (NTXT ("EXPID=="));
2038      sb->append (first);
2039    }
2040  else
2041    {
2042      sb->append (NTXT ("EXPID>="));
2043      sb->append (first);
2044      sb->append (NTXT (" && EXPID<="));
2045      sb->append (last);
2046    }
2047  sb->append (')');
2048}
2049
2050char *
2051DbeView::get_advanced_filter ()
2052{
2053  StringBuilder sb;
2054  bool wasFalse = false;
2055  int first = -1, last = -1;
2056  for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
2057    {
2058      FilterSet *fs = get_filter_set (n);
2059      char *s = fs->get_advanced_filter ();
2060      if (s)
2061	{
2062	  if (streq (s, NTXT ("1")))
2063	    {
2064	      last = n + 1;
2065	      if (first == -1)
2066		first = last;
2067	      continue;
2068	    }
2069	  append_experiments (&sb, first, last);
2070	  first = -1;
2071	  if (streq (s, NTXT ("0")))
2072	    {
2073	      wasFalse = true;
2074	      continue;
2075	    }
2076	  if (sb.length () != 0)
2077	    sb.append (NTXT (" || "));
2078	  sb.append (NTXT ("(EXPID=="));
2079	  sb.append (n + 1);
2080	  sb.append (NTXT (" && ("));
2081	  sb.append (s);
2082	  free (s);
2083	  sb.append (NTXT ("))"));
2084	}
2085      else
2086	{
2087	  last = n + 1;
2088	  if (first == -1)
2089	    first = last;
2090	}
2091    }
2092  if (first != 1)
2093    {
2094      append_experiments (&sb, first, last);
2095      first = -1;
2096    }
2097  if (sb.length () == 0)
2098    sb.append (wasFalse ? '0' : '1');
2099  else
2100    append_experiments (&sb, first, last);
2101  return sb.toString ();
2102}
2103
2104bool
2105DbeView::set_pattern (int m, char *pattern)
2106{
2107  bool error = false;
2108
2109  // Store original setting in case of error
2110  int nexps = dbeSession->nexps ();
2111  int orig_phaseIdx = phaseIdx;
2112  bool *orig_enable = new bool[nexps];
2113  char **orig_pattern = new char*[nexps];
2114  for (int i = 0; i < nexps; i++)
2115    {
2116      orig_pattern[i] = get_FilterNumeric (i, m)->get_pattern ();
2117      orig_enable[i] = get_exp_enable (i);
2118      set_exp_enable (i, false);
2119    }
2120
2121  // Copy the pattern so that we could safely modify it
2122  char *buf = dbe_strdup (pattern);
2123  FilterNumeric *fexp = NULL;
2124  char *pb, *pe;
2125  pb = pe = buf;
2126  for (bool done = false; !done; pe++)
2127    {
2128      if (*pe == ':')
2129	{
2130	  // experiment filter;
2131	  *pe = '\0';
2132	  fexp = new FilterNumeric (NULL, NULL, NULL);
2133	  fexp->set_range (1, nexps, nexps);
2134	  fexp->set_pattern (pb, &error);
2135	  if (error)
2136	    break;
2137	  pb = pe + 1;
2138	}
2139      else if (*pe == '+' || *pe == '\0')
2140	{
2141	  // entity filter
2142	  if (*pe == '\0')
2143	    done = true;
2144	  else
2145	    *pe = '\0';
2146	  for (int i = 0; i < nexps; i++)
2147	    {
2148	      if (!fexp || fexp->is_selected (i + 1))
2149		{
2150		  FilterNumeric *f = get_FilterNumeric (i, m);
2151		  f->set_pattern (pb, &error);
2152		  if (error)
2153		    break;
2154		  set_exp_enable (i, true);
2155		}
2156	    }
2157	  if (error)
2158	    break;
2159	  delete fexp;
2160	  fexp = NULL;
2161	  pb = pe + 1;
2162	}
2163    }
2164
2165  if (error)
2166    {
2167      for (int i = 0; i < nexps; i++)
2168	{
2169	  bool err;
2170	  set_exp_enable (i, orig_enable[i]);
2171	  FilterNumeric *f = get_FilterNumeric (i, m);
2172	  f->set_pattern (orig_pattern[i], &err);
2173	  free (orig_pattern[i]);
2174	}
2175      phaseIdx = orig_phaseIdx;
2176    }
2177  else
2178    {
2179      update_advanced_filter ();
2180      filter_active = true;
2181    }
2182  delete[] orig_enable;
2183  delete[] orig_pattern;
2184  delete fexp;
2185  free (buf);
2186  return !error;
2187}
2188
2189void
2190DbeView::set_view_mode (VMode newmode)
2191{
2192  if (newmode != settings->get_view_mode ())
2193    {
2194
2195      // For OpenMP, the expert mode path-tree is already present with the user mode
2196      // No need to increase the phaseIdx to trigger recomputation of path-tree
2197      // if we toggle between user and expert modes
2198      if (!(dbeSession->is_omp_available ()
2199	    && ((newmode == VMODE_EXPERT
2200		 && settings->get_view_mode () == VMODE_USER)
2201		|| (newmode == VMODE_USER
2202		    && settings->get_view_mode () == VMODE_EXPERT))))
2203	phaseIdx++; // For all other cases
2204      setNewViewMode ();
2205      settings->set_view_mode (newmode);
2206    }
2207}
2208
2209Cmd_status
2210DbeView::set_view_mode (char *str, bool fromRC)
2211{
2212  VMode old = settings->get_view_mode ();
2213  Cmd_status ret = settings->set_view_mode (str, fromRC);
2214  if (old != settings->get_view_mode ())
2215    phaseIdx++;
2216  return ret;
2217}
2218
2219Cmd_status
2220DbeView::set_en_desc (char *str, bool fromRC)
2221{
2222  // Tell the session
2223  Settings *s = dbeSession->get_settings ();
2224  s->set_en_desc (str, fromRC);
2225
2226  // and tell our settings
2227  return settings->set_en_desc (str, fromRC);
2228}
2229
2230// Get processor stats messages
2231char *
2232DbeView::get_processor_msg (int type)
2233{
2234  if (ptree == NULL)  // if no PathTree, no messages
2235    return NULL;
2236
2237  StringBuilder sb;
2238  Emsg *m = (type == PSTAT_MSG) ? ptree->fetch_stats () : ptree->fetch_warnings ();
2239  for (; m != NULL; m = m->next)
2240    {
2241      char* newmsg = m->get_msg ();
2242      sb.append (newmsg);
2243      sb.append ("\n");
2244    }
2245
2246  if (type == PSTAT_MSG)
2247    ptree->delete_stats ();
2248  else
2249    ptree->delete_warnings ();
2250  return (sb.length () > 0) ? sb.toString () : NULL;
2251}
2252
2253void
2254DbeView::dump_nodes (FILE *outfile)
2255{
2256  FILE *f = (outfile == NULL ? stderr : outfile);
2257  ptree->print (f);
2258}
2259
2260// Dump the clock profile events
2261void
2262DbeView::dump_profile (FILE *out_file)
2263{
2264  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2265    {
2266      Experiment *exp = dbeSession->get_exp (idx);
2267      VMode view_mode = get_view_mode ();
2268      char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
2269
2270      // Process clock profile date
2271      DataView *packets = get_filtered_events (idx, DATA_CLOCK);
2272      if (packets && packets->getSize () != 0)
2273	{
2274	  hrtime_t start = exp->getStartTime ();
2275	  fprintf (out_file,
2276		   GTXT ("\nTotal Clock Profiling Packets:  %d Experiment:  %s\n"),
2277		   (int) packets->getSize (), exp->get_expt_name ());
2278	  for (long i = 0; i < packets->getSize (); i++)
2279	    {
2280	      hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
2281	      hrtime_t ts = expr_ts - start;
2282
2283	      // get the properties from the packet
2284	      uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
2285	      uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
2286	      int mstate = (int) packets->getIntValue (PROP_MSTATE, i);
2287	      int nticks = (int) packets->getIntValue (PROP_NTICK, i);
2288
2289	      char *sname;
2290	      char buf[1024];
2291	      if (mstate >= 0 && mstate < LMS_NUM_STATES)
2292		  sname = stateNames[mstate];
2293	      else
2294		{
2295		  snprintf (buf, sizeof (buf), NTXT ("Unexpected mstate = %d"), mstate);
2296		  sname = buf;
2297		}
2298
2299	      // get the stack   IGNORE HIDE
2300	      Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
2301	      int stack_size = stack->size ();
2302
2303	      // print the packet header with the count of stack frames
2304	      fprintf (out_file,
2305		       GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
2306		       i, expr_ts, ts / NANOSEC, ts % NANOSEC,
2307		       expr_ts / NANOSEC, expr_ts % NANOSEC,
2308		       thrid, cpuid, stack_size);
2309	      fprintf (out_file,
2310		       GTXT ("    mstate = %d (%s), nticks = %d\n"),
2311		       mstate, sname, nticks);
2312
2313	      // dump the callstack
2314	      for (int j = stack_size - 1; j >= 0; j--)
2315		{
2316		  Histable *frame = stack->fetch (j);
2317		  fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
2318		}
2319	      fprintf (out_file, "\n");
2320	    }
2321	}
2322      else
2323	fprintf (out_file,
2324		 GTXT ("\nNo Clock Profiling Packets in Experiment:  %s\n"),
2325		 exp->get_expt_name ());
2326    }
2327}
2328
2329// Dump the sync trace events
2330void
2331DbeView::dump_sync (FILE *out_file)
2332{
2333  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2334    {
2335      Experiment *exp = dbeSession->get_exp (idx);
2336      VMode view_mode = get_view_mode ();
2337
2338      // Process heap trace date
2339      DataView *packets = get_filtered_events (idx, DATA_SYNCH);
2340      if (packets && packets->getSize () != 0)
2341	{
2342	  hrtime_t start = exp->getStartTime ();
2343	  fprintf (out_file,
2344		   GTXT ("\nTotal Synctrace Packets:  %d Experiment:  %s\n"),
2345		   (int) packets->getSize (), exp->get_expt_name ());
2346
2347	  for (long i = 0; i < packets->getSize (); i++)
2348	    {
2349	      hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
2350	      hrtime_t ts = expr_ts - start;
2351
2352	      // get the properties from the packet
2353	      uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
2354	      uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
2355	      uint64_t syncobj = (uint64_t) packets->getLongValue (PROP_SOBJ, i);
2356	      hrtime_t syncrtime = (uint64_t) packets->getLongValue (PROP_SRQST, i);
2357	      hrtime_t syncdelay = expr_ts - syncrtime;
2358
2359	      // get the stack   IGNORE HIDE
2360	      Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
2361	      int stack_size = stack->size ();
2362
2363	      // print the packet header with the count of stack frames
2364	      fprintf (out_file,
2365		       GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
2366		       i, expr_ts, ts / NANOSEC, ts % NANOSEC,
2367		       expr_ts / NANOSEC, expr_ts % NANOSEC, thrid,
2368		       cpuid, stack_size);
2369	      fprintf (stderr,
2370		       GTXT ("       synchronization object @ 0x%016llx;  synchronization delay  %3lld.%09lld\n"),
2371		       (unsigned long long) syncobj, (long long) (syncdelay / NANOSEC), (long long) (syncdelay % NANOSEC));
2372
2373	      // dump the callstack
2374	      for (int j = stack_size - 1; j >= 0; j--)
2375		{
2376		  Histable *frame = stack->fetch (j);
2377		  fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
2378		}
2379	      fprintf (out_file, "\n");
2380	    }
2381	}
2382      else
2383	fprintf (out_file, GTXT ("\nNo Synctrace Packets in Experiment:  %s\n"),
2384		 exp->get_expt_name ());
2385    }
2386}
2387
2388// Dump the IO trace events
2389void
2390DbeView::dump_iotrace (FILE *out_file)
2391{
2392  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2393    {
2394      Experiment *exp = dbeSession->get_exp (idx);
2395      VMode view_mode = get_view_mode ();
2396
2397      // Process IO trace date
2398      DataView *packets = get_filtered_events (idx, DATA_IOTRACE);
2399      if (packets && packets->getSize () != 0)
2400	{
2401	  hrtime_t start = exp->getStartTime ();
2402	  fprintf (out_file,
2403		   GTXT ("\nTotal IO trace Packets:  %d Experiment:  %s\n"),
2404		   (int) packets->getSize (), exp->get_expt_name ());
2405	  for (long i = 0; i < packets->getSize (); i++)
2406	    {
2407	      hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
2408	      hrtime_t ts = expr_ts - start;
2409
2410	      // get the properties from the packet
2411	      uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
2412	      uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
2413	      IOTrace_type iotrtype = (IOTrace_type) packets->getIntValue (PROP_IOTYPE, i);
2414	      uint32_t iofd = (uint32_t) packets->getIntValue (PROP_IOFD, i);
2415	      uint64_t ionbyte = (uint64_t) packets->getIntValue (PROP_IONBYTE, i);
2416	      hrtime_t iorqst = (hrtime_t) packets->getLongValue (PROP_IORQST, i);
2417	      uint32_t ioofd = (uint32_t) packets->getIntValue (PROP_IOOFD, i);
2418	      FileSystem_type iofstype = (FileSystem_type) packets->getIntValue (PROP_CPUID, i);
2419	      int64_t iovfd = (int64_t) packets->getIntValue (PROP_IOVFD, i);
2420
2421	      char *fName = NULL;
2422	      StringBuilder *sb = (StringBuilder*) packets->getObjValue (PROP_IOFNAME, i);
2423	      if (sb != NULL && sb->length () > 0)
2424		fName = sb->toString ();
2425
2426	      // get the stack  IGNORE HIDE
2427	      Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
2428	      int stack_size = stack->size ();
2429	      const char *iotrname;
2430	      switch (iotrtype)
2431		{
2432		case READ_TRACE:
2433		  iotrname = "ReadTrace";
2434		  break;
2435		case WRITE_TRACE:
2436		  iotrname = "WriteTrace";
2437		  break;
2438		case OPEN_TRACE:
2439		  iotrname = "OpenTrace";
2440		  break;
2441		case CLOSE_TRACE:
2442		  iotrname = "CloseTrace";
2443		  break;
2444		case OTHERIO_TRACE:
2445		  iotrname = "OtherIOTrace";
2446		  break;
2447		case READ_TRACE_ERROR:
2448		  iotrname = "ReadTraceError";
2449		  break;
2450		case WRITE_TRACE_ERROR:
2451		  iotrname = "WriteTraceError";
2452		  break;
2453		case OPEN_TRACE_ERROR:
2454		  iotrname = "OpenTraceError";
2455		  break;
2456		case CLOSE_TRACE_ERROR:
2457		  iotrname = "CloseTraceError";
2458		  break;
2459		case OTHERIO_TRACE_ERROR:
2460		  iotrname = "OtherIOTraceError";
2461		  break;
2462		default:
2463		  iotrname = "UnknownIOTraceType";
2464		  break;
2465		}
2466
2467	      // print the packet header with the count of stack frames
2468	      fprintf (out_file,
2469		       GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
2470		       i, expr_ts, ts / NANOSEC, ts % NANOSEC,
2471		       expr_ts / NANOSEC, expr_ts % NANOSEC,
2472		       thrid, cpuid, stack_size);
2473	      fprintf (out_file,
2474		       GTXT ("    %s: fd = %d, ofd = %d, vfd = %lld, fstype = %d, rqst =  %3lld.%09lld\n"),
2475		       iotrname, (int) iofd, (int) ioofd, (long long) iovfd,
2476		       (int) iofstype, (long long) (iorqst / NANOSEC),
2477		       (long long) (iorqst % NANOSEC));
2478	      fprintf (out_file, GTXT ("    filename = `%s', nbytes = %d\n"),
2479		       STR (fName), (int) ionbyte);
2480	      free (fName);
2481
2482	      // dump the callstack
2483	      for (int j = stack_size - 1; j >= 0; j--)
2484		{
2485		  Histable *frame = stack->fetch (j);
2486		  fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
2487		}
2488	      fprintf (out_file, "\n");
2489	    }
2490	}
2491      else
2492	fprintf (out_file, GTXT ("\nNo IO trace Packets in Experiment:  %s\n"),
2493		 exp->get_expt_name ());
2494    }
2495}
2496
2497// Dump the HWC Profiling events
2498void
2499DbeView::dump_hwc (FILE *out_file)
2500{
2501  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2502    {
2503      Experiment *exp = dbeSession->get_exp (idx);
2504      VMode view_mode = get_view_mode ();
2505
2506      // Dump HWC profiling data
2507      DataView *packets = get_filtered_events (idx, DATA_HWC);
2508      if (packets && packets->getSize () != 0)
2509	{
2510	  hrtime_t start = exp->getStartTime ();
2511	  fprintf (out_file,
2512		   GTXT ("\nTotal HW Counter Profiling Packets:  %d Experiment:  %s\n"),
2513		   (int) packets->getSize (), exp->get_expt_name ());
2514	  for (long i = 0; i < packets->getSize (); i++)
2515	    {
2516	      const char * hwc_name;
2517	      hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
2518	      hrtime_t ts = expr_ts - start;
2519	      uint32_t tag = (uint32_t) packets->getIntValue (PROP_HWCTAG, i);
2520	      uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
2521	      uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
2522
2523	      // This will work even with a different counter in every packet.
2524	      if (tag < 0 || tag >= MAX_HWCOUNT
2525		  || !exp->coll_params.hw_aux_name[tag])
2526		// if the packet has an invalid tag, use <invalid> as its name
2527		hwc_name = "<invalid>";
2528	      else
2529		hwc_name = exp->coll_params.hw_aux_name[tag];
2530	      int64_t mval = packets->getLongValue (PROP_HWCINT, i);
2531	      const char *err = HWCVAL_HAS_ERR (mval) ? " $$" : "";
2532
2533	      // get the stack IGNORE HIDE
2534	      Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
2535	      int stack_size = stack->size ();
2536
2537	      // print the packet header with the count of stack frames
2538	      fprintf (out_file,
2539		       GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n       count = %10lld (0x%016llx), tag = %d (%s)%s\n"),
2540		       (long) i, (long long) expr_ts,
2541		       (long long) (ts / NANOSEC), (long long) (ts % NANOSEC),
2542		       (long long) (expr_ts / NANOSEC), (long long) (expr_ts % NANOSEC),
2543		       (int) thrid, (int) cpuid, (int) stack_size,
2544		       (long long) (HWCVAL_CLR_ERR (mval)), (long long) mval,
2545		       (int) tag, hwc_name, err);
2546
2547	      //  dump extended HWC packets values
2548	      uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
2549	      uint64_t pa = (uint64_t) packets->getLongValue (PROP_PADDR, i);
2550	      fprintf (out_file, GTXT ("       va = 0x%016llx, pa = 0x%016llx\n"),
2551		       (unsigned long long) va, (unsigned long long) pa);
2552
2553	      // dump the callstack
2554	      for (int j = stack_size - 1; j >= 0; j--)
2555		{
2556		  Histable *frame = stack->fetch (j);
2557		  fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
2558		}
2559	      fprintf (out_file, "\n");
2560	    }
2561	}
2562      else
2563	fprintf (out_file,
2564		 GTXT ("\nNo HWC Profiling Packets in Experiment:  %s\n"),
2565		 exp->get_expt_name ());
2566    }
2567}
2568
2569// Dump the Heap events
2570void
2571DbeView::dump_heap (FILE *out_file)
2572{
2573  char *heapstrings[] = HEAPTYPE_STATE_USTRINGS;
2574  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2575    {
2576      Experiment *exp = dbeSession->get_exp (idx);
2577      VMode view_mode = get_view_mode ();
2578
2579      // Process heap trace date
2580      DataView *packets = get_filtered_events (idx, DATA_HEAP);
2581      if (packets && packets->getSize () != 0)
2582	{
2583	  hrtime_t start = exp->getStartTime ();
2584	  fprintf (out_file, GTXT ("\nTotal Heaptrace Packets:  %d Experiment:  %s\n"),
2585		   (int) packets->getSize (), exp->get_expt_name ());
2586	  for (long i = 0; i < packets->getSize (); i++)
2587	    {
2588	      hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
2589	      hrtime_t ts = expr_ts - start;
2590
2591	      // get the properties from the packet
2592	      uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
2593	      uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
2594	      uint32_t heaptype = (uint32_t) packets->getIntValue (PROP_HTYPE, i);
2595	      uint64_t heapsize = (uint64_t) packets->getULongValue (PROP_HSIZE, i);
2596	      uint64_t heapvaddr = (uint64_t) packets->getULongValue (PROP_HVADDR, i);
2597	      uint64_t heapovaddr = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
2598	      if (heaptype == MUNMAP_TRACE)
2599		{
2600		  heapsize = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
2601		  heapovaddr = 0;
2602		}
2603
2604	      // get the stack  IGNORE HIDE
2605	      Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
2606	      int stack_size = stack->size ();
2607
2608	      // print the packet header with the count of stack frames
2609	      fprintf (out_file,
2610		       GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
2611		       i, expr_ts, ts / NANOSEC, ts % NANOSEC,
2612		       expr_ts / NANOSEC, expr_ts % NANOSEC,
2613		       thrid, cpuid, stack_size);
2614	      char *typestr = heapstrings[heaptype];
2615	      fprintf (out_file,
2616		       GTXT ("    type = %d (%s), size = %llu (0x%llx), VADDR = 0x%016llx, OVADDR = 0x%016llx\n"),
2617		       (int) heaptype, typestr, (long long unsigned int) heapsize,
2618		       (long long unsigned int) heapsize,
2619		       (long long unsigned int) heapvaddr,
2620		       (long long unsigned int) heapovaddr);
2621
2622	      // dump the callstack
2623	      for (int j = stack_size - 1; j >= 0; j--)
2624		{
2625		  Histable *frame = stack->fetch (j);
2626		  fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
2627		}
2628	      fprintf (out_file, "\n");
2629	    }
2630	}
2631      else
2632	fprintf (out_file, GTXT ("\nNo Heaptrace Packets in Experiment:  %s\n"),
2633		 exp->get_expt_name ());
2634    }
2635}
2636
2637// Dump the Java garbage collector events
2638void
2639DbeView::dump_gc_events (FILE *out_file)
2640{
2641  for (int idx = 0; idx < dbeSession->nexps (); idx++)
2642    {
2643      Experiment *exp = dbeSession->get_exp (idx);
2644      if (!exp->has_java)
2645	fprintf (out_file,
2646		 GTXT ("# No GC events in experiment %d, %s (PID %d, %s)\n"),
2647		 idx, exp->get_expt_name (), exp->getPID (), exp->utargname);
2648      else
2649	{
2650	  Vector<GCEvent*> *gce = exp->get_gcevents ();
2651	  GCEvent *this_event;
2652	  int index;
2653	  fprintf (out_file,
2654		   GTXT ("# %li events in experiment %d: %s (PID %d, %s)\n"),
2655		   gce->size (), idx,
2656		   exp->get_expt_name (), exp->getPID (), exp->utargname);
2657	  fprintf (out_file,
2658	       GTXT ("# exp:idx     GC_start,        GC_end,   GC_duration\n"));
2659	  Vec_loop (GCEvent*, gce, index, this_event)
2660	  {
2661	    hrtime_t start = this_event->start - exp->getStartTime ();
2662	    hrtime_t end = this_event->end - exp->getStartTime ();
2663	    hrtime_t delta = this_event->end - this_event->start;
2664	    fprintf (out_file,
2665		     "%5d:%d, %3lld.%09lld, %3lld.%09lld, %3lld.%09lld\n",
2666		     idx, index,
2667		     (long long) (start / NANOSEC), (long long) (start % NANOSEC),
2668		     (long long) (end / NANOSEC), (long long) (end % NANOSEC),
2669		     (long long) (delta / NANOSEC), (long long) (delta % NANOSEC));
2670	  }
2671	}
2672    }
2673}
2674
2675void
2676DbeView::purge_events (int n)
2677{
2678  phaseIdx++;
2679  int lst;
2680  if (n == -1)
2681    lst = filters->size ();
2682  else
2683    lst = n > filters->size () ? filters->size () : n + 1;
2684  for (int i = n == -1 ? 0 : n; i < lst; i++)
2685    {
2686      Vector<DataView*> *expDataViewList = dataViews->fetch (i);
2687      if (expDataViewList)
2688	{
2689	  // clear out all the data_ids, but don't change the vector size
2690	  for (int data_id = 0; data_id < expDataViewList->size (); ++data_id)
2691	    {
2692	      delete expDataViewList->fetch (data_id);
2693	      expDataViewList->store (data_id, NULL);
2694	    }
2695	}
2696    }
2697  filter_active = false;
2698}
2699
2700
2701// LIBRARY_VISIBILITY
2702void
2703DbeView::resetAndConstructShowHideStacks ()
2704{
2705  for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
2706    {
2707      Experiment *exp = dbeSession->get_exp (n);
2708      if (exp != NULL)
2709	resetAndConstructShowHideStack (exp);
2710    }
2711}
2712
2713// LIBRARY_VISIBILITY
2714void
2715DbeView::resetAndConstructShowHideStack (Experiment *exp)
2716{
2717  exp->resetShowHideStack ();
2718  /*  Vector<DataDescriptor*> *dDscrs = */ exp->getDataDescriptors ();
2719
2720  DataDescriptor *dd;
2721  // Construct show hide stack only for objects which have call stacks
2722  // list below similar to path tree. What about HEAP_SZ? (DBFIXME)
2723  dd = exp->get_raw_events (DATA_CLOCK);
2724  if (dd != NULL)
2725    constructShowHideStack (dd, exp);
2726  dd = exp->get_raw_events (DATA_SYNCH);
2727  if (dd != NULL)
2728    constructShowHideStack (dd, exp);
2729  dd = exp->get_raw_events (DATA_IOTRACE);
2730  if (dd != NULL)
2731    constructShowHideStack (dd, exp);
2732  dd = exp->get_raw_events (DATA_HWC);
2733  if (dd != NULL)
2734    constructShowHideStack (dd, exp);
2735  dd = exp->get_raw_events (DATA_HEAP);
2736  if (dd != NULL)
2737    constructShowHideStack (dd, exp);
2738  dd = exp->get_raw_events (DATA_RACE);
2739  if (dd != NULL)
2740    constructShowHideStack (dd, exp);
2741  dd = exp->get_raw_events (DATA_DLCK);
2742  if (dd != NULL)
2743    constructShowHideStack (dd, exp);
2744}
2745
2746// LIBRARY_VISIBILITY
2747void
2748DbeView::constructShowHideStack (DataDescriptor *dDscr, Experiment *exp)
2749{
2750  if (dDscr == NULL)
2751    return;
2752  int stack_prop = PROP_NONE;
2753  VMode view_mode = get_view_mode ();
2754  if (view_mode == VMODE_MACHINE)
2755    stack_prop = PROP_MSTACK;
2756  else if (view_mode == VMODE_EXPERT)
2757    stack_prop = PROP_XSTACK;
2758  else if (view_mode == VMODE_USER)
2759    stack_prop = PROP_USTACK;
2760
2761  for (long j = 0, sz = dDscr->getSize (); j < sz; j++)
2762    {
2763      void *stackId = dDscr->getObjValue (stack_prop, j);
2764      Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId);
2765      int stack_size = stack->size ();
2766      bool hide_on = false;
2767      LoadObject *hide_lo = NULL;
2768      Histable *last_addr = NULL;
2769      Histable *api_addr = NULL;
2770      DbeInstr *h_instr;
2771
2772      Vector<Histable*> *hidepcs = new Vector<Histable*>;
2773      for (int i = stack_size - 1; i >= 0; i--)
2774	{
2775	  bool leaf = (i == 0);
2776	  Histable *cur_addr = stack->fetch (i);
2777	  Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION);
2778	  if (func != NULL)
2779	    {
2780	      Module *mod = func->module;
2781	      LoadObject *lo = mod->loadobject;
2782	      int segx = lo->seg_idx;
2783	      if ((get_lo_expand (segx) == LIBEX_API) && (i != (stack_size - 1)))
2784		{
2785		  leaf = true;
2786		  api_addr = cur_addr;
2787		}
2788	      else if (get_lo_expand (segx) == LIBEX_HIDE)
2789		{
2790		  if (hide_on)
2791		    {
2792		      if (lo != hide_lo)
2793			{
2794			  // Changed hidden loadobject
2795			  if (last_addr != NULL)
2796			    {
2797			      h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
2798			      hidepcs->append (h_instr);
2799			      last_addr = cur_addr;
2800			    }
2801			  hide_lo = lo;
2802			}
2803		    }
2804		  else
2805		    {
2806		      // Start hide
2807		      hide_on = true;
2808		      last_addr = cur_addr;
2809		      hide_lo = lo;
2810		    }
2811		  if (!leaf)
2812		    continue;
2813		}
2814	      else
2815		{
2816		  hide_on = false;
2817		  if (last_addr != NULL)
2818		    {
2819		      h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
2820		      hidepcs->append (h_instr);
2821		      last_addr = NULL;
2822		    }
2823		}
2824	    }
2825	  if (last_addr != NULL && leaf) cur_addr = last_addr;
2826	  if (hide_on)
2827	    {
2828	      h_instr = hide_lo->get_hide_instr ((DbeInstr*) cur_addr);
2829	      hidepcs->append (h_instr);
2830	      if (api_addr != NULL)
2831		hidepcs->append (api_addr);
2832	    }
2833	  else
2834	    hidepcs->append (cur_addr);
2835	  if (leaf)
2836	    break;
2837	}
2838      for (int i = 0, k = hidepcs->size () - 1; i < k; ++i, --k)
2839	hidepcs->swap (i, k);
2840
2841      CallStack *cstkSH = exp->callTreeShowHide ();
2842      CallStackNode *hstack = (CallStackNode *) cstkSH->add_stack (hidepcs);
2843      dDscr->setObjValue (PROP_HSTACK, j, hstack);
2844      CallStack::setHideStack (stackId, hstack);
2845      delete hidepcs;
2846      delete stack;
2847    }
2848}
2849
2850DataView *
2851DbeView::get_filtered_events (int idx, int data_id)
2852{
2853  if (idx < 0 || idx >= dataViews->size ())
2854    return NULL;
2855  Vector<DataView*> *expDataViewList = dataViews->fetch (idx);
2856  if (!expDataViewList)
2857    return NULL; // Weird
2858
2859  DataView *dview = expDataViewList->fetch (data_id);
2860  Experiment *exp = dbeSession->get_exp (idx);
2861  if (dview)
2862    {
2863      // if show-hide is on force a reconstruction of hide stacks
2864      // LIBRARY_VISIBILITY
2865      if (!showAll && (showHideChanged || newViewMode))
2866	{
2867	  DataDescriptor *dDscr = exp->get_raw_events (data_id);
2868	  constructShowHideStack (dDscr, exp);
2869	}
2870      return dview;
2871    }
2872
2873  int orig_data_id = data_id;
2874  data_id = exp->base_data_id (data_id);
2875  if (orig_data_id != data_id)
2876    // orig_data_id is a derived DataView.  Get the master DataView:
2877    dview = expDataViewList->fetch (data_id);
2878  if (dview == NULL)
2879    {
2880      Expression *saved = cur_filter_expr;
2881      if (!adjust_filter (exp))
2882	return NULL;
2883
2884      DataDescriptor *dDscr = exp->get_raw_events (data_id);
2885      if (!showAll && (showHideChanged || newViewMode))
2886	constructShowHideStack (dDscr, exp);
2887
2888      Emsg *m = exp->fetch_warnings ();
2889      if (m != NULL)
2890	this->warning_msg = m->get_msg ();
2891
2892      if (dDscr != NULL)
2893	{
2894	  FilterExp *filter = get_FilterExp (exp);
2895	  dview = dDscr->createView ();
2896	  dview->setFilter (filter);
2897	  if (dview->getSize () < dDscr->getSize ())
2898	    filter_active = true;
2899	}
2900      expDataViewList->store (data_id, dview);
2901
2902      if (saved)
2903	{
2904	  delete cur_filter_expr;
2905	  cur_filter_expr = saved;
2906	}
2907    }
2908  if (orig_data_id != data_id)
2909    {
2910      // create the derived DataView:
2911      dview = exp->create_derived_data_view (orig_data_id, dview);
2912      expDataViewList->store (orig_data_id, dview);
2913    }
2914  return dview;
2915}
2916
2917DataView *
2918DbeView::get_filtered_events (int idx, int data_id,
2919			      const int sortprops[], int sortprop_count)
2920{
2921  DataView *packets = get_filtered_events (idx, data_id);
2922  if (packets)
2923    packets->sort (sortprops, sortprop_count);
2924  return packets;
2925}
2926
2927bool
2928DbeView::adjust_filter (Experiment *exp)
2929{
2930  if (cur_filter_expr)
2931    {
2932      Expression::Context ctx (this, exp);
2933      resetFilterHideMode ();
2934      Expression *fltr = cur_filter_expr->pEval (&ctx);
2935      if (fltr->complete ())
2936	{ // Filter is a constant
2937	  if (fltr->eval (NULL) == 0)
2938	    return false;
2939	  delete fltr;
2940	  fltr = NULL;
2941	}
2942      cur_filter_expr = fltr;
2943    }
2944  return true;
2945}
2946
2947// Moved from Cacheable.cc:
2948char *
2949DbeView::status_str (DbeView_status status)
2950{
2951  switch (status)
2952    {
2953    case DBEVIEW_SUCCESS:
2954      return NULL;
2955    case DBEVIEW_NO_DATA:
2956      return dbe_strdup (GTXT ("Data not available for this filter selection"));
2957    case DBEVIEW_IO_ERROR:
2958      return dbe_strdup (GTXT ("Unable to open file"));
2959    case DBEVIEW_BAD_DATA:
2960      return dbe_strdup (GTXT ("Data corrupted"));
2961    case DBEVIEW_BAD_SYMBOL_DATA:
2962      return dbe_strdup (GTXT ("Functions/Modules information corrupted"));
2963    case DBEVIEW_NO_SEL_OBJ:
2964      return dbe_strdup (GTXT ("No selected object, bring up Functions Tab"));
2965    }
2966  return NULL;
2967}
2968
2969Histable *
2970DbeView::set_sel_obj (Histable *obj)
2971{
2972  if (obj)
2973    {
2974      switch (obj->get_type ())
2975	{
2976	case Histable::INSTR:
2977	  lastSelInstr = (DbeInstr *) obj;
2978	  lastSelFunc = lastSelInstr->func;
2979	  this->sel_binctx = lastSelFunc;
2980	  break;
2981	case Histable::FUNCTION:
2982	  if (lastSelInstr && lastSelInstr->func != obj)
2983	    lastSelInstr = NULL;
2984	  lastSelFunc = (Function *) obj;
2985	  break;
2986	case Histable::LINE:
2987	  {
2988	    DbeLine *dbeLine = (DbeLine *) obj;
2989	    if (dbeLine->func)
2990	      {
2991		// remember previous DbeInstr and DbeFunc
2992		lastSelFunc = dbeLine->func;
2993		if (lastSelInstr && lastSelInstr->func != lastSelFunc)
2994		  lastSelInstr = NULL;
2995		this->sel_binctx = lastSelFunc;
2996	      }
2997	    else
2998	      this->sel_binctx = dbeLine->convertto (Histable::FUNCTION);
2999	    break;
3000	  }
3001	case Histable::MODULE:
3002	case Histable::LOADOBJECT:
3003	case Histable::EADDR:
3004	case Histable::MEMOBJ:
3005	case Histable::INDEXOBJ:
3006	case Histable::PAGE:
3007	case Histable::DOBJECT:
3008	case Histable::SOURCEFILE:
3009	case Histable::IOACTFILE:
3010	case Histable::IOACTVFD:
3011	case Histable::IOCALLSTACK:
3012	case Histable::HEAPCALLSTACK:
3013	case Histable::EXPERIMENT:
3014	case Histable::OTHER:
3015	  break;
3016	}
3017    }
3018  sel_obj = obj;
3019  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d obj %s\n"),
3020	   __LINE__, obj ? obj->dump () : "NULL");
3021  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d sel_obj %s\n"),
3022	   __LINE__, sel_obj ? sel_obj->dump () : "NULL");
3023  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelFunc %s\n"),
3024	   __LINE__, lastSelFunc ? lastSelFunc->dump () : "NULL");
3025  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelInstr %s\n"),
3026	   __LINE__, lastSelInstr ? lastSelInstr->dump () : "NULL");
3027  return sel_obj;
3028}
3029
3030DbeInstr *
3031DbeView::convert_line_to_instr (DbeLine *dbeLine)
3032{
3033  Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d dbeLine=%s\n", __LINE__, dbeLine->dump ());
3034  Function *func = convert_line_to_func (dbeLine);
3035  if (func)
3036    {
3037      Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d func=%s\n", __LINE__, func->dump ());
3038      DbeInstr *dbeInstr = func->mapLineToPc (dbeLine);
3039      Dprintf (DEBUG_DBE && dbeInstr, "### convert_line_to_instr DbeView::%d dbeInstr=%s\n", __LINE__, dbeInstr->dump ());
3040      return dbeInstr;
3041    }
3042  Dprintf (DEBUG_DBE && lastSelInstr, "### convert_line_to_instr DbeView::%d lastSelInstr=%s\n", __LINE__, lastSelInstr->dump ());
3043  return lastSelInstr;
3044}
3045
3046DbeInstr *
3047DbeView::convert_func_to_instr (Function *func)
3048{
3049  return (lastSelInstr && lastSelInstr->func == func) ?
3050	  lastSelInstr : (DbeInstr *) func->convertto (Histable::INSTR);
3051}
3052
3053Function *
3054DbeView::convert_line_to_func (DbeLine *dbeLine)
3055{
3056  Function *func = dbeLine->func;
3057  if (func)
3058    return func;
3059  if (lastSelFunc != NULL)
3060    // Can be mapped to the same function ?
3061    for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
3062      if (dl->func == lastSelFunc)
3063	return lastSelFunc;
3064
3065  PathTree *pathTree = NULL;
3066  Function *firstFunc = NULL;
3067  for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
3068    {
3069      // Find a first function with non-zero metrics
3070      if (dl->func)
3071	{
3072	  if (pathTree == NULL)
3073	    pathTree = get_path_tree ();
3074	  if (pathTree->get_func_nodeidx (dl->func))
3075	    return dl->func;
3076	  if (firstFunc == NULL)
3077	    firstFunc = dl->func;
3078	}
3079    }
3080  // Take a first function
3081  return firstFunc;
3082}
3083
3084Histable *
3085DbeView::get_sel_obj (Histable::Type type)
3086{
3087  Histable *lastSelObj = sel_obj;
3088  Dprintf (DEBUG_DBE, NTXT ("### get_sel_obj: DbeView.cc:%d type=%d sel_obj %s\n"),
3089	   __LINE__, type, lastSelObj ? lastSelObj->dump () : "NULL");
3090  if (lastSelObj == NULL)
3091    return NULL;
3092  switch (type)
3093    {
3094    case Histable::INSTR:
3095      if (!showAll)
3096	{
3097	  // DBFIXME LIBRARY VISIBILITY
3098	  // hack to get to the hide mode object for PCs when filtering
3099	  // with a PC in timeline
3100	  if (lastSelObj->get_type () == Histable::INSTR)
3101	    {
3102	      Function *func = (Function*) (lastSelObj->convertto (Histable::FUNCTION));
3103	      LoadObject *lo = func->module->loadobject;
3104	      if (get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
3105		return lo->get_hide_function ();
3106	    }
3107	}
3108      if (lastSelObj->get_type () == Histable::LINE)
3109	return convert_line_to_instr ((DbeLine*) lastSelObj);
3110      else if (lastSelObj->get_type () == Histable::FUNCTION)
3111	return convert_func_to_instr ((Function *) lastSelObj);
3112      return lastSelObj->convertto (type);
3113    case Histable::FUNCTION:
3114      if (lastSelObj->get_type () == Histable::LINE)
3115	{
3116	  Function *func = convert_line_to_func ((DbeLine*) lastSelObj);
3117	  if (func)
3118	    return func;
3119	  return NULL;
3120	}
3121      return lastSelObj->convertto (type);
3122    case Histable::LINE:
3123    default:
3124      return lastSelObj->convertto (type);
3125    }
3126}
3127