diff options
Diffstat (limited to 'gprofng/src/DbeSession.cc')
-rw-r--r-- | gprofng/src/DbeSession.cc | 3525 |
1 files changed, 3525 insertions, 0 deletions
diff --git a/gprofng/src/DbeSession.cc b/gprofng/src/DbeSession.cc new file mode 100644 index 00000000000..94b8f6b762b --- /dev/null +++ b/gprofng/src/DbeSession.cc @@ -0,0 +1,3525 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <ctype.h> +#include <stdio.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/types.h> +#include <errno.h> +#include <sys/param.h> + +#include "util.h" +#include "Application.h" +#include "Experiment.h" +#include "ExpGroup.h" +#include "Expression.h" +#include "DataObject.h" +#include "Elf.h" +#include "Function.h" +#include "DbeSession.h" +#include "LoadObject.h" +#include "DbeSyncMap.h" +#include "DbeThread.h" +#include "ClassFile.h" +#include "IndexObject.h" +#include "PathTree.h" +#include "Print.h" + +// Bison 3.0 doesn't define YY_NULLPTR. I copied this from QLParser.tab.cc. +// Why this is not in QLParser.tab.hh ? YY_NULLPTR is used in QLParser.tab.hh +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif +#include "QLParser.tab.hh" +#include "DbeView.h" +#include "MemorySpace.h" +#include "Module.h" +#include "SourceFile.h" +#include "StringBuilder.h" +#include "BaseMetric.h" +#include "BaseMetricTreeNode.h" +#include "Command.h" +#include "UserLabel.h" +#include "StringMap.h" +#include "DbeFile.h" +#include "DbeJarFile.h" +#include "IOActivity.h" +#include "HeapActivity.h" + +// This is a universal List structure to organize objects +// of various types, even if different. +struct List +{ + List *next; + void *val; +}; + +struct Countable +{ + Countable (void *_item) + { + item = _item; + ref_count = 0; + } + + void *item; + int ref_count; +}; + +Platform_t DbeSession::platform = +#if ARCH(SPARC) + Sparc; +#elif ARCH(Aarch64) + Aarch64; +#else // ARCH(Intel) + Intel; +#endif + +// This constant determines the size of the data object name hash table. +static const int HTableSize = 8192; +static int DEFAULT_TINY_THRESHOLD = -1; + +unsigned int mpmt_debug_opt = 0; +DbeSession *dbeSession = NULL; + +DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode) +{ + dbeSession = this; + ipc_mode = _ipc_mode; + rdt_mode = _rdt_mode; + settings = new Settings (_settings); + views = new Vector<DbeView*>; + exps = new Vector<Experiment*>; + lobjs = new Vector<LoadObject*>; + objs = new Vector<Histable*>; + dobjs = new Vector<DataObject*>; + metrics = new Vector<Countable*>; + reg_metrics = new Vector<BaseMetric*>; + hwcentries = NULL; + reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse + idxobjs = new Vector<HashMap<uint64_t, Histable*>*>; + tmp_files = new Vector<char*>; + search_path = new Vector<char*>; + classpath = new Vector<char*>; + classpath_df = NULL; + expGroups = new Vector<ExpGroup*>; + sourcesMap = new HashMap<char*, SourceFile*>; + sources = new Vector<SourceFile*>; + comp_lobjs = new HashMap<char*, LoadObject*>; + comp_dbelines = new HashMap<char*, DbeLine*>; + comp_sources = new HashMap<char*, SourceFile*>; + loadObjMap = new DbeSyncMap<LoadObject>; + f_special = new Vector<Function*>(LastSpecialFunction); + omp_functions = new Vector<Function*>(OMP_LAST_STATE); + interactive = false; + lib_visibility_used = false; + + // Define all known property names + propNames = new Vector<PropDescr*>; + propNames_name_store (PROP_NONE, NTXT ("")); + propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP")); + propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP")); + propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP")); + propNames_name_store (PROP_THRID, NTXT ("THRID")); + propNames_name_store (PROP_LWPID, NTXT ("LWPID")); + propNames_name_store (PROP_CPUID, NTXT ("CPUID")); + propNames_name_store (PROP_FRINFO, NTXT ("FRINFO")); + propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME")); + + // Samples + propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ")); + propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE")); + + // GCEvents + propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ")); + propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT")); + + // Metadata used by some packet types + propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"), + NULL, TYPE_UINT64, DDFLAG_NOSHOW); + + // Clock profiling properties + propNames_name_store (PROP_UCPU, NTXT ("UCPU")); + propNames_name_store (PROP_SCPU, NTXT ("SCPU")); + propNames_name_store (PROP_TRAP, NTXT ("TRAP")); + propNames_name_store (PROP_TFLT, NTXT ("TFLT")); + propNames_name_store (PROP_DFLT, NTXT ("DFLT")); + propNames_name_store (PROP_KFLT, NTXT ("KFLT")); + propNames_name_store (PROP_ULCK, NTXT ("ULCK")); + propNames_name_store (PROP_TSLP, NTXT ("TSLP")); + propNames_name_store (PROP_WCPU, NTXT ("WCPU")); + propNames_name_store (PROP_TSTP, NTXT ("TSTP")); + + propNames_name_store (PROP_MSTATE, NTXT ("MSTATE")); + propNames_name_store (PROP_NTICK, NTXT ("NTICK")); + propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE")); + + // Synchronization tracing properties + propNames_name_store (PROP_SRQST, NTXT ("SRQST")); + propNames_name_store (PROP_SOBJ, NTXT ("SOBJ")); + + // Hardware counter profiling properties + propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG")); + propNames_name_store (PROP_HWCINT, NTXT ("HWCINT")); + propNames_name_store (PROP_VADDR, NTXT ("VADDR")); + propNames_name_store (PROP_PADDR, NTXT ("PADDR")); + propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC")); + propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC")); + propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME")); + propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME")); + propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE")); + propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP")); + propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE")); + propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP")); + propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ")); + propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT")); + propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC")); + + // Heap tracing properties + propNames_name_store (PROP_HTYPE, NTXT ("HTYPE")); + propNames_name_store (PROP_HSIZE, NTXT ("HSIZE")); + propNames_name_store (PROP_HVADDR, NTXT ("HVADDR")); + propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR")); + propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"), + GTXT ("Leaked bytes"), TYPE_UINT64, 0); + propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE")); + propNames_name_store (PROP_HFREED, NTXT ("HFREED"), + GTXT ("Freed bytes"), TYPE_UINT64, 0); + propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"), + GTXT ("Current allocations"), TYPE_INT64, 0); + propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"), + NULL, TYPE_INT64, DDFLAG_NOSHOW); + propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"), + GTXT ("Current leaks"), TYPE_UINT64, 0); + propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"), + NULL, TYPE_UINT64, DDFLAG_NOSHOW); + + // IO tracing properties + propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE")); + propNames_name_store (PROP_IOFD, NTXT ("IOFD")); + propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE")); + propNames_name_store (PROP_IORQST, NTXT ("IORQST")); + propNames_name_store (PROP_IOOFD, NTXT ("IOOFD")); + propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME")); + propNames_name_store (PROP_IOVFD, NTXT ("IOVFD")); + propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE")); + + // omptrace raw properties + propNames_name_store (PROP_CPRID, NTXT ("CPRID")); + propNames_name_store (PROP_PPRID, NTXT ("PPRID")); + propNames_name_store (PROP_TSKID, NTXT ("TSKID")); + propNames_name_store (PROP_PTSKID, NTXT ("PTSKID")); + propNames_name_store (PROP_PRPC, NTXT ("PRPC")); + + // Data race detection properties + propNames_name_store (PROP_RID, NTXT ("RID")); + propNames_name_store (PROP_RTYPE, NTXT ("RTYPE")); + propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC")); + propNames_name_store (PROP_RVADDR, NTXT ("RVADDR")); + propNames_name_store (PROP_RCNT, NTXT ("RCNT")); + + // Deadlock detection properties + propNames_name_store (PROP_DID, NTXT ("DID")); + propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE")); + propNames_name_store (PROP_DTYPE, NTXT ("DTYPE")); + propNames_name_store (PROP_DVADDR, NTXT ("DVADDR")); + + // Synthetic properties (queries only) + propNames_name_store (PROP_STACK, NTXT ("STACK")); + propNames_name_store (PROP_MSTACK, NTXT ("MSTACK")); + propNames_name_store (PROP_USTACK, NTXT ("USTACK")); + propNames_name_store (PROP_XSTACK, NTXT ("XSTACK")); + propNames_name_store (PROP_HSTACK, NTXT ("HSTACK")); + propNames_name_store (PROP_STACKID, NTXT ("STACKID")); + //propNames_name_store( PROP_CPRID, NTXT("CPRID") ); + //propNames_name_store( PROP_TSKID, NTXT("TSKID") ); + propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"), + GTXT ("Java thread number"), TYPE_UINT64, 0); + + propNames_name_store (PROP_LEAF, NTXT ("LEAF")); + propNames_name_store (PROP_DOBJ, NTXT ("DOBJ")); + propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP")); + propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP")); + propNames_name_store (PROP_PID, NTXT ("PID"), + GTXT ("Process id"), TYPE_UINT64, 0); + propNames_name_store (PROP_EXPID, NTXT ("EXPID"), + GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW); + propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"), + GTXT ("Comparable Experiment Id"), TYPE_UINT64, + DDFLAG_NOSHOW); //YXXX find better description + propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"), + GTXT ("Comparison Group id"), TYPE_UINT64, 0); + propNames_name_store (PROP_PARREG, NTXT ("PARREG")); + propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"), + GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0); + propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"), + GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0); + propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"), + GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, + DDFLAG_NOSHOW); + propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"), + GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0); + propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"), + GTXT ("Clock Profiling Interval, Microseconds"), + TYPE_UINT64, 0); + + propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES")); + + propNames_name_store (PROP_STACKL, NTXT ("STACKL")); + propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL")); + propNames_name_store (PROP_USTACKL, NTXT ("USTACKL")); + propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL")); + + propNames_name_store (PROP_STACKI, NTXT ("STACKI")); + propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI")); + propNames_name_store (PROP_USTACKI, NTXT ("USTACKI")); + propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI")); + + // Make sure predefined names are not used for dynamic properties + propNames_name_store (PROP_LAST, NTXT ("")); + + localized_SP_UNKNOWN_NAME = GTXT ("(unknown)"); + + // define Index objects + dyn_indxobj = new Vector<IndexObjType_t*>(); + dyn_indxobj_indx = 0; + char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"), + (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT); + indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL); + free (s); + indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL); + indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"), + NULL, NULL); + indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"), + NULL, NULL); + indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"), + NTXT ("(TSTAMP/1000000000)"), NULL, NULL); + indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"), + NULL, NULL); + s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"), + (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT, + (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT); + indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL); + free (s); + indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"), + "(IOHEAPBYTES==0?0:" + "((IOHEAPBYTES<=(1<<0)?(1<<0):" + "((IOHEAPBYTES<=(1<<2)?(1<<2):" + "((IOHEAPBYTES<=(1<<4)?(1<<4):" + "((IOHEAPBYTES<=(1<<6)?(1<<6):" + "((IOHEAPBYTES<=(1<<8)?(1<<8):" + "((IOHEAPBYTES<=(1<<10)?(1<<10):" + "((IOHEAPBYTES<=(1<<12)?(1<<12):" + "((IOHEAPBYTES<=(1<<14)?(1<<14):" + "((IOHEAPBYTES<=(1<<16)?(1<<16):" + "((IOHEAPBYTES<=(1<<18)?(1<<18):" + "((IOHEAPBYTES<=(1<<20)?(1<<20):" + "((IOHEAPBYTES<=(1<<22)?(1<<22):" + "((IOHEAPBYTES<=(1<<24)?(1<<24):" + "((IOHEAPBYTES<=(1<<26)?(1<<26):" + "((IOHEAPBYTES<=(1<<28)?(1<<28):" + "((IOHEAPBYTES<=(1<<30)?(1<<30):" + "((IOHEAPBYTES<=(1<<32)?(1<<32):" + "((IOHEAPBYTES<=(1<<34)?(1<<34):" + "((IOHEAPBYTES<=(1<<36)?(1<<36):" + "((IOHEAPBYTES<=(1<<38)?(1<<38):" + "((IOHEAPBYTES<=(1<<40)?(1<<40):" + "((IOHEAPBYTES<=(1<<42)?(1<<42):" + "((IOHEAPBYTES<=(1<<44)?(1<<44):" + "((IOHEAPBYTES<=(1<<46)?(1<<46):" + "((IOHEAPBYTES<=(1<<48)?(1<<48):" + "((IOHEAPBYTES<=(1<<50)?(1<<50):" + "(IOHEAPBYTES==-1?-1:(1<<50|1)" + "))))))))))))))))))))))))))))))))))))))))))))))))))))))", + NULL, NULL); + indxobj_define (NTXT ("Duration"), GTXT ("Duration"), + "((TSTAMP_HI-TSTAMP_LO)==0?0:" + "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:" + "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:" + "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:" + "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:" + "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:" + "(10000000000001))))))))))))))))))))))))", NULL, NULL); + dyn_indxobj_indx_fixed = dyn_indxobj_indx; + Elf::elf_init (); + defExpName = NULL; + mach_model_loaded = NULL; + tmp_dir_name = NULL; + settings->read_rc (ipc_mode || rdt_mode); + + init (); +} + +DbeSession::~DbeSession () +{ + Destroy (views); + Destroy (exps); + Destroy (dobjs); + Destroy (metrics); + Destroy (search_path); + Destroy (classpath); + Destroy (propNames); + Destroy (expGroups); + Destroy (userLabels); + if (hwcentries) + { + for (long i = 0, sz = hwcentries->size (); i < sz; i++) + { + Hwcentry *h = hwcentries->get (i); + free (h->int_name); + free (h->name); + delete h; + } + delete hwcentries; + } + + if (idxobjs) + { + for (int i = 0; i < idxobjs->size (); ++i) + { + HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i); + if (hMap) + { + hMap->values ()->destroy (); + delete hMap; + } + } + delete idxobjs; + } + + for (int i = 0; i < HTableSize; i++) + { + List *list = dnameHTable[i]; + while (list) + { + List *tmp = list; + list = list->next; + delete tmp; + } + } + delete[] dnameHTable; + delete classpath_df; + Destroy (objs); + Destroy (reg_metrics); + Destroy (dyn_indxobj); + delete lobjs; + delete f_special; + destroy_map (DbeFile *, dbeFiles); + destroy_map (DbeJarFile *, dbeJarFiles); + delete loadObjMap; + delete omp_functions; + delete sourcesMap; + delete sources; + delete comp_lobjs; + delete comp_dbelines; + delete comp_sources; + delete reg_metrics_tree; + delete settings; + free (mach_model_loaded); + + if (defExpName != NULL) + { + StringBuilder *sb = new StringBuilder (); + sb->append (NTXT ("/bin/rm -rf ")); + sb->append (defExpName); + char *cmd = sb->toString (); + system (cmd); + free (cmd); + delete sb; + free (defExpName); + } + unlink_tmp_files (); + delete tmp_files; + dbeSession = NULL; +} + +void +DbeSession::unlink_tmp_files () +{ + if (tmp_files) + { + for (int i = 0, sz = tmp_files->size (); i < sz; i++) + unlink (tmp_files->fetch (i)); + tmp_files->destroy (); + delete tmp_files; + tmp_files = NULL; + } + if (tmp_dir_name) + { + char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name); + system (cmd); + free (cmd); + free (tmp_dir_name); + tmp_dir_name = NULL; + } +} + +char * +DbeSession::get_tmp_file_name (const char *nm, bool for_java) +{ + if (tmp_dir_name == NULL) + { + tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"), + (unsigned long long) getuid (), (long long) getpid ()); + mkdir (tmp_dir_name, S_IRWXU); + } + char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm); + if (for_java) + for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++) + if (*s == '/') + *s = '.'; + return fnm; +} + +void +DbeSession::init () +{ + user_exp_id_counter = 0; + status_ompavail = 0; + archive_mode = 0; + +#if DEBUG + char *s = getenv (NTXT ("MPMT_DEBUG")); + if (s) + mpmt_debug_opt = atoi (s); +#endif /* DEBUG */ + dbeFiles = new StringMap<DbeFile*>(); + dbeJarFiles = new StringMap<DbeJarFile*>(128, 128); + + // set up the initial (after .rc file reading) search path + set_search_path (settings->str_search_path, true); + userLabels = NULL; + + // Preset all objects as they may reuse each other + lo_unknown = NULL; + f_unknown = NULL; + j_unknown = NULL; + lo_total = NULL; + sf_unknown = NULL; + f_total = NULL; + f_jvm = NULL; + d_total = NULL; + d_scalars = NULL; + d_unknown = NULL; + expGroups->destroy (); + f_special->reset (); + for (int i = 0; i < LastSpecialFunction; i++) + f_special->append (NULL); + + lo_omp = NULL; + omp_functions->reset (); + for (int i = 0; i < OMP_LAST_STATE; i++) + omp_functions->append (NULL); + + // make sure the metric list is initialized + register_metric (Metric::SIZES); + register_metric (Metric::ADDRESS); + register_metric (Metric::ONAME); + + // This is needed only to maintain loadobject id's + // for <Total> and <Unknown> in tests + (void) get_Unknown_LoadObject (); + (void) get_Total_LoadObject (); + + // Create the data object name hash table. + dnameHTable = new List*[HTableSize]; + for (int i = 0; i < HTableSize; i++) + dnameHTable[i] = NULL; + + d_total = createDataObject (); + d_total->set_name (NTXT ("<Total>")); + + // XXXX <Scalars> only appropriate for Program/Data-oriented analyses + d_scalars = createDataObject (); + d_scalars->set_name (GTXT ("<Scalars>")); + + d_unknown = createDataObject (); + d_unknown->set_name (GTXT ("<Unknown>")); + + // assign d_unknown's children so data_olayout has consistent sorting + for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++) + { + char *errcode; + DataObject* dobj = createDataObject (); + switch (pp_code) + { + case NUM_ABS_PP_CODES + 1: + errcode = PTXT (DOBJ_UNDETERMINED); + break; + case NUM_ABS_PP_CODES: + errcode = PTXT (DOBJ_UNSPECIFIED); + break; + case NUM_ABS_PP_CODES - 1: + errcode = PTXT (DOBJ_UNIDENTIFIED); + break; + default: + errcode = PTXT (ABS_PP_CODES[pp_code]); + } + dobj->parent = d_unknown; + dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set + } + + for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++) + { + DataObject* dobj = createDataObject (); + dobj->parent = d_unknown; + dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set + } +} + +void +DbeSession::reset_data () +{ + for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i) + if (idxobjs->get (i)) + idxobjs->get (i)->reset (); +} + +void +DbeSession::reset () +{ + loadObjMap->reset (); + DbeView *dbev; + int index; + + Vec_loop (DbeView*, views, index, dbev) + { + dbev->reset (); + } + + destroy_map (DbeFile *, dbeFiles); + destroy_map (DbeJarFile *, dbeJarFiles); + exps->destroy (); + lobjs->reset (); // all LoadObjects belong to objs + dobjs->destroy (); // deletes d_unknown and d_total as well + objs->destroy (); + comp_lobjs->clear (); + comp_dbelines->clear (); + comp_sources->clear (); + sourcesMap->clear (); + sources->reset (); + + // Delete the data object name hash table. + for (int i = 0; i < HTableSize; i++) + { + List *list = dnameHTable[i]; + while (list) + { + List *tmp = list; + list = list->next; + delete tmp; + } + } + delete[] dnameHTable; + + // IndexObect definitions remain, objects themselves may go + for (int i = 0; i < idxobjs->size (); ++i) + { + HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i); + if (v != NULL) + { + v->values ()->destroy (); + v->clear (); + } + } + init (); +} + +Vector<SourceFile*> * +DbeSession::get_sources () +{ + return sources; +} + +DbeFile * +DbeSession::getDbeFile (char *filename, int filetype) +{ + Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile filetype=0x%x %s\n"), filetype, filename); + if (strncmp (filename, NTXT ("./"), 2) == 0) + filename += 2; + DbeFile *dbeFile = dbeFiles->get (filename); + if (dbeFile == NULL) + { + dbeFile = new DbeFile (filename); + dbeFiles->put (filename, dbeFile); + } + dbeFile->filetype |= filetype; + return dbeFile; +} + +LoadObject * +DbeSession::get_Total_LoadObject () +{ + if (lo_total == NULL) + { + lo_total = createLoadObject (NTXT ("<Total>")); + lo_total->dbeFile->filetype |= DbeFile::F_FICTION; + } + return lo_total; +} + +Function * +DbeSession::get_Total_Function () +{ + if (f_total == NULL) + { + f_total = createFunction (); + f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET; + f_total->set_name (NTXT ("<Total>")); + Module *mod = get_Total_LoadObject ()->noname; + f_total->module = mod; + mod->functions->append (f_total); + } + return f_total; +} + +LoadObject * +DbeSession::get_Unknown_LoadObject () +{ + if (lo_unknown == NULL) + { + lo_unknown = createLoadObject (GTXT ("<Unknown>")); + lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable + lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION; + + // force creation of the <Unknown> function + (void) get_Unknown_Function (); + } + return lo_unknown; +} + +SourceFile * +DbeSession::get_Unknown_Source () +{ + if (sf_unknown == NULL) + { + sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME); + sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION; + sf_unknown->flags |= SOURCE_FLAG_UNKNOWN; + } + return sf_unknown; +} + +Function * +DbeSession::get_Unknown_Function () +{ + if (f_unknown == NULL) + { + f_unknown = createFunction (); + f_unknown->flags |= FUNC_FLAG_SIMULATED; + f_unknown->set_name (GTXT ("<Unknown>")); + Module *mod = get_Unknown_LoadObject ()->noname; + f_unknown->module = mod; + mod->functions->append (f_unknown); + } + return f_unknown; +} + +// LIBRARY_VISIBILITY + +Function * +DbeSession::create_hide_function (LoadObject *lo) +{ + Function *h_function = createFunction (); + h_function->set_name (lo->get_name ()); + h_function->module = lo->noname; + h_function->isHideFunc = true; + lo->noname->functions->append (h_function); + return h_function; +} + +Function * +DbeSession::get_JUnknown_Function () +{ + if (j_unknown == NULL) + { + j_unknown = createFunction (); + j_unknown->flags |= FUNC_FLAG_SIMULATED; + j_unknown->set_name (GTXT ("<no Java callstack recorded>")); + Module *mod = get_Unknown_LoadObject ()->noname; + j_unknown->module = mod; + mod->functions->append (j_unknown); + } + return j_unknown; +} + +Function * +DbeSession::get_jvm_Function () +{ + if (f_jvm == NULL) + { + f_jvm = createFunction (); + f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET; + f_jvm->set_name (GTXT ("<JVM-System>")); + + // Find the JVM LoadObject + LoadObject *jvm = get_Unknown_LoadObject (); + for (int i = 0; i < lobjs->size (); ++i) + { + LoadObject *lo = lobjs->fetch (i); + if (lo->flags & SEG_FLAG_JVM) + { + jvm = lo; + break; + } + } + Module *mod = jvm->noname; + f_jvm->module = mod; + mod->functions->append (f_jvm); + // XXXX is it required? no consistency among all special functions + // jvm->functions->append( f_jvm ); + } + return f_jvm; +} + +Function * +DbeSession::getSpecialFunction (SpecialFunction kind) +{ + if (kind < 0 || kind >= LastSpecialFunction) + return NULL; + + Function *func = f_special->fetch (kind); + if (func == NULL) + { + char *fname; + switch (kind) + { + case TruncatedStackFunc: + fname = GTXT ("<Truncated-stack>"); + break; + case FailedUnwindFunc: + fname = GTXT ("<Stack-unwind-failed>"); + break; + default: + return NULL; + } + func = createFunction (); + func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET; + Module *mod = get_Total_LoadObject ()->noname; + func->module = mod; + mod->functions->append (func); + func->set_name (fname); + f_special->store (kind, func); + } + return func; +} + +LoadObject * +DbeSession::get_OMP_LoadObject () +{ + if (lo_omp == NULL) + { + for (int i = 0, sz = lobjs->size (); i < sz; i++) + { + LoadObject *lo = lobjs->fetch (i); + if (lo->flags & SEG_FLAG_OMP) + { + lo_omp = lo; + return lo_omp; + } + } + lo_omp = createLoadObject (GTXT ("<OMP>")); + lo_omp->type = LoadObject::SEG_TEXT; + lo_omp->dbeFile->filetype |= DbeFile::F_FICTION; + } + return lo_omp; +} + +Function * +DbeSession::get_OMP_Function (int n) +{ + if (n < 0 || n >= OMP_LAST_STATE) + return NULL; + + Function *func = omp_functions->fetch (n); + if (func == NULL) + { + char *fname; + switch (n) + { + case OMP_OVHD_STATE: + fname = GTXT ("<OMP-overhead>"); + break; + case OMP_IDLE_STATE: + fname = GTXT ("<OMP-idle>"); + break; + case OMP_RDUC_STATE: + fname = GTXT ("<OMP-reduction>"); + break; + case OMP_IBAR_STATE: + fname = GTXT ("<OMP-implicit_barrier>"); + break; + case OMP_EBAR_STATE: + fname = GTXT ("<OMP-explicit_barrier>"); + break; + case OMP_LKWT_STATE: + fname = GTXT ("<OMP-lock_wait>"); + break; + case OMP_CTWT_STATE: + fname = GTXT ("<OMP-critical_section_wait>"); + break; + case OMP_ODWT_STATE: + fname = GTXT ("<OMP-ordered_section_wait>"); + break; + case OMP_ATWT_STATE: + fname = GTXT ("<OMP-atomic_wait>"); + break; + default: + return NULL; + } + func = createFunction (); + func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET; + func->set_name (fname); + + LoadObject *omp = get_OMP_LoadObject (); + func->module = omp->noname; + omp->noname->functions->append (func); + omp->functions->append (func); + omp_functions->store (n, func); + } + return func; +} + +// Divide the original createExperiment() into two steps +// In part1, we just create the data structure, in part2, if +// we decide to keep the experiment around, add it to various +// lists in DbeSession +Experiment * +DbeSession::createExperimentPart1 () +{ + Experiment *exp = new Experiment (); + return exp; +} + +void +DbeSession::createExperimentPart2 (Experiment *exp) +{ + int ind = expGroups->size (); + if (ind > 0) + { + ExpGroup *gr = expGroups->fetch (ind - 1); + exp->groupId = gr->groupId; + gr->append (exp); + } + exp->setExpIdx (exps->size ()); + exp->setUserExpId (++user_exp_id_counter); + exps->append (exp); +} + +Experiment * +DbeSession::createExperiment () +{ + Experiment *exp = new Experiment (); + append (exp); + return exp; +} + +void +DbeSession::append (Experiment *exp) +{ + exp->setExpIdx (exps->size ()); + exp->setUserExpId (++user_exp_id_counter); + exps->append (exp); + if (exp->founder_exp) + { + if (exp->founder_exp->children_exps == NULL) + exp->founder_exp->children_exps = new Vector<Experiment *>; + exp->founder_exp->children_exps->append (exp); + if (exp->founder_exp->groupId > 0) + { + exp->groupId = exp->founder_exp->groupId; + expGroups->get (exp->groupId - 1)->append (exp); + } + } + if (exp->groupId == 0) + { + long ind = VecSize (expGroups); + if (ind > 0) + { + ExpGroup *gr = expGroups->get (ind - 1); + exp->groupId = gr->groupId; + gr->append (exp); + } + } +} + +void +DbeSession::append (Hwcentry *h) +{ + if (hwcentries == NULL) + hwcentries = new Vector<Hwcentry*>; + hwcentries->append (h); +} + +int +DbeSession::ngoodexps () +{ + return exps->size (); +} + +int +DbeSession::createView (int index, int cloneindex) +{ + // ensure that there is no view with that index + DbeView *dbev = getView (index); + if (dbev != NULL) + abort (); + + // find the view to be cloned + dbev = getView (cloneindex); + DbeView *newview; + if (dbev == NULL) + newview = new DbeView (theApplication, settings, index); + else + newview = new DbeView (dbev, index); + views->append (newview); + return index; +} + +DbeView * +DbeSession::getView (int index) +{ + int i; + DbeView *dbev; + Vec_loop (DbeView*, views, i, dbev) + { + if (dbev->vindex == index) + return dbev; + } + return NULL; +} + +void +DbeSession::dropView (int index) +{ + int i; + DbeView *dbev; + + Vec_loop (DbeView*, views, i, dbev) + { + if (dbev->vindex == index) + { + views->remove (i); + delete dbev; + return; + } + } + // view not found; ignore for now +} + +Vector<char*> * +DbeSession::get_group_or_expt (char *path) +{ + Vector<char*> *exp_list = new Vector<char*>; + FILE *fptr; + char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN]; + + fptr = fopen (path, NTXT ("r")); + if (!fptr || !fgets (buf, (int) sizeof (buf), fptr) + || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER))) + { + // it's not an experiment group + new_path = dbe_strdup (path); + new_path = canonical_path (new_path); + exp_list->append (new_path); + } + else + { + // it is an experiment group, read the list to get them all + while (fgets (buf, (int) sizeof (buf), fptr)) + { + if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1)) + { + new_path = dbe_strdup (name); + new_path = canonical_path (new_path); + exp_list->append (new_path); + } + } + } + if (fptr) + fclose (fptr); + return exp_list; +} + +#define GET_INT_VAL(v, s, len) \ + for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); } + +static int +dir_name_cmp (const void *a, const void *b) +{ + char *s1 = *((char **) a); + char *s2 = *((char **) b); + while (*s1) + { + if (isdigit (*s1) && isdigit (*s2)) + { + int v1, v2, len1, len2; + GET_INT_VAL (v1, s1, len1); + GET_INT_VAL (v2, s2, len2); + if (v1 != v2) + return v1 - v2; + if (len1 != len2) + return len2 - len1; + continue; + } + if (*s1 != *s2) + break; + s1++; + s2++; + } + return *s1 - *s2; +} + +static int +read_experiment_data_in_parallel (void *arg) +{ + exp_ctx *ctx = (exp_ctx *) arg; + Experiment *dexp = ctx->exp; + bool read_ahead = ctx->read_ahead; + dexp->read_experiment_data (read_ahead); + free (ctx); + return 0; +} + +void +DbeSession::open_experiment (Experiment *exp, char *path) +{ + exp->open (path); + if (exp->get_status () != Experiment::FAILURE) + exp->read_experiment_data (false); + exp->open_epilogue (); + + // Update all DbeViews + for (int i = 0, sz = views->size (); i < sz; i++) + { + DbeView *dbev = views->fetch (i); + dbev->add_experiment (exp->getExpIdx (), true); + } + + if (exp->get_status () == Experiment::FAILURE) + { + check_tab_avail (); + return; + } + + char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS")); + int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds + if (discard_tiny != NULL) + { + user_specified_tiny_threshold = (atoi (discard_tiny)); + if (user_specified_tiny_threshold < 0) + user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; + } + + // Open descendant experiments + DIR *exp_dir = opendir (path); + if (exp_dir == NULL) + { + check_tab_avail (); + return; + } + + Vector<char*> *exp_names = new Vector<char*>(); + struct dirent *entry = NULL; + while ((entry = readdir (exp_dir)) != NULL) + { + if (entry->d_name[0] != '_') + continue; + size_t len = strlen (entry->d_name); + if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0) + continue; + exp_names->append (dbe_strdup (entry->d_name)); + } + closedir (exp_dir); + exp_names->sort (dir_name_cmp); + Experiment **t_exp_list = new Experiment *[exp_names->size ()]; + int nsubexps = 0; + + for (int j = 0, jsz = exp_names->size (); j < jsz; j++) + { + t_exp_list[j] = NULL; + + char *lineage_name = exp_names->fetch (j); + struct stat64 sbuf; + char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name); + + // look for experiments with no profile collected + if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD) + { + char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE); + int st = dbe_stat (frinfoname, &sbuf); + free (frinfoname); + if (st == 0) + { + // if no profile/trace data do not process this experiment any further + if (sbuf.st_size == 0) + { + free (dpath); + continue; + } + } + } + else + { // check if dpath is a directory + if (dbe_stat (dpath, &sbuf) != 0) + { + free (dpath); + continue; + } + else if (!S_ISDIR (sbuf.st_mode)) + { + free (dpath); + continue; + } + } + size_t lineage_name_len = strlen (lineage_name); + lineage_name[lineage_name_len - 3] = 0; /* remove .er */ + Experiment *dexp = new Experiment (); + dexp->founder_exp = exp; + if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD) + { + dexp->setTinyThreshold (user_specified_tiny_threshold); + dexp->open (dpath); + if (dexp->isDiscardedTinyExperiment ()) + { + delete dexp; + free (dpath); + continue; + } + } + else + dexp->open (dpath); + append (dexp); + t_exp_list[j] = dexp; + nsubexps++; + dexp->set_clock (exp->clock); + + // DbeView add_experiment() is split into two parts + // add_subexperiment() is called repeeatedly for + // all sub_experiments, later add_experiment_epilogue() finishes up the task + for (int i = 0, sz = views->size (); i < sz; i++) + { + DbeView *dbev = views->fetch (i); + bool enabled = settings->check_en_desc (lineage_name, dexp->utargname); + dbev->add_subexperiment (dexp->getExpIdx (), enabled); + } + free (dpath); + } + + for (int i = 0, sz = views->size (); i < sz; i++) + { + DbeView *dbev = views->fetch (i); + dbev->add_experiment_epilogue (); + } + + DbeThreadPool * threadPool = new DbeThreadPool (-1); + for (int j = 0, jsz = exp_names->size (); j < jsz; j++) + { + if (t_exp_list[j] == NULL) continue; + Experiment *dexp = t_exp_list[j]; + exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx)); + new_ctx->path = NULL; + new_ctx->exp = dexp; + new_ctx->ds = this; + new_ctx->read_ahead = true; + DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx); + threadPool->put_queue (q); + } + threadPool->wait_queues (); + delete threadPool; + + for (long j = 0, jsz = exp_names->size (); j < jsz; j++) + { + if (t_exp_list[j] == NULL) continue; + Experiment *dexp = t_exp_list[j]; + dexp->open_epilogue (); + } + exp_names->destroy (); + delete[] t_exp_list; + delete exp_names; + + // update setting for leaklist and dataspace + check_tab_avail (); +} + +void +DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp) +{ + if (exp->fetch_errors () != NULL) + { + // yes, there were errors + char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT ("")); + sb->append (path); + sb->append (NTXT (": ")); + sb->append (ststr); + free (ststr); + } + + Emsg *m = exp->fetch_warnings (); + if (m != NULL) + { + sb->append (path); + sb->append (NTXT (": ")); + if (!is_interactive ()) + sb->append (GTXT ("Experiment has warnings, see header for details\n")); + else + sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n")); + } + + // Check for descendant experiments that are not loaded + int num_desc = VecSize (exp->children_exps); + if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL)) + { + char *s; + if (!is_interactive ()) + s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc); + else + s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc); + sb->append (path); + sb->append (NTXT (": ")); + sb->append (s); + free (s); + } +} + +Experiment * +DbeSession::get_exp (int exp_ind) +{ + if (exp_ind < 0 || exp_ind >= exps->size ()) + return NULL; + Experiment *exp = exps->fetch (exp_ind); + exp->setExpIdx (exp_ind); + return exp; +} + +Vector<Vector<char*>*> * +DbeSession::getExperimensGroups () +{ + if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0) + return NULL; + bool compare_mode = expGroups->size () > 1; + Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> ( + compare_mode ? expGroups->size () : 1); + for (int i = 0; i < expGroups->size (); i++) + { + ExpGroup *grp = expGroups->fetch (i); + Vector<Experiment*> *founders = grp->get_founders (); + if (founders && founders->size () != 0) + { + Vector<char *> *names = new Vector<char*> (founders->size ()); + for (int j = 0; j < founders->size (); j++) + { + Experiment *exp = founders->fetch (j); + names->append (dbe_strdup (exp->get_expt_name ())); + } + if (compare_mode || groups->size () == 0) + groups->append (names); + else + groups->fetch (0)->addAll (names); + } + delete founders; + } + return groups; +} + +char * +DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups) +{ + StringBuilder sb; + for (int i = 0; i < groups->size (); i++) + { + Vector<char *> *names = groups->fetch (i); + ExpGroup *grp; + if (names->size () == 1) + grp = new ExpGroup (names->fetch (0)); + else + { + char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1); + grp = new ExpGroup (nm); + free (nm); + } + expGroups->append (grp); + grp->groupId = expGroups->size (); + + for (int j = 0; j < names->size (); j++) + { + char *path = names->fetch (j); + size_t len = strlen (path); + if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg"))) + { + Vector<char*> *lst = get_group_or_expt (path); + for (int j1 = 0; j1 < lst->size (); j1++) + { + Experiment *exp = new Experiment (); + append (exp); + open_experiment (exp, lst->get (j1)); + if (exp->get_status () == Experiment::FAILURE) + append_mesgs (&sb, path, exp); + } + lst->destroy (); + delete lst; + } + else + { + Experiment *exp = new Experiment (); + append (exp); + open_experiment (exp, path); + if (exp->get_status () == Experiment::FAILURE) + append_mesgs (&sb, path, exp); + } + } + } + + for (int i = 0, sz = views->size (); i < sz; i++) + { + DbeView *dbev = views->fetch (i); + dbev->update_advanced_filter (); + int cmp = dbev->get_settings ()->get_compare_mode (); + dbev->set_compare_mode (CMP_DISABLE); + dbev->set_compare_mode (cmp); + } + return sb.length () == 0 ? NULL : sb.toString (); +} + +char * +DbeSession::drop_experiment (int exp_ind) +{ + DbeView *dbev; + int index; + Experiment *exp2; + + status_ompavail = -1; + Experiment *exp = exps->fetch (exp_ind); + + // If this is a sub experiment, don't do it + if (exp->founder_exp != NULL) // this is a sub experiment; don't do it + return (dbe_strdup (GTXT ("Can not drop subexperiments"))); + + if (VecSize (exp->children_exps) > 0) + for (;;) + { + // search the list of experiments to find all that have this one as founder + bool found = false; + Vec_loop (Experiment*, exps, index, exp2) + { + if (exp2->founder_exp == exp) + { + exp2->founder_exp = NULL; + drop_experiment (index); + found = true; + break; + } + } + if (found == false) + break; + } + + // then proceed to finish the drop + Vec_loop (DbeView*, views, index, dbev) + { + dbev->drop_experiment (exp_ind); + } + + int old_cnt = expGroups->size (); + for (int i = 0; i < old_cnt; i++) + { + ExpGroup *gr = expGroups->fetch (i); + if (gr->groupId == exp->groupId) + { + gr->drop_experiment (exp); + if ((gr->founder == NULL) && (gr->exps->size () == 0)) + { + delete gr; + expGroups->remove (i); + } + break; + } + } + delete exps->remove (exp_ind); + if (old_cnt != expGroups->size ()) + { + for (int i = 0, sz = expGroups->size (); i < sz; i++) + { + ExpGroup *gr = expGroups->fetch (i); + gr->groupId = i + 1; + Vector<Experiment*> *expList = gr->exps; + for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++) + expList->fetch (i1)->groupId = gr->groupId; + } + for (int i = 0, sz = views->size (); i < sz; i++) + { + dbev = views->fetch (i); + int cmp = dbev->get_compare_mode (); + dbev->set_compare_mode (CMP_DISABLE); + dbev->set_compare_mode (cmp); + } + } + check_tab_avail (); // update tab availability + return NULL; +} + +int +DbeSession::find_experiment (char *path) +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (strcmp (exp->get_expt_name (), path) == 0) + return exp->getExpIdx (); + } + return -1; +} + +LoadObject * +DbeSession::createLoadObject (const char *nm, int64_t cksum) +{ + return loadObjMap->sync_create_item (nm, cksum); +} + +LoadObject * +DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df) +{ + return loadObjMap->sync_create_item (nm, runTimePath, df); +} + +void +DbeSession::append (LoadObject *lobj) +{ + Histable *obj = lobj; // workaround for a C++ problem + objs->append (obj); + lobj->id = objs->size () - 1; + lobjs->append (lobj); + lobj->seg_idx = lobjs->size () - 1; + char *loname = lobj->get_pathname (); + dbeFiles->put (loname, lobj->dbeFile); +} + +DbeJarFile * +DbeSession::get_JarFile (const char *name) +{ + DbeJarFile *jf = dbeJarFiles->get (name); + if (jf == NULL) + { + jf = new DbeJarFile (name); + dbeJarFiles->put (name, jf); + } + return jf; +} + +Module * +DbeSession::createModule (LoadObject *lo, const char *nm) +{ + Module *mod = new Module (); + Histable *obj = mod; // workaround for a C++ problem + objs->append (obj); + mod->id = objs->size () - 1; + mod->loadobject = lo; + mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME)); + lo->seg_modules->append (mod); + return mod; +} + +Module * +DbeSession::createUnknownModule (LoadObject *lo) +{ + Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME); + mod->flags |= MOD_FLAG_UNKNOWN; + mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME)); + return mod; +} + +SourceFile * +DbeSession::createSourceFile (const char *_path) +{ + char *path = (char *) _path; + if (strncmp (path, NTXT ("./"), 2) == 0) + path += 2; + SourceFile *source = sourcesMap->get (path); + if (source == NULL) + { + source = new SourceFile (path); + (void) sourcesMap->put (path, source); + append (source); + } + return source; +} + +Function * +DbeSession::createFunction () +{ + Function *func = new Function (objs->size ()); + Histable *obj = func; // workaround for a C++ problem + objs->append (obj); + return func; +} + +JMethod * +DbeSession::createJMethod () +{ + JMethod *jmthd = new JMethod (objs->size ()); + Histable *obj = jmthd; // workaround for a C++ problem + objs->append (obj); + return jmthd; +} + +Module * +DbeSession::createClassFile (char *className) +{ + ClassFile *cls = new ClassFile (); + cls->set_name (className); + char *clpath = cls->get_java_file_name (className, true); + cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS); + free (clpath); + Histable *obj = cls; // workaround for a C++ problem + objs->append (obj); + cls->id = objs->size () - 1; + return cls; +} + +Histable * +DbeSession::createHistObject (Histable::Type type) +{ + switch (type) + { + case Histable::DOBJECT: + { + DataObject *dataobj = new DataObject (); + dobjs->append (dataobj); + dataobj->id = dobjs->size () - 1; + return dataobj; + } + default: + assert (0); + } + return NULL; +} + +DataObject * +DbeSession::createDataObject () +{ + DataObject *dataobj = new DataObject (); + dobjs->append (dataobj); + dataobj->id = dobjs->size () - 1; + return dataobj; +} + +DataObject * +DbeSession::createDataObject (DataObject *dobj, DataObject *parent) +{ + DataObject *dataobj = new DataObject (); + dataobj->size = dobj->size; + dataobj->offset = dobj->offset; + dataobj->parent = parent; + dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ()); + dobjs->append (dataobj); + dataobj->id = dobjs->size () - 1; + return dataobj; +} + +DataObject * +DbeSession::createMasterDataObject (DataObject *dobj) +{ + DataObject *parent = NULL; + if (dobj->parent) + { // define master parent first + parent = find_dobj_master (dobj->parent); + if (!parent) + { // clone master from this dataobject parent + parent = createDataObject (dobj->parent); + parent->scope = NULL; // master is scope-less + Dprintf (DEBUG_DATAOBJ, + "Master DataObject(%llu) cloned from (%llu) %s\n", + (ull_t) parent->id, (ull_t) dobj->parent->id, + dobj->parent->get_name ()); + // clone master DataObject elements + Vector<DataObject*> *delem = get_dobj_elements (dobj->parent); + int element_index = 0; + DataObject *element = NULL; + Vec_loop (DataObject*, delem, element_index, element) + { + DataObject *master_element = createDataObject (element, parent); + master_element->scope = NULL; // master is scope-less + Dprintf (DEBUG_DATAOBJ, + "Member DataObject(%llu) cloned from (%llu) %s\n", + (ull_t) master_element->id, (ull_t) element->id, + element->get_name ()); + } + } + else + Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n", + (ull_t) parent->id, (ull_t) dobj->parent->id, + dobj->parent->get_name ()); + } + + DataObject *master = find_dobj_master (dobj); + if (!master) + { // clone master from this dataobject + master = createDataObject (dobj, parent); + master->scope = NULL; // master is scope-less + Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n", + (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ()); + } + else + Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n", + (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ()); + return master; +} + +void +DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist) +{ + if ((mtr->get_flavors () & Metric::STATIC) == 0) + { + // insert in front of the first STATIC + for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++) + { + BaseMetric *m = mlist->fetch (i); + if (m->get_flavors () & Metric::STATIC) + { + mlist->insert (i, mtr); + return; + } + } + } + mlist->append (mtr); +} + +BaseMetricTreeNode* +DbeSession::get_reg_metrics_tree () +{ + if (reg_metrics_tree == NULL) + // Can't init earlier because BaseMetric() requires DbeSession::ql_parse + reg_metrics_tree = new BaseMetricTreeNode (); + return reg_metrics_tree; +} + +void +DbeSession::update_metric_tree (BaseMetric *m) +{ + get_reg_metrics_tree ()->register_metric (m); +} + +BaseMetric * +DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec) +{ + BaseMetric *m = find_metric (type, cmd, expr_spec); + if (m) + return m; + BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version + m = new BaseMetric (*bm); + m->set_expr_spec (expr_spec); + insert_metric (m, reg_metrics); + return m; +} + +BaseMetric * +DbeSession::register_metric (BaseMetric::Type type) +{ + BaseMetric *m = find_metric (type, NULL, NULL); + if (m) + return m; + m = new BaseMetric (type); + insert_metric (m, reg_metrics); + update_metric_tree (m); + return m; +} + +BaseMetric * +DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username) +{ + BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL); + if (m) + // That may be a problem when metrics aren't an exact match. + // For example, memoryspace is disabled in one experiment and not in another. + return m; + if (ctr->timecvt) + { + char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux); + char *time_username = dbe_sprintf (GTXT ("%s Time"), + ctr->metric ? ctr->metric : + (ctr->name ? ctr->name : ctr->int_name)); + BaseMetric *m1; + if (ipc_mode) + { + // Two visible metrics are presented in GUI + m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL); + insert_metric (m1, reg_metrics); + update_metric_tree (m1); + m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1); + } + else + { + // Only one visible metric is presented in er_print + m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL); + insert_metric (m1, reg_metrics); + m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1); + } + free (time_cmd); + free (time_username); + } + else + m = new BaseMetric (ctr, aux, username, VAL_VALUE); + insert_metric (m, reg_metrics); + update_metric_tree (m); + return m; +} + +BaseMetric * +DbeSession::register_metric (char *name, char *username, char *_def) +{ + BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL); + if (m) + return m; + Definition *p = Definition::add_definition (_def); + if (p == NULL) + return NULL; + m = new BaseMetric (name, username, p); + insert_metric (m, reg_metrics); + update_metric_tree (m); + return m; +} + +void +DbeSession::drop_metric (BaseMetric *mtr) +{ + Countable *cnt; + int index; + + Vec_loop (Countable*, metrics, index, cnt) + { + if (mtr == (BaseMetric *) cnt->item) + { + cnt->ref_count--; + if (cnt->ref_count == 0) + { + // Remove this metric from all views + DbeView *dbev; + int index2; + Vec_loop (DbeView*, views, index2, dbev) + { + dbev->reset_metrics (); + } + delete metrics->remove (index); + delete mtr; + return; + } + } + } +} + +BaseMetric * +DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec) +{ + for (int i = 0, sz = reg_metrics->size (); i < sz; i++) + { + BaseMetric *bm = reg_metrics->fetch (i); + if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0) + { + if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR) + && dbe_strcmp (bm->get_cmd (), cmd) != 0) + continue; + return bm; + } + } + return NULL; +} + +BaseMetric * +DbeSession::find_base_reg_metric (char * mcmd) +{ + for (int i = 0, sz = reg_metrics->size (); i < sz; i++) + { + BaseMetric *bm = reg_metrics->fetch (i); + if (bm->get_expr_spec () != NULL) + continue; // skip compare metrics + if (dbe_strcmp (bm->get_cmd (), mcmd) == 0) + return bm; + } + return NULL; +} + +Vector<BaseMetric*> * +DbeSession::get_base_reg_metrics () +{ + Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>; + Vector<BaseMetric*> *ml = get_all_reg_metrics (); + for (int i = 0, sz = ml->size (); i < sz; i++) + { + BaseMetric *m = ml->fetch (i); + if (m->get_expr_spec () == NULL) + mlist->append (m); + } + return mlist; +} + +void +DbeSession::check_tab_avail () +{ + DbeView *dbev; + int index; + // tell the views to update their tab lists + Vec_loop (DbeView*, views, index, dbev) + { + dbev->get_settings ()->updateTabAvailability (); + } +} + +bool +DbeSession::is_datamode_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->dataspaceavail) + return true; + } + return false; +} + +bool +DbeSession::is_leaklist_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->leaklistavail) + return true; + } + return false; +} + +bool +DbeSession::is_heapdata_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->heapdataavail) + return true; + } + return false; +} + +bool +DbeSession::is_iodata_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->iodataavail) + return true; + } + return false; +} + +bool +DbeSession::is_racelist_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->racelistavail) + return true; + } + return false; +} + +bool +DbeSession::is_deadlocklist_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->deadlocklistavail) + return true; + } + return false; +} + +bool +DbeSession::is_timeline_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->timelineavail) + return true; + } + return false; +} + +bool +DbeSession::is_ifreq_available () +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + if (exp->ifreqavail) + return true; + } + return false; +} + +bool +DbeSession::is_omp_available () +{ + if (status_ompavail == -1) + { + status_ompavail = 0; + for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++) + { + Experiment *exp = exps->fetch (i); + if (exp->ompavail) + { + status_ompavail = 1; + break; + } + } + } + return status_ompavail == 1; +} + +bool +DbeSession::has_java () +{ + int status_has_java = 0; + for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++) + { + Experiment *exp = exps->fetch (i); + if (exp->has_java) + { + status_has_java = 1; + break; + } + } + return status_has_java == 1; +} + +bool +DbeSession::has_ompavail () +{ + int status_has_ompavail = 0; + for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++) + { + Experiment *exp = exps->fetch (i); + if (exp->ompavail) + { + status_has_ompavail = 1; + break; + } + } + return status_has_ompavail == 1; +} + +int +DbeSession::get_clock (int whichexp) +{ + // XXXX clock frequency should be an attribute of each CPU, + // XXX and not a property of the session + // if whichexp is -1, pick the first exp that has a clock + // otherwise return the clock from the numbered experiment + Experiment *exp; + if (whichexp != -1) + { + exp = get_exp (whichexp); + if (exp != NULL) + return exp->clock; + return 0; + } + int n = nexps (); + for (int i = 0; i < n; i++) + { + exp = get_exp (i); + if (exp != NULL && exp->clock != 0) + return exp->clock; + } + return 0; +} + +LoadObject * +DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum) +{ + return loadObjMap->get (lobj_name, cksum); +} + +static unsigned +hash (char *s) +{ + unsigned res = 0; + for (int i = 0; i < 64 && *s; i++) + res = res * 13 + *s++; + return res; +} + +// This method is introduced to fix performance +// problems with the data space profiling in the +// current release. A better design is desired. +void +DbeSession::dobj_updateHT (DataObject *dobj) +{ + unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize; + List *list = new List; + list->val = (void*) dobj; + list->next = dnameHTable[index]; + dnameHTable[index] = list; +} + +DataObject * +DbeSession::find_dobj_by_name (char *dobj_name) +{ + unsigned index = hash (dobj_name) % HTableSize; + List *list = dnameHTable[index]; + for (; list; list = list->next) + { + DataObject *d = (DataObject*) list->val; + if (strcmp (d->get_unannotated_name (), dobj_name) == 0) + return d; + } + return (DataObject *) NULL; +} + +DataObject * +DbeSession::find_dobj_match (DataObject *dobj) +{ + char *dobj_name = dobj->get_unannotated_name (); + unsigned index = hash (dobj_name) % HTableSize; + List *list = dnameHTable[index]; + for (; list; list = list->next) + { + DataObject *d = (DataObject*) list->val; + if (strcmp (d->get_unannotated_name (), dobj_name) == 0 + && d->size == dobj->size && d->offset == dobj->offset + && d->scope == dobj->scope) + return d; + } + return (DataObject *) NULL; +} + +DataObject * +DbeSession::find_dobj_master (DataObject *dobj) +{ + char *dobj_name = dobj->get_unannotated_name (); + unsigned index = hash (dobj_name) % HTableSize; + List *list = dnameHTable[index]; + for (; list; list = list->next) + { + DataObject *d = (DataObject*) list->val; + // XXXX should parent also match? + if (strcmp (d->get_unannotated_name (), dobj_name) == 0 + && d->size == dobj->size && d->offset == dobj->offset + && d->master == NULL && d->scope == NULL) + return d; + } + return (DataObject *) NULL; +} + +Vector<DataObject*>* +DbeSession::get_dobj_elements (DataObject *dobj) +{ + DataObject *d; + int index; + Vector<DataObject*> *elements = new Vector<DataObject*>; + if (dobj == d_total) + return elements; + Vec_loop (DataObject*, dobjs, index, d) + { + if (d->get_parent () && d->get_parent () == dobj) + elements->append (d); + } + return elements; +} + +Vector<LoadObject*>* +DbeSession::get_text_segments () +{ + LoadObject *lo; + int index; + Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>; + Vec_loop (LoadObject*, lobjs, index, lo) + { + if (lo->type == LoadObject::SEG_TEXT) + tlobjs->append (lo); + } + return tlobjs; +} + +static long long +getNumber (const char *s, char * &last) +{ + long long val; + char *sp; + errno = 0; + val = strtoll (s, &sp, 0); + if (errno == EINVAL) + last = NULL; + else + { + while (isspace (*sp)) + sp++; + last = sp; + } + return (val); +} + +bool +DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj, + char *name, const char *sel, Histable::Type type, bool xdefault) +{ + Vector<Histable*> *obj_lst; + int which = -1; + char *last = NULL; + if (type != Histable::FUNCTION && sel) + { + // check that a number has been provided + which = (int) getNumber (sel, last); + if (last == NULL || *last != '\0') + { + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel); + sel = NULL; + which = 0; + } + which--; + } + obj_lst = new Vector<Histable*>; + switch (type) + { + case Histable::FUNCTION: + obj = map_NametoFunction (name, obj_lst, sel); + break; + case Histable::MODULE: + obj = map_NametoModule (name, obj_lst, which); + break; + case Histable::LOADOBJECT: + obj = map_NametoLoadObject (name, obj_lst, which); + break; + case Histable::DOBJECT: + obj = map_NametoDataObject (name, obj_lst, which); + break; + default: + abort (); // unexpected Histable! + } + + if ((obj == NULL) && (obj_lst->size () > 0)) + { + if (obj_lst->size () == 1) + which = 0; + else + { + if (sel && (which < 0 || which >= obj_lst->size ())) + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel); + if (xdefault) + { + fprintf (stderr, GTXT ("Default selection \"1\" made\n")); + which = 0; + } + else + { + which = ask_which (dis_file, inp_file, obj_lst, name); + if (which == -1) + { + delete obj_lst; + return false; + } + } + } + obj = obj_lst->fetch (which); + } + delete obj_lst; + return true; +} + +int +DbeSession::ask_which (FILE *dis_file, FILE *inp_file, + Vector<Histable*> *list, char *name) +{ + Histable *hitem; + Function *func; + Module *module; + int which, index, index1; + char *item_name, *lo_name, *fname, *last; + char buf[BUFSIZ]; + for (;;) + { + fprintf (dis_file, GTXT ("Available name list:\n")); + fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0); + Vec_loop (Histable*, list, index, hitem) + { + index1 = index + 1; + item_name = hitem->get_name (); + switch (hitem->get_type ()) + { + case Histable::FUNCTION: + func = (Function *) hitem; + module = func->module; + + // id == -1 indicates er_src invocation + if (module == NULL || (module->lang_code == Sp_lang_java + && module->loadobject->id == -1)) + fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name); + else + { + lo_name = module->loadobject->get_pathname (); + fname = (module->file_name && *module->file_name) ? + module->file_name : module->get_name (); + if (fname && *fname) + fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1, + item_name, lo_name, (ull_t) func->img_offset, fname); + else + fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1, + item_name, lo_name, (ull_t) func->img_offset); + } + break; + case Histable::MODULE: + module = (Module *) hitem; + lo_name = module->loadobject->get_pathname (); + if (name[strlen (name) - 1] == + module->file_name[strlen (module->file_name) - 1]) + fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, + module->file_name, lo_name); + else + fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name, + lo_name); + break; + default: + fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name); + break; + } + } + if (inp_file != stdin) + return -1; + fprintf (dis_file, GTXT ("Enter selection: ")); + if (fgets (buf, (int) sizeof (buf), inp_file) == NULL) + { + fprintf (stderr, GTXT ("Error: Invalid number entered:\n")); + return -1; + } + which = (int) getNumber (buf, last); + if (last && *last == '\0') + if (which >= 0 && which <= list->size ()) + return which - 1; + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf); + } +} + +static bool +match_basename (char *name, char *full_name, int len = -1) +{ + if (full_name == NULL) + return false; + if (!strchr (name, '/')) + full_name = get_basename (full_name); + if (len == -1) + return streq (name, full_name); + return strncmp (name, full_name, len) == 0; +} + +LoadObject * +DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which) +{ + // Search the tree to find the first module whose module name + // matches "name" or whose source file name matches "name" + // Issues: is the name a pathname, or a base name? + // Should we look at suffix to disambiguate? + LoadObject *loitem; + int index; + Vec_loop (LoadObject*, lobjs, index, loitem) + { + // try pathname first + // if failed, try object name next + if (match_basename (name, loitem->get_pathname ()) || + match_basename (name, loitem->get_name ())) + { + if (which == list->size ()) + return loitem; + list->append (loitem); + } + } + return (LoadObject *) NULL; +} + +Module * +DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which) +{ + // Search the tree to find the first loadobject whose loadobject name + // matches "name". + + // Issues: is the name a pathname, or a base name? + // Should we look at suffix to disambiguate? + LoadObject *loitem; + Module *mitem; + int index1, index2; + Vec_loop (LoadObject*, lobjs, index1, loitem) + { + Vec_loop (Module*, loitem->seg_modules, index2, mitem) + { + // try source name first + // if failed, try object name next + if (match_basename (name, mitem->file_name) || + match_basename (name, mitem->get_name ())) + { + if (which == list->size ()) + return mitem; + list->append (mitem); + } + } + } + return (Module *) NULL; +} + +Function * +DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list, + const char *sel) +{ + // Search the tree to find the first function whose + // name matches "name". + // Issues: is the name a full name, or a short name? + // Is it a demangled name? If so, what about spaces + // within the name? + // Is there a way to return all names that match? + // How can the user specify a particular function of that name? + LoadObject *loitem; + Function *fitem, *main_func = NULL; + Module *mitem, *main_mod = NULL; + int index1, index2, index3, which = -1; + if (sel) + { + char *last = NULL; + if (*sel == '@') + { // 'sel' is "@seg_num:address" + which = (int) getNumber (sel + 1, last); + if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ())) + { + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel); + return NULL; + } + uint64_t address = getNumber (last + 1, last); + if (last == NULL || *last != '\0') + { + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel); + return NULL; + } + loitem = lobjs->fetch (which); + Vec_loop (Module*, loitem->seg_modules, index2, mitem) + { + Vec_loop (Function*, mitem->functions, index3, fitem) + { + if (address == fitem->img_offset && match_FName (name, fitem)) + return fitem; + } + } + return NULL; + } + + which = (int) getNumber (sel, last); + if (last == NULL || *last != '\0') + { + fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel); + return NULL; + } + which--; + } + + int len_path = 0; + char *with_path = name; + name = StrRchr (name, '`'); + if (name != with_path) + len_path = (int) (name - with_path); + else + with_path = NULL; + + Vec_loop (LoadObject*, lobjs, index1, loitem) + { + Vec_loop (Module*, loitem->seg_modules, index2, mitem) + { + if (with_path) + { // with file name + // try source name first + // if failed, try object name next + if (!match_basename (with_path, mitem->file_name, len_path) && + !match_basename (with_path, mitem->get_name (), len_path)) + continue; + } + Vec_loop (Function*, mitem->functions, index3, fitem) + { + if (match_FName (name, fitem)) + { + if (which == list->size ()) + return fitem; + list->append (fitem); + continue; + } + if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ()) + { + main_func = fitem; + main_mod = mitem; + } + } + } + } + + if (main_mod && main_func) + { + main_mod->read_stabs (); + if (streq (main_func->get_match_name (), name) && which <= 1) + return main_func; + } + return (Function *) NULL; +} + +DataObject * +DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list, + int which) +{ + // Search master list to find dataobjects whose names match "name" + // selecting only the entry corresponding to "which" if it is not -1. + // Issues: is the name fully qualified or only partially? + DataObject *ditem = NULL; + int index; + char *full_name; + Vec_loop (DataObject*, dobjs, index, ditem) + { + if (ditem->scope) continue; // skip non-master dataobjects + + // try fully-qualified dataobject name first + if ((full_name = ditem->get_name ()) != NULL) + { + if (streq (name, full_name)) + { + if (which == list->size ()) + return ditem; + list->append (ditem); + } + } + } + if (list->size () > 0) + return ditem; // return fully-qualified match + + // if fully-qualified name doesn't match anything, try a partial match + Vec_loop (DataObject*, dobjs, index, ditem) + { + if (ditem->scope) continue; // skip non-master dataobjects + + // try fully-qualified dataobject name first + if ((full_name = ditem->get_name ()) != NULL) + { + if (strstr (full_name, name)) + { + if (which == list->size ()) + return ditem; + list->append (ditem); + } + } + } + return (DataObject *) NULL; +} + +bool +DbeSession::match_FName (char *name, Function *func) +{ + size_t len; + char buf[MAXDBUF]; + char *full_name; + if (streq (func->get_name (), name)) // try full name comparison + return true; + if (streq (func->get_mangled_name (), name)) // try mangled name + return true; + if (streq (func->get_match_name (), name)) // try match name + return true; + + Module *md = func->module; // try FORTRAN name + if (md && md->is_fortran ()) + { + char *mangled_name = func->get_mangled_name (); + len = strlen (name); + if (((len + 1) == strlen (mangled_name)) && + (strncmp (name, mangled_name, len) == 0)) + return true; + } + snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ()); + full_name = buf; + char *arg = NULL; // find modifier and C++ class name + int i = get_paren (buf); + if (i >= 0) + { + arg = buf + i; + *arg = '\0'; + } + + char *mod = strchr (full_name, ' '); + char *cls = strchr (full_name, ':'); + + if (mod) + { + len = mod - full_name + 1; + if (!strncmp (full_name, name, len)) + name += len; + full_name += len; + if (streq (full_name, name)) // try without modifier + return true; + } + + size_t len_cmp = strlen (name); + if (arg) + { + *arg = '('; + len = arg - full_name; // try without 'args' + if (len_cmp == len && !strncmp (full_name, name, len)) + return true; + if (cls) + { + len = arg - cls - 2; // and without 'class name' + if ((len_cmp == len) && !strncmp (cls + 2, name, len)) + return true; + } + } + + if (cls) + { + len = cls - full_name; // try C++ class name only + if (len_cmp == len && !strncmp (full_name, name, len)) + return true; + if (streq (cls + 2, name)) // try without 'class name' + return true; + } + return false; +} + +bool +DbeSession::add_path (char *path) +{ + return add_path (path, get_search_path ()); +} + +bool +DbeSession::add_classpath (char *path) +{ + return add_path (path, classpath); +} + +Vector<DbeFile*> * +DbeSession::get_classpath () +{ + if (classpath_df == NULL) + classpath_df = new Vector<DbeFile*>; + for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++) + classpath_df->store (i, getDbeFile (classpath->fetch (i), + DbeFile::F_DIR_OR_JAR)); + return classpath_df; +} + +bool +DbeSession::add_path (char *path, Vector<char*> *pathes) +{ + bool result = false; + Vector <char *> *tokens = split_str (path, ':'); + for (long j = 0, jsz = VecSize (tokens); j < jsz; j++) + { + char *spath = tokens->get (j); + // Don't append path if it's already there + bool got = false; + for (int i = 0, sz = pathes->size (); i < sz; i++) + { + char *nm = pathes->get (i); + if (streq (nm, spath)) + { + got = true; + break; + } + } + if (!got) + { + pathes->append (spath); + result = true; + } + else + free (spath); + } + delete tokens; + return result; +} + +void +DbeSession::set_need_refind () +{ + Vector<DbeFile*> *f_list = dbeFiles->values (); + for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++) + { + DbeFile *f = f_list->get (i); + f->set_need_refind (true); + } + delete f_list; + for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++) + { + SourceFile *f = sources->get (i); + if (f && f->dbeFile) + f->dbeFile->set_need_refind (true); + } +} + +void +DbeSession::set_search_path (Vector<char*> *path, bool reset) +{ + if (reset) + search_path->destroy (); + for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++) + { + char *name = path->fetch (i); + if (add_path (name)) + reset = true; + } + if (reset) + { + set_need_refind (); + + // now reset the string setting for it + StringBuilder sb; + for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++) + { + char *name = search_path->fetch (i); + if (sb.length () != 0) + sb.append (':'); + sb.append (name); + } + free (settings->str_search_path); + settings->str_search_path = sb.toString (); + } +} + +void +DbeSession::set_search_path (char *_lpath, bool reset) +{ + Vector<char *> *path = new Vector<char*>; + char *lpath = dbe_strdup (_lpath); + for (char *s = lpath; s;) + { + path->append (s); + s = strchr (s, ':'); + if (s) + { + *s = 0; + s++; + } + } + set_search_path (path, reset); + delete path; + free (lpath); +} + +void +DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap) +{ + set_need_refind (); + settings->set_pathmaps (newPathMap); +} + +Vector<pathmap_t*> * +DbeSession::get_pathmaps () +{ + return settings->pathmaps; +} + +void +DbeSession::mobj_define (MemObjType_t *mobj) +{ + settings->mobj_define (mobj, false); + DbeView *dbev; + int index; + Vec_loop (DbeView*, views, index, dbev) + { + dbev->get_settings ()->mobj_define (mobj, false); + } +} + +void +DbeSession::dump_segments (FILE *out) +{ + int index; + LoadObject *loitem; + Vec_loop (LoadObject*, lobjs, index, loitem) + { + fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"), + index, loitem->get_name (), loitem->get_pathname ()); + loitem->dump_functions (out); + fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"), + index, loitem->get_name (), loitem->get_pathname ()); + } +} + +void +DbeSession::dump_dataobjects (FILE *out) +{ + DataObject *ditem; + int index; + + fprintf (out, NTXT ("\nMaster list of DataObjects:\n")); + Vec_loop (DataObject*, dobjs, index, ditem) + { + Histable* scope = ditem->get_scope (); + DataObject* parent = ditem->get_parent (); + DataObject* master = ditem->get_master (); + if (parent != NULL) + fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n", + (ll_t) ditem->id, (ll_t) ditem->get_size (), + (ll_t) parent->id, (ll_t) ditem->get_offset (), + ditem->get_name ()); + else + { + // parent is NULL + fprintf (out, NTXT ("id %6lld: [%4lld] %s "), + (ll_t) ditem->id, (ll_t) ditem->get_size (), + ditem->get_name ()); + if (master != NULL) + fprintf (out, NTXT (" master=%lld "), (ll_t) master->id); + else if (scope != NULL) + fprintf (out, NTXT (" master=?? ")); + else + fprintf (out, NTXT (" MASTER ")); +#if DEBUG + if (scope != NULL) + { + switch (scope->get_type ()) + { + case Histable::LOADOBJECT: + case Histable::FUNCTION: + fprintf (out, NTXT ("%s"), scope->get_name ()); + break; + case Histable::MODULE: + { + char *filename = get_basename (scope->get_name ()); + fprintf (out, NTXT ("%s"), filename); + break; + } + default: + fprintf (out, NTXT (" Unexpected scope %d:%s"), + scope->get_type (), scope->get_name ()); + } + } +#endif + fprintf (out, NTXT ("\n")); + } + } +} + +void +DbeSession::dump_map (FILE *out) +{ + Experiment *exp; + int index; + Vec_loop (Experiment*, exps, index, exp) + { + exp->dump_map (out); + } +} + +void +DbeSession::dump_stacks (FILE *outfile) +{ + Experiment *exp; + int n = nexps (); + FILE *f = (outfile == NULL ? stderr : outfile); + for (int i = 0; i < n; i++) + { + exp = get_exp (i); + fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ()); + exp->dump_stacks (f); + } +} + +void +DbeSession::propNames_name_store (int propId, const char *propName) +{ + PropDescr *prop = new PropDescr (propId, propName); + prop->flags = PRFLAG_NOSHOW; // do not show descriptions + propNames->store (propId, prop); +} + +void +DbeSession::propNames_name_store (int propId, const char* propName, + const char* propUname, VType_type dataType, + int flags) +{ + PropDescr *prop = new PropDescr (propId, propName); + prop->vtype = dataType; + prop->uname = dbe_strdup (propUname); + prop->flags = flags; + propNames->store (propId, prop); +} + +char * +DbeSession::propNames_name_fetch (int i) +{ + PropDescr *prop = propNames->fetch (i); + if (prop) + return prop->name; + return NULL; +} + +int +DbeSession::registerPropertyName (const char *name) +{ + if (name == NULL) + return PROP_NONE; + for (int i = 0; i < propNames->size (); i++) + { + char *pname = propNames_name_fetch (i); + if (pname && strcasecmp (pname, name) == 0) + return i; + } + int propId = propNames->size (); + propNames_name_store (propId, name); + return propId; +} + +int +DbeSession::getPropIdByName (const char *name) +{ + if (name == NULL) + return PROP_NONE; + for (int i = 0; i < propNames->size (); i++) + { + char *pname = propNames_name_fetch (i); + if (pname && strcasecmp (pname, name) == 0) + return i; + } + return PROP_NONE; +} + +char * +DbeSession::getPropName (int propId) +{ + if (!propNames) + return NULL; + if (propId < 0 || propId >= propNames->size ()) + return NULL; + return dbe_strdup (propNames_name_fetch (propId)); +} + +char * +DbeSession::getPropUName (int propId) +{ + if (!propNames) + return NULL; + if (propId < 0 || propId >= propNames->size ()) + return NULL; + PropDescr *prop = propNames->fetch (propId); + if (prop) + return dbe_strdup (prop->uname); + return NULL; +} + +void +DbeSession::append (UserLabel *lbl) +{ + if (lbl->expr) + { + if (userLabels == NULL) + userLabels = new Vector<UserLabel*> (); + userLabels->append (lbl); + } +} + +void +DbeSession::append (SourceFile *sf) +{ + sources->append (sf); + objs->append (sf); +} + +UserLabel * +DbeSession::findUserLabel (const char *name) +{ + for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++) + { + UserLabel *lbl = userLabels->fetch (i); + if (strcasecmp (lbl->name, name) == 0) + return lbl; + } + return NULL; +} + +Expression * +DbeSession::findObjDefByName (const char *name) +{ + Expression *expr = NULL; + + MemObjType_t *mot = MemorySpace::findMemSpaceByName (name); + if (mot != NULL) + { + char *index_expr_str = mot->index_expr; + expr = ql_parse (index_expr_str); + } + + if (expr == NULL) + { + int indxtype = findIndexSpaceByName (name); + expr = getIndexSpaceExpr (indxtype); + } + if (expr == NULL) + { + UserLabel *ulbl = findUserLabel (name); + if (ulbl) + expr = ulbl->expr; + } + return expr; +} + +Expression * +DbeSession::ql_parse (const char *expr_spec) +{ + if (expr_spec == NULL) + expr_spec = ""; + QL::Result result (expr_spec); + QL::Parser qlparser (result); + if (qlparser.parse () != 0) + return NULL; + return result (); +} + +Vector<void*> * +DbeSession::getIndxObjDescriptions () +{ + int size = dyn_indxobj_indx; + if (size == 0) + return NULL; + Vector<int> *type = new Vector<int>(dyn_indxobj_indx); + Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx); + Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx); + Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx); + Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx); + Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx); + Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx); + Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx); + + for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++) + { + IndexObjType_t *tot = dyn_indxobj->get (i); + if (tot->memObj == NULL) + { + type->append ((int) tot->type); + desc->append (dbe_strdup (tot->name)); + i18ndesc->append (dbe_strdup (tot->i18n_name)); + sdesc->append (dbe_strdup (tot->short_description)); + ldesc->append (dbe_strdup (tot->long_description)); + mnemonic->append (tot->mnemonic); + orderList->append (settings->indx_tab_order->fetch (i)); + exprList->append (dbe_strdup (tot->index_expr_str)); + } + } + Vector<void*> *res = new Vector<void*>(8); + res->store (0, type); + res->store (1, desc); + res->store (2, mnemonic); + res->store (3, i18ndesc); + res->store (4, orderList); + res->store (5, exprList); + res->store (6, sdesc); + res->store (7, ldesc); + return (res); +} + +// Static function to get a vector of custom index object definitions +Vector<void*> * +DbeSession::getCustomIndxObjects () +{ + Vector<char*> *name = new Vector<char*>; + Vector<char*> *formula = new Vector<char*>; + for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++) + { + IndexObjType_t *tot = dyn_indxobj->get (i); + if (tot->memObj == NULL) + { + name->append (dbe_strdup (tot->name)); + formula->append (dbe_strdup (tot->index_expr_str)); + } + } + Vector<void*> *res = new Vector<void*>(2); + res->store (0, name); + res->store (1, formula); + return (res); +} + +// Static function to define a new index object type +char * +DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description) +{ + if (mname == NULL) + return dbe_strdup (GTXT ("No index object type name has been specified.")); + if (isalpha ((int) (mname[0])) == 0) + return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"), + mname); + const char *p = mname; + while (*p != 0) + { + if ((isalnum ((int) (*p)) == 0) && (*p != '_')) + return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"), + mname); + p++; + } + + // make sure the name is not in use + if (MemorySpace::findMemSpaceByName (mname) != NULL) + return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"), + mname); + + int idxx = findIndexSpaceByName (mname); + if (idxx >= 0) + { + IndexObjType_t *mt = dyn_indxobj->fetch (idxx); + if (strcmp (mt->index_expr_str, index_expr_str) == 0) + // It's a redefinition, but the new definition is the same + return NULL; + return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"), + mname); + } + if (index_expr_str == NULL) + return dbe_strdup (GTXT ("No index-expr has been specified.")); + if (strlen (index_expr_str) == 0) + return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"), + index_expr_str); + + // verify that the index expression parses correctly + char *expr_str = dbe_strdup (index_expr_str); + Expression *expr = ql_parse (expr_str); + if (expr == NULL) + return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"), + expr_str); + + // It's OK, create the new table entry + IndexObjType_t *tot = new IndexObjType_t; + tot->type = dyn_indxobj_indx++; + tot->name = dbe_strdup (mname); + tot->i18n_name = dbe_strdup (i18nname); + tot->short_description = dbe_strdup (short_description); + tot->long_description = dbe_strdup (long_description); + tot->index_expr_str = expr_str; + tot->index_expr = expr; + tot->mnemonic = mname[0]; + + // add it to the list + dyn_indxobj->append (tot); + idxobjs->append (new HashMap<uint64_t, Histable*>); + + // tell the session + settings->indxobj_define (tot->type, false); + + DbeView *dbev; + int index; + Vec_loop (DbeView*, views, index, dbev) + { + dbev->addIndexSpace (tot->type); + } + return NULL; +} + +char * +DbeSession::getIndexSpaceName (int index) +{ + if (index < 0 || index >= dyn_indxobj->size ()) + return NULL; + return dyn_indxobj->fetch (index)->name; +} + +char * +DbeSession::getIndexSpaceDescr (int index) +{ + if (index < 0 || index >= dyn_indxobj->size ()) + return NULL; + return dyn_indxobj->fetch (index)->i18n_name; +} + +Expression * +DbeSession::getIndexSpaceExpr (int index) +{ + if (index < 0 || index >= dyn_indxobj->size ()) + return NULL; + return dyn_indxobj->fetch (index)->index_expr; +} + +char * +DbeSession::getIndexSpaceExprStr (int index) +{ + if (index < 0 || index >= dyn_indxobj->size ()) + return NULL; + return dyn_indxobj->fetch (index)->index_expr_str; +} + +int +DbeSession::findIndexSpaceByName (const char *mname) +{ + int idx; + IndexObjType_t *mt; + Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt) + { + if (strcasecmp (mt->name, mname) == 0) + return idx; + } + return -1; +} + +void +DbeSession::removeIndexSpaceByName (const char *mname) +{ + IndexObjType_t *indObj = findIndexSpace (mname); + if (indObj) + indObj->name[0] = 0; +} + +IndexObjType_t * +DbeSession::getIndexSpace (int index) +{ + return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index); +} + +IndexObjType_t * +DbeSession::findIndexSpace (const char *mname) +{ + return getIndexSpace (findIndexSpaceByName (mname)); +} + +void +DbeSession::get_filter_keywords (Vector<void*> *res) +{ + Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0); + Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1); + Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2); + Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3); + Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4); + Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5); + Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6); + + char *vtypeNames[] = VTYPE_TYPE_NAMES; + for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++) + { + UserLabel *lbl = userLabels->fetch (i); + kwCategory->append (dbe_strdup (NTXT ("FK_LABEL"))); + kwCategoryI18N->append (dbe_strdup (GTXT ("Labels"))); + kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL])); + kwKeyword->append (dbe_strdup (lbl->name)); + kwFormula->append (dbe_strdup (lbl->str_expr)); + kwDescription->append (dbe_strdup (lbl->comment)); + kwEnumDescs->append (NULL); + } + + for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++) + { + PropDescr *prop = propNames->fetch (i); + char *pname = prop ? prop->name : NULL; + if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW) + continue; + int vtypeNum = prop->vtype; + if (vtypeNum < 0 || vtypeNum >= TYPE_LAST) + vtypeNum = TYPE_NONE; + kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property + kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions"))); + kwDataType->append (dbe_strdup (vtypeNames[vtypeNum])); + kwKeyword->append (dbe_strdup (pname)); + kwFormula->append (NULL); + kwDescription->append (dbe_strdup (prop->uname)); + kwEnumDescs->append (NULL); + } + + for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++) + { + IndexObjType_t *obj = dyn_indxobj->get (i); + if (obj->memObj) + continue; + kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ"))); + kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions"))); + kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64])); + kwKeyword->append (dbe_strdup (obj->name)); + kwFormula->append (dbe_strdup (obj->index_expr_str)); + kwDescription->append (dbe_strdup (obj->i18n_name)); + kwEnumDescs->append (NULL); + } +} + +Histable * +DbeSession::findIndexObject (int idxtype, uint64_t idx) +{ + HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype); + return iobjs->get (idx); +} + +Histable * +DbeSession::createIndexObject (int idxtype, int64_t idx) +{ + HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype); + + Histable *idxobj = iobjs->get (idx); + if (idxobj == NULL) + { + idxobj = new IndexObject (idxtype, idx); + if (idx == -1) + idxobj->set_name (dbe_strdup (GTXT ("<Unknown>"))); + iobjs->put (idx, idxobj); + } + + return idxobj; +} + +Histable * +DbeSession::createIndexObject (int idxtype, Histable *hobj) +{ + HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype); + int64_t idx = hobj ? hobj->id : -1; + Histable *idxobj = iobjs->get (idx); + if (idxobj == NULL) + { + idxobj = new IndexObject (idxtype, hobj); + if (idx == -1) + idxobj->set_name (dbe_strdup (GTXT ("<Unknown>"))); + iobjs->put (idx, idxobj); + } + + return idxobj; +} + +Histable * +DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id) +{ + switch (type) + { + case Histable::FUNCTION: + case Histable::MODULE: + case Histable::LOADOBJECT: + return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL; + case Histable::INDEXOBJ: + return findIndexObject (subtype, id); + // ignoring the following cases + case Histable::INSTR: + case Histable::LINE: + case Histable::EADDR: + case Histable::MEMOBJ: + case Histable::PAGE: + case Histable::DOBJECT: + case Histable::SOURCEFILE: + case Histable::IOACTFILE: + case Histable::IOACTVFD: + case Histable::IOCALLSTACK: + case Histable::HEAPCALLSTACK: + case Histable::OTHER: + case Histable::EXPERIMENT: + break; + } + return NULL; +} + +// return a vector of Functions that match the regular expression input string +Vector<JThread *> * +DbeSession::match_java_threads (char *ustr, int matchParent, + Vector<uint64_t> * &grids, + Vector<uint64_t> * &expids) +{ + if (ustr == NULL) + return NULL; + + char *str = dbe_sprintf (NTXT ("^%s$"), ustr); + regex_t regex_desc; + int rc = regcomp (®ex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + free (str); + if (rc) // syntax error in parsing string + return NULL; + + // allocate the new vector + Vector<JThread *> *ret = new Vector<JThread*>; + grids = new Vector<uint64_t>; + expids = new Vector<uint64_t>; + + int index; + JThread *jthread; + int expid; + Experiment* exp; + Vec_loop (Experiment*, exps, expid, exp) + { + + Vec_loop (JThread*, exp->get_jthreads (), index, jthread) + { + const char * name; + if (matchParent) + name = jthread->parent_name; + else + name = jthread->group_name; + if (name == NULL) + name = ""; + if (!regexec (®ex_desc, name, 0, NULL, 0)) + { + // this one matches + ret->append (jthread); + grids->append (exp->groupId); + expids->append (exp->getUserExpId ()); + } + } + } + + regfree (®ex_desc); + return ret; +} + +// return a vector of Functions that match the regular expression input string +Vector<Function *> * +DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt) +{ + if (ustr == NULL) + return NULL; + char *str = dbe_sprintf (NTXT ("^%s$"), ustr); + regex_t regex_desc; + int rc = regcomp (®ex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + free (str); + if (rc) // syntax error in parsing string + return NULL; + + // allocate the new vector + Vector<Function *> *ret = new Vector<Function*>; + + int index; + Histable *obj; + Vec_loop (Histable*, objs, index, obj) + { + if (obj->get_type () == Histable::FUNCTION) + { + Function *func = (Function*) obj; + if (!regexec (®ex_desc, func->get_name (nfmt), 0, NULL, 0)) + // this one matches + ret->append (func); + } + } + regfree (®ex_desc); + return ret; +} + +// return a vector of Functions that match the regular expression input string +Vector<FileData *> * +DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt) +{ + if (ustr == NULL) + return NULL; + char *str = dbe_sprintf (NTXT ("^%s$"), ustr); + regex_t regex_desc; + int rc = regcomp (®ex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + free (str); + if (rc) // syntax error in parsing string + return NULL; + + // allocate the new vector + Vector<FileData *> *ret = new Vector<FileData*>; + int numExps = nexps (); + DefaultMap<int64_t, FileData*>* fDataMap; + Vector<FileData *> *fDataObjs; + FileData *fData; + int size; + for (int i = 0; i < numExps; i++) + { + Experiment *exp = get_exp (i); + fDataMap = exp->getFDataMap (); + fDataObjs = fDataMap->values (); + size = fDataObjs->size (); + for (int j = 0; j < size; j++) + { + fData = fDataObjs->fetch (j); + if (fData + && !regexec (®ex_desc, fData->get_raw_name (nfmt), 0, NULL, 0)) + // this one matches + ret->append (fData); + } + } + regfree (®ex_desc); + return ret; +} + +// return a vector of DataObjects that match the regular expression input string +Vector<DataObject *> * +DbeSession::match_dobj_names (char *ustr) +{ + if (ustr == NULL) + return NULL; + char *str = dbe_sprintf (NTXT ("^%s$"), ustr); + regex_t regex_desc; + int rc = regcomp (®ex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE); + free (str); + if (rc) // syntax error in parsing string + return NULL; + + // allocate the new vector + Vector<DataObject *> *ret = new Vector<DataObject*>; + int index; + DataObject *ditem; + Vec_loop (DataObject*, dobjs, index, ditem) + { + // does this one match + if (!regexec (®ex_desc, ditem->get_name (), 0, NULL, 0)) + // this one matches + ret->append (ditem); + } + regfree (®ex_desc); + return ret; +} + +void +DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist) +{ + if (msg) + fprintf (stderr, "%s\n", msg); + int sz = mlist ? mlist->size () : -1; + for (int i = 0; i < sz; i++) + { + BaseMetric *m = mlist->fetch (i); + char *s = m->dump (); + fprintf (stderr, "%2d %s\n", i, s); + free (s); + } + fprintf (stderr, "======END of mlist[%d] =========\n", sz); +} + +void +DbeSession::dump (char *msg, Vector<Metric*> *mlist) +{ + if (msg) + fprintf (stderr, "%s\n", msg); + int sz = mlist ? mlist->size () : -1; + for (int i = 0; i < sz; i++) + { + Metric *m = mlist->fetch (i); + char *s = m->dump (); + fprintf (stderr, "%2d %s\n", i, s); + free (s); + } + fprintf (stderr, "======END of mlist[%d] =========\n", sz); +} |