diff options
author | Vladimir Mezentsev <vladimir.mezentsev@oracle.com> | 2022-03-11 08:58:31 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2022-03-11 08:58:31 +0000 |
commit | bb368aad297fe3ad40cf397e6fc85aa471429a28 (patch) | |
tree | 0ab25909b8fe789d676bbdb00d501d4d485e4afe /gprofng/src/Dbe.cc | |
parent | a655f19af95eb685ba64f48ee8fc2b3b7a3d886a (diff) | |
download | gdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.zip gdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.gz gdb-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.bz2 |
gprofng: a new GNU profiler
top-level
* Makefile.def: Add gprofng module.
* configure.ac: Add --enable-gprofng option.
* src-release.sh: Add gprofng.
* Makefile.in: Regenerate.
* configure: Regenerate.
* gprofng: New directory.
binutils
* MAINTAINERS: Add gprofng maintainer.
* README-how-to-make-a-release: Add gprofng.
include.
* collectorAPI.h: New file.
* libcollector.h: New file.
* libfcollector.h: New file.
Diffstat (limited to 'gprofng/src/Dbe.cc')
-rw-r--r-- | gprofng/src/Dbe.cc | 10371 |
1 files changed, 10371 insertions, 0 deletions
diff --git a/gprofng/src/Dbe.cc b/gprofng/src/Dbe.cc new file mode 100644 index 0000000..1a6e521 --- /dev/null +++ b/gprofng/src/Dbe.cc @@ -0,0 +1,10371 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "config.h" +#include <errno.h> +#include <sys/types.h> // open, chmod +#include <signal.h> +#include <fcntl.h> // open +#include <strings.h> +#include <unistd.h> + +#include "util.h" +#include "Histable.h" +#include "DbeSession.h" +#include "DbeView.h" +#include "BaseMetric.h" +#include "CallStack.h" +#include "collctrl.h" +#include "Command.h" +#include "Dbe.h" +#include "DbeApplication.h" +#include "DefaultMap.h" +#include "LoadObject.h" +#include "Experiment.h" +#include "IndexObject.h" +#include "IOActivity.h" +#include "PreviewExp.h" +#include "Function.h" +#include "Hist_data.h" +#include "MetricList.h" +#include "Module.h" +#include "DataSpace.h" +#include "MemorySpace.h" +#include "DataObject.h" +#include "MemObject.h" +#include "Filter.h" +#include "FilterSet.h" +#include "FilterExp.h" +#include "Sample.h" +#include "Print.h" +#include "StringBuilder.h" +#include "dbe_types.h" +#include "ExpGroup.h" +#include "vec.h" +#include "UserLabel.h" +#include "DbeFile.h" +#include "PathTree.h" + +// Data structures for managing the collector control info for Collection GUI +static Coll_Ctrl *col_ctr = NULL; + +template<> VecType Vector<int>::type () +{ + return VEC_INTEGER; +} + +template<> VecType Vector<unsigned>::type () +{ + return VEC_INTEGER; +} + +template<> VecType Vector<char>::type () +{ + return VEC_CHAR; +} + +template<> VecType Vector<bool>::type () +{ + return VEC_BOOL; +} + +template<> VecType Vector<double>::type () +{ + return VEC_DOUBLE; +} + +template<> VecType Vector<long long>::type () +{ + return VEC_LLONG; +} + +template<> VecType Vector<uint64_t>::type () +{ + return VEC_LLONG; +} + +template<> VecType Vector<void*>::type () +{ + return VEC_VOIDARR; +} + +template<> VecType Vector<char*>::type () +{ + return VEC_STRING; +} + +template<> VecType Vector<Vector<int>*>::type () +{ + return VEC_INTARR; +} + +template<> VecType Vector<Vector<char*>*>::type () +{ + return VEC_STRINGARR; +} + +template<> VecType Vector<Vector<long long>*>::type () +{ + return VEC_LLONGARR; +} + +// gcc won't instantiate Vector<unsigned>::type() without it +Vector<unsigned> __dummy_unsigned_vector; + +#define CASE_S(x) case x: return #x +static const char * +dsp_type_to_string (int t) +{ + switch (t) + { + CASE_S (DSP_FUNCTION); + CASE_S (DSP_LINE); + CASE_S (DSP_PC); + CASE_S (DSP_SOURCE); + CASE_S (DSP_DISASM); + CASE_S (DSP_SELF); + CASE_S (DSP_CALLER); + CASE_S (DSP_CALLEE); + CASE_S (DSP_CALLTREE); + CASE_S (DSP_TIMELINE); + CASE_S (DSP_STATIS); + CASE_S (DSP_EXP); + CASE_S (DSP_LEAKLIST); + CASE_S (DSP_MEMOBJ); + CASE_S (DSP_DATAOBJ); + CASE_S (DSP_DLAYOUT); + CASE_S (DSP_SRC_FILE); + CASE_S (DSP_IFREQ); + CASE_S (DSP_RACES); + CASE_S (DSP_INDXOBJ); + CASE_S (DSP_DUALSOURCE); + CASE_S (DSP_SOURCE_DISASM); + CASE_S (DSP_DEADLOCKS); + CASE_S (DSP_SOURCE_V2); + CASE_S (DSP_DISASM_V2); + CASE_S (DSP_IOACTIVITY); + CASE_S (DSP_OVERVIEW); + CASE_S (DSP_IOCALLSTACK); + CASE_S (DSP_HEAPCALLSTACK); + CASE_S (DSP_SAMPLE); + default: + break; + } + return NTXT ("ERROR"); +} + +enum +{ + COMPARE_BIT = 1 << 8, + MTYPE_MASK = (1 << 8) - 1, + GROUP_ID_SHIFT = 16 +}; + +static DbeView * +getDbeView (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return dbev; +} + + +Vector<char*> * +dbeGetInitMessages () +{ + // If any comments from the .rc files, send them to the GUI + Emsg *msg = theDbeApplication->fetch_comments (); + int size = 0; + while (msg != NULL) + { + size++; + msg = msg->next; + } + + // Initialize Java String array + Vector<char*> *list = new Vector<char*>(size); + msg = theDbeApplication->fetch_comments (); + size = 0; + int i = 0; + while (msg != NULL) + { + char *str = msg->get_msg (); + list->store (i, dbe_strdup (str)); + i++; + msg = msg->next; + } + + // now delete the comments + theDbeApplication->delete_comments (); + return list; +} + +Vector<char*> * +dbeGetExpPreview (int /*dbevindex*/, char *exp_name) +{ + PreviewExp *preview = new PreviewExp (); + preview->experiment_open (exp_name); + preview->open_epilogue (); + + // Initialize Java String array + Vector<char*> *info = preview->preview_info (); + int size = info->size (); + Vector<char*> *list = new Vector<char*>(size); + + // Get experiment names + for (int i = 0; i < size; i++) + { + char *str = info->fetch (i); + if (str == NULL) + str = GTXT ("N/A"); + list->store (i, dbe_strdup (str)); + } + delete info; + delete preview; + return list; +} + +char * +dbeGetExpParams (int /*dbevindex*/, char *exp_name) +{ + PreviewExp *preview = new PreviewExp (); + preview->experiment_open (exp_name); + + // Initialize Java String array + char *arg_list = dbe_strdup (preview->getArgList ()); + delete preview; + return arg_list; +} + +/** + * Gets File Attributes according to the specified format + * Supported formats: + * "/bin/ls -dl " - see 'man ls' for details + * @param filename + * @param format + * @return char * attributes + */ +char * +dbeGetFileAttributes (const char *filename, const char *format) +{ + if (format != NULL) + { + if (!strcmp (format, NTXT ("/bin/ls -dl "))) + { + // A kind of "/bin/ls -dl " simulation + struct stat64 sbuf; + sbuf.st_mode = 0; + dbe_stat (filename, &sbuf); + if (S_IREAD & sbuf.st_mode) + { // Readable + if (S_ISDIR (sbuf.st_mode) != 0) + return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("drwxrwxr-x"), filename); + else if (S_ISREG (sbuf.st_mode) != 0) + return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("-rwxrwxr-x"), filename); + } + } + } + return dbe_strdup (NTXT ("")); +} + +/** + * Gets list of files for specified directory according to the specified format + * Supported formats: + * "/bin/ls -a" - see 'man ls' for details + * "/bin/ls -aF" - see 'man ls' for details + * @param dirname + * @param format + * @return char * files + */ +char * +dbeGetFiles (const char *dirname, const char *format) +{ + if (format != NULL) + return dbe_read_dir (dirname, format); + return dbe_strdup (NTXT ("")); +} + +/** + * Creates the directory named by this full path name, including any + * necessary but nonexistent parent directories. + * @param dirname + * @return result + */ +char * +dbeCreateDirectories (const char *dirname) +{ + if (dirname != NULL) + { + char *res = dbe_create_directories (dirname); + if (res != NULL) + return res; + } + return dbe_strdup (NTXT ("")); +} + +/** + * Deletes the file or the directory named by the specified path name. + * If this pathname denotes a directory, then the directory must be empty in order to be deleted. + * @param const char *pathname + * @return int result + */ +char * +dbeDeleteFile (const char *pathname) +{ + // return unlink(pathname); + if (pathname != NULL) + { + char *res = dbe_delete_file (pathname); + if (res != NULL) + return res; + } + return dbe_strdup (NTXT ("")); +} + +/** + * Reads the file named by the specified path name. + * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit. + * If the operation was successful, the contents is in the first element, and second element is NULL. + * If the operation failed, then first element is NULL, and second element contains the error message. + * @param const char *pathname + * @return Vector<char*> *result + */ +Vector<char*> * +dbeReadFile (const char *pathname) +{ + Vector<char*> *result = new Vector<char*>(2); + int limit = 1024 * 1024; // Temporary limit: 1 MB + char * contents = (char *) malloc (limit); + StringBuilder sb; + if (NULL == contents) + { + sb.sprintf (NTXT ("\nError: Cannot allocate %d bytes\n"), limit); + result->store (0, NULL); + result->store (1, sb.toString ()); // failure + return result; + } + int fd = open (pathname, O_RDONLY); + if (fd >= 0) + { + int64_t bytes = read_from_file (fd, contents, limit); + close (fd); + if (bytes >= limit) + { + sb.sprintf (NTXT ("\nError: file size is greater than the limit (%d bytes)\n"), limit); + result->store (0, NULL); + result->store (1, sb.toString ()); // failure + } + else + { + contents[bytes] = '\0'; // add string terminator + result->store (0, contents); + result->store (1, NULL); // success + } + } + else + { + sb.sprintf (NTXT ("\nError: Cannot open file %s\n"), pathname); + result->store (0, NULL); + result->store (1, sb.toString ()); // failure + free (contents); + } + return result; +} + +/** + * Writes the file named by the specified path name. + * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit. + * If the operation failed, then -1 is returned. + * @param const char *pathname + * @return int result (written bytes) + */ +int +dbeWriteFile (const char *pathname, const char *contents) +{ + int result = -1; // error + size_t len = 0; + if (NULL != contents) + len = strlen (contents); + size_t limit = 1024 * 1024; // Temporary limit: 1 MB + if (len > limit) return result; + unlink (pathname); + mode_t mode = S_IRUSR | S_IWUSR; + int fd = open (pathname, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd >= 0) + { // replace file contents + chmod (pathname, /*S_IRUSR || S_IWUSR*/ 0600); // rw for owner only + ssize_t bytes = 0; + if (len > 0) + bytes = write (fd, contents, len); + close (fd); + result = (int) bytes; + } + return result; +} + +/** + * Gets list of running processes according to the specified format + * Supported formats: + * "/bin/ps -ef" - see 'man ps' for details + * @param format + * @return char * processes + */ +char * +dbeGetRunningProcesses (const char *format) +{ + if (format != NULL) + return dbe_get_processes (format); + return dbe_strdup (NTXT ("")); +} + +// +// Open experiment +// +char * +dbeOpenExperimentList (int /* dbevindex */, Vector<Vector<char*>*> *groups, + bool sessionRestart) +{ + if (sessionRestart) + dbeSession->reset (); + char *errstr; + // Open experiments + try + { + errstr = dbeSession->setExperimentsGroups (groups); + } + catch (ExperimentLoadCancelException *) + { + errstr = dbe_strdup (NTXT ("Experiment Load Cancelled")); + } + return errstr; +} + +// +// Drop experiments +// +char * +dbeDropExperiment (int /* dbevindex */, Vector<int> *drop_index) +{ + for (int i = drop_index->size () - 1; i >= 0; i--) + { + char *ret = dbeSession->drop_experiment (drop_index->fetch (i)); + if (ret != NULL) + return ret; + } + return NULL; +} + +/** + * Read .er.rc file from the specified location + * @param path + * @return + */ +char * +dbeReadRCFile (int dbevindex, char* path) +{ + DbeView *dbev = getDbeView (dbevindex); + char *err_msg = dbev->get_settings ()->read_rc (path); + return err_msg; +} + +char * +dbeSetExperimentsGroups (Vector<Vector<char*>*> *groups) +{ + int cmp_mode = dbeSession->get_settings ()->get_compare_mode (); + if (groups->size () < 2) + cmp_mode = CMP_DISABLE; + else if (cmp_mode == CMP_DISABLE) + cmp_mode = CMP_ENABLE; + for (int i = 0;; i++) + { + DbeView *dbev = dbeSession->getView (i); + if (dbev == NULL) + break; + dbev->get_settings ()->set_compare_mode (cmp_mode); + } + char *err_msg = dbeSession->setExperimentsGroups (groups); + + // automatically load machine model if applicable + dbeDetectLoadMachineModel (0); + return err_msg; +} + +Vector<Vector<char*>*> * +dbeGetExperimensGroups () +{ + Vector<Vector<char*>*> *grops = dbeSession->getExperimensGroups (); + return grops; +} + +Vector<int> * +dbeGetFounderExpId (Vector<int> *expIds) +{ + Vector<int> *ret = new Vector<int>(expIds->size ()); + for (int i = 0; i < expIds->size (); i++) + { + int expId = expIds->fetch (i); + Experiment *exp = dbeSession->get_exp (expId); + if (exp != NULL) + { + int founderExpId = exp->getBaseFounder ()->getExpIdx (); + ret->store (i, founderExpId); + } + else + ret->store (i, -1); + } + return ret; +} + +Vector<int> * +dbeGetUserExpId (Vector<int> *expIds) +{ + // returns "User Visible" ids used for EXPID filters and timeline processes + Vector<int> *ret = new Vector<int>(expIds->size ()); + for (int i = 0; i < expIds->size (); i++) + { + int expId = expIds->fetch (i); + Experiment *exp = dbeSession->get_exp (expId); + if (exp != NULL) + { + int userExpId = exp->getUserExpId (); + ret->store (i, userExpId); + } + else + ret->store (i, -1); + } + return ret; +} + +// +// Get experiment groupid +// +Vector<int> * +dbeGetExpGroupId (Vector<int> *expIds) +{ + Vector<int> *ret = new Vector<int>(expIds->size ()); + for (int i = 0; i < expIds->size (); i++) + { + int expId = expIds->fetch (i); + Experiment *exp = dbeSession->get_exp (expId); + if (exp != NULL) + { + int gId = exp->groupId; + ret->store (i, gId); + } + else + ret->store (i, -1); + } + return ret; +} + +Vector<char*> * +dbeGetExpsProperty (const char *prop_name) +{ + long nexps = dbeSession->nexps (); + if (prop_name == NULL || nexps == 0) + return NULL; + Vector<char*> *list = new Vector<char*>(nexps); + StringBuilder sb; + int empty = 1; + int prop = 99; + if (strcasecmp (prop_name, NTXT ("ERRORS")) == 0) + prop = 1; + else if (strcasecmp (prop_name, NTXT ("WARNINGS")) == 0) + prop = 2; + if (prop < 3) + { + for (long i = 0; i < nexps; i++) + { + Experiment *exp = dbeSession->get_exp (i); + char *nm = exp->get_expt_name (); + sb.setLength (0); + for (Emsg *emsg = (prop == 1) ? exp->fetch_errors () : exp->fetch_warnings (); + emsg; emsg = emsg->next) + sb.appendf (NTXT ("%s: %s\n"), STR (nm), STR (emsg->get_msg ())); + char *s = NULL; + if (sb.length () > 0) + { + s = sb.toString (); + empty = 0; + } + list->append (s); + } + } + if (empty) + { + delete list; + list = NULL; + } + return list; +} + +// +// Get experiment names +// +Vector<char*> * +dbeGetExpName (int /*dbevindex*/) +{ + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + // Initialize Java String array + Vector<char*> *list = new Vector<char*>(size); + + // Get experiment names + for (int i = 0; i < size; i++) + { + Experiment *texp = dbeSession->get_exp (i); + char *buf = dbe_sprintf (NTXT ("%s [%s]"), texp->get_expt_name (), + texp->utargname != NULL ? texp->utargname : GTXT ("(unknown)")); + list->store (i, buf); + } + return list; +} + +// +// Get experiment state +// +Vector<int> * +dbeGetExpState (int /* dbevindex */) +{ + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + // Initialize Java array + Vector<int> *state = new Vector<int>(size); + + // Get experiment state + for (int i = 0; i < size; i++) + { + Experiment *exp = dbeSession->get_exp (i); + int set = EXP_SUCCESS; + if (exp->get_status () == Experiment::FAILURE) + set |= EXP_FAILURE; + if (exp->get_status () == Experiment::INCOMPLETE) + set |= EXP_INCOMPLETE; + if (exp->broken) + set |= EXP_BROKEN; + if (exp->obsolete) + set |= EXP_OBSOLETE; + state->store (i, set); + } + return state; +} + +// +// Get enabled experiment indices +// +Vector<bool> * +dbeGetExpEnable (int dbevindex) +{ + DbeView *dbev = getDbeView (dbevindex); + int size = dbeSession->nexps (); + if (dbev == NULL || size == 0) + return NULL; + + // Get enabled experiment + Vector<bool> *enable = new Vector<bool>(size); + for (int i = 0; i < size; i++) + { + bool val = dbev->get_exp_enable (i) && !dbeSession->get_exp (i)->broken; + enable->store (i, val); + } + return enable; +} + +// +// Get enabled experiment indices +// +bool +dbeSetExpEnable (int dbevindex, Vector<bool> *enable) +{ + DbeView *dbev = getDbeView (dbevindex); + bool ret = false; + int size = dbeSession->nexps (); + if (dbev == NULL || size == 0) + return false; + + // set enable, as per input vector + for (int i = 0; i < size; i++) + if (!dbeSession->get_exp (i)->broken + && dbev->get_exp_enable (i) != enable->fetch (i)) + { + dbev->set_exp_enable (i, enable->fetch (i)); + ret = true; + } + return ret; +} + +// +// Get experiment info +// +Vector<char*> * +dbeGetExpInfo (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + + // Initialize Java String array + Vector<char*> *list = new Vector<char*>(size * 2 + 1); + + // Get experiment names + Vector<LoadObject*> *text_segments = dbeSession->get_text_segments (); + char *msg = pr_load_objects (text_segments, NTXT ("")); + delete text_segments; + list->store (0, msg); + int k = 1; + for (int i = 0; i < size; i++) + { + Experiment *exp = dbeSession->get_exp (i); + char *msg0 = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT ("")); + char *msg1 = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT ("")); + char *msg2 = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT ("")); + char *msg3 = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT ("")); + char *msg4 = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT ("")); + msg = dbe_sprintf (NTXT ("%s%s%s%s"), msg1, msg2, msg3, msg4); + list->store (k++, msg0); + list->store (k++, msg); + free (msg1); + free (msg2); + free (msg3); + free (msg4); + } + return list; +} + +bool +dbeGetViewModeEnable () +{ + return dbeSession->has_ompavail () || dbeSession->has_java (); +} + +bool +dbeGetJavaEnable () +{ + return dbeSession->has_java (); +} + +int +dbeUpdateNotes (int dbevindex, int exp_id, int type, char* text, bool handle_file) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + int size = dbeSession->nexps (); + if (size == 0) + return -1; + Experiment *exp = dbeSession->get_exp (exp_id); + return (type == 0) ? exp->save_notes (text, handle_file) : exp->delete_notes (handle_file); +} + +// +// Get load object names +// +Vector<char*> * +dbeGetLoadObjectName (int /* dbevindex */) +{ + Vector<LoadObject*> *lobjs = dbeSession->get_text_segments (); + int size = lobjs->size (); + + // Initialize Java String array + Vector<char*> *list = new Vector<char*>(size); + + // Get load object names + LoadObject *lo; + int index; + Vec_loop (LoadObject*, lobjs, index, lo) + { + list->store (index, dbe_strdup (lo->get_name ())); + } + delete lobjs; + return list; +} + +// XXX Will use later when order has to be passed too, +// Get complete List of tabs +// +Vector<void*> * +dbeGetTabList (int /* dbevindex */) +{ + //DbeView *dbev = getDbeView (dbevindex); + //Vector<void*> *tabs = dbeSession->get_TabList(); + //return tabs; + return NULL; +} + +// +// Returns list of available tabs +// +Vector<void*> * +dbeGetTabListInfo (int dbevindex) +{ + int index; + DispTab *dsptab; + DbeView *dbev = getDbeView (dbevindex); + + // make sure the tabs are initialized properly + dbev->get_settings ()->proc_tabs (theDbeApplication->rdtMode); + Vector<DispTab*> *tabs = dbev->get_TabList (); + + // Get number of available tabs + int size = 0; + Vec_loop (DispTab*, tabs, index, dsptab) + { + if (!dsptab->available) + continue; + size++; + } + Vector<void*> *data = new Vector<void*>(2); + Vector<int> *typelist = new Vector<int>(size); + Vector<char*> *cmdlist = new Vector<char*>(size); + Vector<int> *ordlist = new Vector<int>(size); + + // Build list of avaliable tabs + int i = 0; + + Vec_loop (DispTab*, tabs, index, dsptab) + { + if (!dsptab->available) + continue; + typelist->store (i, dsptab->type); + cmdlist->store (i, dbe_strdup (Command::get_cmd_str (dsptab->cmdtoken))); + ordlist->store (i, dsptab->order); + i++; + } + data->store (0, typelist); + data->store (1, cmdlist); + data->store (2, ordlist); + return data; +} + +// Return visibility state for all available tabs +// +Vector<bool> * +dbeGetTabSelectionState (int dbevindex) +{ + int index; + DispTab *dsptab; + DbeView *dbev = getDbeView (dbevindex); + Vector<DispTab*> *tabs = dbev->get_TabList (); + + // Get number of available tabs + int size = 0; + Vec_loop (DispTab*, tabs, index, dsptab) + { + if (!dsptab->available) + continue; + size++; + } + Vector<bool> *states = new Vector<bool>(size); + + // Get visibility bit for all available tabs + int i = 0; + Vec_loop (DispTab*, tabs, index, dsptab) + { + if (!dsptab->available) + continue; + states->store (i++, dsptab->visible); + } + return states; +} + +// Set visibility bit for a tab +void +dbeSetTabSelectionState (int dbevindex, Vector<bool> *selected) +{ + int index; + DispTab *dsptab; + DbeView *dbev = getDbeView (dbevindex); + Vector<DispTab*> *tabs = dbev->get_TabList (); + int i = 0; + Vec_loop (DispTab*, tabs, index, dsptab) + { + if (!dsptab->available) + continue; + dsptab->visible = selected->fetch (i++); + } +} + +// Return visibility state for all available MemObj tabs +Vector<bool> * +dbeGetMemTabSelectionState (int dbevindex) +{ + int index; + bool dsptab; + DbeView *dbev = getDbeView (dbevindex); + Vector<bool> *memtabs = dbev->get_MemTabState (); + + // set the output vector + int size = memtabs->size (); + Vector<bool> *states = new Vector<bool>(size); + + // Get visibility bit for all available tabs + int i = 0; + Vec_loop (bool, memtabs, index, dsptab) + { + states->store (i++, dsptab); + } + return states; +} + +// Set visibility bit for a memory tab +// +void +dbeSetMemTabSelectionState (int dbevindex, Vector<bool> *selected) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_MemTabState (selected); +} + +// Return visibility state for all available index tabs +Vector<bool> * +dbeGetIndxTabSelectionState (int dbevindex) +{ + int index; + bool dsptab; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<bool> *indxtabs = dbev->get_IndxTabState (); + + // set the output vector + int size = indxtabs->size (); + Vector<bool> *states = new Vector<bool>(size); + + // Get visibility bit for all available tabs + int i = 0; + Vec_loop (bool, indxtabs, index, dsptab) + { + states->store (i++, dsptab); + } + return states; +} + +// Set visibility bit for a index tab +void +dbeSetIndxTabSelectionState (int dbevindex, Vector<bool> *selected) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_IndxTabState (selected); +} + +// +// Get search path +// +Vector<char*> * +dbeGetSearchPath (int /*dbevindex*/) +{ + Vector<char*> *path = dbeSession->get_search_path (); + int size = path->size (); + Vector<char*> *list = new Vector<char*>(size); + int index; + char *name; + Vec_loop (char*, path, index, name) + { + list->store (index, dbe_strdup (name)); + } + return list; +} + +// +// Set search path +// +void +dbeSetSearchPath (int /*dbevindex*/, Vector<char*> *path) +{ + dbeSession->set_search_path (path, true); + return; +} + +// +// Get pathmaps +// +Vector<void*> * +dbeGetPathmaps (int /*dbevindex*/) +{ + int index; + pathmap_t *pthmap; + Vector<pathmap_t*> *path = dbeSession->get_pathmaps (); + int size = path->size (); + Vector<void*> *data = new Vector<void*>(2); + Vector<char*> *oldlist = new Vector<char*>(size); + Vector<char*> *newlist = new Vector<char*>(size); + + int i = 0; + Vec_loop (pathmap_t*, path, index, pthmap) + { + oldlist->store (i, dbe_strdup (pthmap->old_prefix)); + newlist->store (i, dbe_strdup (pthmap->new_prefix)); + i++; + } + data->store (0, oldlist); + data->store (1, newlist); + return data; +} // dbeGetPathmaps + +char * +dbeSetPathmaps (Vector<char*> *from, Vector<char*> *to) +{ + if (from == NULL || to == NULL || from->size () != to->size ()) + return dbe_strdup ("dbeSetPathmaps: size of 'from' does not match for size of 'to'\n"); + Vector<pathmap_t*> *newPath = new Vector<pathmap_t*>(from->size ()); + for (int i = 0, sz = from->size (); i < sz; i++) + { + char *err = Settings::add_pathmap (newPath, from->get (i), to->get (i)); + if (err) + { + newPath->destroy (); + delete newPath; + return err; + } + } + dbeSession->set_pathmaps (newPath); + return NULL; +} + +// +// Add pathmap +char * +dbeAddPathmap (int /* dbevindex */, char *from, char *to) +{ + Vector<pathmap_t*> *pmp = dbeSession->get_pathmaps (); + char *err = Settings::add_pathmap (pmp, from, to); + return err; +} + +// +// Get error/warning string of data +char * +dbeGetMsg (int dbevindex, int type) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + char *msgstr = NULL; + if (type == ERROR_MSG) + msgstr = dbev->get_error_msg (); + else if (type == WARNING_MSG) + msgstr = dbev->get_warning_msg (); + else if (type == PSTAT_MSG) + msgstr = dbev->get_processor_msg (PSTAT_MSG); + else if (type == PWARN_MSG) + msgstr = dbev->get_processor_msg (PWARN_MSG); + return msgstr ? dbe_strdup (msgstr) : NULL; +} + +// Create a DbeView, given new index, and index of view to clone +int +dbeInitView (int id, int cloneid) +{ + return dbeSession->createView (id, cloneid); +} + + +// Delete a DbeView +void +dbeDeleteView (int dbevindex) +{ + dbeSession->dropView (dbevindex); + return; +} // dbeDeleteView + +MetricList * +dbeGetMetricListV2 (int dbevindex, MetricType mtype, + Vector<int> *type, Vector<int> *subtype, Vector<bool> *sort, + Vector<int> *vis, Vector<char*> *cmd, + Vector<char*> *expr_spec, Vector<char*> *legends) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + MetricList *mlist = new MetricList (mtype); + for (int i = 0, msize = type->size (); i < msize; i++) + { + BaseMetric *bm = dbev->register_metric_expr ((BaseMetric::Type) type->fetch (i), + cmd->fetch (i), + expr_spec->fetch (i)); + Metric *m = new Metric (bm, (Metric::SubType) subtype->fetch (i)); + m->set_raw_visbits (vis->fetch (i)); + if (m->legend == NULL) + m->legend = dbe_strdup (legends->fetch (i)); + mlist->append (m); + if (sort->fetch (i)) + { + mlist->set_sort_ref_index (i); + } + } + return mlist; +} + +static Vector<void*> * +dbeGetMetricList (MetricList *mlist) +{ + int clock_val = dbeSession->get_clock (-1); + Vector<Metric*> *items = mlist->get_items (); + int size = items->size (); + + Vector<int> *type = new Vector<int>(size); + Vector<int> *subtype = new Vector<int>(size); + Vector<int> *clock = new Vector<int>(size); + Vector<int> *flavors = new Vector<int>(size); + Vector<int> *vis = new Vector<int>(size); + Vector<bool> *sorted = new Vector<bool>(size); + Vector<int> *value_styles = new Vector<int>(size); + Vector<char*> *aux = new Vector<char*>(size); + Vector<char*> *name = new Vector<char*>(size); + Vector<char*> *abbr = new Vector<char*>(size); + Vector<char*> *comd = new Vector<char*>(size); + Vector<char*> *unit = new Vector<char*>(size); + Vector<char*> *user_name = new Vector<char*>(size); + Vector<char*> *expr_spec = new Vector<char*>(size); + Vector<char*> *legend = new Vector<char*>(size); + Vector<int> *valtype = new Vector<int>(size); + Vector<char*> *data_type_name = new Vector<char*>(size); + Vector<char*> *data_type_uname = new Vector<char*>(size); + Vector<char*> *short_desc = new Vector<char*>(size); + + int sort_index = mlist->get_sort_ref_index (); + // Fill metric elements + for (int i = 0; i < size; i++) + { + Metric *m = items->fetch (i); + type->append (m->get_type ()); + subtype->append (m->get_subtype ()); + flavors->append (m->get_flavors ()); + abbr->append (dbe_strdup (m->get_abbr ())); + char *s = m->get_abbr_unit (); + if ((m->get_visbits () & VAL_RATIO) != 0) + s = NULL; + unit->append (dbe_strdup (s ? s : NTXT (""))); + value_styles->append (m->get_value_styles ()); + vis->append (m->get_visbits ()); + sorted->append (i == sort_index); + clock->append (m->get_type () == Metric::HWCNTR ? clock_val + : m->get_clock_unit ()); + aux->append (dbe_strdup (m->get_aux ())); + name->append (dbe_strdup (m->get_name ())); + comd->append (dbe_strdup (m->get_cmd ())); + user_name->append (dbe_strdup (m->get_username ())); + expr_spec->append (dbe_strdup (m->get_expr_spec ())); + legend->append (dbe_strdup (m->legend)); + valtype->append (m->get_vtype2 ()); + + char* _data_type_name = NULL; + char* _data_type_uname = NULL; + int data_type = m->get_packet_type (); + if (data_type >= 0 && data_type < DATA_LAST) + { + _data_type_name = dbe_strdup (get_prof_data_type_name (data_type)); + _data_type_uname = dbe_strdup (get_prof_data_type_uname (data_type)); + } + data_type_name->append (_data_type_name); + data_type_uname->append (_data_type_uname); + + char* _short_desc = NULL; + if (m->get_type () == Metric::HWCNTR) + { + Hwcentry * hwctr = m->get_hw_ctr (); + if (hwctr) + _short_desc = dbe_strdup (hwctr->short_desc); + } + short_desc->append (_short_desc); + } + + // Set Java array + Vector<void*> *data = new Vector<void*>(16); + data->append (type); + data->append (subtype); + data->append (clock); + data->append (flavors); + data->append (value_styles); + data->append (user_name); + data->append (expr_spec); + data->append (aux); + data->append (name); + data->append (abbr); + data->append (comd); + data->append (unit); + data->append (vis); + data->append (sorted); + data->append (legend); + data->append (valtype); + data->append (data_type_name); + data->append (data_type_uname); + data->append (short_desc); + return data; +} + +Vector<void*> * +dbeGetRefMetricsV2 () +{ + MetricList *mlist = new MetricList (MET_NORMAL); + Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics (); + for (long i = 0, sz = base_metrics->size (); i < sz; i++) + { + BaseMetric *bm = base_metrics->fetch (i); + Metric *m; + if (bm->get_flavors () & Metric::EXCLUSIVE) + { + m = new Metric (bm, Metric::EXCLUSIVE); + m->enable_all_visbits (); + mlist->append (m); + } + else if (bm->get_flavors () & BaseMetric::STATIC) + { + m = new Metric (bm, BaseMetric::STATIC); + m->enable_all_visbits (); + mlist->append (m); + } + } + Vector<void*> *data = dbeGetMetricList (mlist); + delete mlist; + return data; +} + +Vector<void*> * +dbeGetCurMetricsV2 (int dbevindex, MetricType mtype) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + MetricList *mlist = dbev->get_metric_list (mtype); + Vector<void*> *data = dbeGetMetricList (mlist); + return data; +} + +// YXXX we should refactor Metrics/BaseMetrics so that it no longer uses VAL_VALUE to enable time. +static int +convert_visbits_to_gui_checkbox_bits (BaseMetric *bm, const int visbits) +{ + // The purpose of this function is to handle the following case: + // When bm->get_value_styles() supports VAL_TIMEVAL but not VAL_VALUE + // Metric and BaseMetric use (visbits&VAL_VALUE) to enable time. + // However, the Overview expects the VAL_TIMEVAL bit to enable time. + // Inputs: visbits as returned by BaseMetric->get_default_visbits(); + // Returns: valuebits, as used for checks in GUI checkboxes + int valuebits = visbits; + const int value_styles = bm->get_value_styles (); + if ((value_styles & VAL_TIMEVAL) && // supports time + !(value_styles & VAL_VALUE)) + { // but not value + unsigned mask = ~(VAL_VALUE | VAL_TIMEVAL); + valuebits = (unsigned) valuebits & mask; // clear bits + if (visbits & VAL_VALUE) + valuebits |= VAL_TIMEVAL; // set VAL_TIMEVAL + if (visbits & VAL_TIMEVAL) + valuebits |= VAL_TIMEVAL; // weird, this should never happen. + } + return valuebits; +} + +static Vector<void*> * +dbeGetMetricTreeNode (BaseMetricTreeNode* curr, MetricList *mlist, + bool include_unregistered, bool has_clock_profiling_data) +{ + Vector<void*> *data = new Vector<void*>(2); + + // ----- fields + Vector<void*> *fields = new Vector<void*>(); + Vector<char*> *name = new Vector<char*>(1); + Vector<char*> *username = new Vector<char*>(1); + Vector<char*> *description = new Vector<char*>(1); + Vector<int> * flavors = new Vector<int>(1); + Vector<int> * vtype = new Vector<int>(1); + Vector<int> * vstyles_capable = new Vector<int>(1); + + // Specifies which default styles should be enabled when a metric is enabled. + // Also, specifies if metric should start enabled + Vector<int> *vstyles_e_defaults = new Vector<int>(1); + Vector<int> *vstyles_i_defaults = new Vector<int>(1); + Vector<bool> *registered = new Vector<bool>(1); + Vector<bool> *aggregation = new Vector<bool>(1); + Vector<bool> *has_value = new Vector<bool>(1); + Vector<char*> *unit = new Vector<char*>(1); + Vector<char*> *unit_uname = new Vector<char*>(1); + + char *_name = NULL; + char *_username = NULL; + char *_description = dbe_strdup (curr->get_description ()); + + // BaseMetric fields + int _flavors = 0; // SubType bitmask: (e.g. EXCLUSIVE) + int _vtype = 0; // ValueTag: e.g. VT_INT, VT_FLOAT, ... + int _vstyles_capable = 0; // ValueType bitmask, e.g. VAL_TIMEVAL + int _vstyles_e_default_values = 0; // default visibility settings, exclusive/static + int _vstyles_i_derault_values = 0; // default visibility settings, inclusive + bool _registered = curr->is_registered () + || curr->get_num_registered_descendents () > 0; + bool _aggregation = curr->is_composite_metric () + && curr->get_num_registered_descendents () > 0; + bool _has_value = false; //not used yet; for nodes that don't have metrics + char *_unit = NULL; + char *_unit_uname = NULL; + + BaseMetric *bm = curr->get_BaseMetric (); + if (bm) + { + _name = dbe_strdup (bm->get_cmd ()); + _username = dbe_strdup (bm->get_username ()); + if (!include_unregistered && !curr->is_registered ()) + abort (); + _flavors = bm->get_flavors (); + _vtype = bm->get_vtype (); + _vstyles_capable = bm->get_value_styles (); + int e_visbits = bm->get_default_visbits (BaseMetric::EXCLUSIVE); + int i_visbits = bm->get_default_visbits (BaseMetric::INCLUSIVE); + _vstyles_e_default_values = convert_visbits_to_gui_checkbox_bits (bm, e_visbits); + _vstyles_i_derault_values = convert_visbits_to_gui_checkbox_bits (bm, i_visbits); + // not all metrics shown in er_print cmd line should be selected in the GUI at startup: + if (has_clock_profiling_data && bm->get_hw_ctr ()) + { + bool hide = true; // by default, hide HWCs + if (dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("c_stalls")) == 0 || + dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("K_c_stalls")) == 0) + { + bool is_time = (bm->get_value_styles () & VAL_TIMEVAL) != 0; + if (is_time) + // By default, show time variant of c_stalls + hide = false; + } + if (hide) + { + _vstyles_e_default_values |= VAL_HIDE_ALL; + _vstyles_i_derault_values |= VAL_HIDE_ALL; + } + } + } + else + { + // not a base metric + _name = dbe_strdup (curr->get_name ()); + _username = dbe_strdup (curr->get_user_name ()); + if (curr->get_unit ()) + { // represents a value + _has_value = true; + _unit = dbe_strdup (curr->get_unit ()); + _unit_uname = dbe_strdup (curr->get_unit_uname ()); + } + } + name->append (_name); // unique id string (dmetrics cmd) + username->append (_username); // user-visible name + description->append (_description); + flavors->append (_flavors); // SubType bitmask: (e.g. EXCLUSIVE) + vtype->append (_vtype); // ValueTag: e.g. VT_INT, VT_FLOAT, ... + vstyles_capable->append (_vstyles_capable); // ValueType bitmask, e.g. VAL_TIMEVAL + vstyles_e_defaults->append (_vstyles_e_default_values); + vstyles_i_defaults->append (_vstyles_i_derault_values); + registered->append (_registered); // is a "live" metric + aggregation->append (_aggregation); // value derived from children nodes + has_value->append (_has_value); // value generated from other source + unit->append (_unit); // See BaseMetric.h, e.g. UNIT_SECONDS + unit_uname->append (_unit_uname); //See BaseMetric.h, + + fields->append (name); + fields->append (username); + fields->append (description); + fields->append (flavors); + fields->append (vtype); + fields->append (vstyles_capable); + fields->append (vstyles_e_defaults); + fields->append (vstyles_i_defaults); + fields->append (registered); + fields->append (aggregation); + fields->append (has_value); + fields->append (unit); + fields->append (unit_uname); + data->append (fields); + + // ----- children + Vector<BaseMetricTreeNode*> *children = curr->get_children (); + int num_children = children->size (); + Vector<void*> *children_list = new Vector<void*>(num_children); + BaseMetricTreeNode *child_node; + int index; + + Vec_loop (BaseMetricTreeNode*, children, index, child_node) + { + if (include_unregistered /* fetch everything */ + || child_node->is_registered () + || child_node->get_num_registered_descendents () > 0) + { + //Special case for metrics that aren't registered + // but have registered children + // Linux example: Total Time is unregistered, CPU Time is registered + if (!include_unregistered && /* not fetching everything */ + !child_node->is_registered () && + (child_node->get_BaseMetric () != NULL || + child_node->is_composite_metric ())) + { + Vector<BaseMetricTreeNode*> *registered_descendents = + new Vector<BaseMetricTreeNode*>(); + child_node->get_nearest_registered_descendents (registered_descendents); + int idx2; + BaseMetricTreeNode*desc_node; + Vec_loop (BaseMetricTreeNode*, registered_descendents, idx2, desc_node) + { + Vector<void*> *desc_data; + desc_data = dbeGetMetricTreeNode (desc_node, mlist, + include_unregistered, has_clock_profiling_data); + children_list->append (desc_data); + } + delete registered_descendents; + continue; + } + Vector<void*> *child_data; + child_data = dbeGetMetricTreeNode (child_node, mlist, + include_unregistered, has_clock_profiling_data); + children_list->append (child_data); + } + } + data->append (children_list); + return data; +} + +Vector<void*> * +dbeGetRefMetricTree (int dbevindex, bool include_unregistered) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + MetricList *mlist = dbev->get_metric_list (MET_NORMAL); + bool has_clock_profiling_data = false; + for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++) + { + Metric *m = mlist->get_items ()->fetch (i); + if (m->get_packet_type () == DATA_CLOCK) + { + has_clock_profiling_data = true; + break; + } + } + BaseMetricTreeNode *curr = dbeSession->get_reg_metrics_tree (); + return dbeGetMetricTreeNode (curr, mlist, include_unregistered, has_clock_profiling_data); +} + +static Vector<void*> * +dbeGetTableDataV2Data (DbeView *dbev, Hist_data *data); + +static Vector<void*> *dbeGetTableDataOneColumn (Hist_data *data, int met_ind); +static Vector<void*> * +dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data, + ValueTag vtype, int metricColumnNumber); + +static hrtime_t +dbeCalcGroupDuration (int grInd) +{ + int thisGroupSize = 1; + hrtime_t max_time = 0; + Experiment *exp; + if (dbeSession->expGroups->size () > 0) + { + ExpGroup *grp = dbeSession->expGroups->fetch (grInd); + thisGroupSize = grp->exps->size (); + for (int ii = 0; ii < thisGroupSize; ii++) + { + exp = grp->exps->fetch (ii); + Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors (); + delete ddscr;// getDataDescriptors() forces reading of experiment data + if (exp != NULL) + { + hrtime_t tot_time = exp->getLastEvent () - exp->getStartTime () + + exp->getRelativeStartTime (); + if (max_time < tot_time) + max_time = tot_time; + } + } + } + else + { + exp = dbeSession->get_exp (0); + if (exp != NULL) + max_time = exp->getLastEvent () - exp->getStartTime (); + } + return max_time; //nanoseconds +} + +static hrtime_t +dbeCalcGroupGCDuration (int grInd) +{ + int thisGroupSize = 1; + hrtime_t tot_time = 0; + Experiment *exp; + if (dbeSession->expGroups->size () > 0) + { + ExpGroup *grp = dbeSession->expGroups->fetch (grInd); + thisGroupSize = grp->exps->size (); + for (int ii = 0; ii < thisGroupSize; ii++) + { + exp = grp->exps->fetch (ii); + Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors (); + delete ddscr; // getDataDescriptors() forces reading of experiment data + if (exp != NULL) + tot_time += exp->getGCDuration (); + } + } + else + { + exp = dbeSession->get_exp (0); + if (exp != NULL) + tot_time = exp->getGCDuration (); + } + return tot_time; //nanoseconds +} + +Vector<void*> * +dbeGetRefMetricTreeValues (int dbevindex, Vector<char *> *metric_cmds, + Vector<char *> *non_metric_cmds) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + // valueTable will have N "columns" of values, where N is the number of + // requested metrics and non-metrics. + // Each column will be a vector with M "rows", where M is the number of + // compare groups. + // highlightTable mirrors the structure of valueTable. Each cell indicates + // if the corresponding valueTable cell is "hot" (interesting) + int numMetrics = metric_cmds->size (); + int numNonMetrics = non_metric_cmds->size (); + int totalColumns = numMetrics + numNonMetrics; // Columns + Vector<void*> *valueTable = new Vector<void*>(totalColumns); + Vector<void*> *highlightTable = new Vector<void*>(totalColumns); + + // the return value consists of the two tables discussed above. + Vector<void*> *rc = new Vector<void*>(2); + rc->append (valueTable); + rc->append (highlightTable); + if (dbeSession->nexps () == 0) + { // no experiments are loaded + for (int jj = 0; jj < totalColumns; jj++) + { + Vector<void *> *columnData = new Vector<void *>(); + valueTable->append (columnData); + highlightTable->append (columnData); + } + return rc; + } + + int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group) + if (ngroups == 0 || !dbev->comparingExperiments ()) + ngroups = 1; + + Vector<double> *groupTotalTime = new Vector<double>(ngroups); + Vector<double> *groupCpuTime = new Vector<double>(ngroups); + // initialize highlight table + for (int ii = 0; ii < totalColumns; ii++) + { // metrics + Vector<bool> *columnData = new Vector<bool>(ngroups); + highlightTable->append (columnData); + for (int grInd = 0; grInd < ngroups; grInd++) + columnData->store (grInd, false); // non-highlight + } + + if (numMetrics > 0) + { + MetricList *bmlist; + // set bmlist to list of requested base metrics + BaseMetricTreeNode *root = dbeSession->get_reg_metrics_tree (); + int index; + char *mcmd; + Vector<BaseMetric*> *base_metrics = new Vector<BaseMetric*>(); + Vec_loop (char *, metric_cmds, index, mcmd) + { + BaseMetricTreeNode *bmt_node = root->find (mcmd); + if (!bmt_node) + abort (); //YXXX weird + BaseMetric * baseNetric = bmt_node->get_BaseMetric (); + if (!baseNetric) + abort (); + base_metrics->append (baseNetric); + } + + // MET_INDX will create MetricList of Exclusive metrics + bmlist = new MetricList (base_metrics, MET_SRCDIS); + + // Use the Function List to fetch <Total> values + // A temporary table, v_totals, stores <total> by group + Vector<Hist_data::HistItem *> *v_totals = new Vector<Hist_data::HistItem *>(ngroups); + for (int grInd = 0; grInd < ngroups; grInd++) + { + MetricList *mlist; + if (ngroups > 1) + mlist = dbev->get_compare_mlist (bmlist, grInd); + else + mlist = bmlist; + if (mlist->size () != numMetrics) + abort (); + + Hist_data *data; + data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, + Hist_data::ALL); + Hist_data::HistItem * totals = data->get_totals (); + v_totals->append (totals); + } + + // store the Hist_data totals in valueTable + { + Metric *mitem; + int index; + Vec_loop (Metric*, bmlist->get_items (), index, mitem) + { + Vector<void*> * columnData = dbeGetTableDataOneColumn (dbev, + v_totals, mitem->get_vtype (), index); + valueTable->append (columnData); + } + } + + // 7207285: hack for hwc profiling cycles conversion: + { + Metric *mitem; + int index; + Vec_loop (Metric*, bmlist->get_items (), index, mitem) + { + if (mitem->is_time_val () + && mitem->get_vtype () == VT_ULLONG) + { + Vector<long long> *cycleValues = (Vector<long long> *)valueTable->fetch (index); + Vector<double> *timeValues = new Vector<double>(ngroups); + assert (cycleValues->size () == ngroups); + for (int grInd = 0; grInd < ngroups; grInd++) + { + long long cycles = cycleValues->fetch (grInd); + int expId; + if (dbeSession->expGroups->size () > 0) + { + ExpGroup *gr = dbeSession->expGroups->fetch (grInd); + Experiment *exp = gr->exps->fetch (0); + expId = exp->getExpIdx (); + } + else + expId = -1; + int clock = dbeSession->get_clock (expId); + double time; + if (clock) + time = cycles / (1.e+6 * clock); + else + time = cycles; //weird + timeValues->store (grInd, time); + } + delete cycleValues; + valueTable->store (index, timeValues); + } + } + } + + // Scan metrics for best measure of CPU time + int bestCpuTimeIndx = -1; + { + Metric *mitem; + int index; + Vec_loop (Metric*, bmlist->get_items (), index, mitem) + { + BaseMetric::Type type = mitem->get_type (); + if (type == BaseMetric::CP_KERNEL_CPU) + { + bestCpuTimeIndx = index; + break; // CP_KERNEL_CPU trumps other measures + } + if (type == BaseMetric::CP_TOTAL_CPU) + { + // clock profiling CPU time + bestCpuTimeIndx = index; + // keep looking in case CP_KERNEL_CPU also exists + continue; + } + + bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0); + bool isHwcCycles = (type == BaseMetric::HWCNTR + && (dbe_strcmp (mitem->get_aux (), "cycles") == 0) + && isTime); + if (isHwcCycles) + if (bestCpuTimeIndx < 0) + bestCpuTimeIndx = index; + } + if (bestCpuTimeIndx >= 0) + { + Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (bestCpuTimeIndx); + if (timeValues->type () == VEC_DOUBLE) + for (int grInd = 0; grInd < ngroups; grInd++) + { + double time = timeValues->fetch (grInd); + groupCpuTime->append (time); + } + } + } + + // Scan metrics for Total Thread time + { + Metric *mitem; + int index; + Vec_loop (Metric*, bmlist->get_items (), index, mitem) + { + BaseMetric::Type type = mitem->get_type (); + if (type == BaseMetric::CP_TOTAL) + { + Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index); + if (timeValues->type () != VEC_DOUBLE) + continue; // weird + for (int grInd = 0; grInd < ngroups; grInd++) + { + double time = timeValues->fetch (grInd); + groupTotalTime->append (time); + } + break; + } + } + } + + // highlight metrics based on cpu time +#define CPUSEC_PERCENT_THRESHOLD 10.0 +#define HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD 15 + { + Metric *mitem; + int index; + Vec_loop (Metric*, bmlist->get_items (), index, mitem) + { + BaseMetric::Type type = mitem->get_type (); + Vector<bool> * columnHilites = (Vector<bool> *)highlightTable->fetch (index); + + // always highlight the following + if (index == bestCpuTimeIndx) + { + for (int grInd = 0; grInd < ngroups; grInd++) + columnHilites->store (grInd, true); + continue; + } + + // skip certain types + bool typeIsCycles = (type == BaseMetric::HWCNTR + && dbe_strcmp (mitem->get_aux (), NTXT ("cycles")) == 0); + bool typeIsInsts = (type == BaseMetric::HWCNTR + && dbe_strcmp (mitem->get_aux (), NTXT ("insts")) == 0); + if (type == BaseMetric::CP_TOTAL + || type == BaseMetric::CP_TOTAL_CPU + || type == BaseMetric::CP_LMS_USER + || type == BaseMetric::CP_LMS_SYSTEM + || type == BaseMetric::CP_LMS_TRAP + || type == BaseMetric::CP_LMS_USER_LOCK + || type == BaseMetric::CP_LMS_SLEEP + || type == BaseMetric::CP_KERNEL_CPU + || type == BaseMetric::OMP_WORK + || typeIsCycles + || typeIsInsts + // || type == BaseMetric::CP_TOTAL_WAIT + ) + continue; // types we never highlight + + // for time values, compare against CPUSEC_PERCENT_THRESHOLD + bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0); + if (isTime) + { + if (groupCpuTime->size () == 0) + continue; // no time to use as reference + Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index); + if (timeValues->type () != VEC_DOUBLE) + continue; // weird + for (int grInd = 0; grInd < ngroups; grInd++) + { + double thistime = timeValues->fetch (grInd); + double usertime = groupCpuTime->fetch (grInd); + if (thistime / (CPUSEC_PERCENT_THRESHOLD / 100) > usertime) + columnHilites->store (grInd, true); + } + continue; + } + + // for HWC event counts, look at rate of events + if (type == BaseMetric::HWCNTR) + { + Hwcentry *hwctr = mitem->get_hw_ctr (); + if (!hwctr) + continue; // weird + if (!hwctr->metric) + continue; // raw counter + if (groupCpuTime->size () == 0) + continue; // no time to use as reference + if (mitem->get_base_metric ()->get_dependent_bm ()) + continue; // has a derived time metric, only flag time version + Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index); + if (llValues->type () != VEC_LLONG) + continue; // weird + int overflowVal = hwctr->val; //overflow count + if (!overflowVal) + continue; // weird + if (overflowVal > (4000000)) + // cut off events that are very frequent like loads/stores + // 4Ghz * (0.01 seconds/event) / (4000000 events/overflow) = 10 cycles + continue; + // for HWCs we could base it on the overflow rate + for (int grInd = 0; grInd < ngroups; grInd++) + { + double thisVal = llValues->fetch (grInd); + thisVal /= overflowVal; + double usertime = groupCpuTime->fetch (grInd); + if (thisVal > usertime * HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD) + columnHilites->store (grInd, true); + } + continue; + } + + // check for non-zero counts of the following + if (type == BaseMetric::DEADLOCKS || + type == BaseMetric::RACCESS || + type == BaseMetric::HEAP_ALLOC_BYTES || + type == BaseMetric::HEAP_LEAK_BYTES) + { + Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index); + if (llValues->type () != VEC_LLONG) + continue; // weird + for (int grInd = 0; grInd < ngroups; grInd++) + { + long long thisVal = llValues->fetch (grInd); + if (thisVal) + columnHilites->store (grInd, true); + } + continue; + } + // continue adding cases as needed + } + } + } + + if (numNonMetrics > 0) + { + int index; + char *mcmd; + Vec_loop (char *, non_metric_cmds, index, mcmd) + { + if (dbe_strcmp (mcmd, NTXT ("YXXX_TOTAL_TIME_PLUS_THREADS")) == 0 + && groupCpuTime->size () == ngroups) + { + Vector<char *> *columnData = new Vector<char *>(ngroups); + for (int grInd = 0; grInd < ngroups; grInd++) + { + double totaltime = groupTotalTime->fetch (grInd); + columnData->append (dbe_sprintf (NTXT ("%0.3f %s"), totaltime, GTXT ("Seconds"))); + } + valueTable->append (columnData); + } + else if (dbe_strcmp (mcmd, L1_DURATION) == 0) + { + Vector<double> *columnData = new Vector<double>(ngroups); + for (int grInd = 0; grInd < ngroups; grInd++) + { + hrtime_t duration = dbeCalcGroupDuration (grInd); + double seconds = duration * 1.e-9; + columnData->append (seconds); + } + valueTable->append (columnData); + } + else if (dbe_strcmp (mcmd, L1_GCDURATION) == 0) + { + Vector<double> *columnData = new Vector<double>(ngroups); + for (int grInd = 0; grInd < ngroups; grInd++) + { + hrtime_t duration = dbeCalcGroupGCDuration (grInd); + double seconds = duration * 1.e-9; + columnData->append (seconds); + } + valueTable->append (columnData); + } + else + { + Vector<char *> *columnData = new Vector<char *>(ngroups); + char * valueString = NTXT ("<unknown>"); + for (int grInd = 0; grInd < ngroups; grInd++) + columnData->append (dbe_strdup (valueString)); + valueTable->append (columnData); + } + } + } + return rc; +} + +Vector<char*> * +dbeGetOverviewText (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + Vector<char*> *info = new Vector<char*>; + char *field; + int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group) + if (ngroups == 0 || !dbev->comparingExperiments ()) + ngroups = 1; + for (int grInd = 0; grInd < ngroups; grInd++) + { + int thisGroupSize = 1; + Experiment *exp; + if (dbeSession->expGroups->size () > 0) + { + ExpGroup *gr = dbeSession->expGroups->fetch (grInd); + exp = gr->exps->fetch (0); + thisGroupSize = gr->exps->size (); + } + else + { + if (dbeSession->nexps () == 0) + return info; + exp = dbeSession->get_exp (0); + } + char * expHeader; + if (ngroups == 1) + expHeader = dbe_strdup (GTXT ("Experiment :")); + else if (grInd == 0) + expHeader = dbe_strdup (GTXT ("Base Group : ")); + else if (ngroups == 2) + expHeader = dbe_strdup (GTXT ("Compare Group : ")); + else + expHeader = dbe_sprintf (GTXT ("Compare Group %d : "), grInd); + if (thisGroupSize == 1) + info->append (dbe_sprintf ("%s%s", expHeader, exp->get_expt_name ())); + else + info->append (dbe_sprintf ("%s%s (plus %d more)", + expHeader, exp->get_expt_name (), thisGroupSize - 1)); + free (expHeader); + field = exp->uarglist; + if (field && field[0]) + info->append (dbe_sprintf (GTXT (" Target : '%s'"), field)); + field = exp->hostname; + if (field && field[0]) + info->append (dbe_sprintf (NTXT (" %s %s (%s, %s)"), + GTXT ("Host :"), + field, + exp->architecture ? exp->architecture + : GTXT ("<CPU architecture not recorded>"), + exp->os_version ? exp->os_version + : GTXT ("<OS version not recorded>"))); + long start_sec = exp->start_sec; + char *p = ctime (&start_sec); // does this need to be freed? YXXX + hrtime_t tot_time = dbeCalcGroupDuration (grInd); + double seconds = tot_time * 1.e-9; + info->append (dbe_sprintf (NTXT (" %s %s %s %0.3f %s"), + GTXT ("Start Time :"), p, + GTXT ("Duration :"), seconds, + GTXT ("Seconds"))); + // Number of descendants/processes would be nice + info->append (dbe_strdup (NTXT (""))); + } + return info; +} + +//-------------------------------------------------------------------------- +// Set Sort by index +// +void +dbeSetSort (int dbevindex, int sort_index, MetricType mtype, bool reverse) +{ + DbeView *dbev; + + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->setSort (sort_index, mtype, reverse); + return; +} + +// +// Get annotation setting +// +Vector<int> * +dbeGetAnoValue (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<int> *set = new Vector<int>(9); + set->store (0, dbev->get_src_compcom ()); + set->store (1, dbev->get_dis_compcom ()); + set->store (2, dbev->get_thresh_src ()); + set->store (3, dbev->get_thresh_src ()); + set->store (4, dbev->get_src_visible ()); + set->store (5, (int) dbev->get_srcmetric_visible ()); + set->store (6, (int) dbev->get_hex_visible ()); + set->store (7, (int) dbev->get_cmpline_visible ()); + set->store (8, (int) dbev->get_func_scope ()); + return set; +} + +// +// Set annotation setting +// +void +dbeSetAnoValue (int dbevindex, Vector<int> *set) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (set->size () != 10) + return; + dbev->set_src_compcom (set->fetch (0)); + dbev->set_dis_compcom (set->fetch (1)); + dbev->set_thresh_src (set->fetch (2)); + dbev->set_thresh_dis (set->fetch (3)); + dbev->set_src_visible (set->fetch (4)); + dbev->set_srcmetric_visible ((bool)set->fetch (5)); + dbev->set_hex_visible ((bool)set->fetch (6)); + dbev->set_cmpline_visible ((bool)set->fetch (7)); + dbev->set_func_scope (set->fetch (8)); + dbev->set_funcline_visible ((bool)set->fetch (9)); + return; +} + +// +// Get name formats +// +int +dbeGetNameFormat (int dbevindex) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable::NameFormat fmt = dbev->get_name_format (); + return Histable::fname_fmt (fmt); +} + +bool +dbeGetSoName (int dbevindex) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable::NameFormat fmt = dbev->get_name_format (); + return Histable::soname_fmt (fmt); +} + +// +// Set name formats +// +void +dbeSetNameFormat (int dbevindex, int nformat, bool soname) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_name_format (nformat, soname); +} + +// +// Get View mode +// +int +dbeGetViewMode (int dbevindex) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return (int) dbev->get_view_mode (); +} + +// Set View mode +void +dbeSetViewMode (int dbevindex, int nmode) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_view_mode ((VMode) nmode); + return; +} + +// Get timeline setting +// +Vector<void*> * +dbeGetTLValue (int dbevindex) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<char *> *strings = new Vector<char *>(); + char *tldata_cmd = dbev->get_tldata (); + strings->store (0, tldata_cmd); + + Vector<int> *ints = new Vector<int>(3); + int val; + val = dbev->get_tlmode (); + ints->store (0, val); + val = dbev->get_stack_align (); + ints->store (1, val); + val = dbev->get_stack_depth (); + ints->store (2, val); + + Vector<void*> *objs = new Vector<void*>(2); + objs->store (0, strings); + objs->store (1, ints); + return objs; +} + +// +// Set timeline setting +// +void +dbeSetTLValue (int dbevindex, const char *tldata_cmd, + int entitiy_prop_id, int stackalign, int stackdepth) +{ + DbeView *dbev; + dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_tldata (tldata_cmd); + dbev->set_tlmode (entitiy_prop_id); + dbev->set_stack_align (stackalign); + dbev->set_stack_depth (stackdepth); + return; +} + +// +// Get founder experiments and their descendants +// +Vector<void*> * +dbeGetExpFounderDescendants () +{ + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + Vector<void*> *table = new Vector<void*>(2); + Vector<int> *founderExpIds = new Vector<int>(); + Vector<Vector<int> *> *subExpIds = new Vector<Vector<int>*>(); + for (int index = 0; index < size; index++) + { + Experiment *exp = dbeSession->get_exp (index); + if (exp->founder_exp == NULL) + { + founderExpIds->append (exp->getExpIdx ()); + Vector<int> *subExps = new Vector<int>(); + for (int i = 0; i < exp->children_exps->size (); i++) + { + Experiment * subExp = exp->children_exps->fetch (i); + subExps->append (subExp->getExpIdx ()); + } + subExpIds->append (subExps); + } + } + table->store (0, founderExpIds); + table->store (1, subExpIds); + return table; +} + +// +// Get experiment selection +// +Vector<void*> * +dbeGetExpSelection (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + Vector<void*> *table = new Vector<void*>(3); + Vector<char*> *names = new Vector<char*>(size); + Vector<bool> *enable = new Vector<bool>(size); + Vector<int> *userExpIds = new Vector<int>(size); + + // Get experiment names + for (int index = 0; index < size; index++) + { + Experiment *exp = dbeSession->get_exp (index); + char *buf = dbeGetName (dbevindex, index); + names->store (index, buf); + bool val; + val = dbev->get_exp_enable (index); + enable->store (index, val); + userExpIds->store (index, exp->getUserExpId ()); + } + table->store (0, names); + table->store (1, enable); + table->store (2, userExpIds); + return table; +} + +int +dbeValidateFilterExpression (char *str_expr) +{ + if (str_expr == NULL) + return 0; + Expression *expr = dbeSession->ql_parse (str_expr); + if (expr == NULL) + return 0; + delete expr; + return 1; +} + +Vector<void*> * +dbeGetFilterKeywords (int /* dbevindex */) +{ + Vector <char*> *kwCategory = new Vector<char *>(); + Vector <char*> *kwCategoryI18N = new Vector<char *>(); + Vector <char*> *kwDataType = new Vector<char *>(); + Vector <char*> *kwKeyword = new Vector<char *>(); + Vector <char*> *kwFormula = new Vector<char *>(); + Vector <char*> *kwDescription = new Vector<char *>(); + Vector <void*> *kwEnumDescs = new Vector<void *>(); + + Vector<void*> *res = new Vector<void*>(7); + res->append (kwCategory); + res->append (kwCategoryI18N); + res->append (kwDataType); + res->append (kwKeyword); + res->append (kwFormula); + res->append (kwDescription); + res->append (kwEnumDescs); + + char *vtypeNames[] = VTYPE_TYPE_NAMES; + // section header for global definitions + kwCategory->append (dbe_strdup (NTXT ("FK_SECTION"))); + kwCategoryI18N->append (dbe_strdup (GTXT ("Global Definitions"))); + kwDataType->append (NULL); + kwKeyword->append (NULL); + kwFormula->append (NULL); + kwDescription->append (NULL); + kwEnumDescs->append (NULL); + dbeSession->get_filter_keywords (res); + MemorySpace::get_filter_keywords (res); + + // loop thru all founder experiments + int nexp = dbeSession->nexps (); + for (int ii = 0; ii < nexp; ++ii) + { + Experiment* fexp = dbeSession->get_exp (ii); + if (fexp->founder_exp != NULL) + continue; // is a child; should be covered when we get to founder + + // section header for each founder + // section header for founder experiment + kwCategory->append (dbe_strdup (NTXT ("FK_SECTION"))); + kwCategoryI18N->append (dbe_sprintf (NTXT ("%s [EXPGRID==%d]"), + fexp->get_expt_name (), + fexp->groupId)); + kwDataType->append (NULL); + kwKeyword->append (NULL); + kwFormula->append (NULL); + kwDescription->append (NULL); + kwEnumDescs->append (NULL); + + int nchildren = fexp->children_exps->size (); + Experiment *exp; + // category header: Experiments + { + char *propUName = dbeSession->getPropUName (PROP_EXPID); + + // store list of subexperiments in kwEnumDescs + Vector <char*> *enumDescs = new Vector<char *>(); + int jj = 0; + exp = fexp; + while (1) + { + char * expBasename = get_basename (exp->get_expt_name ()); + char * targetName = exp->utargname ? exp->utargname + : (char *) GTXT ("(unknown)"); + enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s [%s, PID %d]"), + exp->getUserExpId (), expBasename, + targetName, exp->getPID ())); + if (jj >= nchildren) + break; + exp = fexp->children_exps->fetch (jj); + jj++; + } + kwCategory->append (dbe_strdup (NTXT ("FK_EXPLIST"))); + kwCategoryI18N->append (dbe_strdup (GTXT ("Experiments"))); + kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT32])); + kwKeyword->append (dbe_strdup (NTXT ("EXPID"))); + kwFormula->append (NULL); + kwDescription->append (propUName); + kwEnumDescs->append (enumDescs); + } + + // select representative experiment + if (nchildren == 0) + exp = fexp; // founder + else + exp = fexp->children_exps->fetch (0); // first child + int expIdx = exp->getExpIdx (); + Vector<void*> *data = dbeGetDataDescriptorsV2 (expIdx); + if (data == NULL) + continue; + Vector<int> *dataId = (Vector<int>*)data->fetch (0); + Vector<char*> *dataName = (Vector<char*>*)data->fetch (1); + Vector<char*> *dataUName = (Vector<char*>*)data->fetch (2); + if (dataId == NULL || dataName == NULL) + { + destroy (data); + continue; + } + // loop thru data descriptors + int ndata = dataId->size (); + for (int j = 0; j < ndata; ++j) + { + // category: data name (e.g. Clock Profiling) + char * catName = dataName->fetch (j); + char * dUname = dataUName ? dataUName->fetch (j) : catName; + char * catUname = dUname ? dUname : catName; + + Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j)); + if (props == NULL) + continue; + Vector<char*> *propUName = (Vector<char*>*)props->fetch (1); + Vector<int> *propTypeId = (Vector<int> *)props->fetch (2); + Vector<char*> *propType = (Vector<char*>*)props->fetch (3); + Vector<char*> *propName = (Vector<char*>*)props->fetch (5); + Vector<Vector<char*>*> *propStateNames = + (Vector<Vector<char*>*> *)props->fetch (6); + Vector<Vector<char*>*> *propStateUNames = + (Vector<Vector<char*>*> *)props->fetch (7); + if (propName == NULL || propUName == NULL || propType == NULL + || propName->size () <= 0) + { + destroy (props); + continue; + } + int nprop = propName->size (); + for (int k = 0; k < nprop; ++k) + { + if (propTypeId->fetch (k) == TYPE_OBJ) + continue; + if (dbe_strcmp (propName->fetch (k), NTXT ("FRINFO")) == 0) + continue; + + // store list of states in kwEnumDescs + Vector<char*> *enumDescs = new Vector<char *>(); + Vector<char*>* stateNames = propStateNames->fetch (k); + Vector<char*>* stateUNames = propStateUNames->fetch (k); + int nStates = stateNames ? stateNames->size () : 0; + for (int kk = 0; kk < nStates; ++kk) + { + const char *stateName = stateNames->fetch (kk); + if (stateName == NULL || strlen (stateName) == 0) + continue; + const char *stateUName = stateUNames->fetch (kk); + if (stateUName == NULL || strlen (stateUName) == 0) + stateUName = stateName; + enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s"), kk, stateUName)); + } + kwCategory->append (dbe_strdup (catName)); + kwCategoryI18N->append (dbe_strdup (catUname)); + kwDataType->append (dbe_strdup (propType->fetch (k))); + kwKeyword->append (dbe_strdup (propName->fetch (k))); + kwFormula->append (NULL); + kwDescription->append (dbe_strdup (propUName->fetch (k))); + kwEnumDescs->append (enumDescs); + } + destroy (props); + } + destroy (data); + } + return (res); +} + +// GetFilters -- returns the list of filters for the indexed experiment +// returns false if there's a problem; true otherwise +// +Vector<void*> * +dbeGetFilters (int dbevindex, int nexp) +{ + FilterNumeric *filt; + int index; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<FilterNumeric *>*filters = dbev->get_all_filters (nexp); + if (filters == NULL) + return NULL; + + // return an array of filter data for that experiment + Vector <int> *findex = new Vector<int>(); // index of the filters + Vector <char*> *shortname = new Vector<char *>(); + // short name of filter + Vector <char*> *i18n_name = new Vector<char *>(); + // External I18N'd name of filter + Vector <char*> *pattern = new Vector<char *>(); + // current setting string + Vector <char*> *status = new Vector<char *>(); + // current status of filter (%, range, etc.) + + Vec_loop (FilterNumeric *, filters, index, filt) + { + findex->append (index); + shortname->append (dbe_strdup (filt->get_cmd ())); + i18n_name->append (dbe_strdup (filt->get_name ())); + pattern->append (dbe_strdup (filt->get_pattern ())); + status->append (dbe_strdup (filt->get_status ())); + } + Vector<void*> *res = new Vector<void*>(5); + res->store (0, findex); + res->store (1, shortname); + res->store (2, i18n_name); + res->store (3, pattern); + res->store (4, status); + return (res); +} + +// Set a filter string for a view +// Returns NULL if OK, error message if not + +char * +dbeSetFilterStr (int dbevindex, char *filter_str) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->clear_error_msg (); + dbev->clear_warning_msg (); + char *ret = dbev->set_filter (filter_str); + return ret; +} + +// Get the current filter setting for the view +char * +dbeGetFilterStr (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + char *ret = dbev->get_filter (); + return ret; +} + +// Update a filters for a single experiment +// Returns true if any filter->set_pattern() returns true, +// implying rereading the data is needed (i.e., a filter changed) +// +bool +dbeUpdateFilters (int dbevindex, Vector<bool> *selected, Vector<char *> *pattern_str) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->clear_error_msg (); + dbev->clear_warning_msg (); + + // Get index of first selected experiment + int size = selected->size (); + int nselexp = -1; + for (int index = 0; index < size; index++) + { + if (selected->fetch (index) == true) + { + nselexp = index; + break; + } + } + if (nselexp == -1) // No experiment selected + return false; + + bool ret = false; + for (int j = 0; j < size; j++) + { + if (selected->fetch (j) == false) + continue; + bool error; + if (dbev->set_pattern (j, pattern_str, &error)) + ret = true; + } + dbev->update_advanced_filter (); + return ret; +} + +char * +dbeComposeFilterClause (int dbevindex, int type, int subtype, Vector<int> *selections) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + // ask the cached data to generate the string + Hist_data *data; + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + case DSP_DLAYOUT: + data = dbev->dlay_data; + break; + case DSP_DATAOBJ: + data = dbev->dobj_data; + break; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + data = dbev->get_indxobj_data (subtype); + break; + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_SOURCE: + data = dbev->src_data; + break; + case DSP_DISASM: + data = dbev->dis_data; + break; + case DSP_IOACTIVITY: + data = dbev->iofile_data; + break; + case DSP_IOVFD: + data = dbev->iovfd_data; + break; + case DSP_IOCALLSTACK: + data = dbev->iocs_data; + break; + case DSP_HEAPCALLSTACK: + data = dbev->heapcs_data; + break; + default: + return NULL; + } + if (data == NULL) + return NULL; + + // Get array of object indices, and compose filter string + Vector<uint64_t> *obj_ids = data->get_object_indices (selections); + if (obj_ids == NULL || obj_ids->size () == 0) + return NULL; + + uint64_t sel; + int index; + int found = 0; + char buf[128]; + StringBuilder sb; + sb.append ('('); + switch (type) + { + case DSP_LINE: + case DSP_PC: + case DSP_SOURCE: + case DSP_DISASM: + case DSP_FUNCTION: + sb.append (NTXT ("LEAF IN ")); + break; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + sb.append (dbeSession->getIndexSpaceName (subtype)); + sb.append (NTXT (" IN ")); + break; + } + Vec_loop (uint64_t, obj_ids, index, sel) + { + if (found == 0) + { + found = 1; + sb.append ('('); + } + else + sb.append (NTXT (", ")); + snprintf (buf, sizeof (buf), NTXT ("%llu"), (long long) sel); + sb.append (buf); + } + if (found == 1) + sb.append (')'); + + switch (type) + { + case DSP_DLAYOUT: + case DSP_DATAOBJ: + sb.append (NTXT (" SOME IN DOBJ")); + break; + } + sb.append (')'); + return sb.toString (); +} + +// +// Get load object states +// +Vector<void *> * +dbeGetLoadObjectList (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<LoadObject*> *lobjs = dbeSession->get_text_segments (); + int size = lobjs->size (); + + // Initialize Java boolean array + Vector<char *> *names = new Vector<char *>(size); + Vector<int> *states = new Vector<int>(size); + Vector<int> *indices = new Vector<int>(size); + Vector<char *> *paths = new Vector<char *>(size); + Vector<int> *isJava = new Vector<int>(size); + + // Get load object states + int index; + LoadObject *lo; + char *lo_name; + + // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java + // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs + // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]]; + + // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is + // called. Possibility of further optimization by making it more persistent. + // Only consumer of this list is dbeSetLoadObjectState + int new_index = 0; + if (dbev->lobjectsNoJava == NULL) + dbev->lobjectsNoJava = new Vector<int>(1); + else + dbev->lobjectsNoJava->reset (); + + Vec_loop (LoadObject*, lobjs, index, lo) + { + // Set 0, 1, or 2 for show/hide/api + enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx); + + lo_name = lo->get_name (); + if (lo_name != NULL) + { + size_t len = strlen (lo_name); + if (len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) + isJava->store (new_index, 1); + else + isJava->store (new_index, 0); + } + else + isJava->store (new_index, 0); + dbev->lobjectsNoJava->append (index); + + names->store (new_index, dbe_sprintf (NTXT ("%s"), lo_name)); + states->store (new_index, (int) expand); + indices->store (new_index, (int) lo->seg_idx); + paths->store (new_index, dbe_sprintf (NTXT ("%s"), lo->get_pathname ())); + new_index++; + } + Vector<void*> *res = new Vector<void*>(5); + res->store (0, names); + res->store (1, states); + res->store (2, indices); + res->store (3, paths); + res->store (4, isJava); + delete lobjs; + return res; +} + +Vector<int> * +dbeGetLoadObjectState (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<LoadObject*> *lobjs = dbeSession->get_text_segments (); + int size = lobjs->size (); + + // Initialize Java boolean array + Vector<int> *states = new Vector<int>(size); + char *lo_name; + + // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java + // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs + // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]]; + + // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is + // called. Possibility of further optimization by making it more persistent. + // Only consumer of this list is dbeSetLoadObjectState + int new_index = 0; + if (dbev->lobjectsNoJava == NULL) + dbev->lobjectsNoJava = new Vector<int>(1); + else + dbev->lobjectsNoJava->reset (); + + // Get load object states + int index; + LoadObject *lo; + + Vec_loop (LoadObject*, lobjs, index, lo) + { + // Set 0, 1, or 2 for show/hide/api + lo_name = lo->get_name (); + if (lo_name != NULL) + { + size_t len = strlen (lo_name); + if (len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) + continue; + } + else + dbev->lobjectsNoJava->append (index); + + enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx); + states->store (new_index, (int) expand); + new_index++; + } + delete lobjs; + return states; +} + +// Set load object states +void +dbeSetLoadObjectState (int dbevindex, Vector<int> *selected) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<LoadObject*> *lobjs = dbeSession->get_text_segments (); + + int index; + bool changed = false; + + LoadObject *lo; + int new_index = 0; + dbev->setShowAll (); + Vec_loop (LoadObject*, lobjs, index, lo) + { + if (dbev->lobjectsNoJava != NULL) + { + // This loadobject is a java class and was skipped + if (dbev->lobjectsNoJava->fetch (new_index) != index) + continue; + } + // Get array of settings + enum LibExpand expand = (enum LibExpand) selected->fetch (new_index); + if (expand == LIBEX_HIDE) + { + dbev->resetShowAll (); + dbeSession->set_lib_visibility_used (); + } + changed = changed | dbev->set_libexpand (lo->get_pathname (), expand); + new_index++; + } + delete lobjs; + if (changed == true) + { + dbev->setShowHideChanged (); + dbev->update_lo_expands (); + } + + return; +} + +// Reset load object states +void +dbeSetLoadObjectDefaults (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_libdefaults (); +} + +// Get Machine model +Vector<char*>* +dbeGetCPUVerMachineModel (int dbevindex) +{ + Vector<char*>* table = new Vector<char*>(); + DbeView *dbev = dbeSession->getView (dbevindex); + char * mach_model = dbev->get_settings ()->get_machinemodel (); + if (mach_model != NULL) + { + table->append (mach_model); + return table; + } + int grsize = dbeSession->expGroups->size (); + for (int j = 0; j < grsize; j++) + { + ExpGroup *gr = dbeSession->expGroups->fetch (j); + Vector<Experiment*> *exps = gr->exps; + for (int i = 0, sz = exps->size (); i < sz; i++) + { + Experiment *exp = exps->fetch (i); + char *model = exp->machinemodel; + if (model != NULL) + table->append (dbe_strdup (model)); + } + } + return table; +} + +// automatically load machine model if applicable +void +dbeDetectLoadMachineModel (int dbevindex) +{ + if (dbeSession->is_datamode_available ()) + { + char *model = dbeGetMachineModel (); + if (model == NULL) + { + Vector<char*>* models = dbeGetCPUVerMachineModel (dbevindex); + char * machineModel = NTXT ("generic"); + if (models->size () > 0) + { + machineModel = models->get (0); + for (int i = 1; i < models->size (); i++) + { + if (strncmp (models->get (i), machineModel, strlen (machineModel)) == 0) + { + machineModel = NTXT ("generic"); + break; + } + } + dbeLoadMachineModel (machineModel); + } + delete models; + } + } +} + +// Managing Memory Objects +char * +dbeDefineMemObj (char *name, char *index_expr, char *machinemodel, + char *sdesc, char *ldesc) +{ + return MemorySpace::mobj_define (name, index_expr, machinemodel, sdesc, ldesc); +} + +char * +dbeDeleteMemObj (char *name) +{ + return MemorySpace::mobj_delete (name); +} + +Vector<void*> * +dbeGetMemObjects (int /*dbevindex*/) +{ + Vector<void*> *res = MemorySpace::getMemObjects (); + return res; +} + +// Managing machine model +char * +dbeLoadMachineModel (char *name) +{ + return dbeSession->load_mach_model (name); +} + +char * +dbeGetMachineModel () +{ + return dbeSession->get_mach_model (); +} + +Vector <char *> * +dbeListMachineModels () +{ + return dbeSession->list_mach_models (); +} + +// Managing Index Objects +char * +dbeDefineIndxObj (char *name, char *index_expr, char *sdesc, char *ldesc) +{ + return dbeSession->indxobj_define (name, NULL, index_expr, sdesc, ldesc); +} + +Vector<void*> * +dbeGetIndxObjDescriptions (int /*dbevindex*/) +{ + Vector<void*> *res = dbeSession->getIndxObjDescriptions (); + return res; +} + +Vector<void*> * +dbeGetCustomIndxObjects (int /*dbevindex*/) +{ + Vector<void*> *res = dbeSession->getCustomIndxObjects (); + return res; +} + +void +dbeSetSelObj (int dbevindex, Obj sel_obj_or_ind, int type, int subtype) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *sel_obj; + Hist_data *data; + int sel_ind = (int) sel_obj_or_ind; + + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_CALLER: + data = dbev->callers; + break; + case DSP_CALLEE: + data = dbev->callees; + break; + case DSP_SOURCE: + data = dbev->src_data; + break; + case DSP_DISASM: + data = dbev->dis_data; + break; + case DSP_DLAYOUT: + data = dbev->dlay_data; + if (data == NULL) + { + dbev->sel_binctx = NULL; + return; + } + if (sel_ind >= 0 && sel_ind < dbev->dlay_data->size ()) + dbev->sel_dobj = dbev->dlay_data->fetch (sel_ind)->obj; + return; + case DSP_DATAOBJ: + data = dbev->dobj_data; + if (data == NULL) + { + dbev->sel_binctx = NULL; + return; + } + if (sel_ind >= 0 && sel_ind < dbev->dobj_data->size ()) + dbev->sel_dobj = dbev->dobj_data->fetch (sel_ind)->obj; + return; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + dbev->set_indxobj_sel (subtype, sel_ind); + sel_obj = dbev->get_indxobj_sel (subtype); + if (sel_obj && sel_obj->get_type () == Histable::INDEXOBJ) + dbev->set_sel_obj (((IndexObject*) sel_obj)->get_obj ()); + return; + case DSP_SOURCE_V2: + case DSP_DISASM_V2: + case DSP_TIMELINE: + case DSP_LEAKLIST: + case DSP_RACES: + case DSP_DEADLOCKS: + case DSP_DUALSOURCE: + case DSP_SOURCE_DISASM: + case DSP_IOACTIVITY: + case DSP_IOVFD: + case DSP_IOCALLSTACK: + case DSP_HEAPCALLSTACK: + case DSP_MINICALLER: + dbev->set_sel_obj ((Histable *) sel_obj_or_ind); + return; + default: + // abort(); + return; + } + if (type != DSP_SOURCE && type != DSP_DISASM && type != DSP_SOURCE_V2 + && type != DSP_DISASM_V2) + dbev->sel_binctx = NULL; + + if (data == NULL || data->get_status () != Hist_data::SUCCESS + || sel_ind >= data->size ()) + return; + + if (sel_ind >= 0 && sel_ind < data->size ()) + dbev->set_sel_obj (data->fetch (sel_ind)->obj); +} + +void +dbeSetSelObjV2 (int dbevindex, uint64_t id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->set_sel_obj (dbeSession->findObjectById (id)); +} + +Obj +dbeGetSelObj (int dbevindex, int type, int subtype) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + Histable *sel_obj = NULL; + switch (type) + { + case DSP_FUNCTION: + sel_obj = dbev->get_sel_obj (Histable::FUNCTION); + break; + case DSP_LINE: + case DSP_SOURCE: + case DSP_SOURCE_V2: + sel_obj = dbev->get_sel_obj (Histable::LINE); + break; + case DSP_PC: + case DSP_DISASM: + case DSP_DISASM_V2: + sel_obj = dbev->get_sel_obj (Histable::INSTR); + break; + case DSP_SRC_FILE: + sel_obj = dbev->get_sel_obj (Histable::SOURCEFILE); + break; + case DSP_DATAOBJ: + case DSP_DLAYOUT: + if (dbev->sel_dobj) + sel_obj = dbev->sel_dobj->convertto (Histable::DOBJECT); + break; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + sel_obj = dbev->get_indxobj_sel (subtype); + break; + default: + abort (); + } + Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObj: Dbe.cc:%d %s (%d) returns %s\n"), + __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL"); + return (Obj) sel_obj; +} + +Obj +dbeConvertSelObj (Obj obj, int type) +{ + Histable *sel_obj = (Histable *) obj; + Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) sel_obj=%s\n"), + __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () + : "NULL"); + if (sel_obj == NULL) + return (Obj) NULL; + switch (type) + { + case DSP_FUNCTION: + return (Obj) sel_obj->convertto (Histable::FUNCTION); + case DSP_LINE: + return (Obj) sel_obj->convertto (Histable::LINE); + case DSP_SOURCE: + case DSP_SOURCE_V2: + { + SourceFile* srcCtx = NULL; + if (sel_obj->get_type () == Histable::INSTR) + { + DbeInstr* dbei = (DbeInstr *) sel_obj; + srcCtx = (SourceFile*) dbei->convertto (Histable::SOURCEFILE); + } + else if (sel_obj->get_type () == Histable::LINE) + { + DbeLine * dbel = (DbeLine *) sel_obj; + srcCtx = dbel->sourceFile; + } + sel_obj = sel_obj->convertto (Histable::LINE, srcCtx); + Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) returns %s\n"), + __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL"); + if (sel_obj && sel_obj->get_type () == Histable::LINE) + { + DbeLine * dbel = (DbeLine *) sel_obj; + return (Obj) dbel->dbeline_base; + } + return (Obj) sel_obj->convertto (Histable::LINE, srcCtx); + } + case DSP_PC: + case DSP_DISASM: + case DSP_DISASM_V2: + return (Obj) sel_obj->convertto (Histable::INSTR); + case DSP_SRC_FILE: + return (Obj) sel_obj->convertto (Histable::SOURCEFILE); + default: + abort (); + } + return (Obj) NULL; +} + +uint64_t +dbeGetSelObjV2 (int dbevindex, char *typeStr) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *obj = NULL; + if (typeStr != NULL) + { + if (streq (typeStr, NTXT ("FUNCTION"))) + obj = dbev->get_sel_obj (Histable::FUNCTION); + else if (streq (typeStr, NTXT ("INSTRUCTION"))) + obj = dbev->get_sel_obj (Histable::INSTR); + else if (streq (typeStr, NTXT ("SOURCELINE"))) + obj = dbev->get_sel_obj (Histable::LINE); + else if (streq (typeStr, NTXT ("SOURCEFILE"))) + obj = dbev->get_sel_obj (Histable::SOURCEFILE); + } + Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObjV2: Dbe.cc:%d %s returns %s\n"), + __LINE__, STR (typeStr), obj ? obj->dump () : "NULL"); + return obj != NULL ? obj->id : (uint64_t) - 1; +} + +Vector<uint64_t> * +dbeGetSelObjsIO (int dbevindex, Vector<uint64_t> *ids, int type) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<uint64_t> *res = NULL; + Vector<uint64_t> *result = new Vector<uint64_t>(); + for (int i = 0; i < ids->size (); i++) + { + res = dbeGetSelObjIO (dbevindex, ids->fetch (i), type); + if (res != NULL) + { + result->addAll (res); + delete res; + } + } + return result; +} + +Vector<uint64_t> * +dbeGetSelObjIO (int dbevindex, uint64_t id, int type) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *obj = NULL; + Vector<uint64_t> *res = NULL; + int size = 0; + switch (type) + { + case DSP_IOACTIVITY: + obj = dbev->get_sel_obj_io (id, Histable::IOACTFILE); + size = obj != NULL ? ((FileData*) obj)->getVirtualFds ()->size () : 0; + if (size) + { + res = new Vector<uint64_t>(); + Vector<int64_t> *vfds = ((FileData*) obj)->getVirtualFds (); + for (int i = 0; i < size; i++) + res->append (vfds->fetch (i)); + } + break; + case DSP_IOVFD: + obj = dbev->get_sel_obj_io (id, Histable::IOACTVFD); + if (obj) + { + res = new Vector<uint64_t>(); + res->append (obj->id); + } + break; + case DSP_IOCALLSTACK: + obj = dbev->get_sel_obj_io (id, Histable::IOCALLSTACK); + if (obj) + { + Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, obj->id); + if (instrs == NULL) + return NULL; + int stsize = instrs->size (); + res = new Vector<uint64_t>(stsize); + for (int i = 0; i < stsize; i++) + { + Histable *objFunc = (DbeInstr*) (instrs->fetch (i)); + if (objFunc->get_type () != Histable::LINE) + { + objFunc = objFunc->convertto (Histable::FUNCTION); + res->insert (0, objFunc->id); + } + } + delete instrs; + } + break; + default: + break; + } + return res; +} + +uint64_t +dbeGetSelObjHeapTimestamp (int dbevindex, uint64_t id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *obj = NULL; + uint64_t res = 0; + Vector<uint64_t> *peakStackIds; + Vector<hrtime_t> *peakTimestamps; + + // Find and return the timestamp for the peak + bool foundPeakId = false; + if (id > 0) + { + obj = dbev->get_sel_obj_heap (0); + if (obj != NULL) + { + peakStackIds = ((HeapData*) obj)->getPeakStackIds (); + peakTimestamps = ((HeapData*) obj)->getPeakTimestamps (); + for (int i = 0; i < peakStackIds->size (); i++) + { + if (id == peakStackIds->fetch (i)) + { + res = peakTimestamps->fetch (i); + foundPeakId = true; + break; + } + } + } + } + + // Return the first timestamp for the peak + // if the callstack id is zero or it + // doesn't match with the peak stack id + if (id == 0 || !foundPeakId) + { + obj = dbev->get_sel_obj_heap (0); + res = obj != NULL ? ((HeapData*) obj)->getPeakTimestamps ()->fetch (0) : 0; + } + return res; +} + +int +dbeGetSelObjHeapUserExpId (int dbevindex, uint64_t id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *obj = NULL; + int res = 0; + obj = dbev->get_sel_obj_heap (id); + res = obj != NULL ? ((HeapData*) obj)->getUserExpId () : 0; + return res; +} + +// +// Get index of selected function/object +// +int +dbeGetSelIndex (int dbevindex, Obj sel_obj, int type, int subtype) +{ + Hist_data *data; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + case DSP_DLAYOUT: + data = dbev->dlay_data; + break; + case DSP_DATAOBJ: + data = dbev->dobj_data; + break; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + data = dbev->get_indxobj_data (subtype); + break; + default: + data = NULL; + break; + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return -1; + + Histable *chk_obj = (Histable *) sel_obj; + Vector<Hist_data::HistItem*> *histItems = data->get_hist_items (); + if (histItems == NULL || chk_obj == NULL) + return -1; + for (int i = 0, sz = histItems->size (); i < sz; i++) + { + if (histItems->get (i)->obj == chk_obj) + return i; + if (histItems->get (i)->obj == NULL) + continue; + if (histItems->get (i)->obj->get_type () == Histable::LINE + && chk_obj->get_type () == Histable::LINE) + { + if (((DbeLine*) histItems->get (i)->obj)->convertto (Histable::FUNCTION) + == ((DbeLine*) chk_obj)->convertto (Histable::FUNCTION) + && ((DbeLine*) histItems->get (i)->obj)->lineno + == ((DbeLine*) chk_obj)->lineno) + return i; + } + else if (histItems->get (i)->obj->get_type () == Histable::INSTR + && chk_obj->get_type () == Histable::INSTR) + if (((DbeInstr*) histItems->get (i)->obj)->convertto (Histable::FUNCTION) + == ((DbeInstr*) chk_obj)->convertto (Histable::FUNCTION) + && ((DbeInstr*) histItems->get (i)->obj)->addr + == ((DbeInstr*) chk_obj)->addr) + return i; + } + + Histable *chk_obj1 = NULL; + switch (type) + { + case DSP_FUNCTION: + chk_obj1 = chk_obj->convertto (Histable::FUNCTION); + break; + case DSP_LINE: + case DSP_SOURCE: + case DSP_SOURCE_V2: + chk_obj1 = chk_obj->convertto (Histable::LINE); + break; + case DSP_PC: + case DSP_DISASM: + case DSP_DISASM_V2: + chk_obj1 = chk_obj->convertto (Histable::INSTR); + break; + } + if (chk_obj1 && chk_obj != chk_obj1) + for (int i = 0, sz = histItems->size (); i < sz; i++) + if (histItems->get (i)->obj == chk_obj1) + return i; + + if (type == DSP_LINE) + { + for (int i = 0, sz = histItems->size (); i < sz; i++) + if (histItems->get (i)->obj != NULL + && chk_obj->convertto (Histable::FUNCTION) + == histItems->get (i)->obj->convertto (Histable::FUNCTION)) + return i; + } + else if (type == DSP_PC) + { + for (int i = 0, sz = histItems->size (); i < sz; i++) + if (histItems->get (i)->obj != NULL + && (histItems->get (i)->obj)->convertto (Histable::FUNCTION) + == (chk_obj)->convertto (Histable::FUNCTION) + && ((DbeLine*) histItems->get (i)->obj->convertto (Histable::LINE))->lineno + == ((DbeLine*) chk_obj->convertto (Histable::LINE))->lineno) + return i; + for (int i = 0, sz = histItems->size (); i < sz; i++) + if (histItems->get (i)->obj != NULL + && (histItems->get (i)->obj)->convertto (Histable::FUNCTION) + == (chk_obj)->convertto (Histable::FUNCTION)) + return i; + } + + // If we clicked on an mfunction line in the called-by call mini in user mode for omp + // we might not find that function in func data + if (dbev->isOmpDisMode () && type == DSP_FUNCTION) + { + int p = dbeGetSelIndex (dbevindex, sel_obj, DSP_DISASM, subtype); + if (p != -1) + return p; + } + return -1; +} + +// Print data +// +char * +dbePrintData (int dbevindex, int type, int subtype, char *printer, + char *fname, FILE *outfile) +{ + Histable *current_obj; + Function *func; + Module *module; + MetricList *mlist_orig; + bool header; + Print_params params; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + + // Set print parameters + if (printer != NULL) + { + params.dest = DEST_PRINTER; + params.name = printer; + } + else if (outfile != NULL) + { + params.dest = DEST_OPEN_FILE; + params.openfile = outfile; + params.name = NULL; + } + else + { + params.dest = DEST_FILE; + params.name = fname; + if (*(params.name) == '\0') + { + free (params.name); + return dbe_strdup (GTXT ("Please enter the name of the file to which to print")); + } + } + params.ncopies = 1; + if (outfile != NULL) + header = false; + else + header = !(type == DSP_SOURCE || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2); + + params.header = header; + + // figure out what kind of metrics to use + if (type == DSP_SELF || type == DSP_CALLER || type == DSP_CALLEE + || type == DSP_CALLTREE) + mlist_orig = dbev->get_metric_list (MET_CALL); + else if (type == DSP_DATAOBJ || type == DSP_DLAYOUT || type == DSP_MEMOBJ) + mlist_orig = dbev->get_metric_list (MET_DATA); + else if (type == DSP_INDXOBJ) + mlist_orig = dbev->get_metric_list (MET_INDX); + else if (type == DSP_IOACTIVITY || type == DSP_IOVFD + || type == DSP_IOCALLSTACK) + mlist_orig = dbev->get_metric_list (MET_IO); + else if (type == DSP_HEAPCALLSTACK) + mlist_orig = dbev->get_metric_list (MET_HEAP); + else + mlist_orig = dbev->get_metric_list (MET_NORMAL); + + // make a compacted version of the input list + // the list will either be moved to the generated data, + // or freed below if it wasn't needed + MetricList *mlist = new MetricList (mlist_orig); + Hist_data *data = NULL; + er_print_common_display *cd = NULL; + int ix; + // Set data + switch (type) + { + case DSP_FUNCTION: + case DSP_LINE: + case DSP_PC: + case DSP_MEMOBJ: + case DSP_INDXOBJ: + case DSP_DATAOBJ: + data = dbev->get_hist_data (mlist, + ((type == DSP_FUNCTION) ? Histable::FUNCTION : + (type == DSP_LINE) ? Histable::LINE : + (type == DSP_PC) ? Histable::INSTR : + (type == DSP_INDXOBJ) ? Histable::INDEXOBJ : + (type == DSP_MEMOBJ) ? Histable::MEMOBJ + : Histable::DOBJECT), + subtype, Hist_data::ALL); + if (data->get_status () != Hist_data::SUCCESS) + return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup() + + cd = new er_print_histogram (dbev, data, mlist, MODE_LIST, + dbev->get_limit (), + mlist->get_sort_name (), NULL, true, true); + break; + case DSP_DLAYOUT: + { + data = dbev->get_hist_data (mlist, Histable::DOBJECT, 0, Hist_data::LAYOUT); + if (data->get_status () != Hist_data::SUCCESS) + return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup() + cd = new er_print_histogram (dbev, data, mlist, MODE_ANNOTATED, + dbev->get_thresh_dis (), + mlist->get_sort_name (), NULL, true, true); + break; + } + + // source and disassembly + case DSP_SOURCE: + case DSP_DISASM: + case DSP_SOURCE_V2: + case DSP_DISASM_V2: + if (dbev->sel_obj == NULL) + return NULL; + current_obj = dbev->sel_obj->convertto (Histable::FUNCTION); + if (current_obj->get_type () != Histable::FUNCTION) + return dbe_strdup (GTXT ("Not a real function; no source or disassembly available.")); + func = (Function*) current_obj->convertto (Histable::FUNCTION); + if (func->flags & FUNC_FLAG_SIMULATED) + return dbe_strdup (GTXT ("Not a real function; no source or disassembly available.")); + if (func->get_name () == NULL) + return dbe_strdup (GTXT ("Source location not recorded in experiment")); + module = func->module; + if (module == NULL || module->get_name () == NULL) + return dbe_strdup (GTXT ("Object name not recorded in experiment")); + ix = module->loadobject->seg_idx; + if (dbev->get_lo_expand (ix) == LIBEX_HIDE) + return dbe_strdup (GTXT ("No source or disassembly available for hidden object")); + cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_ANNOTATED, + type == DSP_DISASM || type == DSP_DISASM_V2, + mlist->get_sort_name (), + func, false, false); + break; + + // callers-callees + case DSP_SELF: + case DSP_CALLER: + case DSP_CALLEE: + if (dbev->sel_obj == NULL) + return NULL; + current_obj = dbev->sel_obj->convertto (Histable::FUNCTION); + cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_GPROF, 1, + mlist->get_sort_name (), current_obj, + false, false); + break; + + // statistics; this won't use the metric list copied above, so delete it + case DSP_STATIS: + cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1, + true, true, true, true, false); + delete mlist; + break; + case DSP_EXP: + cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1, + true, true, false, false, false); + delete mlist; + break; + case DSP_LEAKLIST: + cd = new er_print_leaklist (dbev, true, true, dbev->get_limit ()); + delete mlist; + break; + case DSP_HEAPCALLSTACK: + cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false, + dbev->get_limit ()); + delete mlist; + break; + case DSP_IOACTIVITY: + cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false, + dbev->get_limit ()); + delete mlist; + break; + case DSP_IOVFD: + cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false, + dbev->get_limit ()); + delete mlist; + break; + + // the io call stack + case DSP_IOCALLSTACK: + cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false, + dbev->get_limit ()); + delete mlist; + break; + + // some unknown panel -- return an error string + default: + delete mlist; + return dbe_strdup (GTXT ("Print not available")); + } + + // Start printing + char *buf = NULL; + + // first open the file/device/whatever + if (cd->open (¶ms) == 0) + { + // now call the actual print routine + cd->data_dump (); + if (params.dest == DEST_PRINTER) + { + if (streq ((char *) params.name, NTXT ("-"))) + { + // Special case - return report to the GUI + int maxbytes = 2 * 1024 * 1024; // IPC large buffer limit + char *report = cd->get_output (maxbytes); + delete data; + delete cd; + return report; // TEMPORARY + } + } + if (cd->print_output () == false) + buf = dbe_sprintf (NTXT ("%s: %s"), + GTXT ("Unable to submit print request to"), + params.name); + } + else + // if unable to set up the print, return an error + buf = dbe_sprintf (NTXT ("%s: %s"), + GTXT ("Unable to open file"), + params.name); + + // dbe_free((void *) params.name); XXX when should this happen? + if (data) + if (data->isViewOwned () == false) + delete data; + delete cd; + return buf; +} + +// Set limit for print data +// +char * +dbeSetPrintLimit (int dbevindex, int limit) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return (dbev->set_limit (limit)); +} + +// get limit for print data +int +dbeGetPrintLimit (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + int limit = dbev->get_limit (); + return limit; +} + +// set printmode for data +char * +dbeSetPrintMode (int dbevindex, char * pmode) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + char *r = dbev->set_printmode (pmode); + return r; +} + +// get printmode for data +int +dbeGetPrintMode (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return (dbev->get_printmode ()); +} + +// get printmode for data +char * +dbeGetPrintModeString (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return ( dbev->get_printmode_str ()); +} + +// get print delimiter for csv data +char +dbeGetPrintDelim (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + return (dbev->get_printdelimiter ()); +} + +// Set Source/Object/Load-Object file names +static void +set_file_names (Function *func, char *names[3]) +{ + Module *module = func->module; + LoadObject *loadobject = module->loadobject; + if (loadobject == NULL) + loadobject = dbeSession->get_Unknown_LoadObject (); + free (names[0]); + free (names[1]); + free (names[2]); + SourceFile *sf = func->getDefSrc (); + char *src_name = sf->dbeFile->get_location_info (); + DbeFile *df = module->dbeFile; + if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0) + df = module->loadobject->dbeFile; + char *lo_name = df->get_location_info (); + char *dot_o_name = lo_name; + if (module->dot_o_file) + dot_o_name = module->dot_o_file->dbeFile->get_location_info (); + names[0] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Source File"), src_name); + names[1] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Object File"), dot_o_name); + names[2] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Load Object"), lo_name); +} + +// dbeSetFuncData +// Master function to generate all Tab data for the analyzer +// Returns the index of the selected item in the specified list +// +// After calling it to set up, the Analyzer calls dbeGetFuncList +// to format the generated data and return the table +// Most of the data is destined for a JTable +// +int +dbeSetFuncData (int dbevindex, Obj sel_obj, int type, int subtype) +{ + MetricList *_mlist; + Histable *org_obj; + Hist_data *data = NULL; + int index, sel_index; + Function *func; + char *name; + int ix; + + DbeView *dbev = dbeSession->getView (dbevindex); + sel_index = -1; + dbev->resetOmpDisMode (); + dbev->error_msg = dbev->warning_msg = NULL; + + // get metric list, make a compact duplicate + _mlist = dbev->get_metric_list (MET_NORMAL); + MetricList *mlist = new MetricList (_mlist); + + // Remove old function/obj list data & Get new function/obj list data + org_obj = (Histable *) sel_obj; + + // Figure out which "function" data is being asked for, i.e., + // which of the analyzer displays is asking for data + switch (type) + { + // the various tables: functions, lines, PCs, DataObjects, IndexObjects + case DSP_FUNCTION: + case DSP_LINE: + case DSP_PC: + case DSP_DATAOBJ: + case DSP_MEMOBJ: + case DSP_INDXOBJ: + switch (type) + { + case DSP_FUNCTION: + if (dbev->func_data) + delete dbev->func_data; + dbev->func_data = data = dbev->get_hist_data (mlist, + Histable::FUNCTION, subtype, Hist_data::ALL); + break; + case DSP_LINE: + if (dbev->line_data) + delete dbev->line_data; + dbev->line_data = data = dbev->get_hist_data (mlist, + Histable::LINE, subtype, Hist_data::ALL); + break; + case DSP_PC: + if (dbev->pc_data) + delete dbev->pc_data; + dbev->pc_data = data = dbev->get_hist_data (mlist, + Histable::INSTR, subtype, Hist_data::ALL); + break; + case DSP_DATAOBJ: + if (dbev->dobj_data) + delete dbev->dobj_data; + mlist = dbev->get_metric_list (MET_DATA); + dbev->dobj_data = data = dbev->get_hist_data (mlist, + Histable::DOBJECT, subtype, Hist_data::ALL); + break; + case DSP_MEMOBJ: + mlist = dbev->get_metric_list (MET_DATA); + data = dbev->get_hist_data (mlist, Histable::MEMOBJ, subtype, + Hist_data::ALL); + dbev->indx_data->store (subtype, data); + break; + case DSP_INDXOBJ: + mlist = dbev->get_metric_list (MET_INDX); + data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, subtype, + Hist_data::ALL); + dbev->indx_data->store (subtype, data); + break; + default: + break; + } + + // Set the selection of row item + if (data->get_status () == Hist_data::SUCCESS) + { + // otherwise, look for it + sel_index = -1; + if (org_obj) + { + Hist_data::HistItem *hi; + Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi) + { + if (hi->obj == org_obj) + { + sel_index = index; + break; + } + } + if (sel_index == -1 && (type == DSP_LINE || type == DSP_PC)) + { + Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi) + { + name = hi->obj->get_name (); + if (strcmp (name, NTXT ("<Total>")) && + strcmp (name, GTXT ("<Unknown>"))) + { + int done = 0; + switch (type) + { + case DSP_LINE: + if (org_obj->convertto (Histable::FUNCTION) + == hi->obj->convertto (Histable::FUNCTION)) + { + sel_index = index; + done = 1; + } + break; + case DSP_PC: + if (hi->obj->convertto (Histable::FUNCTION) + == org_obj->convertto (Histable::FUNCTION) + && ((DbeLine*) hi->obj->convertto (Histable::LINE))->lineno + == ((DbeLine*) org_obj->convertto (Histable::LINE))->lineno) + { + sel_index = index; + done = 1; + } + break; + } + if (done) + break; + } + } + } + if (sel_index == -1 && type == DSP_PC) + { + Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi) + { + name = hi->obj->get_name (); + if (strcmp (name, NTXT ("<Total>")) && + strcmp (name, GTXT ("<Unknown>"))) + { + int done = 0; + if (hi->obj->convertto (Histable::FUNCTION) == + org_obj->convertto (Histable::FUNCTION)) + { + sel_index = index; + done = 1; + } + if (done) + break; + } + } + } + } + if (sel_index == -1) + { + Hist_data::HistItem *hi; + Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi) + { + name = hi->obj->get_name (); + if (strcmp (name, NTXT ("<Total>")) && + strcmp (name, GTXT ("<Unknown>"))) + { + sel_index = index; + break; + } + } + } + } + else + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); + return sel_index; + // the end of the code for the regular tables + + // Data Layout + case DSP_DLAYOUT: + if (dbev->dlay_data) + delete dbev->dlay_data; + dbev->marks->reset (); + mlist = dbev->get_metric_list (MET_DATA); + + // initial dobj list ... + data = dbev->get_hist_data (mlist, Histable::DOBJECT, subtype, + Hist_data::LAYOUT); + // .. provides metric data for layout + dbev->dlay_data = data = dbev->get_data_space ()->get_layout_data (data, + dbev->marks, dbev->get_thresh_dis ()); + if (data->get_status () != Hist_data::SUCCESS) + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); + return sel_index; + + // Source or disassembly + case DSP_SOURCE_V2: + case DSP_DISASM_V2: + case DSP_SOURCE: + case DSP_DISASM: + { + if (org_obj == NULL) + { + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ); + return sel_index; + } + if (org_obj->get_type () != Histable::FUNCTION) + { + dbev->error_msg = dbe_strdup ( + GTXT ("Not a real function; no source or disassembly available.")); + return sel_index; + } + func = (Function *) org_obj; + if (func->flags & FUNC_FLAG_SIMULATED) + { + dbev->error_msg = dbe_strdup ( + GTXT ("Not a real function; no source or disassembly available.")); + return sel_index; + } + if (func->get_name () == NULL) + { + dbev->error_msg = dbe_strdup ( + GTXT ("Source location not recorded in experiment")); + return sel_index; + } + Module *module = func->module; + if ((module == NULL) || (module->get_name () == NULL)) + { + dbev->error_msg = dbe_strdup ( + GTXT ("Object name not recorded in experiment")); + return sel_index; + } + ix = module->loadobject->seg_idx; + if (dbev->get_lo_expand (ix) == LIBEX_HIDE) + { + dbev->error_msg = dbe_strdup ( + GTXT ("No source or disassembly available for hidden object")); + return sel_index; + } + + if ((type == DSP_DISASM || type == DSP_DISASM_V2) + && dbev->get_view_mode () == VMODE_USER + && dbeSession->is_omp_available ()) + dbev->setOmpDisMode (); + + dbev->marks->reset (); + SourceFile *srcContext = NULL; + switch (dbev->sel_obj->get_type ()) + { + case Histable::FUNCTION: + { + Function *f = (Function *) dbev->sel_obj; + srcContext = f->getDefSrc (); + dbev->sel_binctx = f->module; + break; + } + case Histable::LINE: + { + DbeLine *dl = (DbeLine *) dbev->sel_obj; + srcContext = dl->sourceFile; + Function *f = dl->func; + if (f) + dbev->sel_binctx = f; + break; + } + case Histable::INSTR: + { + Function *f = (Function *) dbev->sel_obj->convertto (Histable::FUNCTION); + if (f) + { + dbev->sel_binctx = f; + srcContext = f->getDefSrc (); + } + break; + } + default: + break; + } + mlist = dbev->get_metric_list (MET_SRCDIS); + + // for source and disassembly the name needs to be invisible, + // but that's handled in the module code + if (type == DSP_SOURCE) + { + if (dbev->src_data) + delete dbev->src_data; + + // func_data computation needed for get_totals + if (dbev->func_data == NULL) + dbev->func_data = data = dbev->get_hist_data (mlist, + Histable::FUNCTION, subtype, Hist_data::ALL); + dbev->marks2dsrc->reset (); + dbev->marks2dsrc_inc->reset (); + data = dbev->src_data = module->get_data (dbev, mlist, + Histable::LINE, dbev->func_data->get_totals ()->value, + srcContext, func, dbev->marks, + dbev->get_thresh_src (), dbev->get_src_compcom (), + dbev->get_src_visible (), dbev->get_hex_visible (), + false, false, dbev->marks2dsrc, dbev->marks2dsrc_inc); + set_file_names (func, dbev->names_src); + if (srcContext) + { + free (dbev->names_src[0]); + dbev->names_src[0] = dbe_sprintf (GTXT ("Source File: %s"), + srcContext->dbeFile->get_location_info ()); + } + Obj obj = (Obj) func->convertto (Histable::LINE, srcContext); + sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype); + } + else + { /* type == DSP_DISASM */ + if (dbev->dis_data) + delete dbev->dis_data; + + // func_data computation needed for get_totals + if (dbev->func_data == NULL) + dbev->func_data = data = dbev->get_hist_data (mlist, + Histable::FUNCTION, subtype, Hist_data::ALL); + dbev->marks2ddis->reset (); + dbev->marks2ddis_inc->reset (); + data = dbev->dis_data = module->get_data (dbev, mlist, + Histable::INSTR, dbev->func_data->get_totals ()->value, + srcContext, func, dbev->marks, dbev->get_thresh_dis (), + dbev->get_dis_compcom (), dbev->get_src_visible (), + dbev->get_hex_visible (), dbev->get_func_scope (), + false, dbev->marks2ddis, dbev->marks2ddis_inc); + set_file_names (func, dbev->names_dis); + if (srcContext) + { + free (dbev->names_dis[0]); + dbev->names_dis[0] = dbe_sprintf (GTXT ("Source File: %s"), + srcContext->dbeFile->get_location_info ()); + } + Obj obj = (Obj) func->convertto (Histable::INSTR); + sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype); + } + return sel_index; + } + + // the three cases for caller-callee + case DSP_SELF: + case DSP_CALLER: + case DSP_CALLEE: + if (org_obj == NULL) + { + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ); + return sel_index; + } + + // Caller data + if (dbev->callers) + delete dbev->callers; + mlist = dbev->get_metric_list (MET_CALL); + dbev->callers = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype, + Hist_data::CALLERS, org_obj); + if (dbev->callers->get_status () != Hist_data::SUCCESS) + { + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); + return sel_index; + } + + // Callee data + if (dbev->callees) + delete dbev->callees; + dbev->callees = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype, + Hist_data::CALLEES, org_obj); + if (dbev->callees->get_status () != Hist_data::SUCCESS) + { + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); + return sel_index; + } + + // Center Function item + if (dbev->fitem_data) + delete dbev->fitem_data; + dbev->fitem_data = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype, + Hist_data::SELF, org_obj); + if (dbev->fitem_data->get_status () != Hist_data::SUCCESS) + { + dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA); + return sel_index; + } + return sel_index; + default: + abort (); + } + return sel_index; +} + +Vector<void*>* +dbeGetTotals (int dbevindex, int dsptype, int subtype) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + MetricList *mlist = dbev->get_metric_list (dsptype, subtype); + Hist_data *data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0, + Hist_data::ALL); + Hist_data::HistItem *totals = data->get_totals (); + Vector<void*> *tbl = new Vector<void*>(mlist->size ()); + for (long i = 0, sz = mlist->size (); i < sz; i++) + { + Metric *m = mlist->get (i); + switch (m->get_vtype ()) + { + case VT_DOUBLE: + { + Vector<double> *lst = new Vector<double>(1); + lst->append (totals->value[i].d); + tbl->append (lst); + break; + } + case VT_INT: + { + Vector<int> *lst = new Vector<int>(1); + lst->append (totals->value[i].i); + tbl->append (lst); + break; + } + case VT_LLONG: + case VT_ULLONG: + case VT_ADDRESS: + { + Vector<long long> *lst = new Vector<long long>(1); + lst->append (totals->value[i].ll); + tbl->append (lst); + break; + } + case VT_LABEL: + { + Vector<char *> *lst = new Vector<char *>(1); + Histable::NameFormat nfmt = dbev->get_name_format (); + lst->append (dbe_strdup (totals->obj->get_name (nfmt))); + tbl->append (lst); + break; + } + default: + abort (); + } + } + Vector<void*> *res = new Vector<void*>(2); + res->append (dbeGetMetricList (mlist)); + res->append (tbl); + return res; +} + +Vector<void*>* +dbeGetHotMarks (int dbevindex, int type) +{ + Vector<void*>* table = new Vector<void*>(2); + Vector<int>* table0 = new Vector<int> (); + Vector<int>* table1 = new Vector<int> (); + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + return NULL; + + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + for (int i = 0; i < dbev->marks2dsrc->size (); i++) + { + table0->append (dbev->marks2dsrc->fetch (i).index1); + table1->append (dbev->marks2dsrc->fetch (i).index2); + } + break; + case DSP_DISASM: + case DSP_DISASM_V2: + for (int i = 0; i < dbev->marks2ddis->size (); i++) + { + table0->append (dbev->marks2ddis->fetch (i).index1); + table1->append (dbev->marks2ddis->fetch (i).index2); + } + break; + default: + break; + } + table->store (0, table0); + table->store (1, table1); + return table; +} + +Vector<void*>* +dbeGetHotMarksInc (int dbevindex, int type) +{ + Vector<void*>* table = new Vector<void*>(2); + Vector<int>* table0 = new Vector<int> (); + Vector<int>* table1 = new Vector<int> (); + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + return NULL; + + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + for (int i = 0; i < dbev->marks2dsrc_inc->size (); i++) + { + table0->append (dbev->marks2dsrc_inc->fetch (i).index1); + table1->append (dbev->marks2dsrc_inc->fetch (i).index2); + } + break; + case DSP_DISASM: + case DSP_DISASM_V2: + for (int i = 0; i < dbev->marks2ddis_inc->size (); i++) + { + table0->append (dbev->marks2ddis_inc->fetch (i).index1); + table1->append (dbev->marks2ddis_inc->fetch (i).index2); + } + break; + default: + break; + } + table->store (0, table0); + table->store (1, table1); + return table; +} + +Vector<void*>* +dbeGetSummaryHotMarks (int dbevindex, Vector<Obj> *sel_objs, int type) +{ + Vector<void*>* table = new Vector<void*>(2); + Vector<int>* table0 = new Vector<int> (); + Vector<int>* table1 = new Vector<int> (); + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + return NULL; + if (sel_objs == NULL || sel_objs->size () == 0) + return NULL; + + Hist_data *data; + Vector<int_pair_t> *marks2d; + Vector<int_pair_t>* marks2d_inc; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + marks2d = dbev->marks2dsrc; + marks2d_inc = dbev->marks2dsrc_inc; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + marks2d = dbev->marks2ddis; + marks2d_inc = dbev->marks2ddis_inc; + break; + default: + data = NULL; + marks2d = NULL; + marks2d_inc = NULL; + break; + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS + || marks2d_inc == NULL || marks2d == NULL) + return NULL; + + MetricList *orig_mlist = data->get_metric_list (); + MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL)); + if (prop_mlist && dbev->comparingExperiments ()) + prop_mlist = dbev->get_compare_mlist (prop_mlist, 0); + Metric *mitem; + int index, index2; + index2 = 0; + Vec_loop (Metric*, prop_mlist->get_items (), index, mitem) + { + if (mitem->get_subtype () == Metric::STATIC) + continue; + + for (int i = 0; i < marks2d_inc->size (); i++) + { + int found = 0; + for (int j = 0; j < sel_objs->size (); j++) + { + int sel_index = (int) sel_objs->fetch (j); + int marked_index = marks2d_inc->fetch (i).index1; + if (sel_index == marked_index) + { + found = 1; + break; + } + } + if (!found) + continue; + int mindex = marks2d_inc->fetch (i).index2; + Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex); + if (orig_metric->get_id () == mitem->get_id () + && mitem->get_subtype () == Metric::INCLUSIVE) + { + table0->append (index2); + table1->append (1); + } + } + + for (int i = 0; i < marks2d->size (); i++) + { + int found = 0; + for (int j = 0; j < sel_objs->size (); j++) + { + int sel_index = (int) sel_objs->fetch (j); + int marked_index = marks2d->fetch (i).index1; + if (sel_index == marked_index) + { + found = 1; + break; + } + } + if (!found) + continue; + int mindex = marks2d->fetch (i).index2; + Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex); + if (orig_metric->get_id () == mitem->get_id () + && mitem->get_subtype () == Metric::EXCLUSIVE) + { + table0->append (index2); + table1->append (0); + } + } + if (!(mitem->get_subtype () == Metric::EXCLUSIVE + || mitem->get_subtype () == Metric::DATASPACE)) + index2++; + } + table->store (0, table0); + table->store (1, table1); + return table; +} + +// Get a vector of function ids of data(begin, begin + length - 1) +// Currently only support source/disassembly view +Vector<uint64_t>* +dbeGetFuncId (int dbevindex, int type, int begin, int length) +{ + Vector<uint64_t>* table = new Vector<uint64_t > (); + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + + Hist_data *data; + Function* given_func = NULL; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + default: + data = NULL; + abort (); + } + + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + + if (begin < 0 || begin + length > data->size ()) + return NULL; + + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + case DSP_DISASM: + case DSP_DISASM_V2: + { + for (int i = begin; i < begin + length; i++) + { + given_func = NULL; + Histable * sel_obj = data->fetch (i)->obj; + if (sel_obj != NULL) + given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev); + if (given_func == NULL) + table->append (0); + else + table->append (given_func->id); + } + } + break; + default: + abort (); + } + return table; +} + +Vector<void*>* +dbeGetFuncCallerInfo (int dbevindex, int type, Vector<int>* idxs, int groupId) +{ + Vector<void*>* data = new Vector<void*>(); + if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0); + if (sel_func == 0) + return data; + Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type); + if (cmpObjs == NULL) + return data; + DbeView *dbev = dbeSession->getView (dbevindex); + int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT); + MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK), + (mtype & COMPARE_BIT) != 0, + mtype >> GROUP_ID_SHIFT); + Histable *selObj = (Histable *) cmpObjs->fetch (groupId); + int subtype = 0; + Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype); + if (hist_data == NULL) + return data; + } + for (int i = 0; i < idxs->size (); i++) + data->append (dbeGetFuncCallerInfoById (dbevindex, type, idxs->fetch (i))); + return data; +} + +// +// Get Table of Caller info: +// param: idx -- selected AT_FUNC row +// return: callsite_id, callsite_name (function: file: line) +Vector<void*>* +dbeGetFuncCallerInfoById (int dbevindex, int type, int idx) +{ + Vector<void*>* table = new Vector<void*>(3); + Vector<uint64_t>* table0 = new Vector<uint64_t> (); + Vector<int>* table1 = new Vector<int> (); + Vector<char*>* table2 = new Vector<char*>(); + + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Hist_data *data; + Function* given_func = NULL; + Vector<Histable*> *instr_info = NULL; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + default: + data = NULL; + abort (); + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + + if (idx < 0 || idx >= data->size ()) + return NULL; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + case DSP_DISASM: + case DSP_DISASM_V2: + { + Histable * sel_obj = data->fetch (idx)->obj; + if (sel_obj == NULL) + return NULL; + given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev); + if (given_func == NULL) + return NULL; + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + instr_info = ptree->get_clr_instr (given_func); + DefaultMap<uint64_t, int> * line_seen = new DefaultMap<uint64_t, int>(); + for (int j = 0; j < ((Vector<Histable*>*)instr_info)->size (); j++) + { + Histable *instr = ((Vector<Histable*>*)instr_info)->fetch (j); + Function *cur_func = NULL; + if (instr->get_type () == Histable::INSTR) + cur_func = ((DbeInstr*) instr)->func; + else if (instr->get_type () == Histable::LINE) + cur_func = ((DbeLine*) instr)->func; + if (cur_func == NULL || (cur_func->flags & FUNC_FLAG_SIMULATED)) + continue; // skip functions like <Total> + Histable* line; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + if (cur_func != NULL) + { + SourceFile *sourceFile = cur_func->getDefSrc (); + if (sourceFile == NULL || + (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0) + continue; // skip functions like <Function: %s, instructions without line numbers> + } + line = instr->convertto (Histable::LINE, NULL); + break; + case DSP_DISASM: + case DSP_DISASM_V2: + line = instr->convertto (Histable::INSTR, NULL); + break; + default: + abort (); + } + uint64_t func_id = cur_func->id; + uint64_t line_id = instr->id; + int is_null = 0; + int line_no = -1; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + is_null = (((DbeLine*) line)->func == NULL) ? 1 : 0; + if (is_null) + ((DbeLine*) line)->func = cur_func; + line_no = ((DbeLine*) line)->lineno; + if (line_seen->get (line_id) == 0) + { + line_seen->put (line_id, 1); + table0->append (func_id); + table1->append (line_no); + Histable::NameFormat nfmt = dbev->get_name_format (); + table2->append (dbe_strdup (line->get_name (nfmt))); + } + if (is_null) + ((DbeLine*) line)->func = NULL; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + is_null = (((DbeInstr*) line)->func == NULL) ? 1 : 0; + if (is_null) + ((DbeInstr*) line)->func = cur_func; + line_no = ((DbeInstr*) line)->addr; + if (line_seen->get (line_id) == 0) + { + line_seen->put (line_id, 1); + table0->append (func_id); + table1->append (line_no); + Histable::NameFormat nfmt = dbev->get_name_format (); + table2->append (dbe_strdup (line->get_name (nfmt))); + } + if (is_null) + ((DbeInstr*) line)->func = NULL; + break; + default: + abort (); + } + } + delete line_seen; + delete instr_info; + } + break; + default: + abort (); + } + table->store (0, table0); + table->store (1, table1); + table->store (2, table2); + return table; +} + +Vector<void*>* +dbeGetFuncCalleeInfo (int dbevindex, int type, Vector<int>* idxs, int groupId) +{ + Vector<void*>* data = new Vector<void*>(); + if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0); + if (sel_func == 0) + return data; + Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type); + if (cmpObjs == NULL) + return data; + DbeView *dbev = dbeSession->getView (dbevindex); + int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT); + MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK), + (mtype & COMPARE_BIT) != 0, + mtype >> GROUP_ID_SHIFT); + Histable *selObj = (Histable *) cmpObjs->fetch (groupId); + int subtype = 0; + Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype); + if (hist_data == NULL) + return data; + } + + for (int i = 0; i < idxs->size (); i++) + data->append (dbeGetFuncCalleeInfoById (dbevindex, type, idxs->fetch (i))); + return data; +} + +// +// Get Table of Callee info: +// param: idx -- selected AT_FUNC row +// return: callsite_row, callee_id, callee_name +// +Vector<void*>* +dbeGetFuncCalleeInfoById (int dbevindex, int type, int idx) +{ + Vector<void*>* table = new Vector<void*>(3); + Vector<int>* table0 = new Vector<int>(); + Vector<uint64_t>* table1 = new Vector<uint64_t > (); + Vector<char*>* table2 = new Vector<char*>(); + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Hist_data *data; + Function* given_func = NULL; + Vector<Histable*> *instr_info = NULL; + Vector<void*> *func_info = NULL; + + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + default: + data = NULL; + abort (); + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + if (idx < 0 || idx >= data->size ()) + return NULL; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + case DSP_DISASM: + case DSP_DISASM_V2: + { + Histable * sel_obj = data->fetch (idx)->obj; + if (sel_obj == NULL) + return NULL; + given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev); + if (given_func == NULL) + return NULL; + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + Vector<Histable*> *instrs = NULL; + Vector<void*> *callee_instrs = ptree->get_cle_instr (given_func, instrs); + func_info = new Vector<void*>(); + instr_info = new Vector<Histable*>(); + for (long a = 0, sz_a = callee_instrs ? callee_instrs->size () : 0; a < sz_a; a++) + { + Vector<Histable*> *temp = ((Vector<Vector<Histable*>*>*)callee_instrs)->get (a); + DefaultMap<Function*, int> * func_seen = new DefaultMap<Function*, int>(); + Histable* instr0 = (Histable*) instrs->fetch (a); + for (long b = 0, sz_b = temp ? temp->size () : 0; b < sz_b; b++) + { + Histable *instr = temp->get (b); + if (instr->get_type () == Histable::INSTR) + { + Function* func1 = ((DbeInstr *) instr)->func; + func_seen->put (func1, 1); + } + else if (instr->get_type () == Histable::LINE) + { + Function* func1 = ((DbeLine *) instr)->func; + func_seen->put (func1, 1); + } + } + Vector<Function*> *funcs = func_seen->keySet (); + delete func_seen; + if (funcs->size () > 0) + { + instr_info->append (instr0); + func_info->append (funcs); + } + } + delete instrs; + destroy (callee_instrs); + + DefaultMap<uint64_t, Vector<int>* > * instr_idxs = new DefaultMap<uint64_t, Vector<int>* >(); + DefaultMap<uint64_t, int> * func_idxs = new DefaultMap<uint64_t, int>(); + for (long j = 0, sz_j = instr_info ? instr_info->size () : 0; j < sz_j; j++) + { + Histable *instr = instr_info->get (j); + Function *cur_func = NULL; + if (instr->get_type () == Histable::INSTR) + cur_func = ((DbeInstr*) instr)->func; + else if (instr->get_type () == Histable::LINE) + cur_func = ((DbeLine*) instr)->func; + if (cur_func != NULL && (cur_func->flags & FUNC_FLAG_SIMULATED)) + continue; // skip functions like <Total> + Histable* line; + switch (type) + { + case DSP_SOURCE: + case DSP_SOURCE_V2: + if (cur_func != NULL) + { + SourceFile *sourceFile = cur_func->getDefSrc (); + if (sourceFile == NULL || + (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0) + // skip functions like <Function: %s, instructions without line numbers> + continue; + } + line = instr->convertto (Histable::LINE, NULL); + if (type == DSP_SOURCE_V2) + line = dbev->get_compare_obj (line); + break; + case DSP_DISASM: + case DSP_DISASM_V2: + line = instr; + if (type == DSP_DISASM_V2) + line = dbev->get_compare_obj (line); + break; + default: + abort (); + } + if (func_idxs->get (line->id) == 0) + { + func_idxs->put (line->id, 1); + Vector<int> *temp_idx = new Vector<int>(); + temp_idx->append (j); + instr_idxs->put (line->id, temp_idx); + } + else + { + Vector<int> *temp_idx = instr_idxs->get (line->id); + temp_idx->append (j); + } + } + for (long i = 0; i < data->size (); i++) + { + Histable* line = data->fetch (i)->obj; + if (line == NULL) + continue; + Vector<int> * instr_idx = instr_idxs->get (line->id); + if (instr_idx == NULL) + continue; + for (long j = 0; j < instr_idx->size (); j++) + { + Vector<void*>* callee_funcs_vec = (Vector<void*>*)func_info; + if (callee_funcs_vec->size () == 0) + continue; + Vector<Function*>* callee_funcs_value = (Vector<Function*>*)callee_funcs_vec->fetch (instr_idx->fetch (j)); + for (int k = 0; callee_funcs_value != NULL && k < callee_funcs_value->size (); k++) + { + uint64_t funcobj_id = ((Function*) callee_funcs_value->fetch (k))->id; + int old_size = table0->size (); + if (old_size > 0 && i == table0->fetch (old_size - 1) + && funcobj_id == table1->fetch (old_size - 1)) + continue; + table0->append (i); + table1->append (funcobj_id); + table2->append (dbe_strdup (((Function*) callee_funcs_value->fetch (k))->get_name ())); + } + } + } + delete instr_idxs; + delete func_idxs; + destroy (func_info); + delete instr_info; + } + break; + default: + abort (); + } + table->store (0, table0); + table->store (1, table1); + table->store (2, table2); + return table; +} + +// +// Get Table of Function List data with only total values +// +Vector<void*> * +dbeGetFuncListMini (int dbevindex, int type, int /*subtype*/) +{ + Hist_data *data; + DbeView *dbev = dbeSession->getView (dbevindex); + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + default: + data = NULL; + break; + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + + MetricList *mlist = data->get_metric_list (); + + // Get table size: count visible metrics + int nvisible = 0; + for (long i = 0, sz = mlist->size (); i < sz; i++) + { + Metric *m = mlist->get (i); + if (m->is_visible () || m->is_tvisible () || m->is_pvisible ()) + nvisible++; + } + Vector<void*> *table = new Vector<void*>(nvisible + 1); + + // Fill function list elements + Hist_data::HistItem *totals = data->get_totals (); + for (long i = 0, sz = mlist->size (); i < sz; i++) + { + Metric *m = mlist->get (i); + if (!m->is_visible () && !m->is_tvisible () && !m->is_pvisible ()) + continue; + TValue res; + TValue *v = data->get_value (&res, i, totals); + if ((m->get_visbits () & VAL_RATIO) != 0) + { + Vector<double> *col = new Vector<double>(1); + double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN + col->append (d); + table->append (col); + continue; + } + switch (m->get_vtype ()) + { + case VT_INT: + { + Vector<int> *col = new Vector<int>(1); + col->append (v->i); + table->append (col); + break; + } + case VT_ADDRESS: + case VT_ULLONG: + case VT_LLONG: + { + Vector<long long> *col = new Vector<long long>(1); + col->append (v->ll); + table->append (col); + break; + } + case VT_LABEL: + { + Vector<char *> *col = new Vector<char *>(1); + col->append (dbe_strdup (v->l)); + table->append (col); + break; + } + case VT_DOUBLE: + default: + { + Vector<double> *col = new Vector<double>(1); + col->append (v->d); + table->append (col); + break; + } + } + } + table->append (NULL); + return table; +} + +// Get Table of Function List data +Vector<void*> * +dbeGetFuncList (int dbevindex, int type, int subtype) +{ + MetricList *mlist; + Metric *mitem; + int nitems, nvisible; + int index, index2, nv; + char *cell; + Vector<int> *ji_list; + Hist_data *data; + Hist_data::HistItem *item; + + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + + // fprintf(stderr, NTXT("XXX dbeGetFuncList, FuncListDisp_type = %d\n"), type); + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + case DSP_SELF: + data = dbev->fitem_data; + break; + case DSP_CALLER: + data = dbev->callers; + break; + case DSP_CALLEE: + data = dbev->callees; + break; + case DSP_DLAYOUT: + data = dbev->dlay_data; + break; + case DSP_DATAOBJ: + data = dbev->dobj_data; + break; + case DSP_MEMOBJ: + case DSP_INDXOBJ: + data = dbev->get_indxobj_data (subtype); + break; + default: + data = NULL; + break; + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + mlist = data->get_metric_list (); + + // Get table size: count visible metrics + nitems = data->size (); + nvisible = 0; + Vec_loop (Metric*, mlist->get_items (), index, mitem) + { + if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ()) + nvisible++; + } + + // Initialize Java String array + Vector<void*> *table = new Vector<void*>(nvisible + 1); + + // Mark Hi-value metric items for annotated src/dis/layout + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT + || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + ji_list = new Vector<int>(nitems); + + if (dbev->marks->size () > 0) + index = dbev->marks->fetch (0); + else + index = -1; + int mindex = 0; + for (index2 = 0; index2 < nitems; index2++) + { + item = data->fetch (index2); + if (index2 == index) + { + ji_list->store (index2, -item->type); + if (++mindex < dbev->marks->size ()) + index = dbev->marks->fetch (mindex); + else + index = -1; + } + else + ji_list->store (index2, item->type); + } + table->store (nvisible, ji_list); + } + else + table->store (nvisible, NULL); + + // Fill function list elements + nv = 0; + + Vec_loop (Metric*, mlist->get_items (), index, mitem) + { + if (!mitem->is_visible () && !mitem->is_tvisible () && + !mitem->is_pvisible ()) + continue; + + // Fill values + switch (mitem->get_vtype ()) + { + case VT_LABEL: + { + Vector<char*> *jobjects = new Vector<char*>(nitems); + char *buf = NULL; + size_t bufsz = 0; + int lspace = 0; + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 + || type == DSP_DISASM_V2) + { + // if this is source or disassembly, where we'll insert + // a preface into the output line, figure out how wide + // it needs to be + // first, scan all the lines, to get the maximum line number + bufsz = 1024; + buf = (char *) malloc (bufsz); + int max_lineno = 0; + int hidx; + Hist_data::HistItem *hitem; + Vec_loop (Hist_data::HistItem*, data, hidx, hitem) + { + if (!hitem->obj) + continue; + if (hitem->obj->get_type () == Histable::LINE && + ((DbeLine*) hitem->obj)->lineno > max_lineno) + max_lineno = ((DbeLine*) hitem->obj)->lineno; + else if (hitem->obj->get_type () == Histable::INSTR + && ((DbeInstr*) hitem->obj)->lineno > max_lineno) + max_lineno = ((DbeInstr*) hitem->obj)->lineno; + } + + // we have the maximum integer over all linenumbers in the file + // figure out how many digits are needed + lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno); + } + for (index2 = 0; index2 < nitems; index2++) + { + item = data->fetch (index2); + if (type == DSP_DLAYOUT) + cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ()); + else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + // This code is duplicated in output.cc, yet it's + // intended for presentation purpose and thus is + // potentially different for er_print and analyzer. + switch (item->type) + { + case Module::AT_SRC_ONLY: + case Module::AT_SRC: + if (item->obj == NULL) + snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' '); + else + snprintf (buf, bufsz, NTXT (" %*d. "), lspace, ((DbeLine*) item->obj)->lineno); + break; + case Module::AT_FUNC: + case Module::AT_QUOTE: + snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' '); + break; + case Module::AT_DIS: + case Module::AT_DIS_ONLY: + if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1) + snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ', lspace, NTXT ("?")); + else + snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ', lspace, + ((DbeInstr*) item->obj)->lineno); + break; + case Module::AT_COM: + case Module::AT_EMPTY: + *buf = (char) 0; + break; + } + // get the line's text + char *s = item->value[index].l; + if (s != NULL) + { + // copy the string expanding all tabulations + // (JTable doesn't render them) + char *d = buf + strlen (buf); + char c; + size_t column = 0; + do + { + c = *s++; + if (c == '\t') + { + do + { + *d++ = ' '; + column++; + } + while (column & 07); + } + else + { + *d++ = c; + column++; + } + if (column + 32 > bufsz) + { + // Reallocate the buffer + size_t curlen = d - buf; + bufsz += 1024; + char *buf_new = (char *) malloc (bufsz); + strncpy (buf_new, buf, curlen); + buf_new[curlen] = '\0'; + free (buf); + buf = buf_new; + d = buf + curlen; + } + } + while (c != (char) 0); + } + cell = dbe_strdup (buf); + free (item->value[index].l); + item->value[index].l = NULL; //YXXX missing from dbeGetFuncListV2 + } + else + { + // omazur: why don't we have it as metric value + Histable::NameFormat nfmt = dbev->get_name_format (); + cell = dbe_strdup (item->obj->get_name (nfmt)); + } + jobjects->store (index2, cell); + } + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 + || type == DSP_DISASM_V2) + free (buf); + table->store (nv++, jobjects); + break; + } + default: + table->store (nv++, dbeGetTableDataOneColumn (data, index)); + break; + } + } + return table; +} + +Vector<Obj> * +dbeGetComparableObjsV2 (int /* dbevindex */, Obj sel_obj, int type) +{ + long grsize = dbeSession->expGroups->size (); + Vector<Obj> *res = new Vector<Obj> (grsize + 1); + for (long j = 0; j < grsize; j++) + res->append ((Obj) NULL); + res->append (sel_obj); + Histable *obj = (Histable *) sel_obj; + if (obj == NULL) + return res; + Function *func = (Function *) obj->convertto (Histable::FUNCTION); + if (func == NULL) + return res; + Vector<Histable *> *cmpObjs = func->get_comparable_objs (); + if (cmpObjs == NULL || cmpObjs->size () != grsize) + return res; + + Histable::Type conv_type = (type == DSP_SOURCE || type == DSP_SOURCE_V2) ? + Histable::LINE : Histable::INSTR; + switch (obj->get_type ()) + { + case Histable::FUNCTION: + for (long j = 0; j < grsize; j++) + res->store (j, (Obj) cmpObjs->get (j)); + return res; + case Histable::INSTR: + case Histable::LINE: + { + SourceFile *srcContext = (SourceFile *) obj->convertto (Histable::SOURCEFILE); + char *bname = get_basename (srcContext->get_name ()); + for (long j = 0; j < grsize; j++) + { + Function *func1 = (Function *) cmpObjs->get (j); + if (func == func1) + { + if (conv_type == Histable::LINE) + res->store (j, (Obj) obj); + else + res->store (j, (Obj) obj->convertto (conv_type, srcContext)); + continue; + } + if (func1 == NULL) + continue; + Vector<SourceFile*> *sources = func1->get_sources (); + SourceFile *sf = NULL; + for (long j1 = 0, sz1 = sources ? sources->size () : 0; j1 < sz1; j1++) + { + SourceFile *sf1 = sources->get (j1); + if (sf1 == srcContext) + { // the same file + sf = srcContext; + break; + } + else if (sf == NULL) + { + char *bname1 = get_basename (sf1->get_name ()); + if (dbe_strcmp (bname, bname1) == 0) + sf = sf1; + } + } + res->store (j, (Obj) func1->convertto (conv_type, srcContext)); + } + break; + } + default: + break; + } + return res; +} + +// Get Table of Function List data +Vector<void *> * +dbeGetFuncListV2 (int dbevindex, int mtype, Obj sel_obj, int type, int subtype) +{ + Metric *mitem; + int nitems, nvisible; + int index, index2, nv; + char *cell; + Hist_data::HistItem *item; + DbeView *dbev = dbeSession->getView (dbevindex); + dbev->error_msg = dbev->warning_msg = NULL; + MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK), + (mtype & COMPARE_BIT) != 0, + mtype >> GROUP_ID_SHIFT); + Histable *selObj = (Histable *) sel_obj; + int old_compare_mode = dbev->get_compare_mode (); + if ((mtype & COMPARE_BIT) != 0) + dbev->reset_compare_mode (CMP_DISABLE); + Hist_data *data = dbev->get_data (mlist, selObj, type, subtype); + dbev->reset_compare_mode (old_compare_mode); + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + nitems = data->size (); + nvisible = mlist->get_items ()->size (); + + // Initialize Java String array + Vector<void*> *table = new Vector<void*>(nvisible + 3); + // Mark Hi-value metric items for annotated src/dis/layout + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT + || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + Vector<int> *types = new Vector<int>(nitems); + Vector<Obj> *ids = new Vector<Obj > (nitems); + if (dbev->marks->size () > 0) + index = dbev->marks->fetch (0); + else + index = -1; + int mindex = 0; + for (int i = 0; i < nitems; i++) + { + item = data->fetch (i); + ids->store (i, (Obj) item->obj); + if (i == index) + { + types->store (i, -item->type); + if (++mindex < dbev->marks->size ()) + index = dbev->marks->fetch (mindex); + else + index = -1; + } + else + types->store (i, item->type); + } + table->store (nvisible, types); + table->store (nvisible + 1, ids); + } + else + { + table->store (nvisible, NULL); + table->store (nvisible + 1, NULL); + } + + // Fill function list elements + nv = 0; + Vec_loop (Metric*, mlist->get_items (), index, mitem) + { + if (!mitem->is_visible () && !mitem->is_tvisible () && + !mitem->is_pvisible ()) + continue; + + // Fill values + switch (mitem->get_vtype ()) + { + default: + table->store (nv++, dbeGetTableDataOneColumn (data, index)); + break; + case VT_LABEL: + Vector<char*> *jobjects = new Vector<char*>(nitems); + char *buf = NULL; + size_t bufsz = 0; + int lspace = 0; + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 + || type == DSP_DISASM_V2) + { + // if this is source or disassembly, where we'll insert + // a preface into the output line, figure out how wide + // it needs to be + // first, scan all the lines, to get the maximum line number + bufsz = 1024; + buf = (char *) malloc (bufsz); + int max_lineno = 0; + int hidx; + Hist_data::HistItem *hitem; + Vec_loop (Hist_data::HistItem*, data, hidx, hitem) + { + if (!hitem->obj) + continue; + if (hitem->obj->get_type () == Histable::LINE && + ((DbeLine*) hitem->obj)->lineno > max_lineno) + max_lineno = ((DbeLine*) hitem->obj)->lineno; + else if (hitem->obj->get_type () == Histable::INSTR + && ((DbeInstr*) hitem->obj)->lineno > max_lineno) + max_lineno = ((DbeInstr*) hitem->obj)->lineno; + } + + // we have the maximum integer over all linenumbers in the file + // figure out how many digits are needed + lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno); + } + + for (index2 = 0; index2 < nitems; index2++) + { + item = data->fetch (index2); + if (type == DSP_DLAYOUT) + cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ()); + else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2) + { + // This code is duplicated in output.cc, yet it's + // intended for presentation purpose and thus is + // potentially different for er_print and analyzer. + switch (item->type) + { + case Module::AT_SRC_ONLY: + case Module::AT_SRC: + if (item->obj == NULL) + snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' '); + else + snprintf (buf, bufsz, NTXT (" %*d. "), lspace, + ((DbeLine*) item->obj)->lineno); + break; + case Module::AT_FUNC: + case Module::AT_QUOTE: + snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' '); + break; + case Module::AT_DIS: + case Module::AT_DIS_ONLY: + if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1) + snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ', + lspace, NTXT ("?")); + else + snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ', + lspace, + ((DbeInstr*) item->obj)->lineno); + break; + case Module::AT_COM: + case Module::AT_EMPTY: + *buf = (char) 0; + break; + } + // get the line's text + char *s = item->value[index].l; + if (s != NULL) + { + // copy the string expanding all tabulations + // (JTable doesn't render them) + char *d = buf + strlen (buf); + char c; + size_t column = 0; + do + { + c = *s++; + if (c == '\t') + { + do + { + *d++ = ' '; + column++; + } + while (column & 07); + } + else + { + *d++ = c; + column++; + } + if (column + 32 > bufsz) + { + // Reallocate the buffer + size_t curlen = d - buf; + bufsz += 1024; + char *buf_new = (char *) malloc (bufsz); + strncpy (buf_new, buf, curlen); + buf_new[curlen] = '\0'; + free (buf); + buf = buf_new; + d = buf + curlen; + } + } + while (c != (char) 0); + } + cell = dbe_strdup (buf); + } + else + { + Histable::NameFormat nfmt = dbev->get_name_format (); + cell = dbe_strdup (item->obj->get_name (nfmt)); + } + jobjects->store (index2, cell); + } + + if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 + || type == DSP_DISASM_V2) + free (buf); + table->store (nv++, jobjects); + break; + } + } + table->append (dbeGetMetricList (mlist)); + return table; +} // dbeGetFuncListV2 + +// +// Get Table DataV2 +// +Vector<void*> * +dbeGetTableDataV2 (int dbevindex, char *mlistStr, char *modeStr, char *typeStr, + char *subtypeStr, Vector<uint64_t> *ids) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + + // Process metric list specification + if (mlistStr == NULL) + return NULL; + bool met_call = false; + MetricList *mlist = NULL; + if (streq (mlistStr, NTXT ("MET_NORMAL"))) + mlist = dbev->get_metric_list (MET_NORMAL); + else if (streq (mlistStr, NTXT ("MET_CALL"))) + { + met_call = true; + mlist = dbev->get_metric_list (MET_CALL); + } + else if (streq (mlistStr, NTXT ("MET_CALL_AGR"))) + mlist = dbev->get_metric_list (MET_CALL_AGR); + else if (streq (mlistStr, NTXT ("MET_DATA"))) + mlist = dbev->get_metric_list (MET_DATA); + else if (streq (mlistStr, NTXT ("MET_INDX"))) + mlist = dbev->get_metric_list (MET_INDX); + else if (streq (mlistStr, NTXT ("MET_IO"))) + mlist = dbev->get_metric_list (MET_IO); + else if (streq (mlistStr, NTXT ("MET_HEAP"))) + mlist = dbev->get_metric_list (MET_HEAP); + else + return NULL; + + // Process mode specification + if (modeStr == NULL) + return NULL; + Hist_data::Mode mode = (Hist_data::Mode)0; + if (streq (modeStr, NTXT ("CALLERS"))) + mode = Hist_data::CALLERS; + else if (streq (modeStr, NTXT ("CALLEES"))) + mode = Hist_data::CALLEES; + else if (streq (modeStr, NTXT ("SELF"))) + mode = Hist_data::SELF; + else if (streq (modeStr, NTXT ("ALL"))) + mode = Hist_data::ALL; + else + return NULL; + + // Process type specification + if (typeStr == NULL) + return NULL; + Histable::Type type = Histable::OTHER; + if (streq (typeStr, NTXT ("FUNCTION"))) + type = Histable::FUNCTION; + else if (streq (typeStr, NTXT ("INDEXOBJ"))) + type = Histable::INDEXOBJ; + else if (streq (typeStr, NTXT ("IOACTFILE"))) + type = Histable::IOACTFILE; + else if (streq (typeStr, NTXT ("IOACTVFD"))) + type = Histable::IOACTVFD; + else if (streq (typeStr, NTXT ("IOCALLSTACK"))) + type = Histable::IOCALLSTACK; + else if (streq (typeStr, NTXT ("HEAPCALLSTACK"))) + type = Histable::HEAPCALLSTACK; + else if (streq (typeStr, NTXT ("LINE"))) + type = Histable::LINE; + else if (streq (typeStr, NTXT ("INSTR"))) + type = Histable::INSTR; + else + // XXX Accepting objects other than above may require a different + // implementation of the id -> Histable mapping below + return NULL; + + // Process subtype specification + int subtype = 0; + if (subtypeStr != NULL) + subtype = atoi (subtypeStr); + Vector<Histable*> *hobjs = NULL; + if (ids != NULL) + { + hobjs = new Vector<Histable*>(); + for (int i = 0; i < ids->size (); ++i) + { + Histable::Type obj_type = type; + if ((obj_type == Histable::LINE || obj_type == Histable::INSTR) + && subtype == 0) + obj_type = Histable::FUNCTION; + Histable *hobj = dbeSession->findObjectById (obj_type, subtype, ids->fetch (i)); + if ((obj_type == Histable::LINE || obj_type == Histable::INSTR) + && subtype == 0 && hobj == NULL) + return NULL; + hobjs->append (hobj); + } + } + + PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE; + if (dbev->isOmpDisMode () && type == Histable::FUNCTION + && mode == Hist_data::CALLEES && met_call) + flag = PathTree::COMPUTEOPT_OMP_CALLEE; + + Hist_data *data = dbev->get_hist_data (mlist, type, subtype, mode, hobjs, NULL, NULL, flag); + return dbeGetTableDataV2Data (dbev, data); +} + +static Vector<void*> * +dbeGetTableDataV2Data (DbeView * /*dbev*/, Hist_data *data) +{ + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + MetricList *mlist; + mlist = data->get_metric_list (); + int nitems = data->size (); + + // Initialize Java String array + Vector<void*> *table = new Vector<void*>(mlist->size () + 1); + + // Fill function list elements + for (long i = 0, sz = mlist->size (); i < sz; i++) + { + Metric *mitem = mlist->get (i); + if (!mitem->is_visible () && !mitem->is_tvisible () && + !mitem->is_pvisible ()) + continue; + table->append (dbeGetTableDataOneColumn (data, i)); + } + + // Add an array of Histable IDs + Vector<uint64_t> *idList = new Vector<uint64_t>(nitems); + for (int i = 0; i < nitems; ++i) + { + Hist_data::HistItem *item = data->fetch (i); + if (item->obj->get_type () == Histable::LINE + || item->obj->get_type () == Histable::INSTR) + idList->store (i, (uint64_t) (item->obj)); + else + idList->store (i, item->obj->id); + } + table->append (idList); + return table; +} // dbeGetTableData + +//YXXX try to use the following to consolidate similar cut/paste code + +static Vector<void*> * +dbeGetTableDataOneColumn (Hist_data *data, int met_ind) +{ + // Allocates a vector and fills it with metric values for one column + TValue res; + Metric *m = data->get_metric_list ()->get (met_ind); + if ((m->get_visbits () & VAL_RATIO) != 0) + { + Vector<double> *col = new Vector<double>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN + col->append (d); + } + return (Vector<void*> *) col; + } + + switch (m->get_vtype ()) + { + case VT_DOUBLE: + { + Vector<double> *col = new Vector<double>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + col->append (v->d); + } + return (Vector<void*> *) col; + } + case VT_INT: + { + Vector<int> *col = new Vector<int>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + col->append (v->i); + } + return (Vector<void*> *) col; + } + case VT_ULLONG: + case VT_LLONG: + { + Vector<long long> *col = new Vector<long long>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + col->append (v->ll); + } + return (Vector<void*> *) col; + } + case VT_ADDRESS: + { + Vector<long long> *col = new Vector<long long>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + // set the highest bit to mark this jlong as + // a VT_ADDRESS (rather than a regular VT_LLONG) + col->append (v->ll | 0x8000000000000000ULL); + } + return (Vector<void*> *) col; + } + case VT_LABEL: + { + Vector<char *> *col = new Vector<char *>(data->size ()); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + TValue *v = data->get_value (&res, met_ind, row); + col->append (dbe_strdup (v->l)); + } + return (Vector<void*> *) col; + } + default: + return NULL; + } +} + +static Vector<void*> * +dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data, + ValueTag vtype, int metricColumnNumber) +// Allocates a vector and fills it with metric values for one column +{ + Vector<void*> *column_data = NULL; + int nitems = data->size (); // number of rows + int index = metricColumnNumber; + switch (vtype) + { + case VT_DOUBLE: + { + Vector<double> *jd_list = new Vector<double>(nitems); + for (int index2 = 0; index2 < nitems; index2++) + { + Hist_data::HistItem *item = data->fetch (index2); + jd_list->store (index2, item->value[index].d); + } + column_data = (Vector<void*> *)jd_list; + break; + } + case VT_INT: + { + Vector<int> *ji_list = new Vector<int>(nitems); + for (int index2 = 0; index2 < nitems; index2++) + { + Hist_data::HistItem *item = data->fetch (index2); + ji_list->store (index2, item->value[index].i); + } + column_data = (Vector<void*> *)ji_list; + break; + } + case VT_ULLONG: + case VT_LLONG: + { + Vector<long long> *jl_list = new Vector<long long>(nitems); + for (int index2 = 0; index2 < nitems; index2++) + { + Hist_data::HistItem *item = data->fetch (index2); + jl_list->store (index2, item->value[index].ll); + } + column_data = (Vector<void*> *)jl_list; + break; + } + case VT_ADDRESS: + { + Vector<long long> *jl_list = new Vector<long long>(nitems); + for (int index2 = 0; index2 < nitems; index2++) + { + Hist_data::HistItem *item = data->fetch (index2); + + // set the highest bit to mark this jlong as + // a VT_ADDRESS (rather than a regular VT_LLONG) + uint64_t addr = item->value[index].ll; + addr |= 0x8000000000000000ULL; + jl_list->store (index2, addr); + } + column_data = (Vector<void*> *)jl_list; + break; + } + case VT_LABEL: + { + Vector<char*> *jobjects = new Vector<char*>(nitems); + for (int index2 = 0; index2 < nitems; index2++) + { + Hist_data::HistItem *item = data->fetch (index2); + + // omazur: why don't we have it as metric value + Histable::NameFormat nfmt = dbev->get_name_format (); + char *str = dbe_strdup (item->obj->get_name (nfmt)); + jobjects->store (index2, str); + } + column_data = (Vector<void*> *)jobjects; + break; + } + default: + abort (); + } + return column_data; +} + +int +dbeGetCallTreeNumLevels (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return 0; + return ptree->get_ftree_depth (); +} + +Vector<void*>* +dbeGetCallTreeLevel (int dbevindex, char *mcmd, int level) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + if (mcmd == NULL) + return NULL; + BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd); + if (bm == NULL) + return NULL; + return ptree->get_ftree_level (bm, level); +} + +Vector<void*>* +dbeGetCallTreeLevels (int dbevindex, char *mcmd) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + if (mcmd == NULL) + return NULL; + BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd); + if (bm == NULL) + return NULL; + + int depth = ptree->get_ftree_depth (); + Vector<void*> *results = new Vector<void*>(depth); + for (int ii = 0; ii < depth; ii++) + results->append (ptree->get_ftree_level (bm, ii)); + return results; +} + +Vector<void*>* +dbeGetCallTreeLevelFuncs (int dbevindex, int start_level, int end_level) +{ // (0,-1) -> all levels + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + + int depth = ptree->get_ftree_depth (); + if (start_level < 0) + start_level = 0; + if (end_level < 0 || end_level >= depth) + end_level = depth - 1; + + Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format? + Vector<char*> *funcNames = new Vector<char*>(); + Vector<long long> *funcIds = new Vector<long long>(); + Vector<Obj> *funcObjs = new Vector<Obj>(); + + if (start_level == 0 && end_level == depth - 1) + return dbeGetCallTreeFuncs (dbevindex); + else + { + for (int ii = start_level; ii <= end_level; ii++) + { + Vector<void*> *info = ptree->get_ftree_level (NULL, ii); /*no metric*/ + if (!info) + continue; + Vector<long long> *fids = (Vector<long long> *)info->get (2); + if (!fids) + continue; + int index; + long long fid; + Vec_loop (long long, fids, index, fid) + { + funcIds->append (fid); + Histable *obj = dbeSession->findObjectById (fid); + char * fname = obj ? dbe_strdup (obj->get_name (nfmt)) : NULL; + funcNames->append (fname); + funcObjs->append ((unsigned long) obj); // avoiding sign extension + } + destroy (info); + } + } + Vector<void*> *results = new Vector<void*>(3); + results->append (funcIds); + results->append (funcNames); + results->append (funcObjs); + return results; +} + +Vector<void*> * +dbeGetCallTreeFuncs (int dbevindex) +{ // does not require ptree->get_ftree_level() to be computed + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return 0; + Vector<Function*>* funcs = ptree->get_funcs (); // Unique functions in tree + if (funcs == NULL) + return NULL; + + long sz = funcs->size (); + Vector<void*> *results = new Vector<void*>(3); + Vector<long long> *funcIds = new Vector<long long>(sz); + Vector<char*> *funcNames = new Vector<char*>(sz); + Vector<Obj> *funcObjs = new Vector<Obj>(sz); + + int index; + Function * func; + Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format? + Vec_loop (Function *, funcs, index, func) + { + funcIds->append (func->id); // do we need IDs? + char *fname = dbe_strdup (func->get_name (nfmt)); + funcNames->append (fname); + funcObjs->append ((unsigned long) func); // avoiding sign extension + } + results->put (0, funcIds); + results->put (1, funcNames); + results->put (2, funcObjs); + destroy (funcs); + return results; +} + +Vector<void*>* +dbeGetCallTreeChildren (int dbevindex, char *mcmd, Vector<int /*NodeIdx*/>*node_idxs) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (node_idxs == NULL || node_idxs->size () == 0) + return NULL; + long sz = node_idxs->size (); + PathTree * ptree = dbev->get_path_tree (); + if (ptree == NULL) + return NULL; + if (mcmd == NULL) + return NULL; + BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd); + if (bm == NULL) + return NULL; + + Vector<void*> *results = new Vector<void*>(sz); + for (long ii = 0; ii < sz; ii++) + { + PathTree::NodeIdx nodeIdx = node_idxs->get (ii); // upcasted from int + results->append (ptree->get_ftree_node_children (bm, nodeIdx)); + } + return results; +} + +Vector<int> * +dbeGetGroupIds (int /*dbevindex*/) +{ + Vector<ExpGroup*> *groups = dbeSession->expGroups; + int sz = groups->size (); + Vector<int> *grIds = new Vector<int>(sz); + for (int i = 0; i < sz; i++) + grIds->store (i, groups->fetch (i)->groupId); + return grIds; +} + +// +// Get label for name column +// +Vector<char*> * +dbeGetNames (int dbevindex, int type, Obj sel_obj) +{ + char *s0, *s1, *s2; + bool need_strdup = true; + switch (type) + { + case DSP_SOURCE_V2: + case DSP_DISASM_V2: + case DSP_SOURCE: + case DSP_DISASM: + { + if (sel_obj) + { + Histable *selObj = (Histable*) sel_obj; + Function *func = (Function *) selObj->convertto (Histable::FUNCTION); + if (func) + { + char *names[3] = {NULL, NULL, NULL}; + set_file_names (func, names); + s0 = names[0]; + s1 = names[1]; + s2 = names[2]; + need_strdup = false; + break; + } + } + DbeView *dbev = dbeSession->getView (dbevindex); + char **names = type == DSP_SOURCE || type == DSP_SOURCE_V2 ? dbev->names_src : dbev->names_dis; + s0 = names[0]; + s1 = names[1]; + s2 = names[2]; + break; + } + case DSP_LINE: + s0 = GTXT ("Lines"); + s1 = GTXT ("Function, line # in \"sourcefile\""); + s2 = NTXT (""); + break; + case DSP_PC: + s0 = GTXT ("PCs"); + s1 = GTXT ("Function + offset"); + s2 = NTXT (""); + break; + case DSP_DLAYOUT: + s0 = GTXT ("Name"); + s1 = GTXT ("* +offset .element"); + s2 = NTXT (""); + break; + default: + s0 = GTXT ("Name"); + s1 = s2 = NTXT (""); + break; + } + if (need_strdup) + { + s0 = dbe_strdup (s0); + s1 = dbe_strdup (s1); + s2 = dbe_strdup (s2); + } + Vector<char*> *table = new Vector<char*>(3); + table->store (0, s0); + table->store (1, s1); + table->store (2, s2); + return table; +} + +// +// Get Total/Maximum element of Function List +// +Vector<void*> * +dbeGetTotalMax (int dbevindex, int type, int subtype) +{ + Hist_data *data; + int index; + Hist_data::HistItem *total_item, *maximum_item; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + + switch (type) + { + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_CALLER: + data = dbev->callers; + break; + case DSP_SELF: + case DSP_CALLEE: + data = dbev->callees; + break; + case DSP_DLAYOUT: + data = dbev->dlay_data; + break; + case DSP_DATAOBJ: + data = dbev->dobj_data; + break; + case DSP_MEMOBJ: + data = dbev->get_indxobj_data (subtype); + break; + case DSP_INDXOBJ: + data = dbev->get_indxobj_data (subtype); + break; + case DSP_FUNCTION: // annotated src/dis use func total/max + case DSP_SOURCE: + case DSP_DISASM: + case DSP_SOURCE_V2: + case DSP_DISASM_V2: + data = dbev->func_data; + break; + default: + abort (); + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + + // Get list size + // XXX -- the original list has all items, visible or not; + // XXX -- the one from Hist_data has only visible items, + // XXX -- and should be the only ones computed + // XXX -- Analyzer got confused (yesterday), when we used the shorter list + // XXX -- Why can we fetch total/max for metrics never + // XXX -- computed without core dumping? + MetricList *mlist2 = data->get_metric_list (); + int size = mlist2->get_items ()->size (); + + // Initialize Java array + Vector<void*> *total_max = new Vector<void*>(2); + Vector<double> *total = new Vector<double>(size); + Vector<double> *maximum = new Vector<double>(size); + + // Fill total/maximum element + total_item = data->get_totals (); + maximum_item = data->get_maximums (); + + for (index = 0; index < size; index++) + { + total->store (index, total_item->value[index].to_double ()); + maximum->store (index, maximum_item->value[index].to_double ()); + } + total_max->store (0, total); + total_max->store (1, maximum); + return total_max; +} + +// +// Get Table of Overview List +Vector<void*> * +dbeGetStatisOverviewList (int dbevindex) +{ + int size; + Ovw_data **data; + Ovw_data::Ovw_item labels, *totals; + int nitems; + int index, index2; + + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->error_msg = dbev->warning_msg = NULL; + + size = dbeSession->nexps (); + totals = new Ovw_data::Ovw_item[size + 1]; + data = new Ovw_data*[size + 1]; + data[0] = new Ovw_data (); + + for (index = 1; index <= size; index++) + { + data[index] = dbev->get_ovw_data (index - 1); + if (data[index] == NULL) + { + Ovw_data::reset_item (&totals[index]); // set contents to zeros + continue; + } + data[0]->sum (data[index]); + totals[index] = data[index]->get_totals (); //shallow copy! + } + totals[0] = data[0]->get_totals (); + + // Get table size + labels = data[0]->get_labels (); + nitems = labels.size + 4; + + // Initialize Java String array + Vector<void*> *table = new Vector<void*>(size + 4); + Vector<char*> *jobjects = new Vector<char*>(nitems); + + // Set the label + jobjects->store (0, dbe_strdup (GTXT ("Start Time (sec.)"))); + jobjects->store (1, dbe_strdup (GTXT ("End Time (sec.)"))); + jobjects->store (2, dbe_strdup (GTXT ("Duration (sec.)"))); + jobjects->store (3, dbe_strdup (GTXT ("Total Thread Time (sec.)"))); + jobjects->store (4, dbe_strdup (GTXT ("Average number of Threads"))); + + for (index2 = 5; index2 < nitems; index2++) + jobjects->store (index2, dbe_strdup (labels.values[index2 - 4].l)); + table->store (0, jobjects); + + // Set the data + for (index = 0; index <= size; index++) + { + Vector<double> *jd_list = new Vector<double>(nitems); + jd_list->store (0, tstodouble (totals[index].start)); + jd_list->store (1, tstodouble (totals[index].end)); + jd_list->store (2, tstodouble (totals[index].duration)); + jd_list->store (3, tstodouble (totals[index].tlwp)); + jd_list->store (4, totals[index].nlwp); + for (index2 = 5; index2 < nitems; index2++) + jd_list->store (index2, tstodouble (totals[index].values[index2 - 4].t)); + table->store (index + 1, jd_list); + } + for (index = 0; index <= size; index++) + delete data[index]; + delete[] data; + delete[] totals; + return table; +} + +// Get Table of Statistics List +Vector<void*> * +dbeGetStatisList (int dbevindex) +{ + int size; + Stats_data **data; + int nitems; + int index, index2; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + dbev->error_msg = dbev->warning_msg = NULL; + if ((size = dbeSession->nexps ()) == 0) + return NULL; + + // Get statistics data + data = (Stats_data **) malloc ((size + 1) * sizeof (Stats_data *)); + data[0] = new Stats_data (); + for (index = 1; index <= size; index++) + { + data[index] = dbev->get_stats_data (index - 1); + if (data[index] == NULL) + continue; + data[0]->sum (data[index]); + } + + // Get table size + nitems = data[0]->size (); + + // Initialize Java String array + Vector<void*> *table = new Vector<void*>(size + 2); + Vector<char*> *jobjects = new Vector<char*>(nitems); + + // Set the label + for (index2 = 0; index2 < nitems; index2++) + jobjects->store (index2, dbe_strdup (data[0]->fetch (index2).label)); + table->store (0, jobjects); + + // Set the data + for (index = 0; index <= size; index++) + { + Vector<double> *jd_list = new Vector<double>(nitems); + for (index2 = 0; index2 < nitems; index2++) + { + double val = 0; + if (data[index]) + val = data[index]->fetch (index2).value.to_double (); + jd_list->store (index2, val); + } + table->store (index + 1, jd_list); + } + if (data) + { + for (index = 0; index <= size; index++) + delete data[index]; + free (data); + } + return table; +} + + +// +// Set summary list +// +static void +setSummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, Vector<char*> *jvalues) +{ + char *sname = NULL, *oname = NULL, *lname = NULL, *alias = NULL, + *mangle = NULL, *address = NULL, *size = NULL, + *name_0 = NULL, *sname_0 = NULL, *oname_0 = NULL, *lname_0 = NULL, + *alias_0 = NULL, *mangle_0 = NULL; + Function *func, *last_func = NULL; + int one_func = 1; + + // Get the source/object/load-object files & aliases + long long ll_size = 0; + for (long i = 0; i < objs->size (); i++) + { + Histable *current_obj = objs->fetch (i); + Histable::Type htype = current_obj->get_type (); + if (htype == Histable::LOADOBJECT) + lname = ((LoadObject *) current_obj)->dbeFile->get_location_info (); + else if ((func = (Function*) current_obj->convertto (Histable::FUNCTION)) != NULL) + { + if (one_func && last_func != NULL && last_func != func) + one_func = 0; + last_func = func; + sname = NULL; + DbeLine *dbeline = (DbeLine*) current_obj->convertto (Histable::LINE); + if (dbeline) + { + SourceFile *sf; + if (dbeline->lineno == 0 && dbeline->include != NULL) + sf = dbeline->include; + else if (dbeline->sourceFile != NULL) + sf = dbeline->sourceFile; + else + sf = func->getDefSrc (); + if (sf) + sname = sf->dbeFile->get_location_info (); + } + char *func_name = func->get_name (); + mangle = func->get_mangled_name (); + if (mangle && streq (func_name, mangle)) + mangle = NULL; + Module *module = func->module; + if (module != NULL) + { + module->read_stabs (); + if (sname == NULL || strlen (sname) == 0) + { + SourceFile *sf = module->getMainSrc (); + sname = sf->dbeFile->get_location_info (); + } + DbeFile *df = module->dbeFile; + if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0) + df = module->loadobject->dbeFile; + lname = df->get_location_info (); + oname = lname; + if (module->dot_o_file) + oname = module->dot_o_file->dbeFile->get_location_info (); + } + + if (htype == Histable::INSTR && dbeSession->is_datamode_available ()) + alias = ((DbeInstr*) current_obj)->get_descriptor (); + } + + char *name = current_obj->get_name (); + if (i == 0) + { + name_0 = name; + lname_0 = lname; + sname_0 = sname; + oname_0 = oname; + mangle_0 = mangle; + alias_0 = alias; + if (objs->size () == 1) + { + uint64_t addr = current_obj->get_addr (); + address = dbe_sprintf (NTXT ("%lld:0x%08llX"), + (long long) ADDRESS_SEG (addr), + (long long) ADDRESS_OFF (addr)); + } + } + else + { + if (name_0 != name) + name_0 = NULL; + if (lname_0 != lname) + lname_0 = NULL; + if (sname_0 != sname) + sname_0 = NULL; + if (oname_0 != oname) + oname_0 = NULL; + if (mangle_0 != mangle) + mangle_0 = NULL; + if (alias_0 != alias) + alias_0 = NULL; + } + if (current_obj->get_size () == -1) + { + if (size == NULL) + size = dbe_strdup (GTXT ("(Unknown)")); + } + else + ll_size += current_obj->get_size (); + } + if (size == NULL) + size = dbe_sprintf (NTXT ("%lld"), ll_size); + if (name_0 == NULL) + { + if (objs->size () > 1) + { + char *func_name = last_func == NULL ? NULL : + (one_func == 0 ? NULL : last_func->get_name ()); + name_0 = dbe_sprintf (NTXT ("%s%s%s (%lld %s)"), + func_name == NULL ? "" : func_name, + func_name == NULL ? "" : ": ", + GTXT ("Multiple Selection"), + (long long) objs->size (), + GTXT ("objects")); + } + } + else + name_0 = dbe_strdup (name_0); + + // Set the name area + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'N'); + jlabels->store (0, dbe_strdup (GTXT ("Name"))); + jvalues->store (0, name_0); + + saligns->store (1, TEXT_LEFT); + mnemonic->store (1, 'P'); + jlabels->store (1, dbe_strdup (GTXT ("PC Address"))); + jvalues->store (1, address); + + saligns->store (2, TEXT_LEFT); + mnemonic->store (2, 'z'); + jlabels->store (2, dbe_strdup (GTXT ("Size"))); + jvalues->store (2, size); + + saligns->store (3, TEXT_RIGHT); + mnemonic->store (3, 'r'); + jlabels->store (3, dbe_strdup (GTXT ("Source File"))); + jvalues->store (3, dbe_strdup (sname_0)); + + saligns->store (4, TEXT_RIGHT); + mnemonic->store (4, 'b'); + jlabels->store (4, dbe_strdup (GTXT ("Object File"))); + jvalues->store (4, dbe_strdup (oname_0)); + + saligns->store (5, TEXT_LEFT); + mnemonic->store (5, 'j'); + jlabels->store (5, dbe_strdup (GTXT ("Load Object"))); + jvalues->store (5, dbe_strdup (lname_0)); + + saligns->store (6, TEXT_LEFT); + mnemonic->store (6, 'm'); + jlabels->store (6, dbe_strdup (GTXT ("Mangled Name"))); + jvalues->store (6, dbe_strdup (mangle_0)); + + saligns->store (7, TEXT_LEFT); + mnemonic->store (7, 'A'); + jlabels->store (7, dbe_strdup (GTXT ("Aliases"))); + jvalues->store (7, dbe_strdup (alias_0)); +} + +// Set memory-object summary list +// +static void +setMemSummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, + Vector<char*> *jvalues) +{ + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'M'); + jlabels->store (0, dbe_strdup (GTXT ("Memory Object"))); + if (objs->size () == 1) + { + Histable *current_obj = objs->fetch (0); + jvalues->store (0, dbe_strdup (current_obj->get_name ())); + } + else + { + char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), + GTXT ("Multiple Selection"), + (long long) objs->size (), GTXT ("objects")); + jvalues->store (0, name); + } +} + +// Set index-object summary list +// +static void +setIndxSummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, + Vector<char*> *jvalues) +{ + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'I'); + jlabels->store (0, dbe_strdup (GTXT ("Index Object"))); + + if (objs->size () == 1) + { + Histable *current_obj = objs->fetch (0); + jvalues->store (0, dbe_strdup (current_obj->get_name ())); + } + else + { + char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"), + (long long) objs->size (), GTXT ("objects")); + jvalues->store (0, name); + } +} + +// Set I/O activity summary list +// +static void +setIOActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, + Vector<char*> *jvalues) +{ + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'O'); + jlabels->store (0, dbe_strdup (GTXT ("I/O Activity"))); + if (objs->size () == 1) + { + Histable *current_obj = objs->fetch (0); + jvalues->store (0, dbe_strdup (current_obj->get_name ())); + } + else + { + char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"), + (long long) objs->size (), GTXT ("objects")); + jvalues->store (0, name); + } +} + +// Set heap activity summary list +// +static void +setHeapActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, + Vector<char*> *jvalues) +{ + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'O'); + jlabels->store (0, dbe_strdup (GTXT ("Heap Activity"))); + + if (objs->size () == 1) + { + Histable *current_obj = objs->fetch (0); + jvalues->store (0, dbe_strdup (current_obj->get_name ())); + } + else + { + char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"), + (long long) objs->size (), GTXT ("objects")); + jvalues->store (0, name); + } +} + +// +// Set data-object summary list +// +static void +setDataSummary (Vector<Histable*> *objs, Vector<int> *saligns, + Vector<char> *mnemonic, Vector<char*> *jlabels, + Vector<char*> *jvalues) +{ + char *name, *type, *member, *elist; + DataObject *dobj; + Vector<DataObject *> *delem; + Histable *scope; + int index; + char *size, *offset, *elements, *scopename; + + // Get the data object elements + member = elist = type = size = offset = elements = scopename = NULL; + + if (objs->size () == 1) + { + Histable *current_obj = objs->fetch (0); + name = dbe_strdup (current_obj->get_name ()); + dobj = (DataObject *) current_obj; + type = dobj->get_typename (); + scope = dobj->get_scope (); + delem = dbeSession->get_dobj_elements (dobj); + if (type == NULL) + type = GTXT ("(Synthetic)"); + if (!scope) + scopename = dbe_strdup (GTXT ("(Global)")); + else + { + switch (scope->get_type ()) + { + case Histable::FUNCTION: + scopename = dbe_sprintf (NTXT ("%s(%s)"), + ((Function*) scope)->module->get_name (), + scope->get_name ()); + break; + case Histable::LOADOBJECT: + case Histable::MODULE: + default: + scopename = dbe_strdup (scope->get_name ()); + break; + } + } + + if (dobj->get_offset () != -1) + { + if (dobj->get_parent ()) + member = dbe_strdup (dobj->get_parent ()->get_name ()); + offset = dbe_sprintf (NTXT ("%lld"), (long long) dobj->get_offset ()); + } + size = dbe_sprintf ("%lld", (long long) dobj->get_size ()); + + if (delem->size () > 0) + { + elements = dbe_sprintf (NTXT ("%lld"), (long long) delem->size ()); + StringBuilder sb_tmp, sb; + sb.append (GTXT ("Offset Size Name\n")); + for (index = 0; index < delem->size (); index++) + { + DataObject *ditem = delem->fetch (index); + sb_tmp.sprintf (NTXT ("%6lld %5lld %s\n"), + (long long) ditem->get_offset (), + (long long) ditem->get_size (), ditem->get_name ()); + sb.append (&sb_tmp); + } + if (sb.charAt (sb.length () - 1) == '\n') + sb.setLength (sb.length () - 1); + elist = sb.toString (); + } + } + else + name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"), + (long long) objs->size (), GTXT ("objects")); + + saligns->store (0, TEXT_LEFT); + mnemonic->store (0, 'D'); + jlabels->store (0, dbe_strdup (GTXT ("Data Object"))); + jvalues->store (0, name); + + saligns->store (1, TEXT_LEFT); + mnemonic->store (1, 'S'); + jlabels->store (1, dbe_strdup (GTXT ("Scope"))); + jvalues->store (1, scopename); + + saligns->store (2, TEXT_LEFT); + mnemonic->store (2, 'T'); + jlabels->store (2, dbe_strdup (GTXT ("Type"))); + jvalues->store (2, dbe_strdup (type)); + + saligns->store (3, TEXT_LEFT); + mnemonic->store (3, 'M'); + jlabels->store (3, dbe_strdup (GTXT ("Member of"))); + jvalues->store (3, member); + + saligns->store (4, TEXT_LEFT); + mnemonic->store (4, 'O'); + jlabels->store (4, dbe_strdup (GTXT ("Offset"))); + jvalues->store (4, offset); + + saligns->store (5, TEXT_LEFT); + mnemonic->store (5, 'z'); + jlabels->store (5, dbe_strdup (GTXT ("Size"))); + jvalues->store (5, size); + + saligns->store (6, TEXT_LEFT); + mnemonic->store (6, 'E'); + jlabels->store (6, dbe_strdup (GTXT ("Elements"))); + jvalues->store (6, elements); + + saligns->store (7, TEXT_LEFT); + mnemonic->store (7, 'L'); + jlabels->store (7, dbe_strdup (GTXT ("List"))); + jvalues->store (7, elist); +} + +#define SUMMARY_NAME 8 +#define DSUMMARY_NAME 8 +#define LSUMMARY_NAME 7 +#define IMSUMMARY_NAME 1 + +Vector<void*> * +dbeGetSummaryV2 (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype) +{ + if (sel_objs == NULL || sel_objs->size () == 0) + return NULL; + DbeView *dbev = dbeSession->getView (dbevindex); + Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ()); + for (int i = 0; i < sel_objs->size (); i++) + { + Histable *obj = (Histable *) sel_objs->fetch (i); + if (obj == NULL) + continue; + char *nm = obj->get_name (); + if (streq (nm, NTXT ("<Total>"))) + { + // Special case for 'Total'. + // Multi selection which includes 'Total' is only 'Total' + objs->reset (); + objs->append (obj); + break; + } + objs->append (obj); + } + if (objs->size () == 0) + return NULL; + + // Set name area + int nname = SUMMARY_NAME; + Vector<int> *saligns = new Vector<int>(nname); + Vector<char>*mnemonic = new Vector<char>(nname); + Vector<char*> *jlabels = new Vector<char*>(nname); + Vector<char*> *jvalues = new Vector<char*>(nname); + Vector<void*> *name_objs = new Vector<void*>(4); + name_objs->store (0, saligns); + name_objs->store (1, mnemonic); + name_objs->store (2, jlabels); + name_objs->store (3, jvalues); + setSummary (objs, saligns, mnemonic, jlabels, jvalues); + + MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL)); + if (prop_mlist && dbev->comparingExperiments ()) + prop_mlist = dbev->get_compare_mlist (prop_mlist, 0); + + int nitems = prop_mlist->get_items ()->size (); + + // Set the metrics area + jlabels = new Vector<char*>(nitems); + Vector<double> *clock_list = new Vector<double>(nitems); + Vector<double> *excl_list = new Vector<double>(nitems); + Vector<double> *ep_list = new Vector<double>(nitems); + Vector<double> *incl_list = new Vector<double>(nitems); + Vector<double> *ip_list = new Vector<double>(nitems); + Vector<int> *vtype = new Vector<int>(nitems); + + // Initialize Java String array + Vector<void*> *metric_objs = new Vector<void*>(8); + metric_objs->store (0, jlabels); + metric_objs->store (1, clock_list); + metric_objs->store (2, excl_list); + metric_objs->store (3, ep_list); + metric_objs->store (4, incl_list); + metric_objs->store (5, ip_list); + metric_objs->store (6, vtype); + + int last_init = -1; + for (int i = 0; i < objs->size (); i++) + { + Histable *obj = objs->fetch (i); + // Get the data to be displayed + Hist_data *data = dbev->get_hist_data (prop_mlist, obj->get_type (), subtype, + Hist_data::SELF, obj, dbev->sel_binctx, objs); + + if (data->get_status () != Hist_data::SUCCESS) + { + if (type != DSP_DLAYOUT) + { // For data_layout, rows with zero metrics are OK + delete data; + continue; + } + } + TValue *values = NULL; + if (data->get_status () == Hist_data::SUCCESS) + { + Hist_data::HistItem *hi = data->fetch (0); + if (hi) + values = hi->value; + } + Hist_data::HistItem *total = data->get_totals (); + int index2 = 0; + char *tstr = GTXT (" Time"); + char *estr = GTXT ("Exclusive "); + size_t len = strlen (estr); + + // get the metric list from the data + MetricList *mlist = data->get_metric_list (); + int index; + Metric *mitem; + double clock; + Vec_loop (Metric*, mlist->get_items (), index, mitem) + { + if (mitem->get_subtype () == Metric::STATIC) + continue; + if (last_init < index2) + { + last_init = index2; + jlabels->store (index2, NULL); + clock_list->store (index2, 0.0); + excl_list->store (index2, 0.0); + ep_list->store (index2, 0.0); + incl_list->store (index2, 0.0); + ip_list->store (index2, 0.0); + vtype->store (index2, 0); + } + double dvalue = (values != NULL) ? values[index].to_double () : 0.0; + double dtotal = total->value[index].to_double (); + if (mitem->is_time_val ()) + clock = 1.e+6 * dbeSession->get_clock (-1); + else + clock = 0.0; + + clock_list->store (index2, clock); + if ((mitem->get_subtype () == Metric::EXCLUSIVE) || + (mitem->get_subtype () == Metric::DATASPACE)) + { + if (i == 0) + { + char *sstr = mitem->get_name (); + if (!strncmp (sstr, estr, len)) + sstr += len; + char *buf, *lstr = strstr (sstr, tstr); + if (lstr) + buf = dbe_strndup (sstr, lstr - sstr); + else + buf = dbe_strdup (sstr); + jlabels->store (index2, buf); + vtype->store (index2, mitem->get_vtype ()); + } + dvalue += excl_list->fetch (index2); + double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100; + excl_list->store (index2, dvalue); + ep_list->store (index2, percent); + } + else + { + dvalue += incl_list->fetch (index2); + if (dvalue > dtotal) + dvalue = dtotal; // temporary correction + double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100; + incl_list->store (index2, dvalue); + ip_list->store (index2, percent); + index2++; + } + } + delete data; + } + delete prop_mlist; + Vector<void*> *summary = new Vector<void*>(2); + summary->store (0, name_objs); + summary->store (1, metric_objs); + return summary; +} + +// Get Summary List +Vector<void*> * +dbeGetSummary (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype) +{ + bool is_data, is_mem, is_indx, is_iodata, is_heapdata; + Hist_data::HistItem *total; + MetricList *prop_mlist; // as passed to get_hist_data + MetricList *mlist; // as stored in the data + Metric *mitem; + int i, nname, nitems, index, index2; + TValue *values; + double dvalue, clock; + Hist_data *data; + Vector<double> *percent_scale; + + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (sel_objs == NULL || sel_objs->size () == 0) + return NULL; + + is_mem = false; + is_data = false; + is_indx = false; + is_iodata = false; + is_heapdata = false; + nname = SUMMARY_NAME; + Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ()); + if (type == DSP_TIMELINE) + objs->append ((Histable *) sel_objs->fetch (0)); + else + { + switch (type) + { + case DSP_FUNCTION: + data = dbev->func_data; + break; + case DSP_LINE: + data = dbev->line_data; + break; + case DSP_PC: + data = dbev->pc_data; + break; + case DSP_SELF: + data = dbev->fitem_data; + break; + case DSP_SOURCE: + case DSP_SOURCE_V2: + data = dbev->src_data; + break; + case DSP_DISASM: + case DSP_DISASM_V2: + data = dbev->dis_data; + break; + case DSP_DLAYOUT: + is_data = true; + nname = LSUMMARY_NAME; + data = dbev->dlay_data; + break; + case DSP_DATAOBJ: + is_data = true; + nname = DSUMMARY_NAME; + data = dbev->dobj_data; + break; + case DSP_MEMOBJ: + is_data = true; + is_mem = true; + nname = IMSUMMARY_NAME; + data = dbev->get_indxobj_data (subtype); + break; + case DSP_INDXOBJ: + is_indx = true; + nname = IMSUMMARY_NAME; + data = dbev->get_indxobj_data (subtype); + break; + case DSP_IOACTIVITY: + is_iodata = true; + nname = IMSUMMARY_NAME; + data = dbev->iofile_data; + break; + case DSP_IOVFD: + is_iodata = true; + nname = IMSUMMARY_NAME; + data = dbev->iovfd_data; + break; + case DSP_IOCALLSTACK: + is_iodata = true; + nname = IMSUMMARY_NAME; + data = dbev->iocs_data; + break; + case DSP_HEAPCALLSTACK: + is_heapdata = true; + nname = IMSUMMARY_NAME; + data = dbev->heapcs_data; + break; + default: + data = NULL; + break; + } + if (data == NULL || data->get_status () != Hist_data::SUCCESS) + return NULL; + + Hist_data::HistItem *current_item; + for (i = 0; i < sel_objs->size (); i++) + { + int sel_index = (int) sel_objs->fetch (i); + if (type != DSP_IOACTIVITY && type != DSP_IOVFD && + type != DSP_IOCALLSTACK && type != DSP_HEAPCALLSTACK) + { + if (sel_index < 0 || sel_index >= data->size ()) + continue; + current_item = data->fetch (sel_index); + if (current_item->obj == NULL) + continue; + } + else + { + if (sel_index < 0) + continue; + bool found = false; + for (int j = 0; j < data->size (); j++) + { + current_item = data->fetch (j); + if ((current_item->obj != NULL) && (current_item->obj->id == sel_index)) + { + found = true; + break; + } + } + if (!found) + continue; + } + char *nm = current_item->obj->get_name (); + if (streq (nm, NTXT ("<Total>"))) + { + // Special case for 'Total'. + // Multi selection which includes 'Total' is only 'Total' + objs->reset (); + objs->append (current_item->obj); + break; + } + objs->append (current_item->obj); + } + } + if (objs->size () == 0) + return NULL; + + // Set name area + Vector<int> *saligns = new Vector<int>(nname); + Vector<char>*mnemonic = new Vector<char>(nname); + Vector<char*> *jlabels = new Vector<char*>(nname); + Vector<char*> *jvalues = new Vector<char*>(nname); + Vector<void*> *name_objs = new Vector<void*>(4); + name_objs->store (0, saligns); + name_objs->store (1, mnemonic); + name_objs->store (2, jlabels); + name_objs->store (3, jvalues); + if (is_mem) + setMemSummary (objs, saligns, mnemonic, jlabels, jvalues); + else if (is_indx) + setIndxSummary (objs, saligns, mnemonic, jlabels, jvalues); + else if (is_data) + setDataSummary (objs, saligns, mnemonic, jlabels, jvalues); + else if (is_iodata) + setIOActivitySummary (objs, saligns, mnemonic, jlabels, jvalues); + else if (is_heapdata) + setHeapActivitySummary (objs, saligns, mnemonic, jlabels, jvalues); + else + setSummary (objs, saligns, mnemonic, jlabels, jvalues); + + // Get the reference metrics + if (is_data) + prop_mlist = new MetricList (dbev->get_metric_ref (MET_DATA)); + else if (is_indx) + prop_mlist = new MetricList (dbev->get_metric_ref (MET_INDX)); + else if (is_iodata) + prop_mlist = new MetricList (dbev->get_metric_ref (MET_IO)); + else if (is_heapdata) + prop_mlist = new MetricList (dbev->get_metric_ref (MET_HEAP)); + else + prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL)); + + // XXXX a workaround to avoid aggregated data for compare mode, only show base experiment data + if (prop_mlist && dbev->comparingExperiments ()) + prop_mlist = dbev->get_compare_mlist (prop_mlist, 0); + nitems = prop_mlist->get_items ()->size (); + + // Set the metrics area + jlabels = new Vector<char*>(nitems); + Vector<double> *clock_list = new Vector<double>(nitems); + Vector<double> *excl_list = new Vector<double>(nitems); + Vector<double> *ep_list = new Vector<double>(nitems); + Vector<double> *incl_list = new Vector<double>(nitems); + Vector<double> *ip_list = new Vector<double>(nitems); + Vector<int> *vtype = new Vector<int>(nitems); + + // Initialize Java String array + Vector<void*> *metric_objs = new Vector<void*>(8); + metric_objs->store (0, jlabels); + metric_objs->store (1, clock_list); + metric_objs->store (2, excl_list); + metric_objs->store (3, ep_list); + metric_objs->store (4, incl_list); + metric_objs->store (5, ip_list); + metric_objs->store (6, vtype); + percent_scale = new Vector<double>(); + int last_init = -1; + for (i = 0; i < objs->size (); i++) + { + Histable *current_obj = objs->fetch (i); + // Get the data to be displayed + data = dbev->get_hist_data (prop_mlist, current_obj->get_type (), subtype, + Hist_data::SELF, current_obj, dbev->sel_binctx, objs); + if (data->get_status () != Hist_data::SUCCESS) + { + if (type != DSP_DLAYOUT) + { // For data_layout, rows with zero metrics are OK + delete data; + continue; + } + } + Hist_data::HistItem *hi = data->fetch (0); + values = hi ? hi->value : NULL; + total = data->get_totals (); + index2 = 0; + + // get the metric list from the data + mlist = data->get_metric_list (); + + // We loop over the metrics in mlist. + // We construct index2, which tells us + // the corresponding entry in the metric_objs lists. + // We need this mapping multiple times. + // So, if you change the looping in any way here, + // do so as well in other similar loops. + // All such loops are marked so: + // See discussion on "mlist-to-index2 mapping". + + Vec_loop (Metric*, mlist->get_items (), index, mitem) + { + if (mitem->get_subtype () == Metric::STATIC) + continue; + if (last_init < index2) + { + last_init = index2; + jlabels->store (index2, NULL); + clock_list->store (index2, 0.0); + excl_list->store (index2, 0.0); + ep_list->store (index2, 0.0); + incl_list->store (index2, 0.0); + ip_list->store (index2, 0.0); + vtype->store (index2, 0); + } + dvalue = (values != NULL) ? values[index].to_double () : 0.0; + double dtotal = total->value[index].to_double (); + percent_scale->store (index, dtotal == 0. ? 0. : 100. / dtotal); + if (mitem->is_time_val ()) + clock = 1.e+6 * dbeSession->get_clock (-1); + else + clock = 0.0; + + clock_list->store (index2, clock); + if (mitem->get_subtype () == Metric::EXCLUSIVE || + mitem->get_subtype () == Metric::DATASPACE) + { + if (i == 0) + { + char *sstr = mitem->get_username (); + char *buf = dbe_strdup (sstr); + jlabels->store (index2, buf); + vtype->store (index2, mitem->get_vtype ()); + } + dvalue += excl_list->fetch (index2); + double percent = dvalue * percent_scale->fetch (index); + excl_list->store (index2, dvalue); + ep_list->store (index2, percent); + if (is_data || is_indx || is_iodata || is_heapdata) + // move to next row, except if there's inclusive data, too + index2++; + } + else + { + dvalue += incl_list->fetch (index2); + if (dvalue > dtotal && mitem->get_type () != BaseMetric::DERIVED) + dvalue = dtotal; // temporary correction + double percent = dvalue * percent_scale->fetch (index); + incl_list->store (index2, dvalue); + ip_list->store (index2, percent); + index2++; + } + } + delete data; + } + + // for multi-selection, we have to recompute the derived metrics + if (objs->size () > 1 && + dbev->get_derived_metrics () != NULL && + dbev->get_derived_metrics ()->get_items () != NULL && + dbev->get_derived_metrics ()->get_items ()->size () > 0) + { + // See discussion on "mlist-to-index2 mapping". + Vector<Metric*> *mvec = new Vector<Metric*>(nitems); + index2 = 0; + Vec_loop (Metric*, prop_mlist->get_items (), index, mitem) + { + if (mitem->get_subtype () == Metric::STATIC) + continue; + if (mitem->get_subtype () == Metric::EXCLUSIVE || + mitem->get_subtype () == Metric::DATASPACE) + { + mvec->store (index2, mitem); + if (is_data || is_indx || is_iodata || is_heapdata) + index2++; + } + else + { + assert (strcmp (mvec->fetch (index2)->get_cmd (), mitem->get_cmd ()) == 0); + index2++; + } + } + int *map = dbev->get_derived_metrics ()->construct_map (mvec, BaseMetric::EXCLUSIVE, mvec->fetch (0)->get_expr_spec ()); + if (map != NULL) + { + int nmetrics = mvec->size (); + double *evalues = (double *) malloc (nmetrics * sizeof (double)); + double *ivalues = (double *) malloc (nmetrics * sizeof (double)); + for (index2 = 0; index2 < nmetrics; index2++) + { + evalues[index2] = excl_list->fetch (index2); + ivalues[index2] = incl_list->fetch (index2); + } + + // evaluate derived metrics + dbev->get_derived_metrics ()->eval (map, evalues); + dbev->get_derived_metrics ()->eval (map, ivalues); + for (index2 = 0; index2 < nmetrics; index2++) + { + excl_list->store (index2, evalues[index2]); + incl_list->store (index2, ivalues[index2]); + } + + // recompute percentages for derived metrics EUGENE maybe all percentage computations should be moved here + // See discussion on "mlist-to-index2 mapping". + index2 = 0; + Vec_loop (Metric*, prop_mlist->get_items (), index, mitem) + { + if (mitem->get_subtype () == Metric::STATIC) + continue; + if (mitem->get_subtype () == Metric::EXCLUSIVE || + mitem->get_subtype () == Metric::DATASPACE) + { + if (mitem->get_type () == BaseMetric::DERIVED) + ep_list->store (index2, excl_list->fetch (index2) * percent_scale->fetch (index)); + if (is_data || is_indx || is_iodata || is_heapdata) + index2++; + } + else + { + if (mitem->get_type () == BaseMetric::DERIVED) + ip_list->store (index2, incl_list->fetch (index2) * percent_scale->fetch (index)); + index2++; + } + } + free (evalues); + free (ivalues); + free (map); + } + delete mvec; + } + delete prop_mlist; + Vector<void*> *summary = new Vector<void*>(2); + summary->store (0, name_objs); + summary->store (1, metric_objs); + delete objs; + delete percent_scale; + return summary; +} + +char * +dbeGetExpName (int /*dbevindex*/, char *dir_name) +{ + char *ret; + char *warn; + if (col_ctr == NULL) + col_ctr = new Coll_Ctrl (1); // Potential race condition? + if (dir_name != NULL) + { + ret = col_ctr->set_directory (dir_name, &warn); + // note that the warning and error msgs are written to stderr, not returned to caller + if (warn != NULL) + fprintf (stderr, NTXT ("%s"), warn); + if (ret != NULL) + fprintf (stderr, NTXT ("%s"), ret); + } + return dbe_strdup (col_ctr->get_expt ()); +} + +// === CollectDialog HWC info === + +Vector<Vector<char*>*> * +dbeGetHwcSets (int /*dbevindex*/, bool forKernel) +{ + Vector<Vector<char*>*> *list = new Vector<Vector<char*>*>(2); + char * defctrs = hwc_get_default_cntrs2 (forKernel, 1); + Vector<char*> *i18n = new Vector<char*>(1); // User name + Vector<char*> *name = new Vector<char*>(1); // Internal name + if (NULL != defctrs) + { + i18n->store (0, strdup (defctrs)); + name->store (0, strdup (NTXT ("default"))); + } + list->store (0, i18n); + list->store (1, name); + return list; +} + +static Vector<void*> * +dbeGetHwcs (Hwcentry **hwcs) +{ + int sz; + for (sz = 0; hwcs && hwcs[sz]; sz++) + ; + Vector<void*> *list = new Vector<void*>(9); + Vector<char*> *i18n = new Vector<char*>(sz); + Vector<char*> *name = new Vector<char*>(sz); + Vector<char*> *int_name = new Vector<char*>(sz); + Vector<char*> *metric = new Vector<char*>(sz); + Vector<long long> *val = new Vector<long long>(sz); + Vector<int> *timecvt = new Vector<int>(sz); + Vector<int> *memop = new Vector<int>(sz); + Vector<char*> *short_desc = new Vector<char*>(sz); + Vector<Vector<int>*> *reglist_v = new Vector<Vector<int>*>(sz); + Vector<bool> *supportsAttrs = new Vector<bool>(sz); + Vector<bool> *supportsMemspace = new Vector<bool>(sz); + + for (int i = 0; i < sz; i++) + { + Hwcentry *ctr = hwcs[i]; + Vector<int> *registers = new Vector<int>(MAX_PICS); + regno_t *reglist = ctr->reg_list; + for (int k = 0; !REG_LIST_EOL (reglist[k]) && k < MAX_PICS; k++) + registers->store (k, reglist[k]); + + i18n->store (i, dbe_strdup (hwc_i18n_metric (ctr))); + name->store (i, dbe_strdup (ctr->name)); + int_name->store (i, dbe_strdup (ctr->int_name)); + metric->store (i, dbe_strdup (ctr->metric)); + val->store (i, ctr->val); // signed promotion from int + timecvt->store (i, ctr->timecvt); + memop->store (i, ctr->memop); + reglist_v->store (i, registers); + short_desc->store (i, dbe_strdup (ctr->short_desc)); + supportsAttrs->store (i, true); + supportsMemspace->store (i, ABST_MEMSPACE_ENABLED (ctr->memop)); + } + list->store (0, i18n); + list->store (1, name); + list->store (2, int_name); + list->store (3, metric); + list->store (4, val); + list->store (5, timecvt); + list->store (6, memop); + list->store (7, short_desc); + list->store (8, reglist_v); + list->store (9, supportsAttrs); + list->store (10, supportsMemspace); + return list; +} + +Vector<void *> * +dbeGetHwcsAll (int /*dbevindex*/, bool forKernel) +{ + Vector<void*> *list = new Vector<void*>(2); + list->store (0, dbeGetHwcs (hwc_get_std_ctrs (forKernel))); + list->store (1, dbeGetHwcs (hwc_get_raw_ctrs (forKernel))); + return list; +} + +Vector<char*> * +dbeGetHwcHelp (int /*dbevindex*/, bool forKernel) +{ + Vector<char*> *strings = new Vector<char*>(32); + FILE *f = tmpfile (); + hwc_usage_f (forKernel, f, "", 0, 0, 1); // writes to f + fflush (f); + fseek (f, 0, SEEK_SET); +#define MAX_LINE_LEN 2048 + char buff[MAX_LINE_LEN]; + int ii = 0; + while (fgets (buff, MAX_LINE_LEN, f)) + strings->store (ii++, dbe_strdup (buff)); + fclose (f); + return strings; +} + +Vector<char*> * +dbeGetHwcAttrList (int /*dbevindex*/, bool forKernel) +{ + char ** attr_list = hwc_get_attrs (forKernel); // Get Attribute list + int size; + for (size = 0; attr_list && attr_list[size]; size++) + ; + + Vector<char*> *name = new Vector<char*>(size); + for (int i = 0; i < size; i++) + name->store (i, dbe_strdup (attr_list[i])); + return name; +} + +//Get maximum number of simultaneous counters +int +dbeGetHwcMaxConcurrent (int /*dbevindex*/, bool forKernel) +{ + return hwc_get_max_concurrent (forKernel); +} + +// === End CollectDialog HWC info === + + +// Instruction-frequency data +Vector<char*> * +dbeGetIfreqData (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (!dbeSession->is_ifreq_available ()) + return NULL; + int size = dbeSession->nexps (); + if (size == 0) + return NULL; + + // Initialize Java String array + Vector<char*> *list = new Vector<char*>(); + for (int i = 0; i < size; i++) + { + Experiment *exp = dbeSession->get_exp (i); + if (exp->broken || !dbev->get_exp_enable (i) || !exp->ifreqavail) + continue; + // write a header for the experiment + list->append (dbe_sprintf (GTXT ("Instruction frequency data from experiment %s\n\n"), + exp->get_expt_name ())); + // add its instruction frequency messages + char *ifreq = pr_mesgs (exp->fetch_ifreq (), NTXT (""), NTXT ("")); + list->append (ifreq); + } + return list; +} + +// LeakList related methods +// +Vector<void*> * +dbeGetLeakListInfo (int dbevindex, bool leakflag) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + MetricList *origmlist = dbev->get_metric_list (MET_NORMAL); + MetricList *nmlist = new MetricList (origmlist); + if (leakflag) + nmlist->set_metrics (NTXT ("e.heapleakbytes:e.heapleakcnt:name"), true, + dbev->get_derived_metrics ()); + else + nmlist->set_metrics (NTXT ("e.heapallocbytes:e.heapalloccnt:name"), true, + dbev->get_derived_metrics ()); + MetricList *mlist = new MetricList (nmlist); + delete nmlist; + + CStack_data *lam = dbev->get_cstack_data (mlist); + if (lam == NULL || lam->size () == 0) + { + delete lam; + delete mlist; + return NULL; + } + Vector<Vector<Obj>*> *evalue = new Vector<Vector<Obj>*>(lam->size ()); + Vector<Vector<Obj>*> *pcstack = new Vector<Vector<Obj>*>(lam->size ()); + Vector<Vector<Obj>*> *offstack = new Vector<Vector<Obj>*>(lam->size ()); + Vector<Vector<Obj>*> *fpcstack = new Vector<Vector<Obj>*>(lam->size ()); + Vector<Vector<Obj>*> *sumval = new Vector<Vector<Obj>*>(lam->size ()); + + int index; + CStack_data::CStack_item *lae; + Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae) + { + Vector<Obj> *jivals = NULL; + if (lae != NULL) + { + jivals = new Vector<Obj>(4); + jivals->store (0, (Obj) (index + 1)); + jivals->store (1, (Obj) lae->value[1].ll); + jivals->store (2, (Obj) lae->value[0].ll); + jivals->store (3, (Obj) (leakflag ? 1 : 2)); + } + evalue->store (index, jivals); + int snum = lae->stack->size (); + Vector<Obj> *jivals1 = new Vector<Obj>(snum); + Vector<Obj> *jivals2 = new Vector<Obj>(snum); + Vector<Obj> *jivals3 = new Vector<Obj>(snum); + if (lae->stack != NULL) + { + for (int i = lae->stack->size () - 1; i >= 0; i--) + { + DbeInstr *instr = lae->stack->fetch (i); + jivals1->store (i, (Obj) instr); + jivals2->store (i, (Obj) instr->func); + jivals3->store (i, (Obj) instr->addr); + } + } + fpcstack->store (index, jivals1); + pcstack->store (index, jivals2); + offstack->store (index, jivals3); + lae++; + } + Vector<Obj> *jivals4 = new Vector<Obj>(3); + jivals4->store (0, (Obj) lam->size ()); + jivals4->store (1, (Obj) lam->total->value[1].ll); + jivals4->store (2, (Obj) lam->total->value[0].ll); + sumval->store (0, jivals4); + delete lam; + delete mlist; + Vector<void*> *earray = new Vector<void*>(5); + earray->store (0, evalue); + earray->store (1, pcstack); + earray->store (2, offstack); + earray->store (3, fpcstack); + earray->store (4, sumval); + return earray; +} + +// Map timeline address to function instr +// +Obj +dbeGetObject (int dbevindex, Obj sel_func, Obj sel_pc) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (sel_pc) + return sel_pc; + return sel_func; +} + +char * +dbeGetName (int /*dbevindex*/, int exp_id) +// This function's name is not descriptive enough - it returns a string +// containing the full experiment name with path, process name, and PID. +// There are various dbe functions that provide experiment name and experiment +// details, and they should probably be consolidated/refactored. (TBR) +// For another example of similar output formatting, see dbeGetExpName(). +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + if (exp == NULL) + return NULL; + char *buf = + dbe_sprintf (NTXT ("%s [%s, PID %d]"), + exp->get_expt_name (), + exp->utargname != NULL ? exp->utargname : GTXT ("(unknown)"), + exp->getPID ()); + return buf; +} + +Vector<char*> * +dbeGetExpVerboseName (Vector<int> *exp_ids) +{ + int len = exp_ids->size (); + Vector<char*> *list = new Vector<char*>(len); + for (int i = 0; i < len; i++) + { + char * verboseName = dbeGetName (0, exp_ids->fetch (i)); // no strdup() + list->store (i, verboseName); + } + return list; +} + +long long +dbeGetStartTime (int /*dbevindex*/, int exp_id) +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + return exp ? exp->getStartTime () : (long long) 0; +} + +long long +dbeGetRelativeStartTime (int /*dbevindex*/, int exp_id) +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + return exp ? exp->getRelativeStartTime () : (long long) 0; +} + +long long +dbeGetEndTime (int /*dbevindex*/, int exp_id) +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + + // Experiment::getEndTime was initially implemented as + // returning exp->last_event. To preserve the semantics + // new Experiment::getLastEvent() is used here. + return exp ? exp->getLastEvent () : (long long) 0; +} + +int +dbeGetClock (int /*dbevindex*/, int exp_id) +{ + return dbeSession->get_clock (exp_id); +} + +long long +dbeGetWallStartSec (int /*dbevindex*/, int exp_id) +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + return exp ? exp->getWallStartSec () : 0ll; +} + +char * +dbeGetHostname (int /*dbevindex*/, int exp_id) +{ + int id = (exp_id < 0) ? 0 : exp_id; + Experiment *exp = dbeSession->get_exp (id); + return exp ? dbe_strdup (exp->hostname) : NULL; +} + +static DataView * +getTimelinePackets (int dbevindex, int exp_id, int data_id, int entity_prop_id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + const int sortprop_count = 3; + const int sortprops[sortprop_count] = { + PROP_HWCTAG, // aux + entity_prop_id, + PROP_TSTAMP + }; + DataView *packets = dbev->get_filtered_events (exp_id, data_id, + sortprops, sortprop_count); + return packets; +} + +static long +getIdxByVals (DataView * packets, int aux, int entity_prop_val, + uint64_t time, DataView::Relation rel) +{ + const int sortprop_count = 3; + Datum tval[sortprop_count]; + tval[0].setUINT32 (aux); + tval[1].setUINT32 (entity_prop_val); //CPUID, LWPID, THRID are downsized to 32 + tval[2].setUINT64 (time); + long idx = packets->getIdxByVals (tval, rel); + return idx; +} + +static bool +isValidIdx (DataView * packets, int entity_prop_id, + int aux, int entity_prop_val, long idx) +{ + if (idx < 0 || idx >= packets->getSize ()) + return false; + int pkt_aux = packets->getIntValue (PROP_HWCTAG, idx); + if (pkt_aux != aux) + return false; + if (entity_prop_id == PROP_EXPID) + return true; // not a packet property; we know the packet is in this experiment + if (entity_prop_id == PROP_NONE) + return true; // not a packet property; we know the packet is in this experiment + int pkt_ent = packets->getIntValue (entity_prop_id, idx); + if (pkt_ent != entity_prop_val) + return false; + return true; +} + +static bool +hasInvisbleTLEvents (Experiment *exp, VMode view_mode) +{ + if (exp->has_java && view_mode == VMODE_USER) + return true; + return false; +} + +static bool +isVisibleTLEvent (Experiment *exp, VMode view_mode, DataView* packets, long idx) +{ + if (hasInvisbleTLEvents (exp, view_mode)) + { + JThread *jthread = (JThread*) packets->getObjValue (PROP_JTHREAD, idx); + if (jthread == JTHREAD_NONE || (jthread != NULL && jthread->is_system ())) + return false; + } + return true; +} + +static long +getTLVisibleIdxByStepping (Experiment *exp, VMode view_mode, int entity_prop_id, + DataView * packets, int aux, int entity_prop_val, + long idx, long move_count, int direction) +{ + assert (move_count >= 0); + assert (direction == 1 || direction == -1 || direction == 0); + if (direction == 0 /* precise hit required */) + move_count = 0; + do + { + if (!isValidIdx (packets, entity_prop_id, aux, entity_prop_val, idx)) + return -1; + if (isVisibleTLEvent (exp, view_mode, packets, idx)) + { + if (move_count <= 0) + break; + move_count--; + } + if (direction == 0) + return -1; + idx += direction; + } + while (1); + return idx; +} + +static long +getTLVisibleIdxByVals (Experiment *exp, VMode view_mode, int entity_prop_id, + DataView * packets, + int aux, int entity_prop_val, uint64_t time, DataView::Relation rel) +{ + long idx = getIdxByVals (packets, aux, entity_prop_val, time, rel); + if (!hasInvisbleTLEvents (exp, view_mode)) + return idx; + if (idx < 0) + return idx; + if (rel == DataView::REL_EQ) + return -1; // would require bi-directional search... not supported for now + int direction = (rel == DataView::REL_LT || rel == DataView::REL_LTEQ) ? -1 : 1; + idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets, + aux, entity_prop_val, + idx, 0 /* first match */, direction); + return idx; +} + +// In thread mode, the entity name for non Java thread should be the 1st func +// from the current thread's stack. See #4961315 +static char* +getThreadRootFuncName (int, int, int, int, VMode) +{ + return NULL; // until we figure out what we want to show... YXXX +} + +Vector<void*> * +dbeGetEntityProps (int dbevindex) //YXXX TBD, should this be exp-specific? +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Vector<int> *prop_id = new Vector<int>(); + Vector<char*> *prop_name = new Vector<char*>(); + Vector<char*> *prop_uname = new Vector<char*>(); + Vector<char*> *prop_cname = new Vector<char*>(); //must match TLModeCmd vals! + + prop_id->append (PROP_NONE); + prop_name->append (dbe_strdup (GTXT ("NONE"))); + prop_uname->append (dbe_strdup (GTXT ("Unknown"))); + prop_cname->append (dbe_strdup (NTXT ("unknown"))); + + prop_id->append (PROP_LWPID); + prop_name->append (dbe_strdup (GTXT ("LWPID"))); + prop_uname->append (dbe_strdup (GTXT ("LWP"))); + prop_cname->append (dbe_strdup (NTXT ("lwp"))); + + prop_id->append (PROP_THRID); + prop_name->append (dbe_strdup (GTXT ("THRID"))); + prop_uname->append (dbe_strdup (GTXT ("Thread"))); + prop_cname->append (dbe_strdup (NTXT ("thread"))); + + prop_id->append (PROP_CPUID); + prop_name->append (dbe_strdup (GTXT ("CPUID"))); + prop_uname->append (dbe_strdup (GTXT ("CPU"))); + prop_cname->append (dbe_strdup (NTXT ("cpu"))); + + prop_id->append (PROP_EXPID); + prop_name->append (dbe_strdup (GTXT ("EXPID"))); + prop_uname->append (dbe_strdup (GTXT ("Process"))); // placeholder... + // ...until we finalize how to expose user-level Experiments, descendents + prop_cname->append (dbe_strdup (NTXT ("experiment"))); + Vector<void*> *darray = new Vector<void*>(); + darray->store (0, prop_id); + darray->store (1, prop_name); + darray->store (2, prop_uname); + darray->store (3, prop_cname); + return darray; +} + +Vector<void*> * +dbeGetEntities (int dbevindex, int exp_id, int entity_prop_id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Experiment *exp = dbeSession->get_exp (exp_id); + if (exp == NULL) + return NULL; + + // Recognize and skip faketime experiments + if (exp->timelineavail == false) + return NULL; + Vector<Histable*> *tagObjs = exp->getTagObjs ((Prop_type) entity_prop_id); + int total_nelem; + if (tagObjs) + total_nelem = (int) tagObjs->size (); + else + total_nelem = 0; + const VMode view_mode = dbev->get_view_mode (); + bool show_java_threadnames = (entity_prop_id == PROP_THRID && + view_mode != VMODE_MACHINE); + // allocate the structures for the return + Vector<int> *entity_prop_vals = new Vector<int>(); + Vector<char*> *jthr_names = new Vector<char*>(); + Vector<char*> *jthr_g_names = new Vector<char*>(); + Vector<char*> *jthr_p_names = new Vector<char*>(); + + // now walk the tagObjs from the experiment, and check for filtering + for (int tagObjsIdx = 0; tagObjsIdx < total_nelem; tagObjsIdx++) + { + int entity_prop_val = (int) ((Other *) tagObjs->fetch (tagObjsIdx))->tag; + entity_prop_vals->append (entity_prop_val); + char *jname, *jgname, *jpname; + JThread *jthread = NULL; + bool has_java_threadnames = false; + if (show_java_threadnames) + { + jthread = exp->get_jthread (entity_prop_val); + has_java_threadnames = (jthread != JTHREAD_DEFAULT + && jthread != JTHREAD_NONE); + } + if (!has_java_threadnames) + { + jname = jgname = jpname = NULL; + if (entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID) + // if non Java thread, set thread name to the 1st func + // from the current thread's stack. see #4961315 + jname = getThreadRootFuncName (dbevindex, exp_id, entity_prop_id, + entity_prop_val, view_mode); + } + else + { + jname = dbe_strdup (jthread->name); + jgname = dbe_strdup (jthread->group_name); + jpname = dbe_strdup (jthread->parent_name); + } + jthr_names->append (jname); + jthr_g_names->append (jgname); + jthr_p_names->append (jpname); + } + Vector<char*> *entity_prop_name_v = new Vector<char*>(); + char* entity_prop_name = dbeSession->getPropName (entity_prop_id); + entity_prop_name_v->append (entity_prop_name); + Vector<void*> *darray = new Vector<void*>(5); + darray->store (0, entity_prop_vals); + darray->store (1, jthr_names); + darray->store (2, jthr_g_names); + darray->store (3, jthr_p_names); + darray->store (4, entity_prop_name_v); // vector only has 1 element + return darray; +} + +// TBR: dbeGetEntities() can be set to private now that we have dbeGetEntitiesV2() +Vector<void*> * +dbeGetEntitiesV2 (int dbevindex, Vector<int> *exp_ids, int entity_prop_id) +{ + int sz = exp_ids->size (); + Vector<void*> *res = new Vector<void*>(sz); + for (int ii = 0; ii < sz; ii++) + { + int expIdx = exp_ids->fetch (ii); + Vector<void*>* ents = dbeGetEntities (dbevindex, expIdx, entity_prop_id); + res->store (ii, ents); + } + return res; +} + +//YXXX old-tl packets still used for details +static Vector<void*> * +getTLDetailValues (int dbevindex, Experiment * exp, int data_id, + VMode view_mode, DataView *packets, long idx) +{ + Vector<long long> *value = new Vector<long long>(15); + long i = idx; + if (data_id == DATA_SAMPLE || data_id == DATA_GCEVENT) + { + //YXXX DATA_SAMPLE not handled but could be. + } + Obj stack = (unsigned long) getStack (view_mode, packets, i); + Vector<Obj> *funcs = stack ? dbeGetStackFunctions (dbevindex, stack) : NULL; + Function *func = (Function*) + getStackPC (0, view_mode, packets, i)->convertto (Histable::FUNCTION); + // Fill common data + value->store (0, packets->getIntValue (PROP_LWPID, i)); + value->store (1, packets->getIntValue (PROP_THRID, i)); + value->store (2, packets->getIntValue (PROP_CPUID, i)); + value->store (3, packets->getLongValue (PROP_TSTAMP, i)); + value->store (4, (unsigned long) stack); + value->store (5, (unsigned long) func); + + // Fill specific data + switch (data_id) + { + case DATA_CLOCK: + value->store (6, packets->getIntValue (PROP_MSTATE, i)); + { + hrtime_t interval = exp->get_params ()->ptimer_usec * 1000LL // nanoseconds + * packets->getLongValue (PROP_NTICK, i); + value->store (7, interval); + } + value->store (8, packets->getIntValue (PROP_OMPSTATE, i)); + value->store (9, packets->getLongValue (PROP_EVT_TIME, i)); // visual duration + break; + case DATA_SYNCH: + value->store (6, packets->getLongValue (PROP_EVT_TIME, i)); + value->store (7, packets->getLongValue (PROP_SOBJ, i)); + break; + case DATA_HWC: + value->store (6, packets->getLongValue (PROP_HWCINT, i)); + value->store (7, packets->getLongValue (PROP_VADDR, i)); // data vaddr + value->store (8, packets->getLongValue (PROP_PADDR, i)); // data paddr + value->store (9, packets->getLongValue (PROP_VIRTPC, i)); // pc paddr + value->store (10, packets->getLongValue (PROP_PHYSPC, i)); // pc vaddr + break; + case DATA_RACE: + value->store (6, packets->getIntValue (PROP_RTYPE, i)); + value->store (7, packets->getIntValue (PROP_RID, i)); + value->store (8, packets->getLongValue (PROP_RVADDR, i)); + break; + case DATA_DLCK: + value->store (6, packets->getIntValue (PROP_DTYPE, i)); + value->store (7, packets->getIntValue (PROP_DLTYPE, i)); + value->store (8, packets->getIntValue (PROP_DID, i)); + value->store (9, packets->getLongValue (PROP_DVADDR, i)); + break; + case DATA_HEAP: + case DATA_HEAPSZ: + value->store (6, packets->getIntValue (PROP_HTYPE, i)); + value->store (7, packets->getLongValue (PROP_HSIZE, i)); + value->store (8, packets->getLongValue (PROP_HVADDR, i)); + value->store (9, packets->getLongValue (PROP_HOVADDR, i)); + value->store (10, packets->getLongValue (PROP_HLEAKED, i)); + value->store (11, packets->getLongValue (PROP_HFREED, i)); + value->store (12, packets->getLongValue (PROP_HCUR_ALLOCS, i)); // signed int64_t + value->store (13, packets->getLongValue (PROP_HCUR_LEAKS, i)); + break; + case DATA_IOTRACE: + value->store (6, packets->getIntValue (PROP_IOTYPE, i)); + value->store (7, packets->getIntValue (PROP_IOFD, i)); + value->store (8, packets->getLongValue (PROP_IONBYTE, i)); + value->store (9, packets->getLongValue (PROP_EVT_TIME, i)); + value->store (10, packets->getIntValue (PROP_IOVFD, i)); + break; + } + Vector<void*> *result = new Vector<void*>(5); + result->store (0, value); + result->store (1, funcs); // Histable::Function* + result->store (2, funcs ? dbeGetFuncNames (dbevindex, funcs) : 0); // formatted func names + result->store (3, stack ? dbeGetStackPCs (dbevindex, stack) : 0); // Histable::DbeInstr* + result->store (4, stack ? dbeGetStackNames (dbevindex, stack) : 0); // formatted pc names + return result; +} + +Vector<void*> * +dbeGetTLDetails (int dbevindex, int exp_id, int data_id, + int entity_prop_id, Obj event_id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Experiment *exp = dbeSession->get_exp (exp_id < 0 ? 0 : exp_id); + if (exp == NULL) + return NULL; + DataView *packets = + getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id); + if (!packets) + return NULL; + + VMode view_mode = dbev->get_view_mode (); + long idx = (long) event_id; + Vector<void*> *values = getTLDetailValues (dbevindex, exp, data_id, view_mode, packets, idx); + return values; +} + +Vector<Obj> * +dbeGetStackFunctions (int dbevindex, Obj stack) +{ + Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack); + if (instrs == NULL) + return NULL; + int stsize = instrs->size (); + Vector<Obj> *jivals = new Vector<Obj>(stsize); + for (int i = 0; i < stsize; i++) + { + Histable *obj = (Histable*) instrs->fetch (i); + // if ( obj->get_type() != Histable::LINE ) {//YXXX what is this? + // Remove the above check: why not do this conversion for lines - + // otherwise filtering in timeline by function stack in omp user mode is broken + obj = obj->convertto (Histable::FUNCTION); + jivals->store (i, (Obj) obj); + } + delete instrs; + return jivals; +} + +Vector<void*> * +dbeGetStacksFunctions (int dbevindex, Vector<Obj> *stacks) +{ + long sz = stacks->size (); + Vector<void*> *res = new Vector<void*>(sz); + for (int ii = 0; ii < sz; ii++) + { + Obj stack = stacks->fetch (ii); + Vector<Obj> *jivals = dbeGetStackFunctions (dbevindex, stack); + res->store (ii, jivals); + } + return res; +} + +Vector<Obj> * +dbeGetStackPCs (int dbevindex, Obj stack) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (stack == 0) + return NULL; + + bool show_all = dbev->isShowAll (); + Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stack, !show_all); + int stsize = instrs->size (); + int istart = 0; + bool showAll = dbev->isShowAll (); + for (int i = 0; i < stsize - 1; i++) + { + Function *func = (Function*) instrs->fetch (i)->convertto (Histable::FUNCTION); + int ix = func->module->loadobject->seg_idx; + if (showAll && dbev->get_lo_expand (ix) == LIBEX_API) + // truncate stack here: LIBRARY_VISIBILITY if we are using API only but no hide + istart = i; + } + stsize = stsize - istart; + Vector<Obj> *jlvals = new Vector<Obj>(stsize); + for (int i = 0; i < stsize; i++) + { + Histable *instr = instrs->fetch (i + istart); + jlvals->store (i, (Obj) instr); + } + delete instrs; + return jlvals; +} + +Vector<char*> * +dbeGetStackNames (int dbevindex, Obj stack) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack); + if (instrs == NULL) + return NULL; + int stsize = instrs->size (); + Vector<char*> *list = new Vector<char*>(stsize); + bool showAll = dbev->isShowAll (); + for (int i = 0; i < stsize; i++) + { + Histable* instr = (Histable*) instrs->fetch (i); + if (!showAll) + { + // LIBRARY_VISIBILITY + Function *func = (Function*) instr->convertto (Histable::FUNCTION); + LoadObject *lo = ((Function*) func)->module->loadobject; + if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE) + { + list->store (i, dbe_strdup (lo->get_name ())); + continue; + } + } + list->store (i, dbe_strdup (instr->get_name (dbev->get_name_format ()))); + } + delete instrs; + return list; +} + +Vector<void*> * +dbeGetSamples (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx) +{ + DataView * packets = + getTimelinePackets (dbevindex, exp_id, DATA_SAMPLE, PROP_EXPID); + if (packets == NULL || packets->getSize () == 0) + return NULL; + long lo; + if (lo_idx < 0) + lo = 0; + else + lo = (long) lo_idx; + + long long max = packets->getSize () - 1; + long hi; + if (hi_idx < 0 || hi_idx > max) + hi = (long) max; + else + hi = (long) hi_idx; + + Vector<Vector<long long>*> *sarray = new Vector<Vector<long long>*>; + Vector<long long>* starts = new Vector<long long>; + Vector<long long>* ends = new Vector<long long>; + Vector<long long>* rtimes = new Vector<long long>; + Vector<char*> *startNames = new Vector<char*>; + Vector<char*> *endNames = new Vector<char*>; + Vector<int> *sampId = new Vector<int>; + + for (long index = lo; index <= hi; index++) + { + Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index); + PrUsage *prusage = sample->get_usage (); + if (prusage == NULL) + prusage = new PrUsage; + Vector<long long> *states = prusage->getMstateValues (); + sarray->append (states); + starts->append (sample->get_start_time ()); + ends->append (sample->get_end_time ()); + rtimes->append (prusage->pr_rtime); + startNames->append (dbe_strdup (sample->get_start_label ())); + endNames->append (dbe_strdup (sample->get_end_label ())); + sampId->append (sample->get_number ()); + } + Vector<void *> *res = new Vector<void*>(6); + res->store (0, sarray); + res->store (1, starts); + res->store (2, ends); + res->store (3, rtimes); + res->store (4, startNames); + res->store (5, endNames); + res->store (6, sampId); + return res; +} + +Vector<void*> * +dbeGetGCEvents (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx) +{ + DataView *packets = + getTimelinePackets (dbevindex, exp_id, DATA_GCEVENT, PROP_EXPID); + if (packets == NULL || packets->getSize () == 0) + return NULL; + + long lo; + if (lo_idx < 0) + lo = 0; + else + lo = (long) lo_idx; + long long max = packets->getSize () - 1; + long hi; + if (hi_idx < 0 || hi_idx > max) + hi = (long) max; + else + hi = (long) hi_idx; + + Vector<long long>* starts = new Vector<long long>; + Vector<long long>* ends = new Vector<long long>; + Vector<int> *eventId = new Vector<int>; + for (long index = lo; index <= hi; index++) + { + GCEvent *gcevent = (GCEvent*) packets->getObjValue (PROP_GCEVENTOBJ, index); + if (gcevent) + { + starts->append (gcevent->start); + ends->append (gcevent->end); + eventId->append (gcevent->id); + } + } + Vector<void *> *res = new Vector<void*>(3); + res->store (0, starts); + res->store (1, ends); + res->store (2, eventId); + return res; +} + +Vector<Vector<char*>*>* +dbeGetIOStatistics (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + Hist_data *hist_data; + Hist_data::HistItem *hi; + FileData *fDataTotal; + + hist_data = dbev->iofile_data; + if (hist_data == NULL) + return NULL; + hi = hist_data->fetch (0); + fDataTotal = (FileData*) hi->obj; + + Vector<char*> *writeStat = new Vector<char*>; + Vector<char*> *readStat = new Vector<char*>; + Vector<char*> *otherStat = new Vector<char*>; + Vector<char*> *errorStat = new Vector<char*>; + + writeStat->append (dbe_strdup (GTXT ("Write Statistics"))); + readStat->append (dbe_strdup (GTXT ("Read Statistics"))); + otherStat->append (dbe_strdup (GTXT ("Other I/O Statistics"))); + errorStat->append (dbe_strdup (GTXT ("I/O Error Statistics"))); + + StringBuilder sb; + if (fDataTotal->getWriteCnt () > 0) + { + if (fDataTotal->getW0KB1KBCnt () > 0) + { + sb.sprintf (GTXT ("0KB - 1KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW0KB1KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW1KB8KBCnt () > 0) + { + sb.sprintf (GTXT ("1KB - 8KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW1KB8KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW8KB32KBCnt () > 0) + { + sb.sprintf (GTXT ("8KB - 32KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW8KB32KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW32KB128KBCnt () > 0) + { + sb.sprintf (GTXT ("32KB - 128KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW32KB128KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW128KB256KBCnt () > 0) + { + sb.sprintf (GTXT ("128KB - 256KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW128KB256KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW256KB512KBCnt () > 0) + { + sb.sprintf (GTXT ("256KB - 512KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW256KB512KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW512KB1000KBCnt () > 0) + { + sb.sprintf (GTXT ("512KB - 1000KB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW512KB1000KBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW1000KB10MBCnt () > 0) + { + sb.sprintf (GTXT ("1000KB - 10MB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW1000KB10MBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW10MB100MBCnt () > 0) + { + sb.sprintf (GTXT ("10MB - 100MB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW10MB100MBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW100MB1GBCnt () > 0) + { + sb.sprintf (GTXT ("100MB - 1GB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW100MB1GBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW1GB10GBCnt () > 0) + { + sb.sprintf (GTXT ("1GB - 10GB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW1GB10GBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW10GB100GBCnt () > 0) + { + sb.sprintf (GTXT ("10GB - 100GB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW10GB100GBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW100GB1TBCnt () > 0) + { + sb.sprintf (GTXT ("100GB - 1TB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW100GB1TBCnt ()); + writeStat->append (sb.toString ()); + } + if (fDataTotal->getW1TB10TBCnt () > 0) + { + sb.sprintf (GTXT ("1TB - 10TB")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getW1TB10TBCnt ()); + writeStat->append (sb.toString ()); + } + + sb.sprintf (GTXT ("Longest write")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC)); + writeStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Smallest write bytes")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWSmallestBytes ())); + writeStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Largest write bytes")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWLargestBytes ())); + writeStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total time")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getWriteTime () / (double) NANOSEC)); + writeStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total calls")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWriteCnt ())); + writeStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total bytes")); + writeStat->append (sb.toString ()); + sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getWriteBytes ())); + writeStat->append (sb.toString ()); + } + + if (fDataTotal->getReadCnt () > 0) + { + if (fDataTotal->getR0KB1KBCnt () > 0) + { + sb.sprintf (GTXT ("0KB - 1KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR0KB1KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR1KB8KBCnt () > 0) + { + sb.sprintf (GTXT ("1KB - 8KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR1KB8KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR8KB32KBCnt () > 0) + { + sb.sprintf (GTXT ("8KB - 32KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR8KB32KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR32KB128KBCnt () > 0) + { + sb.sprintf (GTXT ("32KB - 128KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR32KB128KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR128KB256KBCnt () > 0) + { + sb.sprintf (GTXT ("128KB - 256KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR128KB256KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR256KB512KBCnt () > 0) + { + sb.sprintf (GTXT ("256KB - 512KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR256KB512KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR512KB1000KBCnt () > 0) + { + sb.sprintf (GTXT ("512KB - 1000KB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR512KB1000KBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR1000KB10MBCnt () > 0) + { + sb.sprintf (GTXT ("1000KB - 10MB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR1000KB10MBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR10MB100MBCnt () > 0) + { + sb.sprintf (GTXT ("10MB - 100MB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR10MB100MBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR100MB1GBCnt () > 0) + { + sb.sprintf (GTXT ("100MB - 1GB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR100MB1GBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR1GB10GBCnt () > 0) + { + sb.sprintf (GTXT ("1GB - 10GB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR1GB10GBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR10GB100GBCnt () > 0) + { + sb.sprintf (GTXT ("10GB - 100GB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR10GB100GBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR100GB1TBCnt () > 0) + { + sb.sprintf (GTXT ("100GB - 1TB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR100GB1TBCnt ()); + readStat->append (sb.toString ()); + } + if (fDataTotal->getR1TB10TBCnt () > 0) + { + sb.sprintf (GTXT ("1TB - 10TB")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), fDataTotal->getR1TB10TBCnt ()); + readStat->append (sb.toString ()); + } + + sb.sprintf (GTXT ("Longest read")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC)); + readStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Smallest read bytes")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRSmallestBytes ())); + readStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Largest read bytes")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRLargestBytes ())); + readStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total time")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getReadTime () / (double) NANOSEC)); + readStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total calls")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getReadCnt ())); + readStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total bytes")); + readStat->append (sb.toString ()); + sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getReadBytes ())); + readStat->append (sb.toString ()); + } + + if (fDataTotal->getOtherCnt () > 0) + { + sb.sprintf (GTXT ("Total time")); + otherStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getOtherTime () / (double) NANOSEC)); + otherStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total calls")); + otherStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getOtherCnt ())); + otherStat->append (sb.toString ()); + } + + if (fDataTotal->getErrorCnt () > 0) + { + sb.sprintf (GTXT ("Total time")); + errorStat->append (sb.toString ()); + sb.sprintf (NTXT ("%.6f (secs.)"), + (double) (fDataTotal->getErrorTime () / (double) NANOSEC)); + errorStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total calls")); + errorStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getErrorCnt ())); + errorStat->append (sb.toString ()); + } + Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(4); + statisticsData->store (0, writeStat); + statisticsData->store (1, readStat); + statisticsData->store (2, otherStat); + statisticsData->store (3, errorStat); + return statisticsData; +} + +Vector<Vector<char*>*>* +dbeGetHeapStatistics (int dbevindex) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + Hist_data *hist_data; + Hist_data::HistItem *hi; + HeapData *hDataTotal; + hist_data = dbev->heapcs_data; + if (hist_data == NULL) + return NULL; + + hi = hist_data->fetch (0); + hDataTotal = (HeapData*) hi->obj; + Vector<char*> *memoryUsage = new Vector<char*>; + Vector<char*> *allocStat = new Vector<char*>; + Vector<char*> *leakStat = new Vector<char*>; + + memoryUsage->append (dbe_strdup (GTXT ("Process With Highest Peak Memory Usage"))); + allocStat->append (dbe_strdup (GTXT ("Memory Allocations Statistics"))); + leakStat->append (dbe_strdup (GTXT ("Memory Leaks Statistics"))); + StringBuilder sb; + if (hDataTotal->getPeakMemUsage () > 0) + { + sb.sprintf (GTXT ("Heap size bytes")); + memoryUsage->append (sb.toString ()); + sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getPeakMemUsage ())); + memoryUsage->append (sb.toString ()); + + sb.sprintf (GTXT ("Experiment Id")); + memoryUsage->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getUserExpId ())); + memoryUsage->append (sb.toString ()); + + sb.sprintf (GTXT ("Process Id")); + memoryUsage->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getPid ())); + memoryUsage->append (sb.toString ()); + + Vector<hrtime_t> *pTimestamps; + pTimestamps = hDataTotal->getPeakTimestamps (); + if (pTimestamps != NULL) + { + for (int i = 0; i < pTimestamps->size (); i++) + { + sb.sprintf (GTXT ("Time of peak")); + memoryUsage->append (sb.toString ()); + sb.sprintf (NTXT ("%.3f (secs.)"), (double) (pTimestamps->fetch (i) / (double) NANOSEC)); + memoryUsage->append (sb.toString ()); + } + } + } + + if (hDataTotal->getAllocCnt () > 0) + { + if (hDataTotal->getA0KB1KBCnt () > 0) + { + sb.sprintf (GTXT ("0KB - 1KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA0KB1KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA1KB8KBCnt () > 0) + { + sb.sprintf (GTXT ("1KB - 8KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA1KB8KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA8KB32KBCnt () > 0) + { + sb.sprintf (GTXT ("8KB - 32KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA8KB32KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA32KB128KBCnt () > 0) + { + sb.sprintf (GTXT ("32KB - 128KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA32KB128KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA128KB256KBCnt () > 0) + { + sb.sprintf (GTXT ("128KB - 256KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA128KB256KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA256KB512KBCnt () > 0) + { + sb.sprintf (GTXT ("256KB - 512KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA256KB512KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA512KB1000KBCnt () > 0) + { + sb.sprintf (GTXT ("512KB - 1000KB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA512KB1000KBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA1000KB10MBCnt () > 0) + { + sb.sprintf (GTXT ("1000KB - 10MB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA1000KB10MBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA10MB100MBCnt () > 0) + { + sb.sprintf (GTXT ("10MB - 100MB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA10MB100MBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA100MB1GBCnt () > 0) + { + sb.sprintf (GTXT ("100MB - 1GB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA100MB1GBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA1GB10GBCnt () > 0) + { + sb.sprintf (GTXT ("1GB - 10GB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA1GB10GBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA10GB100GBCnt () > 0) + { + sb.sprintf (GTXT ("10GB - 100GB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA10GB100GBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA100GB1TBCnt () > 0) + { + sb.sprintf (GTXT ("100GB - 1TB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA100GB1TBCnt ()); + allocStat->append (sb.toString ()); + } + if (hDataTotal->getA1TB10TBCnt () > 0) + { + sb.sprintf (GTXT ("1TB - 10TB")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getA1TB10TBCnt ()); + allocStat->append (sb.toString ()); + } + + sb.sprintf (GTXT ("Smallest allocation bytes")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getASmallestBytes ())); + allocStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Largest allocation bytes")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getALargestBytes ())); + allocStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total allocations")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getAllocCnt ())); + allocStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total bytes")); + allocStat->append (sb.toString ()); + sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getAllocBytes ())); + allocStat->append (sb.toString ()); + } + + if (hDataTotal->getLeakCnt () > 0) + { + if (hDataTotal->getL0KB1KBCnt () > 0) + { + sb.sprintf (GTXT ("0KB - 1KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL0KB1KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL1KB8KBCnt () > 0) + { + sb.sprintf (GTXT ("1KB - 8KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL1KB8KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL8KB32KBCnt () > 0) + { + sb.sprintf (GTXT ("8KB - 32KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL8KB32KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL32KB128KBCnt () > 0) + { + sb.sprintf (GTXT ("32KB - 128KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL32KB128KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL128KB256KBCnt () > 0) + { + sb.sprintf (GTXT ("128KB - 256KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL128KB256KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL256KB512KBCnt () > 0) + { + sb.sprintf (GTXT ("256KB - 512KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL256KB512KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL512KB1000KBCnt () > 0) + { + sb.sprintf (GTXT ("512KB - 1000KB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL512KB1000KBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL1000KB10MBCnt () > 0) + { + sb.sprintf (GTXT ("1000KB - 10MB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL1000KB10MBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL10MB100MBCnt () > 0) + { + sb.sprintf (GTXT ("10MB - 100MB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL10MB100MBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL100MB1GBCnt () > 0) + { + sb.sprintf (GTXT ("100MB - 1GB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL100MB1GBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL1GB10GBCnt () > 0) + { + sb.sprintf (GTXT ("1GB - 10GB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL1GB10GBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL10GB100GBCnt () > 0) + { + sb.sprintf (GTXT ("10GB - 100GB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL10GB100GBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL100GB1TBCnt () > 0) + { + sb.sprintf (GTXT ("100GB - 1TB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL100GB1TBCnt ()); + leakStat->append (sb.toString ()); + } + if (hDataTotal->getL1TB10TBCnt () > 0) + { + sb.sprintf (GTXT ("1TB - 10TB")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), hDataTotal->getL1TB10TBCnt ()); + leakStat->append (sb.toString ()); + } + + sb.sprintf (GTXT ("Smallest leaked bytes")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLSmallestBytes ())); + leakStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Largest leaked bytes")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLLargestBytes ())); + leakStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total leaked")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLeakCnt ())); + leakStat->append (sb.toString ()); + + sb.sprintf (GTXT ("Total bytes")); + leakStat->append (sb.toString ()); + sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getLeakBytes ())); + leakStat->append (sb.toString ()); + } + Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(3); + statisticsData->store (0, memoryUsage); + statisticsData->store (1, allocStat); + statisticsData->store (2, leakStat); + return statisticsData; +} + +Vector<char*> * +dbeGetFuncNames (int dbevindex, Vector<Obj> *funcs) +{ + int len = funcs->size (); + Vector<char*> *list = new Vector<char*>(len); + for (int i = 0; i < len; i++) + list->store (i, dbeGetFuncName (dbevindex, funcs->fetch (i))); // no strdup() + return list; +} + +Vector<char*> * +dbeGetObjNamesV2 (int dbevindex, Vector<uint64_t> *ids) +{ + int len = ids->size (); + Vector<char*> *list = new Vector<char*>(len); + for (int i = 0; i < len; i++) + list->store (i, dbeGetObjNameV2 (dbevindex, ids->fetch (i))); // no strdup() + return list; +} + +char * +dbeGetFuncName (int dbevindex, Obj func) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (func == 0) + return NULL; + char *fname; + fname = ((Histable *) func)->get_name (dbev->get_name_format ()); + return fname ? dbe_strdup (fname) : NULL; +} + +Vector<uint64_t> * +dbeGetFuncIds (int dbevindex, Vector<Obj> *funcs) +{ + int len = funcs->size (); + Vector<uint64_t> *list = new Vector<uint64_t>(len); + for (int i = 0; i < len; i++) + list->store (i, dbeGetFuncId (dbevindex, funcs->fetch (i))); + return list; +} + +uint64_t +dbeGetFuncId (int dbevindex, Obj func) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + if (func == 0) + return 0; + uint64_t id = ((Histable *) func)->id; + return id; +} + +char * +dbeGetObjNameV2 (int dbevindex, uint64_t id) +{ + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Histable *obj = dbeSession->findObjectById (id); + if (obj == NULL) + return NULL; + char *fname = obj->get_name (dbev->get_name_format ()); + return fname ? dbe_strdup (fname) : NULL; +} + +char * +dbeGetDataspaceTypeDesc (int /*dbevindex*/, Obj stack) +{ + if (stack == 0) + return NULL; + Histable *hist = CallStack::getStackPC ((void *) stack, 0); + DbeInstr *instr; + Histable::Type type = hist->get_type (); + if (type != Histable::INSTR) + return NULL; + else + instr = (DbeInstr *) hist; + char *descriptor = instr->get_descriptor (); + return descriptor ? dbe_strdup (descriptor) : NULL; +} + +Vector<void*> * +dbeGetDataDescriptorsV2 (int exp_id) +{ + Experiment *exp = dbeSession->get_exp (exp_id); + if (exp == NULL) + return NULL; + Vector<int> *dataId = new Vector<int>; + Vector<char*> *dataName = new Vector<char*>; + Vector<char*> *dataUName = new Vector<char*>; + Vector<int> *auxProp = new Vector<int>; + Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors (); + for (int i = 0; i < ddscr->size (); i++) + { + DataDescriptor *dataDscr = ddscr->fetch (i); + if (dataDscr->getFlags () & DDFLAG_NOSHOW) + continue; + int data_id = dataDscr->getId (); + int aux_prop_id = (data_id == DATA_HWC) ? PROP_HWCTAG : PROP_NONE; + dataId->append (data_id); + dataName->append (strdup (dataDscr->getName ())); + dataUName->append (strdup (dataDscr->getUName ())); + auxProp->append (aux_prop_id); + } + delete ddscr; + Vector<void*> *res = new Vector<void*>(3); + res->store (0, dataId); + res->store (1, dataName); + res->store (2, dataUName); + res->store (3, auxProp); + return res; +} + +Vector<void*> * +dbeGetDataPropertiesV2 (int exp_id, int data_id) +{ + Experiment *exp = dbeSession->get_exp (exp_id); + if (exp == NULL) + return NULL; + DataDescriptor *dataDscr = exp->get_raw_events (data_id); + if (dataDscr == NULL) + return NULL; + Vector<PropDescr*> *props = dataDscr->getProps (); + Vector<int> *propId = new Vector<int>(props->size ()); + Vector<char*> *propUName = new Vector<char*>(props->size ()); + Vector<int> *propTypeId = new Vector<int>(props->size ()); + Vector<char*> *propTypeName = new Vector<char*>(props->size ()); + Vector<int> *propFlags = new Vector<int>(props->size ()); + Vector<char*> *propName = new Vector<char*>(props->size ()); + Vector<void*> *propStateNames = new Vector<void*>(props->size ()); + Vector<void*> *propStateUNames = new Vector<void*>(props->size ()); + + for (int i = 0; i < props->size (); i++) + { + PropDescr *prop = props->fetch (i); + char *pname = prop->name; + if (pname == NULL) + pname = NTXT (""); + char *uname = prop->uname; + if (uname == NULL) + uname = pname; + int vtypeNum = prop->vtype; + if (vtypeNum < 0 || vtypeNum >= TYPE_LAST) + vtypeNum = TYPE_NONE; + const char * vtypeNames[] = VTYPE_TYPE_NAMES; + const char *vtype = vtypeNames[prop->vtype]; + Vector<char*> *stateNames = NULL; + Vector<char*> *stateUNames = NULL; + int nStates = prop->getMaxState (); + if (nStates > 0) + { + stateNames = new Vector<char*>(nStates); + stateUNames = new Vector<char*>(nStates); + for (int kk = 0; kk < nStates; kk++) + { + const char * stateName = prop->getStateName (kk); + stateNames->store (kk, dbe_strdup (stateName)); + const char * Uname = prop->getStateUName (kk); + stateUNames->store (kk, dbe_strdup (Uname)); + } + } + propId->store (i, prop->propID); + propUName->store (i, dbe_strdup (uname)); + propTypeId->store (i, prop->vtype); + propTypeName->store (i, dbe_strdup (vtype)); + propFlags->store (i, prop->flags); + propName->store (i, dbe_strdup (pname)); + propStateNames->store (i, stateNames); + propStateUNames->store (i, stateUNames); + } + Vector<void*> *res = new Vector<void*>(7); + res->store (0, propId); + res->store (1, propUName); + res->store (2, propTypeId); + res->store (3, propTypeName); + res->store (4, propFlags); + res->store (5, propName); + res->store (6, propStateNames); + res->store (7, propStateUNames); + return res; +} + +Vector<void *> * +dbeGetExperimentTimeInfo (Vector<int> *exp_ids) +{ + int sz = exp_ids->size (); + Vector<long long> *offset_time = new Vector<long long> (sz); + Vector<long long> *start_time = new Vector<long long> (sz); + Vector<long long> *end_time = new Vector<long long> (sz); + Vector<long long> *start_wall_sec = new Vector<long long> (sz); + Vector<char* > *hostname = new Vector<char*> (sz); + Vector<int> *cpu_freq = new Vector<int> (sz); + for (int ii = 0; ii < sz; ii++) + { + int expIdx = exp_ids->fetch (ii); + { // update end_time by forcing fetch of experiment data + // workaround until dbeGetEndTime() is more robust + int id = (expIdx < 0) ? 0 : expIdx; + Experiment *exp = dbeSession->get_exp (id); + if (exp) + { + Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors (); + delete ddscr; + } + } + offset_time->store (ii, dbeGetRelativeStartTime (0, expIdx)); + start_time->store (ii, dbeGetStartTime (0, expIdx)); + end_time->store (ii, dbeGetEndTime (0, expIdx)); + start_wall_sec->store (ii, dbeGetWallStartSec (0, expIdx)); + hostname->store (ii, dbeGetHostname (0, expIdx)); + cpu_freq->store (ii, dbeGetClock (0, expIdx)); + } + Vector<void*> *res = new Vector<void*>(4); + res->store (0, offset_time); + res->store (1, start_time); + res->store (2, end_time); + res->store (3, start_wall_sec); + res->store (4, hostname); + res->store (5, cpu_freq); + return res; +} + +Vector<void *> * +dbeGetExperimentDataDescriptors (Vector<int> *exp_ids) +{ + int sz = exp_ids->size (); + Vector<void*> *exp_dscr_info = new Vector<void*> (sz); + Vector<void*> *exp_dscr_props = new Vector<void*> (sz); + + for (int ii = 0; ii < sz; ii++) + { + int expIdx = exp_ids->fetch (ii); + Vector<void*> *ddscrInfo = dbeGetDataDescriptorsV2 (expIdx); + Vector<void*> *ddscrProps = new Vector<void*> (); // one entry per ddscrInfo + if (ddscrInfo) + { + Vector<int> *dataId = (Vector<int>*)ddscrInfo->fetch (0); + if (dataId) + { + // loop thru data descriptors + int ndata = dataId->size (); + for (int j = 0; j < ndata; ++j) + { + Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j)); + ddscrProps->store (j, props); + } + } + } + exp_dscr_info->store (ii, ddscrInfo); + exp_dscr_props->store (ii, ddscrProps); + } + Vector<void*> *res = new Vector<void*>(2); + res->store (0, exp_dscr_info); + res->store (1, exp_dscr_props); + return res; +} + +static Vector<void *> * +dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta, + int numDeltas, DataView*packets, + Vector<long> *representativeEvents, bool showDuration); + +static bool +dbeHasTLData (int dbevindex, int exp_id, int data_id, int entity_prop_id, + int entity_prop_value, int aux) +{ + DataView *packets = + getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id); + if (!packets || packets->getSize () == 0) + return false; + long start_ind = getIdxByVals (packets, aux, entity_prop_value, + 0, DataView::REL_GTEQ); // time >= 0 + if (start_ind < 0) + return false; + + DbeView *dbev = dbeSession->getView (dbevindex); + VMode view_mode = dbev->get_view_mode (); + Experiment *exp = dbeSession->get_exp (exp_id); + if (!hasInvisbleTLEvents (exp, view_mode)) + return true; // all events are visible, no further checking required + long end_ind = getIdxByVals (packets, aux, entity_prop_value, + MAX_TIME, DataView::REL_LTEQ); + for (long ii = start_ind; ii <= end_ind; ii++) + { + if (!isVisibleTLEvent (exp, view_mode, packets, ii)) + continue; + return true; // first visible packet => has data + } + return false; +} + +Vector<bool> * +dbeHasTLData (int dbev_index, Vector<int> *exp_ids, Vector<int> *data_ids, + Vector<int> *entity_prop_ids, // LWP,CPU,THR, etc + Vector<int> *entity_prop_values, Vector<int> *auxs) +{ + DbeView *dbev = dbeSession->getView (dbev_index); + if (!dbev->isShowAll () && (dbev->isShowHideChanged () + || dbev->isNewViewMode ())) + { + // LIBRARY_VISIBILITY + dbev->resetAndConstructShowHideStacks (); + if (dbev->isNewViewMode ()) + dbev->resetNewViewMode (); + if (dbev->isShowHideChanged ()) + dbev->resetShowHideChanged (); + } + + int sz = exp_ids->size (); + Vector<bool> *hasVec = new Vector<bool>(sz); + for (int ii = 0; ii < sz; ii++) + { + bool hasData = dbeHasTLData (dbev_index, exp_ids->fetch (ii), + data_ids->fetch (ii), + entity_prop_ids->fetch (ii), + entity_prop_values->fetch (ii), + auxs->fetch (ii)); + hasVec->store (ii, hasData); + } + return hasVec; +} + +/* + * dbeGetTLData implements: + * FROM data_id + * DURATION >= delta AND ( start_ts <= TSTAMP < start_ts+num*delta OR + * start_ts <= TSTAMP-DURATION < start_ts+num*delta ) + * OR + * FAIR( DURATION < delta AND ( start_ts <= TSTAMP < start_ts+num*delta ) ) + * WHERE lfilter + */ + +Vector<void *> * +dbeGetTLData ( + int dbevindex, + int exp_id, + int data_id, // DATA_* + int entity_prop_id, // Show PROP_LWPID, PROP_CPUID, PROP_THRID, PROP_EXPID, or N/A + int entity_prop_value, // which LWPID, CPUID, THRID, EXPID for this request + int aux, + hrtime_t param_start_ts, + hrtime_t param_delta, + int param_numDeltas, + bool getRepresentatives, // fetch TL representatives + Vector<char *> *chartProps) // calculate sums for these property vals +{ + const hrtime_t start_ts = param_start_ts; + const hrtime_t delta = param_delta; + const int numDeltas = param_numDeltas; + DbeView *dbev = dbeSession->getView (dbevindex); + if (dbev == NULL) + abort (); + Experiment *exp = dbeSession->get_exp (exp_id); + if (exp == NULL) + return NULL; + if (getRepresentatives == false && chartProps == NULL) + return NULL; + if (delta <= 0) + return NULL; + + hrtime_t tmp_ts = start_ts + delta * numDeltas; + if (tmp_ts < start_ts) + tmp_ts = MAX_TIME; + const hrtime_t end_ts = tmp_ts; + if (exp->get_status () == Experiment::INCOMPLETE && + exp->getLastEvent () < end_ts) + exp->update (); + DataView *packets = + getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id); + if (packets == NULL) + return NULL; // strange, no data view? + + VMode view_mode = dbev->get_view_mode (); // user, expert, machine //YXXX yuck + + // storage for calculating timeline representative events + Vector<long> *representativeEvents = NULL; + // list of representative events to be displayed on TL + Vector<int> *binRepIdx = NULL; + // for each bin, index of current "best" representativeEvent + Vector<void*> *representativeVals = NULL; + // TL representative packets' values + + // storage for calculating charts + Vector<int> *propIds = NULL; // [propIdx], which prop to measure + Vector<void*> *propVals = NULL; // [propIdx][bin], prop vals + Vector<int> *propNumStates = NULL; // [propIdx], how many states for prop? + Vector<bool> *propCumulativeChart = NULL; // [propIdx], data represents cumulative totals + Vector<long long> *propCumulativeRecentBinLastVal = NULL; // [propIdx], most recent value + Vector<long long> *propCumulativeRecentBinHighVal = NULL; // [propIdx], highest value for propCumulativeRecentBin + Vector<int> *propCumulativeRecentBin = NULL; // [propIdx], most recent bin + + // determine when to show duration of events + bool tmp_repsShowDuration = false; + bool tmp_statesUseDuration = false; + bool tmp_extendMicrostates = false; + const hrtime_t ptimerTickDuration = exp->get_params ()->ptimer_usec * 1000LL; // nanoseconds per tick + const bool hasDuration = packets->getProp (PROP_EVT_TIME) ? true : false; + if (hasDuration) + { + switch (entity_prop_id) + { + case PROP_CPUID: + tmp_repsShowDuration = false; + tmp_statesUseDuration = false; + break; + case PROP_THRID: + case PROP_LWPID: + tmp_repsShowDuration = true; + tmp_statesUseDuration = true; + tmp_extendMicrostates = (DATA_CLOCK == data_id) && (ptimerTickDuration < param_delta); + break; + case PROP_EXPID: + case PROP_NONE: // experiment summary row uses this + default: + if (DATA_SAMPLE == data_id) + { + tmp_repsShowDuration = true; + tmp_statesUseDuration = true; + } + else if (DATA_GCEVENT == data_id) + { + tmp_repsShowDuration = true; + tmp_statesUseDuration = true; + } + else if (DATA_CLOCK == data_id) + { + tmp_repsShowDuration = false; + tmp_statesUseDuration = true; + tmp_extendMicrostates = true; + } + else + { + tmp_repsShowDuration = false; + tmp_statesUseDuration = true; + } + break; + } + } + const bool repsShowDuration = tmp_repsShowDuration; // show stretched callstacks + const bool statesUseDuration = tmp_statesUseDuration; // use duration to calculate state charts + const bool extendMicrostates = tmp_extendMicrostates; // we show discrete profiling microstates with + // width=(tick-1), but for computing + // zoomed-out graphs we need to extend to + // account for all ticks, width=(ntick) + const bool reverseScan = repsShowDuration || extendMicrostates; // scan packets in reverse + + // determine range of packet indices (lo_pkt_idx, hi_pkt_idx) + long lo_pkt_idx, hi_pkt_idx; + if (extendMicrostates && !(entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID)) + { + // merging data from multiple threads, need to scan all packets with timestamp [start_ts, exp end] + hrtime_t exp_end_time = exp->getLastEvent () + 1; + hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value, + exp_end_time, DataView::REL_LT); // last item + } + else + hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value, + end_ts, DataView::REL_LT); + if (repsShowDuration) + { + // There are two issues to deal with + // 1. events that end "off screen" to the right + // 2. overlapping events + + // 1. events that end "off screen" to the right + // For now, we only consistently handle the case where events don't overlap. + // Note that packet timestamps mark end of duration, not start. + // This means that the rightmost event won't be within hi_pkt_idx. + // Solution: Check if end+1 packet _started_ in-range + // Caveat: because we only look ahead by one packet, if there are + // overlapping duration events (e.g. EXPID aggregation)), zoom level + // and panning combo may cause events with TSTAMP>end_ts + // to appear/disappear. A complete solution would involve + // a solution to 2. + + // 2. overlapping events + // For now, we have a simplistic solution that makes "wide" events win. However, + // a future solution for deterministically dealing with overlap might look like this: + // - find all packets that touch the visible time range + // - possibly use two DataViews: one with TSTAMP_HI sort and one with TSTAMP_LO + // sort to allow efficient determination of packets with HI and LO endpoints in-range + // - create buckets to capture "winning" event for each bin (each pixel, that is) + // - sort the new list of packets by TSTAMP_HI (for example) + // - looping thru the packets that are in-range, update every bin it touches with it's id + // - if there is overlap, earlier packets will be kicked out of bins + // - On the GUI side, paint one event at a time, as normal. + // - However, for selections, recognize that duration of event may span many bins + // + long idx; + if (hi_pkt_idx >= 0) + // a packet was found to the left of the end time + idx = hi_pkt_idx + 1; // attempt to go one packet right + else + idx = getIdxByVals (packets, aux, entity_prop_value, + end_ts, DataView::REL_GTEQ); + if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, idx)) + { + int64_t pkt_ts = packets->getLongValue (PROP_TSTAMP, idx); + int64_t duration = packets->getLongValue (PROP_EVT_TIME, idx); + pkt_ts -= duration; + if (pkt_ts < end_ts) + hi_pkt_idx = idx; + } + } + lo_pkt_idx = getIdxByVals (packets, aux, entity_prop_value, + start_ts, DataView::REL_GTEQ); + + // allocate structs that return chart data + bool hasCumulativeCharts = false; + if (chartProps && chartProps->size () > 0) + { + int nprops = chartProps->size (); + // pre-allocate storage + propIds = new Vector<int> (nprops); + propVals = new Vector<void*>(nprops); + propNumStates = new Vector<int> (nprops); + propCumulativeChart = new Vector<bool>(nprops); + propCumulativeRecentBinLastVal = new Vector<long long>(nprops); + propCumulativeRecentBinHighVal = new Vector<long long>(nprops); + propCumulativeRecentBin = new Vector<int>(nprops); + for (int propNum = 0; propNum < nprops; propNum++) + { + const char* propStr = chartProps->fetch (propNum); + int items_per_prop = 0; + int prop_id = PROP_NONE; + if (!strcmp (propStr, "EVT_COUNT")) + items_per_prop = 1; // use PROP_NONE for counting packets + else + { + int lookup_prop_id = dbeSession->getPropIdByName (propStr); + PropDescr *propDscr = packets->getProp (lookup_prop_id); + if (propDscr != NULL) + { + switch (propDscr->vtype) + { + case TYPE_INT32: + case TYPE_UINT32: + case TYPE_INT64: + case TYPE_UINT64: + items_per_prop = propDscr->getMaxState () + 1; + // add extra slot to store values with out-of-range idx + prop_id = lookup_prop_id; + break; + case TYPE_DOUBLE: + break; // not implemented yet + case TYPE_STRING: + case TYPE_OBJ: + case TYPE_DATE: + default: + break; + } + } + } + void *vals; + if (!items_per_prop) + vals = NULL; + else if (items_per_prop == 1) + { + Vector<long long> *longVals = new Vector<long long> (); + longVals->store (numDeltas - 1, 0); // initialize all elements + vals = longVals; + } + else + { + Vector<Vector<long long>*> *stateVals = + new Vector<Vector<long long>*> (); + vals = stateVals; + // initialize only on-demand, some may not be needed + } + + bool isCumulativeChart; +#define YXXX_HEAP_VS_TIME 1 // YXXX add data meaning to properties? +#if YXXX_HEAP_VS_TIME + isCumulativeChart = (prop_id == PROP_HCUR_LEAKS || prop_id == PROP_HCUR_ALLOCS); +#endif + if (isCumulativeChart) + hasCumulativeCharts = true; + propIds->store (propNum, prop_id); + propVals->store (propNum, vals); + propNumStates->store (propNum, items_per_prop); + propCumulativeRecentBinLastVal->store (propNum, 0); + propCumulativeRecentBinHighVal->store (propNum, 0); + propCumulativeRecentBin->store (propNum, 0); + propCumulativeChart->store (propNum, isCumulativeChart); + } + } + + // Adjust idx range for calculating 'cumulative charts' e.g. heap size + if (hasCumulativeCharts) + { + // set initial values if earlier packet exists + long lo_idx; + if (lo_pkt_idx >= 0) + // packet was found to the right of start + lo_idx = lo_pkt_idx - 1; // attempt to go left by one event + else + // no packet was to the right of start, look left of start + lo_idx = getIdxByVals (packets, aux, entity_prop_value, + start_ts, DataView::REL_LT); + if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, lo_idx)) + { + // preceding packet found + // update initial values + int nprops = propCumulativeChart->size (); + for (int propNum = 0; propNum < nprops; propNum++) + { + if (!propCumulativeChart->fetch (propNum)) + continue; + int propId = propIds->fetch (propNum); + long long value = packets->getLongValue (propId, lo_idx); + propCumulativeRecentBinLastVal->store (propNum, value); + propCumulativeRecentBinHighVal->store (propNum, value); + } + // update indices used for iterating + lo_pkt_idx = lo_idx; + if (hi_pkt_idx < lo_pkt_idx) + hi_pkt_idx = lo_pkt_idx; + } + } + if (lo_pkt_idx < 0 || hi_pkt_idx < 0) + goto dbeGetTLData_done; // no data; return empty vectors, not null + + // representative events (subset of callstacks to represent on TL) + if (getRepresentatives) + { + representativeEvents = new Vector<long>(numDeltas); + // per-bin, longest event's index + binRepIdx = new Vector<int>(numDeltas); + for (int ii = 0; ii < numDeltas; ++ii) + binRepIdx->append (-1); + } + // While packets are sorted by _end_ timestamp (TSTAMP), + // after calculating start times for non-zero durations, + // start times are not guaranteed be monotonically increasing. + // For packets with duration, we'll scan them in reverse order to + // take advantage of the monotonically decreasing _end_ timestamps. + long start_idx, idx_inc; + if (!reverseScan) + { + start_idx = lo_pkt_idx; + idx_inc = 1; + } + else + { + start_idx = hi_pkt_idx; + idx_inc = -1; + } + for (long ii = start_idx; ii >= lo_pkt_idx && ii <= hi_pkt_idx; ii += idx_inc) + { + if (!isVisibleTLEvent (exp, view_mode, packets, ii) && !hasCumulativeCharts) + continue; + + // determine packet time duration and start bin + int tmp_start_bin; // packet start bin + int tmp_end_bin; // packet end bin (inclusive) + const hrtime_t pkt_end_ts = packets->getLongValue (PROP_TSTAMP, ii); + const hrtime_t pkt_dur = packets->getLongValue (PROP_EVT_TIME, ii); + const hrtime_t pkt_start_ts = pkt_end_ts - pkt_dur; + if (pkt_end_ts < start_ts && !hasCumulativeCharts) + continue; // weird, should not happen + if (pkt_start_ts >= end_ts) + continue; // could happen + hrtime_t bin_end_ts = pkt_end_ts; + if (bin_end_ts >= end_ts) + bin_end_ts = end_ts - 1; + tmp_end_bin = (int) ((bin_end_ts - start_ts) / delta); + hrtime_t bin_start_ts = pkt_start_ts; + if (bin_start_ts < start_ts) + bin_start_ts = start_ts; // event truncated to left. + tmp_start_bin = (int) ((bin_start_ts - start_ts) / delta); + // By definition + // (end_ts - start_ts) == delta * numDeltas + // and we know + // pkt_start < end_ts + // therefore + // (pkt_start - start_ts) < delta * numDeltas + // (pkt_start - start_ts) / delta < numDeltas + // bin < numDeltas + assert (tmp_end_bin < numDeltas); + assert (tmp_start_bin < numDeltas); + const bool is_offscreen = tmp_end_bin < 0 ? true : false; + if (tmp_end_bin < 0) + tmp_end_bin = 0; + const int pkt_end_bin = tmp_end_bin; // packet end bin (inclusive) + const int pkt_start_bin = tmp_start_bin; + if (getRepresentatives && !is_offscreen) + { // find best representative + // Note: for events with duration, we're scanning packets in order + // of decreasing end-timestamp. This means that the first packet + // that hits a particular _start_ bin will have the longest duration + // of any later packet that might hit that start bin. The + // the first packet will be the best (longest) packet. + const int bin = reverseScan ? pkt_start_bin : pkt_end_bin; + int eventIdx = binRepIdx->fetch (bin); + if (eventIdx == -1) + { + eventIdx = representativeEvents->size (); // append to end + representativeEvents->append (ii); + binRepIdx->store (bin, eventIdx); + } + } + if (propIds) + { // per-bin chart: sum across filtered packets + for (int propNum = 0; propNum < propIds->size (); propNum++) + { + void *thisProp = propVals->fetch (propNum); + if (thisProp == NULL) + continue; // no valid data + if (is_offscreen && !propCumulativeChart->fetch (propNum)) + continue; // offscreen events are only processed for cumulative charts + int propId = propIds->fetch (propNum); + long long val; + if (propId == PROP_NONE) + val = 1; // count + else + val = packets->getLongValue (propId, ii); + long nitems = propNumStates->fetch (propNum); + if (nitems < 1) + continue; + else if (nitems == 1) + { + // chart is not based on not multiple states + Vector<long long>* thisPropVals = + (Vector<long long>*)thisProp; + if (thisPropVals->size () == 0) + thisPropVals->store (numDeltas - 1, 0); + const int bin = statesUseDuration ? pkt_start_bin : pkt_end_bin; + if (!propCumulativeChart->fetch (propNum)) + { + val += thisPropVals->fetch (bin); + thisPropVals->store (bin, val); + } + else + { + // propCumulativeChart + long long high_value = propCumulativeRecentBinHighVal->fetch (propNum); + int last_bin = propCumulativeRecentBin->fetch (propNum); + if (last_bin < bin) + { + // backfill from previous event + // last_bin: store largest value (in case of multiple events) + thisPropVals->store (last_bin, high_value); + // propagate forward the bin's last value + long long last_value = propCumulativeRecentBinLastVal->fetch (propNum); + for (int kk = last_bin + 1; kk < bin; kk++) + thisPropVals->store (kk, last_value); + // prepare new bin for current event + high_value = 0; // high value of next bin is 0. + propCumulativeRecentBinHighVal->store (propNum, high_value); + propCumulativeRecentBin->store (propNum, bin); + } + long long this_value = packets->getLongValue (propId, ii); + propCumulativeRecentBinLastVal->store (propNum, this_value); + if (high_value < this_value) + { + // record the max + high_value = this_value; + propCumulativeRecentBinHighVal->store (propNum, high_value); + } + if (ii == hi_pkt_idx) + { + // bin: show largest value (in case of multiple events + thisPropVals->store (bin, high_value); + //forward fill remaining bins + for (int kk = bin + 1; kk < numDeltas; kk++) + thisPropVals->store (kk, this_value); + } + } + } + else + { + // means val is actually a state # + Vector<Vector<long long>*>* thisPropStateVals = + (Vector<Vector<long long>*>*)thisProp; + if (thisPropStateVals->size () == 0) + thisPropStateVals->store (numDeltas - 1, 0); + long stateNum; + if (val >= 0 && val < nitems) + stateNum = (long) val; + else + stateNum = nitems - 1; // out of range, use last slot + hrtime_t graph_pkt_dur = pkt_dur; + hrtime_t graph_pkt_start_ts = pkt_start_ts; + int tmp2_start_bin = pkt_start_bin; + if (propId == PROP_MSTATE) + { + if (statesUseDuration && extendMicrostates) + { + // microstate stacks are shown and filtered with width=NTICK-1 + // but for microstate graph calcs use width=NTICK. + graph_pkt_dur += ptimerTickDuration; + graph_pkt_start_ts -= ptimerTickDuration; + hrtime_t bin_start_ts = graph_pkt_start_ts; + if (bin_start_ts < start_ts) + bin_start_ts = start_ts; // event truncated to left. + tmp2_start_bin = (int) ((bin_start_ts - start_ts) / delta); + } + } + const int graph_pkt_start_bin = statesUseDuration ? tmp2_start_bin : pkt_end_bin; + + // We will distribute the state's presence evenly over duration of the event. + // When only a 'partial bin' is touched by an event, adjust accordingly. + long long value_per_bin; // weight to be applied to each bin + { + long long weight; + if (propId == PROP_MSTATE) // ticks to nanoseconds + weight = packets->getLongValue (PROP_NTICK, ii) * ptimerTickDuration; + else if (graph_pkt_dur) + weight = graph_pkt_dur; // nanoseconds + else + weight = 1; // no duration; indicate presence + if (graph_pkt_start_bin != pkt_end_bin) + { + // spans multiple bins + double nbins = (double) graph_pkt_dur / delta; + value_per_bin = weight / nbins; + } + else + value_per_bin = weight; + } + for (int evtbin = graph_pkt_start_bin; evtbin <= pkt_end_bin; evtbin++) + { + Vector<long long>* stateValues = + (Vector<long long>*) thisPropStateVals->fetch (evtbin); + if (stateValues == NULL) + { + // on-demand storage + stateValues = new Vector<long long>(nitems); + stateValues->store (nitems - 1, 0); // force memset of full vector + thisPropStateVals->store (evtbin, stateValues); + } + long long new_val = stateValues->fetch (stateNum); + if (graph_pkt_start_bin == pkt_end_bin || + (evtbin > graph_pkt_start_bin && evtbin < pkt_end_bin)) + { + new_val += value_per_bin; + } + else + { + // partial bin + const hrtime_t bin_start = start_ts + evtbin * delta; + const hrtime_t bin_end = start_ts + (evtbin + 1) * delta - 1; + if (evtbin == graph_pkt_start_bin) + { + // leftmost bin + if (graph_pkt_start_ts < bin_start) + new_val += value_per_bin; + else + { + double percent = (double) (bin_end - graph_pkt_start_ts) / delta; + new_val += value_per_bin*percent; + } + } + else + { + // rightmost bin + if (pkt_end_ts > bin_end) + new_val += value_per_bin; + else + { + double percent = (double) (pkt_end_ts - bin_start) / delta; + new_val += value_per_bin*percent; + } + } + } + stateValues->store (stateNum, new_val); + } + } + } + } + } + delete binRepIdx; + delete propIds; + delete propCumulativeChart; + delete propCumulativeRecentBinLastVal; + delete propCumulativeRecentBinHighVal; + delete propCumulativeRecentBin; + if (representativeEvents != NULL && reverseScan) + { + if (repsShowDuration) + { + //YXXX for now prune here, but in the future, let gui decide what to show + // Prune events that are completely obscured long duration events. + // Note: representativeEvents is sorted by decreasing _end_ timestamps. + Vector<long> *prunedEvents = new Vector<long>(numDeltas); + hrtime_t prev_start_ts = MAX_TIME; + long repCnt = representativeEvents->size (); + for (long kk = 0; kk < repCnt; kk++) + { + long ii = representativeEvents->fetch (kk); + hrtime_t tmp_end_ts = packets->getLongValue (PROP_TSTAMP, ii); + hrtime_t tmp_dur = packets->getLongValue (PROP_EVT_TIME, ii); + hrtime_t tmp_start_ts = tmp_end_ts - tmp_dur; + if (tmp_start_ts >= prev_start_ts) + // this event would be completely hidden + // (because of sorting, we know tmp_end_ts <= prev_end_ts) + continue; + prev_start_ts = tmp_start_ts; + prunedEvents->append (ii); + } + // invert order to to get increasing _end_ timestamps + representativeEvents->reset (); + for (long kk = prunedEvents->size () - 1; kk >= 0; kk--) + { + long packet_idx = prunedEvents->fetch (kk); + representativeEvents->append (packet_idx); + } + delete prunedEvents; + } + else + { // !repsShowDuration + // Note: representativeEvents is sorted by decreasing _end_ timestamps. + // Reverse the order: + long hi_idx = representativeEvents->size () - 1; + long lo_idx = 0; + while (hi_idx > lo_idx) + { + // swap + long lo = representativeEvents->fetch (lo_idx); + long hi = representativeEvents->fetch (hi_idx); + representativeEvents->store (lo_idx, hi); + representativeEvents->store (hi_idx, lo); + hi_idx--; + lo_idx++; + } + } + } + +dbeGetTLData_done: + if (getRepresentatives) + { + representativeVals = dbeGetTLDataRepVals (view_mode, start_ts, delta, + numDeltas, packets, representativeEvents, repsShowDuration); + delete representativeEvents; + } + Vector<void*> *results = new Vector<void*> (2); + results->store (0, representativeVals); + results->store (1, propVals); + return results; +} + +// add representative events to return buffer + +static Vector<void *> * +dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta, + int numDeltas, DataView*packets, + Vector<long> *representativeEvents, bool showDuration) +{ + int numrecs = representativeEvents ? representativeEvents->size () : 0; + // allocate storage for results + Vector<int> *startBins = new Vector<int>(numrecs); + Vector<int> *numBins = new Vector<int>(numrecs); + Vector<Obj> *eventIdxs = new Vector<Obj>(numrecs); + Vector<Obj> *stackIds = NULL; + if (packets->getProp (PROP_FRINFO)) + stackIds = new Vector<Obj>(numrecs); + Vector<int> *mstates = NULL; + if (packets->getProp (PROP_MSTATE)) + mstates = new Vector<int>(numrecs); + Vector<Vector<long long>*> *sampleVals = NULL; + if (packets->getProp (PROP_SMPLOBJ)) + sampleVals = new Vector<Vector<long long>*>(numrecs); + Vector<long long> *timeStart = new Vector<long long>(numrecs); + Vector<long long> *timeEnd = new Vector<long long>(numrecs); + int prevEndBin = -1; // make sure we don't overlap bins + for (int eventIdx = 0; eventIdx < numrecs; eventIdx++) + { + long packetIdx = representativeEvents->fetch (eventIdx); + // long eventId = packets->getIdByIdx( packetIdx ); + const hrtime_t pkt_tstamp = packets->getLongValue (PROP_TSTAMP, packetIdx); + const hrtime_t pkt_dur = showDuration ? packets->getLongValue (PROP_EVT_TIME, packetIdx) : 0; + timeStart->store (eventIdx, pkt_tstamp - pkt_dur); + timeEnd->store (eventIdx, pkt_tstamp); + + // calc startBin + int startBin = (int) ((pkt_tstamp - pkt_dur - start_ts) / delta); + if (startBin <= prevEndBin) + startBin = prevEndBin + 1; + // calc binCnt + int endBin = (int) ((pkt_tstamp - start_ts) / delta); + if (endBin >= numDeltas) + endBin = numDeltas - 1; + int binCnt = endBin - startBin + 1; + prevEndBin = endBin; + startBins->store (eventIdx, startBin); + numBins->store (eventIdx, binCnt); + eventIdxs->store (eventIdx, packetIdx); // store packet's idx + if (stackIds != NULL) + { + void* stackId = getStack (view_mode, packets, packetIdx); + stackIds->store (eventIdx, (Obj) (unsigned long) stackId); + } + if (mstates != NULL) + { + int mstate = packets->getIntValue (PROP_MSTATE, packetIdx); + mstates->store (eventIdx, mstate); + } + if (sampleVals != NULL) + { + Sample* sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, packetIdx); + if (!sample || !sample->get_usage ()) + sample = sample; + else + { + PrUsage* prusage = sample->get_usage (); + Vector<long long> *mstateVals = prusage->getMstateValues (); + sampleVals->store (eventIdx, mstateVals); + } + } + } + // caller responsible for: delete representativeEvents; + Vector<void*> *results = new Vector<void*> (8); + results->store (0, startBins); + results->store (1, numBins); + results->store (2, eventIdxs); + results->store (3, stackIds); + results->store (4, mstates); + results->store (5, sampleVals); + results->store (6, timeStart); + results->store (7, timeEnd); + return results; +} + +// starting from <event_id> packet idx, step <move_count> visible events +// return the resulting idx and that packet's center time, or null if no event. +Vector<long long> * +dbeGetTLEventCenterTime (int dbevindex, int exp_id, int data_id, + int entity_prop_id, int entity_prop_val, int aux, + long long event_id, long long move_count) +{ + DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id, + entity_prop_id); + if (packets == NULL) + return NULL; + long idx = (long) event_id; + + DbeView *dbev = dbeSession->getView (dbevindex); + VMode view_mode = dbev->get_view_mode (); + Experiment *exp = dbeSession->get_exp (exp_id); + int direction; + if (move_count == 0) + direction = 0; + else if (move_count < 0) + { + move_count = -move_count; + direction = -1; + } + else + direction = 1; + idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets, aux, + entity_prop_val, idx, move_count, direction); + if (idx >= 0) + { + long long ts = packets->getLongValue (PROP_TSTAMP, idx); + long long dur = packets->getLongValue (PROP_EVT_TIME, idx); + long long center = ts - dur / 2; + Vector<long long> *results = new Vector<long long> (2); + results->store (0, idx); // result idx + results->store (1, center); // result timestamp + return results; + } + return NULL; +} + +long long +dbeGetTLEventIdxNearTime (int dbevindex, int exp_id, int data_id, + int entity_prop_id, int entity_prop_val, int aux, + int searchDirection, long long tstamp) +{ + DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id, + entity_prop_id); + if (packets == NULL) + return -1; + DbeView *dbev = dbeSession->getView (dbevindex); + VMode view_mode = dbev->get_view_mode (); + Experiment *exp = dbeSession->get_exp (exp_id); + if (searchDirection < 0) + { + int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id, + packets, aux, entity_prop_val, tstamp, + DataView::REL_LTEQ); + if (idx != -1) + return idx; + searchDirection = 1; // couldn't find to left, try to right + } + if (searchDirection > 0) + { + int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id, + packets, aux, entity_prop_val, tstamp, + DataView::REL_GTEQ); + if (idx != -1) + return idx; + // couldn't find to right, fall through to generic + } + // search left and right of timestamp + long idx1, idx2; + idx1 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id, + packets, aux, entity_prop_val, tstamp, + DataView::REL_LT); + idx2 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id, + packets, aux, entity_prop_val, tstamp, + DataView::REL_GTEQ); + if (idx1 == -1) + return idx2; + else if (idx2 == -1) + return idx1; + + // both valid, so need to compare to see which is closer + long long t1 = packets->getLongValue (PROP_TSTAMP, idx1); + long long t2 = packets->getLongValue (PROP_TSTAMP, idx2); + long long t2dur = packets->getLongValue (PROP_EVT_TIME, idx2); + long long delta1 = tstamp - t1; // should always be positive + long long delta2 = (t2 - t2dur) - tstamp; // if negative, overlaps idx1 + if (delta1 > delta2) + return idx2; + else + return idx1; +} + +enum Aggr_type +{ + AGGR_NONE, + AGGR_FAIR, + AGGR_MAX, + AGGR_MIN, + AGGR_CNT, + AGGR_SUM, + AGGR_AVG +}; + +static Aggr_type +getAggrFunc (char *aname) +{ + Aggr_type agrfn = AGGR_NONE; + if (aname == NULL) + return agrfn; + if (strcmp (aname, NTXT ("FAIR")) == 0) + agrfn = AGGR_FAIR; + else if (strcmp (aname, NTXT ("MAX")) == 0) + agrfn = AGGR_MAX; + else if (strcmp (aname, NTXT ("MIN")) == 0) + agrfn = AGGR_MIN; + else if (strcmp (aname, NTXT ("CNT")) == 0) + agrfn = AGGR_CNT; + else if (strcmp (aname, NTXT ("SUM")) == 0) + agrfn = AGGR_SUM; + else if (strcmp (aname, NTXT ("AVG")) == 0) + agrfn = AGGR_AVG; + return agrfn; +} + +static long long +computeAggrVal (DefaultMap<long long, long long> *fval_map, Aggr_type agrfn) +{ + long long aval = 0; + long cnt = 0; + Vector<long long> *fvals = fval_map->values (); + long nvals = fvals->size (); + for (int i = 0; i < nvals; ++i) + { + long long val = fvals->fetch (i); + switch (agrfn) + { + case AGGR_FAIR: + aval = val; + break; + case AGGR_MAX: + if (aval < val || cnt == 0) + aval = val; + break; + case AGGR_MIN: + if (aval > val || cnt == 0) + aval = val; + break; + case AGGR_CNT: + aval = cnt + 1; + break; + case AGGR_SUM: + case AGGR_AVG: + aval += val; + break; + case AGGR_NONE: + break; + } + if (agrfn == AGGR_FAIR) + break; + cnt += 1; + } + + // Finalize aggregation + if (agrfn == AGGR_AVG) + if (cnt > 0) + aval = (aval + cnt / 2) / cnt; + delete fvals; + return aval; +} + +Vector<long long> * +dbeGetAggregatedValue (int data_id, // data table id + char *lfilter, // local filter + char *fexpr, // function expression + char *pname_ts, // property name for timestamp + hrtime_t start_ts, // start of the first time interval + hrtime_t delta, // time interval length + int num, // number of time intervals + char *pname_key, // property name for aggregation key + char *aggr_func) // aggregation function +{ + Vector<long long> *res = new Vector<long long>; + Experiment *exp = dbeSession->get_exp (0); + if (exp == NULL) + return res; + hrtime_t end_ts = start_ts + delta * num; + if (end_ts < start_ts) // check overflow + end_ts = MAX_TIME; + + if (exp->get_status () == Experiment::INCOMPLETE + && exp->getLastEvent () < end_ts) + exp->update (); + + DataDescriptor *dataDscr = exp->get_raw_events (data_id); + if (dataDscr == NULL) + return res; + + // Process timestamp argument + int prop_ts = dbeSession->getPropIdByName (pname_ts); + if (prop_ts == PROP_NONE) + return res; + assert (prop_ts == -1); + + // Parse all expressions + Expression *flt_expr = NULL; + if (lfilter != NULL) + flt_expr = dbeSession->ql_parse (lfilter); + Expression *func_expr = NULL; + if (fexpr != NULL) + func_expr = dbeSession->ql_parse (fexpr); + if (func_expr == NULL) // Not specified or malformed + return res; + + // Process aggregation key argument + int prop_key = PROP_NONE; + Data *data_key = NULL; + if (pname_key != NULL) + { + prop_key = dbeSession->getPropIdByName (pname_key); + data_key = dataDscr->getData (prop_key); + if (data_key == NULL) // Specified but not found + return res; + } + + // Process aggregation function argument + Aggr_type agrfn = AGGR_FAIR; + if (aggr_func != NULL) + { + agrfn = getAggrFunc (aggr_func); + if (agrfn == AGGR_NONE) // Specified but not recognized + return res; + } + DefaultMap<long long, long long> * + fval_map = new DefaultMap<long long, long long>; // key_val -> func_val + Vector<long long> *key_set = NULL; + assert (key_set != NULL); + if (key_set == NULL) + { + key_set = new Vector<long long>; + key_set->append (0L); + } + DefaultMap<long long, int> *key_seen = new DefaultMap<long long, int>; + long idx_prev = -1; + for (int tidx = 0; tidx < num; ++tidx) + { + long idx_cur = -1; + assert (idx_cur != -1); + int left = key_set->size (); + key_seen->clear (); + for (long idx = idx_cur; idx > idx_prev; --idx) + { + long id = 0; + assert (id != 0); + + // Pre-create expression context + Expression::Context ctx (dbeSession->getView (0), exp, NULL, id); + // First use the filter + if (flt_expr != NULL) + if (flt_expr->eval (&ctx) == 0) + continue; + + // Calculate the key + // keys are limited to integral values + long long key = 0; + if (data_key != NULL) + key = data_key->fetchLong (id); + + // Check if already seen + if (key_seen->get (key) == 1) + continue; + key_seen->put (key, 1); + left -= 1; + + // Calculate function value + // function values are limited to integral values + long long fval = func_expr->eval (&ctx); + fval_map->put (key, fval); + if (left == 0) + break; + } + idx_prev = idx_cur; + long long aval = computeAggrVal (fval_map, agrfn); + res->store (tidx, aval); + } + delete key_seen; + delete fval_map; + delete flt_expr; + delete func_expr; + return res; +} + +Vector<char*> * +dbeGetLineInfo (Obj pc) +{ + DbeInstr *instr = (DbeInstr*) pc; + if (instr == NULL || instr->get_type () != Histable::INSTR) + return NULL; + DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE); + const char *fname = dbeline ? dbeline->sourceFile->get_name () : NTXT (""); + char lineno[16]; + *lineno = '\0'; + if (dbeline != NULL) + snprintf (lineno, sizeof (lineno), NTXT ("%d"), dbeline->lineno); + Vector<char*> *res = new Vector<char*>(2); + res->store (0, strdup (fname)); + res->store (1, strdup (lineno)); + return res; +} + +int +dbeSetAlias (char *name, char *uname, char *expr) +{ + char *res = dbeSession->indxobj_define (name, uname, expr, NULL, NULL); + return res == NULL ? 0 : 1; +} + +Vector<char*> * +dbeGetAlias (char *name) +{ + Vector<char*> *res = new Vector<char*>; + int idx = dbeSession->findIndexSpaceByName (name); + if (idx >= 0) + { + char *str = dbeSession->getIndexSpaceDescr (idx); + res->append (dbe_strdup (str)); + str = dbeSession->getIndexSpaceExprStr (idx); + res->append (dbe_strdup (str)); + } + return res; +} + +static int +key_cmp (const void *p1, const void *p2) +{ + long long ll1 = *(long long*) p1; + long long ll2 = *(long long*) p2; + return ll1 < ll2 ? -1 : ll1 > ll2 ? 1 : 0; +} + +Vector<Vector<long long>*> * +dbeGetXYPlotData ( + int data_id, // data table id + char *lfilter, // local filter expression + char *arg, // name for the argument + char *func1, // expression for the first axis (x) + char *aggr1, // aggregation function for func1: "SUM","CNT",... + char *func2, // expression for the second axis (y) + char *aggr2, // aggregation function for func2 + char *func3, // expression for the third axis (color) + char *aggr3) // aggregation function for func3 +{ + Vector<Vector<long long>*> *res = new Vector<Vector<long long>*>; + Experiment *exp = dbeSession->get_exp (0); + if (exp == NULL) + return res; + if (exp->get_status () == Experiment::INCOMPLETE) + exp->update (); + + DataDescriptor *dataDscr = exp->get_raw_events (data_id); + if (dataDscr == NULL) + return res; + + // Parse all expressions + Vector<Expression*> *funcs = new Vector<Expression*>; + Vector<Aggr_type> *aggrs = new Vector<Aggr_type>; + Vector<DefaultMap<long long, long long>*> *fval_maps = + new Vector<DefaultMap<long long, long long>*>; + Vector<DefaultMap<long long, long>*> *cnt_maps = + new Vector<DefaultMap<long long, long>*>; + if (func1 != NULL) + { + Expression *expr = dbeSession->ql_parse (func1); + funcs->append (expr); + aggrs->append (getAggrFunc (aggr1)); + fval_maps->append (new DefaultMap<long long, long long>); + cnt_maps->append (new DefaultMap<long long, long>); + res->append (new Vector<long long>); + if (func2 != NULL) + { + expr = dbeSession->ql_parse (func2); + funcs->append (expr); + aggrs->append (getAggrFunc (aggr2)); + fval_maps->append (new DefaultMap<long long, long long>); + cnt_maps->append (new DefaultMap<long long, long>); + res->append (new Vector<long long>); + if (func3 != NULL) + { + expr = dbeSession->ql_parse (func3); + funcs->append (expr); + aggrs->append (getAggrFunc (aggr3)); + fval_maps->append (new DefaultMap<long long, long long>); + cnt_maps->append (new DefaultMap<long long, long>); + res->append (new Vector<long long>); + } + } + } + if (funcs->size () == 0) + { + funcs->destroy (); + delete funcs; + fval_maps->destroy (); + delete fval_maps; + cnt_maps->destroy (); + delete cnt_maps; + delete aggrs; + return res; + } + Expression *arg_expr = NULL; + if (arg != NULL) + arg_expr = dbeSession->ql_parse (arg); + if (arg_expr == NULL) + { + funcs->destroy (); + delete funcs; + fval_maps->destroy (); + delete fval_maps; + cnt_maps->destroy (); + delete cnt_maps; + delete aggrs; + return res; + } + Expression *flt_expr = NULL; + if (lfilter != NULL) + flt_expr = dbeSession->ql_parse (lfilter); + Vector<long long> *kidx_map = new Vector<long long>(); // key_idx -> key_val + for (long i = 0; i < dataDscr->getSize (); i++) + { + Expression::Context ctx (dbeSession->getView (0), exp, NULL, i); + // First use the filter + if (flt_expr != NULL) + if (flt_expr->eval (&ctx) == 0) + continue; + + // Compute the argument + long long key = arg_expr->eval (&ctx); + if (kidx_map->find (key) == -1) + kidx_map->append (key); + for (long j = 0; j < funcs->size (); ++j) + { + Expression *func = funcs->fetch (j); + Aggr_type aggr = aggrs->fetch (j); + DefaultMap<long long, long long> *fval_map = fval_maps->fetch (j); + DefaultMap<long long, long> *cnt_map = cnt_maps->fetch (j); + long long fval = func->eval (&ctx); + long long aval = fval_map->get (key); + long cnt = cnt_map->get (key); + switch (aggr) + { + case AGGR_NONE: + case AGGR_FAIR: + if (cnt == 0) + aval = fval; + break; + case AGGR_MAX: + if (aval < fval || cnt == 0) + aval = fval; + break; + case AGGR_MIN: + if (aval > fval || cnt == 0) + aval = fval; + break; + case AGGR_CNT: + aval = cnt + 1; + break; + case AGGR_SUM: + case AGGR_AVG: + aval += fval; + break; + } + cnt_map->put (key, cnt + 1); + fval_map->put (key, aval); + } + } + kidx_map->sort (key_cmp); + + // Finalize aggregation, prepare result + for (long j = 0; j < funcs->size (); ++j) + { + Aggr_type aggr = aggrs->fetch (j); + Vector<long long> *resj = res->fetch (j); + DefaultMap<long long, long long> * + fval_map = fval_maps->fetch (j); + DefaultMap<long long, long> * + cnt_map = cnt_maps->fetch (j); + for (int kidx = 0; kidx < kidx_map->size (); ++kidx) + { + long long key = kidx_map->fetch (kidx); + long long aval = fval_map->get (key); + if (aggr == AGGR_AVG) + { + long cnt = cnt_map->get (key); + if (cnt > 0) + aval = (aval + cnt / 2) / cnt; + } + resj->append (aval); + } + } + delete flt_expr; + funcs->destroy (); + delete funcs; + delete aggrs; + delete arg_expr; + delete kidx_map; + fval_maps->destroy (); + delete fval_maps; + cnt_maps->destroy (); + delete cnt_maps; + return res; +} + +/* ********************************************************************* */ +/* Routines for use by Collector GUI */ +/** + * Returns signal value for provided name. Example of name: "SIGUSR1" + * @param signal + * @return value + */ +int +dbeGetSignalValue (char *signal) +{ + int ret = -1; + if (signal == NULL) + return ret; + if (strcmp (signal, "SIGUSR1") == 0) + return (SIGUSR1); + if (strcmp (signal, "SIGUSR2") == 0) + return (SIGUSR2); + if (strcmp (signal, "SIGPROF") == 0) + return (SIGPROF); + return ret; +} + +char * +dbeSendSignal (pid_t p, int signum) +{ + int ret = kill (p, signum); + if (p == 0 || p == -1) + return (dbe_sprintf (GTXT ("kill of process %d not supported\n"), p)); + if (ret == 0) + return NULL; + char *msg = dbe_sprintf (GTXT ("kill(%d, %d) failed: %s\n"), p, signum, + strerror (errno)); + return msg; +} + +char * +dbeGetCollectorControlValue (char *control) +{ + if (control == NULL) + return NULL; + if (col_ctr == NULL) + col_ctr = new Coll_Ctrl (1); + char *msg = col_ctr->get (control); + return msg; +} + +char * +dbeSetCollectorControlValue (char *control, char * value) +{ + if (control == NULL) + return NULL; + if (col_ctr == NULL) + col_ctr = new Coll_Ctrl (1); + char *msg = col_ctr->set (control, value); + return msg; +} + +char * +dbeUnsetCollectorControlValue (char *control) +{ + if (control == NULL) + return NULL; + if (col_ctr == NULL) + col_ctr = new Coll_Ctrl (1); + char *msg = col_ctr->unset (control); + return msg; +} + +void +dbeSetLocation (const char *fname, const char *location) +{ + Vector<SourceFile*> *sources = dbeSession->get_sources (); + for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++) + { + SourceFile *src = sources->get (i); + DbeFile *df = src->dbeFile; + if (df && (strcmp (fname, df->get_name ()) == 0)) + { + df->find_file ((char *) location); + break; + } + } +} + +void +dbeSetLocations (Vector<const char *> *fnames, Vector<const char *> *locations) +{ + if (fnames == NULL || locations == NULL + || fnames->size () != locations->size ()) + return; + for (long i = 0, sz = fnames->size (); i < sz; i++) + dbeSetLocation (fnames->get (i), locations->get (i)); +} + +Vector<void*> * +dbeResolvedWith_setpath (const char *path) +{ + Vector<char*> *names = new Vector<char*>(); + Vector<char*> *pathes = new Vector<char*>(); + Vector<long long> *ids = new Vector<long long>(); + Vector<SourceFile*> *sources = dbeSession->get_sources (); + for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++) + { + SourceFile *src = sources->get (i); + DbeFile *df = src->dbeFile; + if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0) + continue; + char *fnm = df->get_name (); + if ((df->filetype & (DbeFile::F_JAVACLASS | DbeFile::F_JAVA_SOURCE)) != 0) + { + char *jnm = dbe_sprintf (NTXT ("%s/%s"), path, fnm); + if (df->check_access (jnm) == DbeFile::F_FILE) + { + names->append (dbe_strdup (fnm)); + pathes->append (jnm); + ids->append (src->id); + continue; + } + free (jnm); + } + char *nm = dbe_sprintf (NTXT ("%s/%s"), path, get_basename (fnm)); + if (df->check_access (nm) == DbeFile::F_FILE) + { + names->append (dbe_strdup (fnm)); + pathes->append (nm); + ids->append (src->id); + continue; + } + free (nm); + } + if (names->size () != 0) + { + Vector<void*> *data = new Vector<void*>(3); + data->append (names); + data->append (pathes); + data->append (ids); + return data; + } + return NULL; +} + +Vector<void*> * +dbeResolvedWith_pathmap (const char *old_prefix, const char *new_prefix) +{ + size_t len = strlen (old_prefix); + Vector<char*> *names = new Vector<char*>(); + Vector<char*> *pathes = new Vector<char*>(); + Vector<long long> *ids = new Vector<long long>(); + Vector<SourceFile*> *sources = dbeSession->get_sources (); + for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++) + { + SourceFile *src = sources->get (i); + DbeFile *df = src->dbeFile; + if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0) + continue; + char *fnm = df->get_name (); + if (strncmp (old_prefix, fnm, len) == 0 + && (fnm[len] == '/' || fnm[len] == '\0')) + { + char *nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm + len); + if (df->check_access (nm) == DbeFile::F_FILE) + { + names->append (dbe_strdup (fnm)); + pathes->append (nm); + ids->append (src->id); + continue; + } + if ((df->filetype & DbeFile::F_JAVA_SOURCE) != 0) + { + free (nm); + nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm); + if (df->check_access (nm) == DbeFile::F_FILE) + { + names->append (dbe_strdup (fnm)); + pathes->append (nm); + ids->append (src->id); + continue; + } + } + free (nm); + } + } + if (names->size () != 0) + { + Vector<void*> *data = new Vector<void*>(3); + data->append (names); + data->append (pathes); + data->append (ids); + return data; + } + return NULL; +} + +void +dbe_archive (Vector<long long> *ids, Vector<const char *> *locations) +{ + if (ids == NULL || locations == NULL || ids->size () != locations->size ()) + return; + Experiment *exp = dbeSession->get_exp (0); + if (exp == NULL) + return; + Vector<SourceFile*> *sources = dbeSession->get_sources (); + for (long i1 = 0, sz1 = ids->size (); i1 < sz1; i1++) + { + long long id = ids->get (i1); + for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++) + { + SourceFile *src = sources->get (i); + if (src->id == id) + { + DbeFile *df = src->dbeFile; + if (df) + { + char *fnm = df->find_file ((char *) locations->get (i1)); + if (fnm) + { + char *nm = df->get_name (); + char *anm = exp->getNameInArchive (nm, false); + exp->copy_file (fnm, anm, true); + free (anm); + } + } + } + } + } +} + +/* ************************************************************************ */ + +/* Routines to check connection between Remote Analyzer Client and er_print */ +char * +dbeCheckConnection (char *str) +{ + return dbe_strdup (str); +} |