/* 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. 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 <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; } void Descendants::append (CallStackNode* item) { if (count < limit) data[count++] = item; else insert (count, item); } void Descendants::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 // stacks void CallStackP::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 void CallStackP::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 NULL void CallStackP::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);