aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/DataSpace.cc
diff options
context:
space:
mode:
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>2022-03-11 08:58:31 +0000
committerNick Clifton <nickc@redhat.com>2022-03-11 08:58:31 +0000
commitbb368aad297fe3ad40cf397e6fc85aa471429a28 (patch)
tree0ab25909b8fe789d676bbdb00d501d4d485e4afe /gprofng/src/DataSpace.cc
parenta655f19af95eb685ba64f48ee8fc2b3b7a3d886a (diff)
downloadbinutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.zip
binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.gz
binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.bz2
gprofng: a new GNU profiler
top-level * Makefile.def: Add gprofng module. * configure.ac: Add --enable-gprofng option. * src-release.sh: Add gprofng. * Makefile.in: Regenerate. * configure: Regenerate. * gprofng: New directory. binutils * MAINTAINERS: Add gprofng maintainer. * README-how-to-make-a-release: Add gprofng. include. * collectorAPI.h: New file. * libcollector.h: New file. * libfcollector.h: New file.
Diffstat (limited to 'gprofng/src/DataSpace.cc')
-rw-r--r--gprofng/src/DataSpace.cc558
1 files changed, 558 insertions, 0 deletions
diff --git a/gprofng/src/DataSpace.cc b/gprofng/src/DataSpace.cc
new file mode 100644
index 0000000..e5b48dd
--- /dev/null
+++ b/gprofng/src/DataSpace.cc
@@ -0,0 +1,558 @@
+/* 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 <stdlib.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "DbeSession.h"
+#include "MetricList.h"
+#include "Function.h"
+#include "Module.h"
+#include "MemObject.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "DataSpace.h"
+#include "LoadObject.h"
+
+#include "debug.h"
+#include "ABS.h"
+
+//char *DOBJ_UNSPECIFIED = STXT("(Not identified by the compiler as a memory-referencing instruction)");
+char *DOBJ_UNSPECIFIED = STXT("(No type information)");
+char *DOBJ_UNIDENTIFIED = STXT("(No identifying descriptor provided by the compiler)");
+char *DOBJ_UNDETERMINED = STXT("(Not determined from the symbolic information provided by the compiler)");
+char *DOBJ_ANON = STXT("(Padding in structure)");
+
+// run-time codes
+// ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
+// ABS_BLOCKED = 0x02, /* runtime backtrack blocker reached */
+// ABS_INCOMPLETE = 0x03, /* runtime backtrack limit reached */
+// ABS_REG_LOSS = 0x04, /* address register contaminated */
+// ABS_INVALID_EA = 0x05, /* invalid effective address value */
+
+const char *ABS_RT_CODES[NUM_ABS_RT_CODES] = {
+ "(OK)",
+ "(Dataspace data not requested during data collection)",
+ "(Backtracking was prevented by a jump or call instruction)",
+ "(Backtracking did not find trigger PC)",
+ "(Could not determine VA because registers changed after trigger instruction)",
+ "(Memory-referencing instruction did not specify a valid VA)",
+ "(UNKNOWN)"
+};
+
+// post-processing codes
+// ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
+// ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
+// ABS_CTI_TARGET = 0x30, /* CTI target invalidated backtrack */
+char *DOBJ_UNASCERTAINABLE = STXT("(Module with trigger PC not compiled with -xhwcprof)");
+char *DOBJ_UNVERIFIABLE = STXT("(Backtracking failed to find a valid branch target)");
+char *DOBJ_UNRESOLVABLE = STXT("(Backtracking traversed a branch target)");
+
+char *ABS_PP_CODES[NUM_ABS_PP_CODES] = {
+ STXT ("(OK)"),
+ DOBJ_UNASCERTAINABLE,
+ DOBJ_UNVERIFIABLE,
+ DOBJ_UNRESOLVABLE,
+ STXT ("(<INTERNAL ERROR DURING POST-PROCESSING>)")
+};
+
+DataSpace::DataSpace (DbeView *_dbev, int /* _picked */)
+{
+ dbev = _dbev;
+}
+
+DataSpace::~DataSpace () { }
+
+void
+DataSpace::reset () { }
+
+char *
+DataSpace::status_str ()
+{
+ return NULL;
+}
+
+Histable *
+DataSpace::get_hist_obj (Histable::Type type, DataView *dview, long i)
+{
+ DataObject *dobj = NULL;
+ char *errcode = NTXT ("<internal error>");
+ switch (type)
+ {
+ case Histable::DOBJECT:
+ dobj = (DataObject*) dview->getObjValue (PROP_HWCDOBJ, i);
+ if (dobj == NULL)
+ {
+ Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+ unsigned rt_code = (unsigned) ABS_GET_RT_CODE (leafVA);
+ unsigned pp_code = (unsigned) ABS_GET_PP_CODE (leafVA);
+ if (leafVA < ABS_CODE_RANGE
+ && (pp_code || (rt_code && rt_code != ABS_REG_LOSS)))
+ {
+ if (rt_code >= NUM_ABS_RT_CODES)
+ rt_code = NUM_ABS_RT_CODES - 1;
+ if (pp_code >= NUM_ABS_PP_CODES)
+ pp_code = NUM_ABS_PP_CODES - 1;
+ if (rt_code)
+ errcode = PTXT (ABS_RT_CODES[rt_code]);
+ else
+ errcode = PTXT (ABS_PP_CODES[pp_code]);
+ }
+ else
+ {
+ // associate dataobject with event
+ int index;
+
+ // search for memop in Module infoList
+ void *cstack = dview->getObjValue (PROP_MSTACK, i);
+ Histable *leafPCObj = CallStack::getStackPC (cstack, 0);
+ DbeInstr *leafPC = NULL;
+ if (leafPCObj->get_type () == Histable::INSTR)
+ leafPC = (DbeInstr*) leafPCObj;
+ else // DBELINE
+ leafPC = (DbeInstr*) leafPCObj->convertto (Histable::INSTR);
+ Function *func = leafPC->func;
+ uint64_t leafPC_offset = func->img_offset + leafPC->addr;
+ Module *mod = func->module;
+ uint32_t dtype_id = 0;
+ inst_info_t *info = NULL;
+ Vec_loop (inst_info_t*, mod->infoList, index, info)
+ {
+ if (info->offset == leafPC_offset)
+ {
+ dtype_id = info->memop->datatype_id;
+ break;
+ }
+ }
+ dobj = mod->get_dobj (dtype_id);
+ if (dobj == NULL)
+ {
+ // ensure dobj is determined
+ if (dtype_id == DataObject::UNSPECIFIED_ID)
+ errcode = PTXT (DOBJ_UNSPECIFIED);
+ else
+ errcode = PTXT (DOBJ_UNIDENTIFIED);
+ }
+ else
+ {
+ // determine associated master dataobject
+ if (!dobj->master && dobj->scope)
+ dobj->master = dbeSession->createMasterDataObject (dobj);
+ if (dobj->scope)
+ dobj = dobj->master; // use associated master
+ }
+ }
+ if (!dobj)
+ {
+ // if dobj is not set yet, supply a dobj for errcode
+ // search for a dobj with the same name
+ dobj = dbeSession->find_dobj_by_name (errcode);
+ if (dobj == NULL)
+ {
+ // create new DataObject for unknown code
+ dobj = (DataObject*) dbeSession->createHistObject (Histable::DOBJECT);
+ dobj->size = 0;
+ dobj->offset = -1;
+ dobj->parent = dbeSession->get_Unknown_DataObject ();
+ dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+ }
+ }
+ dview->setObjValue (PROP_HWCDOBJ, i, dobj);
+ }
+ break;
+ default:
+ break;
+ }
+ return dobj;
+}
+
+Hist_data *
+DataSpace::compute_metrics (MetricList *mlist, Histable::Type type,
+ Hist_data::Mode mode, Histable *sel_obj)
+{
+ int nmetrics = mlist->get_items ()->size ();
+ int sort_ind = -1;
+ Hist_data::HistItem *hi;
+ int index;
+
+ // reset event_data count for all datatypes
+ Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+ for (int i = 0, sz = lobjs ? lobjs->size () : -1; i < sz; i++)
+ {
+ LoadObject *lo = lobjs->fetch (i);
+ Vector<Module*> *modules = lo->seg_modules;
+ for (int j = 0, msize = modules ? modules->size () : -1; j < msize; j++)
+ {
+ Module *mod = modules->fetch (j);
+ mod->reset_datatypes ();
+ }
+ }
+ Hist_data *hist_data = new Hist_data (mlist, type, mode);
+
+ // add each experiment, skipping disabled and broken experiments
+ for (index = 0; index < dbeSession->nexps (); index++)
+ {
+ Experiment *exp = dbeSession->get_exp (index);
+ if (exp->broken)
+ continue;
+
+ Collection_params *params = exp->get_params ();
+ if (!params->xhw_mode)
+ continue;
+
+ char *expt_name = exp->get_expt_name ();
+ char *base_name = strrchr (expt_name, '/');
+ base_name = base_name ? base_name + 1 : expt_name;
+
+ // Determine mapping of experiment HWC metrics to hist_data metric list
+ int *xlate = new int[MAX_HWCOUNT];
+ for (unsigned i = 0; i < MAX_HWCOUNT; i++)
+ {
+ xlate[i] = -1;
+ if (params->hw_interval[i] > 0)
+ {
+ const char *ctr_name = params->hw_aux_name[i];
+ int mindex;
+ Metric *met;
+ Vec_loop (Metric*, mlist->get_items (), mindex, met)
+ {
+ if (dbe_strcmp (met->get_cmd (), ctr_name) == 0)
+ xlate[i] = mindex;
+ }
+ }
+ }
+
+ //
+ // Process hardware profiling data
+ //
+ DataView *dview = dbev->get_filtered_events (index, DATA_HWC);
+ if (dview)
+ {
+ DataDescriptor *ddscr = dview ->getDataDescriptor ();
+ if (ddscr->getProp (PROP_HWCDOBJ) == NULL)
+ {
+ PropDescr *prop = new PropDescr (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+ prop->uname = NULL;
+ prop->vtype = TYPE_OBJ;
+ ddscr->addProperty (prop);
+ }
+ }
+ if (dview && dview->getSize () != 0)
+ {
+ char *msg = NULL;
+ for (long i = 0; i < dview->getSize (); i++)
+ {
+ if (i % 5000 == 0)
+ {
+ int percent = (int) (100.0 * i / dview->getSize ());
+ if (percent == 0 && msg == NULL)
+ msg = dbe_sprintf (GTXT ("Filtering HW Profile Address Data: %s"), base_name);
+ theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+ }
+
+ uint32_t tag = dview->getIntValue (PROP_HWCTAG, i);
+ if (tag < 0 || tag >= MAX_HWCOUNT)
+ continue; // invalid HWC tag in the record; ignore it
+ int mHwcntr_idx = xlate[tag];
+ if (mHwcntr_idx < 0)
+ continue;
+
+ Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+ if (leafVA == ABS_UNSUPPORTED)
+ continue; // skip this record
+ Histable *obj = get_hist_obj (type, dview, i);
+ if (obj == NULL)
+ continue;
+ uint64_t interval = dview->getLongValue (PROP_HWCINT, i);
+ if (HWCVAL_HAS_ERR (interval))
+ continue;
+ if (mode == Hist_data::ALL)
+ { // data_objects
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ }
+ else if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
+ { // data_single
+ {
+ // for data layout, insert elements that have no metrics yet
+ DataObject *tmpParent = ((DataObject *) obj)->parent;
+ if (tmpParent && tmpParent->get_typename ())
+ {
+ // dobj is an aggregate element
+ if (!hist_data->find_hist_item (tmpParent))
+ {
+ // parent not yet a member of hist_data
+ // supply parent's children with 0 values for layout
+ Vector<DataObject*> *elements = dbeSession->get_dobj_elements (tmpParent);
+ for (long eli = 0, sz = elements->size (); eli < sz; eli++)
+ {
+ DataObject* element = elements->fetch (eli);
+ assert (!hist_data->find_hist_item (element));
+ hi = hist_data->append_hist_item (element);
+ }
+ }
+ }
+ }
+
+ // Same as for mode == Hist_data::ALL:
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ }
+ else if (mode == Hist_data::SELF)
+ { // used by dbeGetSummary()
+ if (obj == sel_obj)
+ {
+ hi = hist_data->append_hist_item (obj);
+ hi->value[mHwcntr_idx].ll += interval;
+ }
+ else
+ {
+ for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+ {
+ if ((Histable*) dobj == sel_obj)
+ {
+ hi = hist_data->append_hist_item (dobj);
+ hi->value[mHwcntr_idx].ll += interval;
+ break;
+ }
+ }
+ }
+ }
+ // Update total
+ hist_data->total->value[mHwcntr_idx].ll += interval;
+ }
+ free (msg);
+ theApplication->set_progress (0, NTXT (""));
+ }
+ delete[] xlate;
+ }
+
+ // include a regular HistItem for <Total> -- for all DataObjects, and MemObjects
+ DataObject *dtot = dbeSession->get_Total_DataObject ();
+ if (mode == Hist_data::ALL || mode == Hist_data::DETAIL
+ || mode == Hist_data::LAYOUT ||
+ sel_obj == dtot)
+ {
+ hi = hist_data->append_hist_item (dtot);
+ for (int mind = 0; mind < nmetrics; mind++)
+ hi->value[mind] = hist_data->total->value[mind];
+ }
+ if (hist_data->get_status () != Hist_data::SUCCESS)
+ return hist_data;
+ theApplication->set_progress (0, GTXT ("Constructing Metrics"));
+
+ // Determine by which metric to sort if any
+ bool rev_sort = mlist->get_sort_rev ();
+
+ // Compute static metrics: SIZES, ADDRESS.
+ for (int mind = 0; mind < nmetrics; mind++)
+ {
+ Metric *mtr = mlist->get_items ()->fetch (mind);
+ if (mlist->get_sort_ref_index () == mind)
+ sort_ind = mind;
+ else if (!mtr->is_visible () && !mtr->is_tvisible ()
+ && !mtr->is_pvisible ())
+ continue;
+ Metric::Type mtype = mtr->get_type ();
+ if (mtype == Metric::SIZES)
+ {
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].tag = VT_LLONG;
+ hi->value[mind].ll = h ? h->get_size () : 0;
+ }
+ }
+ else if (mtype == Metric::ONAME
+ && (mode == Hist_data::SELF
+ || ((DataObject*) sel_obj == dbeSession->get_Total_DataObject ())))
+ {
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = VT_OFFSET; // offset labels
+ }
+ }
+ else if (mtype == Metric::ADDRESS)
+ { // pseudo-address
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = VT_ADDRESS;
+ Histable *h = mtr->get_comparable_obj (hi->obj);
+ hi->value[mind].ll = h ? h->get_addr () : 0;
+ }
+ // force sort by offset // XXXX should visibility also be set?
+ if (mode == Hist_data::SELF)
+ { // used by dbeGetSummary()
+ sort_ind = mind;
+ //hist_data->metrics->fetch(mind)->set_visible(T);
+ }
+ }
+ else
+ {
+ ValueTag vtype = mtr->get_vtype ();
+ switch (vtype)
+ {
+ case VT_ULLONG: // most Data-derived HWC metrics are VT_ULLONG
+ hist_data->total->value[mind].tag = vtype;
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ }
+ break;
+ case VT_DOUBLE:
+ {
+ double prec = mtr->get_precision ();
+ hist_data->total->value[mind].tag = vtype;
+ hist_data->total->value[mind].d = hist_data->total->value[mind].ll / prec;
+ Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+ {
+ hi->value[mind].tag = vtype;
+ hi->value[mind].d = hi->value[mind].ll / prec;
+ }
+ break;
+ }
+ default:
+ if (mtr->get_subtype () != Metric::STATIC)
+ abort ();
+ break;
+ }
+ }
+ }
+ hist_data->sort (sort_ind, rev_sort);
+ hist_data->compute_minmax ();
+ theApplication->set_progress (0, NTXT (""));
+ return hist_data;
+}
+
+
+// generate annotated structure info for data_layout
+// note: similar data traversal found in er_print_histogram::dump_detail()
+Hist_data *
+DataSpace::get_layout_data (Hist_data *sorted_data,
+ Vector<int> *marks, int /* _threshold */)
+{
+ Hist_data *data_items = NULL;
+ Hist_data::HistItem *new_item;
+ MetricList *mlist = new MetricList (sorted_data->get_metric_list ());
+ int no_metrics = mlist->get_items ()->size ();
+ int index, addr_index = -1, name_index = -1;
+ Dprintf (DEBUG_DATAOBJ, NTXT ("DataSpace::get_layout_data(ALL)\n"));
+
+ // Allocate a new Hist_data for the list, to be copied from the DataObect list
+ data_items = new Hist_data (mlist, Histable::DOBJECT, Hist_data::MODL);
+ data_items->set_status (sorted_data->get_status ());
+
+ // suppress threshold setting
+ // XXX this threshold should probably not be used
+ sorted_data->set_threshold ((double) 75. / 100.0);
+ TValue* all_empty = new TValue[no_metrics];
+ memset (all_empty, 0, sizeof (TValue) * no_metrics);
+
+ Metric *mitem;
+ Vec_loop (Metric*, mlist->get_items (), index, mitem)
+ {
+ // new data items have same total as original items
+ data_items->total->value[index] = sorted_data->total->value[index];
+ // empty metric items need matching types
+ all_empty[index].tag = mitem->get_vtype ();
+ if (mitem->get_type () == Metric::ONAME) name_index = index;
+ if (mitem->get_type () == Metric::ADDRESS) addr_index = index;
+ }
+
+ int64_t next_elem_offset = 0;
+ for (long i = 0; i < sorted_data->size (); i++)
+ {
+ Hist_data::HistItem* ditem = sorted_data->fetch (i);
+ DataObject* dobj = (DataObject*) (ditem->obj);
+ if (!dobj->get_parent ())
+ { // doesn't have a parent; top level item
+ next_elem_offset = 0;
+ if (i > 0)
+ { // add a blank line as separator
+ // fixme xxxxx, is it really ok to create a DataObject just for this?
+ DataObject* empty = new DataObject ();
+ empty->size = 0;
+ empty->offset = 0;
+ empty->set_name (NTXT (""));
+ new_item = sorted_data->new_hist_item (empty, Module::AT_EMPTY, all_empty);
+ new_item->value[name_index].tag = VT_LABEL;
+ new_item->value[name_index].l = NULL;
+ data_items->append_hist_item (new_item);
+ }
+ // then add the aggregate
+ new_item = sorted_data->new_hist_item (dobj, Module::AT_SRC, ditem->value);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (dobj->get_name ());
+ data_items->append_hist_item (new_item);
+ }
+ else
+ { // is a child
+ if (dobj->get_parent ()->get_typename ())
+ { // typed sub-element that has offset
+ if (dobj->offset > next_elem_offset)
+ { // filler entry
+ // hole in offsets
+ // fixme xxxxx, is it really ok to create a DataObject just for this?
+ DataObject* filler = new DataObject ();
+ filler->set_name (PTXT (DOBJ_ANON));
+ filler->size = (dobj->offset - next_elem_offset);
+ filler->offset = next_elem_offset;
+ new_item = sorted_data->new_hist_item (filler, Module::AT_EMPTY, all_empty);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (filler->get_offset_name ());
+ if (addr_index >= 0)
+ {
+ new_item->value[addr_index].tag = VT_ADDRESS;
+ new_item->value[addr_index].ll = (dobj->get_addr () - filler->size);
+ }
+ data_items->append_hist_item (new_item);
+ }
+ next_elem_offset = dobj->offset + dobj->size;
+ }
+ // then add the aggregate's subelement
+ if (marks)
+ if (sorted_data->above_threshold (ditem))
+ marks->append (data_items->size ());
+ new_item = sorted_data->new_hist_item (dobj, Module::AT_DIS, ditem->value);
+ new_item->value[name_index].tag = VT_OFFSET;
+ new_item->value[name_index].l = dbe_strdup (dobj->get_offset_name ());
+ data_items->append_hist_item (new_item);
+ }
+ }
+ delete[] all_empty;
+ return data_items;
+}