| /* Copyright (C) 2021 Free Software Foundation, Inc. | |
| Contributed by Oracle. | |
| This file is part of GNU Binutils. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3, or (at your option) | |
| any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
| MA 02110-1301, USA. */ | |
| #include "config.h" | |
| #include "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)) | |
| { | |
| 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); | |
| } | |
| } |