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