| /* Copyright (C) 2021-2024 Free Software Foundation, Inc. | |
| Contributed by Oracle. | |
| This file is part of GNU Binutils. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3, or (at your option) | |
| any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
| MA 02110-1301, USA. */ | |
| #include "config.h" | |
| #include <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 | |
| dbe_stat_t 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 (GTXT (" Host : %s (%s, %s)"), | |
| field, | |
| exp->architecture ? exp->architecture | |
| : GTXT ("<CPU architecture not recorded>"), | |
| exp->os_version ? exp->os_version | |
| : GTXT ("<OS version not recorded>"))); | |
| time_t start_sec = (time_t) exp->start_sec; | |
| char *p = ctime (&start_sec); | |
| hrtime_t tot_time = dbeCalcGroupDuration (grInd); | |
| double seconds = tot_time * 1.e-9; | |
| info->append (dbe_sprintf ( | |
| GTXT (" Start Time : %s Duration : %0.3f Seconds"), | |
| p, 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); | |
| } |