1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
26 #include "Application.h"
27 #include "CallStack.h"
28 #include "Experiment.h"
29 #include "Exp_Layout.h"
30 #include "DataObject.h"
31 #include "DbeSession.h"
32 #include "MetricList.h"
35 #include "MemObject.h"
38 #include "DataSpace.h"
39 #include "LoadObject.h"
44 //char *DOBJ_UNSPECIFIED = STXT("(Not identified by the compiler as a memory-referencing instruction)");
45 char *DOBJ_UNSPECIFIED = STXT("(No type information)");
46 char *DOBJ_UNIDENTIFIED = STXT("(No identifying descriptor provided by the compiler)");
47 char *DOBJ_UNDETERMINED = STXT("(Not determined from the symbolic information provided by the compiler)");
48 char *DOBJ_ANON = STXT("(Padding in structure)");
51 // ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
52 // ABS_BLOCKED = 0x02, /* runtime backtrack blocker reached */
53 // ABS_INCOMPLETE = 0x03, /* runtime backtrack limit reached */
54 // ABS_REG_LOSS = 0x04, /* address register contaminated */
55 // ABS_INVALID_EA = 0x05, /* invalid effective address value */
57 const char *ABS_RT_CODES[NUM_ABS_RT_CODES] = {
59 "(Dataspace data not requested during data collection)",
60 "(Backtracking was prevented by a jump or call instruction)",
61 "(Backtracking did not find trigger PC)",
62 "(Could not determine VA because registers changed after trigger instruction)",
63 "(Memory-referencing instruction did not specify a valid VA)",
67 // post-processing codes
68 // ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
69 // ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
70 // ABS_CTI_TARGET = 0x30, /* CTI target invalidated backtrack */
71 char *DOBJ_UNASCERTAINABLE = STXT("(Module with trigger PC not compiled with -xhwcprof)");
72 char *DOBJ_UNVERIFIABLE = STXT("(Backtracking failed to find a valid branch target)");
73 char *DOBJ_UNRESOLVABLE = STXT("(Backtracking traversed a branch target)");
75 char *ABS_PP_CODES[NUM_ABS_PP_CODES] = {
80 STXT ("(<INTERNAL ERROR DURING POST-PROCESSING>)")
83 DataSpace::DataSpace (DbeView *_dbev, int /* _picked */)
88 DataSpace::~DataSpace () { }
91 DataSpace::reset () { }
94 DataSpace::status_str ()
100 DataSpace::get_hist_obj (Histable::Type type, DataView *dview, long i)
102 DataObject *dobj = NULL;
103 char *errcode = NTXT ("<internal error>");
106 case Histable::DOBJECT:
107 dobj = (DataObject*) dview->getObjValue (PROP_HWCDOBJ, i);
110 Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
111 unsigned rt_code = (unsigned) ABS_GET_RT_CODE (leafVA);
112 unsigned pp_code = (unsigned) ABS_GET_PP_CODE (leafVA);
113 if (leafVA < ABS_CODE_RANGE
114 && (pp_code || (rt_code && rt_code != ABS_REG_LOSS)))
116 if (rt_code >= NUM_ABS_RT_CODES)
117 rt_code = NUM_ABS_RT_CODES - 1;
118 if (pp_code >= NUM_ABS_PP_CODES)
119 pp_code = NUM_ABS_PP_CODES - 1;
121 errcode = PTXT (ABS_RT_CODES[rt_code]);
123 errcode = PTXT (ABS_PP_CODES[pp_code]);
127 // associate dataobject with event
130 // search for memop in Module infoList
131 void *cstack = dview->getObjValue (PROP_MSTACK, i);
132 Histable *leafPCObj = CallStack::getStackPC (cstack, 0);
133 DbeInstr *leafPC = NULL;
134 if (leafPCObj->get_type () == Histable::INSTR)
135 leafPC = (DbeInstr*) leafPCObj;
137 leafPC = (DbeInstr*) leafPCObj->convertto (Histable::INSTR);
138 Function *func = leafPC->func;
139 uint64_t leafPC_offset = func->img_offset + leafPC->addr;
140 Module *mod = func->module;
141 uint32_t dtype_id = 0;
142 inst_info_t *info = NULL;
143 Vec_loop (inst_info_t*, mod->infoList, index, info)
145 if (info->offset == leafPC_offset)
147 dtype_id = info->memop->datatype_id;
151 dobj = mod->get_dobj (dtype_id);
154 // ensure dobj is determined
155 if (dtype_id == DataObject::UNSPECIFIED_ID)
156 errcode = PTXT (DOBJ_UNSPECIFIED);
158 errcode = PTXT (DOBJ_UNIDENTIFIED);
162 // determine associated master dataobject
163 if (!dobj->master && dobj->scope)
164 dobj->master = dbeSession->createMasterDataObject (dobj);
166 dobj = dobj->master; // use associated master
171 // if dobj is not set yet, supply a dobj for errcode
172 // search for a dobj with the same name
173 dobj = dbeSession->find_dobj_by_name (errcode);
176 // create new DataObject for unknown code
177 dobj = (DataObject*) dbeSession->createHistObject (Histable::DOBJECT);
180 dobj->parent = dbeSession->get_Unknown_DataObject ();
181 dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
184 dview->setObjValue (PROP_HWCDOBJ, i, dobj);
194 DataSpace::compute_metrics (MetricList *mlist, Histable::Type type,
195 Hist_data::Mode mode, Histable *sel_obj)
197 int nmetrics = mlist->get_items ()->size ();
199 Hist_data::HistItem *hi;
202 // reset event_data count for all datatypes
203 Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
204 for (int i = 0, sz = lobjs ? lobjs->size () : -1; i < sz; i++)
206 LoadObject *lo = lobjs->fetch (i);
207 Vector<Module*> *modules = lo->seg_modules;
208 for (int j = 0, msize = modules ? modules->size () : -1; j < msize; j++)
210 Module *mod = modules->fetch (j);
211 mod->reset_datatypes ();
214 Hist_data *hist_data = new Hist_data (mlist, type, mode);
216 // add each experiment, skipping disabled and broken experiments
217 for (index = 0; index < dbeSession->nexps (); index++)
219 Experiment *exp = dbeSession->get_exp (index);
223 Collection_params *params = exp->get_params ();
224 if (!params->xhw_mode)
227 char *expt_name = exp->get_expt_name ();
228 char *base_name = strrchr (expt_name, '/');
229 base_name = base_name ? base_name + 1 : expt_name;
231 // Determine mapping of experiment HWC metrics to hist_data metric list
232 int *xlate = new int[MAX_HWCOUNT];
233 for (unsigned i = 0; i < MAX_HWCOUNT; i++)
236 if (params->hw_interval[i] > 0)
238 const char *ctr_name = params->hw_aux_name[i];
241 Vec_loop (Metric*, mlist->get_items (), mindex, met)
243 if (dbe_strcmp (met->get_cmd (), ctr_name) == 0)
250 // Process hardware profiling data
252 DataView *dview = dbev->get_filtered_events (index, DATA_HWC);
255 DataDescriptor *ddscr = dview ->getDataDescriptor ();
256 if (ddscr->getProp (PROP_HWCDOBJ) == NULL)
258 PropDescr *prop = new PropDescr (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
260 prop->vtype = TYPE_OBJ;
261 ddscr->addProperty (prop);
264 if (dview && dview->getSize () != 0)
267 for (long i = 0; i < dview->getSize (); i++)
271 int percent = (int) (100.0 * i / dview->getSize ());
272 if (percent == 0 && msg == NULL)
273 msg = dbe_sprintf (GTXT ("Filtering HW Profile Address Data: %s"), base_name);
274 theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
277 uint32_t tag = dview->getIntValue (PROP_HWCTAG, i);
278 if (tag < 0 || tag >= MAX_HWCOUNT)
279 continue; // invalid HWC tag in the record; ignore it
280 int mHwcntr_idx = xlate[tag];
284 Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
285 if (leafVA == ABS_UNSUPPORTED)
286 continue; // skip this record
287 Histable *obj = get_hist_obj (type, dview, i);
290 uint64_t interval = dview->getLongValue (PROP_HWCINT, i);
291 if (HWCVAL_HAS_ERR (interval))
293 if (mode == Hist_data::ALL)
295 hi = hist_data->append_hist_item (obj);
296 hi->value[mHwcntr_idx].ll += interval;
297 for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
299 hi = hist_data->append_hist_item (dobj);
300 hi->value[mHwcntr_idx].ll += interval;
303 else if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
306 // for data layout, insert elements that have no metrics yet
307 DataObject *tmpParent = ((DataObject *) obj)->parent;
308 if (tmpParent && tmpParent->get_typename ())
310 // dobj is an aggregate element
311 if (!hist_data->find_hist_item (tmpParent))
313 // parent not yet a member of hist_data
314 // supply parent's children with 0 values for layout
315 Vector<DataObject*> *elements = dbeSession->get_dobj_elements (tmpParent);
316 for (long eli = 0, sz = elements->size (); eli < sz; eli++)
318 DataObject* element = elements->fetch (eli);
319 assert (!hist_data->find_hist_item (element));
320 hi = hist_data->append_hist_item (element);
326 // Same as for mode == Hist_data::ALL:
327 hi = hist_data->append_hist_item (obj);
328 hi->value[mHwcntr_idx].ll += interval;
329 for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
331 hi = hist_data->append_hist_item (dobj);
332 hi->value[mHwcntr_idx].ll += interval;
335 else if (mode == Hist_data::SELF)
336 { // used by dbeGetSummary()
339 hi = hist_data->append_hist_item (obj);
340 hi->value[mHwcntr_idx].ll += interval;
344 for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
346 if ((Histable*) dobj == sel_obj)
348 hi = hist_data->append_hist_item (dobj);
349 hi->value[mHwcntr_idx].ll += interval;
356 hist_data->total->value[mHwcntr_idx].ll += interval;
359 theApplication->set_progress (0, NTXT (""));
364 // include a regular HistItem for <Total> -- for all DataObjects, and MemObjects
365 DataObject *dtot = dbeSession->get_Total_DataObject ();
366 if (mode == Hist_data::ALL || mode == Hist_data::DETAIL
367 || mode == Hist_data::LAYOUT ||
370 hi = hist_data->append_hist_item (dtot);
371 for (int mind = 0; mind < nmetrics; mind++)
372 hi->value[mind] = hist_data->total->value[mind];
374 if (hist_data->get_status () != Hist_data::SUCCESS)
376 theApplication->set_progress (0, GTXT ("Constructing Metrics"));
378 // Determine by which metric to sort if any
379 bool rev_sort = mlist->get_sort_rev ();
381 // Compute static metrics: SIZES, ADDRESS.
382 for (int mind = 0; mind < nmetrics; mind++)
384 Metric *mtr = mlist->get_items ()->fetch (mind);
385 if (mlist->get_sort_ref_index () == mind)
387 else if (!mtr->is_visible () && !mtr->is_tvisible ()
388 && !mtr->is_pvisible ())
390 Metric::Type mtype = mtr->get_type ();
391 if (mtype == Metric::SIZES)
393 Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
395 Histable *h = mtr->get_comparable_obj (hi->obj);
396 hi->value[mind].tag = VT_LLONG;
397 hi->value[mind].ll = h ? h->get_size () : 0;
400 else if (mtype == Metric::ONAME
401 && (mode == Hist_data::SELF
402 || ((DataObject*) sel_obj == dbeSession->get_Total_DataObject ())))
404 Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
406 hi->value[mind].tag = VT_OFFSET; // offset labels
409 else if (mtype == Metric::ADDRESS)
411 Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
413 hi->value[mind].tag = VT_ADDRESS;
414 Histable *h = mtr->get_comparable_obj (hi->obj);
415 hi->value[mind].ll = h ? h->get_addr () : 0;
417 // force sort by offset // XXXX should visibility also be set?
418 if (mode == Hist_data::SELF)
419 { // used by dbeGetSummary()
421 //hist_data->metrics->fetch(mind)->set_visible(T);
426 ValueTag vtype = mtr->get_vtype ();
429 case VT_ULLONG: // most Data-derived HWC metrics are VT_ULLONG
430 hist_data->total->value[mind].tag = vtype;
431 Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
433 hi->value[mind].tag = vtype;
438 double prec = mtr->get_precision ();
439 hist_data->total->value[mind].tag = vtype;
440 hist_data->total->value[mind].d = hist_data->total->value[mind].ll / prec;
441 Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
443 hi->value[mind].tag = vtype;
444 hi->value[mind].d = hi->value[mind].ll / prec;
449 if (mtr->get_subtype () != Metric::STATIC)
455 hist_data->sort (sort_ind, rev_sort);
456 hist_data->compute_minmax ();
457 theApplication->set_progress (0, NTXT (""));
462 // generate annotated structure info for data_layout
463 // note: similar data traversal found in er_print_histogram::dump_detail()
465 DataSpace::get_layout_data (Hist_data *sorted_data,
466 Vector<int> *marks, int /* _threshold */)
468 Hist_data *data_items = NULL;
469 Hist_data::HistItem *new_item;
470 MetricList *mlist = new MetricList (sorted_data->get_metric_list ());
471 int no_metrics = mlist->get_items ()->size ();
472 int index, addr_index = -1, name_index = -1;
473 Dprintf (DEBUG_DATAOBJ, NTXT ("DataSpace::get_layout_data(ALL)\n"));
475 // Allocate a new Hist_data for the list, to be copied from the DataObect list
476 data_items = new Hist_data (mlist, Histable::DOBJECT, Hist_data::MODL);
477 data_items->set_status (sorted_data->get_status ());
479 // suppress threshold setting
480 // XXX this threshold should probably not be used
481 sorted_data->set_threshold ((double) 75. / 100.0);
482 TValue* all_empty = new TValue[no_metrics];
483 memset (all_empty, 0, sizeof (TValue) * no_metrics);
486 Vec_loop (Metric*, mlist->get_items (), index, mitem)
488 // new data items have same total as original items
489 data_items->total->value[index] = sorted_data->total->value[index];
490 // empty metric items need matching types
491 all_empty[index].tag = mitem->get_vtype ();
492 if (mitem->get_type () == Metric::ONAME) name_index = index;
493 if (mitem->get_type () == Metric::ADDRESS) addr_index = index;
496 int64_t next_elem_offset = 0;
497 for (long i = 0; i < sorted_data->size (); i++)
499 Hist_data::HistItem* ditem = sorted_data->fetch (i);
500 DataObject* dobj = (DataObject*) (ditem->obj);
501 if (!dobj->get_parent ())
502 { // doesn't have a parent; top level item
503 next_elem_offset = 0;
505 { // add a blank line as separator
506 // fixme xxxxx, is it really ok to create a DataObject just for this?
507 DataObject* empty = new DataObject ();
510 empty->set_name (NTXT (""));
511 new_item = sorted_data->new_hist_item (empty, Module::AT_EMPTY, all_empty);
512 new_item->value[name_index].tag = VT_LABEL;
513 new_item->value[name_index].l = NULL;
514 data_items->append_hist_item (new_item);
516 // then add the aggregate
517 new_item = sorted_data->new_hist_item (dobj, Module::AT_SRC, ditem->value);
518 new_item->value[name_index].tag = VT_OFFSET;
519 new_item->value[name_index].l = dbe_strdup (dobj->get_name ());
520 data_items->append_hist_item (new_item);
524 if (dobj->get_parent ()->get_typename ())
525 { // typed sub-element that has offset
526 if (dobj->offset > next_elem_offset)
529 // fixme xxxxx, is it really ok to create a DataObject just for this?
530 DataObject* filler = new DataObject ();
531 filler->set_name (PTXT (DOBJ_ANON));
532 filler->size = (dobj->offset - next_elem_offset);
533 filler->offset = next_elem_offset;
534 new_item = sorted_data->new_hist_item (filler, Module::AT_EMPTY, all_empty);
535 new_item->value[name_index].tag = VT_OFFSET;
536 new_item->value[name_index].l = dbe_strdup (filler->get_offset_name ());
539 new_item->value[addr_index].tag = VT_ADDRESS;
540 new_item->value[addr_index].ll = (dobj->get_addr () - filler->size);
542 data_items->append_hist_item (new_item);
544 next_elem_offset = dobj->offset + dobj->size;
546 // then add the aggregate's subelement
548 if (sorted_data->above_threshold (ditem))
549 marks->append (data_items->size ());
550 new_item = sorted_data->new_hist_item (dobj, Module::AT_DIS, ditem->value);
551 new_item->value[name_index].tag = VT_OFFSET;
552 new_item->value[name_index].l = dbe_strdup (dobj->get_offset_name ());
553 data_items->append_hist_item (new_item);