| /* Copyright (C) 2021-2023 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 |