/* Copyright (C) 2021-2024 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 #include #include #include #include #include #include #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; #elif ARCH(RISCV) RISCV; #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; exps = new Vector; lobjs = new Vector; objs = new Vector; dobjs = new Vector; metrics = new Vector; reg_metrics = new Vector; hwcentries = NULL; reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse idxobjs = new Vector*>; tmp_files = new Vector; search_path = new Vector; classpath = new Vector; classpath_df = NULL; expGroups = new Vector; sourcesMap = new HashMap; sources = new Vector; comp_lobjs = new HashMap; comp_dbelines = new HashMap; comp_sources = new HashMap; loadObjMap = new DbeSyncMap; f_special = new Vector(LastSpecialFunction); omp_functions = new Vector(OMP_LAST_STATE); interactive = false; lib_visibility_used = false; // Define all known property names propNames = new Vector; 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(); 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 *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(); dbeJarFiles = new StringMap(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 and 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 ("")); // XXXX only appropriate for Program/Data-oriented analyses d_scalars = createDataObject (); d_scalars->set_name (GTXT ("")); d_unknown = createDataObject (); d_unknown->set_name (GTXT ("")); // 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 *v = idxobjs->fetch (i); if (v != NULL) { v->values ()->destroy (); v->clear (); } } init (); } Vector * 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 ("")); 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 ("")); 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 ("")); lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION; // force creation of the 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 ("")); 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 ("")); 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 ("")); // 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 (""); break; case FailedUnwindFunc: fname = GTXT (""); 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 ("")); 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 (""); break; case OMP_IDLE_STATE: fname = GTXT (""); break; case OMP_RDUC_STATE: fname = GTXT (""); break; case OMP_IBAR_STATE: fname = GTXT (""); break; case OMP_EBAR_STATE: fname = GTXT (""); break; case OMP_LKWT_STATE: fname = GTXT (""); break; case OMP_CTWT_STATE: fname = GTXT (""); break; case OMP_ODWT_STATE: fname = GTXT (""); break; case OMP_ATWT_STATE: fname = GTXT (""); 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; 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; 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 * DbeSession::get_group_or_expt (char *path) { Vector *exp_list = new Vector; 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 *exp_names = new Vector(); 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); dbe_stat_t 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*> * DbeSession::getExperimensGroups () { if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0) return NULL; bool compare_mode = expGroups->size () > 1; Vector*> *groups = new Vector*> ( compare_mode ? expGroups->size () : 1); for (int i = 0; i < expGroups->size (); i++) { ExpGroup *grp = expGroups->fetch (i); Vector *founders = grp->get_founders (); if (founders && founders->size () != 0) { Vector *names = new Vector (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*> *groups) { StringBuilder sb; for (int i = 0; i < groups->size (); i++) { Vector *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 *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 *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 *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 *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 * DbeSession::get_base_reg_metrics () { Vector *mlist = new Vector; Vector *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* DbeSession::get_dobj_elements (DataObject *dobj) { DataObject *d; int index; Vector *elements = new Vector; 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* DbeSession::get_text_segments () { LoadObject *lo; int index; Vector *tlobjs = new Vector; 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 *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; 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 *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 *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 *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 *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 *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 * DbeSession::get_classpath () { if (classpath_df == NULL) classpath_df = new Vector; 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 *pathes) { bool result = false; Vector *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 *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 *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 *path = new Vector; 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 *newPathMap) { set_need_refind (); settings->set_pathmaps (newPathMap); } Vector * 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 (); 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 * DbeSession::getIndxObjDescriptions () { int size = dyn_indxobj_indx; if (size == 0) return NULL; Vector *type = new Vector(dyn_indxobj_indx); Vector *desc = new Vector(dyn_indxobj_indx); Vector *i18ndesc = new Vector(dyn_indxobj_indx); Vector *mnemonic = new Vector(dyn_indxobj_indx); Vector *orderList = new Vector(dyn_indxobj_indx); Vector *exprList = new Vector(dyn_indxobj_indx); Vector *sdesc = new Vector(dyn_indxobj_indx); Vector *ldesc = new Vector(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 *res = new Vector(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 * DbeSession::getCustomIndxObjects () { Vector *name = new Vector; Vector *formula = new Vector; 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 *res = new Vector(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); // 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 *res) { Vector *kwCategory = (Vector*) res->fetch (0); Vector *kwCategoryI18N = (Vector*) res->fetch (1); Vector *kwDataType = (Vector*) res->fetch (2); Vector *kwKeyword = (Vector*) res->fetch (3); Vector *kwFormula = (Vector*) res->fetch (4); Vector *kwDescription = (Vector*) res->fetch (5); Vector *kwEnumDescs = (Vector*) 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 *iobjs = idxobjs->fetch (idxtype); return iobjs->get (idx); } Histable * DbeSession::createIndexObject (int idxtype, int64_t idx) { HashMap *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 (""))); iobjs->put (idx, idxobj); } return idxobj; } Histable * DbeSession::createIndexObject (int idxtype, Histable *hobj) { HashMap *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 (""))); 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 * DbeSession::match_java_threads (char *ustr, int matchParent, Vector * &grids, Vector * &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 *ret = new Vector; grids = new Vector; expids = new Vector; 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 * 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 *ret = new Vector; 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 * 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 *ret = new Vector; int numExps = nexps (); DefaultMap* fDataMap; Vector *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 * 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 *ret = new Vector; 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 *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 *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); }