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 <ctype.h>
23#include <stdio.h>
24#include <dirent.h>
25#include <unistd.h>
26#include <sys/types.h>
27#include <errno.h>
28#include <sys/param.h>
29
30#include "util.h"
31#include "Application.h"
32#include "Experiment.h"
33#include "ExpGroup.h"
34#include "Expression.h"
35#include "DataObject.h"
36#include "Elf.h"
37#include "Function.h"
38#include "DbeSession.h"
39#include "LoadObject.h"
40#include "DbeSyncMap.h"
41#include "DbeThread.h"
42#include "ClassFile.h"
43#include "IndexObject.h"
44#include "PathTree.h"
45#include "Print.h"
46#include "QLParser.tab.hh"
47#include "DbeView.h"
48#include "MemorySpace.h"
49#include "Module.h"
50#include "SourceFile.h"
51#include "StringBuilder.h"
52#include "BaseMetric.h"
53#include "BaseMetricTreeNode.h"
54#include "Command.h"
55#include "UserLabel.h"
56#include "StringMap.h"
57#include "DbeFile.h"
58#include "DbeJarFile.h"
59#include "IOActivity.h"
60#include "HeapActivity.h"
61
62// This is a universal List structure to organize objects
63// of various types, even if different.
64struct List
65{
66  List *next;
67  void *val;
68};
69
70struct Countable
71{
72  Countable (void *_item)
73  {
74    item = _item;
75    ref_count = 0;
76  }
77
78  void *item;
79  int ref_count;
80};
81
82Platform_t DbeSession::platform =
83#if ARCH(SPARC)
84        Sparc;
85#elif ARCH(Aarch64)
86        Aarch64;
87#else   // ARCH(Intel)
88        Intel;
89#endif
90
91// This constant determines the size of the data object name hash table.
92static const int HTableSize         = 8192;
93static int DEFAULT_TINY_THRESHOLD   = -1;
94
95unsigned int mpmt_debug_opt = 0;
96DbeSession *dbeSession = NULL;
97
98DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode)
99{
100  dbeSession = this;
101  ipc_mode = _ipc_mode;
102  rdt_mode = _rdt_mode;
103  settings = new Settings (_settings);
104  views = new Vector<DbeView*>;
105  exps = new Vector<Experiment*>;
106  lobjs = new Vector<LoadObject*>;
107  objs = new Vector<Histable*>;
108  dobjs = new Vector<DataObject*>;
109  metrics = new Vector<Countable*>;
110  reg_metrics = new Vector<BaseMetric*>;
111  hwcentries = NULL;
112  reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse
113  idxobjs = new Vector<HashMap<uint64_t, Histable*>*>;
114  tmp_files = new Vector<char*>;
115  search_path = new Vector<char*>;
116  classpath = new Vector<char*>;
117  classpath_df = NULL;
118  expGroups = new Vector<ExpGroup*>;
119  sourcesMap = new HashMap<char*, SourceFile*>;
120  sources = new Vector<SourceFile*>;
121  comp_lobjs = new HashMap<char*, LoadObject*>;
122  comp_dbelines = new HashMap<char*, DbeLine*>;
123  comp_sources = new HashMap<char*, SourceFile*>;
124  loadObjMap = new DbeSyncMap<LoadObject>;
125  f_special = new Vector<Function*>(LastSpecialFunction);
126  omp_functions = new Vector<Function*>(OMP_LAST_STATE);
127  interactive = false;
128  lib_visibility_used = false;
129
130  // Define all known property names
131  propNames = new Vector<PropDescr*>;
132  propNames_name_store (PROP_NONE, NTXT (""));
133  propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP"));
134  propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP"));
135  propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP"));
136  propNames_name_store (PROP_THRID, NTXT ("THRID"));
137  propNames_name_store (PROP_LWPID, NTXT ("LWPID"));
138  propNames_name_store (PROP_CPUID, NTXT ("CPUID"));
139  propNames_name_store (PROP_FRINFO, NTXT ("FRINFO"));
140  propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME"));
141
142  // Samples
143  propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
144  propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE"));
145
146  // GCEvents
147  propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
148  propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT"));
149
150  // Metadata used by some packet types
151  propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"),
152                        NULL, TYPE_UINT64, DDFLAG_NOSHOW);
153
154  // Clock profiling properties
155  propNames_name_store (PROP_UCPU, NTXT ("UCPU"));
156  propNames_name_store (PROP_SCPU, NTXT ("SCPU"));
157  propNames_name_store (PROP_TRAP, NTXT ("TRAP"));
158  propNames_name_store (PROP_TFLT, NTXT ("TFLT"));
159  propNames_name_store (PROP_DFLT, NTXT ("DFLT"));
160  propNames_name_store (PROP_KFLT, NTXT ("KFLT"));
161  propNames_name_store (PROP_ULCK, NTXT ("ULCK"));
162  propNames_name_store (PROP_TSLP, NTXT ("TSLP"));
163  propNames_name_store (PROP_WCPU, NTXT ("WCPU"));
164  propNames_name_store (PROP_TSTP, NTXT ("TSTP"));
165
166  propNames_name_store (PROP_MSTATE, NTXT ("MSTATE"));
167  propNames_name_store (PROP_NTICK, NTXT ("NTICK"));
168  propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE"));
169
170  // Synchronization tracing properties
171  propNames_name_store (PROP_SRQST, NTXT ("SRQST"));
172  propNames_name_store (PROP_SOBJ, NTXT ("SOBJ"));
173
174  // Hardware counter profiling properties
175  propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG"));
176  propNames_name_store (PROP_HWCINT, NTXT ("HWCINT"));
177  propNames_name_store (PROP_VADDR, NTXT ("VADDR"));
178  propNames_name_store (PROP_PADDR, NTXT ("PADDR"));
179  propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC"));
180  propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC"));
181  propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME"));
182  propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME"));
183  propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE"));
184  propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP"));
185  propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE"));
186  propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP"));
187  propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
188  propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT"));
189  propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC"));
190
191  // Heap tracing properties
192  propNames_name_store (PROP_HTYPE, NTXT ("HTYPE"));
193  propNames_name_store (PROP_HSIZE, NTXT ("HSIZE"));
194  propNames_name_store (PROP_HVADDR, NTXT ("HVADDR"));
195  propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR"));
196  propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"),
197                        GTXT ("Leaked bytes"), TYPE_UINT64, 0);
198  propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
199  propNames_name_store (PROP_HFREED, NTXT ("HFREED"),
200                        GTXT ("Freed bytes"), TYPE_UINT64, 0);
201  propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"),
202                        GTXT ("Current allocations"), TYPE_INT64, 0);
203  propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"),
204                        NULL, TYPE_INT64, DDFLAG_NOSHOW);
205  propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"),
206                        GTXT ("Current leaks"), TYPE_UINT64, 0);
207  propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"),
208                        NULL, TYPE_UINT64, DDFLAG_NOSHOW);
209
210  // IO tracing properties
211  propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE"));
212  propNames_name_store (PROP_IOFD, NTXT ("IOFD"));
213  propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE"));
214  propNames_name_store (PROP_IORQST, NTXT ("IORQST"));
215  propNames_name_store (PROP_IOOFD, NTXT ("IOOFD"));
216  propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME"));
217  propNames_name_store (PROP_IOVFD, NTXT ("IOVFD"));
218  propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE"));
219
220  // omptrace raw properties
221  propNames_name_store (PROP_CPRID, NTXT ("CPRID"));
222  propNames_name_store (PROP_PPRID, NTXT ("PPRID"));
223  propNames_name_store (PROP_TSKID, NTXT ("TSKID"));
224  propNames_name_store (PROP_PTSKID, NTXT ("PTSKID"));
225  propNames_name_store (PROP_PRPC, NTXT ("PRPC"));
226
227  // Data race detection properties
228  propNames_name_store (PROP_RID, NTXT ("RID"));
229  propNames_name_store (PROP_RTYPE, NTXT ("RTYPE"));
230  propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC"));
231  propNames_name_store (PROP_RVADDR, NTXT ("RVADDR"));
232  propNames_name_store (PROP_RCNT, NTXT ("RCNT"));
233
234  // Deadlock detection properties
235  propNames_name_store (PROP_DID, NTXT ("DID"));
236  propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE"));
237  propNames_name_store (PROP_DTYPE, NTXT ("DTYPE"));
238  propNames_name_store (PROP_DVADDR, NTXT ("DVADDR"));
239
240  // Synthetic properties (queries only)
241  propNames_name_store (PROP_STACK, NTXT ("STACK"));
242  propNames_name_store (PROP_MSTACK, NTXT ("MSTACK"));
243  propNames_name_store (PROP_USTACK, NTXT ("USTACK"));
244  propNames_name_store (PROP_XSTACK, NTXT ("XSTACK"));
245  propNames_name_store (PROP_HSTACK, NTXT ("HSTACK"));
246  propNames_name_store (PROP_STACKID, NTXT ("STACKID"));
247  //propNames_name_store( PROP_CPRID,   NTXT("CPRID") );
248  //propNames_name_store( PROP_TSKID,   NTXT("TSKID") );
249  propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"),
250                        GTXT ("Java thread number"), TYPE_UINT64, 0);
251
252  propNames_name_store (PROP_LEAF, NTXT ("LEAF"));
253  propNames_name_store (PROP_DOBJ, NTXT ("DOBJ"));
254  propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP"));
255  propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP"));
256  propNames_name_store (PROP_PID, NTXT ("PID"),
257                        GTXT ("Process id"), TYPE_UINT64, 0);
258  propNames_name_store (PROP_EXPID, NTXT ("EXPID"),
259                        GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW);
260  propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"),
261                        GTXT ("Comparable Experiment Id"), TYPE_UINT64,
262                        DDFLAG_NOSHOW); //YXXX find better description
263  propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"),
264                        GTXT ("Comparison Group id"), TYPE_UINT64, 0);
265  propNames_name_store (PROP_PARREG, NTXT ("PARREG"));
266  propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"),
267                        GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0);
268  propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"),
269                        GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0);
270  propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"),
271                        GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64,
272                        DDFLAG_NOSHOW);
273  propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"),
274                        GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0);
275  propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"),
276                        GTXT ("Clock Profiling Interval, Microseconds"),
277                        TYPE_UINT64, 0);
278
279  propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES"));
280
281  propNames_name_store (PROP_STACKL, NTXT ("STACKL"));
282  propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL"));
283  propNames_name_store (PROP_USTACKL, NTXT ("USTACKL"));
284  propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL"));
285
286  propNames_name_store (PROP_STACKI, NTXT ("STACKI"));
287  propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI"));
288  propNames_name_store (PROP_USTACKI, NTXT ("USTACKI"));
289  propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI"));
290
291  // Make sure predefined names are not used for dynamic properties
292  propNames_name_store (PROP_LAST, NTXT (""));
293
294  localized_SP_UNKNOWN_NAME = GTXT ("(unknown)");
295
296  // define Index objects
297  dyn_indxobj = new Vector<IndexObjType_t*>();
298  dyn_indxobj_indx = 0;
299  char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"),
300                         (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
301  indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL);
302  free (s);
303  indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL);
304  indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"),
305                  NULL, NULL);
306  indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"),
307                  NULL, NULL);
308  indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"),
309                  NTXT ("(TSTAMP/1000000000)"), NULL, NULL);
310  indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"),
311                  NULL, NULL);
312  s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"),
313                   (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT,
314                   (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
315  indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL);
316  free (s);
317  indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"),
318                  "(IOHEAPBYTES==0?0:"
319                  "((IOHEAPBYTES<=(1<<0)?(1<<0):"
320                  "((IOHEAPBYTES<=(1<<2)?(1<<2):"
321                  "((IOHEAPBYTES<=(1<<4)?(1<<4):"
322                  "((IOHEAPBYTES<=(1<<6)?(1<<6):"
323                  "((IOHEAPBYTES<=(1<<8)?(1<<8):"
324                  "((IOHEAPBYTES<=(1<<10)?(1<<10):"
325                  "((IOHEAPBYTES<=(1<<12)?(1<<12):"
326                  "((IOHEAPBYTES<=(1<<14)?(1<<14):"
327                  "((IOHEAPBYTES<=(1<<16)?(1<<16):"
328                  "((IOHEAPBYTES<=(1<<18)?(1<<18):"
329                  "((IOHEAPBYTES<=(1<<20)?(1<<20):"
330                  "((IOHEAPBYTES<=(1<<22)?(1<<22):"
331                  "((IOHEAPBYTES<=(1<<24)?(1<<24):"
332                  "((IOHEAPBYTES<=(1<<26)?(1<<26):"
333                  "((IOHEAPBYTES<=(1<<28)?(1<<28):"
334                  "((IOHEAPBYTES<=(1<<30)?(1<<30):"
335                  "((IOHEAPBYTES<=(1<<32)?(1<<32):"
336                  "((IOHEAPBYTES<=(1<<34)?(1<<34):"
337                  "((IOHEAPBYTES<=(1<<36)?(1<<36):"
338                  "((IOHEAPBYTES<=(1<<38)?(1<<38):"
339                  "((IOHEAPBYTES<=(1<<40)?(1<<40):"
340                  "((IOHEAPBYTES<=(1<<42)?(1<<42):"
341                  "((IOHEAPBYTES<=(1<<44)?(1<<44):"
342                  "((IOHEAPBYTES<=(1<<46)?(1<<46):"
343                  "((IOHEAPBYTES<=(1<<48)?(1<<48):"
344                  "((IOHEAPBYTES<=(1<<50)?(1<<50):"
345                  "(IOHEAPBYTES==-1?-1:(1<<50|1)"
346                  "))))))))))))))))))))))))))))))))))))))))))))))))))))))",
347                  NULL, NULL);
348  indxobj_define (NTXT ("Duration"), GTXT ("Duration"),
349                  "((TSTAMP_HI-TSTAMP_LO)==0?0:"
350                  "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:"
351                  "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:"
352                  "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:"
353                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:"
354                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:"
355                  "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:"
356                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:"
357                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:"
358                  "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:"
359                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:"
360                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:"
361                  "(10000000000001))))))))))))))))))))))))", NULL, NULL);
362  dyn_indxobj_indx_fixed = dyn_indxobj_indx;
363  Elf::elf_init ();
364  defExpName = NULL;
365  mach_model_loaded = NULL;
366  tmp_dir_name = NULL;
367  settings->read_rc (ipc_mode || rdt_mode);
368
369  init ();
370}
371
372DbeSession::~DbeSession ()
373{
374  Destroy (views);
375  Destroy (exps);
376  Destroy (dobjs);
377  Destroy (metrics);
378  Destroy (search_path);
379  Destroy (classpath);
380  Destroy (propNames);
381  Destroy (expGroups);
382  Destroy (userLabels);
383  if (hwcentries)
384    {
385      for (long i = 0, sz = hwcentries->size (); i < sz; i++)
386        {
387          Hwcentry *h = hwcentries->get (i);
388          free (h->int_name);
389          free (h->name);
390          delete h;
391        }
392      delete hwcentries;
393    }
394
395  if (idxobjs)
396    {
397      for (int i = 0; i < idxobjs->size (); ++i)
398        {
399          HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i);
400          if (hMap)
401            {
402              hMap->values ()->destroy ();
403              delete hMap;
404            }
405        }
406      delete idxobjs;
407    }
408
409  for (int i = 0; i < HTableSize; i++)
410    {
411      List *list = dnameHTable[i];
412      while (list)
413        {
414          List *tmp = list;
415          list = list->next;
416          delete tmp;
417        }
418    }
419  delete[] dnameHTable;
420  delete classpath_df;
421  Destroy (objs);
422  Destroy (reg_metrics);
423  Destroy (dyn_indxobj);
424  delete lobjs;
425  delete f_special;
426  destroy_map (DbeFile *, dbeFiles);
427  destroy_map (DbeJarFile *, dbeJarFiles);
428  delete loadObjMap;
429  delete omp_functions;
430  delete sourcesMap;
431  delete sources;
432  delete comp_lobjs;
433  delete comp_dbelines;
434  delete comp_sources;
435  delete reg_metrics_tree;
436  delete settings;
437  free (mach_model_loaded);
438
439  if (defExpName != NULL)
440    {
441      StringBuilder *sb = new StringBuilder ();
442      sb->append (NTXT ("/bin/rm -rf "));
443      sb->append (defExpName);
444      char *cmd = sb->toString ();
445      system (cmd);
446      free (cmd);
447      delete sb;
448      free (defExpName);
449    }
450  unlink_tmp_files ();
451  delete tmp_files;
452  dbeSession = NULL;
453}
454
455void
456DbeSession::unlink_tmp_files ()
457{
458  if (tmp_files)
459    {
460      for (int i = 0, sz = tmp_files->size (); i < sz; i++)
461        unlink (tmp_files->fetch (i));
462      tmp_files->destroy ();
463      delete tmp_files;
464      tmp_files = NULL;
465    }
466  if (tmp_dir_name)
467    {
468      char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name);
469      system (cmd);
470      free (cmd);
471      free (tmp_dir_name);
472      tmp_dir_name = NULL;
473    }
474}
475
476char *
477DbeSession::get_tmp_file_name (const char *nm, bool for_java)
478{
479  if (tmp_dir_name == NULL)
480    {
481      tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"),
482                         (unsigned long long) getuid (), (long long) getpid ());
483      mkdir (tmp_dir_name, S_IRWXU);
484    }
485  char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm);
486  if (for_java)
487    for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++)
488      if (*s == '/')
489        *s = '.';
490  return fnm;
491}
492
493void
494DbeSession::init ()
495{
496  user_exp_id_counter = 0;
497  status_ompavail = 0;
498  archive_mode = 0;
499
500#if DEBUG
501  char *s = getenv (NTXT ("MPMT_DEBUG"));
502  if (s)
503    mpmt_debug_opt = atoi (s);
504#endif /* DEBUG */
505  dbeFiles = new StringMap<DbeFile*>();
506  dbeJarFiles = new StringMap<DbeJarFile*>(128, 128);
507
508  // set up the initial (after .rc file reading) search path
509  set_search_path (settings->str_search_path, true);
510  userLabels = NULL;
511
512  // Preset all objects as they may reuse each other
513  lo_unknown = NULL;
514  f_unknown = NULL;
515  j_unknown = NULL;
516  lo_total = NULL;
517  sf_unknown = NULL;
518  f_total = NULL;
519  f_jvm = NULL;
520  d_total = NULL;
521  d_scalars = NULL;
522  d_unknown = NULL;
523  expGroups->destroy ();
524  f_special->reset ();
525  for (int i = 0; i < LastSpecialFunction; i++)
526    f_special->append (NULL);
527
528  lo_omp = NULL;
529  omp_functions->reset ();
530  for (int i = 0; i < OMP_LAST_STATE; i++)
531    omp_functions->append (NULL);
532
533  // make sure the metric list is initialized
534  register_metric (Metric::SIZES);
535  register_metric (Metric::ADDRESS);
536  register_metric (Metric::ONAME);
537
538  // This is needed only to maintain loadobject id's
539  // for <Total> and <Unknown> in tests 
540  (void) get_Unknown_LoadObject ();
541  (void) get_Total_LoadObject ();
542
543  // Create the data object name hash table.
544  dnameHTable = new List*[HTableSize];
545  for (int i = 0; i < HTableSize; i++)
546    dnameHTable[i] = NULL;
547
548  d_total = createDataObject ();
549  d_total->set_name (NTXT ("<Total>"));
550
551  // XXXX <Scalars> only appropriate for Program/Data-oriented analyses
552  d_scalars = createDataObject ();
553  d_scalars->set_name (GTXT ("<Scalars>"));
554
555  d_unknown = createDataObject ();
556  d_unknown->set_name (GTXT ("<Unknown>"));
557
558  // assign d_unknown's children so data_olayout has consistent sorting
559  for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++)
560    {
561      char *errcode;
562      DataObject* dobj = createDataObject ();
563      switch (pp_code)
564        {
565        case NUM_ABS_PP_CODES + 1:
566          errcode = PTXT (DOBJ_UNDETERMINED);
567          break;
568        case NUM_ABS_PP_CODES:
569          errcode = PTXT (DOBJ_UNSPECIFIED);
570          break;
571        case NUM_ABS_PP_CODES - 1:
572          errcode = PTXT (DOBJ_UNIDENTIFIED);
573          break;
574        default:
575          errcode = PTXT (ABS_PP_CODES[pp_code]);
576        }
577      dobj->parent = d_unknown;
578      dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
579    }
580
581  for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++)
582    {
583      DataObject* dobj = createDataObject ();
584      dobj->parent = d_unknown;
585      dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set
586    }
587}
588
589void
590DbeSession::reset_data ()
591{
592  for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i)
593    if (idxobjs->get (i))
594      idxobjs->get (i)->reset ();
595}
596
597void
598DbeSession::reset ()
599{
600  loadObjMap->reset ();
601  DbeView *dbev;
602  int index;
603
604  Vec_loop (DbeView*, views, index, dbev)
605  {
606    dbev->reset ();
607  }
608
609  destroy_map (DbeFile *, dbeFiles);
610  destroy_map (DbeJarFile *, dbeJarFiles);
611  exps->destroy ();
612  lobjs->reset ();      // all LoadObjects belong to objs
613  dobjs->destroy ();    // deletes d_unknown and d_total as well
614  objs->destroy ();
615  comp_lobjs->clear ();
616  comp_dbelines->clear ();
617  comp_sources->clear ();
618  sourcesMap->clear ();
619  sources->reset ();
620
621  // Delete the data object name hash table.
622  for (int i = 0; i < HTableSize; i++)
623    {
624      List *list = dnameHTable[i];
625      while (list)
626        {
627          List *tmp = list;
628          list = list->next;
629          delete tmp;
630        }
631    }
632  delete[] dnameHTable;
633
634  // IndexObect definitions remain, objects themselves may go
635  for (int i = 0; i < idxobjs->size (); ++i)
636    {
637      HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i);
638      if (v != NULL)
639        {
640          v->values ()->destroy ();
641          v->clear ();
642        }
643    }
644  init ();
645}
646
647Vector<SourceFile*> *
648DbeSession::get_sources ()
649{
650  return sources;
651}
652
653DbeFile *
654DbeSession::getDbeFile (char *filename, int filetype)
655{
656  Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile  filetype=0x%x %s\n"), filetype, filename);
657  if (strncmp (filename, NTXT ("./"), 2) == 0)
658    filename += 2;
659  DbeFile *dbeFile = dbeFiles->get (filename);
660  if (dbeFile == NULL)
661    {
662      dbeFile = new DbeFile (filename);
663      dbeFiles->put (filename, dbeFile);
664    }
665  dbeFile->filetype |= filetype;
666  return dbeFile;
667}
668
669LoadObject *
670DbeSession::get_Total_LoadObject ()
671{
672  if (lo_total == NULL)
673    {
674      lo_total = createLoadObject (NTXT ("<Total>"));
675      lo_total->dbeFile->filetype |= DbeFile::F_FICTION;
676    }
677  return lo_total;
678}
679
680Function *
681DbeSession::get_Total_Function ()
682{
683  if (f_total == NULL)
684    {
685      f_total = createFunction ();
686      f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
687      f_total->set_name (NTXT ("<Total>"));
688      Module *mod = get_Total_LoadObject ()->noname;
689      f_total->module = mod;
690      mod->functions->append (f_total);
691    }
692  return f_total;
693}
694
695LoadObject *
696DbeSession::get_Unknown_LoadObject ()
697{
698  if (lo_unknown == NULL)
699    {
700      lo_unknown = createLoadObject (GTXT ("<Unknown>"));
701      lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable
702      lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
703
704      // force creation of the <Unknown> function
705      (void) get_Unknown_Function ();
706    }
707  return lo_unknown;
708}
709
710SourceFile *
711DbeSession::get_Unknown_Source ()
712{
713  if (sf_unknown == NULL)
714    {
715      sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME);
716      sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
717      sf_unknown->flags |= SOURCE_FLAG_UNKNOWN;
718    }
719  return sf_unknown;
720}
721
722Function *
723DbeSession::get_Unknown_Function ()
724{
725  if (f_unknown == NULL)
726    {
727      f_unknown = createFunction ();
728      f_unknown->flags |= FUNC_FLAG_SIMULATED;
729      f_unknown->set_name (GTXT ("<Unknown>"));
730      Module *mod = get_Unknown_LoadObject ()->noname;
731      f_unknown->module = mod;
732      mod->functions->append (f_unknown);
733    }
734  return f_unknown;
735}
736
737// LIBRARY_VISIBILITY
738
739Function *
740DbeSession::create_hide_function (LoadObject *lo)
741{
742  Function *h_function = createFunction ();
743  h_function->set_name (lo->get_name ());
744  h_function->module = lo->noname;
745  h_function->isHideFunc = true;
746  lo->noname->functions->append (h_function);
747  return h_function;
748}
749
750Function *
751DbeSession::get_JUnknown_Function ()
752{
753  if (j_unknown == NULL)
754    {
755      j_unknown = createFunction ();
756      j_unknown->flags |= FUNC_FLAG_SIMULATED;
757      j_unknown->set_name (GTXT ("<no Java callstack recorded>"));
758      Module *mod = get_Unknown_LoadObject ()->noname;
759      j_unknown->module = mod;
760      mod->functions->append (j_unknown);
761    }
762  return j_unknown;
763}
764
765Function *
766DbeSession::get_jvm_Function ()
767{
768  if (f_jvm == NULL)
769    {
770      f_jvm = createFunction ();
771      f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
772      f_jvm->set_name (GTXT ("<JVM-System>"));
773
774      // Find the JVM LoadObject
775      LoadObject *jvm = get_Unknown_LoadObject ();
776      for (int i = 0; i < lobjs->size (); ++i)
777        {
778          LoadObject *lo = lobjs->fetch (i);
779          if (lo->flags & SEG_FLAG_JVM)
780            {
781              jvm = lo;
782              break;
783            }
784        }
785      Module *mod = jvm->noname;
786      f_jvm->module = mod;
787      mod->functions->append (f_jvm);
788      // XXXX is it required? no consistency among all special functions
789      // jvm->functions->append( f_jvm );
790    }
791  return f_jvm;
792}
793
794Function *
795DbeSession::getSpecialFunction (SpecialFunction kind)
796{
797  if (kind < 0 || kind >= LastSpecialFunction)
798    return NULL;
799
800  Function *func = f_special->fetch (kind);
801  if (func == NULL)
802    {
803      char *fname;
804      switch (kind)
805        {
806        case TruncatedStackFunc:
807          fname = GTXT ("<Truncated-stack>");
808          break;
809        case FailedUnwindFunc:
810          fname = GTXT ("<Stack-unwind-failed>");
811          break;
812        default:
813          return NULL;
814        }
815      func = createFunction ();
816      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
817      Module *mod = get_Total_LoadObject ()->noname;
818      func->module = mod;
819      mod->functions->append (func);
820      func->set_name (fname);
821      f_special->store (kind, func);
822    }
823  return func;
824}
825
826LoadObject *
827DbeSession::get_OMP_LoadObject ()
828{
829  if (lo_omp == NULL)
830    {
831      for (int i = 0, sz = lobjs->size (); i < sz; i++)
832        {
833          LoadObject *lo = lobjs->fetch (i);
834          if (lo->flags & SEG_FLAG_OMP)
835            {
836              lo_omp = lo;
837              return lo_omp;
838            }
839        }
840      lo_omp = createLoadObject (GTXT ("<OMP>"));
841      lo_omp->type = LoadObject::SEG_TEXT;
842      lo_omp->dbeFile->filetype |= DbeFile::F_FICTION;
843    }
844  return lo_omp;
845}
846
847Function *
848DbeSession::get_OMP_Function (int n)
849{
850  if (n < 0 || n >= OMP_LAST_STATE)
851    return NULL;
852
853  Function *func = omp_functions->fetch (n);
854  if (func == NULL)
855    {
856      char *fname;
857      switch (n)
858        {
859        case OMP_OVHD_STATE:
860          fname = GTXT ("<OMP-overhead>");
861          break;
862        case OMP_IDLE_STATE:
863          fname = GTXT ("<OMP-idle>");
864          break;
865        case OMP_RDUC_STATE:
866          fname = GTXT ("<OMP-reduction>");
867          break;
868        case OMP_IBAR_STATE:
869          fname = GTXT ("<OMP-implicit_barrier>");
870          break;
871        case OMP_EBAR_STATE:
872          fname = GTXT ("<OMP-explicit_barrier>");
873          break;
874        case OMP_LKWT_STATE:
875          fname = GTXT ("<OMP-lock_wait>");
876          break;
877        case OMP_CTWT_STATE:
878          fname = GTXT ("<OMP-critical_section_wait>");
879          break;
880        case OMP_ODWT_STATE:
881          fname = GTXT ("<OMP-ordered_section_wait>");
882          break;
883        case OMP_ATWT_STATE:
884          fname = GTXT ("<OMP-atomic_wait>");
885          break;
886        default:
887          return NULL;
888        }
889      func = createFunction ();
890      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
891      func->set_name (fname);
892
893      LoadObject *omp = get_OMP_LoadObject ();
894      func->module = omp->noname;
895      omp->noname->functions->append (func);
896      omp->functions->append (func);
897      omp_functions->store (n, func);
898    }
899  return func;
900}
901
902// Divide the original createExperiment() into two steps
903// In part1, we just create the data structure, in part2, if
904// we decide to keep the experiment around, add it to various
905// lists in DbeSession
906Experiment *
907DbeSession::createExperimentPart1 ()
908{
909  Experiment *exp = new Experiment ();
910  return exp;
911}
912
913void
914DbeSession::createExperimentPart2 (Experiment *exp)
915{
916  int ind = expGroups->size ();
917  if (ind > 0)
918    {
919      ExpGroup *gr = expGroups->fetch (ind - 1);
920      exp->groupId = gr->groupId;
921      gr->append (exp);
922    }
923  exp->setExpIdx (exps->size ());
924  exp->setUserExpId (++user_exp_id_counter);
925  exps->append (exp);
926}
927
928Experiment *
929DbeSession::createExperiment ()
930{
931  Experiment *exp = new Experiment ();
932  append (exp);
933  return exp;
934}
935
936void
937DbeSession::append (Experiment *exp)
938{
939  exp->setExpIdx (exps->size ());
940  exp->setUserExpId (++user_exp_id_counter);
941  exps->append (exp);
942  if (exp->founder_exp)
943    {
944      if (exp->founder_exp->children_exps == NULL)
945        exp->founder_exp->children_exps = new Vector<Experiment *>;
946      exp->founder_exp->children_exps->append (exp);
947      if (exp->founder_exp->groupId > 0)
948        {
949          exp->groupId = exp->founder_exp->groupId;
950          expGroups->get (exp->groupId - 1)->append (exp);
951        }
952    }
953  if (exp->groupId == 0)
954    {
955      long ind = VecSize (expGroups);
956      if (ind > 0)
957        {
958          ExpGroup *gr = expGroups->get (ind - 1);
959          exp->groupId = gr->groupId;
960          gr->append (exp);
961        }
962    }
963}
964
965void
966DbeSession::append (Hwcentry *h)
967{
968  if (hwcentries == NULL)
969    hwcentries = new Vector<Hwcentry*>;
970  hwcentries->append (h);
971}
972
973int
974DbeSession::ngoodexps ()
975{
976  int cnt = 0;
977  for (long i = 0, sz = VecSize (exps); i < sz; i++)
978    if (exps->get (i)->get_status () == Experiment::SUCCESS)
979      cnt++;
980  return cnt;
981}
982
983int
984DbeSession::createView (int index, int cloneindex)
985{
986  // ensure that there is no view with that index
987  DbeView *dbev = getView (index);
988  if (dbev != NULL)
989    abort ();
990
991  // find the view to be cloned
992  dbev = getView (cloneindex);
993  DbeView *newview;
994  if (dbev == NULL)
995    newview = new DbeView (theApplication, settings, index);
996  else
997    newview = new DbeView (dbev, index);
998  views->append (newview);
999  return index;
1000}
1001
1002DbeView *
1003DbeSession::getView (int index)
1004{
1005  int i;
1006  DbeView *dbev;
1007  Vec_loop (DbeView*, views, i, dbev)
1008  {
1009    if (dbev->vindex == index)
1010      return dbev;
1011  }
1012  return NULL;
1013}
1014
1015void
1016DbeSession::dropView (int index)
1017{
1018  int i;
1019  DbeView *dbev;
1020
1021  Vec_loop (DbeView*, views, i, dbev)
1022  {
1023    if (dbev->vindex == index)
1024      {
1025        views->remove (i);
1026        delete dbev;
1027        return;
1028      }
1029  }
1030  // view not found; ignore for now
1031}
1032
1033Vector<char*> *
1034DbeSession::get_group_or_expt (char *path)
1035{
1036  Vector<char*> *exp_list = new Vector<char*>;
1037  FILE *fptr;
1038  char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN];
1039
1040  fptr = fopen (path, NTXT ("r"));
1041  if (!fptr || !fgets (buf, (int) sizeof (buf), fptr)
1042      || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER)))
1043    {
1044      // it's not an experiment group
1045      new_path = dbe_strdup (path);
1046      new_path = canonical_path (new_path);
1047      exp_list->append (new_path);
1048    }
1049  else
1050    {
1051      // it is an experiment group, read the list to get them all
1052      while (fgets (buf, (int) sizeof (buf), fptr))
1053        {
1054          if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1))
1055            {
1056              new_path = dbe_strdup (name);
1057              new_path = canonical_path (new_path);
1058              exp_list->append (new_path);
1059            }
1060        }
1061    }
1062  if (fptr)
1063    fclose (fptr);
1064  return exp_list;
1065}
1066
1067#define GET_INT_VAL(v, s, len) \
1068    for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
1069
1070static int
1071dir_name_cmp (const void *a, const void *b)
1072{
1073  char *s1 = *((char **) a);
1074  char *s2 = *((char **) b);
1075  while (*s1)
1076    {
1077      if (isdigit (*s1) && isdigit (*s2))
1078        {
1079          int v1, v2, len1, len2;
1080          GET_INT_VAL (v1, s1, len1);
1081          GET_INT_VAL (v2, s2, len2);
1082          if (v1 != v2)
1083            return v1 - v2;
1084          if (len1 != len2)
1085            return len2 - len1;
1086          continue;
1087        }
1088      if (*s1 != *s2)
1089        break;
1090      s1++;
1091      s2++;
1092    }
1093  return *s1 - *s2;
1094}
1095
1096static int
1097read_experiment_data_in_parallel (void *arg)
1098{
1099  exp_ctx *ctx = (exp_ctx *) arg;
1100  Experiment *dexp = ctx->exp;
1101  bool read_ahead = ctx->read_ahead;
1102  dexp->read_experiment_data (read_ahead);
1103  free (ctx);
1104  return 0;
1105}
1106
1107void
1108DbeSession::open_experiment (Experiment *exp, char *path)
1109{
1110  exp->open (path);
1111  if (exp->get_status () != Experiment::FAILURE)
1112    exp->read_experiment_data (false);
1113  exp->open_epilogue ();
1114
1115  // Update all DbeViews 
1116  for (int i = 0, sz = views->size (); i < sz; i++)
1117    {
1118      DbeView *dbev = views->fetch (i);
1119      dbev->add_experiment (exp->getExpIdx (), true);
1120    }
1121
1122  if (exp->get_status () == Experiment::FAILURE)
1123    {
1124      check_tab_avail ();
1125      return;
1126    }
1127
1128  char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS"));
1129  int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds
1130  if (discard_tiny != NULL)
1131    {
1132      user_specified_tiny_threshold = (atoi (discard_tiny));
1133      if (user_specified_tiny_threshold < 0)
1134        user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD;
1135    }
1136
1137  // Open descendant experiments
1138  DIR *exp_dir = opendir (path);
1139  if (exp_dir == NULL)
1140    {
1141      check_tab_avail ();
1142      return;
1143    }
1144
1145  Vector<char*> *exp_names = new Vector<char*>();
1146  struct dirent *entry = NULL;
1147  while ((entry = readdir (exp_dir)) != NULL)
1148    {
1149      if (entry->d_name[0] != '_')
1150        continue;
1151      size_t len = strlen (entry->d_name);
1152      if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0)
1153        continue;
1154      exp_names->append (dbe_strdup (entry->d_name));
1155    }
1156  closedir (exp_dir);
1157  exp_names->sort (dir_name_cmp);
1158  Experiment **t_exp_list = new Experiment *[exp_names->size ()];
1159  int nsubexps = 0;
1160
1161  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
1162    {
1163      t_exp_list[j] = NULL;
1164
1165      char *lineage_name = exp_names->fetch (j);
1166      struct stat64 sbuf;
1167      char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name);
1168
1169      // look for experiments with no profile collected
1170      if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD)
1171        {
1172          char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE);
1173          int st = dbe_stat (frinfoname, &sbuf);
1174          free (frinfoname);
1175          if (st == 0)
1176            {
1177              // if no profile/trace data do not process this experiment any further
1178              if (sbuf.st_size == 0)
1179                {
1180                  free (dpath);
1181                  continue;
1182                }
1183            }
1184        }
1185      else
1186        { // check if dpath is a directory
1187          if (dbe_stat (dpath, &sbuf) != 0)
1188            {
1189              free (dpath);
1190              continue;
1191            }
1192          else if (!S_ISDIR (sbuf.st_mode))
1193            {
1194              free (dpath);
1195              continue;
1196            }
1197        }
1198      size_t lineage_name_len = strlen (lineage_name);
1199      lineage_name[lineage_name_len - 3] = 0; /* remove .er */
1200      Experiment *dexp = new Experiment ();
1201      dexp->founder_exp = exp;
1202      if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD)
1203        {
1204          dexp->setTinyThreshold (user_specified_tiny_threshold);
1205          dexp->open (dpath);
1206          if (dexp->isDiscardedTinyExperiment ())
1207            {
1208              delete dexp;
1209              free (dpath);
1210              continue;
1211            }
1212        }
1213      else
1214        dexp->open (dpath);
1215      append (dexp);
1216      t_exp_list[j] = dexp;
1217      nsubexps++;
1218      dexp->set_clock (exp->clock);
1219
1220      // DbeView add_experiment() is split into two parts
1221      // add_subexperiment() is called repeeatedly for
1222      // all sub_experiments, later add_experiment_epilogue() finishes up the task
1223      for (int i = 0, sz = views->size (); i < sz; i++)
1224        {
1225          DbeView *dbev = views->fetch (i);
1226          bool enabled = settings->check_en_desc (lineage_name, dexp->utargname);
1227          dbev->add_subexperiment (dexp->getExpIdx (), enabled);
1228        }
1229      free (dpath);
1230    }
1231
1232  for (int i = 0, sz = views->size (); i < sz; i++)
1233    {
1234      DbeView *dbev = views->fetch (i);
1235      dbev->add_experiment_epilogue ();
1236    }
1237
1238  DbeThreadPool * threadPool = new DbeThreadPool (-1);
1239  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
1240    {
1241      if (t_exp_list[j] == NULL) continue;
1242      Experiment *dexp = t_exp_list[j];
1243      exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx));
1244      new_ctx->path = NULL;
1245      new_ctx->exp = dexp;
1246      new_ctx->ds = this;
1247      new_ctx->read_ahead = true;
1248      DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx);
1249      threadPool->put_queue (q);
1250    }
1251  threadPool->wait_queues ();
1252  delete threadPool;
1253
1254  for (long j = 0, jsz = exp_names->size (); j < jsz; j++)
1255    {
1256      if (t_exp_list[j] == NULL) continue;
1257      Experiment *dexp = t_exp_list[j];
1258      dexp->open_epilogue ();
1259    }
1260  exp_names->destroy ();
1261  delete[] t_exp_list;
1262  delete exp_names;
1263
1264  // update setting for leaklist and dataspace
1265  check_tab_avail ();
1266}
1267
1268void
1269DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp)
1270{
1271  if (exp->fetch_errors () != NULL)
1272    {
1273      // yes, there were errors
1274      char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""));
1275      sb->append (path);
1276      sb->append (NTXT (": "));
1277      sb->append (ststr);
1278      free (ststr);
1279    }
1280
1281  Emsg *m = exp->fetch_warnings ();
1282  if (m != NULL)
1283    {
1284      sb->append (path);
1285      sb->append (NTXT (": "));
1286      if (!is_interactive ())
1287        sb->append (GTXT ("Experiment has warnings, see header for details\n"));
1288      else
1289        sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n"));
1290    }
1291
1292  // Check for descendant experiments that are not loaded
1293  int num_desc = VecSize (exp->children_exps);
1294  if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL))
1295    {
1296      char *s;
1297      if (!is_interactive ())
1298        s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc);
1299      else
1300        s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc);
1301      sb->append (path);
1302      sb->append (NTXT (": "));
1303      sb->append (s);
1304      free (s);
1305    }
1306}
1307
1308Experiment *
1309DbeSession::get_exp (int exp_ind)
1310{
1311  if (exp_ind < 0 || exp_ind >= exps->size ())
1312    return NULL;
1313  Experiment *exp = exps->fetch (exp_ind);
1314  exp->setExpIdx (exp_ind);
1315  return exp;
1316}
1317
1318Vector<Vector<char*>*> *
1319DbeSession::getExperimensGroups ()
1320{
1321  if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0)
1322    return NULL;
1323  bool compare_mode = expGroups->size () > 1;
1324  Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> (
1325                                         compare_mode ? expGroups->size () : 1);
1326  for (int i = 0; i < expGroups->size (); i++)
1327    {
1328      ExpGroup *grp = expGroups->fetch (i);
1329      Vector<Experiment*> *founders = grp->get_founders ();
1330      if (founders && founders->size () != 0)
1331        {
1332          Vector<char *> *names = new Vector<char*> (founders->size ());
1333          for (int j = 0; j < founders->size (); j++)
1334            {
1335              Experiment *exp = founders->fetch (j);
1336              names->append (dbe_strdup (exp->get_expt_name ()));
1337            }
1338          if (compare_mode || groups->size () == 0)
1339            groups->append (names);
1340          else
1341            groups->fetch (0)->addAll (names);
1342        }
1343      delete founders;
1344    }
1345  return groups;
1346}
1347
1348char *
1349DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups)
1350{
1351  StringBuilder sb;
1352  for (int i = 0; i < groups->size (); i++)
1353    {
1354      Vector<char *> *names = groups->fetch (i);
1355      ExpGroup *grp;
1356      if (names->size () == 1)
1357        grp = new ExpGroup (names->fetch (0));
1358      else
1359        {
1360          char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1);
1361          grp = new ExpGroup (nm);
1362          free (nm);
1363        }
1364      expGroups->append (grp);
1365      grp->groupId = expGroups->size ();
1366
1367      for (int j = 0; j < names->size (); j++)
1368        {
1369          char *path = names->fetch (j);
1370          size_t len = strlen (path);
1371          if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg")))
1372            {
1373              Vector<char*> *lst = get_group_or_expt (path);
1374              for (int j1 = 0; j1 < lst->size (); j1++)
1375                {
1376                  Experiment *exp = new Experiment ();
1377                  append (exp);
1378                  open_experiment (exp, lst->get (j1));
1379                  if (exp->get_status () == Experiment::FAILURE)
1380                    append_mesgs (&sb, path, exp);
1381                }
1382              lst->destroy ();
1383              delete lst;
1384            }
1385          else
1386            {
1387              Experiment *exp = new Experiment ();
1388              append (exp);
1389              open_experiment (exp, path);
1390              if (exp->get_status () == Experiment::FAILURE)
1391                append_mesgs (&sb, path, exp);
1392            }
1393        }
1394    }
1395
1396  for (int i = 0, sz = views->size (); i < sz; i++)
1397    {
1398      DbeView *dbev = views->fetch (i);
1399      dbev->update_advanced_filter ();
1400      int cmp = dbev->get_settings ()->get_compare_mode ();
1401      dbev->set_compare_mode (CMP_DISABLE);
1402      dbev->set_compare_mode (cmp);
1403    }
1404  return sb.length () == 0 ? NULL : sb.toString ();
1405}
1406
1407char *
1408DbeSession::drop_experiment (int exp_ind)
1409{
1410  DbeView *dbev;
1411  int index;
1412  Experiment *exp2;
1413
1414  status_ompavail = -1;
1415  Experiment *exp = exps->fetch (exp_ind);
1416
1417  // If this is a sub experiment, don't do it
1418  if (exp->founder_exp != NULL)     // this is a sub experiment; don't do it
1419    return (dbe_strdup (GTXT ("Can not drop subexperiments")));
1420
1421  if (VecSize (exp->children_exps) > 0)
1422    for (;;)
1423      {
1424        // search the list of experiments to find all that have this one as founder
1425        bool found = false;
1426        Vec_loop (Experiment*, exps, index, exp2)
1427        {
1428          if (exp2->founder_exp == exp)
1429            {
1430              exp2->founder_exp = NULL;
1431              drop_experiment (index);
1432              found = true;
1433              break;
1434            }
1435        }
1436        if (found == false)
1437          break;
1438      }
1439
1440  // then proceed to finish the drop
1441  Vec_loop (DbeView*, views, index, dbev)
1442  {
1443    dbev->drop_experiment (exp_ind);
1444  }
1445
1446  int old_cnt = expGroups->size ();
1447  for (int i = 0; i < old_cnt; i++)
1448    {
1449      ExpGroup *gr = expGroups->fetch (i);
1450      if (gr->groupId == exp->groupId)
1451        {
1452          gr->drop_experiment (exp);
1453          if ((gr->founder == NULL) && (gr->exps->size () == 0))
1454            {
1455              delete gr;
1456              expGroups->remove (i);
1457            }
1458          break;
1459        }
1460    }
1461  delete exps->remove (exp_ind);
1462  if (old_cnt != expGroups->size ())
1463    {
1464      for (int i = 0, sz = expGroups->size (); i < sz; i++)
1465        {
1466          ExpGroup *gr = expGroups->fetch (i);
1467          gr->groupId = i + 1;
1468          Vector<Experiment*> *expList = gr->exps;
1469          for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++)
1470            expList->fetch (i1)->groupId = gr->groupId;
1471        }
1472      for (int i = 0, sz = views->size (); i < sz; i++)
1473        {
1474          dbev = views->fetch (i);
1475          int cmp = dbev->get_compare_mode ();
1476          dbev->set_compare_mode (CMP_DISABLE);
1477          dbev->set_compare_mode (cmp);
1478        }
1479    }
1480  check_tab_avail ();   // update tab availability
1481  return NULL;
1482}
1483
1484int
1485DbeSession::find_experiment (char *path)
1486{
1487  Experiment *exp;
1488  int index;
1489  Vec_loop (Experiment*, exps, index, exp)
1490  {
1491    if (strcmp (exp->get_expt_name (), path) == 0)
1492      return exp->getExpIdx ();
1493  }
1494  return -1;
1495}
1496
1497LoadObject *
1498DbeSession::createLoadObject (const char *nm, int64_t cksum)
1499{
1500  return loadObjMap->sync_create_item (nm, cksum);
1501}
1502
1503LoadObject *
1504DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df)
1505{
1506  return loadObjMap->sync_create_item (nm, runTimePath, df);
1507}
1508
1509void
1510DbeSession::append (LoadObject *lobj)
1511{
1512  Histable *obj = lobj; // workaround for a C++ problem
1513  objs->append (obj);
1514  lobj->id = objs->size () - 1;
1515  lobjs->append (lobj);
1516  lobj->seg_idx = lobjs->size () - 1;
1517  char *loname = lobj->get_pathname ();
1518  dbeFiles->put (loname, lobj->dbeFile);
1519}
1520
1521DbeJarFile *
1522DbeSession::get_JarFile (const char *name)
1523{
1524  DbeJarFile *jf = dbeJarFiles->get (name);
1525  if (jf == NULL)
1526    {
1527      jf = new DbeJarFile (name);
1528      dbeJarFiles->put (name, jf);
1529    }
1530  return jf;
1531}
1532
1533Module *
1534DbeSession::createModule (LoadObject *lo, const char *nm)
1535{
1536  Module *mod = new Module ();
1537  Histable *obj = mod; // workaround for a C++ problem
1538  objs->append (obj);
1539  mod->id = objs->size () - 1;
1540  mod->loadobject = lo;
1541  mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME));
1542  lo->seg_modules->append (mod);
1543  return mod;
1544}
1545
1546Module *
1547DbeSession::createUnknownModule (LoadObject *lo)
1548{
1549  Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME);
1550  mod->flags |= MOD_FLAG_UNKNOWN;
1551  mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME));
1552  return mod;
1553}
1554
1555SourceFile *
1556DbeSession::createSourceFile (const char *_path)
1557{
1558  char *path = (char *) _path;
1559  if (strncmp (path, NTXT ("./"), 2) == 0)
1560    path += 2;
1561  SourceFile *source = sourcesMap->get (path);
1562  if (source == NULL)
1563    {
1564      source = new SourceFile (path);
1565      (void) sourcesMap->put (path, source);
1566      append (source);
1567    }
1568  return source;
1569}
1570
1571Function *
1572DbeSession::createFunction ()
1573{
1574  Function *func = new Function (objs->size ());
1575  Histable *obj = func; // workaround for a C++ problem
1576  objs->append (obj);
1577  return func;
1578}
1579
1580JMethod *
1581DbeSession::createJMethod ()
1582{
1583  JMethod *jmthd = new JMethod (objs->size ());
1584  Histable *obj = jmthd; // workaround for a C++ problem
1585  objs->append (obj);
1586  return jmthd;
1587}
1588
1589Module *
1590DbeSession::createClassFile (char *className)
1591{
1592  ClassFile *cls = new ClassFile ();
1593  cls->set_name (className);
1594  char *clpath = cls->get_java_file_name (className, true);
1595  cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS);
1596  free (clpath);
1597  Histable *obj = cls; // workaround for a C++ problem
1598  objs->append (obj);
1599  cls->id = objs->size () - 1;
1600  return cls;
1601}
1602
1603Histable *
1604DbeSession::createHistObject (Histable::Type type)
1605{
1606  switch (type)
1607    {
1608    case Histable::DOBJECT:
1609      {
1610        DataObject *dataobj = new DataObject ();
1611        dobjs->append (dataobj);
1612        dataobj->id = dobjs->size () - 1;
1613        return dataobj;
1614      }
1615    default:
1616      assert (0);
1617    }
1618  return NULL;
1619}
1620
1621DataObject *
1622DbeSession::createDataObject ()
1623{
1624  DataObject *dataobj = new DataObject ();
1625  dobjs->append (dataobj);
1626  dataobj->id = dobjs->size () - 1;
1627  return dataobj;
1628}
1629
1630DataObject *
1631DbeSession::createDataObject (DataObject *dobj, DataObject *parent)
1632{
1633  DataObject *dataobj = new DataObject ();
1634  dataobj->size = dobj->size;
1635  dataobj->offset = dobj->offset;
1636  dataobj->parent = parent;
1637  dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ());
1638  dobjs->append (dataobj);
1639  dataobj->id = dobjs->size () - 1;
1640  return dataobj;
1641}
1642
1643DataObject *
1644DbeSession::createMasterDataObject (DataObject *dobj)
1645{
1646  DataObject *parent = NULL;
1647  if (dobj->parent)
1648    { // define master parent first
1649      parent = find_dobj_master (dobj->parent);
1650      if (!parent)
1651        { // clone master from this dataobject parent
1652          parent = createDataObject (dobj->parent);
1653          parent->scope = NULL; // master is scope-less
1654          Dprintf (DEBUG_DATAOBJ,
1655                   "Master DataObject(%llu) cloned from (%llu) %s\n",
1656                   (ull_t) parent->id, (ull_t) dobj->parent->id,
1657                   dobj->parent->get_name ());
1658          // clone master DataObject elements
1659          Vector<DataObject*> *delem = get_dobj_elements (dobj->parent);
1660          int element_index = 0;
1661          DataObject *element = NULL;
1662          Vec_loop (DataObject*, delem, element_index, element)
1663          {
1664            DataObject *master_element = createDataObject (element, parent);
1665            master_element->scope = NULL; // master is scope-less
1666            Dprintf (DEBUG_DATAOBJ,
1667                     "Member DataObject(%llu) cloned from (%llu) %s\n",
1668                     (ull_t) master_element->id, (ull_t) element->id,
1669                     element->get_name ());
1670          }
1671        }
1672      else
1673        Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
1674                 (ull_t) parent->id, (ull_t) dobj->parent->id,
1675                 dobj->parent->get_name ());
1676    }
1677
1678  DataObject *master = find_dobj_master (dobj);
1679  if (!master)
1680    { // clone master from this dataobject
1681      master = createDataObject (dobj, parent);
1682      master->scope = NULL; // master is scope-less
1683      Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n",
1684               (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
1685    }
1686  else
1687    Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
1688             (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
1689  return master;
1690}
1691
1692void
1693DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist)
1694{
1695  if ((mtr->get_flavors () & Metric::STATIC) == 0)
1696    {
1697      // insert in front of the first STATIC
1698      for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++)
1699        {
1700          BaseMetric *m = mlist->fetch (i);
1701          if (m->get_flavors () & Metric::STATIC)
1702            {
1703              mlist->insert (i, mtr);
1704              return;
1705            }
1706        }
1707    }
1708  mlist->append (mtr);
1709}
1710
1711BaseMetricTreeNode*
1712DbeSession::get_reg_metrics_tree ()
1713{
1714  if (reg_metrics_tree == NULL)
1715    // Can't init earlier because BaseMetric() requires DbeSession::ql_parse
1716    reg_metrics_tree = new BaseMetricTreeNode ();
1717  return reg_metrics_tree;
1718}
1719
1720void
1721DbeSession::update_metric_tree (BaseMetric *m)
1722{
1723  get_reg_metrics_tree ()->register_metric (m);
1724}
1725
1726BaseMetric *
1727DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
1728{
1729  BaseMetric *m = find_metric (type, cmd, expr_spec);
1730  if (m)
1731    return m;
1732  BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version
1733  m = new BaseMetric (*bm);
1734  m->set_expr_spec (expr_spec);
1735  insert_metric (m, reg_metrics);
1736  return m;
1737}
1738
1739BaseMetric *
1740DbeSession::register_metric (BaseMetric::Type type)
1741{
1742  BaseMetric *m = find_metric (type, NULL, NULL);
1743  if (m)
1744    return m;
1745  m = new BaseMetric (type);
1746  insert_metric (m, reg_metrics);
1747  update_metric_tree (m);
1748  return m;
1749}
1750
1751BaseMetric *
1752DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username)
1753{
1754  BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL);
1755  if (m)
1756    // That may be a problem when metrics aren't an exact match.
1757    // For example, memoryspace is disabled in one experiment and not in another.
1758    return m;
1759  if (ctr->timecvt)
1760    {
1761      char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux);
1762      char *time_username = dbe_sprintf (GTXT ("%s Time"),
1763                                       ctr->metric ? ctr->metric :
1764                                       (ctr->name ? ctr->name : ctr->int_name));
1765      BaseMetric *m1;
1766      if (ipc_mode)
1767        {
1768          // Two visible metrics are presented in GUI
1769          m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL);
1770          insert_metric (m1, reg_metrics);
1771          update_metric_tree (m1);
1772          m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1);
1773        }
1774      else
1775        {
1776          // Only one visible metric is presented in er_print
1777          m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL);
1778          insert_metric (m1, reg_metrics);
1779          m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1);
1780        }
1781      free (time_cmd);
1782      free (time_username);
1783    }
1784  else
1785    m = new BaseMetric (ctr, aux, username, VAL_VALUE);
1786  insert_metric (m, reg_metrics);
1787  update_metric_tree (m);
1788  return m;
1789}
1790
1791BaseMetric *
1792DbeSession::register_metric (char *name, char *username, char *_def)
1793{
1794  BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL);
1795  if (m)
1796    return m;
1797  Definition *p = Definition::add_definition (_def);
1798  if (p == NULL)
1799    return NULL;
1800  m = new BaseMetric (name, username, p);
1801  insert_metric (m, reg_metrics);
1802  update_metric_tree (m);
1803  return m;
1804}
1805
1806void
1807DbeSession::drop_metric (BaseMetric *mtr)
1808{
1809  Countable *cnt;
1810  int index;
1811
1812  Vec_loop (Countable*, metrics, index, cnt)
1813  {
1814    if (mtr == (BaseMetric *) cnt->item)
1815      {
1816        cnt->ref_count--;
1817        if (cnt->ref_count == 0)
1818          {
1819            // Remove this metric from all views
1820            DbeView *dbev;
1821            int index2;
1822            Vec_loop (DbeView*, views, index2, dbev)
1823            {
1824              dbev->reset_metrics ();
1825            }
1826            delete metrics->remove (index);
1827            delete mtr;
1828            return;
1829          }
1830      }
1831  }
1832}
1833
1834BaseMetric *
1835DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec)
1836{
1837  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
1838    {
1839      BaseMetric *bm = reg_metrics->fetch (i);
1840      if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0)
1841        {
1842          if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR)
1843               && dbe_strcmp (bm->get_cmd (), cmd) != 0)
1844            continue;
1845          return bm;
1846        }
1847    }
1848  return NULL;
1849}
1850
1851BaseMetric *
1852DbeSession::find_base_reg_metric (char * mcmd)
1853{
1854  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
1855    {
1856      BaseMetric *bm = reg_metrics->fetch (i);
1857      if (bm->get_expr_spec () != NULL)
1858        continue; // skip compare metrics
1859      if (dbe_strcmp (bm->get_cmd (), mcmd) == 0)
1860        return bm;
1861    }
1862  return NULL;
1863}
1864
1865Vector<BaseMetric*> *
1866DbeSession::get_base_reg_metrics ()
1867{
1868  Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>;
1869  Vector<BaseMetric*> *ml = get_all_reg_metrics ();
1870  for (int i = 0, sz = ml->size (); i < sz; i++)
1871    {
1872      BaseMetric *m = ml->fetch (i);
1873      if (m->get_expr_spec () == NULL)
1874        mlist->append (m);
1875    }
1876  return mlist;
1877}
1878
1879void
1880DbeSession::check_tab_avail ()
1881{
1882  DbeView *dbev;
1883  int index;
1884  // tell the views to update their tab lists
1885  Vec_loop (DbeView*, views, index, dbev)
1886  {
1887    dbev->get_settings ()->updateTabAvailability ();
1888  }
1889}
1890
1891bool
1892DbeSession::is_datamode_available ()
1893{
1894  Experiment *exp;
1895  int index;
1896  Vec_loop (Experiment*, exps, index, exp)
1897  {
1898    if (exp->dataspaceavail)
1899      return true;
1900  }
1901  return false;
1902}
1903
1904bool
1905DbeSession::is_leaklist_available ()
1906{
1907  Experiment *exp;
1908  int index;
1909  Vec_loop (Experiment*, exps, index, exp)
1910  {
1911    if (exp->leaklistavail)
1912      return true;
1913  }
1914  return false;
1915}
1916
1917bool
1918DbeSession::is_heapdata_available ()
1919{
1920  Experiment *exp;
1921  int index;
1922  Vec_loop (Experiment*, exps, index, exp)
1923  {
1924    if (exp->heapdataavail)
1925      return true;
1926  }
1927  return false;
1928}
1929
1930bool
1931DbeSession::is_iodata_available ()
1932{
1933  Experiment *exp;
1934  int index;
1935  Vec_loop (Experiment*, exps, index, exp)
1936  {
1937    if (exp->iodataavail)
1938      return true;
1939  }
1940  return false;
1941}
1942
1943bool
1944DbeSession::is_racelist_available ()
1945{
1946  Experiment *exp;
1947  int index;
1948  Vec_loop (Experiment*, exps, index, exp)
1949  {
1950    if (exp->racelistavail)
1951      return true;
1952  }
1953  return false;
1954}
1955
1956bool
1957DbeSession::is_deadlocklist_available ()
1958{
1959  Experiment *exp;
1960  int index;
1961  Vec_loop (Experiment*, exps, index, exp)
1962  {
1963    if (exp->deadlocklistavail)
1964      return true;
1965  }
1966  return false;
1967}
1968
1969bool
1970DbeSession::is_timeline_available ()
1971{
1972  Experiment *exp;
1973  int index;
1974  Vec_loop (Experiment*, exps, index, exp)
1975  {
1976    if (exp->timelineavail)
1977      return true;
1978  }
1979  return false;
1980}
1981
1982bool
1983DbeSession::is_ifreq_available ()
1984{
1985  Experiment *exp;
1986  int index;
1987  Vec_loop (Experiment*, exps, index, exp)
1988  {
1989    if (exp->ifreqavail)
1990      return true;
1991  }
1992  return false;
1993}
1994
1995bool
1996DbeSession::is_omp_available ()
1997{
1998  if (status_ompavail == -1)
1999    {
2000      status_ompavail = 0;
2001      for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
2002        {
2003          Experiment *exp = exps->fetch (i);
2004          if (exp->ompavail)
2005            {
2006              status_ompavail = 1;
2007              break;
2008            }
2009        }
2010    }
2011  return status_ompavail == 1;
2012}
2013
2014bool
2015DbeSession::has_java ()
2016{
2017  int status_has_java = 0;
2018  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
2019    {
2020      Experiment *exp = exps->fetch (i);
2021      if (exp->has_java)
2022        {
2023          status_has_java = 1;
2024          break;
2025        }
2026    }
2027  return status_has_java == 1;
2028}
2029
2030bool
2031DbeSession::has_ompavail ()
2032{
2033  int status_has_ompavail = 0;
2034  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
2035    {
2036      Experiment *exp = exps->fetch (i);
2037      if (exp->ompavail)
2038        {
2039          status_has_ompavail = 1;
2040          break;
2041        }
2042    }
2043  return status_has_ompavail == 1;
2044}
2045
2046int
2047DbeSession::get_clock (int whichexp)
2048{
2049  // XXXX clock frequency should be an attribute of each CPU,
2050  // XXX  and not a property of the session
2051  // if whichexp is -1, pick the first exp that has a clock
2052  // otherwise return the clock from the numbered experiment
2053  Experiment *exp;
2054  if (whichexp != -1)
2055    {
2056      exp = get_exp (whichexp);
2057      if (exp != NULL)
2058        return exp->clock;
2059      return 0;
2060    }
2061  int n = nexps ();
2062  for (int i = 0; i < n; i++)
2063    {
2064      exp = get_exp (i);
2065      if (exp != NULL && exp->clock != 0)
2066        return exp->clock;
2067    }
2068  return 0;
2069}
2070
2071LoadObject *
2072DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum)
2073{
2074  return loadObjMap->get (lobj_name, cksum);
2075}
2076
2077static unsigned
2078hash (char *s)
2079{
2080  unsigned res = 0;
2081  for (int i = 0; i < 64 && *s; i++)
2082    res = res * 13 + *s++;
2083  return res;
2084}
2085
2086// This method is introduced to fix performance
2087// problems with the data space profiling in the
2088// current release. A better design is desired.
2089void
2090DbeSession::dobj_updateHT (DataObject *dobj)
2091{
2092  unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize;
2093  List *list = new List;
2094  list->val = (void*) dobj;
2095  list->next = dnameHTable[index];
2096  dnameHTable[index] = list;
2097}
2098
2099DataObject *
2100DbeSession::find_dobj_by_name (char *dobj_name)
2101{
2102  unsigned index = hash (dobj_name) % HTableSize;
2103  List *list = dnameHTable[index];
2104  for (; list; list = list->next)
2105    {
2106      DataObject *d = (DataObject*) list->val;
2107      if (strcmp (d->get_unannotated_name (), dobj_name) == 0)
2108        return d;
2109    }
2110  return (DataObject *) NULL;
2111}
2112
2113DataObject *
2114DbeSession::find_dobj_match (DataObject *dobj)
2115{
2116  char *dobj_name = dobj->get_unannotated_name ();
2117  unsigned index = hash (dobj_name) % HTableSize;
2118  List *list = dnameHTable[index];
2119  for (; list; list = list->next)
2120    {
2121      DataObject *d = (DataObject*) list->val;
2122      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
2123          && d->size == dobj->size && d->offset == dobj->offset
2124          && d->scope == dobj->scope)
2125        return d;
2126    }
2127  return (DataObject *) NULL;
2128}
2129
2130DataObject *
2131DbeSession::find_dobj_master (DataObject *dobj)
2132{
2133  char *dobj_name = dobj->get_unannotated_name ();
2134  unsigned index = hash (dobj_name) % HTableSize;
2135  List *list = dnameHTable[index];
2136  for (; list; list = list->next)
2137    {
2138      DataObject *d = (DataObject*) list->val;
2139      // XXXX should parent also match?
2140      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
2141          && d->size == dobj->size && d->offset == dobj->offset
2142          && d->master == NULL && d->scope == NULL)
2143        return d;
2144    }
2145  return (DataObject *) NULL;
2146}
2147
2148Vector<DataObject*>*
2149DbeSession::get_dobj_elements (DataObject *dobj)
2150{
2151  DataObject *d;
2152  int index;
2153  Vector<DataObject*> *elements = new Vector<DataObject*>;
2154  if (dobj == d_total)
2155    return elements;
2156  Vec_loop (DataObject*, dobjs, index, d)
2157  {
2158    if (d->get_parent () && d->get_parent () == dobj)
2159      elements->append (d);
2160  }
2161  return elements;
2162}
2163
2164Vector<LoadObject*>*
2165DbeSession::get_text_segments ()
2166{
2167  LoadObject *lo;
2168  int index;
2169  Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>;
2170  Vec_loop (LoadObject*, lobjs, index, lo)
2171  {
2172    if (lo->type == LoadObject::SEG_TEXT)
2173      tlobjs->append (lo);
2174  }
2175  return tlobjs;
2176}
2177
2178static long long
2179getNumber (const char *s, char * &last)
2180{
2181  long long val;
2182  char *sp;
2183  errno = 0;
2184  val = strtoll (s, &sp, 0);
2185  if (errno == EINVAL)
2186    last = NULL;
2187  else
2188    {
2189      while (isspace (*sp))
2190        sp++;
2191      last = sp;
2192    }
2193  return (val);
2194}
2195
2196bool
2197DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj,
2198                      char *name, const char *sel, Histable::Type type, bool xdefault)
2199{
2200  Vector<Histable*> *obj_lst;
2201  int which = -1;
2202  char *last = NULL;
2203  if (type != Histable::FUNCTION && sel)
2204    {
2205      // check that a number has been provided
2206      which = (int) getNumber (sel, last);
2207      if (last == NULL || *last != '\0')
2208        {
2209          fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
2210          sel = NULL;
2211          which = 0;
2212        }
2213      which--;
2214    }
2215  obj_lst = new Vector<Histable*>;
2216  switch (type)
2217    {
2218    case Histable::FUNCTION:
2219      obj = map_NametoFunction (name, obj_lst, sel);
2220      break;
2221    case Histable::MODULE:
2222      obj = map_NametoModule (name, obj_lst, which);
2223      break;
2224    case Histable::LOADOBJECT:
2225      obj = map_NametoLoadObject (name, obj_lst, which);
2226      break;
2227    case Histable::DOBJECT:
2228      obj = map_NametoDataObject (name, obj_lst, which);
2229      break;
2230    default:
2231      abort (); // unexpected Histable!
2232    }
2233
2234  if ((obj == NULL) && (obj_lst->size () > 0))
2235    {
2236      if (obj_lst->size () == 1)
2237        which = 0;
2238      else
2239        {
2240          if (sel && (which < 0 || which >= obj_lst->size ()))
2241            fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
2242          if (xdefault)
2243            {
2244              fprintf (stderr, GTXT ("Default selection \"1\" made\n"));
2245              which = 0;
2246            }
2247          else
2248            {
2249              which = ask_which (dis_file, inp_file, obj_lst, name);
2250              if (which == -1)
2251                {
2252                  delete obj_lst;
2253                  return false;
2254                }
2255            }
2256        }
2257      obj = obj_lst->fetch (which);
2258    }
2259  delete obj_lst;
2260  return true;
2261}
2262
2263int
2264DbeSession::ask_which (FILE *dis_file, FILE *inp_file,
2265                       Vector<Histable*> *list, char *name)
2266{
2267  Histable *hitem;
2268  Function *func;
2269  Module *module;
2270  int which, index, index1;
2271  char *item_name, *lo_name, *fname, *last;
2272  char buf[BUFSIZ];
2273  for (;;)
2274    {
2275      fprintf (dis_file, GTXT ("Available name list:\n"));
2276      fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0);
2277      Vec_loop (Histable*, list, index, hitem)
2278      {
2279        index1 = index + 1;
2280        item_name = hitem->get_name ();
2281        switch (hitem->get_type ())
2282          {
2283          case Histable::FUNCTION:
2284            func = (Function *) hitem;
2285            module = func->module;
2286
2287            // id == -1 indicates er_src invocation
2288            if (module == NULL || (module->lang_code == Sp_lang_java
2289                                   && module->loadobject->id == -1))
2290                fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
2291            else
2292              {
2293                lo_name = module->loadobject->get_pathname ();
2294                fname = (module->file_name && *module->file_name) ?
2295                        module->file_name : module->get_name ();
2296                if (fname && *fname)
2297                  fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1,
2298                           item_name, lo_name, (ull_t) func->img_offset, fname);
2299                else
2300                  fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1,
2301                           item_name, lo_name, (ull_t) func->img_offset);
2302              }
2303            break;
2304          case Histable::MODULE:
2305            module = (Module *) hitem;
2306            lo_name = module->loadobject->get_pathname ();
2307            if (name[strlen (name) - 1] ==
2308                module->file_name[strlen (module->file_name) - 1])
2309              fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1,
2310                       module->file_name, lo_name);
2311            else
2312              fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name,
2313                       lo_name);
2314            break;
2315          default:
2316            fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
2317            break;
2318          }
2319      }
2320      if (inp_file != stdin)
2321        return -1;
2322      fprintf (dis_file, GTXT ("Enter selection: "));
2323      if (fgets (buf, (int) sizeof (buf), inp_file) == NULL)
2324        {
2325          fprintf (stderr, GTXT ("Error: Invalid number entered:\n"));
2326          return -1;
2327        }
2328      which = (int) getNumber (buf, last);
2329      if (last && *last == '\0')
2330        if (which >= 0 && which <= list->size ())
2331          return which - 1;
2332      fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf);
2333    }
2334}
2335
2336static bool
2337match_basename (char *name, char *full_name, int len = -1)
2338{
2339  if (full_name == NULL)
2340    return false;
2341  if (!strchr (name, '/'))
2342    full_name = get_basename (full_name);
2343  if (len == -1)
2344    return streq (name, full_name);
2345  return strncmp (name, full_name, len) == 0;
2346}
2347
2348LoadObject *
2349DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which)
2350{
2351  // Search the tree to find the first module whose module name
2352  //	matches "name" or whose source file name matches "name"
2353  //  Issues: is the name a pathname, or a base name?
2354  //	Should we look at suffix to disambiguate?
2355  LoadObject *loitem;
2356  int index;
2357  Vec_loop (LoadObject*, lobjs, index, loitem)
2358  {
2359    // try pathname first
2360    // if failed, try object name next
2361    if (match_basename (name, loitem->get_pathname ()) ||
2362        match_basename (name, loitem->get_name ()))
2363      {
2364        if (which == list->size ())
2365          return loitem;
2366        list->append (loitem);
2367      }
2368  }
2369  return (LoadObject *) NULL;
2370}
2371
2372Module *
2373DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which)
2374{
2375  // Search the tree to find the first loadobject whose loadobject name
2376  //	matches "name".
2377
2378  //  Issues: is the name a pathname, or a base name?
2379  //	Should we look at suffix to disambiguate?
2380  LoadObject *loitem;
2381  Module *mitem;
2382  int index1, index2;
2383  Vec_loop (LoadObject*, lobjs, index1, loitem)
2384  {
2385    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
2386    {
2387      // try source name first
2388      // if failed, try object name next
2389      if (match_basename (name, mitem->file_name) ||
2390          match_basename (name, mitem->get_name ()))
2391        {
2392          if (which == list->size ())
2393            return mitem;
2394          list->append (mitem);
2395        }
2396    }
2397  }
2398  return (Module *) NULL;
2399}
2400
2401Function *
2402DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list,
2403                                const char *sel)
2404{
2405  // Search the tree to find the first function whose
2406  //	name matches "name".
2407  //  Issues: is the name a full name, or a short name?
2408  //	Is it a demangled name?  If so, what about spaces
2409  //		within the name?
2410  //	Is there a way to return all names that match?
2411  //	How can the user specify a particular function of that name?
2412  LoadObject *loitem;
2413  Function *fitem, *main_func = NULL;
2414  Module *mitem, *main_mod = NULL;
2415  int index1, index2, index3, which = -1;
2416  if (sel)
2417    {
2418      char *last = NULL;
2419      if (*sel == '@')
2420        { // 'sel' is "@seg_num:address"
2421          which = (int) getNumber (sel + 1, last);
2422          if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ()))
2423            {
2424              fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
2425              return NULL;
2426            }
2427          uint64_t address = getNumber (last + 1, last);
2428          if (last == NULL || *last != '\0')
2429            {
2430              fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
2431              return NULL;
2432            }
2433          loitem = lobjs->fetch (which);
2434          Vec_loop (Module*, loitem->seg_modules, index2, mitem)
2435          {
2436            Vec_loop (Function*, mitem->functions, index3, fitem)
2437            {
2438              if (address == fitem->img_offset && match_FName (name, fitem))
2439                return fitem;
2440            }
2441          }
2442          return NULL;
2443        }
2444
2445      which = (int) getNumber (sel, last);
2446      if (last == NULL || *last != '\0')
2447        {
2448          fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
2449          return NULL;
2450        }
2451      which--;
2452    }
2453
2454  int len_path = 0;
2455  char *with_path = name;
2456  name = StrRchr (name, '`');
2457  if (name != with_path)
2458    len_path = (int) (name - with_path);
2459  else
2460    with_path = NULL;
2461
2462  Vec_loop (LoadObject*, lobjs, index1, loitem)
2463  {
2464    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
2465    {
2466      if (with_path)
2467        { // with file name
2468          // try source name first
2469          // if failed, try object name next
2470          if (!match_basename (with_path, mitem->file_name, len_path) &&
2471              !match_basename (with_path, mitem->get_name (), len_path))
2472            continue;
2473        }
2474      Vec_loop (Function*, mitem->functions, index3, fitem)
2475      {
2476        if (match_FName (name, fitem))
2477          {
2478            if (which == list->size ())
2479              return fitem;
2480            list->append (fitem);
2481            continue;
2482          }
2483        if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ())
2484          {
2485            main_func = fitem;
2486            main_mod = mitem;
2487          }
2488      }
2489    }
2490  }
2491
2492  if (main_mod && main_func)
2493    {
2494      main_mod->read_stabs ();
2495      if (streq (main_func->get_match_name (), name) && which <= 1)
2496        return main_func;
2497    }
2498  return (Function *) NULL;
2499}
2500
2501DataObject *
2502DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list,
2503                                  int which)
2504{
2505  // Search master list to find dataobjects whose names match "name"
2506  // selecting only the entry corresponding to "which" if it is not -1.
2507  // Issues: is the name fully qualified or only partially?
2508  DataObject *ditem = NULL;
2509  int index;
2510  char *full_name;
2511  Vec_loop (DataObject*, dobjs, index, ditem)
2512  {
2513    if (ditem->scope) continue; // skip non-master dataobjects
2514
2515    // try fully-qualified dataobject name first
2516    if ((full_name = ditem->get_name ()) != NULL)
2517      {
2518        if (streq (name, full_name))
2519          {
2520            if (which == list->size ())
2521              return ditem;
2522            list->append (ditem);
2523          }
2524      }
2525  }
2526  if (list->size () > 0)
2527    return ditem; // return fully-qualified match
2528
2529  // if fully-qualified name doesn't match anything, try a partial match
2530  Vec_loop (DataObject*, dobjs, index, ditem)
2531  {
2532    if (ditem->scope) continue; // skip non-master dataobjects
2533
2534    // try fully-qualified dataobject name first
2535    if ((full_name = ditem->get_name ()) != NULL)
2536      {
2537        if (strstr (full_name, name))
2538          {
2539            if (which == list->size ())
2540              return ditem;
2541            list->append (ditem);
2542          }
2543      }
2544  }
2545  return (DataObject *) NULL;
2546}
2547
2548bool
2549DbeSession::match_FName (char *name, Function *func)
2550{
2551  size_t len;
2552  char buf[MAXDBUF];
2553  char *full_name;
2554  if (streq (func->get_name (), name)) // try full name comparison
2555    return true;
2556  if (streq (func->get_mangled_name (), name)) // try mangled name
2557    return true;
2558  if (streq (func->get_match_name (), name)) // try match name
2559    return true;
2560
2561  Module *md = func->module; // try FORTRAN name
2562  if (md && md->is_fortran ())
2563    {
2564      char *mangled_name = func->get_mangled_name ();
2565      len = strlen (name);
2566      if (((len + 1) == strlen (mangled_name)) &&
2567          (strncmp (name, mangled_name, len) == 0))
2568        return true;
2569    }
2570  snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ());
2571  full_name = buf;
2572  char *arg = NULL; // find modifier and C++ class name
2573  int i = get_paren (buf);
2574  if (i >= 0)
2575    {
2576      arg = buf + i;
2577      *arg = '\0';
2578    }
2579
2580  char *mod = strchr (full_name, ' ');
2581  char *cls = strchr (full_name, ':');
2582
2583  if (mod)
2584    {
2585      len = mod - full_name + 1;
2586      if (!strncmp (full_name, name, len))
2587        name += len;
2588      full_name += len;
2589      if (streq (full_name, name)) // try without modifier
2590        return true;
2591    }
2592
2593  size_t len_cmp = strlen (name);
2594  if (arg)
2595    {
2596      *arg = '(';
2597      len = arg - full_name; // try without 'args'
2598      if (len_cmp == len && !strncmp (full_name, name, len))
2599        return true;
2600      if (cls)
2601        {
2602          len = arg - cls - 2; // and without 'class name'
2603          if ((len_cmp == len) && !strncmp (cls + 2, name, len))
2604            return true;
2605        }
2606    }
2607
2608  if (cls)
2609    {
2610      len = cls - full_name; // try C++ class name only
2611      if (len_cmp == len && !strncmp (full_name, name, len))
2612        return true;
2613      if (streq (cls + 2, name)) // try without 'class name'
2614        return true;
2615    }
2616  return false;
2617}
2618
2619bool
2620DbeSession::add_path (char *path)
2621{
2622  return add_path (path, get_search_path ());
2623}
2624
2625bool
2626DbeSession::add_classpath (char *path)
2627{
2628  return add_path (path, classpath);
2629}
2630
2631Vector<DbeFile*> *
2632DbeSession::get_classpath ()
2633{
2634  if (classpath_df == NULL)
2635    classpath_df = new Vector<DbeFile*>;
2636  for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++)
2637    classpath_df->store (i, getDbeFile (classpath->fetch (i),
2638                                        DbeFile::F_DIR_OR_JAR));
2639  return classpath_df;
2640}
2641
2642bool
2643DbeSession::add_path (char *path, Vector<char*> *pathes)
2644{
2645  bool result = false;
2646  Vector <char *> *tokens = split_str (path, ':');
2647  for (long j = 0, jsz = VecSize (tokens); j < jsz; j++)
2648    {
2649      char *spath = tokens->get (j);
2650      // Don't append path if it's already there
2651      bool got = false;
2652      for (int i = 0, sz = pathes->size (); i < sz; i++)
2653        {
2654          char *nm = pathes->get (i);
2655          if (streq (nm, spath))
2656            {
2657              got = true;
2658              break;
2659            }
2660        }
2661      if (!got)
2662        {
2663          pathes->append (spath);
2664          result = true;
2665        }
2666      else
2667        free (spath);
2668    }
2669  delete tokens;
2670  return result;
2671}
2672
2673void
2674DbeSession::set_need_refind ()
2675{
2676  Vector<DbeFile*> *f_list = dbeFiles->values ();
2677  for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++)
2678    {
2679      DbeFile *f = f_list->get (i);
2680      f->set_need_refind (true);
2681    }
2682  delete f_list;
2683  for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++)
2684    {
2685      SourceFile *f = sources->get (i);
2686      if (f && f->dbeFile)
2687        f->dbeFile->set_need_refind (true);
2688    }
2689}
2690
2691void
2692DbeSession::set_search_path (Vector<char*> *path, bool reset)
2693{
2694  if (reset)
2695    search_path->destroy ();
2696  for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++)
2697    {
2698      char *name = path->fetch (i);
2699      if (add_path (name))
2700        reset = true;
2701    }
2702  if (reset)
2703    {
2704      set_need_refind ();
2705
2706      // now reset the string setting for it
2707      StringBuilder sb;
2708      for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++)
2709        {
2710          char *name = search_path->fetch (i);
2711          if (sb.length () != 0)
2712            sb.append (':');
2713          sb.append (name);
2714        }
2715      free (settings->str_search_path);
2716      settings->str_search_path = sb.toString ();
2717    }
2718}
2719
2720void
2721DbeSession::set_search_path (char *_lpath, bool reset)
2722{
2723  Vector<char *> *path = new Vector<char*>;
2724  char *lpath = dbe_strdup (_lpath);
2725  for (char *s = lpath; s;)
2726    {
2727      path->append (s);
2728      s = strchr (s, ':');
2729      if (s)
2730        {
2731          *s = 0;
2732          s++;
2733        }
2734    }
2735  set_search_path (path, reset);
2736  delete path;
2737  free (lpath);
2738}
2739
2740void
2741DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap)
2742{
2743  set_need_refind ();
2744  settings->set_pathmaps (newPathMap);
2745}
2746
2747Vector<pathmap_t*> *
2748DbeSession::get_pathmaps ()
2749{
2750  return settings->pathmaps;
2751}
2752
2753void
2754DbeSession::mobj_define (MemObjType_t *mobj)
2755{
2756  settings->mobj_define (mobj, false);
2757  DbeView *dbev;
2758  int index;
2759  Vec_loop (DbeView*, views, index, dbev)
2760  {
2761    dbev->get_settings ()->mobj_define (mobj, false);
2762  }
2763}
2764
2765void
2766DbeSession::dump_segments (FILE *out)
2767{
2768  int index;
2769  LoadObject *loitem;
2770  Vec_loop (LoadObject*, lobjs, index, loitem)
2771  {
2772    fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"),
2773             index, loitem->get_name (), loitem->get_pathname ());
2774    loitem->dump_functions (out);
2775    fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"),
2776             index, loitem->get_name (), loitem->get_pathname ());
2777  }
2778}
2779
2780void
2781DbeSession::dump_dataobjects (FILE *out)
2782{
2783  DataObject *ditem;
2784  int index;
2785
2786  fprintf (out, NTXT ("\nMaster list of DataObjects:\n"));
2787  Vec_loop (DataObject*, dobjs, index, ditem)
2788  {
2789    Histable* scope = ditem->get_scope ();
2790    DataObject* parent = ditem->get_parent ();
2791    DataObject* master = ditem->get_master ();
2792    if (parent != NULL)
2793      fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n",
2794               (ll_t) ditem->id, (ll_t) ditem->get_size (),
2795               (ll_t) parent->id, (ll_t) ditem->get_offset (),
2796               ditem->get_name ());
2797    else
2798      {
2799        // parent is NULL
2800        fprintf (out, NTXT ("id %6lld: [%4lld] %s "),
2801                 (ll_t) ditem->id, (ll_t) ditem->get_size (),
2802                 ditem->get_name ());
2803        if (master != NULL)
2804          fprintf (out, NTXT (" master=%lld "), (ll_t) master->id);
2805        else if (scope != NULL)
2806          fprintf (out, NTXT (" master=?? "));
2807        else
2808          fprintf (out, NTXT (" MASTER "));
2809#if DEBUG
2810        if (scope != NULL)
2811          {
2812            switch (scope->get_type ())
2813              {
2814              case Histable::LOADOBJECT:
2815              case Histable::FUNCTION:
2816                fprintf (out, NTXT ("%s"), scope->get_name ());
2817                break;
2818              case Histable::MODULE:
2819                {
2820                  char *filename = get_basename (scope->get_name ());
2821                  fprintf (out, NTXT ("%s"), filename);
2822                  break;
2823                }
2824              default:
2825                fprintf (out, NTXT (" Unexpected scope %d:%s"),
2826                         scope->get_type (), scope->get_name ());
2827              }
2828          }
2829#endif
2830        fprintf (out, NTXT ("\n"));
2831      }
2832  }
2833}
2834
2835void
2836DbeSession::dump_map (FILE *out)
2837{
2838  Experiment *exp;
2839  int index;
2840  Vec_loop (Experiment*, exps, index, exp)
2841  {
2842    exp->dump_map (out);
2843  }
2844}
2845
2846void
2847DbeSession::dump_stacks (FILE *outfile)
2848{
2849  Experiment *exp;
2850  int n = nexps ();
2851  FILE *f = (outfile == NULL ? stderr : outfile);
2852  for (int i = 0; i < n; i++)
2853    {
2854      exp = get_exp (i);
2855      fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ());
2856      exp->dump_stacks (f);
2857    }
2858}
2859
2860void
2861DbeSession::propNames_name_store (int propId, const char *propName)
2862{
2863  PropDescr *prop = new PropDescr (propId, propName);
2864  prop->flags = PRFLAG_NOSHOW; // do not show descriptions
2865  propNames->store (propId, prop);
2866}
2867
2868void
2869DbeSession::propNames_name_store (int propId, const char* propName,
2870                                  const char* propUname, VType_type dataType,
2871                                  int flags)
2872{
2873  PropDescr *prop = new PropDescr (propId, propName);
2874  prop->vtype = dataType;
2875  prop->uname = dbe_strdup (propUname);
2876  prop->flags = flags;
2877  propNames->store (propId, prop);
2878}
2879
2880char *
2881DbeSession::propNames_name_fetch (int i)
2882{
2883  PropDescr *prop = propNames->fetch (i);
2884  if (prop)
2885    return prop->name;
2886  return NULL;
2887}
2888
2889int
2890DbeSession::registerPropertyName (const char *name)
2891{
2892  if (name == NULL)
2893    return PROP_NONE;
2894  for (int i = 0; i < propNames->size (); i++)
2895    {
2896      char *pname = propNames_name_fetch (i);
2897      if (pname && strcasecmp (pname, name) == 0)
2898        return i;
2899    }
2900  int propId = propNames->size ();
2901  propNames_name_store (propId, name);
2902  return propId;
2903}
2904
2905int
2906DbeSession::getPropIdByName (const char *name)
2907{
2908  if (name == NULL)
2909    return PROP_NONE;
2910  for (int i = 0; i < propNames->size (); i++)
2911    {
2912      char *pname = propNames_name_fetch (i);
2913      if (pname && strcasecmp (pname, name) == 0)
2914        return i;
2915    }
2916  return PROP_NONE;
2917}
2918
2919char *
2920DbeSession::getPropName (int propId)
2921{
2922  if (!propNames)
2923    return NULL;
2924  if (propId < 0 || propId >= propNames->size ())
2925    return NULL;
2926  return dbe_strdup (propNames_name_fetch (propId));
2927}
2928
2929char *
2930DbeSession::getPropUName (int propId)
2931{
2932  if (!propNames)
2933    return NULL;
2934  if (propId < 0 || propId >= propNames->size ())
2935    return NULL;
2936  PropDescr *prop = propNames->fetch (propId);
2937  if (prop)
2938    return dbe_strdup (prop->uname);
2939  return NULL;
2940}
2941
2942void
2943DbeSession::append (UserLabel *lbl)
2944{
2945  if (lbl->expr)
2946    {
2947      if (userLabels == NULL)
2948         userLabels = new Vector<UserLabel*> ();
2949      userLabels->append (lbl);
2950    }
2951}
2952
2953void
2954DbeSession::append (SourceFile *sf)
2955{
2956  sources->append (sf);
2957  objs->append (sf);
2958}
2959
2960UserLabel *
2961DbeSession::findUserLabel (char *name)
2962{
2963  for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
2964    {
2965      UserLabel *lbl = userLabels->fetch (i);
2966      if (strcasecmp (lbl->name, name) == 0)
2967        return lbl;
2968    }
2969  return NULL;
2970}
2971
2972Expression *
2973DbeSession::findObjDefByName (char *name)
2974{
2975  Expression *expr = NULL;
2976
2977  MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
2978  if (mot != NULL)
2979    {
2980      char *index_expr_str = mot->index_expr;
2981      expr = ql_parse (index_expr_str);
2982    }
2983
2984  if (expr == NULL)
2985    {
2986      int indxtype = findIndexSpaceByName (name);
2987      expr = getIndexSpaceExpr (indxtype);
2988    }
2989  if (expr == NULL)
2990    {
2991      UserLabel *ulbl = findUserLabel (name);
2992      if (ulbl)
2993        expr = ulbl->expr;
2994    }
2995  return expr;
2996}
2997
2998Expression *
2999DbeSession::ql_parse (const char *expr_spec)
3000{
3001  /* (This slight duplication means we don't need to worry about copy
3002     constructors for the QL::Result, nor about the lifetime of the
3003     expr_spec.)  */
3004  if (expr_spec != NULL)
3005    {
3006      QL::Result result (expr_spec);
3007      QL::Parser qlparser (result);
3008      if (qlparser () != 0)
3009        return NULL;
3010      return result ();
3011    }
3012  else
3013    {
3014      QL::Result result;
3015      QL::Parser qlparser (result);
3016      if (qlparser () != 0)
3017        return NULL;
3018      return result ();
3019    }
3020}
3021
3022Vector<void*> *
3023DbeSession::getIndxObjDescriptions ()
3024{
3025  int size = dyn_indxobj_indx;
3026  if (size == 0)
3027    return NULL;
3028  Vector<int> *type = new Vector<int>(dyn_indxobj_indx);
3029  Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx);
3030  Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx);
3031  Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx);
3032  Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx);
3033  Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx);
3034  Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx);
3035  Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx);
3036
3037  for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++)
3038    {
3039      IndexObjType_t *tot = dyn_indxobj->get (i);
3040      if (tot->memObj == NULL)
3041        {
3042          type->append ((int) tot->type);
3043          desc->append (dbe_strdup (tot->name));
3044          i18ndesc->append (dbe_strdup (tot->i18n_name));
3045          sdesc->append (dbe_strdup (tot->short_description));
3046          ldesc->append (dbe_strdup (tot->long_description));
3047          mnemonic->append (tot->mnemonic);
3048          orderList->append (settings->indx_tab_order->fetch (i));
3049          exprList->append (dbe_strdup (tot->index_expr_str));
3050        }
3051    }
3052  Vector<void*> *res = new Vector<void*>(8);
3053  res->store (0, type);
3054  res->store (1, desc);
3055  res->store (2, mnemonic);
3056  res->store (3, i18ndesc);
3057  res->store (4, orderList);
3058  res->store (5, exprList);
3059  res->store (6, sdesc);
3060  res->store (7, ldesc);
3061  return (res);
3062}
3063
3064// Static function to get a vector of custom index object definitions
3065Vector<void*> *
3066DbeSession::getCustomIndxObjects ()
3067{
3068  Vector<char*> *name = new Vector<char*>;
3069  Vector<char*> *formula = new Vector<char*>;
3070  for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++)
3071    {
3072      IndexObjType_t *tot = dyn_indxobj->get (i);
3073      if (tot->memObj == NULL)
3074        {
3075          name->append (dbe_strdup (tot->name));
3076          formula->append (dbe_strdup (tot->index_expr_str));
3077        }
3078    }
3079  Vector<void*> *res = new Vector<void*>(2);
3080  res->store (0, name);
3081  res->store (1, formula);
3082  return (res);
3083}
3084
3085// Static function to define a new index object type
3086char *
3087DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description)
3088{
3089  if (mname == NULL)
3090    return dbe_strdup (GTXT ("No index object type name has been specified."));
3091  if (isalpha ((int) (mname[0])) == 0)
3092    return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"),
3093                          mname);
3094  const char *p = mname;
3095  while (*p != 0)
3096    {
3097      if ((isalnum ((int) (*p)) == 0) && (*p != '_'))
3098        return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"),
3099                            mname);
3100      p++;
3101    }
3102
3103  // make sure the name is not in use
3104  if (MemorySpace::findMemSpaceByName (mname) != NULL)
3105    return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
3106                          mname);
3107
3108  int idxx = findIndexSpaceByName (mname);
3109  if (idxx >= 0)
3110    {
3111      IndexObjType_t *mt = dyn_indxobj->fetch (idxx);
3112      if (strcmp (mt->index_expr_str, index_expr_str) == 0)
3113        // It's a redefinition, but the new definition is the same
3114        return NULL;
3115      return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
3116                          mname);
3117    }
3118  if (index_expr_str == NULL)
3119    return dbe_strdup (GTXT ("No index-expr has been specified."));
3120  if (strlen (index_expr_str) == 0)
3121    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
3122                        index_expr_str);
3123
3124  // verify that the index expression parses correctly
3125  char *expr_str = dbe_strdup (index_expr_str);
3126  Expression *expr = ql_parse (expr_str);
3127  if (expr == NULL)
3128    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
3129                        expr_str);
3130
3131  // It's OK, create the new table entry
3132  IndexObjType_t *tot = new IndexObjType_t;
3133  tot->type = dyn_indxobj_indx++;
3134  tot->name = dbe_strdup (mname);
3135  tot->i18n_name = dbe_strdup (i18nname);
3136  tot->short_description = dbe_strdup (short_description);
3137  tot->long_description = dbe_strdup (long_description);
3138  tot->index_expr_str = expr_str;
3139  tot->index_expr = expr;
3140  tot->mnemonic = mname[0];
3141
3142  // add it to the list
3143  dyn_indxobj->append (tot);
3144  idxobjs->append (new HashMap<uint64_t, Histable*>);
3145
3146  // tell the session
3147  settings->indxobj_define (tot->type, false);
3148
3149  DbeView *dbev;
3150  int index;
3151  Vec_loop (DbeView*, views, index, dbev)
3152  {
3153    dbev->addIndexSpace (tot->type);
3154  }
3155  return NULL;
3156}
3157
3158char *
3159DbeSession::getIndexSpaceName (int index)
3160{
3161  if (index < 0 || index >= dyn_indxobj->size ())
3162    return NULL;
3163  return dyn_indxobj->fetch (index)->name;
3164}
3165
3166char *
3167DbeSession::getIndexSpaceDescr (int index)
3168{
3169  if (index < 0 || index >= dyn_indxobj->size ())
3170    return NULL;
3171  return dyn_indxobj->fetch (index)->i18n_name;
3172}
3173
3174Expression *
3175DbeSession::getIndexSpaceExpr (int index)
3176{
3177  if (index < 0 || index >= dyn_indxobj->size ())
3178    return NULL;
3179  return dyn_indxobj->fetch (index)->index_expr;
3180}
3181
3182char *
3183DbeSession::getIndexSpaceExprStr (int index)
3184{
3185  if (index < 0 || index >= dyn_indxobj->size ())
3186    return NULL;
3187  return dyn_indxobj->fetch (index)->index_expr_str;
3188}
3189
3190int
3191DbeSession::findIndexSpaceByName (const char *mname)
3192{
3193  int idx;
3194  IndexObjType_t *mt;
3195  Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt)
3196  {
3197    if (strcasecmp (mt->name, mname) == 0)
3198      return idx;
3199  }
3200  return -1;
3201}
3202
3203void
3204DbeSession::removeIndexSpaceByName (const char *mname)
3205{
3206  IndexObjType_t *indObj = findIndexSpace (mname);
3207  if (indObj)
3208    indObj->name[0] = 0;
3209}
3210
3211IndexObjType_t *
3212DbeSession::getIndexSpace (int index)
3213{
3214  return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index);
3215}
3216
3217IndexObjType_t *
3218DbeSession::findIndexSpace (const char *mname)
3219{
3220  return getIndexSpace (findIndexSpaceByName (mname));
3221}
3222
3223void
3224DbeSession::get_filter_keywords (Vector<void*> *res)
3225{
3226  Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
3227  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
3228  Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
3229  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
3230  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
3231  Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
3232  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
3233
3234  char *vtypeNames[] = VTYPE_TYPE_NAMES;
3235  for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
3236    {
3237      UserLabel *lbl = userLabels->fetch (i);
3238      kwCategory->append (dbe_strdup (NTXT ("FK_LABEL")));
3239      kwCategoryI18N->append (dbe_strdup (GTXT ("Labels")));
3240      kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL]));
3241      kwKeyword->append (dbe_strdup (lbl->name));
3242      kwFormula->append (dbe_strdup (lbl->str_expr));
3243      kwDescription->append (dbe_strdup (lbl->comment));
3244      kwEnumDescs->append (NULL);
3245    }
3246
3247  for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++)
3248    {
3249      PropDescr *prop = propNames->fetch (i);
3250      char *pname = prop ? prop->name : NULL;
3251      if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW)
3252        continue;
3253      int vtypeNum = prop->vtype;
3254      if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
3255        vtypeNum = TYPE_NONE;
3256      kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property
3257      kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions")));
3258      kwDataType->append (dbe_strdup (vtypeNames[vtypeNum]));
3259      kwKeyword->append (dbe_strdup (pname));
3260      kwFormula->append (NULL);
3261      kwDescription->append (dbe_strdup (prop->uname));
3262      kwEnumDescs->append (NULL);
3263    }
3264
3265  for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++)
3266    {
3267      IndexObjType_t *obj = dyn_indxobj->get (i);
3268      if (obj->memObj)
3269        continue;
3270      kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ")));
3271      kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions")));
3272      kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
3273      kwKeyword->append (dbe_strdup (obj->name));
3274      kwFormula->append (dbe_strdup (obj->index_expr_str));
3275      kwDescription->append (dbe_strdup (obj->i18n_name));
3276      kwEnumDescs->append (NULL);
3277    }
3278}
3279
3280Histable *
3281DbeSession::findIndexObject (int idxtype, uint64_t idx)
3282{
3283  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
3284  return iobjs->get (idx);
3285}
3286
3287Histable *
3288DbeSession::createIndexObject (int idxtype, int64_t idx)
3289{
3290  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
3291
3292  Histable *idxobj = iobjs->get (idx);
3293  if (idxobj == NULL)
3294    {
3295      idxobj = new IndexObject (idxtype, idx);
3296      if (idx == -1)
3297        idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
3298      iobjs->put (idx, idxobj);
3299    }
3300
3301  return idxobj;
3302}
3303
3304Histable *
3305DbeSession::createIndexObject (int idxtype, Histable *hobj)
3306{
3307  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
3308  int64_t idx = hobj ? hobj->id : -1;
3309  Histable *idxobj = iobjs->get (idx);
3310  if (idxobj == NULL)
3311    {
3312      idxobj = new IndexObject (idxtype, hobj);
3313      if (idx == -1)
3314        idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
3315      iobjs->put (idx, idxobj);
3316    }
3317
3318  return idxobj;
3319}
3320
3321Histable *
3322DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id)
3323{
3324  switch (type)
3325    {
3326    case Histable::FUNCTION:
3327    case Histable::MODULE:
3328    case Histable::LOADOBJECT:
3329      return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL;
3330    case Histable::INDEXOBJ:
3331      return findIndexObject (subtype, id);
3332      // ignoring the following cases
3333    case Histable::INSTR:
3334    case Histable::LINE:
3335    case Histable::EADDR:
3336    case Histable::MEMOBJ:
3337    case Histable::PAGE:
3338    case Histable::DOBJECT:
3339    case Histable::SOURCEFILE:
3340    case Histable::IOACTFILE:
3341    case Histable::IOACTVFD:
3342    case Histable::IOCALLSTACK:
3343    case Histable::HEAPCALLSTACK:
3344    case Histable::OTHER:
3345    case Histable::EXPERIMENT:
3346      break;
3347    }
3348  return NULL;
3349}
3350
3351// return a vector of Functions that match the regular expression input string
3352Vector<JThread *> *
3353DbeSession::match_java_threads (char *ustr, int matchParent,
3354                                Vector<uint64_t> * &grids,
3355                                Vector<uint64_t> * &expids)
3356{
3357  if (ustr == NULL)
3358    return NULL;
3359
3360  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
3361  regex_t regex_desc;
3362  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
3363  free (str);
3364  if (rc)   // syntax error in parsing string
3365    return NULL;
3366
3367  // allocate the new vector
3368  Vector<JThread *> *ret = new Vector<JThread*>;
3369  grids = new Vector<uint64_t>;
3370  expids = new Vector<uint64_t>;
3371
3372  int index;
3373  JThread *jthread;
3374  int expid;
3375  Experiment* exp;
3376  Vec_loop (Experiment*, exps, expid, exp)
3377  {
3378
3379    Vec_loop (JThread*, exp->get_jthreads (), index, jthread)
3380    {
3381      const char * name;
3382      if (matchParent)
3383        name = jthread->parent_name;
3384      else
3385        name = jthread->group_name;
3386      if (name == NULL)
3387        name = "";
3388      if (!regexec (&regex_desc, name, 0, NULL, 0))
3389        {
3390          // this one matches
3391          ret->append (jthread);
3392          grids->append (exp->groupId);
3393          expids->append (exp->getUserExpId ());
3394        }
3395    }
3396  }
3397
3398  regfree (&regex_desc);
3399  return ret;
3400}
3401
3402// return a vector of Functions that match the regular expression input string
3403Vector<Function *> *
3404DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt)
3405{
3406  if (ustr == NULL)
3407    return NULL;
3408  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
3409  regex_t regex_desc;
3410  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
3411  free (str);
3412  if (rc)   // syntax error in parsing string
3413    return NULL;
3414
3415  // allocate the new vector
3416  Vector<Function *> *ret = new Vector<Function*>;
3417
3418  int index;
3419  Histable *obj;
3420  Vec_loop (Histable*, objs, index, obj)
3421  {
3422    if (obj->get_type () == Histable::FUNCTION)
3423      {
3424        Function *func = (Function*) obj;
3425        if (!regexec (&regex_desc, func->get_name (nfmt), 0, NULL, 0))
3426          // this one matches
3427          ret->append (func);
3428      }
3429  }
3430  regfree (&regex_desc);
3431  return ret;
3432}
3433
3434// return a vector of Functions that match the regular expression input string
3435Vector<FileData *> *
3436DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt)
3437{
3438  if (ustr == NULL)
3439    return NULL;
3440  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
3441  regex_t regex_desc;
3442  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
3443  free (str);
3444  if (rc)   // syntax error in parsing string
3445    return NULL;
3446
3447  // allocate the new vector
3448  Vector<FileData *> *ret = new Vector<FileData*>;
3449  int numExps = nexps ();
3450  DefaultMap<int64_t, FileData*>* fDataMap;
3451  Vector<FileData *> *fDataObjs;
3452  FileData *fData;
3453  int size;
3454  for (int i = 0; i < numExps; i++)
3455    {
3456      Experiment *exp = get_exp (i);
3457      fDataMap = exp->getFDataMap ();
3458      fDataObjs = fDataMap->values ();
3459      size = fDataObjs->size ();
3460      for (int j = 0; j < size; j++)
3461        {
3462          fData = fDataObjs->fetch (j);
3463          if (fData
3464              && !regexec (&regex_desc, fData->get_raw_name (nfmt), 0, NULL, 0))
3465            // this one matches
3466            ret->append (fData);
3467        }
3468    }
3469  regfree (&regex_desc);
3470  return ret;
3471}
3472
3473// return a vector of DataObjects that match the regular expression input string
3474Vector<DataObject *> *
3475DbeSession::match_dobj_names (char *ustr)
3476{
3477  if (ustr == NULL)
3478    return NULL;
3479  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
3480  regex_t regex_desc;
3481  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
3482  free (str);
3483  if (rc)   // syntax error in parsing string
3484    return NULL;
3485
3486  // allocate the new vector
3487  Vector<DataObject *> *ret = new Vector<DataObject*>;
3488  int index;
3489  DataObject *ditem;
3490  Vec_loop (DataObject*, dobjs, index, ditem)
3491  {
3492    // does this one match
3493    if (!regexec (&regex_desc, ditem->get_name (), 0, NULL, 0))
3494      // this one matches
3495      ret->append (ditem);
3496  }
3497  regfree (&regex_desc);
3498  return ret;
3499}
3500
3501void
3502DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist)
3503{
3504  if (msg)
3505    fprintf (stderr, "%s\n", msg);
3506  int sz = mlist ? mlist->size () : -1;
3507  for (int i = 0; i < sz; i++)
3508    {
3509      BaseMetric *m = mlist->fetch (i);
3510      char *s = m->dump ();
3511      fprintf (stderr, "%2d %s\n", i, s);
3512      free (s);
3513    }
3514  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
3515}
3516
3517void
3518DbeSession::dump (char *msg, Vector<Metric*> *mlist)
3519{
3520  if (msg)
3521    fprintf (stderr, "%s\n", msg);
3522  int sz = mlist ? mlist->size () : -1;
3523  for (int i = 0; i < sz; i++)
3524    {
3525      Metric *m = mlist->fetch (i);
3526      char *s = m->dump ();
3527      fprintf (stderr, "%2d %s\n", i, s);
3528      free (s);
3529    }
3530  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
3531}
3532