/* Copyright (C) 2021-2026 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 voidPathTree::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;} voidPathTree::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);} voidPathTree::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;} PtreePhaseStatusPathTree::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;} intPathTree::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;} voidPathTree::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;} intPathTree::find_slot (int id){ for (int i = 0; i < nslots; i++) if (slots[i].id == id) return i; return -1;} PathTree::NodeIdxPathTree::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::NodeIdxPathTree::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 intdesc_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::NodeIdxPathTree::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;Lines 1–500 of 2637. Load more
/* Copyright (C) 2021-2026 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;