| /* 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<MemorySpace*>; |
| iospace = new IOActivity (this); |
| heapspace = new HeapActivity (this); |
| filters = new Vector<FilterSet*>; |
| lo_expands = new Vector<enum LibExpand>; |
| cur_filter_str = NULL; |
| prev_filter_str = NULL; |
| cur_filter_expr = NULL; |
| filter_active = false; |
| noParFilter = false; |
| dataViews = new Vector<Vector<DataView*>*>; |
| 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<int>; |
| marks2dsrc = new Vector<int_pair_t>; |
| marks2dsrc_inc = new Vector<int_pair_t>; |
| marks2ddis = new Vector<int_pair_t>; |
| marks2ddis_inc = new Vector<int_pair_t>; |
| 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<PathTree*>(sz); |
| indx_data = new Vector<Hist_data*>(sz); |
| sel_idxobj = new Vector<Histable*>(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<LoadObject*> *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<MemorySpace*>; |
| filters = new Vector<FilterSet*>; |
| lo_expands = new Vector<enum LibExpand>; |
| cur_filter_str = NULL; |
| prev_filter_str = NULL; |
| cur_filter_expr = NULL; |
| noParFilter = false; |
| dataViews = new Vector<Vector<DataView*>*>; |
| 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<int>; |
| marks2dsrc = new Vector<int_pair_t>; |
| marks2dsrc_inc = new Vector<int_pair_t>; |
| marks2ddis = new Vector<int_pair_t>; |
| marks2ddis_inc = new Vector<int_pair_t>; |
| 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<PathTree*>(sz); |
| indx_data = new Vector<Hist_data*>(sz); |
| sel_idxobj = new Vector<Histable*>(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<DataView*> *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<BaseMetric*>; |
| metrics_lists = new Vector<MetricList*>; |
| metrics_ref_lists = new Vector<MetricList*>; |
| 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<LoadObject*> *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<DataView*> *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 <Total> 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<BaseMetric*> * |
| DbeView::get_all_reg_metrics () |
| { |
| Vector<BaseMetric*> *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<BaseMetric*> *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<BaseMetric*> *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<BaseMetric*> *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<LoadObject*> *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<DataView*> *expDataViewList = new Vector<DataView*>; |
| 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<DataView*> *expDataViewList = new Vector<DataView*>; |
| 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<DataView*> *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<Metric*> *items = mlist->get_items (); |
| Vector<Metric*> *newItems = new Vector<Metric*>(); |
| 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<Metric*> *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<Metric*> *items = mlist->get_items (); |
| Vector<Metric*> *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<Metric*> *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<Metric*> *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<Metric*> *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<Hist_data::HistItem*> *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<char*, DbeLine*>; |
| 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<char*, SourceFile*>; |
| 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<Histable*> *sel_objs, |
| PathTree::PtreeComputeOption flag) |
| { |
| Vector<Histable*> *objs = NULL; |
| if (obj != NULL) |
| { |
| objs = new Vector<Histable*>(); |
| 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<Histable*> *objs, |
| Histable *context, Vector<Histable*> *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<BaseMetric*> *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<Hist_data::HistItem*> *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<Hist_data::HistItem*> *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<FilterNumeric*> * |
| 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<char *> *pattern_str, bool *error) |
| { |
| Vector<FilterNumeric*> *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<Histable*> *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<Histable*> *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<Histable*> *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 <invalid> as its name |
| hwc_name = "<invalid>"; |
| 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<Histable*> *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<Histable*> *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<GCEvent*> *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<DataView*> *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<DataDescriptor*> *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<Histable*> *stack = (Vector<Histable*>*)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<Histable*> *hidepcs = new Vector<Histable*>; |
| 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<DataView*> *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)) |
| |