/* Copyright (C) 2021-2023 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "util.h" #include "Application.h" #include "DbeSession.h" #include "CallStack.h" #include "Command.h" #include "DataObject.h" #include "Experiment.h" #include "ExpGroup.h" #include "FilterExp.h" #include "FilterSet.h" #include "Function.h" #include "DbeView.h" #include "PathTree.h" #include "DataSpace.h" #include "MemorySpace.h" #include "IOActivity.h" #include "HeapActivity.h" #include "Print.h" #include "MetricList.h" #include "Module.h" #include "Filter.h" #include "LoadObject.h" #include "dbe_types.h" #include "StringBuilder.h" DbeView::DbeView (Application *_app, Settings *_settings, int _vindex) { init (); phaseIdx = 0; settings = new Settings (_settings); ptree = new PathTree (this); dspace = new DataSpace (this); memspaces = new Vector; iospace = new IOActivity (this); heapspace = new HeapActivity (this); filters = new Vector; lo_expands = new Vector; cur_filter_str = NULL; prev_filter_str = NULL; cur_filter_expr = NULL; filter_active = false; noParFilter = false; dataViews = new Vector*>; names_src[0] = NULL; names_src[1] = NULL; names_src[2] = NULL; names_dis[0] = NULL; names_dis[1] = NULL; names_dis[2] = NULL; marks = new Vector; marks2dsrc = new Vector; marks2dsrc_inc = new Vector; marks2ddis = new Vector; marks2ddis_inc = new Vector; app = _app; // set the view's index vindex = _vindex; // clear the precomputed data func_data = NULL; line_data = NULL; pc_data = NULL; src_data = NULL; dis_data = NULL; fitem_data = NULL; callers = NULL; callees = NULL; dobj_data = NULL; dlay_data = NULL; iofile_data = NULL; iovfd_data = NULL; iocs_data = NULL; heapcs_data = NULL; // and clear the selections sel_obj = NULL; sel_dobj = NULL; sel_binctx = NULL; func_scope = false; lastSelInstr = NULL; lastSelFunc = NULL; // Initialize index spaces int sz = settings->get_IndxTabState ()->size (); indxspaces = new Vector(sz); indx_data = new Vector(sz); sel_idxobj = new Vector(sz); for (int i = 0; i < sz; i++) { PathTree *is = new PathTree (this, i); indxspaces->store (i, is); indx_data->store (i, NULL); sel_idxobj->store (i, NULL); } reset (); lobjectsNoJava = NULL; // set lo_expands for already existing LoadObjects int idx; LoadObject *lo; Vector *lobjs = dbeSession->get_text_segments (); Vec_loop (LoadObject*, lobjs, idx, lo) { lo_expands->store (lo->seg_idx, LIBEX_SHOW); set_lo_expand (lo->seg_idx, LIBEX_SHOW); } delete lobjs; } DbeView::DbeView (DbeView *dbev, int _vindex) { init (); phaseIdx = 0; settings = new Settings (dbev->settings); ptree = new PathTree (this); dspace = new DataSpace (this); iospace = new IOActivity (this); heapspace = new HeapActivity (this); memspaces = new Vector; filters = new Vector; lo_expands = new Vector; cur_filter_str = NULL; prev_filter_str = NULL; cur_filter_expr = NULL; noParFilter = false; dataViews = new Vector*>; names_src[0] = NULL; names_src[1] = NULL; names_src[2] = NULL; names_dis[0] = NULL; names_dis[1] = NULL; names_dis[2] = NULL; marks = new Vector; marks2dsrc = new Vector; marks2dsrc_inc = new Vector; marks2ddis = new Vector; marks2ddis_inc = new Vector; app = dbev->app; // set the view's index vindex = _vindex; // clear the precomputed data func_data = NULL; line_data = NULL; pc_data = NULL; src_data = NULL; dis_data = NULL; fitem_data = NULL; callers = NULL; callees = NULL; dobj_data = NULL; dlay_data = NULL; iofile_data = NULL; iovfd_data = NULL; iocs_data = NULL; heapcs_data = NULL; // and clear the selections sel_obj = NULL; sel_dobj = NULL; sel_binctx = NULL; func_scope = false; lastSelInstr = NULL; lastSelFunc = NULL; // create the vector of IndexSpaces int sz = dbev->indxspaces->size (); indxspaces = new Vector(sz); indx_data = new Vector(sz); sel_idxobj = new Vector(sz); for (int i = 0; i < sz; i++) { PathTree *is = new PathTree (this, i); indxspaces->store (i, is); indx_data->store (i, NULL); sel_idxobj->store (i, NULL); } reset (); // now copy the relevant information from the original view for (int i = 0; i < dbeSession->nexps (); i++) add_experiment (i, dbev->get_exp_enable (i)); update_advanced_filter (); delete lo_expands; lo_expands = dbev->lo_expands->copy (); lobjectsNoJava = NULL; } DbeView::~DbeView () { delete settings; delete ptree; delete dspace; delete iospace; delete heapspace; Destroy (memspaces); Destroy (filters); delete lo_expands; free (cur_filter_str); free (prev_filter_str); delete cur_filter_expr; for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id) { Vector *expDataViewList = dataViews->fetch (exp_id); Destroy (expDataViewList); } delete dataViews; delete reg_metrics; metrics_lists->destroy (); delete metrics_lists; metrics_ref_lists->destroy (); delete metrics_ref_lists; delete derived_metrics; delete marks; delete marks2dsrc; delete marks2dsrc_inc; delete marks2ddis; delete marks2ddis_inc; // Index spaces indxspaces->destroy (); delete indxspaces; indx_data->destroy (); delete indx_data; delete sel_idxobj; delete lobjectsNoJava; } void DbeView::init () { phaseIdx = 0; reg_metrics = new Vector; metrics_lists = new Vector; metrics_ref_lists = new Vector; for (int i = 0; i <= MET_HEAP; i++) { metrics_lists->append (NULL); metrics_ref_lists->append (NULL); } derived_metrics = new DerivedMetrics; derived_metrics->add_definition (GTXT ("CPI"), GTXT ("Cycles Per Instruction"), GTXT ("cycles/insts")); derived_metrics->add_definition (GTXT ("IPC"), GTXT ("Instructions Per Cycle"), GTXT ("insts/cycles")); derived_metrics->add_definition (GTXT ("K_CPI"), GTXT ("Kernel Cycles Per Instruction"), GTXT ("K_cycles/K_insts")); derived_metrics->add_definition (GTXT ("K_IPC"), GTXT ("Kernel Instructions Per Cycle"), GTXT ("K_insts/K_cycles")); } bool DbeView::set_libexpand (char *liblist, enum LibExpand flag) { bool changed = settings->set_libexpand (liblist, flag, false); // Show/hide performance optimization: // No need to call update_lo_expand for every library because dbev->set_libexpand() // is called from a loop in Dbe.cc SetLoadObjectState for every load object. // It is sufficient to call update_lo_expand() just once at the end of the loop. // At all other places such as er_print.cc which calls specific set_libexpand() // explicitly call update_lo_expands(); return changed; } bool DbeView::set_libdefaults () { bool changed = settings->set_libdefaults (); if (changed == true) update_lo_expands (); return changed; } void DbeView::update_lo_expands () { int index; LoadObject *lo; // search all load objects Vector *lobjs = dbeSession->get_text_segments (); Vec_loop (LoadObject*, lobjs, index, lo) { // now search the settings list for this one enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ()); set_lo_expand (lo->seg_idx, flag); } delete lobjs; } enum LibExpand DbeView::get_lo_expand (int idx) { if (idx < lo_expands->size ()) return lo_expands->get (idx); return LIBEX_SHOW; } bool DbeView::set_lo_expand (int idx, enum LibExpand flag) { // LIBRARY_VISIBILITY if (flag == LIBEX_HIDE) { resetShowAll (); dbeSession->set_lib_visibility_used (); } // if no change if (idx < lo_expands->size () && flag == get_lo_expand (idx)) return false; setShowHideChanged (); // this is necessary if called from er_print // change the flag lo_expands->store (idx, flag); // and reset the data fflush (stderr); purge_events (); reset_data (true); return true; } void DbeView::reset () { phaseIdx++; // reset all the per-experiment arrays filters->destroy (); lo_expands->reset (); free (cur_filter_str); cur_filter_str = NULL; free (prev_filter_str); prev_filter_str = NULL; delete cur_filter_expr; cur_filter_expr = NULL; noParFilter = false; for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id) { Vector *expDataViewList = dataViews->fetch (exp_id); if (expDataViewList) expDataViewList->destroy (); } dataViews->destroy (); reset_metrics (); // now reset any cached data reset_data (true); ompDisMode = false; showAll = true; showHideChanged = false; newViewMode = false; } void DbeView::reset_data (bool all) { // clear the precomputed data if (func_data != NULL) { delete func_data; func_data = NULL; } if (line_data != NULL) { delete line_data; line_data = NULL; } if (pc_data != NULL) { delete pc_data; pc_data = NULL; } if (src_data != NULL) { delete src_data; src_data = NULL; } if (dis_data != NULL) { delete dis_data; dis_data = NULL; } if (fitem_data != NULL) { delete fitem_data; fitem_data = NULL; } if (callers != NULL) { delete callers; callers = NULL; } if (callees != NULL) { delete callees; callees = NULL; } if (dobj_data != NULL) { delete dobj_data; dobj_data = NULL; } if (dlay_data != NULL) { delete dlay_data; dlay_data = NULL; } if (iofile_data != NULL) { delete iofile_data; iofile_data = NULL; } if (iovfd_data != NULL) { delete iovfd_data; iovfd_data = NULL; } if (iocs_data != NULL) { delete iocs_data; iocs_data = NULL; } if (heapcs_data != NULL) { delete heapcs_data; heapcs_data = NULL; } // and reset the selections if (all) { sel_obj = NULL; sel_dobj = NULL; lastSelInstr = NULL; lastSelFunc = NULL; // Set selected object if possible Function * ft = dbeSession->get_Total_Function (); set_sel_obj (ft); } sel_binctx = NULL; dspace->reset (); iospace->reset (); heapspace->reset (); // loop over MemorySpaces, resetting each one for (long i = 0, sz = VecSize (memspaces); i < sz; i++) { MemorySpace *ms = memspaces->get (i); ms->reset (); } // loop over IndexSpaces, resetting cached data indx_data->destroy (); for (long i = 0, sz = VecSize (indxspaces); i < sz; i++) { indx_data->store (i, NULL); sel_idxobj->store (i, NULL); } } Vector * DbeView::get_all_reg_metrics () { Vector *mlist = dbeSession->get_all_reg_metrics (); return mlist; } BaseMetric * DbeView::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec) { BaseMetric *bm = dbeSession->register_metric_expr (type, cmd, expr_spec); return bm; } Metric * DbeView::get_compare_metric (Metric *mtr, int groupNum) { if (groupNum == 0 || !mtr->comparable ()) return new Metric (*mtr); ExpGroup *gr = dbeSession->expGroups->get (groupNum - 1); char buf[128]; snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId); BaseMetric *bm = register_metric_expr (mtr->get_type (), mtr->get_cmd (), buf); Metric *m = new Metric (bm, mtr->get_subtype ()); m->set_raw_visbits (mtr->get_visbits ()); if (m->legend == NULL) m->legend = dbe_strdup (get_basename (gr->name)); return m; } MetricList * DbeView::get_metric_ref (MetricType mtype) { if (metrics_ref_lists->fetch (MET_COMMON) == NULL) { Vector *base_metrics = dbeSession->get_base_reg_metrics (); metrics_ref_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS)); metrics_ref_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON)); metrics_ref_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL)); metrics_ref_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL)); metrics_ref_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR)); metrics_ref_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA)); metrics_ref_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX)); metrics_ref_lists->store (MET_IO, new MetricList (base_metrics, MET_IO)); metrics_ref_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP)); delete base_metrics; } return metrics_ref_lists->fetch (mtype); } // logically, the function list must be created first, and it // will create the other two; MetricList * DbeView::get_metric_list (MetricType mtype) { if (metrics_lists->fetch (MET_COMMON) == NULL) { Vector *base_metrics = dbeSession->get_base_reg_metrics (); metrics_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS)); metrics_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON)); metrics_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL)); metrics_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL)); metrics_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR)); metrics_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA)); metrics_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX)); metrics_lists->store (MET_IO, new MetricList (base_metrics, MET_IO)); metrics_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP)); delete base_metrics; // set the defaults if (settings->str_dmetrics == NULL) settings->str_dmetrics = strdup (Command::DEFAULT_METRICS); char *status = setMetrics (settings->str_dmetrics, true); if (status != NULL) { fprintf (stderr, "XXX setMetrics(\"%s\") failed: %s\n", settings->str_dmetrics, status); abort (); } // set the default sort setSort (settings->str_dsort, MET_NORMAL, true); } return metrics_lists->fetch (mtype); } MetricList * DbeView::get_metric_list (int dsptype, int subtype) { MetricList *mlist; switch (dsptype) { case DSP_DISASM: case DSP_SOURCE: case DSP_SOURCE_DISASM: mlist = get_metric_list (MET_COMMON); mlist = new MetricList (mlist); if (subtype != 0) { for (long i = 0, sz = mlist->size (); i < sz; i++) { Metric *m = mlist->get (i); if (m->comparable ()) { Metric *m1 = get_compare_metric (m, subtype); mlist->put (i, m1); delete m; } } } break; default: mlist = get_metric_list (MET_NORMAL); mlist = new MetricList (mlist); break; } return mlist; } void DbeView::reset_metrics () { for (int i = 0, sz = metrics_lists->size (); i < sz; i++) { delete metrics_lists->fetch (i); metrics_lists->store (i, NULL); } for (int i = 0, sz = metrics_ref_lists->size (); i < sz; i++) { delete metrics_ref_lists->fetch (i); metrics_ref_lists->store (i, NULL); } } bool DbeView::comparingExperiments () { if (dbeSession->expGroups->size () <= 1) return false; return 0 != (settings->get_compare_mode () & (CMP_DELTA | CMP_ENABLE | CMP_RATIO)); } void DbeView::set_compare_mode (int mode) { if (mode == get_compare_mode ()) return; settings->set_compare_mode (mode); if (comparingExperiments ()) { Vector *bm_list = dbeSession->get_base_reg_metrics (); for (int i = 0, sz = bm_list->size (); i < sz; i++) { BaseMetric *m = bm_list->fetch (i); if (m->get_expr_spec () || !m->comparable ()) continue; for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++) { ExpGroup *gr = dbeSession->expGroups->fetch (i1); char buf[128]; snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId); register_metric_expr (m->get_type (), m->get_cmd (), buf); } } } MetricList *mlist = get_metric_list (MET_NORMAL); MetricList *gmlist = get_metric_list (MET_CALL); MetricList *dmlist = get_metric_list (MET_DATA); MetricList *imlist = get_metric_list (MET_INDX); if (comparingExperiments ()) { add_compare_metrics (mlist); add_compare_metrics (gmlist); add_compare_metrics (dmlist); add_compare_metrics (imlist); } else { remove_compare_metrics (mlist); remove_compare_metrics (gmlist); remove_compare_metrics (dmlist); remove_compare_metrics (imlist); } } void DbeView::ifreq (FILE *outfile) { if (!dbeSession->is_ifreq_available ()) { fprintf (outfile, GTXT ("No instruction frequency data available\n")); return; } for (int index = 0; index < filters->size (); index++) { Experiment *exp = dbeSession->get_exp (index); if (exp->broken || !get_exp_enable (index) || !exp->ifreqavail) continue; // this experiment has the data; print it fprintf (outfile, GTXT ("Instruction frequency data from experiment %s\n\n"), exp->get_expt_name ()); fprintf (outfile, NTXT ("%s"), pr_mesgs (exp->fetch_ifreq (), "", "")); } } // When adding multiple sub-experiments of an experiment, it is // not necessary to do the following every-time. It is sufficient to call reset_metrics() // and call get_metric_ref() and get_metric_list() in the end after all the sub-experiments // have been added void DbeView::add_experiment_epilogue () { bool flag_LIBEX_HIDE = false; bool flag_ShowHideChanged = false; Vector *lobjs = dbeSession->get_LoadObjects (); for (long i = lo_expands->size (), sz = lobjs ? lobjs->size () : 0; i < sz; i++) { flag_ShowHideChanged = true; LoadObject *lo = lobjs->get (i); enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ()); if (flag == LIBEX_HIDE) flag_LIBEX_HIDE = true; lo_expands->store (lo->seg_idx, flag); } if (flag_LIBEX_HIDE) { resetShowAll (); dbeSession->set_lib_visibility_used (); } if (flag_ShowHideChanged) { setShowHideChanged (); // this is necessary if called from er_print purge_events (); reset_data (true); } reset_metrics (); (void) get_metric_ref (MET_NORMAL); (void) get_metric_ref (MET_CALL); (void) get_metric_ref (MET_CALL_AGR); (void) get_metric_ref (MET_DATA); (void) get_metric_ref (MET_INDX); (void) get_metric_ref (MET_IO); (void) get_metric_ref (MET_HEAP); (void) get_metric_list (MET_NORMAL); (void) get_metric_list (MET_CALL); (void) get_metric_list (MET_CALL_AGR); (void) get_metric_list (MET_DATA); (void) get_metric_list (MET_INDX); (void) get_metric_list (MET_IO); (void) get_metric_list (MET_HEAP); } // When adding multiple sub-experiments of an experiment, avoid invoking the steps in // add_experiment_epilogue() every time and instead call it separately in the end // after all sub-experiments have been added void DbeView::add_subexperiment (int index, bool enabled) { // phaseIdx doesn't change, PathTree can handle adding // new experiments without reset // Set up the FilterSet for the experiments Experiment *exp = dbeSession->get_exp (index); FilterSet *filterset = new FilterSet (this, exp); filterset->set_enabled (enabled); filters->store (index, filterset); assert (index == dataViews->size ()); Vector *expDataViewList = new Vector; for (int data_id = 0; data_id < DATA_LAST; ++data_id) expDataViewList->append (NULL); //experiment data_id's are not known yet dataViews->store (index, expDataViewList); } void DbeView::add_experiment (int index, bool enabled) { // phaseIdx doesn't change, PathTree can handle adding // new experiments without reset // delete any cached data reset_data (true); // Set up the FilterSet for the experiments Experiment *exp = dbeSession->get_exp (index); FilterSet *filterset = new FilterSet (this, exp); filterset->set_enabled (enabled); filters->store (index, filterset); assert (index == dataViews->size ()); Vector *expDataViewList = new Vector; for (int data_id = 0; data_id < DATA_LAST; ++data_id) expDataViewList->append (NULL); //experiment data_id's are not known yet dataViews->store (index, expDataViewList); reset_metrics (); (void) get_metric_ref (MET_NORMAL); (void) get_metric_ref (MET_CALL); (void) get_metric_ref (MET_CALL_AGR); (void) get_metric_ref (MET_DATA); (void) get_metric_ref (MET_INDX); (void) get_metric_ref (MET_IO); (void) get_metric_ref (MET_HEAP); (void) get_metric_list (MET_NORMAL); (void) get_metric_list (MET_CALL); (void) get_metric_list (MET_CALL_AGR); (void) get_metric_list (MET_DATA); (void) get_metric_list (MET_INDX); (void) get_metric_list (MET_IO); (void) get_metric_list (MET_HEAP); } void DbeView::drop_experiment (int index) { phaseIdx++; filters->remove (index); // reset any cached data reset_data (true); Vector *expDataViewList = dataViews->remove (index); if (expDataViewList) { expDataViewList->destroy (); delete expDataViewList; } } bool DbeView::get_exp_enable (int n) { return filters ? filters->fetch (n)->get_enabled () : true; } void DbeView::set_exp_enable (int n, bool e) { FilterSet *fs = filters->fetch (n); if (fs->get_enabled () != e) { fs->set_enabled (e); purge_events (n); phaseIdx++; } } void DbeView::reset_metric_list (MetricList *mlist, int cmp_mode) { MetricType mtype = mlist->get_type (); switch (mtype) { case MET_NORMAL: case MET_COMMON: delete metrics_lists->fetch (MET_COMMON); metrics_lists->store (MET_COMMON, new MetricList (mlist)); remove_compare_metrics (metrics_lists->fetch (MET_COMMON)); break; // ignoring the following cases (why?) case MET_SRCDIS: case MET_CALL: case MET_DATA: case MET_INDX: case MET_CALL_AGR: case MET_IO: case MET_HEAP: break; } if (cmp_mode != -1) { settings->set_compare_mode (cmp_mode); if (comparingExperiments ()) add_compare_metrics (mlist); } switch (mtype) { case MET_NORMAL: delete metrics_lists->fetch (mtype); metrics_lists->store (mtype, mlist); // fall through to next case case MET_COMMON: metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist); metrics_lists->fetch (MET_CALL)->set_metrics (mlist); metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist); remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR)); metrics_lists->fetch (MET_DATA)->set_metrics (mlist); metrics_lists->fetch (MET_INDX)->set_metrics (mlist); metrics_lists->fetch (MET_IO)->set_metrics (mlist); metrics_lists->fetch (MET_HEAP)->set_metrics (mlist); break; case MET_CALL_AGR: delete metrics_lists->fetch (MET_CALL_AGR); metrics_lists->store (MET_CALL_AGR, mlist); remove_compare_metrics (mlist); break; case MET_SRCDIS: case MET_CALL: case MET_DATA: case MET_INDX: case MET_IO: case MET_HEAP: delete metrics_lists->fetch (mtype); metrics_lists->store (mtype, mlist); break; default: abort (); } reset_data (false); } void DbeView::add_compare_metrics (MetricList *mlist) { if (mlist == NULL || !comparingExperiments ()) return; int sort_ref_index = mlist->get_sort_ref_index (); Vector *items = mlist->get_items (); Vector *newItems = new Vector(); int mode = get_compare_mode (); int cmp_vbits = 0; if ((mode & CMP_DELTA) != 0) cmp_vbits = VAL_DELTA; else if ((mode & CMP_RATIO) != 0) cmp_vbits = VAL_RATIO; for (long i = 0, sz = items->size (); i < sz; i++) { Metric *mtr = items->get (i); if (sort_ref_index == i) mlist->set_sort_ref_index (newItems->size ()); int vbits = mtr->get_visbits () & ~(VAL_DELTA | VAL_RATIO); mtr->set_raw_visbits (vbits); if (!mtr->comparable ()) { newItems->append (mtr); continue; } if (mtr->get_expr_spec ()) { if (strcmp (mtr->get_expr_spec (), NTXT ("EXPGRID==1")) != 0) { if ((cmp_vbits & VAL_RATIO) != 0) // for ratios, make sure VAL_TIMEVAL is off and VAL_VALUE is on mtr->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL); else { int ind = mlist->get_listorder (mtr->get_cmd (), mtr->get_subtype (), NTXT ("EXPGRID==1")); if (ind >= 0) // take VAL_VALUE and VAL_TIMEVAL from base experiment mtr->set_raw_visbits (cmp_vbits | (vbits & ~(VAL_VALUE | VAL_TIMEVAL)) | (mlist->get (ind)->get_visbits () & (VAL_VALUE | VAL_TIMEVAL))); else mtr->set_raw_visbits (cmp_vbits | vbits); } } newItems->append (mtr); continue; } for (long i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++) { Metric *m = get_compare_metric (mtr, i1 + 1); switch (m->get_vtype ()) { case VT_LABEL: case VT_ADDRESS: case VT_OFFSET: m->set_raw_visbits (vbits); break; default: if (i1 == 0) m->set_raw_visbits (vbits); else if (cmp_vbits == VAL_RATIO && ((vbits & (VAL_VALUE | VAL_TIMEVAL)) == (VAL_VALUE | VAL_TIMEVAL))) // make ratios for VAL_VALUE only m->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL); else m->set_raw_visbits (vbits | cmp_vbits); break; } newItems->append (m); } } items->reset (); items->addAll (newItems); delete newItems; phaseIdx++; reset_data (false); } MetricList * DbeView::get_compare_mlist (MetricList *met_list, int grInd) { MetricList *mlist = new MetricList (met_list->get_type ()); mlist->set_sort_ref_index (met_list->get_sort_ref_index ()); mlist->set_sort_rev (met_list->get_sort_rev ()); Vector *items_old = met_list->get_items (); for (int i = 0, sz = items_old->size (); i < sz; i++) { Metric *m = get_compare_metric (items_old->get (i), grInd + 1); mlist->append (m); } return mlist; } void DbeView::remove_compare_metrics (MetricList *mlist) { Vector *items = mlist->get_items (); Vector *items_old = items->copy (); items->reset (); int sort_index = mlist->get_sort_ref_index (); mlist->set_sort_ref_index (0); for (int i = 0, sz = items_old->size (); i < sz; i++) { Metric *m = items_old->fetch (i); if (m->get_expr_spec () == NULL) { // this is a 'non-compare' metric; add it items->append (m); if (sort_index == i) mlist->set_sort_ref_index (items->size () - 1); continue; } // is the 'non-compare' version of the metric already in the list? int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype ()); if (ind == -1) { // not in the list; add it BaseMetric *bm = dbeSession->find_metric (m->get_type (), m->get_cmd (), NULL); Metric *new_met = new Metric (bm, m->get_subtype ()); new_met->set_raw_visbits (m->get_visbits () & ~(CMP_DELTA | CMP_RATIO)); items->append (new_met); if (sort_index == i) mlist->set_sort_ref_index (items->size () - 1); } delete m; } delete items_old; reset_data (false); } // setMetrics -- set the metric list according to specification // The previous sort is preserved, if possible // Otherwise, the default sort setting is used // Returns NULL if OK, or an error string if not //YXXX only MET_NORMAL appears to be used... code could be simplified char * DbeView::setMetrics (char *mspec, bool fromRcFile) { char *ret; MetricType mtype = MET_NORMAL; // note that setting the default is done here, while all else is in MetricList if (mspec == NULL) abort (); if (strcasecmp (mspec, Command::DEFAULT_CMD) == 0) { mspec = settings->get_default_metrics (); fromRcFile = true; } MetricList *mlist = get_metric_list (mtype); mlist = new MetricList (mlist); ret = mlist->set_metrics (mspec, fromRcFile, derived_metrics); if (ret == NULL) { switch (mtype) { case MET_NORMAL: case MET_COMMON: delete metrics_lists->fetch (MET_COMMON); metrics_lists->store (MET_COMMON, new MetricList (mlist)); break; // ignoring the following cases (why?) case MET_SRCDIS: case MET_CALL: case MET_DATA: case MET_INDX: case MET_CALL_AGR: case MET_IO: case MET_HEAP: break; } add_compare_metrics (mlist); //YXXX looks like cut/paste code here, see reset_metric_list() switch (mtype) { case MET_NORMAL: delete metrics_lists->fetch (mtype); metrics_lists->store (mtype, mlist); //YXXX is lack of break intentional? If so, add comment... case MET_COMMON: metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist); metrics_lists->fetch (MET_CALL)->set_metrics (mlist); metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist); remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR)); metrics_lists->fetch (MET_DATA)->set_metrics (mlist); metrics_lists->fetch (MET_INDX)->set_metrics (mlist); metrics_lists->fetch (MET_IO)->set_metrics (mlist); metrics_lists->fetch (MET_HEAP)->set_metrics (mlist); break; case MET_CALL_AGR: delete metrics_lists->fetch (MET_CALL_AGR); metrics_lists->store (MET_CALL_AGR, mlist); remove_compare_metrics (mlist); break; case MET_SRCDIS: case MET_CALL: case MET_DATA: case MET_INDX: case MET_IO: case MET_HEAP: delete metrics_lists->fetch (mtype); metrics_lists->store (mtype, mlist); break; default: abort (); } reset_data (false); } else delete mlist; return ret; } // Set Sort by name (er_print) char * DbeView::setSort (char * sort_list, MetricType mtype, bool fromRcFile) { MetricList *mlist = NULL; // note that setting the default is done here, while all else is in MetricList if ((sort_list == NULL) || (strcmp (sort_list, Command::DEFAULT_CMD) == 0)) { if (settings->str_dsort == NULL) settings->str_dsort = strdup (Command::DEFAULT_METRICS); sort_list = settings->get_default_sort (); } mlist = get_metric_list (mtype); if (mlist == NULL) abort (); // set the new sort char *ret = mlist->set_sort (sort_list, fromRcFile); if (ret != NULL) return ret; // now resort all cached data resortData (mtype); return NULL; } // Set sort from the visible index (Analyzer) void DbeView::setSort (int visindex, MetricType mtype, bool reverse) { MetricList *mlist = get_metric_list (mtype); Vector *items = mlist->get_items (); if (visindex >= items->size ()) return; mlist->set_sort (visindex, reverse); resortData (mtype); if (mtype == MET_NORMAL) { int idx_cc = -1; MetricList *mlist_cc = get_metric_list (MET_CALL); Vector *items_cc = mlist_cc->get_items (); for (int i = 0; i < items_cc->size (); i++) { char * name_cc = items_cc->fetch (i)->get_username (); char * name_normal = items->fetch (visindex)->get_username (); if (0 == strncmp (name_cc, name_normal, strlen (name_cc))) { idx_cc = i; break; } } if (idx_cc != -1) { mlist_cc->set_sort (idx_cc, reverse); resortData (MET_CALL); // Change a sort metric for MET_CALL_AGR Metric *m = items_cc->fetch (idx_cc); MetricList *cList = get_metric_list (MET_CALL_AGR); Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ()); if (m1) cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse); } } if (mtype == MET_CALL) { int idx_norm = -1; MetricList *mlist_norm = get_metric_list (MET_NORMAL); Vector *items_norm = mlist_norm->get_items (); for (int i = 0; i < items_norm->size (); i++) { char * name_norm = items_norm->fetch (i)->get_username (); char * name_cc = items->fetch (visindex)->get_username (); if (mlist_norm->get_sort_ref_index () == i && 0 == strncmp (name_norm, name_cc, strlen (name_norm))) { idx_norm = i; break; } } if (idx_norm == -1) { for (int i = 0; i < items_norm->size (); i++) { char * name_norm = items_norm->fetch (i)->get_username (); char * name_cc = items->fetch (visindex)->get_username (); if (0 == strncmp (name_norm, name_cc, strlen (name_norm))) { idx_norm = i; break; } } } if (idx_norm != -1) { mlist_norm->set_sort (idx_norm, reverse); resortData (MET_NORMAL); } // Change a sort metric for MET_CALL_AGR Metric *m = items->fetch (visindex); MetricList *cList = get_metric_list (MET_CALL_AGR); Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ()); if (m1) cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse); } } void DbeView::resortData (MetricType mtype) { int idx; Hist_data *data; MetricList *mlist = get_metric_list (mtype); switch (mtype) { case MET_NORMAL: if (func_data != NULL) func_data->resort (mlist); if (line_data != NULL) line_data->resort (mlist); if (pc_data != NULL) pc_data->resort (mlist); break; case MET_CALL: case MET_CALL_AGR: if (fitem_data != NULL) fitem_data->resort (mlist); if (callers != NULL) callers->resort (mlist); if (callees != NULL) callees->resort (mlist); break; case MET_DATA: if (dobj_data != NULL) dobj_data->resort (mlist); if (dlay_data != NULL) { delete dlay_data; dlay_data = NULL; } break; case MET_INDX: Vec_loop (Hist_data*, indx_data, idx, data) { if (data) data->resort (mlist); } break; case MET_IO: if (iofile_data != NULL) iofile_data->resort (mlist); if (iovfd_data != NULL) iovfd_data->resort (mlist); if (iocs_data != NULL) iocs_data->resort (mlist); break; case MET_HEAP: if (heapcs_data != NULL) heapcs_data->resort (mlist); break; case MET_COMMON: case MET_SRCDIS: break; } } // Get the sort metric name char * DbeView::getSort (MetricType mtype) { MetricList *mlist = get_metric_list (mtype); return mlist->get_sort_name (); } // Get the sort command (to use for resetting) char * DbeView::getSortCmd (MetricType mtype) { MetricList *mlist = get_metric_list (mtype); return mlist->get_sort_cmd (); } int DbeView::get_sel_ind (Histable *selObj, int type, int subtype) { Hist_data *data; switch (type) { case DSP_FUNCTION: data = func_data; break; case DSP_LINE: data = line_data; break; case DSP_PC: data = pc_data; break; case DSP_SOURCE: case DSP_SOURCE_V2: data = src_data; break; case DSP_DISASM: case DSP_DISASM_V2: data = dis_data; break; case DSP_DLAYOUT: data = dlay_data; break; case DSP_DATAOBJ: data = dobj_data; break; case DSP_IOACTIVITY: data = iofile_data; break; case DSP_IOVFD: data = iovfd_data; break; case DSP_IOCALLSTACK: data = iocs_data; break; case DSP_HEAPCALLSTACK: data = heapcs_data; break; case DSP_MEMOBJ: case DSP_INDXOBJ: data = get_indxobj_data (subtype); break; default: data = NULL; break; } if (data == NULL || data->get_status () != Hist_data::SUCCESS) return -1; Vector *hi_data = data->get_hist_items (); for (int i = 0, sz = hi_data->size (); i < sz; i++) { Hist_data::HistItem *hi = hi_data->fetch (i); if (hi->obj == selObj) return i; } return -1; } MetricList * DbeView::get_metric_list (MetricType mtype, bool compare, int gr_num) { MetricList *mlist; switch (mtype) { case MET_COMMON:// comparison mode, src & disasm views if (gr_num == 0) {// signifies same src file (or load obj) used by all groups // show compare metrics in columns (not in separate source panels) mlist = get_metric_list (MET_NORMAL); break; } // once source panel per group; get metrics for this group mlist = get_metric_list (mtype); if (compare) { mlist = get_compare_mlist (mlist, gr_num - 1); int mode = get_compare_mode (); if ((mode & (CMP_DELTA | CMP_RATIO)) != 0) { for (long i = 0, sz = mlist->size (); i < sz; i++) { Metric *m = mlist->get (i); char *expr_spec = m->get_expr_spec (); if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0)) { int vbits = m->get_visbits () & ~(VAL_DELTA | VAL_RATIO); if ((mode & CMP_RATIO) != 0) vbits |= VAL_RATIO; else if ((mode & CMP_DELTA) != 0) vbits |= VAL_DELTA; m->set_raw_visbits (vbits); } } } } break; default: mlist = get_metric_list (mtype); break; } return mlist; } Hist_data * DbeView::get_data (MetricList *mlist, Histable *selObj, int type, int subtype) { Hist_data *data; switch (type) { case DSP_FUNCTION: delete func_data; mlist = new MetricList (mlist); func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL); return func_data; case DSP_LINE: delete line_data; mlist = new MetricList (mlist); line_data = get_hist_data (mlist, Histable::LINE, subtype, Hist_data::ALL); return line_data; case DSP_PC: delete pc_data; mlist = new MetricList (mlist); pc_data = get_hist_data (mlist, Histable::INSTR, subtype, Hist_data::ALL); return pc_data; case DSP_DATAOBJ: delete dobj_data; dobj_data = get_hist_data (mlist, Histable::DOBJECT, subtype, Hist_data::ALL); break; case DSP_MEMOBJ: return get_hist_data (mlist, Histable::MEMOBJ, subtype, Hist_data::ALL); case DSP_INDXOBJ: data = get_hist_data (mlist, Histable::INDEXOBJ, subtype, Hist_data::ALL); indx_data->store (subtype, data); return data; case DSP_DLAYOUT: delete dlay_data; marks->reset (); data = get_hist_data (mlist, Histable::DOBJECT, subtype, Hist_data::LAYOUT); // .. provides metric data for layout dlay_data = get_data_space ()->get_layout_data (data, marks, get_thresh_dis ()); return dlay_data; case DSP_CALLER: delete callers; callers = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::CALLERS, selObj); return callers; case DSP_CALLEE: delete callees; callees = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::CALLEES, selObj); return callees; case DSP_SELF: // Center Function item delete fitem_data; fitem_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::SELF, selObj); return fitem_data; case DSP_SOURCE_V2: case DSP_DISASM_V2: case DSP_SOURCE: case DSP_DISASM: { // Source or disassembly if (selObj == NULL) { error_msg = status_str (DBEVIEW_NO_SEL_OBJ); return NULL; } Function *func = (Function *) selObj->convertto (Histable::FUNCTION); if (func == NULL) { error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available.")); return NULL; } if (func->flags & FUNC_FLAG_SIMULATED) { error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available.")); return NULL; } if (func->get_name () == NULL) { error_msg = dbe_strdup (GTXT ("Source location not recorded in experiment")); return NULL; } Module *module = func->module; if (module == NULL || module->get_name () == NULL) { error_msg = dbe_strdup (GTXT ("Object name not recorded in experiment")); return NULL; } marks->reset (); SourceFile *srcContext = (SourceFile *) selObj->convertto (Histable::SOURCEFILE); sel_binctx = func; if (func_data == NULL) func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL); // for source and disassembly the name needs to be invisible, // but that's handled in the module code if (type == DSP_SOURCE || type == DSP_SOURCE_V2) { marks2dsrc->reset (); marks2dsrc_inc->reset (); delete src_data; data = src_data = module->get_data (this, mlist, Histable::LINE, func_data->get_totals ()->value, srcContext, func, marks, get_thresh_src (), get_src_compcom (), get_src_visible (), get_hex_visible (), false, false, marks2dsrc, marks2dsrc_inc); } else { /* type == DSP_DISASM */ marks2ddis->reset (); marks2ddis_inc->reset (); delete dis_data; data = dis_data = module->get_data (this, mlist, Histable::INSTR, func_data->get_totals ()->value, srcContext, func, marks, get_thresh_dis (), get_dis_compcom (), get_src_visible (), get_hex_visible (), get_func_scope (), false, marks2ddis, marks2ddis_inc); } return data; } default: abort (); } return NULL; } Histable * DbeView::get_compare_obj (Histable *obj) { char *nm; switch (obj->get_type ()) { case Histable::LINE: nm = obj->get_name (); if (nm == NULL) break; if (dbeSession->comp_dbelines == NULL) dbeSession->comp_dbelines = new HashMap; return dbeSession->comp_dbelines->get (nm, (DbeLine*) obj); case Histable::SOURCEFILE: nm = obj->get_name (); if (nm == NULL) break; nm = get_basename (nm); if (dbeSession->comp_sources == NULL) dbeSession->comp_sources = new HashMap; return dbeSession->comp_sources->get (nm, (SourceFile*) obj); default: return obj->get_compare_obj (); } return obj; } // // get_hist_data() creates a new Hist_data object; // it's caller's responsibility to delete it. Hist_data * DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type, int subtype, Hist_data::Mode mode, Histable *obj, Histable *context, Vector *sel_objs, PathTree::PtreeComputeOption flag) { Vector *objs = NULL; if (obj != NULL) { objs = new Vector(); objs->append (obj); } Hist_data *res = get_hist_data (mlist_orig, type, subtype, mode, objs, context, sel_objs, flag); delete objs; return res; } Hist_data * DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type, int subtype, Hist_data::Mode mode, Vector *objs, Histable *context, Vector *sel_objs, PathTree::PtreeComputeOption flag) { MetricList *mlist = new MetricList (mlist_orig); /* * mlist differs from mlist_orig in two ways: * - extra metrics have been added as needed to compute derived metrics * - extra metrics have been added as needed to compute time for HWC (time converted) metrics * (We don't drop those extra metrics but we don't display they to user.) * - visibility bits have been added for compare mode (e.g., VAL_DELTA or VAL_RATIO) * (We want to preserve those visbits.) */ // loop over mlist to add missing dependencies for derived metrics for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++) { Metric *m = mlist->get_items ()->fetch (i); char *expr_spec = m->get_expr_spec (); if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0)) { int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype (), NTXT ("EXPGRID==1")); if (ind < 0) { BaseMetric *bm1 = dbeSession->find_metric (m->get_type (), m->get_cmd (), NTXT ("EXPGRID==1")); Metric *m1 = new Metric (bm1, m->get_subtype ()); m1->set_dmetrics_visbits (VAL_VALUE); mlist->append (m1); } } } for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++) { Metric *m = mlist->get_items ()->fetch (i); if (m->get_type () == BaseMetric::DERIVED) { Definition *def = m->get_definition (); Vector *dependencies = def->get_dependencies (); long *map = def->get_map (); for (long i1 = 0, sz1 = dependencies ? dependencies->size () : 0; i1 < sz1; i1++) { BaseMetric *bm = dependencies->fetch (i1); int ind = mlist->get_listorder (bm->get_cmd (), m->get_subtype (), m->get_expr_spec ()); if (ind < 0) { BaseMetric *bm1 = dbeSession->find_metric (bm->get_type (), bm->get_cmd (), m->get_expr_spec ()); assert (bm1 != NULL); Metric *m1 = new Metric (bm1, m->get_subtype ()); m1->set_dmetrics_visbits (VAL_VALUE); ind = mlist->size (); mlist->append (m1); } map[i1] = ind; } } else if (m->get_type () == BaseMetric::HWCNTR) { if (m->is_tvisible () && m->get_dependent_bm ()) { int ii = mlist->get_listorder (m->get_dependent_bm ()->get_cmd (), m->get_subtype (), m->get_expr_spec ()); if (ii < 0) { BaseMetric *bm1 = dbeSession->find_metric (m->get_type (), m->get_dependent_bm ()->get_cmd (), m->get_expr_spec ()); assert (bm1 != NULL); Metric *m1 = new Metric (bm1, m->get_subtype ()); m1->set_dmetrics_visbits ((m->get_visbits () & ~VAL_VALUE) | VAL_TIMEVAL); mlist->append (m1); } } } } // compute Hist_data Hist_data *data; switch (type) { case Histable::INSTR: case Histable::LINE: data = ptree->compute_metrics (mlist, type, mode, objs, context, sel_objs); break; case Histable::FUNCTION: case Histable::MODULE: case Histable::LOADOBJECT: data = ptree->compute_metrics (mlist, type, mode, objs, NULL, sel_objs, flag); break; case Histable::DOBJECT: data = dspace->compute_metrics (mlist, type, mode, objs ? objs->fetch (0) : NULL); break; case Histable::MEMOBJ: case Histable::INDEXOBJ: data = indxspaces->get (subtype)->compute_metrics (mlist, type, mode, objs, NULL); break; case Histable::IOACTFILE: if (objs == NULL) { data = iofile_data = iospace->compute_metrics (mlist, type, mode, NULL); break; } else { data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0)); break; } case Histable::IOACTVFD: if (objs == NULL) data = iovfd_data = iospace->compute_metrics (mlist, type, mode, NULL); else data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0)); break; case Histable::IOCALLSTACK: if (objs == NULL) data = iocs_data = iospace->compute_metrics (mlist, type, mode, NULL); else data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0)); break; case Histable::HEAPCALLSTACK: if (objs == NULL) data = heapcs_data = heapspace->compute_metrics (mlist, type, mode, NULL); else data = heapspace->compute_metrics (mlist, type, mode, objs->fetch (0)); break; default: data = NULL; break; } for (long i = mlist_orig->get_items ()->size (), sz = mlist->get_items ()->size (); i < sz; i++) { Metric *m = mlist->get_items ()->get (i); m->set_dmetrics_visbits (VAL_HIDE_ALL | m->get_visbits ()); } if (data) data->nmetrics = mlist_orig->size (); return data; } char * DbeView::get_mobj_name (int subtype) { MemorySpace *ms = getMemorySpace (subtype); if (ms == NULL) ms = addMemorySpace (subtype); return ms->getMemObjTypeName (); } MemorySpace * DbeView::getMemorySpace (int subtype) { for (long i = 0, sz = VecSize (memspaces); i < sz; i++) { MemorySpace *ms = memspaces->get (i); if (subtype == ms->getMemObjType ()) return ms; } return NULL; } MemorySpace * DbeView::addMemorySpace (int subtype) { MemorySpace *ms = new MemorySpace (this, subtype); memspaces->append (ms); return ms; } Hist_data * DbeView::get_indxobj_data (int subtype) { if (subtype < 0 || subtype >= indx_data->size ()) return NULL; return indx_data->fetch (subtype); } void DbeView::set_indxobj_sel (int subtype, int sel_ind) { Hist_data *data = get_indxobj_data (subtype); if (data == NULL) return; if (sel_ind >= 0 && sel_ind < data->size ()) { Histable *obj = data->fetch (sel_ind)->obj; sel_idxobj->store (subtype, obj); } } Histable * DbeView::get_indxobj_sel (int subtype) { return sel_idxobj->fetch (subtype); } void DbeView::addIndexSpace (int subtype) { PathTree *is = new PathTree (this, subtype); indxspaces->store (subtype, is); indx_data->store (subtype, NULL); sel_idxobj->store (subtype, NULL); settings->indxobj_define (subtype, false); } Histable * DbeView::get_sel_obj_io (uint64_t id, Histable::Type type) { if (iospace == NULL) return NULL; Histable *obj = NULL; Hist_data *data = NULL; switch (type) { case Histable::IOACTFILE: data = iofile_data; break; case Histable::IOACTVFD: data = iovfd_data; break; case Histable::IOCALLSTACK: data = iocs_data; break; default: break; } if (data == NULL) return NULL; Vector *hi_data = data->get_hist_items (); int size = hi_data->size (); for (int i = 0; i < size; i++) { Hist_data::HistItem *hi = hi_data->fetch (i); if (hi->obj != NULL && (uint64_t) hi->obj->id == id) { obj = hi->obj; break; } } return obj; } Histable * DbeView::get_sel_obj_heap (uint64_t id) { if (heapspace == NULL || heapcs_data == NULL) return NULL; Histable *obj = NULL; Hist_data *data = heapcs_data; Vector *hi_data = data->get_hist_items (); int size = hi_data->size (); for (int i = 0; i < size; i++) { Hist_data::HistItem *hi = hi_data->fetch (i); if ((hi->obj != NULL) && ((uint64_t) hi->obj->id) == id) { obj = hi->obj; break; } } return obj; } CStack_data * DbeView::get_cstack_data (MetricList *mlist) { return ptree->get_cstack_data (mlist); } Stats_data * DbeView::get_stats_data (int index) { DataView *packets = get_filtered_events (index, DATA_SAMPLE); if (packets == NULL) return NULL; return new Stats_data (packets); } Ovw_data * DbeView::get_ovw_data (int index) { DataView *packets = get_filtered_events (index, DATA_SAMPLE); Experiment* exp = dbeSession->get_exp (index); hrtime_t starttime = 0; if (exp != NULL) starttime = exp->getStartTime (); if (packets == NULL) return NULL; return new Ovw_data (packets, starttime); } char * DbeView::set_filter (const char *filter_spec) { if (dbe_strcmp (filter_spec, cur_filter_str) == 0) // Nothing was changed return NULL; // if string is NULL, delete the filter if (filter_spec == NULL) { if (cur_filter_str) { free (cur_filter_str); cur_filter_str = NULL; } if (cur_filter_expr) { delete cur_filter_expr; cur_filter_expr = NULL; } noParFilter = false; purge_events (); reset_data (false); return NULL; } // process the filter Expression *expr = dbeSession->ql_parse (filter_spec); if (expr == NULL) return dbe_sprintf (GTXT ("Invalid filter specification `%s'\n"), filter_spec); if (dbe_strcmp (filter_spec, "1") == 0) noParFilter = false; else if (sel_obj != NULL) if (sel_obj->get_type () == Histable::LINE) if (expr->verifyObjectInExpr (sel_obj)) noParFilter = true; // valid new filter if (cur_filter_str != NULL) { free (prev_filter_str); prev_filter_str = dbe_strdup (cur_filter_str); } free (cur_filter_str); cur_filter_str = dbe_strdup (filter_spec); delete cur_filter_expr; cur_filter_expr = expr; purge_events (); reset_data (false); return NULL; } FilterExp * DbeView::get_FilterExp (Experiment *exp) { if (cur_filter_expr == NULL) return NULL; Expression::Context *ctx = new Expression::Context (this, exp); return new FilterExp (cur_filter_expr, ctx, noParFilter); } char * DbeView::get_filter () { return dbe_strdup (cur_filter_str); } FilterSet * DbeView::get_filter_set (int n) { fflush (stderr); if (n >= filters->size ()) return NULL; return ( filters->fetch (n)); } Vector * DbeView::get_all_filters (int nexp) { FilterSet *fs = get_filter_set (nexp); return fs ? fs->get_all_filters () : NULL; } FilterNumeric * DbeView::get_FilterNumeric (int nexp, int idx) { FilterSet *fs = get_filter_set (nexp); return fs ? fs->get_filter (idx) : NULL; } void DbeView::backtrack_filter() { if (prev_filter_str != NULL) set_filter(prev_filter_str); else set_filter("1"); // reset } void DbeView::update_advanced_filter () { char *s = get_advanced_filter (); if (dbe_strcmp (s, cur_filter_str)) { phaseIdx++; char *err_msg = set_filter (s); if (err_msg) { #ifdef DEBUG fprintf (stderr, NTXT ("ERROR: Advanced Filter: '%s'\n"), err_msg); #endif } } free (s); } bool DbeView::set_pattern (int n, Vector *pattern_str, bool *error) { Vector *filts = get_all_filters (n); bool ret = false; *error = false; int imax = pattern_str->size (); if (imax > filts->size ()) imax = filts->size (); for (int i = 0; i < imax; i++) { FilterNumeric *f = filts->fetch (i); char *s = pattern_str->fetch (i); if (s == NULL) continue; if (f->set_pattern (s, error)) ret = true; } if (ret || cur_filter_expr) { update_advanced_filter (); filter_active = true; } return ret; } static void append_experiments (StringBuilder *sb, int first, int last) { if (first == -1) return; if (sb->length () != 0) sb->append (NTXT (" || ")); sb->append ('('); if (first == last) { sb->append (NTXT ("EXPID==")); sb->append (first); } else { sb->append (NTXT ("EXPID>=")); sb->append (first); sb->append (NTXT (" && EXPID<=")); sb->append (last); } sb->append (')'); } char * DbeView::get_advanced_filter () { StringBuilder sb; bool wasFalse = false; int first = -1, last = -1; for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++) { FilterSet *fs = get_filter_set (n); char *s = fs->get_advanced_filter (); if (s) { if (streq (s, NTXT ("1"))) { last = n + 1; if (first == -1) first = last; continue; } append_experiments (&sb, first, last); first = -1; if (streq (s, NTXT ("0"))) { wasFalse = true; continue; } if (sb.length () != 0) sb.append (NTXT (" || ")); sb.append (NTXT ("(EXPID==")); sb.append (n + 1); sb.append (NTXT (" && (")); sb.append (s); free (s); sb.append (NTXT ("))")); } else { last = n + 1; if (first == -1) first = last; } } if (first != 1) { append_experiments (&sb, first, last); first = -1; } if (sb.length () == 0) sb.append (wasFalse ? '0' : '1'); else append_experiments (&sb, first, last); return sb.toString (); } bool DbeView::set_pattern (int m, char *pattern) { bool error = false; // Store original setting in case of error int nexps = dbeSession->nexps (); int orig_phaseIdx = phaseIdx; bool *orig_enable = new bool[nexps]; char **orig_pattern = new char*[nexps]; for (int i = 0; i < nexps; i++) { orig_pattern[i] = get_FilterNumeric (i, m)->get_pattern (); orig_enable[i] = get_exp_enable (i); set_exp_enable (i, false); } // Copy the pattern so that we could safely modify it char *buf = dbe_strdup (pattern); FilterNumeric *fexp = NULL; char *pb, *pe; pb = pe = buf; for (bool done = false; !done; pe++) { if (*pe == ':') { // experiment filter; *pe = '\0'; fexp = new FilterNumeric (NULL, NULL, NULL); fexp->set_range (1, nexps, nexps); fexp->set_pattern (pb, &error); if (error) break; pb = pe + 1; } else if (*pe == '+' || *pe == '\0') { // entity filter if (*pe == '\0') done = true; else *pe = '\0'; for (int i = 0; i < nexps; i++) { if (!fexp || fexp->is_selected (i + 1)) { FilterNumeric *f = get_FilterNumeric (i, m); f->set_pattern (pb, &error); if (error) break; set_exp_enable (i, true); } } if (error) break; delete fexp; fexp = NULL; pb = pe + 1; } } if (error) { for (int i = 0; i < nexps; i++) { bool err; set_exp_enable (i, orig_enable[i]); FilterNumeric *f = get_FilterNumeric (i, m); f->set_pattern (orig_pattern[i], &err); free (orig_pattern[i]); } phaseIdx = orig_phaseIdx; } else { update_advanced_filter (); filter_active = true; } delete[] orig_enable; delete[] orig_pattern; delete fexp; free (buf); return !error; } void DbeView::set_view_mode (VMode newmode) { if (newmode != settings->get_view_mode ()) { // For OpenMP, the expert mode path-tree is already present with the user mode // No need to increase the phaseIdx to trigger recomputation of path-tree // if we toggle between user and expert modes if (!(dbeSession->is_omp_available () && ((newmode == VMODE_EXPERT && settings->get_view_mode () == VMODE_USER) || (newmode == VMODE_USER && settings->get_view_mode () == VMODE_EXPERT)))) phaseIdx++; // For all other cases setNewViewMode (); settings->set_view_mode (newmode); } } Cmd_status DbeView::set_view_mode (char *str, bool fromRC) { VMode old = settings->get_view_mode (); Cmd_status ret = settings->set_view_mode (str, fromRC); if (old != settings->get_view_mode ()) phaseIdx++; return ret; } Cmd_status DbeView::set_en_desc (char *str, bool fromRC) { // Tell the session Settings *s = dbeSession->get_settings (); s->set_en_desc (str, fromRC); // and tell our settings return settings->set_en_desc (str, fromRC); } // Get processor stats messages char * DbeView::get_processor_msg (int type) { if (ptree == NULL) // if no PathTree, no messages return NULL; StringBuilder sb; Emsg *m = (type == PSTAT_MSG) ? ptree->fetch_stats () : ptree->fetch_warnings (); for (; m != NULL; m = m->next) { char* newmsg = m->get_msg (); sb.append (newmsg); sb.append ("\n"); } if (type == PSTAT_MSG) ptree->delete_stats (); else ptree->delete_warnings (); return (sb.length () > 0) ? sb.toString () : NULL; } void DbeView::dump_nodes (FILE *outfile) { FILE *f = (outfile == NULL ? stderr : outfile); ptree->print (f); } // Dump the clock profile events void DbeView::dump_profile (FILE *out_file) { for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); VMode view_mode = get_view_mode (); char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS; // Process clock profile date DataView *packets = get_filtered_events (idx, DATA_CLOCK); if (packets && packets->getSize () != 0) { hrtime_t start = exp->getStartTime (); fprintf (out_file, GTXT ("\nTotal Clock Profiling Packets: %d Experiment: %s\n"), (int) packets->getSize (), exp->get_expt_name ()); for (long i = 0; i < packets->getSize (); i++) { hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i); hrtime_t ts = expr_ts - start; // get the properties from the packet uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i); uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i); int mstate = (int) packets->getIntValue (PROP_MSTATE, i); int nticks = (int) packets->getIntValue (PROP_NTICK, i); char *sname; char buf[1024]; if (mstate >= 0 && mstate < LMS_NUM_STATES) sname = stateNames[mstate]; else { snprintf (buf, sizeof (buf), NTXT ("Unexpected mstate = %d"), mstate); sname = buf; } // get the stack IGNORE HIDE Vector *stack = getStackPCs (view_mode, packets, i); int stack_size = stack->size (); // print the packet header with the count of stack frames fprintf (out_file, GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"), i, expr_ts, ts / NANOSEC, ts % NANOSEC, expr_ts / NANOSEC, expr_ts % NANOSEC, thrid, cpuid, stack_size); fprintf (out_file, GTXT (" mstate = %d (%s), nticks = %d\n"), mstate, sname, nticks); // dump the callstack for (int j = stack_size - 1; j >= 0; j--) { Histable *frame = stack->fetch (j); fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame); } fprintf (out_file, "\n"); } } else fprintf (out_file, GTXT ("\nNo Clock Profiling Packets in Experiment: %s\n"), exp->get_expt_name ()); } } // Dump the sync trace events void DbeView::dump_sync (FILE *out_file) { for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); VMode view_mode = get_view_mode (); // Process heap trace date DataView *packets = get_filtered_events (idx, DATA_SYNCH); if (packets && packets->getSize () != 0) { hrtime_t start = exp->getStartTime (); fprintf (out_file, GTXT ("\nTotal Synctrace Packets: %d Experiment: %s\n"), (int) packets->getSize (), exp->get_expt_name ()); for (long i = 0; i < packets->getSize (); i++) { hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i); hrtime_t ts = expr_ts - start; // get the properties from the packet uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i); uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i); uint64_t syncobj = (uint64_t) packets->getLongValue (PROP_SOBJ, i); hrtime_t syncrtime = (uint64_t) packets->getLongValue (PROP_SRQST, i); hrtime_t syncdelay = expr_ts - syncrtime; // get the stack IGNORE HIDE Vector *stack = getStackPCs (view_mode, packets, i); int stack_size = stack->size (); // print the packet header with the count of stack frames fprintf (out_file, GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"), i, expr_ts, ts / NANOSEC, ts % NANOSEC, expr_ts / NANOSEC, expr_ts % NANOSEC, thrid, cpuid, stack_size); fprintf (stderr, GTXT (" synchronization object @ 0x%016llx; synchronization delay %3lld.%09lld\n"), (unsigned long long) syncobj, (long long) (syncdelay / NANOSEC), (long long) (syncdelay % NANOSEC)); // dump the callstack for (int j = stack_size - 1; j >= 0; j--) { Histable *frame = stack->fetch (j); fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame); } fprintf (out_file, "\n"); } } else fprintf (out_file, GTXT ("\nNo Synctrace Packets in Experiment: %s\n"), exp->get_expt_name ()); } } // Dump the IO trace events void DbeView::dump_iotrace (FILE *out_file) { for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); VMode view_mode = get_view_mode (); // Process IO trace date DataView *packets = get_filtered_events (idx, DATA_IOTRACE); if (packets && packets->getSize () != 0) { hrtime_t start = exp->getStartTime (); fprintf (out_file, GTXT ("\nTotal IO trace Packets: %d Experiment: %s\n"), (int) packets->getSize (), exp->get_expt_name ()); for (long i = 0; i < packets->getSize (); i++) { hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i); hrtime_t ts = expr_ts - start; // get the properties from the packet uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i); uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i); IOTrace_type iotrtype = (IOTrace_type) packets->getIntValue (PROP_IOTYPE, i); uint32_t iofd = (uint32_t) packets->getIntValue (PROP_IOFD, i); uint64_t ionbyte = (uint64_t) packets->getIntValue (PROP_IONBYTE, i); hrtime_t iorqst = (hrtime_t) packets->getLongValue (PROP_IORQST, i); uint32_t ioofd = (uint32_t) packets->getIntValue (PROP_IOOFD, i); FileSystem_type iofstype = (FileSystem_type) packets->getIntValue (PROP_CPUID, i); int64_t iovfd = (int64_t) packets->getIntValue (PROP_IOVFD, i); char *fName = NULL; StringBuilder *sb = (StringBuilder*) packets->getObjValue (PROP_IOFNAME, i); if (sb != NULL && sb->length () > 0) fName = sb->toString (); // get the stack IGNORE HIDE Vector *stack = getStackPCs (view_mode, packets, i); int stack_size = stack->size (); const char *iotrname; switch (iotrtype) { case READ_TRACE: iotrname = "ReadTrace"; break; case WRITE_TRACE: iotrname = "WriteTrace"; break; case OPEN_TRACE: iotrname = "OpenTrace"; break; case CLOSE_TRACE: iotrname = "CloseTrace"; break; case OTHERIO_TRACE: iotrname = "OtherIOTrace"; break; case READ_TRACE_ERROR: iotrname = "ReadTraceError"; break; case WRITE_TRACE_ERROR: iotrname = "WriteTraceError"; break; case OPEN_TRACE_ERROR: iotrname = "OpenTraceError"; break; case CLOSE_TRACE_ERROR: iotrname = "CloseTraceError"; break; case OTHERIO_TRACE_ERROR: iotrname = "OtherIOTraceError"; break; default: iotrname = "UnknownIOTraceType"; break; } // print the packet header with the count of stack frames fprintf (out_file, GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"), i, expr_ts, ts / NANOSEC, ts % NANOSEC, expr_ts / NANOSEC, expr_ts % NANOSEC, thrid, cpuid, stack_size); fprintf (out_file, GTXT (" %s: fd = %d, ofd = %d, vfd = %lld, fstype = %d, rqst = %3lld.%09lld\n"), iotrname, (int) iofd, (int) ioofd, (long long) iovfd, (int) iofstype, (long long) (iorqst / NANOSEC), (long long) (iorqst % NANOSEC)); fprintf (out_file, GTXT (" filename = `%s', nbytes = %d\n"), STR (fName), (int) ionbyte); free (fName); // dump the callstack for (int j = stack_size - 1; j >= 0; j--) { Histable *frame = stack->fetch (j); fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame); } fprintf (out_file, "\n"); } } else fprintf (out_file, GTXT ("\nNo IO trace Packets in Experiment: %s\n"), exp->get_expt_name ()); } } // Dump the HWC Profiling events void DbeView::dump_hwc (FILE *out_file) { for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); VMode view_mode = get_view_mode (); // Dump HWC profiling data DataView *packets = get_filtered_events (idx, DATA_HWC); if (packets && packets->getSize () != 0) { hrtime_t start = exp->getStartTime (); fprintf (out_file, GTXT ("\nTotal HW Counter Profiling Packets: %d Experiment: %s\n"), (int) packets->getSize (), exp->get_expt_name ()); for (long i = 0; i < packets->getSize (); i++) { const char * hwc_name; hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i); hrtime_t ts = expr_ts - start; uint32_t tag = (uint32_t) packets->getIntValue (PROP_HWCTAG, i); uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i); uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i); // This will work even with a different counter in every packet. if (tag < 0 || tag >= MAX_HWCOUNT || !exp->coll_params.hw_aux_name[tag]) // if the packet has an invalid tag, use as its name hwc_name = ""; else hwc_name = exp->coll_params.hw_aux_name[tag]; int64_t mval = packets->getLongValue (PROP_HWCINT, i); const char *err = HWCVAL_HAS_ERR (mval) ? " $$" : ""; // get the stack IGNORE HIDE Vector *stack = getStackPCs (view_mode, packets, i); int stack_size = stack->size (); // print the packet header with the count of stack frames fprintf (out_file, GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n count = %10lld (0x%016llx), tag = %d (%s)%s\n"), (long) i, (long long) expr_ts, (long long) (ts / NANOSEC), (long long) (ts % NANOSEC), (long long) (expr_ts / NANOSEC), (long long) (expr_ts % NANOSEC), (int) thrid, (int) cpuid, (int) stack_size, (long long) (HWCVAL_CLR_ERR (mval)), (long long) mval, (int) tag, hwc_name, err); // dump extended HWC packets values uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i); uint64_t pa = (uint64_t) packets->getLongValue (PROP_PADDR, i); fprintf (out_file, GTXT (" va = 0x%016llx, pa = 0x%016llx\n"), (unsigned long long) va, (unsigned long long) pa); // dump the callstack for (int j = stack_size - 1; j >= 0; j--) { Histable *frame = stack->fetch (j); fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame); } fprintf (out_file, "\n"); } } else fprintf (out_file, GTXT ("\nNo HWC Profiling Packets in Experiment: %s\n"), exp->get_expt_name ()); } } // Dump the Heap events void DbeView::dump_heap (FILE *out_file) { char *heapstrings[] = HEAPTYPE_STATE_USTRINGS; for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); VMode view_mode = get_view_mode (); // Process heap trace date DataView *packets = get_filtered_events (idx, DATA_HEAP); if (packets && packets->getSize () != 0) { hrtime_t start = exp->getStartTime (); fprintf (out_file, GTXT ("\nTotal Heaptrace Packets: %d Experiment: %s\n"), (int) packets->getSize (), exp->get_expt_name ()); for (long i = 0; i < packets->getSize (); i++) { hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i); hrtime_t ts = expr_ts - start; // get the properties from the packet uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i); uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i); uint32_t heaptype = (uint32_t) packets->getIntValue (PROP_HTYPE, i); uint64_t heapsize = (uint64_t) packets->getULongValue (PROP_HSIZE, i); uint64_t heapvaddr = (uint64_t) packets->getULongValue (PROP_HVADDR, i); uint64_t heapovaddr = (uint64_t) packets->getULongValue (PROP_HOVADDR, i); if (heaptype == MUNMAP_TRACE) { heapsize = (uint64_t) packets->getULongValue (PROP_HOVADDR, i); heapovaddr = 0; } // get the stack IGNORE HIDE Vector *stack = getStackPCs (view_mode, packets, i); int stack_size = stack->size (); // print the packet header with the count of stack frames fprintf (out_file, GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"), i, expr_ts, ts / NANOSEC, ts % NANOSEC, expr_ts / NANOSEC, expr_ts % NANOSEC, thrid, cpuid, stack_size); char *typestr = heapstrings[heaptype]; fprintf (out_file, GTXT (" type = %d (%s), size = %llu (0x%llx), VADDR = 0x%016llx, OVADDR = 0x%016llx\n"), (int) heaptype, typestr, (long long unsigned int) heapsize, (long long unsigned int) heapsize, (long long unsigned int) heapvaddr, (long long unsigned int) heapovaddr); // dump the callstack for (int j = stack_size - 1; j >= 0; j--) { Histable *frame = stack->fetch (j); fprintf (out_file, GTXT (" %s [0x%016llx]\n"), frame->get_name (), (long long) frame); } fprintf (out_file, "\n"); } } else fprintf (out_file, GTXT ("\nNo Heaptrace Packets in Experiment: %s\n"), exp->get_expt_name ()); } } // Dump the Java garbage collector events void DbeView::dump_gc_events (FILE *out_file) { for (int idx = 0; idx < dbeSession->nexps (); idx++) { Experiment *exp = dbeSession->get_exp (idx); if (!exp->has_java) fprintf (out_file, GTXT ("# No GC events in experiment %d, %s (PID %d, %s)\n"), idx, exp->get_expt_name (), exp->getPID (), exp->utargname); else { Vector *gce = exp->get_gcevents (); GCEvent *this_event; int index; fprintf (out_file, GTXT ("# %li events in experiment %d: %s (PID %d, %s)\n"), gce->size (), idx, exp->get_expt_name (), exp->getPID (), exp->utargname); fprintf (out_file, GTXT ("# exp:idx GC_start, GC_end, GC_duration\n")); Vec_loop (GCEvent*, gce, index, this_event) { hrtime_t start = this_event->start - exp->getStartTime (); hrtime_t end = this_event->end - exp->getStartTime (); hrtime_t delta = this_event->end - this_event->start; fprintf (out_file, "%5d:%d, %3lld.%09lld, %3lld.%09lld, %3lld.%09lld\n", idx, index, (long long) (start / NANOSEC), (long long) (start % NANOSEC), (long long) (end / NANOSEC), (long long) (end % NANOSEC), (long long) (delta / NANOSEC), (long long) (delta % NANOSEC)); } } } } void DbeView::purge_events (int n) { phaseIdx++; int lst; if (n == -1) lst = filters->size (); else lst = n > filters->size () ? filters->size () : n + 1; for (int i = n == -1 ? 0 : n; i < lst; i++) { Vector *expDataViewList = dataViews->fetch (i); if (expDataViewList) { // clear out all the data_ids, but don't change the vector size for (int data_id = 0; data_id < expDataViewList->size (); ++data_id) { delete expDataViewList->fetch (data_id); expDataViewList->store (data_id, NULL); } } } filter_active = false; } // LIBRARY_VISIBILITY void DbeView::resetAndConstructShowHideStacks () { for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++) { Experiment *exp = dbeSession->get_exp (n); if (exp != NULL) resetAndConstructShowHideStack (exp); } } // LIBRARY_VISIBILITY void DbeView::resetAndConstructShowHideStack (Experiment *exp) { exp->resetShowHideStack (); /* Vector *dDscrs = */ exp->getDataDescriptors (); DataDescriptor *dd; // Construct show hide stack only for objects which have call stacks // list below similar to path tree. What about HEAP_SZ? (DBFIXME) dd = exp->get_raw_events (DATA_CLOCK); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_SYNCH); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_IOTRACE); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_HWC); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_HEAP); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_RACE); if (dd != NULL) constructShowHideStack (dd, exp); dd = exp->get_raw_events (DATA_DLCK); if (dd != NULL) constructShowHideStack (dd, exp); } // LIBRARY_VISIBILITY void DbeView::constructShowHideStack (DataDescriptor *dDscr, Experiment *exp) { if (dDscr == NULL) return; int stack_prop = PROP_NONE; VMode view_mode = get_view_mode (); if (view_mode == VMODE_MACHINE) stack_prop = PROP_MSTACK; else if (view_mode == VMODE_EXPERT) stack_prop = PROP_XSTACK; else if (view_mode == VMODE_USER) stack_prop = PROP_USTACK; for (long j = 0, sz = dDscr->getSize (); j < sz; j++) { void *stackId = dDscr->getObjValue (stack_prop, j); Vector *stack = (Vector*)CallStack::getStackPCs (stackId); int stack_size = stack->size (); bool hide_on = false; LoadObject *hide_lo = NULL; Histable *last_addr = NULL; Histable *api_addr = NULL; DbeInstr *h_instr; Vector *hidepcs = new Vector; for (int i = stack_size - 1; i >= 0; i--) { bool leaf = (i == 0); Histable *cur_addr = stack->fetch (i); Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION); if (func != NULL) { Module *mod = func->module; LoadObject *lo = mod->loadobject; int segx = lo->seg_idx; if ((get_lo_expand (segx) == LIBEX_API) && (i != (stack_size - 1))) { leaf = true; api_addr = cur_addr; } else if (get_lo_expand (segx) == LIBEX_HIDE) { if (hide_on) { if (lo != hide_lo) { // Changed hidden loadobject if (last_addr != NULL) { h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr); hidepcs->append (h_instr); last_addr = cur_addr; } hide_lo = lo; } } else { // Start hide hide_on = true; last_addr = cur_addr; hide_lo = lo; } if (!leaf) continue; } else { hide_on = false; if (last_addr != NULL) { h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr); hidepcs->append (h_instr); last_addr = NULL; } } } if (last_addr != NULL && leaf) cur_addr = last_addr; if (hide_on) { h_instr = hide_lo->get_hide_instr ((DbeInstr*) cur_addr); hidepcs->append (h_instr); if (api_addr != NULL) hidepcs->append (api_addr); } else hidepcs->append (cur_addr); if (leaf) break; } for (int i = 0, k = hidepcs->size () - 1; i < k; ++i, --k) hidepcs->swap (i, k); CallStack *cstkSH = exp->callTreeShowHide (); CallStackNode *hstack = (CallStackNode *) cstkSH->add_stack (hidepcs); dDscr->setObjValue (PROP_HSTACK, j, hstack); CallStack::setHideStack (stackId, hstack); delete hidepcs; delete stack; } } DataView * DbeView::get_filtered_events (int idx, int data_id) { if (idx < 0 || idx >= dataViews->size ()) return NULL; Vector *expDataViewList = dataViews->fetch (idx); if (!expDataViewList) return NULL; // Weird DataView *dview = expDataViewList->fetch (data_id); Experiment *exp = dbeSession->get_exp (idx); if (dview) { // if show-hide is on force a reconstruction of hide stacks // LIBRARY_VISIBILITY if (!showAll && (showHideChanged || newViewMode)) { DataDescriptor *dDscr = exp->get_raw_events (data_id); constructShowHideStack (dDscr, exp); } return dview; } int orig_data_id = data_id; data_id = exp->base_data_id (data_id); if (orig_data_id != data_id) // orig_data_id is a derived DataView. Get the master DataView: dview = expDataViewList->fetch (data_id); if (dview == NULL) { Expression *saved = cur_filter_expr; if (!adjust_filter (exp)) return NULL; DataDescriptor *dDscr = exp->get_raw_events (data_id); if (!showAll && (showHideChanged || newViewMode)) constructShowHideStack (dDscr, exp); Emsg *m = exp->fetch_warnings (); if (m != NULL) this->warning_msg = m->get_msg (); if (dDscr != NULL) { FilterExp *filter = get_FilterExp (exp); dview = dDscr->createView (); dview->setFilter (filter); if (dview->getSize () < dDscr->getSize ()) filter_active = true; } expDataViewList->store (data_id, dview); if (saved) { delete cur_filter_expr; cur_filter_expr = saved; } } if (orig_data_id != data_id) { // create the derived DataView: dview = exp->create_derived_data_view (orig_data_id, dview); expDataViewList->store (orig_data_id, dview); } return dview; } DataView * DbeView::get_filtered_events (int idx, int data_id, const int sortprops[], int sortprop_count) { DataView *packets = get_filtered_events (idx, data_id); if (packets) packets->sort (sortprops, sortprop_count); return packets; } bool DbeView::adjust_filter (Experiment *exp) { if (cur_filter_expr) { Expression::Context ctx (this, exp); resetFilterHideMode (); Expression *fltr = cur_filter_expr->pEval (&ctx); if (fltr->complete ()) { // Filter is a constant if (fltr->eval (NULL) == 0) return false; delete fltr; fltr = NULL; } cur_filter_expr = fltr; } return true; } // Moved from Cacheable.cc: char * DbeView::status_str (DbeView_status status) { switch (status) { case DBEVIEW_SUCCESS: return NULL; case DBEVIEW_NO_DATA: return dbe_strdup (GTXT ("Data not available for this filter selection")); case DBEVIEW_IO_ERROR: return dbe_strdup (GTXT ("Unable to open file")); case DBEVIEW_BAD_DATA: return dbe_strdup (GTXT ("Data corrupted")); case DBEVIEW_BAD_SYMBOL_DATA: return dbe_strdup (GTXT ("Functions/Modules information corrupted")); case DBEVIEW_NO_SEL_OBJ: return dbe_strdup (GTXT ("No selected object, bring up Functions Tab")); } return NULL; } Histable * DbeView::set_sel_obj (Histable *obj) { if (obj) { switch (obj->get_type ()) { case Histable::INSTR: lastSelInstr = (DbeInstr *) obj; lastSelFunc = lastSelInstr->func; this->sel_binctx = lastSelFunc; break; case Histable::FUNCTION: if (lastSelInstr && lastSelInstr->func != obj) lastSelInstr = NULL; lastSelFunc = (Function *) obj; break; case Histable::LINE: { DbeLine *dbeLine = (DbeLine *) obj; if (dbeLine->func) { // remember previous DbeInstr and DbeFunc lastSelFunc = dbeLine->func; if (lastSelInstr && lastSelInstr->func != lastSelFunc) lastSelInstr = NULL; this->sel_binctx = lastSelFunc; } else this->sel_binctx = dbeLine->convertto (Histable::FUNCTION); break; } case Histable::MODULE: case Histable::LOADOBJECT: case Histable::EADDR: case Histable::MEMOBJ: case Histable::INDEXOBJ: case Histable::PAGE: case Histable::DOBJECT: case Histable::SOURCEFILE: case Histable::IOACTFILE: case Histable::IOACTVFD: case Histable::IOCALLSTACK: case Histable::HEAPCALLSTACK: case Histable::EXPERIMENT: case Histable::OTHER: break; } } sel_obj = obj; Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d obj %s\n"), __LINE__, obj ? obj->dump () : "NULL"); Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d sel_obj %s\n"), __LINE__, sel_obj ? sel_obj->dump () : "NULL"); Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelFunc %s\n"), __LINE__, lastSelFunc ? lastSelFunc->dump () : "NULL"); Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelInstr %s\n"), __LINE__, lastSelInstr ? lastSelInstr->dump () : "NULL"); return sel_obj; } DbeInstr * DbeView::convert_line_to_instr (DbeLine *dbeLine) { Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d dbeLine=%s\n", __LINE__, dbeLine->dump ()); Function *func = convert_line_to_func (dbeLine); if (func) { Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d func=%s\n", __LINE__, func->dump ()); DbeInstr *dbeInstr = func->mapLineToPc (dbeLine); Dprintf (DEBUG_DBE && dbeInstr, "### convert_line_to_instr DbeView::%d dbeInstr=%s\n", __LINE__, dbeInstr->dump ()); return dbeInstr; } Dprintf (DEBUG_DBE && lastSelInstr, "### convert_line_to_instr DbeView::%d lastSelInstr=%s\n", __LINE__, lastSelInstr->dump ()); return lastSelInstr; } DbeInstr * DbeView::convert_func_to_instr (Function *func) { return (lastSelInstr && lastSelInstr->func == func) ? lastSelInstr : (DbeInstr *) func->convertto (Histable::INSTR); } Function * DbeView::convert_line_to_func (DbeLine *dbeLine) { Function *func = dbeLine->func; if (func) return func; if (lastSelFunc != NULL) // Can be mapped to the same function ? for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next) if (dl->func == lastSelFunc) return lastSelFunc; PathTree *pathTree = NULL; Function *firstFunc = NULL; for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next) { // Find a first function with non-zero metrics if (dl->func) { if (pathTree == NULL) pathTree = get_path_tree (); if (pathTree->get_func_nodeidx (dl->func)) return dl->func; if (firstFunc == NULL) firstFunc = dl->func; } } // Take a first function return firstFunc; } Histable * DbeView::get_sel_obj (Histable::Type type) { Histable *lastSelObj = sel_obj; Dprintf (DEBUG_DBE, NTXT ("### get_sel_obj: DbeView.cc:%d type=%d sel_obj %s\n"), __LINE__, type, lastSelObj ? lastSelObj->dump () : "NULL"); if (lastSelObj == NULL) return NULL; switch (type) { case Histable::INSTR: if (!showAll) { // DBFIXME LIBRARY VISIBILITY // hack to get to the hide mode object for PCs when filtering // with a PC in timeline if (lastSelObj->get_type () == Histable::INSTR) { Function *func = (Function*) (lastSelObj->convertto (Histable::FUNCTION)); LoadObject *lo = func->module->loadobject; if (get_lo_expand (lo->seg_idx) == LIBEX_HIDE) return lo->get_hide_function (); } } if (lastSelObj->get_type () == Histable::LINE) return convert_line_to_instr ((DbeLine*) lastSelObj); else if (lastSelObj->get_type () == Histable::FUNCTION) return convert_func_to_instr ((Function *) lastSelObj); return lastSelObj->convertto (type); case Histable::FUNCTION: if (lastSelObj->get_type () == Histable::LINE) { Function *func = convert_line_to_func ((DbeLine*) lastSelObj); if (func) return func; return NULL; } return lastSelObj->convertto (type); case Histable::LINE: default: return lastSelObj->convertto (type); } }