diff options
Diffstat (limited to 'gprofng/src/PathTree.cc')
-rw-r--r-- | gprofng/src/PathTree.cc | 2637 |
1 files changed, 2637 insertions, 0 deletions
diff --git a/gprofng/src/PathTree.cc b/gprofng/src/PathTree.cc new file mode 100644 index 00000000000..798e55c9755 --- /dev/null +++ b/gprofng/src/PathTree.cc @@ -0,0 +1,2637 @@ +/* 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 <stdio.h> +#include <stdlib.h> + +#include "util.h" +#include "DefaultMap.h" +#include "CacheMap.h" + +#include "DbeSession.h" +#include "Application.h" +#include "CallStack.h" +#include "Emsg.h" +#include "Experiment.h" +#include "Expression.h" +#include "Function.h" +#include "Histable.h" +#include "IndexObject.h" +#include "MetricList.h" +#include "Module.h" +#include "DbeView.h" +#include "Metric.h" +#include "PathTree.h" +#include "LoadObject.h" +#include "Sample.h" +#include "StringBuilder.h" +#include "Table.h" + +// Define counts, rate for error warnings for statistical profiles +#define MIN_PROF_CNT 100 +#define MAX_PROF_RATE 1000. + +#define NUM_DESCENDANTS(nd) ((nd)->descendants ? (nd)->descendants->size() : 0) +#define IS_LEAF(nd) ((nd)->descendants == NULL) + +#ifdef DEBUG +#define DBG(__func) __func +#else +#define DBG(__func) +#endif + +void +PathTree::construct (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType) +{ + dbev = _dbev; + indxtype = _indxtype; + pathTreeType = _pathTreeType; + status = 0; + nchunks = 0; + chunks = NULL; + nodes = 1; // don't use node 0 + nslots = 0; + slots = NULL; + root_idx = 0; + root = NULL; + depth = 1; + dnodes = 0; + phaseIdx = -1; + nexps = 0; + total_obj = NULL; + indx_expr = NULL; + statsq = NULL; + warningq = NULL; + cancel_ok = 1; + ptree_internal = NULL; + ftree_internal = NULL; + ftree_needs_update = false; + depth_map = NULL; + init (); +} + +PathTree::~PathTree () +{ + fini (); + for (long i = 0; i < nchunks; i++) + delete[] chunks[i]; + delete[] chunks; +} + +void +PathTree::init () +{ + fn_map = new DefaultMap<Function*, NodeIdx>; + stack_prop = PROP_NONE; + desc_htable_size = 511; + desc_htable_nelem = 0; + descHT = new hash_node_t*[desc_htable_size]; + for (int i = 0; i < desc_htable_size; i++) + descHT[i] = NULL; + pathMap = new CacheMap<uint64_t, NodeIdx>; + statsq = new Emsgqueue (NTXT ("statsq")); + warningq = new Emsgqueue (NTXT ("warningq")); + if (indxtype < 0) + { + Function *ftotal = dbeSession->get_Total_Function (); + if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE) + total_obj = ftotal; + else + total_obj = ftotal->find_dbeinstr (0, 0); + VMode view_mode = dbev->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; + if (dbeSession->is_omp_available () + && pathTreeType == PATHTREE_INTERNAL_OMP) + stack_prop = PROP_XSTACK; + } + } + else + { + total_obj = new IndexObject (indxtype, (uint64_t) - 2); + total_obj->set_name (dbe_strdup (NTXT ("<Total>"))); + char *idxname = dbeSession->getIndexSpaceName (indxtype); + if (streq (idxname, NTXT ("OMP_preg"))) + stack_prop = PROP_CPRID; + else if (streq (idxname, NTXT ("OMP_task"))) + stack_prop = PROP_TSKID; + else + indx_expr = dbeSession->getIndexSpaceExpr (indxtype); + } + root_idx = new_Node (0, total_obj, false); + root = NODE_IDX (root_idx); +} + +void +PathTree::fini () +{ + // For each node free its descendants vector + // and reset the node list of its function + for (long i = 1; i < nodes; i++) + { + Node *node = NODE_IDX (i); + if (node->descendants) + delete node->descendants; + } + nodes = 1; // don't use node 0 + + for (int i = 0; i < nslots; i++) + { + int **tmp = slots[i].mvals; + for (long j = 0; j < nchunks; j++) + delete[] tmp[j]; + delete[] tmp; + } + delete[] slots; + slots = NULL; + nslots = 0; + delete fn_map; + fn_map = NULL; + delete pathMap; + pathMap = NULL; + destroy (depth_map); + depth_map = NULL; + if (indxtype >= 0) + delete total_obj; + + for (int i = 0; i < desc_htable_size; i++) + { + hash_node_t *p = descHT[i]; + while (p) + { + hash_node_t *p1 = p; + p = p->next; + delete p1; + } + } + delete[] descHT; + delete statsq; + delete warningq; + depth = 1; + dnodes = 0; + phaseIdx = -1; + nexps = 0; + status = 0; +} + +PtreePhaseStatus +PathTree::reset () +{ + if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE) + return NORMAL; // never process reset for ftree_internal. + + if (dbeSession->is_omp_available () && dbev->get_view_mode () == VMODE_USER + && pathTreeType == PATHTREE_MAIN && ptree_internal == NULL) + ptree_internal = new PathTree (dbev, indxtype, PATHTREE_INTERNAL_OMP); + + if (phaseIdx != dbev->getPhaseIdx ()) + { + fini (); + init (); + phaseIdx = dbev->getPhaseIdx (); + ftree_needs_update = true; + } + for (; nexps < dbeSession->nexps (); nexps++) + { + ftree_needs_update = true; + if (add_experiment (nexps) == CANCELED) + return CANCELED; + } + + // LIBRARY_VISIBILITY + if (dbev->isNewViewMode ()) + dbev->resetNewViewMode (); + if (dbev->isShowHideChanged ()) + dbev->resetShowHideChanged (); + return NORMAL; +} + +int +PathTree::allocate_slot (int id, ValueTag vtype) +{ + + int i; + int slot_idx = find_slot (id); + if (slot_idx >= 0) + { + DBG (assert (slots[slot_idx].vtype == vtype)); + return slot_idx; + } + slot_idx = nslots++; + + Slot *old_slots = slots; + slots = new Slot[nslots]; + for (i = 0; i < slot_idx; i++) + slots[i] = old_slots[i]; + delete[] old_slots; + + slots[slot_idx].id = id; + slots[slot_idx].vtype = vtype; + int **ip = new int*[nchunks]; + for (i = 0; i < nchunks; i++) + ip[i] = NULL; + slots[slot_idx].mvals = ip; + + return slot_idx; +} + +void +PathTree::allocate_slots (Slot *new_slots, int new_nslots) +{ + // duplicates new_slots + + // if previously had more slots than currently requested, delete the data from those slots. + for (int i = new_nslots; i < nslots; i++) + { + int **tmp = slots[i].mvals; + for (long j = 0; j < nchunks; j++) + delete tmp[j]; + delete tmp; + } + if (new_nslots == 0) + { + nslots = new_nslots; + delete[] slots; + slots = NULL; + return; + } + + Slot *old_slots = slots; + slots = new Slot[new_nslots]; + for (int i = 0; i < new_nslots; i++) + { + slots[i] = new_slots[i]; // pick up id and vtype + if (i < nslots) + slots[i].mvals = old_slots[i].mvals; + else + { + if (nchunks == 0) + slots[i].mvals = NULL; + else + { + int **ip = new int*[nchunks]; + for (long j = 0; j < nchunks; j++) + ip[j] = NULL; + slots[i].mvals = ip; + } + } + } + nslots = new_nslots; + delete old_slots; +} + +int +PathTree::find_slot (int id) +{ + for (int i = 0; i < nslots; i++) + if (slots[i].id == id) + return i; + return -1; +} + +PathTree::NodeIdx +PathTree::new_Node (NodeIdx anc, Histable *instr, bool leaf) +{ + if (nodes >= nchunks * CHUNKSZ) + { + long idx = nchunks++; + + // Reallocate Node chunk array + Node **old_chunks = chunks; + chunks = new Node*[nchunks]; + for (long k = 0; k < idx; k++) + chunks[k] = old_chunks[k]; + delete[] old_chunks; + + // Reallocate metric value chunk arrays. + for (int i = 0; i < nslots; i++) + { + int **mvals = new int*[nchunks]; + for (long k = 0; k < idx; k++) + { + mvals[k] = slots[i].mvals[k]; + } + delete[] slots[i].mvals; + slots[i].mvals = mvals; + slots[i].mvals[idx] = NULL; + } + + // Allocate new chunk for nodes. + // Note that we don't need to allocate new chunks + // for metric values at this point as we rely on + // lazy allocation. + // + allocate_chunk (chunks, idx); + } + NodeIdx node_idx = nodes++; + Node *node = NODE_IDX (node_idx); + node->ancestor = anc; + node->descendants = leaf ? (Vector<NodeIdx>*)NULL : new Vector<NodeIdx>(2); + node->instr = instr; + Function *func = (Function*) (instr->convertto (Histable::FUNCTION)); + node->funclist = fn_map->get (func); + fn_map->put (func, node_idx); + return node_idx; +} + +PathTree::NodeIdx +PathTree::find_path (Experiment *exp, DataView *dview, long recIdx) +{ + if (indx_expr != NULL) + { + Expression::Context ctx (dbev, exp, dview, recIdx); + uint64_t idx = indx_expr->eval (&ctx); + Histable *cur_obj = dbeSession->createIndexObject (indxtype, idx); + cur_obj->set_name_from_context (&ctx); + NodeIdx dsc_idx = find_in_desc_htable (root_idx, cur_obj, true); + depth = 2; + return dsc_idx; + } + + bool showAll = dbev->isShowAll (); + int t_stack_prop = stack_prop; + void *stackId = dview->getObjValue (t_stack_prop, recIdx); + NodeIdx node_idx; + if (stackId != NULL) + { + // pathMap does not work with NULL key + node_idx = pathMap->get ((uint64_t) stackId); + if (node_idx != 0) + return node_idx; + } + Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId, !showAll); + int stack_size = stack->size (); + if (stack_size == 0) + return root_idx; + + node_idx = root_idx; + int thisdepth = 1; + + for (int i = stack_size - 1; i >= 0; i--) + { + bool leaf = (i == 0); + Histable *cur_addr = stack->fetch (i); + + // bail out of loop if load object API-only is set + // and this is not the top frame + // This is now done in HSTACK if hide is set + + 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 (showAll && dbev->get_lo_expand (segx) == LIBEX_API + && i != stack_size - 1) + leaf = true; + } + + NodeIdx dsc_idx = find_desc_node (node_idx, cur_addr, leaf); + thisdepth++; + node_idx = dsc_idx; + + // LIBEX_API processing might have set leaf to true + if (leaf) + break; + } + if (thisdepth > depth) + depth = thisdepth; + delete stack; + pathMap->put ((uint64_t) stackId, node_idx); + return node_idx; +} + +static int +desc_node_comp (const void *s1, const void *s2, const void *ptree) +{ + PathTree::NodeIdx t1, t2; + t1 = *(PathTree::NodeIdx *)s1; + t2 = *(PathTree::NodeIdx *)s2; + PathTree* Ptree = (PathTree *) ptree; + PathTree::Node *n1 = Ptree->NODE_IDX (t1); + PathTree::Node *n2 = Ptree->NODE_IDX (t2); + Histable *d1 = n1->instr; + Histable *d2 = n2->instr; + if (d1->id < d2->id) + return -1; + else if (d1->id > d2->id) + return +1; + else + return 0; +} + +PathTree::NodeIdx +PathTree::find_in_desc_htable (NodeIdx node_idx, Histable *instr, bool leaf) +{ + unsigned int hash_code = (unsigned int) instr->id % desc_htable_size; + Node *node = NODE_IDX (node_idx); + hash_node_t *p = NULL; + for (p = descHT[hash_code]; p; p = p->next) + { + Node *dsc = NODE_IDX (p->nd); + Histable *dinstr = dsc->instr; + if (dinstr->id == instr->id && leaf == IS_LEAF (dsc)) + return p->nd; + } + // Not found + NodeIdx dsc_idx = new_Node (node_idx, instr, leaf); + node->descendants->append (dsc_idx); + p = new hash_node_t (); + p->nd = dsc_idx; + p->next = descHT[hash_code]; + descHT[hash_code] = p; + desc_htable_nelem++; + + // time to resize + if (desc_htable_nelem == desc_htable_size) + { + int old_htable_size = desc_htable_size; + desc_htable_size = old_htable_size * 2 + 1; + hash_node_t **old_htable = descHT; + descHT = new hash_node_t*[desc_htable_size]; + for (int i = 0; i < desc_htable_size; i++) + descHT[i] = NULL; + + for (int i = 0; i < old_htable_size; i++) + if (old_htable[i] != NULL) + { + hash_node *old_p; + hash_node_t *hash_p = old_htable[i]; + while (hash_p != NULL) + { + hash_node_t *new_p = new hash_node_t (); + new_p->nd = hash_p->nd; + Node *dnode = NODE_IDX (hash_p->nd); + Histable *dnode_instr = dnode->instr; + hash_code = (unsigned int) dnode_instr->id % desc_htable_size; + new_p->next = descHT[hash_code]; + descHT[hash_code] = new_p; + old_p = hash_p; + hash_p = hash_p->next; + delete old_p; + } + } + delete[] old_htable; + } + return dsc_idx; +} + +PathTree::NodeIdx +PathTree::find_desc_node (NodeIdx node_idx, Histable *instr, bool leaf) +{ + // Binary search. All nodes are ordered by Histable::id. + + // We have a special case when two nodes with the same + // id value may co-exist: one representing a leaf node and + // another one representing a call site. + Node *node = NODE_IDX (node_idx); + int left = 0; + int right = NUM_DESCENDANTS (node) - 1; + while (left <= right) + { + int index = (left + right) / 2; + NodeIdx dsc_idx = node->descendants->fetch (index); + Node *dsc = NODE_IDX (dsc_idx); + Histable *dinstr = dsc->instr; + if (instr->id < dinstr->id) + right = index - 1; + else if (instr->id > dinstr->id) + left = index + 1; + else if (leaf == IS_LEAF (dsc)) + return dsc_idx; + else if (leaf) + right = index - 1; + else + left = index + 1; + } + + // None was found. Create one. + NodeIdx dsc_idx = new_Node (node_idx, instr, leaf); + node->descendants->insert (left, dsc_idx); + return dsc_idx; +} + +PtreePhaseStatus +PathTree::process_packets (Experiment *exp, DataView *packets, int data_type) +{ + Expression::Context ctx (dbev, exp); + char *progress_bar_msg = NULL; + int progress_bar_percent = -1; + + Vector<BaseMetric*> *mlist = dbev->get_all_reg_metrics (); + Vector<BaseMetric*> mlist2; + StringBuilder stb; + for (int midx = 0, mlist_sz = mlist->size (); midx < mlist_sz; ++midx) + { + BaseMetric *mtr = mlist->fetch (midx); + if (mtr->get_packet_type () == data_type && + (mtr->get_expr () == NULL || mtr->get_expr ()->passes (&ctx))) + { + Hwcentry *hwc = mtr->get_hw_ctr (); + if (hwc) + { + stb.setLength (0); + // XXX this should be done at metric registration + Collection_params *col_params = exp->get_params (); + for (int i = 0; i < MAX_HWCOUNT; i++) + { + // We may have duplicate counters in col_params, + // check for all (see 5081284). + if (dbe_strcmp (hwc->name, col_params->hw_aux_name[i]) == 0) + { + if (stb.length () != 0) + stb.append (NTXT ("||")); + stb.append (NTXT ("HWCTAG==")); + stb.append (i); + } + } + if (stb.length () == 0) + continue; + stb.append (NTXT ("&& ((HWCINT & ")); + stb.append ((long long) HWCVAL_ERR_FLAG); + stb.append (NTXT (")==0)")); + char *s = stb.toString (); + mtr->set_cond_spec (s); + free (s); + } + ValueTag vtype = mtr->get_vtype (); + switch (vtype) + { + case VT_INT: + case VT_ULLONG: + case VT_LLONG: + break; // nothing to do + default: + vtype = VT_ULLONG; // ym: not sure when this would happen + break; + } + allocate_slot (mtr->get_id (), vtype); + mlist2.append (mtr); + } + } + + Slot **mslots = new Slot*[mlist2.size ()]; + for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx) + { + BaseMetric *mtr = mlist2.fetch (midx); + int id = mtr->get_id (); + int slot_ind = find_slot (id); + mslots[midx] = SLOT_IDX (slot_ind); + } + + for (long i = 0, packets_sz = packets->getSize (); i < packets_sz; ++i) + { + if (dbeSession->is_interactive ()) + { + if (NULL == progress_bar_msg) + progress_bar_msg = dbe_sprintf (GTXT ("Processing Experiment: %s"), + get_basename (exp->get_expt_name ())); + int val = (int) (100 * i / packets_sz); + if (val > progress_bar_percent) + { + progress_bar_percent += 10; + if (theApplication->set_progress (val, progress_bar_msg) + && cancel_ok) + { + delete[] mslots; + return CANCELED; + } + } + } + + NodeIdx path_idx = 0; + ctx.put (packets, i); + + for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx) + { + BaseMetric *mtr = mlist2.fetch (midx); + if (mtr->get_cond () != NULL && !mtr->get_cond ()->passes (&ctx)) + continue; + + int64_t mval = mtr->get_val ()->eval (&ctx); + if (mval == 0) + continue; + if (path_idx == 0) + path_idx = find_path (exp, packets, i); + NodeIdx node_idx = path_idx; + Slot *mslot = mslots[midx]; + while (node_idx) + { + INCREMENT_METRIC (mslot, node_idx, mval); + node_idx = NODE_IDX (node_idx)->ancestor; + } + } + } + if (dbeSession->is_interactive ()) + free (progress_bar_msg); + delete[] mslots; + if (indx_expr != NULL) + root->descendants->sort ((CompareFunc) desc_node_comp, this); + return NORMAL; +} + +DataView * +PathTree::get_filtered_events (int exp_index, int data_type) +{ + if (indx_expr != NULL) + { + IndexObjType_t *indexObj = dbeSession->getIndexSpace (indxtype); + if (indexObj->memObj && data_type != DATA_HWC) + return NULL; + } + return dbev->get_filtered_events (exp_index, data_type); +} + +PtreePhaseStatus +PathTree::add_experiment (int exp_index) +{ + StringBuilder sb; + char *expt_name; + char *base_name; + Emsg *m; + Experiment *experiment = dbeSession->get_exp (exp_index); + if (experiment->broken != 0) + return NORMAL; + status = 0; + expt_name = experiment->get_expt_name (); + base_name = get_basename (expt_name); + + hrtime_t starttime = gethrtime (); + hrtime_t startvtime = gethrvtime (); + + // Experiment::getEndTime was initially implemented as + // returning exp->last_event. To preserve the semantics + // new Experiment::getLastEvent() is used here. + hrtime_t tot_time = experiment->getLastEvent () - experiment->getStartTime (); + + if (!dbev->isShowAll () && (dbev->isShowHideChanged () + || dbev->isNewViewMode ())) + experiment->resetShowHideStack (); + + // To report experiment index to the user, + // start numeration from 1, not 0 + sb.sprintf (GTXT ("PathTree processing experiment %d (`%s'); duration %lld.%06lld"), + exp_index + 1, base_name, + tot_time / NANOSEC, (tot_time % NANOSEC / 1000)); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + + DataView *prof_packet = get_filtered_events (exp_index, DATA_CLOCK); + if (prof_packet && prof_packet->getSize () > 0) + { + if (process_packets (experiment, prof_packet, DATA_CLOCK) == CANCELED) + return CANCELED; + long clock_cnt = prof_packet->getSize (); + double clock_rate; + if (tot_time != 0) + clock_rate = (double) clock_cnt / (double) tot_time * (double) NANOSEC; + else + clock_rate = (double) 0.; + if (experiment->timelineavail) + sb.sprintf (GTXT (" Processed %ld clock-profile events (%3.2f/sec.)"), + clock_cnt, clock_rate); + else + sb.sprintf (GTXT (" Processed %ld clock-profile events"), clock_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + + // check for statistical validity + if ((experiment->timelineavail == true) + && !dbev->get_filter_active () && (clock_cnt < MIN_PROF_CNT)) + { + sb.sprintf (GTXT ("WARNING: too few clock-profile events (%ld) in experiment %d (`%s') for statistical validity"), + clock_cnt, exp_index + 1, base_name); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + } + + DataView *sync_packet = get_filtered_events (exp_index, DATA_SYNCH); + if (sync_packet && sync_packet->getSize () > 0) + { + if (process_packets (experiment, sync_packet, DATA_SYNCH) == CANCELED) + return CANCELED; + long sync_cnt = sync_packet->getSize (); + sb.sprintf (GTXT (" Processed %ld synctrace events"), sync_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + + DataView *iotrace_packet = get_filtered_events (exp_index, DATA_IOTRACE); + if (iotrace_packet && iotrace_packet->getSize () > 0) + { + if (process_packets (experiment, iotrace_packet, DATA_IOTRACE) == CANCELED) + return CANCELED; + long iotrace_cnt = iotrace_packet->getSize (); + sb.sprintf (GTXT (" Processed %ld IO trace events"), iotrace_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + + DataView *hwc_packet = get_filtered_events (exp_index, DATA_HWC); + if (hwc_packet && hwc_packet->getSize () > 0) + { + if (process_packets (experiment, hwc_packet, DATA_HWC) == CANCELED) + return CANCELED; + long hwc_cnt = hwc_packet->getSize (); + double hwc_rate = (double) hwc_cnt / (double) tot_time * (double) NANOSEC; + if (experiment->timelineavail) + sb.sprintf (GTXT (" Processed %ld hwc-profile events (%3.2f/sec.)"), + hwc_cnt, hwc_rate); + else + sb.sprintf (GTXT (" Processed %ld hwc-profile events"), hwc_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + + // check for statistical validity + if (experiment->timelineavail && !dbev->get_filter_active () && (hwc_cnt < MIN_PROF_CNT)) + { + sb.sprintf (GTXT ("WARNING: too few HW counter profile events (%ld) in experiment %d (`%s') for statistical validity"), + hwc_cnt, exp_index + 1, base_name); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + } + + DataView *heap_packet = get_filtered_events (exp_index, DATA_HEAP); + if (heap_packet && heap_packet->getSize () > 0) + { + if (process_packets (experiment, heap_packet, DATA_HEAP) == CANCELED) + return CANCELED; + long heap_cnt = heap_packet->getSize (); + sb.sprintf (GTXT (" Processed %ld heaptrace events"), heap_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + + DataView *race_packet = get_filtered_events (exp_index, DATA_RACE); + if (race_packet && race_packet->getSize () > 0) + { + if (process_packets (experiment, race_packet, DATA_RACE) == CANCELED) + return CANCELED; + long race_cnt = race_packet->getSize (); + sb.sprintf (GTXT (" Processed %ld race access events"), race_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + + DataView *deadlock_packet = get_filtered_events (exp_index, DATA_DLCK); + if (deadlock_packet && deadlock_packet->getSize () > 0) + { + if (process_packets (experiment, deadlock_packet, DATA_DLCK) == CANCELED) + return CANCELED; + long race_cnt = deadlock_packet->getSize (); + sb.sprintf (GTXT (" Processed %ld race access events"), race_cnt); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + } + + hrtime_t pathtime = gethrtime () - starttime; + hrtime_t pathvtime = gethrvtime () - startvtime; + sb.sprintf (GTXT ("PathTree time = %lld.%06lld CPU-time %lld.%06lld\n"), + pathtime / NANOSEC, (pathtime % NANOSEC) / 1000, + pathvtime / NANOSEC, (pathvtime % NANOSEC) / 1000); + m = new Emsg (CMSG_COMMENT, sb); + statsq->append (m); + return NORMAL; +} + +Hist_data * +PathTree::compute_metrics (MetricList *mlist, Histable::Type type, + Hist_data::Mode mode, Vector<Histable*> *objs, + Histable *context, Vector<Histable*> *sel_objs, + PtreeComputeOption computeOpt) +{ + VMode view_mode = dbev->get_view_mode (); + + // For displaying disassembly correctly in user mode with openmp + if (ptree_internal != NULL && + (view_mode == VMODE_EXPERT || + (view_mode == VMODE_USER && (type == Histable::INSTR + || (dbev->isOmpDisMode () + && type == Histable::FUNCTION + && mode == Hist_data::CALLEES + && computeOpt == COMPUTEOPT_OMP_CALLEE)) + ))) + return ptree_internal->compute_metrics (mlist, type, mode, objs, context, + sel_objs); + + PtreePhaseStatus resetStatus = reset (); + + hist_data = new Hist_data (mlist, type, mode); + int nmetrics = mlist->get_items ()->size (); + int sort_ind = -1; + Hist_data::HistItem *hi; + int index; + + if (status != 0 || resetStatus == CANCELED) + return hist_data; + + hist_data->set_status (Hist_data::SUCCESS); + if (dbeSession->is_interactive () && mode != Hist_data::CALLEES) + theApplication->set_progress (0, GTXT ("Constructing Metrics")); + + xlate = new int[nmetrics]; + for (int mind = 0; mind < nmetrics; mind++) + { + Metric *mtr = mlist->get (mind); + xlate[mind] = find_slot (mtr->get_id ()); + } + + // Compute dynamic metrics + obj_list = new Histable*[depth]; + if ((type == Histable::LINE || type == Histable::INSTR) + && mode == Hist_data::CALLERS) + node_list = new Node*[depth]; + percent = 0; + ndone = 0; + if (mode == Hist_data::MODL) + { + Histable *obj = objs && objs->size () > 0 ? objs->fetch (0) : NULL; + if (obj != NULL) + { + switch (obj->get_type ()) + { + case Histable::FUNCTION: + { + Vector<Function*> *funclist = new Vector<Function*>; + funclist->append ((Function*) obj); + get_metrics (funclist, context); + delete funclist; + break; + } + case Histable::MODULE: + { + Vector<Histable*> *comparableModules = obj->get_comparable_objs (); + if (comparableModules != NULL) + { + Vector<Function*> *functions = new Vector<Function*>; + for (int i = 0; i < comparableModules->size (); i++) + { + Module *mod = (Module*) comparableModules->fetch (i); + if (mod) + { + bool found = false; + for (int i1 = 0; i1 < i; i1++) + { + if (mod == comparableModules->fetch (i1)) + { + found = true; + break; + } + } + if (!found) + functions->addAll (mod->functions); + } + } + get_metrics (functions, context); + delete functions; + } + else + get_metrics (((Module*) obj)->functions, context); + break; + } + case Histable::SOURCEFILE: + get_metrics (((SourceFile *) obj)->get_functions (), context); + break; + default: + DBG (assert (0)); + } + } + } + else if (mode == Hist_data::CALLERS) + { + if (objs && objs->size () > 0) + get_clr_metrics (objs); + } + else if (mode == Hist_data::CALLEES) + { + if (objs && objs->size () > 0) + get_cle_metrics (objs); + else // Special case: get root + get_cle_metrics (NULL); + } + else if (mode == Hist_data::SELF) + { + if (objs->size () == 1) + { + Histable *obj = objs->fetch (0); + if (obj != NULL) + { + if (obj->get_type () == Histable::LINE) + { + Vector<Function*> *funclist = new Vector<Function*>; + for (DbeLine *dl = (DbeLine*) obj->convertto (Histable::LINE); + dl; dl = dl->dbeline_func_next) + if (dl->func) + funclist->append (dl->func); + + get_self_metrics (obj, funclist, sel_objs); + delete funclist; + } + else if (obj->get_type () == Histable::FUNCTION + || obj->get_type () == Histable::INSTR) + { + // Use shortcut for functions and oth. + if (context) + { + Vector<Function*> *funclist = NULL; + if (context->get_type () == Histable::MODULE) + funclist = ((Module*) context)->functions->copy (); + else + { + funclist = new Vector<Function*>; + funclist->append ((Function*) context); + } + get_self_metrics (obj, funclist, sel_objs); + delete funclist; + } + else + get_self_metrics (objs); + } + else + get_self_metrics (objs); + } + } + else + get_self_metrics (objs); + } + else // Hist_data::ALL + get_metrics (root_idx, 0); + + delete[] obj_list; + if ((type == Histable::LINE || type == Histable::INSTR) + && mode == Hist_data::CALLERS) + delete[] node_list; + + // Postprocess; find total + for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++) + { + Metric *mtr = mlist->get_items ()->get (mind); + Metric::SubType subtype = mtr->get_subtype (); + ValueTag vtype = mtr->get_vtype (); + hist_data->total->value[mind].tag = vtype; + + switch (vtype) + { + // ignoring the following cases (why?) + case VT_SHORT: + case VT_FLOAT: + case VT_HRTIME: + case VT_LABEL: + case VT_ADDRESS: + case VT_OFFSET: + break; + + case VT_INT: + // Calculate total as the sum of all values in hist_data for + // ATTRIBUTED metrics only. For all others, use root node values. + // + if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES) + && subtype == Metric::ATTRIBUTED) + { + hist_data->total->value[mind].i = 0; + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hist_data->total->value[mind].i += hi->value[mind].i; + } + if (mode == Hist_data::CALLEES) + hist_data->total->value[mind].i += hist_data->gprof_item->value[mind].i; + } + else if (xlate[mind] != -1) + ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], + root_idx); + break; + + case VT_LLONG: + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hi->value[mind].tag = vtype; + } + + if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES) + && subtype == Metric::ATTRIBUTED) + { + hist_data->total->value[mind].ll = 0; + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hist_data->total->value[mind].ll += hi->value[mind].ll; + } + if (mode == Hist_data::CALLEES) + hist_data->total->value[mind].ll += hist_data->gprof_item->value[mind].ll; + } + else if (xlate[mind] != -1) + ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx); + break; + + case VT_ULLONG: + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hi->value[mind].tag = vtype; + } + if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES) + && subtype == Metric::ATTRIBUTED) + { + hist_data->total->value[mind].ull = 0; + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hist_data->total->value[mind].ull += hi->value[mind].ull; + } + if (mode == Hist_data::CALLEES) + hist_data->total->value[mind].ull += hist_data->gprof_item->value[mind].ull; + } + else if (xlate[mind] != -1) + ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx); + break; + + case VT_DOUBLE: + double prec = mtr->get_precision (); + ValueTag vt = (xlate[mind] != -1) ? slots[xlate[mind]].vtype : VT_INT; + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + double val = (vt == VT_LLONG ? hi->value[mind].ll : + (vt == VT_ULLONG ? hi->value[mind].ull + : hi->value[mind].i)); + hi->value[mind].tag = vtype; + hi->value[mind].d = val / prec; + } + + if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES) + && subtype == Metric::ATTRIBUTED) + { + hist_data->total->value[mind].d = 0.0; + Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi) + { + hist_data->total->value[mind].d += hi->value[mind].d; + } + if (mode == Hist_data::CALLEES) + hist_data->total->value[mind].d += + (double) (vt == VT_LLONG ? hist_data->gprof_item->value[mind].ll : + (vt == VT_ULLONG ? hist_data->gprof_item->value[mind].ull : + hist_data->gprof_item->value[mind].i)) / prec; + } + else if (xlate[mind] != -1) + { + TValue& total = hist_data->total->value[mind]; + ASN_METRIC_VAL (total, slots[xlate[mind]], root_idx); + double val = (vt == VT_LLONG ? total.ll : + (vt == VT_ULLONG ? total.ll : total.i)); + total.d = val / prec; + } + break; + } + } + delete[] xlate; + + // Determine by which metric to sort if any + bool rev_sort = mlist->get_sort_rev (); + for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++) + { + Metric *mtr = mlist->get_items ()->get (mind); + if (mlist->get_sort_ref_index () == mind) + sort_ind = mind; + + switch (mtr->get_type ()) + { + case BaseMetric::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; + } + break; + case BaseMetric::ADDRESS: + Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi) + { + Histable *h = mtr->get_comparable_obj (hi->obj); + hi->value[mind].tag = VT_ADDRESS; + hi->value[mind].ll = h ? h->get_addr () : 0; + } + break; + case BaseMetric::DERIVED: + { + Definition *def = mtr->get_definition (); + long *map = def->get_map (); + for (long i1 = 0, sz1 = hist_data->hist_items->size (); i1 < sz1; i1++) + { + /* Hist_data::HistItem * */hi = hist_data->hist_items->get (i1); + hi->value[mind].tag = VT_DOUBLE; + hi->value[mind].d = def->eval (map, hi->value); + } + hist_data->total->value[mind].tag = VT_DOUBLE; + hist_data->total->value[mind].d = def->eval (map, hist_data->total->value); + } + break; + default: + break; + } + } + + hist_data->sort (sort_ind, rev_sort); + hist_data->compute_minmax (); + if (dbeSession->is_interactive () && mode != Hist_data::CALLERS) + theApplication->set_progress (0, GTXT ("")); + +#if DEBUG_FTREE + if (ftree_hist_data) + { + bool matches = ftree_debug_match_hist_data (hist_data, ftree_hist_data); + if (!matches) + assert (false); + delete hist_data; + hist_data = ftree_hist_data; // return the debug version + } +#endif + return hist_data; +} + +#if DEBUG_FTREE +bool +PathTree::ftree_debug_match_hist_data (Hist_data *data /* ref */, + Hist_data *data_tmp) +{ + if (data->get_status () != Hist_data::SUCCESS) + { + DBG (assert (false)); + return false; + } + if (data == NULL && data != data_tmp) + { + DBG (assert (false)); + return false; + } + + MetricList *mlist; + mlist = data->get_metric_list (); + MetricList *mlist_tmp; + mlist_tmp = data_tmp->get_metric_list (); + if (mlist->size () != mlist_tmp->size ()) + { + DBG (assert (false)); + return false; + } + + // Get table size: count visible metrics + int nitems = data->size (); + if (data->size () != data_tmp->size ()) + { + DBG (assert (false)); + return false; + } + + for (int i = 0; i < nitems; ++i) + { + Hist_data::HistItem *item = data->fetch (i); + Hist_data::HistItem *item_tmp = data_tmp->fetch (i); + if (item->obj->id != item_tmp->obj->id) + { + DBG (assert (false)); + return false; + } + } + + for (long i = 0, sz = mlist->size (); i < sz; i++) + { + long met_ind = i; + Metric *mitem = mlist->get (i); + Metric *mitem_tmp = mlist_tmp->get (i); + + if (mitem->get_id () != mitem_tmp->get_id ()) + { + DBG (assert (false)); + return false; + } + if (mitem->get_visbits () != mitem_tmp->get_visbits ()) + { + DBG (assert (false)); + return false; + } + if (mitem->get_vtype () != mitem_tmp->get_vtype ()) + { + DBG (assert (false)); + return false; + } + + if (!mitem->is_visible () && !mitem->is_tvisible () + && !mitem->is_pvisible ()) + continue; + // table->append(dbeGetTableDataOneColumn(data, i)); + for (long row = 0, sz_row = data->size (); row < sz_row; row++) + { + Metric *m = mitem; + TValue res; + TValue res_tmp; + TValue *v = data->get_value (&res, met_ind, row); + TValue *v_tmp = data_tmp->get_value (&res_tmp, met_ind, row); + if ((m->get_visbits () & VAL_RATIO) != 0) + { + if (v->tag != VT_LABEL) + { + if (v->to_double () != v_tmp->to_double ()) + { + DBG (assert (false)); + return false; + } + } + continue; + } + switch (m->get_vtype ()) + { + case VT_DOUBLE: + { + double diff = v->d - v_tmp->d; + if (diff < 0) diff = -diff; + if (diff > 0.0001) + { + DBG (assert (false)); + return false; + } + else + DBG (assert (true)); + break; + } + case VT_INT: + if (v->i != v_tmp->i) + { + DBG (assert (false)); + return false; + } + break; + case VT_ULLONG: + case VT_LLONG: + case VT_ADDRESS: + if (v->ll != v_tmp->ll) + { + DBG (assert (false)); + return false; + } + break; + + case VT_LABEL: + if (dbe_strcmp (v->l, v_tmp->l)) + { + DBG (assert (false)); + return false; + } + break; + default: + DBG (assert (false)); + return false; + } + } + } + return true; +} +#endif + +Histable * +PathTree::get_hist_func_obj (Node *node) +{ + LoadObject *lo; + Function *func; + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + // LIBRARY VISIBILITY + lo = func->module->loadobject; + if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE) + return lo->get_hide_function (); + return get_compare_obj (func); +} + +Histable * +PathTree::get_hist_obj (Node *node, Histable* context) +{ + LoadObject *lo; + Function *func; + switch (hist_data->type) + { + case Histable::INSTR: + if (hist_data->mode == Hist_data::MODL) + { + if (node->instr->get_type () != Histable::INSTR) + return NULL; + } + else + { + // LIBRARY VISIBILITY + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + lo = func->module->loadobject; + if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE) + return lo->get_hide_function (); + } + return node->instr; + + case Histable::LINE: + if (hist_data->mode != Hist_data::MODL) + { + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + lo = func->module->loadobject; + // LIBRARY VISIBILITY + if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE) + return lo->get_hide_function (); + } + // For openmp user mode - the stack is already made with dbelines, + // no need to convert it + if (node->instr->get_type () == Histable::LINE) + return node->instr; + return node->instr->convertto (Histable::LINE, context); + + case Histable::FUNCTION: + if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE && node->ancestor != 0) + func = (Function*) node->instr; + else + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + lo = func->module->loadobject; + // LIBRARY VISIBILITY + if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE) + return lo->get_hide_function (); + return get_compare_obj (func); + case Histable::MODULE: + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + return func->module; + case Histable::LOADOBJECT: + func = (Function*) (node->instr->convertto (Histable::FUNCTION)); + return func->module->loadobject; + case Histable::INDEXOBJ: + case Histable::MEMOBJ: + return node->instr; + default: + DBG (assert (0)); + } + return NULL; +} + +Histable * +PathTree::get_compare_obj (Histable *obj) +{ + if (obj && dbev->comparingExperiments ()) + obj = dbev->get_compare_obj (obj); + return obj; +} + +void +PathTree::get_metrics (NodeIdx node_idx, int dpth) +{ + Node *node = NODE_IDX (node_idx); + Histable *cur_obj = get_hist_obj (node); + obj_list[dpth] = cur_obj; + + // Check for recursion (inclusive metrics) + int incl_ok = 1; + for (int i = dpth - 1; i >= 0; i--) + if (cur_obj == obj_list[i]) + { + incl_ok = 0; + break; + } + + // Check for leaf nodes (exclusive metrics) + int excl_ok = 0; + if (IS_LEAF (node) || node == NODE_IDX (root_idx)) + excl_ok = 1; + + // We shouldn't eliminate empty subtrees here because + // we create the list of hist items dynamically and want + // one for each object in the tree. + cur_obj = get_compare_obj (cur_obj); + Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj); + DBG (assert (hi != NULL)); + + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + + switch (subtype) + { + case Metric::INCLUSIVE: + if (incl_ok && hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + case Metric::EXCLUSIVE: + if (excl_ok && hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + // ignoring the following cases (why?) + case Metric::STATIC: + case Metric::ATTRIBUTED: + break; + case Metric::DATASPACE: + if (hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + } + } + + if (dbeSession->is_interactive ()) + { + ndone++; + int new_percent = 95 * ndone / nodes; + if (new_percent > percent) + { + percent = new_percent; + theApplication->set_progress (percent, NULL); + } + } + + // Recursively process all descendants + int index; + int dsize = NUM_DESCENDANTS (node); + for (index = 0; index < dsize; index++) + get_metrics (node->descendants->fetch (index), dpth + 1); +} + +void +PathTree::get_clr_metrics (Vector<Histable*> *objs, NodeIdx node_idx, + int pmatch, int dpth) +{ + Node *node = NODE_IDX (node_idx); + Histable *cur_obj; + if (hist_data->type == Histable::LINE || hist_data->type == Histable::INSTR) + { + cur_obj = get_hist_func_obj (node); + node_list[dpth] = node; + } + else + cur_obj = get_hist_obj (node); + obj_list[dpth] = cur_obj; + + bool match = false; + int nobj = objs->size (); + if (dpth + 1 >= nobj) + { + match = true; + for (int i = 0; i < nobj; ++i) + { + if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i]) + { + match = false; + break; + } + } + } + + Hist_data::HistItem *hi = NULL; + Hist_data::HistItem *hi_adj = NULL; + if (match && dpth >= nobj) + { + if (hist_data->type == Histable::LINE + || hist_data->type == Histable::INSTR) + hi = hist_data->append_hist_item (get_hist_obj (node_list[dpth - nobj])); + else + hi = hist_data->append_hist_item (obj_list[dpth - nobj]); + + if (pmatch >= 0 && pmatch >= nobj) + { + if (hist_data->type == Histable::LINE + || hist_data->type == Histable::INSTR) + hi_adj = hist_data->append_hist_item (get_hist_obj ( + node_list[pmatch - nobj])); + else + hi_adj = hist_data->append_hist_item (obj_list[pmatch - nobj]); + } + } + + if (hi != NULL) + { + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + + switch (subtype) + { + case Metric::ATTRIBUTED: + if (hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + if (hi_adj) + SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx); + break; + case Metric::STATIC: + case Metric::EXCLUSIVE: + case Metric::INCLUSIVE: + case Metric::DATASPACE: + break; + } + } + } + + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + get_clr_metrics (objs, node->descendants->fetch (index), + match ? dpth : pmatch, dpth + 1); +} + +void +PathTree::get_clr_metrics (Vector<Histable*> *objs) +{ + get_clr_metrics (objs, root_idx, -1, 0); +} + +void +PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int pcle, + int pmatch, int dpth) +{ + Node *node = NODE_IDX (node_idx); + Histable *cur_obj = get_hist_obj (node); + obj_list[dpth] = cur_obj; + + bool match = false; + int nobj = objs->size (); + if (dpth + 1 >= nobj) + { + match = true; + for (int i = 0; i < nobj; ++i) + if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i]) + { + match = false; + break; + } + } + + Hist_data::HistItem *hi = NULL; + Hist_data::HistItem *hi_adj = NULL; + if (pmatch >= 0 && dpth == pmatch + 1) + hi = hist_data->append_hist_item (cur_obj); + if (match && IS_LEAF (node)) + hi = hist_data->gprof_item; + if (pcle >= 0) + hi_adj = hist_data->append_hist_item (obj_list[pcle]); + + if (hi != NULL) + { + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + if (subtype == Metric::ATTRIBUTED) + { + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + if (hi_adj) + SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx); + } + } + } + + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + get_cle_metrics (objs, node->descendants->fetch (index), + pmatch >= 0 && dpth == pmatch + 1 ? dpth : pcle, + match ? dpth : pmatch, dpth + 1); +} + +void +PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int dpth) +{ + Node *node = NODE_IDX (node_idx); + Histable *cur_obj = get_hist_obj (node); + Hist_data::HistItem *hi = NULL; + if (NULL == objs) // Special case: get root + hi = hist_data->append_hist_item (cur_obj); + else + { + if (dpth == objs->size ()) + hi = hist_data->append_hist_item (cur_obj); + else if (cur_obj == objs->fetch (dpth)) + { + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + get_cle_metrics (objs, node->descendants->fetch (index), dpth + 1); + if (dpth == objs->size () - 1 && dsize == 0) + hi = hist_data->gprof_item; + } + } + + if (hi != NULL) + { + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + if (subtype == Metric::ATTRIBUTED) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + } + } +} + +void +PathTree::ftree_reset () +{ + if (pathTreeType == PATHTREE_MAIN && indxtype < 0) + { + reset (); + if (ftree_needs_update) + { + if (ftree_internal == NULL) + { + ftree_internal = new PathTree (dbev, indxtype, + PATHTREE_INTERNAL_FUNCTREE); + if (ftree_internal == NULL) + return; + } + ftree_internal->ftree_build (this); + ftree_needs_update = false; + } + } +} + +void +PathTree::ftree_build (PathTree * mstr) +{ + fini (); + init (); + allocate_slots (mstr->slots, mstr->nslots); + ftree_build (mstr, mstr->root_idx, root_idx); + depth = mstr->depth; + depth_map_build (); +} + +#if DEBUG_FTREE // possibly TBR +void +PathTree::ftree_dump () +{ + hrtime_t starttime, endtime; + int nmetrics = 1; + // int nmetrics = nslots; + for (int kk = 0; kk < nmetrics; kk++) + { + int id = slots[kk].id; + starttime = gethrtime (); + long nodecnt = 0; + for (int ii = 0; ii < depth; ii++) + { + Vector<Vector<void*>*> *tmp = (Vector<Vector<void*>*>*)get_ftree_level + (id, ii); + if (tmp == NULL) + continue; + long sz = tmp->get (0)->size (); + nodecnt += sz; +#if 1 + // fprintf(stderr, "... finished (%ld nodes)\n", sz); +#else + Vector<NodeIdx> *nodeIdxList = (Vector<NodeIdx> *)tmp->get (0); + Vector<NodeIdx> *ancestorNodeIdxList = (Vector<NodeIdx> *)tmp->get (1); + Vector<uint64_t> *idList = (Vector<uint64_t> *)tmp->get (2); + Vector<uint64_t> *vals = (Vector<uint64_t> *)tmp->get (3); + for (int jj = 0; jj < sz; jj++) + fprintf (stderr, " ...%d:%d node=%ld, anc=%ld, id=%llu, val=%llu\n", + sz, jj, nodeIdxList->get (jj), + ancestorNodeIdxList->get (jj), + idList->get (jj), vals->get (jj)); +#endif + destroy (tmp); + } + endtime = gethrtime (); + fprintf (stderr, "====================== %ld nodes time=%llu\n", + nodecnt, (endtime - starttime) / 1000 / 1000); + } +} +#endif + +// ftree: translate mstr Histable::INSTR to Histable::FUNCTION +void +PathTree::ftree_build (PathTree *mstr, NodeIdx mstr_node_idx, + NodeIdx local_node_idx) +{ + // requires: slots, nslots + Node *mstr_node = mstr->NODE_IDX (mstr_node_idx); + int dsize = NUM_DESCENDANTS (mstr_node); + + // Add metrics + for (int i = 0; i < nslots; i++) + { + if (i >= mstr->nslots) + continue; //weird + if (slots[i].vtype != mstr->slots[i].vtype) + continue; //weird + TValue val; + val.ll = 0; + mstr->ASN_METRIC_VAL (val, mstr->slots[i], mstr_node_idx); + int64_t mval; + switch (slots[i].vtype) + { + case VT_ULLONG: + case VT_LLONG: + mval = val.ll; + break; + case VT_INT: + mval = val.i; + break; + default: + mval = 0; + break; + } + if (mval) + { + Slot * mslot = SLOT_IDX (i); + if (mslot) + INCREMENT_METRIC (mslot, local_node_idx, mval); + } + } + + // Recursively process all descendants + for (int index = 0; index < dsize; index++) + { + NodeIdx mstr_desc_node_idx = mstr_node->descendants->fetch (index); + Node *mstr_desc_node = mstr->NODE_IDX (mstr_desc_node_idx); + Function *func = (Function*) mstr_desc_node->instr->convertto (Histable::FUNCTION); + int mstr_desc_dsize = NUM_DESCENDANTS (mstr_desc_node); + bool leaf = (mstr_desc_dsize == 0); + NodeIdx local_desc_node_idx = find_desc_node (local_node_idx, func, leaf); + ftree_build (mstr, mstr_desc_node_idx, local_desc_node_idx); + } +} + +void +PathTree::depth_map_build () +{ + destroy (depth_map); + depth_map = new Vector<Vector<NodeIdx>*>(depth); + if (depth) + { + depth_map->put (depth - 1, 0); // fill vector with nulls + depth_map_build (root_idx, 0); + } +} + +void +PathTree::depth_map_build (NodeIdx node_idx, int dpth) +{ + Node *node = NODE_IDX (node_idx); + + Vector<NodeIdx> *node_idxs = depth_map->get (dpth); + if (node_idxs == NULL) + { + node_idxs = new Vector<NodeIdx>(); + depth_map->store (dpth, node_idxs); + } + node_idxs->append (node_idx); + + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + { + NodeIdx desc_node_idx = node->descendants->fetch (index); + depth_map_build (desc_node_idx, dpth + 1); + } +} + +int +PathTree::get_ftree_depth () +{ // external use only + ftree_reset (); + if (!ftree_internal) + return 0; + return ftree_internal->get_depth (); +} + +Vector<Function*>* +PathTree::get_ftree_funcs () +{ // external use only + ftree_reset (); + if (!ftree_internal) + return NULL; + return ftree_internal->get_funcs (); +} + +Vector<Function*>* +PathTree::get_funcs () +{ + // get unique functions + if (fn_map == NULL) + return NULL; + return fn_map->keySet (); +} + +Vector<void*>* +PathTree::get_ftree_level (BaseMetric *bm, int dpth) +{ // external use only + ftree_reset (); + if (!ftree_internal) + return NULL; + return ftree_internal->get_level (bm, dpth); +} + +Vector<void*>* +PathTree::get_level (BaseMetric *bm, int dpth) +{ + // Nodes at tree depth dpth + if (dpth < 0 || dpth >= depth) + return NULL; + if (depth_map == NULL) + return NULL; + Vector<NodeIdx> *node_idxs = depth_map->get (dpth); + return get_nodes (bm, node_idxs); +} + +Vector<void*>* +PathTree::get_ftree_node_children (BaseMetric *bm, NodeIdx node_idx) +{ // external use only + ftree_reset (); + if (!ftree_internal) + return NULL; + return ftree_internal->get_node_children (bm, node_idx); +} + +Vector<void*>* +PathTree::get_node_children (BaseMetric *bm, NodeIdx node_idx) +{ + // Nodes that are children of node_idx + if (depth_map == NULL) + return NULL; + if (node_idx == 0) // special case for root + return get_nodes (bm, depth_map->get (0)); + if (node_idx < 0 || node_idx >= nodes) + return NULL; + Node *node = NODE_IDX (node_idx); + if (node == NULL) + return NULL; + Vector<NodeIdx> *node_idxs = node->descendants; + return get_nodes (bm, node_idxs); +} + +Vector<void*>* +PathTree::get_nodes (BaseMetric *bm, Vector<NodeIdx> *node_idxs) +{ // used for ftree + // capture info for node_idxs: + // node's idx + // node->ancestor idx + // node->instr->id + // mind metric value // in the future, could instead accept vector of mind + if (node_idxs == NULL) + return NULL; + long sz = node_idxs->size (); + if (sz <= 0) + return NULL; + + bool calculate_metric = false; + ValueTag vtype; + int slot_idx; + double prec; + if (bm != NULL) + { + int mind = bm->get_id (); + slot_idx = find_slot (mind); // may be -1 (CPI and IPC) + prec = bm->get_precision (); + vtype = bm->get_vtype (); + } + else + { + slot_idx = -1; + prec = 1.0; + vtype = VT_INT; + } + + if (slot_idx >= 0) + { + switch (vtype) + { + case VT_ULLONG: + case VT_LLONG: + case VT_INT: + if (slots[slot_idx].vtype == vtype) + calculate_metric = true; + else + DBG (assert (false)); + break; + case VT_DOUBLE: + calculate_metric = true; + break; + default: + break; + } + } + + Vector<void*> *results = new Vector<void*>(4); + if (!calculate_metric) + results->store (3, NULL); + else + { + // Code below cribbed from Dbe.cc:dbeGetTableDataV2Data. + // TBD: possibly create an intermediate HistData and instead call that routine + switch (vtype) + { + case VT_ULLONG: + case VT_LLONG: + { + Vector<long long> *vals = new Vector<long long>(sz); + for (long i = 0; i < sz; i++) + { + NodeIdx node_idx = node_idxs->get (i); + TValue val; + val.ll = 0; + ASN_METRIC_VAL (val, slots[slot_idx], node_idx); + vals->append (val.ll); + } + results->store (3, vals); + break; + } + case VT_DOUBLE: + { + Vector<double> *vals = new Vector<double>(sz); + TValue val; + val.tag = slots[slot_idx].vtype; // required for to_double(); + for (long i = 0; i < sz; i++) + { + NodeIdx node_idx = node_idxs->get (i); + val.ll = 0; + ASN_METRIC_VAL (val, slots[slot_idx], node_idx); + double dval = val.to_double (); + dval /= prec; + vals->append (dval); + } + results->store (3, vals); + break; + } + case VT_INT: + { + Vector<int> *vals = new Vector<int>(sz); + for (long i = 0; i < sz; i++) + { + NodeIdx node_idx = node_idxs->get (i); + TValue val; + val.i = 0; + ASN_METRIC_VAL (val, slots[slot_idx], node_idx); + vals->append (val.i); + } + results->store (3, vals); + break; + } + default: + results->store (3, NULL); + break; + } + } + + Vector<int> *nodeIdxList = new Vector<int>(sz); + Vector<int> *ancestorNodeIdxList = new Vector<int>(sz); + Vector<uint64_t> *idList = new Vector<uint64_t>(sz); + for (long i = 0; i < sz; i++) + { + NodeIdx node_idx = node_idxs->get (i); + Node *node = NODE_IDX (node_idx); + NodeIdx ancestor_idx = node->ancestor; + Histable *func = node->instr; + nodeIdxList->append (node_idx); + ancestorNodeIdxList->append (ancestor_idx); + idList->append (func->id); + } + + results->store (0, nodeIdxList); + results->store (1, ancestorNodeIdxList); + results->store (2, idList); + return results; +} + +void +PathTree::get_cle_metrics (Vector<Histable*> *objs) +{ + if (NULL == objs || objs->fetch (0) == get_hist_obj (NODE_IDX (root_idx))) + // Call Tree optimization + get_cle_metrics (objs, root_idx, 0); + else + // General case + get_cle_metrics (objs, root_idx, -1, -1, 0); +} + +void +PathTree::get_metrics (Vector<Function*> *functions, Histable *context) +{ + Function *fitem; + int excl_ok, incl_ok; + NodeIdx node_idx; + Node *node, *anc; + int index; + + Vec_loop (Function*, functions, index, fitem) + { + node_idx = fn_map->get (fitem); + for (; node_idx; node_idx = node->funclist) + { + node = NODE_IDX (node_idx); + Histable *h_obj = get_hist_obj (node, context); + if (h_obj == NULL) + continue; + + // Check for recursion (inclusive metrics) + incl_ok = 1; + for (anc = NODE_IDX (node->ancestor); anc; + anc = NODE_IDX (anc->ancestor)) + { + if (h_obj == get_hist_obj (anc, context)) + { + incl_ok = 0; + break; + } + } + + // Check for leaf nodes (exclusive metrics) + excl_ok = 0; + if (IS_LEAF (node)) + excl_ok = 1; + + h_obj = get_compare_obj (h_obj); + Hist_data::HistItem *hi = hist_data->append_hist_item (h_obj); + + if (!excl_ok) + hist_data->get_callsite_mark ()->put (h_obj, 1); + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + if (subtype == Metric::INCLUSIVE && !incl_ok) + continue; + if (subtype == Metric::EXCLUSIVE && !excl_ok) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + } + } + } +} + +void +PathTree::get_self_metrics (Vector<Histable*> *objs, NodeIdx node_idx, + bool seen, int dpth) +{ + Node *node = NODE_IDX (node_idx); + Histable *cur_obj = get_hist_obj (node); + obj_list[dpth] = cur_obj; + + bool match = false; + int nobj = objs->size (); + if (dpth + 1 >= nobj) + { + match = true; + for (int i = 0; i < nobj; ++i) + { + if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i]) + { + match = false; + break; + } + } + } + + if (match) + { + Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj); + int incl_ok = !seen; + int excl_ok = 0; + if (IS_LEAF (node) || node == NODE_IDX (root_idx)) + excl_ok = 1; + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, sz = mlist->size (); ind < sz; ind++) + { + if (xlate[ind] == -1) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + switch (subtype) + { + case Metric::INCLUSIVE: + if (incl_ok && hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + case Metric::EXCLUSIVE: + case Metric::ATTRIBUTED: + if (excl_ok && hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + case Metric::DATASPACE: + if (hi) + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + break; + // ignoring the following cases (why?) + case Metric::STATIC: + break; + } + } + } + + if (dbeSession->is_interactive ()) + { + ndone++; + int new_percent = 95 * ndone / nodes; + if (new_percent > percent) + { + percent = new_percent; + theApplication->set_progress (percent, NULL); + } + } + + // Recursively process all descendants + int index; + int dsize = NUM_DESCENDANTS (node); + for (index = 0; index < dsize; index++) + get_self_metrics (objs, node->descendants->fetch (index), + seen || match, dpth + 1); +} + +void +PathTree::get_self_metrics (Vector<Histable*> *objs) +{ + get_self_metrics (objs, root_idx, false, 0); +} + +void +PathTree::get_self_metrics (Histable *obj, Vector<Function*> *funclist, + Vector<Histable*>* sel_objs) +{ + int excl_ok, incl_ok; + NodeIdx node_idx; + Node *node, *anc; + + if (obj == NULL) + return; + + SourceFile *src = NULL; + if (obj && obj->get_type () == Histable::LINE) + { + DbeLine *dbeline = (DbeLine*) obj; + src = dbeline->sourceFile; + } + + Hist_data::HistItem *hi = hist_data->append_hist_item (obj); + for (int i = 0, sz = funclist ? funclist->size () : 0; i < sz; i++) + { + Function *fitem = (Function*) get_compare_obj (funclist->fetch (i)); + node_idx = fn_map->get (fitem); + for (; node_idx; node_idx = node->funclist) + { + node = NODE_IDX (node_idx); + if (obj && obj->get_type () == Histable::LINE) + { + Histable *h = get_hist_obj (node, src); + if (h == NULL) + continue; + if (h->convertto (Histable::LINE) != obj->convertto (Histable::LINE)) + continue; + } + else if (get_hist_obj (node, src) != obj) + continue; + + // Check for recursion (inclusive metrics) + incl_ok = 1; + for (anc = NODE_IDX (node->ancestor); anc; + anc = NODE_IDX (anc->ancestor)) + { + if (get_hist_obj (anc, src) == obj) + { + incl_ok = 0; + break; + } + if (sel_objs != NULL) + for (int k = 0; k < sel_objs->size (); k++) + if (sel_objs->fetch (k) == get_hist_obj (anc, src)) + { + incl_ok = 0; + break; + } + } + + // Check for leaf nodes (exclusive metrics) + excl_ok = 0; + if (IS_LEAF (node) || node == NODE_IDX (root_idx)) + excl_ok = 1; + + MetricList *mlist = hist_data->get_metric_list (); + for (long ind = 0, ind_sz = mlist->size (); ind < ind_sz; ind++) + { + if (xlate[ind] == -1) + continue; + Metric *mtr = mlist->get (ind); + Metric::SubType subtype = mtr->get_subtype (); + if (subtype == Metric::INCLUSIVE && !incl_ok) + continue; + if (subtype == Metric::EXCLUSIVE && !excl_ok) + continue; + if (subtype == Metric::ATTRIBUTED && !excl_ok) + continue; + if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx)) + continue; + ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx); + } + } + } +} + +Vector<Histable*> * +PathTree::get_clr_instr (Histable * func) +{ + Vector<Histable*> * instrs = NULL; + if (func->get_type () != Histable::FUNCTION) + return NULL; + NodeIdx node_idx = fn_map->get ((Function*) func); + Node *node = NODE_IDX (node_idx); + if (node == NULL) + return new Vector<Histable*>(); + int instr_num = 0; + for (; node; node = NODE_IDX (node->funclist)) + instr_num++; + instrs = new Vector<Histable*>(instr_num); + node = NODE_IDX (node_idx); + Histable *instr = NODE_IDX (node->ancestor)->instr; + instr_num = 0; + instrs->store (instr_num, instr); + node = NODE_IDX (node->funclist); + for (; node; node = NODE_IDX (node->funclist)) + { + instr = NODE_IDX (node->ancestor)->instr; + instr_num++; + instrs->store (instr_num, instr); + } + return instrs; +} + +Vector<void*> * +PathTree::get_cle_instr (Histable * func, Vector<Histable*>*&instrs) +{ + if (func->get_type () != Histable::FUNCTION) + return NULL; + NodeIdx node_idx = fn_map->get ((Function*) func); + Node *node = NODE_IDX (node_idx); + if (node == NULL) + { + instrs = new Vector<Histable*>(); + return new Vector<void*>(); + } + int instr_num = 0; + for (; node; node = NODE_IDX (node->funclist)) + instr_num++; + instrs = new Vector<Histable*>(instr_num); + Vector<void*> *callee_info = new Vector<void*>(instr_num); + node = NODE_IDX (node_idx); + Histable *instr = node->instr; + instr_num = 0; + instrs->store (instr_num, instr); + int dec_num = 0; + NodeIdx dec_idx = 0; + if (NUM_DESCENDANTS (node) > 0) + { + Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ()); + Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx) + { + Node * dec_node = NODE_IDX (dec_idx); + //XXXX Note: there can be more than one instrs in one leaf function + callee_instrs->store (dec_num, dec_node->instr); + } + callee_info->store (instr_num, callee_instrs); + } + else + callee_info->store (instr_num, NULL); + node = NODE_IDX (node->funclist); + for (; node; node = NODE_IDX (node->funclist)) + { + instr = node->instr; + instr_num++; + instrs->store (instr_num, instr); + if (NUM_DESCENDANTS (node) > 0) + { + Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ()); + Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx) + { + Node * dec_node = NODE_IDX (dec_idx); + //XXXX Note: there can be more than one instrs in one leaf function + callee_instrs->store (dec_num, dec_node->instr); + } + callee_info->store (instr_num, callee_instrs); + } + else + callee_info->store (instr_num, NULL); + } + return callee_info; +} + +// +// +// The following methods are used for debugging purpose only. +// +// +static int maxdepth; +static int maxwidth; + +void +PathTree::print (FILE *fd) +{ + (void) reset (); + fprintf (fd, NTXT ("n = %lld, dn = %lld, MD = %lld\n\n"), + (long long) nodes, (long long) dnodes, (long long) depth); + maxdepth = 0; + maxwidth = 0; + print (fd, root, 0); + fprintf (fd, NTXT ("md = %lld, mw = %lld\n"), + (long long) maxdepth, (long long) maxwidth); +} + +void +PathTree::print (FILE *fd, PathTree::Node *node, int lvl) +{ + const char *t; + char *n; + if (lvl + 1 > maxdepth) + maxdepth = lvl + 1; + for (int i = 0; i < lvl; i++) + fprintf (fd, NTXT ("-")); + Histable *instr = node->instr; + if (instr->get_type () == Histable::LINE) + { + t = "L"; + n = ((DbeLine *) instr)->func->get_name (); + } + else if (instr->get_type () == Histable::INSTR) + { + t = "I"; + n = ((DbeInstr *) instr)->func->get_name (); + } + else + { + t = "O"; + n = instr->get_name (); + } + long long addr = (long long) instr->get_addr (); + fprintf (fd, NTXT ("%s %s (0x%08llx) -- ndesc = %lld\n"), + t, n, addr, (long long) (NUM_DESCENDANTS (node))); + + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + if (dsize > maxwidth) + maxwidth = dsize; + for (int index = 0; index < dsize; index++) + print (fd, NODE_IDX (node->descendants->fetch (index)), lvl + 1); +} + +void +PathTree::printn (FILE *fd) +{ + int n = dbg_nodes (root); + fprintf (fd, GTXT ("Number of nodes: %d, total size: %d\n"), n, (int) (n * sizeof (Node))); +} + +void +PathTree::dumpNodes (FILE *fd, Histable *obj) +{ + const char *t; + char *n; + NodeIdx node_idx = fn_map->get ((Function*) obj); + Node *node = NODE_IDX (node_idx); + if (node == NULL) + { + fprintf (fd, GTXT ("No nodes associated with %s\n"), obj->get_name ()); + return; + } + Histable *instr = node->instr; + for (; node; node = NODE_IDX (node->funclist)) + { + instr = node->instr; + if (instr->get_type () == Histable::LINE) + { + t = "L"; + n = ((DbeLine *) instr)->func->get_name (); + } + else if (instr->get_type () == Histable::INSTR) + { + t = "I"; + n = ((DbeInstr *) instr)->func->get_name (); + } + else + { + t = "O"; + n = instr->get_name (); + } + long long addr = (long long) instr->get_addr (); + if (addr <= 0xFFFFFFFFU) + fprintf (fd, NTXT ("0x%08x -- %s %s\n"), (uint32_t) addr, t, n); + else + fprintf (fd, NTXT ("0x%016llX -- %s %s\n"), addr, t, n); + } +} + +int +PathTree::dbg_nodes (PathTree::Node *node) +{ + int res = 1; + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + res += dbg_nodes (NODE_IDX (node->descendants->fetch (index))); + return res; +} + +static int mind_g; + +int +leak_alloc_comp (const void *s1, const void *s2) +{ + // See Hist_data::sort_compare() for duplicate code + int result = 0; + CStack_data::CStack_item *t1, *t2; + t1 = *(CStack_data::CStack_item **)s1; + t2 = *(CStack_data::CStack_item **)s2; + + switch (t1->value[mind_g].tag) + { + case VT_INT: + if (t1->value[mind_g].i < t2->value[mind_g].i) + result = -1; + else if (t1->value[mind_g].i > t2->value[mind_g].i) + result = 1; + else + result = 0; + break; + case VT_LLONG: + if (t1->value[mind_g].ll < t2->value[mind_g].ll) + result = -1; + else if (t1->value[mind_g].ll > t2->value[mind_g].ll) + result = 1; + else + result = 0; + break; + case VT_ULLONG: + if (t1->value[mind_g].ull < t2->value[mind_g].ull) + result = -1; + else if (t1->value[mind_g].ull > t2->value[mind_g].ull) + result = 1; + else + result = 0; + break; + // ignoring the following cases (why?) + case VT_SHORT: + case VT_FLOAT: + case VT_DOUBLE: + case VT_HRTIME: + case VT_LABEL: + case VT_ADDRESS: + case VT_OFFSET: + break; + } + // Sort in descending order + return -result; +} + +CStack_data * +PathTree::get_cstack_data (MetricList *mlist) +{ + (void) reset (); + CStack_data *lam = new CStack_data (mlist); + int nmetrics = mlist->get_items ()->size (); + mind_g = -1; + xlate = new int[nmetrics]; + for (int mind = 0; mind < nmetrics; mind++) + { + xlate[mind] = -1; + Metric *mtr = mlist->get_items ()->fetch (mind); + if (mlist->get_sort_ref_index () == mind) + mind_g = mind; + xlate[mind] = find_slot (mtr->get_id ()); + } + + // now fill in the actual data + obj_list = new Histable*[depth]; + get_cstack_list (lam, root_idx, 0); + delete[] obj_list; + + if (mind_g >= 0) + lam->cstack_items->sort (leak_alloc_comp); + delete[] xlate; + return lam; +} + +void +PathTree::get_cstack_list (CStack_data *lam, NodeIdx node_idx, int dpth) +{ + + Node *node = NODE_IDX (node_idx); + obj_list[dpth] = node->instr; + + CStack_data::CStack_item *item = NULL; + if (IS_LEAF (node)) + item = lam->new_cstack_item (); + int nmetrics = lam->metrics->get_items ()->size (); + bool subtree_empty = true; + + for (int mind = 0; mind < nmetrics; mind++) + { + if (xlate[mind] == -1) + continue; + if (IS_MVAL_ZERO (slots[xlate[mind]], node_idx)) + continue; + else + subtree_empty = false; + if (item) + { + ADD_METRIC_VAL (item->value[mind], slots[xlate[mind]], node_idx); + ADD_METRIC_VAL (lam->total->value[mind], slots[xlate[mind]], node_idx); + } + } + + if (subtree_empty) + { + delete item; + return; + } + + if (item) + { + // Finish processing a leaf node + item->stack = new Vector<DbeInstr*>(dpth); + for (int i = 1; i <= dpth; i++) + item->stack->append ((DbeInstr*) obj_list[i]); + lam->cstack_items->append (item); + } + else + { + // Recursively process all descendants + int dsize = NUM_DESCENDANTS (node); + for (int index = 0; index < dsize; index++) + get_cstack_list (lam, node->descendants->fetch (index), dpth + 1); + } +} + +Emsg * +PathTree::fetch_stats () +{ + if (statsq == NULL) + return NULL; + return statsq->fetch (); +} + +void +PathTree::delete_stats () +{ + if (statsq != NULL) + { + delete statsq; + statsq = new Emsgqueue (NTXT ("statsq")); + } +} + +Emsg * +PathTree::fetch_warnings () +{ + if (warningq == NULL) + return NULL; + return warningq->fetch (); +} + +void +PathTree::delete_warnings () +{ + if (warningq != NULL) + { + delete warningq; + warningq = new Emsgqueue (NTXT ("warningq")); + } +} |