mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-15 07:29:41 +00:00
3127 lines
85 KiB
C++
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);
|
|
}
|
|
}
|