| /* 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 (); |
|