Wolfgang Thallergcc16 merge934c3885 months agoHistory
1253 lines · 34.8 KB · C++
RawDownload
/* 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 <new> #include "util.h"#include "CacheMap.h"#include "CallStack.h"#include "DbeSession.h"#include "DbeView.h"#include "DbeLinkList.h"#include "Experiment.h"#include "Exp_Layout.h"#include "Function.h"#include "LoadObject.h"#include "Module.h" Descendants::Descendants (){  count = 0;  limit = sizeof (first_data) / sizeof (CallStackNode *);  data = first_data;} Descendants::~Descendants (){  if (data != first_data)    free (data);} CallStackNode *Descendants::find (Histable *hi, int *index){  int cnt = count;  int left = 0;  for (int right = cnt - 1; left <= right;)    {      int ind = (left + right) / 2;      CallStackNode *node = data[ind];      Histable *instr = node->get_instr ();      if (instr == hi)	{	  if (index)	    *index = ind;	  return node;	}      if (instr->id < hi->id)	right = ind - 1;      else	left = ind + 1;    }  if (index)    *index = left;  return NULL;} voidDescendants::append (CallStackNode* item){  if (count < limit)    data[count++] = item;  else    insert (count, item);} voidDescendants::insert (int ind, CallStackNode* item){  CallStackNode **old_data = data;  int old_cnt = count;  if (old_cnt + 1 >= limit)    {      int new_limit = (limit == 0) ? DELTA : limit * 2;      CallStackNode **new_data = (CallStackNode **) xmalloc (new_limit * sizeof (CallStackNode *));      for (int i = 0; i < ind; i++)	new_data[i] = old_data[i];      new_data[ind] = item;      for (int i = ind; i < old_cnt; i++)	new_data[i + 1] = old_data[i];      limit = new_limit;      data = new_data;      if (old_data != first_data)	free (old_data);    }  else    {      for (int i = ind; i < old_cnt; i++)	old_data[i + 1] = old_data[i];      old_data[ind] = item;    }  count++;} /* *    Private implementation of CallStack interface */ // When performing pipeline optimization on resolve_frame_info + add_stack// cstk_ctx structure contains the state (or context) for one iteration to pass on// from Phase 2 to Phase 3 (More details in Experiment.cc)class CallStackP : public CallStack{public:  CallStackP (Experiment *exp);   virtual ~CallStackP ();   virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp, cstk_ctx_chunk *cstCtxChunk);  virtual void *add_stack (Vector<Histable*> *objs);  virtual CallStackNode *get_node (int n);  virtual void print (FILE *); private:   static const int CHUNKSZ = 16384;   Experiment *experiment;  CallStackNode *root;  CallStackNode *jvm_node;  int nodes;  int nchunks;  CallStackNode **chunks;  Map<uint64_t, CallStackNode *> *cstackMap;  DbeLock *cstackLock;   CallStackNode *add_stack (long start, long end, Vector<Histable*> *objs, CallStackNode *myRoot);  CallStackNode *new_Node (CallStackNode*, Histable*);  CallStackNode *find_preg_stack (uint64_t);  // objs are in the root..leaf order  void *add_stack_d (Vector<Histable*> *objs);  void add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp,	hrtime_t tstamp, uint32_t thrid, Vector<Histable*>* natpcs,	bool natpc_added, cstk_ctx_chunk *cstCtxChunk);  void add_stack_java_epilogue (DataDescriptor *dDscr, long idx,	FramePacket *frp, hrtime_t tstamp, uint32_t thrid,	Vector<Histable*>* natpcs, Vector<Histable*>* jpcs, bool natpc_added);   // Adjust HW counter event to find better trigger PC, etc.  DbeInstr *adjustEvent (DbeInstr *leafPC, DbeInstr * candPC,			 Vaddr &eventEA, int abst_type);  Vector<Histable*> *natpcsP;  Vector<Histable*> *jpcsP;}; CallStackP::CallStackP (Experiment *exp){  experiment = exp;  nchunks = 0;  chunks = NULL;  nodes = 0;  cstackMap = new CacheMap<uint64_t, CallStackNode *>;  cstackLock = new DbeLock ();  Function *total = dbeSession->get_Total_Function ();  root = new_Node (0, total->find_dbeinstr (0, 0));  jvm_node = NULL;  natpcsP = NULL;  jpcsP = NULL;} CallStackP::~CallStackP (){  delete cstackLock;  if (chunks)    {      for (int i = 0; i < nodes; i++)	{	  CallStackNode *node = get_node (i);	  node->~CallStackNode ();	}      for (int i = 0; i < nchunks; i++)	free (chunks[i]);      free (chunks);    }  delete natpcsP;  delete jpcsP;  destroy_map (CallStackNode *, cstackMap);} CallStackNode *CallStackP::new_Node (CallStackNode *anc, Histable *pcval){  // cstackLock->aquireLock(); // Caller already locked it  if (nodes >= nchunks * CHUNKSZ)    {      CallStackNode **old_chunks = chunks;      nchunks++;       // Reallocate Node chunk array      chunks = (CallStackNode **) xmalloc (nchunks * sizeof (CallStackNode *));      for (int i = 0; i < nchunks - 1; i++)	chunks[i] = old_chunks[i];      free (old_chunks);      // Allocate new chunk for nodes.      chunks[nchunks - 1] = (CallStackNode *) xmalloc (CHUNKSZ * sizeof (CallStackNode));    }  nodes++;  CallStackNode *node = get_node (nodes - 1);  new (node) CallStackNode (anc, pcval);  // cstackLock->releaseLock();  return node;} CallStackNode *CallStackP::find_preg_stack (uint64_t prid){  DataView *dview = experiment->getOpenMPdata ();  dview->sort (PROP_CPRID);  Datum tval;  tval.setUINT64 (prid);  long idx = dview->getIdxByVals (&tval, DataView::REL_EQ);  if (idx < 0)    return root;  CallStackNode *node = (CallStackNode*) dview->getObjValue (PROP_USTACK, idx);  if (node != NULL)    return node;  uint64_t pprid = dview->getLongValue (PROP_PPRID, idx);  if (pprid == prid)    return root;  void *nat_stack = dview->getObjValue (PROP_MSTACK, idx);  Vector<Histable*> *pcs = getStackPCs (nat_stack);   // Find the bottom frame  int btm;  bool inOMP = false;  DbeInstr *instr;  Histable *hist;  for (btm = 0; btm < pcs->size (); btm++)    {      hist = pcs->fetch (btm);      if (hist->get_type () == Histable::INSTR)	instr = (DbeInstr *) hist;      else    // DBELINE	instr = (DbeInstr *) hist->convertto (Histable::INSTR);      LoadObject *lo = instr->func->module->loadobject;      if (!inOMP)	{	  if (lo->flags & SEG_FLAG_OMP)	    inOMP = true;	}      else if (!(lo->flags & SEG_FLAG_OMP))	break;    }   // Find the top frame  dview->sort (PROP_CPRID);  int top;  tval.setUINT64 (pprid);  long pidx = dview->getIdxByVals (&tval, DataView::REL_EQ);  if (pidx < 0)     // No parent. Process the entire nat_stack    top = pcs->size () - 1;  else    {      uint32_t thrid = (uint32_t) dview->getIntValue (PROP_THRID, idx);      uint32_t pthrid = (uint32_t) dview->getIntValue (PROP_THRID, pidx);      if (thrid != pthrid)	{	  // Parent is on a different stack.	  // Process the entire nat_stack. Skip libthread.	  for (top = pcs->size () - 1; top >= 0; top--)	    {	      hist = pcs->fetch (top);	      if (hist->get_type () == Histable::INSTR)		instr = (DbeInstr *) hist;	      else // DBELINE		instr = (DbeInstr *) hist->convertto (Histable::INSTR);	      if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)		break;	    }	  if (top < 0)  // None found. May be incomplete call stack (x86)	    top = pcs->size () - 1;	}      else	{	  // Parent is on the same stack. Find match.	  top = pcs->size () - 1;	  void *pnat_stack = dview->getObjValue (PROP_MSTACK, pidx);	  Vector<Histable*> *ppcs = getStackPCs (pnat_stack);	  for (int ptop = ppcs->size () - 1; top >= 0 && ptop >= 0;		  top--, ptop--)	    {	      if (pcs->fetch (top) != ppcs->fetch (ptop))		break;	    }	  delete ppcs;	}    }   // Process the found range  Vector<Histable*> *upcs = new Vector<Histable*>(128);  for (int i = btm; i <= top; ++i)    {      hist = (DbeInstr*) pcs->fetch (i);      if (hist->get_type () == Histable::INSTR)	instr = (DbeInstr *) hist;      else // DBELINE	instr = (DbeInstr *) hist->convertto (Histable::INSTR);       if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)	// Skip all frames from libmtsk	continue;      upcs->append (instr);    }  delete pcs;  node = find_preg_stack (pprid);  while (node != root)    {      upcs->append (node->instr);      node = node->ancestor;    }  node = (CallStackNode *) add_stack (upcs);  dview->setObjValue (PROP_USTACK, idx, node);  delete upcs;  return node;} #define JNI_MARKER -3 // This is one iteration if the third stage of// resolve_frame_info + add_stack pipeline. Works on building the java// stacksvoidCallStackP::add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp,			    hrtime_t tstamp, uint32_t thrid,			    Vector<Histable*>* natpcs, bool natpc_added,			    cstk_ctx_chunk *cstCtxChunk){  Vector<Histable*> *jpcs = NULL;  cstk_ctx *cstctx = NULL;  if (cstCtxChunk != NULL)    {      cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];      jpcs = cstctx->jpcs;      jpcs->reset ();    }  if (jpcs == NULL)    {      // this is when we are not doing the pipeline optimization      // Temporary array for resolved addresses      // [leaf_pc .. root_pc] == [0..stack_size-1]      // Leave room for a possible "truncated" frame      if (jpcsP == NULL)	jpcsP = new Vector<Histable*>;      jpcs = jpcsP;      jpcs->reset ();    }   //  // Construct the user stack  //  // Construct Java user stack  int jstack_size = frp->stackSize (true);  if (jstack_size)    {      // jpcs = new Vector<Histable*>( jstack_size );      if (frp->isTruncatedStack (true))	{	  Function *truncf = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);	  jpcs->append (truncf->find_dbeinstr (0, 0));	}       int nind = natpcs->size () - 1; // first native frame      for (int jind = jstack_size - 1; jind >= 0; jind--)	{	  bool jleaf = (jind == 0); // is current java frame a leaf?	  Vaddr mid = frp->getMthdFromStack (jind);	  int bci = frp->getBciFromStack (jind);	  DbeInstr *cur_instr = experiment->map_jmid_to_PC (mid, bci, tstamp);	  jpcs->append (cur_instr);	  if (bci == JNI_MARKER)	    {	      JMethod *j_method = (JMethod*) cur_instr->func;	      // Find matching native function on the native stack	      bool found = false;	      for (; nind >= 0; nind--)		{		  DbeInstr *nat_addr = (DbeInstr *) natpcs->fetch (nind);		  if (0 == nat_addr)		    continue;		  Function *nat_func = nat_addr->func;		  if (!found && j_method->jni_match (nat_func))		    found = true;		  if (found)		    {		      // XXX omazur: the following will skip JNI native method		      // implemented in JVM itself.		      // If we are back in JVM switch to processing Java		      // frames if there are any.		      if ((nat_func->module->loadobject->flags & SEG_FLAG_JVM) && !jleaf)			break;		      jpcs->append (nat_addr);		    }		}	    }	}    }  add_stack_java_epilogue (dDscr, idx, frp, tstamp, thrid, natpcs, jpcs, natpc_added);} // This is one iteration if the fourth stage of// resolve_frame_info + add_stack pipeline.// It adds the native and java stacks to the stackmap voidCallStackP::add_stack_java_epilogue (DataDescriptor *dDscr, long idx,	FramePacket *frp, hrtime_t tstamp, uint32_t thrid,	Vector<Histable*>* natpcs, Vector<Histable*> *jpcs, bool natpc_added){  CallStackNode *node = NULL;  if (!natpc_added)    {      node = (CallStackNode *) add_stack (natpcs);      dDscr->setObjValue (PROP_MSTACK, idx, node);      dDscr->setObjValue (PROP_XSTACK, idx, node);      dDscr->setObjValue (PROP_USTACK, idx, node);    }   int jstack_size = frp->stackSize (true);  if (jstack_size)    {      if (jpcs != NULL)	node = (CallStackNode *) add_stack_d (jpcs);      if (node == NULL)	node = (CallStackNode*) dDscr->getObjValue (PROP_USTACK, idx);      dDscr->setObjValue (PROP_USTACK, idx, node);      Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);      if (func != dbeSession->get_JUnknown_Function ())	dDscr->setObjValue (PROP_XSTACK, idx, node);    }   JThread *jthread = experiment->map_pckt_to_Jthread (thrid, tstamp);  if (jthread == JTHREAD_NONE && jstack_size != 0 && node != NULL)    {      Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);      if (func != dbeSession->get_JUnknown_Function ())	jthread = JTHREAD_DEFAULT;    }  dDscr->setObjValue (PROP_JTHREAD, idx, jthread);  if (jthread == JTHREAD_NONE || (jthread != JTHREAD_DEFAULT && jthread->is_system ()))    {      if (jvm_node == NULL)	{	  Function *jvm = dbeSession->get_jvm_Function ();	  if (jvm)	    {	      jvm_node = new_Node (root, jvm->find_dbeinstr (0, 0));	      CommonPacket::jvm_overhead = jvm_node;	    }	}      dDscr->setObjValue (PROP_USTACK, idx, jvm_node);    }} // This is one iteration of the 2nd stage of// resolve_frame_info + add_stack() pipeline. Builds the stack for a given framepacket.// When pipeline optimization is turnd off, cstctxchunk passed is NULLvoidCallStackP::add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,		       cstk_ctx_chunk* cstCtxChunk){  Vector<Histable*> *natpcs = NULL;  cstk_ctx *cstctx = NULL;  int stack_size = frp->stackSize ();  if (cstCtxChunk != NULL)    {      cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];      natpcs = cstctx->natpcs;      natpcs->reset ();    }  if (natpcs == NULL)    {      // this is when we are not doing the pipeline optimization      // Temporary array for resolved addresses      // [leaf_pc .. root_pc] == [0..stack_size-1]      // Leave room for a possible "truncated" frame      if (natpcsP == NULL)	natpcsP = new Vector<Histable*>;      natpcs = natpcsP;      natpcs->reset ();    }   bool leaf = true;  hrtime_t tstamp = (hrtime_t) dDscr->getLongValue (PROP_TSTAMP, idx);

Lines 1–500 of 1253.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t