Retro68/binutils/gprofng/src/DbeView.cc
Wolfgang Thaller f485e125c4 binutils 2.39
2022-10-27 20:45:45 +02:00

3127 lines
85 KiB
C++

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