|
Lines 11-16
Link Here
|
| 11 |
* |
11 |
* |
| 12 |
* $Id: ProfEnv.cpp,v 1.31 2008/12/08 13:37:37 jkubasta Exp $ |
12 |
* $Id: ProfEnv.cpp,v 1.31 2008/12/08 13:37:37 jkubasta Exp $ |
| 13 |
************************************************************************/ |
13 |
************************************************************************/ |
|
|
14 |
#ifndef LIN |
| 15 |
#pragma warning(disable:4786) // Add for bug 194081 to disable VC compiler warning when use STL |
| 16 |
#endif |
| 14 |
|
17 |
|
| 15 |
#include "ProfEnv.h" |
18 |
#include "ProfEnv.h" |
| 16 |
#include "log.h" |
19 |
#include "log.h" |
|
Lines 19-24
Link Here
|
| 19 |
using namespace Martini::MPI; |
22 |
using namespace Martini::MPI; |
| 20 |
using namespace Martini::OSA; |
23 |
using namespace Martini::OSA; |
| 21 |
using namespace Martini::JPIAgent; |
24 |
using namespace Martini::JPIAgent; |
|
|
25 |
using namespace std; // Add for bug 194081 |
| 22 |
|
26 |
|
| 23 |
CProfEnv::CProfEnv(){ |
27 |
CProfEnv::CProfEnv(){ |
| 24 |
m_pClassSData = 0; |
28 |
m_pClassSData = 0; |
|
Lines 61-66
Link Here
|
| 61 |
m_pAggStorage->Destroy(); |
65 |
m_pAggStorage->Destroy(); |
| 62 |
m_pSSMethodLeaveData_LockObject->Destroy(); |
66 |
m_pSSMethodLeaveData_LockObject->Destroy(); |
| 63 |
lockGetThreadInfoObject->Destroy(); |
67 |
lockGetThreadInfoObject->Destroy(); |
|
|
68 |
|
| 69 |
// Add for bug 194081 |
| 70 |
m_pShadowStackTracker = NULL; |
| 71 |
// Add for bug 194081 |
| 64 |
} |
72 |
} |
| 65 |
|
73 |
|
| 66 |
void |
74 |
void |
|
Lines 101-106
Link Here
|
| 101 |
delete m_pMethodSData; |
109 |
delete m_pMethodSData; |
| 102 |
} |
110 |
} |
| 103 |
m_pMethodSDataLockObject->Leave(); |
111 |
m_pMethodSDataLockObject->Leave(); |
|
|
112 |
|
| 113 |
// Add for bug 194081 |
| 114 |
if (m_pShadowStackTracker) |
| 115 |
{ |
| 116 |
delete m_pShadowStackTracker; |
| 117 |
m_pShadowStackTracker = NULL; |
| 118 |
} |
| 119 |
// Add for bug 194081 |
| 104 |
} |
120 |
} |
| 105 |
|
121 |
|
| 106 |
/* |
122 |
/* |
|
Lines 124-129
Link Here
|
| 124 |
} |
140 |
} |
| 125 |
libraryLoader->Destroy(); |
141 |
libraryLoader->Destroy(); |
| 126 |
(*ecpEnv)(profName, &ec_env); |
142 |
(*ecpEnv)(profName, &ec_env); |
|
|
143 |
|
| 144 |
// Add for bug 194081 |
| 145 |
m_pShadowStackTracker = new CCGShadowStackTracker(*this); |
| 146 |
if ( (NULL == m_pShadowStackTracker) || |
| 147 |
!(m_pShadowStackTracker->ValidateCGShadowStackTracker()) ) |
| 148 |
{ |
| 149 |
return MRTE_ERROR_FAIL; |
| 150 |
} |
| 151 |
// Add for bug 194081 |
| 152 |
|
| 127 |
return MRTE_RESULT_OSA_PLACE_HOLDER; |
153 |
return MRTE_RESULT_OSA_PLACE_HOLDER; |
| 128 |
} |
154 |
} |
| 129 |
|
155 |
|
|
Lines 209-214
Link Here
|
| 209 |
return ret; |
235 |
return ret; |
| 210 |
} |
236 |
} |
| 211 |
|
237 |
|
|
|
238 |
// Add for bug 194081 |
| 239 |
void |
| 240 |
CProfEnv::DeleteMethodsData() |
| 241 |
{ |
| 242 |
if (m_pMethodSData) |
| 243 |
{ |
| 244 |
delete m_pMethodSData; |
| 245 |
m_pMethodSData = NULL; |
| 246 |
} |
| 247 |
} |
| 248 |
// Add for bug 194081 |
| 249 |
|
| 212 |
void |
250 |
void |
| 213 |
CProfEnv::AddNewMethodData(SMethodInfo* pSMethodInfo, TId methodId, bool isPrinted) |
251 |
CProfEnv::AddNewMethodData(SMethodInfo* pSMethodInfo, TId methodId, bool isPrinted) |
| 214 |
{ |
252 |
{ |
|
Lines 366-374
Link Here
|
| 366 |
lockObjectCheckObject->Leave(); |
404 |
lockObjectCheckObject->Leave(); |
| 367 |
} |
405 |
} |
| 368 |
|
406 |
|
|
|
407 |
// Add for bug 194081. Filter additional data referring to CanInstrumentClass |
| 408 |
bool CProfEnv::IsExcludedClass(const char* szClassName) |
| 409 |
{ |
| 410 |
static char* ExcludedClassPatterns[] = |
| 411 |
{ |
| 412 |
"org.eclipse.tptp.martini.", |
| 413 |
"com.ibm.crypto", |
| 414 |
"sun.reflect.Generated", |
| 415 |
"jrockit.", |
| 416 |
"com.Intel.VTune.VTuneAPI", |
| 417 |
"org.eclipse.hyades.collection.profiler", |
| 418 |
"java.lang.", |
| 419 |
"java.security.", |
| 420 |
"java.awt.", |
| 421 |
"java.io.", |
| 422 |
"javax.swing." |
| 423 |
"com.ibm.jvm.", |
| 424 |
"com.ibm.misc.", |
| 425 |
"com.ibm.oti.", |
| 426 |
"sun.nio.", |
| 427 |
"CGLIB$$" |
| 428 |
}; |
| 429 |
|
| 430 |
// Check if the class appear in the excluded class patterns list |
| 431 |
unsigned int patternArraySize = |
| 432 |
sizeof(ExcludedClassPatterns)/sizeof(*ExcludedClassPatterns); |
| 433 |
|
| 434 |
for (unsigned int i = 0; i < patternArraySize; ++i) |
| 435 |
{ |
| 436 |
char *szExcludedPattern = ExcludedClassPatterns[i]; |
| 437 |
if (strstr(szClassName, szExcludedPattern) != NULL) |
| 438 |
{ |
| 439 |
return true; |
| 440 |
} |
| 441 |
} |
| 442 |
|
| 443 |
return false; |
| 444 |
} |
| 445 |
// Add for bug 194081. Filter additional data referring to CanInstrumentClass |
| 369 |
|
446 |
|
| 370 |
void |
447 |
void |
| 371 |
CProfEnv::CheckMethodId(TId methodId) { |
448 |
CProfEnv::CheckMethodId(TId methodId) { |
|
|
449 |
// Add for bug 194081 to filter additional data after reattach |
| 450 |
SMethodInfo methodClassInfo = {0}; |
| 451 |
TResult iRes = m_pMpiApi->GetMethodInfo(m_clientId, |
| 452 |
methodId, DR_CLASS_NAME, &methodClassInfo); |
| 453 |
LOG_ASSERT(iRes == MRTE_RESULT_OK); |
| 454 |
LOG_ASSERT((methodClassInfo.validData & DR_CLASS_NAME) != 0); |
| 455 |
|
| 456 |
if (IsExcludedClass(methodClassInfo.szClassName)) |
| 457 |
{ |
| 458 |
return; |
| 459 |
} |
| 460 |
// Add for bug 194081 to filter additional data after reattach |
| 461 |
|
| 372 |
bool isPrint = false; |
462 |
bool isPrint = false; |
| 373 |
|
463 |
|
| 374 |
m_pMethodSDataLockObject->Enter(); |
464 |
m_pMethodSDataLockObject->Enter(); |
|
Lines 381-387
Link Here
|
| 381 |
methodInfo->managedToSrcLineMap.uiSize = 1; |
471 |
methodInfo->managedToSrcLineMap.uiSize = 1; |
| 382 |
methodInfo->managedToSrcLineMap.entries = (SLineNumberTableEntry*)malloc(sizeof(SLineNumberTableEntry) * 1); |
472 |
methodInfo->managedToSrcLineMap.entries = (SLineNumberTableEntry*)malloc(sizeof(SLineNumberTableEntry) * 1); |
| 383 |
|
473 |
|
| 384 |
TResult iRes = m_pMpiApi->GetMethodInfo(m_clientId, methodId, |
474 |
iRes = m_pMpiApi->GetMethodInfo(m_clientId, methodId, |
| 385 |
DR_JAVA_NATIVE_METHOD_NAME | DR_JAVA_NATIVE_METHOD_SIGNATURE | DR_METHOD_NAME | DR_METHOD_SIGNATURE | |
475 |
DR_JAVA_NATIVE_METHOD_NAME | DR_JAVA_NATIVE_METHOD_SIGNATURE | DR_METHOD_NAME | DR_METHOD_SIGNATURE | |
| 386 |
DR_JAVA_NATIVE_CLASS_NAME | DR_CLASS_NAME | DR_METHOD_LINE_NUMBERS | DR_CLASS_ID | DR_MANAGED_TO_SRC_LINE_MAP, methodInfo); |
476 |
DR_JAVA_NATIVE_CLASS_NAME | DR_CLASS_NAME | DR_METHOD_LINE_NUMBERS | DR_CLASS_ID | DR_MANAGED_TO_SRC_LINE_MAP, methodInfo); |
| 387 |
if (iRes == MRTE_ERROR_BUFFER_TOO_SHORT) { |
477 |
if (iRes == MRTE_ERROR_BUFFER_TOO_SHORT) { |
|
Lines 541-546
Link Here
|
| 541 |
int size = 0; |
631 |
int size = 0; |
| 542 |
int maxDepth = ec_env->getMaxStackDepth(); |
632 |
int maxDepth = ec_env->getMaxStackDepth(); |
| 543 |
TResult retVal; |
633 |
TResult retVal; |
|
|
634 |
|
| 544 |
do { |
635 |
do { |
| 545 |
if(maxDepth >= 0){ |
636 |
if(maxDepth >= 0){ |
| 546 |
size = maxDepth; |
637 |
size = maxDepth; |
|
Lines 574-582
Link Here
|
| 574 |
for (unsigned int i = 0; i < stackTrace->uiSize; i++) { |
665 |
for (unsigned int i = 0; i < stackTrace->uiSize; i++) { |
| 575 |
stackTrace->pStackEntries[i].methodId = threadInfo.vmOffsetStack.pStackEntries[i].methodId; |
666 |
stackTrace->pStackEntries[i].methodId = threadInfo.vmOffsetStack.pStackEntries[i].methodId; |
| 576 |
SMethodInfo* methodInfo = GetMethodData(stackTrace->pStackEntries[i].methodId); |
667 |
SMethodInfo* methodInfo = GetMethodData(stackTrace->pStackEntries[i].methodId); |
| 577 |
stackTrace->pStackEntries[i].methodName = (char*)malloc(strlen(methodInfo->szMethodName) + strlen(methodInfo->szMethodSig) + strlen(methodInfo->szClassName) + 3); |
668 |
if (NULL != methodInfo) |
| 578 |
sprintf(stackTrace->pStackEntries[i].methodName, "%s.%s %s", methodInfo->szClassName, methodInfo->szMethodName, methodInfo->szMethodSig); |
669 |
{ |
| 579 |
stackTrace->pStackEntries[i].lineNumber = GetLineNumber(threadInfo.vmOffsetStack.pStackEntries[i].location, &(methodInfo->managedToSrcLineMap)); |
670 |
stackTrace->pStackEntries[i].methodName = |
|
|
671 |
(char*)malloc(strlen(methodInfo->szMethodName) + |
| 672 |
strlen(methodInfo->szMethodSig) + |
| 673 |
strlen(methodInfo->szClassName) + 3); |
| 674 |
|
| 675 |
sprintf(stackTrace->pStackEntries[i].methodName, "%s.%s %s", |
| 676 |
methodInfo->szClassName, methodInfo->szMethodName, methodInfo->szMethodSig); |
| 677 |
|
| 678 |
stackTrace->pStackEntries[i].lineNumber = |
| 679 |
GetLineNumber(threadInfo.vmOffsetStack.pStackEntries[i].location, |
| 680 |
&(methodInfo->managedToSrcLineMap)); |
| 681 |
} |
| 682 |
|
| 580 |
} |
683 |
} |
| 581 |
free(threadInfo.vmOffsetStack.pStackEntries); |
684 |
free(threadInfo.vmOffsetStack.pStackEntries); |
| 582 |
} |
685 |
} |
|
Lines 598-610
Link Here
|
| 598 |
void |
701 |
void |
| 599 |
CProfEnv::FreeStackTrace(SStackTrace_* stackTrace) |
702 |
CProfEnv::FreeStackTrace(SStackTrace_* stackTrace) |
| 600 |
{ |
703 |
{ |
| 601 |
if (stackTrace->pStackEntries == 0) { |
704 |
if (NULL == stackTrace || stackTrace->pStackEntries == NULL) { |
| 602 |
return; |
705 |
return; |
| 603 |
} |
706 |
} |
| 604 |
for (unsigned int i = 0; i < stackTrace->uiSize; i++) { |
707 |
for (unsigned int i = 0; i < stackTrace->uiSize; i++) { |
| 605 |
free(stackTrace->pStackEntries[i].methodName); |
708 |
if (NULL != stackTrace->pStackEntries[i].methodName) |
|
|
709 |
{ |
| 710 |
free(stackTrace->pStackEntries[i].methodName); |
| 711 |
stackTrace->pStackEntries[i].methodName = NULL; |
| 712 |
} |
| 606 |
} |
713 |
} |
| 607 |
free(stackTrace->pStackEntries); |
714 |
free(stackTrace->pStackEntries); |
|
|
715 |
stackTrace->pStackEntries = NULL; |
| 716 |
stackTrace->uiSize = 0; |
| 608 |
} |
717 |
} |
| 609 |
|
718 |
|
| 610 |
//================================================================================== |
719 |
//================================================================================== |
|
Lines 791-793
Link Here
|
| 791 |
return MRTE_RESULT_OK; |
900 |
return MRTE_RESULT_OK; |
| 792 |
} |
901 |
} |
| 793 |
|
902 |
|
|
|
903 |
//================================================================== |
| 904 |
// Add for bug 194081 |
| 905 |
CCGShadowStackTracker::CCGShadowStackTracker(CProfEnv& profEnv) |
| 906 |
: m_refProfEnv(profEnv) |
| 907 |
{ |
| 908 |
m_lockVMStackDataMap = CreateThreadSync(); |
| 909 |
} |
| 910 |
|
| 911 |
CCGShadowStackTracker::~CCGShadowStackTracker() |
| 912 |
{ |
| 913 |
if (m_lockVMStackDataMap) |
| 914 |
{ |
| 915 |
m_lockVMStackDataMap->Destroy(); |
| 916 |
} |
| 917 |
} |
| 918 |
|
| 919 |
bool CCGShadowStackTracker::isNeedTrack() |
| 920 |
{ |
| 921 |
return ( |
| 922 |
((m_refProfEnv.ec_env)->isCGExecDetails()) && |
| 923 |
!((m_refProfEnv.ec_env)->isStandAlone()) |
| 924 |
); |
| 925 |
} |
| 926 |
|
| 927 |
bool CCGShadowStackTracker::ValidateCGShadowStackTracker() |
| 928 |
{ |
| 929 |
if (!isNeedTrack()) |
| 930 |
{ |
| 931 |
return true; |
| 932 |
} |
| 933 |
|
| 934 |
// You can add additional validate condition in this function |
| 935 |
return (NULL != m_lockVMStackDataMap); |
| 936 |
} |
| 937 |
|
| 938 |
void CCGShadowStackTracker::TrackVMShutdown() |
| 939 |
{ |
| 940 |
if (!(m_refProfEnv.IsSupportedEG(EG_CALL_GRAPH))) |
| 941 |
{// For profilers' common events, just handle for call graph |
| 942 |
return; |
| 943 |
} |
| 944 |
|
| 945 |
if (!isNeedTrack()) |
| 946 |
{ |
| 947 |
return; |
| 948 |
} |
| 949 |
|
| 950 |
ReportLeftStackTrackDataMethodsLeave(); |
| 951 |
} |
| 952 |
|
| 953 |
TResult CCGShadowStackTracker::InitNewThreadInfoArray( |
| 954 |
SThreadInfoArray& threadInfoArray, |
| 955 |
int MAX_THREADS, int MAX_FRAMES) |
| 956 |
{ |
| 957 |
DestroyThreadInfoArray(threadInfoArray); |
| 958 |
|
| 959 |
threadInfoArray.pEntries = |
| 960 |
(SThreadInfoArrayEntry*)malloc(sizeof(SThreadInfoArrayEntry) * MAX_THREADS); |
| 961 |
if (NULL == threadInfoArray.pEntries) |
| 962 |
{ |
| 963 |
return MRTE_ERROR_OUT_OF_MEMORY; |
| 964 |
} |
| 965 |
|
| 966 |
threadInfoArray.uiSize = MAX_THREADS; |
| 967 |
memset(threadInfoArray.pEntries, 0, sizeof(SThreadInfoArrayEntry) * MAX_THREADS); |
| 968 |
|
| 969 |
unsigned int i = 0; |
| 970 |
for (i = 0; i < MAX_THREADS; i++) |
| 971 |
{ |
| 972 |
threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.uiSize = MAX_FRAMES; |
| 973 |
threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.pStackEntries = new SStackEntry[MAX_FRAMES]; |
| 974 |
|
| 975 |
if (NULL == threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.pStackEntries) |
| 976 |
{ |
| 977 |
DestroyThreadInfoArray(threadInfoArray); |
| 978 |
return MRTE_ERROR_OUT_OF_MEMORY; |
| 979 |
} |
| 980 |
|
| 981 |
memset(threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.pStackEntries, 0, |
| 982 |
sizeof(SStackEntry) * MAX_FRAMES); |
| 983 |
} |
| 984 |
|
| 985 |
return MRTE_RESULT_OK; |
| 986 |
} |
| 987 |
|
| 988 |
void CCGShadowStackTracker::DestroyThreadInfoArray( |
| 989 |
SThreadInfoArray& threadInfoArray) |
| 990 |
{ |
| 991 |
if (NULL != threadInfoArray.pEntries) |
| 992 |
{ |
| 993 |
for (unsigned int i = 0; i < threadInfoArray.uiSize; i++) |
| 994 |
{ |
| 995 |
if (NULL != threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.pStackEntries) |
| 996 |
{ |
| 997 |
delete [](threadInfoArray.pEntries[i].threadInfo.vmOffsetStack.pStackEntries); |
| 998 |
} |
| 999 |
} |
| 1000 |
|
| 1001 |
free(threadInfoArray.pEntries); |
| 1002 |
} |
| 1003 |
|
| 1004 |
threadInfoArray.uiSize = 0; |
| 1005 |
threadInfoArray.uiActualSize = 0; |
| 1006 |
} |
| 1007 |
|
| 1008 |
TResult CCGShadowStackTracker::GetInitialShadowStackTraces( |
| 1009 |
SThreadInfoArray& threadInfoArray) |
| 1010 |
{ |
| 1011 |
// Suspend all VM threads and Get all threads stack traces |
| 1012 |
TResult res = (m_refProfEnv.m_pMpiApi)->SuspendVM(); |
| 1013 |
if (MRTE_FAILED(res)) |
| 1014 |
{ |
| 1015 |
LOG_ERROR("Can not suspend VM when try to get shadow stack sanpshot") |
| 1016 |
return res; |
| 1017 |
} |
| 1018 |
|
| 1019 |
// TODO: This fixed thread num and frame num is a limit, referring to original AttachEvent.cpp |
| 1020 |
int MAX_THREADS = 100; |
| 1021 |
int MAX_FRAMES = 100; |
| 1022 |
|
| 1023 |
res = InitNewThreadInfoArray(threadInfoArray, MAX_THREADS, MAX_FRAMES); |
| 1024 |
if (MRTE_FAILED(res)) |
| 1025 |
{ |
| 1026 |
(m_refProfEnv.m_pMpiApi)->ResumeVM(); |
| 1027 |
return res; |
| 1028 |
} |
| 1029 |
|
| 1030 |
res = (m_refProfEnv.m_pMpiApi)->GetAllThreadsInfo(m_refProfEnv.m_clientId, MAX_FRAMES, |
| 1031 |
DR_VM_RELATIVE_STACK_TRACE, &threadInfoArray); |
| 1032 |
if (MRTE_FAILED(res)) |
| 1033 |
{ |
| 1034 |
(m_refProfEnv.m_pMpiApi)->ResumeVM(); |
| 1035 |
DestroyThreadInfoArray(threadInfoArray); |
| 1036 |
} |
| 1037 |
|
| 1038 |
return res; |
| 1039 |
} |
| 1040 |
|
| 1041 |
void CCGShadowStackTracker::ReportThreadsStart(SThreadInfoArray& threadInfoArray) |
| 1042 |
{ |
| 1043 |
for (unsigned int threadIdx = 0; threadIdx < threadInfoArray.uiActualSize; threadIdx++) |
| 1044 |
{ |
| 1045 |
SThreadInfoArrayEntry* pThread = &(threadInfoArray.pEntries[threadIdx]); |
| 1046 |
|
| 1047 |
// Clear outdated data |
| 1048 |
m_refProfEnv.m_Tickets.ReleaseTicket(pThread->threadId); |
| 1049 |
m_refProfEnv.m_Tickets.DeleteThread(pThread->threadId); |
| 1050 |
|
| 1051 |
// Add new data info |
| 1052 |
m_refProfEnv.m_Tickets.AddNewThread(pThread->threadId); |
| 1053 |
|
| 1054 |
m_refProfEnv.GetThreadInfo(m_refProfEnv.m_clientId, pThread->threadId, |
| 1055 |
DR_THREAD_INFO | DR_THREAD_ELAPSED_TIME | DR_THREAD_CPU_TIME, &(pThread->threadInfo)); |
| 1056 |
|
| 1057 |
if (m_refProfEnv.m_profilerIsActive) |
| 1058 |
{ |
| 1059 |
(m_refProfEnv.ec_env)->PrintThreadStartElement(pThread->threadId, 0, |
| 1060 |
&(pThread->threadInfo)); |
| 1061 |
} |
| 1062 |
else |
| 1063 |
{ |
| 1064 |
m_refProfEnv.StoreThreadEvent(pThread->threadId, THREAD_START_EVENT, |
| 1065 |
&(pThread->threadInfo), 0); |
| 1066 |
} |
| 1067 |
} |
| 1068 |
} |
| 1069 |
|
| 1070 |
void CCGShadowStackTracker::ReportMethodEnter(TId threadId, SThreadInfo* pThreadInfo, TId methodId) |
| 1071 |
{ |
| 1072 |
// Get classId according to methodId |
| 1073 |
SMethodInfo methodInfo = {0}; |
| 1074 |
TResult iRes = (m_refProfEnv.m_pMpiApi)->GetMethodInfo(m_refProfEnv.m_clientId, |
| 1075 |
methodId, DR_CLASS_ID | DR_CLASS_NAME, &methodInfo); |
| 1076 |
LOG_ASSERT(iRes == MRTE_RESULT_OK); |
| 1077 |
LOG_ASSERT((methodInfo.validData & DR_CLASS_ID) != 0); |
| 1078 |
LOG_ASSERT((methodInfo.validData & DR_CLASS_NAME) != 0); |
| 1079 |
|
| 1080 |
if (m_refProfEnv.IsExcludedClass(methodInfo.szClassName)) |
| 1081 |
{ |
| 1082 |
return; |
| 1083 |
} |
| 1084 |
|
| 1085 |
// Just for Exec Details |
| 1086 |
m_refProfEnv.CheckMethodId(methodId); |
| 1087 |
|
| 1088 |
if (m_refProfEnv.m_profilerIsActive) |
| 1089 |
{// Profiler is in run mode |
| 1090 |
unsigned long ticket = m_refProfEnv.m_Tickets.GetNewTicket(threadId, |
| 1091 |
pThreadInfo->uiCpuNanos, true); |
| 1092 |
unsigned long stackDepth = m_refProfEnv.m_Tickets.GetStackDepth(threadId); |
| 1093 |
(m_refProfEnv.ec_env)->PrintMethodEntryElement(threadId, methodId, |
| 1094 |
methodInfo.classId, ticket, stackDepth); |
| 1095 |
} |
| 1096 |
else |
| 1097 |
{// Profiler is in pause mode |
| 1098 |
m_refProfEnv.m_Tickets.AddMethodEnterData(threadId, methodId, |
| 1099 |
methodInfo.classId, pThreadInfo->uiCpuNanos); |
| 1100 |
} |
| 1101 |
} |
| 1102 |
|
| 1103 |
void CCGShadowStackTracker::ReportMethodsEnter(SThreadInfoArray& threadInfoArray) |
| 1104 |
{ |
| 1105 |
for (unsigned int threadIdx = 0; threadIdx < threadInfoArray.uiActualSize; threadIdx++) |
| 1106 |
{ |
| 1107 |
TId threadId = threadInfoArray.pEntries[threadIdx].threadId; |
| 1108 |
SThreadInfo* pThreadInfo = &(threadInfoArray.pEntries[threadIdx].threadInfo); |
| 1109 |
|
| 1110 |
for (int stackTraceIdx = (pThreadInfo->vmOffsetStack).uiActualSize - 1; stackTraceIdx >= 0 ; |
| 1111 |
stackTraceIdx--) |
| 1112 |
{ |
| 1113 |
// Get methodId from stack trace info |
| 1114 |
SStackEntry* pStackEntry = &(pThreadInfo->vmOffsetStack.pStackEntries[stackTraceIdx]); |
| 1115 |
|
| 1116 |
ReportMethodEnter(threadId, pThreadInfo, pStackEntry->methodId); |
| 1117 |
} |
| 1118 |
} |
| 1119 |
} |
| 1120 |
|
| 1121 |
void CCGShadowStackTracker::SaveAllShadowStacksMethods(SThreadInfoArray& threadInfoArray) |
| 1122 |
{ |
| 1123 |
for (unsigned int threadIdx = 0; threadIdx < threadInfoArray.uiActualSize; threadIdx++) |
| 1124 |
{ |
| 1125 |
SThreadInfoArrayEntry* pThread = &(threadInfoArray.pEntries[threadIdx]); |
| 1126 |
CVMStackTrackData vmStacks; |
| 1127 |
vmStacks.threadId = pThread->threadId; |
| 1128 |
unsigned int stackTraceSize = |
| 1129 |
(pThread->threadInfo).vmOffsetStack.uiActualSize; |
| 1130 |
|
| 1131 |
for (int stackTraceIdx = stackTraceSize - 1; stackTraceIdx >= 0; stackTraceIdx--) |
| 1132 |
{ |
| 1133 |
vmStacks.shadowStack.push( |
| 1134 |
(pThread->threadInfo).vmOffsetStack.pStackEntries[stackTraceIdx].methodId); |
| 1135 |
} |
| 1136 |
|
| 1137 |
m_VMStacktraceDataMap.insert( |
| 1138 |
std::pair<MPI::TId, CVMStackTrackData>(vmStacks.threadId, vmStacks)); |
| 1139 |
} |
| 1140 |
} |
| 1141 |
|
| 1142 |
void CCGShadowStackTracker::TrackECAttach() |
| 1143 |
{ |
| 1144 |
if (!(m_refProfEnv.IsSupportedEG(EG_CALL_GRAPH))) |
| 1145 |
{// For profilers' common events, just handle for call graph |
| 1146 |
return; |
| 1147 |
} |
| 1148 |
|
| 1149 |
if (!isNeedTrack()) |
| 1150 |
{ |
| 1151 |
return; |
| 1152 |
} |
| 1153 |
|
| 1154 |
SThreadInfoArray threadInfoArray = {0}; |
| 1155 |
TResult res = GetInitialShadowStackTraces(threadInfoArray); |
| 1156 |
if (MRTE_FAILED(res)) |
| 1157 |
{ |
| 1158 |
LOG_ERROR("Can not get VM thread stack traces info.") |
| 1159 |
return; |
| 1160 |
} |
| 1161 |
|
| 1162 |
// Report related events and get initial shadow stacks |
| 1163 |
ReportThreadsStart(threadInfoArray); |
| 1164 |
|
| 1165 |
ReportMethodsEnter(threadInfoArray); |
| 1166 |
|
| 1167 |
SaveAllShadowStacksMethods(threadInfoArray); |
| 1168 |
|
| 1169 |
DestroyThreadInfoArray(threadInfoArray); |
| 1170 |
(m_refProfEnv.m_pMpiApi)->ResumeVM(); |
| 1171 |
} |
| 1172 |
|
| 1173 |
void CCGShadowStackTracker::TrackECDetach() |
| 1174 |
{ |
| 1175 |
if (!(m_refProfEnv.IsSupportedEG(EG_CALL_GRAPH))) |
| 1176 |
{// For profilers' common events, just handle for call graph |
| 1177 |
return; |
| 1178 |
} |
| 1179 |
|
| 1180 |
if (!isNeedTrack()) |
| 1181 |
{ |
| 1182 |
return; |
| 1183 |
} |
| 1184 |
|
| 1185 |
ReportLeftStackTrackDataMethodsLeave(); |
| 1186 |
} |
| 1187 |
|
| 1188 |
void CCGShadowStackTracker::ReportMethodLeave(TId threadId, TId methodId, |
| 1189 |
TTimeStamp uiCpuNanos) |
| 1190 |
{ |
| 1191 |
SMethodInfo methodInfo; |
| 1192 |
TResult iRes = (m_refProfEnv.m_pMpiApi)->GetMethodInfo(m_refProfEnv.m_clientId, |
| 1193 |
methodId, DR_CLASS_ID | DR_CLASS_NAME, &methodInfo); |
| 1194 |
LOG_ASSERT(iRes == MRTE_RESULT_OK); |
| 1195 |
LOG_ASSERT((methodInfo.validData & DR_CLASS_ID) != 0); |
| 1196 |
LOG_ASSERT((methodInfo.validData & DR_CLASS_NAME) != 0); |
| 1197 |
|
| 1198 |
if (m_refProfEnv.IsExcludedClass(methodInfo.szClassName)) |
| 1199 |
{ |
| 1200 |
return; |
| 1201 |
} |
| 1202 |
|
| 1203 |
// Just for Exec Details |
| 1204 |
U64 cpuTime = uiCpuNanos - m_refProfEnv.m_Tickets.GetCpuTime(threadId); |
| 1205 |
unsigned long ticket = m_refProfEnv.m_Tickets.ReleaseTicket(threadId); |
| 1206 |
|
| 1207 |
if (m_refProfEnv.m_profilerIsActive) |
| 1208 |
{ |
| 1209 |
(m_refProfEnv.ec_env)->PrintMethodExitElement(threadId, methodId, |
| 1210 |
methodInfo.classId, ticket, cpuTime); |
| 1211 |
} |
| 1212 |
else if (ticket != -1) |
| 1213 |
{ |
| 1214 |
m_refProfEnv.AddMethodLeaveData(threadId, methodId, methodInfo.classId, |
| 1215 |
ticket, cpuTime); |
| 1216 |
} |
| 1217 |
} |
| 1218 |
|
| 1219 |
void CCGShadowStackTracker::UpdateShadowStack(stack< TId >& tmpShadowStack, |
| 1220 |
stack< TId >& shadowStack, const SMethodEnterEventData& data) |
| 1221 |
{ |
| 1222 |
// Because normal stack is empty now, the tmpShadowStack must less or equal shadowStack |
| 1223 |
while (tmpShadowStack.size() < shadowStack.size()) |
| 1224 |
{// Geneate method leave events for shadow stack method |
| 1225 |
TId methodId = shadowStack.top(); |
| 1226 |
shadowStack.pop(); |
| 1227 |
ReportMethodLeave(data.threadId, methodId, data.uiCpuNanos); |
| 1228 |
} |
| 1229 |
} |
| 1230 |
|
| 1231 |
void CCGShadowStackTracker::TrackMethodEnter(SMethodEnterEventData &data) |
| 1232 |
{ |
| 1233 |
if (!isNeedTrack()) |
| 1234 |
{ |
| 1235 |
return; |
| 1236 |
} |
| 1237 |
|
| 1238 |
m_lockVMStackDataMap->Enter(); |
| 1239 |
map< MPI::TId, CVMStackTrackData >::iterator pos = m_VMStacktraceDataMap.find(data.threadId); |
| 1240 |
|
| 1241 |
if (pos == m_VMStacktraceDataMap.end()) |
| 1242 |
{// Enter a new thread after attach, it has no shadow stack record and can be handled normally |
| 1243 |
m_lockVMStackDataMap->Leave(); |
| 1244 |
return; |
| 1245 |
} |
| 1246 |
|
| 1247 |
CVMStackTrackData& refVmStacks = pos->second; |
| 1248 |
|
| 1249 |
if (refVmStacks.normalStack.empty()) |
| 1250 |
{ |
| 1251 |
SStackTrace_ stackTrace = {0}; |
| 1252 |
|
| 1253 |
m_refProfEnv.GetStackTrace(data.threadId, &stackTrace); |
| 1254 |
|
| 1255 |
std::stack< MPI::TId > tmpShadowStack; |
| 1256 |
// Ignore the new entered method, CGProxy.EarlyMethodEnter and CGProxy.MethodEnter on the stack top |
| 1257 |
const int ignoredMethodNum = 3; |
| 1258 |
for (int stackTraceIdx = stackTrace.uiSize - 1; stackTraceIdx > ignoredMethodNum - 1; stackTraceIdx--) |
| 1259 |
{ |
| 1260 |
tmpShadowStack.push(stackTrace.pStackEntries[stackTraceIdx].methodId); |
| 1261 |
} |
| 1262 |
|
| 1263 |
UpdateShadowStack(tmpShadowStack, refVmStacks.shadowStack, data); |
| 1264 |
|
| 1265 |
if (NULL != stackTrace.pStackEntries) |
| 1266 |
{ |
| 1267 |
stackTrace.uiSize = 0; |
| 1268 |
free(stackTrace.pStackEntries); |
| 1269 |
} |
| 1270 |
} |
| 1271 |
|
| 1272 |
refVmStacks.normalStack.push(data.methodId); |
| 1273 |
m_lockVMStackDataMap->Leave(); |
| 1274 |
} |
| 1275 |
|
| 1276 |
// return value: If continue to handle the MethodLeave events |
| 1277 |
bool CCGShadowStackTracker::TrackMethodLeave(SMethodLeaveEventData &data) |
| 1278 |
{ |
| 1279 |
if (!isNeedTrack()) |
| 1280 |
{ |
| 1281 |
return true; |
| 1282 |
} |
| 1283 |
|
| 1284 |
m_lockVMStackDataMap->Enter(); |
| 1285 |
map< MPI::TId, CVMStackTrackData >::iterator pos = m_VMStacktraceDataMap.find(data.threadId); |
| 1286 |
|
| 1287 |
if (pos == m_VMStacktraceDataMap.end()) |
| 1288 |
{// Enter a new thread after attach, it has no shadow stack record and can be handled normally |
| 1289 |
m_lockVMStackDataMap->Leave(); |
| 1290 |
return true; |
| 1291 |
} |
| 1292 |
|
| 1293 |
CVMStackTrackData& refVmStacks = pos->second; |
| 1294 |
|
| 1295 |
if (refVmStacks.normalStack.empty()) |
| 1296 |
{// Method leave notification is generated by instrumet before reattach, ignore it |
| 1297 |
m_lockVMStackDataMap->Leave(); |
| 1298 |
return false; |
| 1299 |
} |
| 1300 |
else |
| 1301 |
{ |
| 1302 |
refVmStacks.normalStack.pop(); |
| 1303 |
m_lockVMStackDataMap->Leave(); |
| 1304 |
return true; |
| 1305 |
} |
| 1306 |
} |
| 1307 |
|
| 1308 |
void CCGShadowStackTracker::TrackThreadEnd(SThreadEventData &data) |
| 1309 |
{ |
| 1310 |
if (!isNeedTrack()) |
| 1311 |
{ |
| 1312 |
return; |
| 1313 |
} |
| 1314 |
|
| 1315 |
m_lockVMStackDataMap->Enter(); |
| 1316 |
map< MPI::TId, CVMStackTrackData >::iterator pos = m_VMStacktraceDataMap.find(data.threadId); |
| 1317 |
|
| 1318 |
if (pos == m_VMStacktraceDataMap.end()) |
| 1319 |
{// Enter a new thread after attach, it has no shadow stack record and can be handled normally |
| 1320 |
m_lockVMStackDataMap->Leave(); |
| 1321 |
return; |
| 1322 |
} |
| 1323 |
|
| 1324 |
CVMStackTrackData& refVmStacks = pos->second; |
| 1325 |
|
| 1326 |
// refVmStacks.shadowStack report method leave events |
| 1327 |
while (!refVmStacks.shadowStack.empty()) |
| 1328 |
{ |
| 1329 |
TId methodId = refVmStacks.shadowStack.top(); |
| 1330 |
refVmStacks.shadowStack.pop(); |
| 1331 |
ReportMethodLeave(data.threadId, methodId, m_refProfEnv.m_Tickets.GetCpuTime(data.threadId)); |
| 1332 |
} |
| 1333 |
m_lockVMStackDataMap->Leave(); |
| 1334 |
} |
| 1335 |
|
| 1336 |
void CCGShadowStackTracker::ReportLeftStackTrackDataMethodsLeave() |
| 1337 |
{ |
| 1338 |
m_lockVMStackDataMap->Enter(); |
| 1339 |
|
| 1340 |
map< MPI::TId, CVMStackTrackData >::iterator pos = m_VMStacktraceDataMap.begin(); |
| 1341 |
for(; pos != m_VMStacktraceDataMap.end(); pos++) |
| 1342 |
{ |
| 1343 |
CVMStackTrackData& refVmStacks = pos->second; |
| 1344 |
|
| 1345 |
while (!refVmStacks.normalStack.empty()) |
| 1346 |
{ |
| 1347 |
TId methodId = refVmStacks.normalStack.top(); |
| 1348 |
refVmStacks.normalStack.pop(); |
| 1349 |
ReportMethodLeave(pos->first, methodId, m_refProfEnv.m_Tickets.GetCpuTime(pos->first)); |
| 1350 |
} |
| 1351 |
|
| 1352 |
while (!refVmStacks.shadowStack.empty()) |
| 1353 |
{ |
| 1354 |
TId methodId = refVmStacks.shadowStack.top(); |
| 1355 |
refVmStacks.shadowStack.pop(); |
| 1356 |
ReportMethodLeave(pos->first, methodId, m_refProfEnv.m_Tickets.GetCpuTime(pos->first)); |
| 1357 |
} |
| 1358 |
} |
| 1359 |
m_lockVMStackDataMap->Leave(); |
| 1360 |
} |
| 1361 |
// Add for bug 194081 |