1 /* 2 This file is provided under a dual BSD/GPLv2 license. When using or 3 redistributing this file, you may do so under either license. 4 5 GPL LICENSE SUMMARY 6 7 Copyright(c) 2005-2012 Intel Corporation. All rights reserved. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of version 2 of the GNU General Public License as 11 published by the Free Software Foundation. 12 13 This program is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21 The full GNU General Public License is included in this distribution 22 in the file called LICENSE.GPL. 23 24 Contact Information: 25 http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ 26 27 BSD LICENSE 28 29 Copyright(c) 2005-2012 Intel Corporation. All rights reserved. 30 All rights reserved. 31 32 Redistribution and use in source and binary forms, with or without 33 modification, are permitted provided that the following conditions 34 are met: 35 36 * Redistributions of source code must retain the above copyright 37 notice, this list of conditions and the following disclaimer. 38 * Redistributions in binary form must reproduce the above copyright 39 notice, this list of conditions and the following disclaimer in 40 the documentation and/or other materials provided with the 41 distribution. 42 * Neither the name of Intel Corporation nor the names of its 43 contributors may be used to endorse or promote products derived 44 from this software without specific prior written permission. 45 46 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 47 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 48 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 49 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 50 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 51 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 52 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 56 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 */ 58 #include "ittnotify_config.h" 59 60 #if ITT_PLATFORM==ITT_PLATFORM_WIN 61 #include <windows.h> 62 #pragma optimize("", off) 63 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 64 #include <pthread.h> 65 #include <dlfcn.h> 66 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 67 #include <malloc.h> 68 #include <stdlib.h> 69 70 #include "jitprofiling.h" 71 72 static const char rcsid[] = "\n@(#) $Revision: 234474 $\n"; 73 74 #define DLL_ENVIRONMENT_VAR "VS_PROFILER" 75 76 #ifndef NEW_DLL_ENVIRONMENT_VAR 77 #if ITT_ARCH==ITT_ARCH_IA32 78 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32" 79 #else 80 #define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64" 81 #endif 82 #endif /* NEW_DLL_ENVIRONMENT_VAR */ 83 84 #if ITT_PLATFORM==ITT_PLATFORM_WIN 85 #define DEFAULT_DLLNAME "JitPI.dll" 86 HINSTANCE m_libHandle = NULL; 87 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 88 #define DEFAULT_DLLNAME "libJitPI.so" 89 void* m_libHandle = NULL; 90 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 91 92 /* default location of JIT profiling agent on Android */ 93 #define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so" 94 95 /* the function pointers */ 96 typedef unsigned int(*TPInitialize)(void); 97 static TPInitialize FUNC_Initialize=NULL; 98 99 typedef unsigned int(*TPNotify)(unsigned int, void*); 100 static TPNotify FUNC_NotifyEvent=NULL; 101 102 static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING; 103 104 /* end collector dll part. */ 105 106 /* loadiJIT_Funcs() : this function is called just in the beginning and is responsible 107 ** to load the functions from BistroJavaCollector.dll 108 ** result: 109 ** on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1. 110 ** on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0. 111 */ 112 static int loadiJIT_Funcs(void); 113 114 /* global representing whether the BistroJavaCollector can't be loaded */ 115 static int iJIT_DLL_is_missing = 0; 116 117 /* Virtual stack - the struct is used as a virtual stack for each thread. 118 ** Every thread initializes with a stack of size INIT_TOP_STACK. 119 ** Every method entry decreases from the current stack point, 120 ** and when a thread stack reaches its top of stack (return from the global function), 121 ** the top of stack and the current stack increase. Notice that when returning from a function 122 ** the stack pointer is the address of the function return. 123 */ 124 #if ITT_PLATFORM==ITT_PLATFORM_WIN 125 static DWORD threadLocalStorageHandle = 0; 126 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 127 static pthread_key_t threadLocalStorageHandle = (pthread_key_t)0; 128 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 129 130 #define INIT_TOP_Stack 10000 131 132 typedef struct 133 { 134 unsigned int TopStack; 135 unsigned int CurrentStack; 136 } ThreadStack, *pThreadStack; 137 138 /* end of virtual stack. */ 139 140 /* 141 ** The function for reporting virtual-machine related events to VTune. 142 ** Note: when reporting iJVM_EVENT_TYPE_ENTER_NIDS, there is no need to fill in the stack_id 143 ** field in the iJIT_Method_NIDS structure, as VTune fills it. 144 ** 145 ** The return value in iJVM_EVENT_TYPE_ENTER_NIDS && iJVM_EVENT_TYPE_LEAVE_NIDS events 146 ** will be 0 in case of failure. 147 ** in iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event it will be -1 if EventSpecificData == 0 148 ** otherwise it will be 0. 149 */ 150 151 ITT_EXTERN_C int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) 152 { 153 int ReturnValue; 154 155 /******************************************************************************* 156 ** This section is for debugging outside of VTune. 157 ** It creates the environment variables that indicates call graph mode. 158 ** If running outside of VTune remove the remark. 159 ** 160 161 static int firstTime = 1; 162 char DoCallGraph[12] = "DoCallGraph"; 163 if (firstTime) 164 { 165 firstTime = 0; 166 SetEnvironmentVariable( "BISTRO_COLLECTORS_DO_CALLGRAPH", DoCallGraph); 167 } 168 169 ** end of section. 170 *******************************************************************************/ 171 172 /* initialization part - the functions have not been loaded yet. This part 173 ** will load the functions, and check if we are in Call Graph mode. 174 ** (for special treatment). 175 */ 176 if (!FUNC_NotifyEvent) 177 { 178 if (iJIT_DLL_is_missing) 179 return 0; 180 181 // load the Function from the DLL 182 if (!loadiJIT_Funcs()) 183 return 0; 184 185 /* Call Graph initialization. */ 186 } 187 188 /* If the event is method entry/exit, check that in the current mode 189 ** VTune is allowed to receive it 190 */ 191 if ((event_type == iJVM_EVENT_TYPE_ENTER_NIDS || event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) && 192 (executionMode != iJIT_CALLGRAPH_ON)) 193 { 194 return 0; 195 } 196 /* This section is performed when method enter event occurs. 197 ** It updates the virtual stack, or creates it if this is the first 198 ** method entry in the thread. The stack pointer is decreased. 199 */ 200 if (event_type == iJVM_EVENT_TYPE_ENTER_NIDS) 201 { 202 #if ITT_PLATFORM==ITT_PLATFORM_WIN 203 pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle); 204 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 205 pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 206 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 207 208 // check for use of reserved method IDs 209 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) 210 return 0; 211 212 if (!threadStack) 213 { 214 // initialize the stack. 215 threadStack = (pThreadStack) calloc (sizeof(ThreadStack), 1); 216 threadStack->TopStack = INIT_TOP_Stack; 217 threadStack->CurrentStack = INIT_TOP_Stack; 218 #if ITT_PLATFORM==ITT_PLATFORM_WIN 219 TlsSetValue(threadLocalStorageHandle,(void*)threadStack); 220 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 221 pthread_setspecific(threadLocalStorageHandle,(void*)threadStack); 222 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 223 } 224 225 // decrease the stack. 226 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (threadStack->CurrentStack)--; 227 } 228 229 /* This section is performed when method leave event occurs 230 ** It updates the virtual stack. 231 ** Increases the stack pointer. 232 ** If the stack pointer reached the top (left the global function) 233 ** increase the pointer and the top pointer. 234 */ 235 if (event_type == iJVM_EVENT_TYPE_LEAVE_NIDS) 236 { 237 #if ITT_PLATFORM==ITT_PLATFORM_WIN 238 pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle); 239 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 240 pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 241 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 242 243 // check for use of reserved method IDs 244 if ( ((piJIT_Method_NIDS) EventSpecificData)->method_id <= 999 ) 245 return 0; 246 247 if (!threadStack) 248 { 249 /* Error: first report in this thread is method exit */ 250 exit (1); 251 } 252 253 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = ++(threadStack->CurrentStack) + 1; 254 255 if (((piJIT_Method_NIDS) EventSpecificData)->stack_id > threadStack->TopStack) 256 ((piJIT_Method_NIDS) EventSpecificData)->stack_id = (unsigned int)-1; 257 } 258 259 if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED) 260 { 261 // check for use of reserved method IDs 262 if ( ((piJIT_Method_Load) EventSpecificData)->method_id <= 999 ) 263 return 0; 264 } 265 266 ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData); 267 268 return ReturnValue; 269 } 270 271 ITT_EXTERN_C void JITAPI iJIT_RegisterCallbackEx(void *userdata, iJIT_ModeChangedEx NewModeCallBackFuncEx) // The new mode call back routine 272 { 273 // is it already missing... or the load of functions from the DLL failed 274 if (iJIT_DLL_is_missing || !loadiJIT_Funcs()) 275 { 276 NewModeCallBackFuncEx(userdata, iJIT_NO_NOTIFICATIONS); // then do not bother with notifications 277 /* Error: could not load JIT functions. */ 278 return; 279 } 280 // nothing to do with the callback 281 } 282 283 /* 284 ** This function allows the user to query in which mode, if at all, VTune is running 285 */ 286 ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive() 287 { 288 if (!iJIT_DLL_is_missing) 289 { 290 loadiJIT_Funcs(); 291 } 292 293 return executionMode; 294 } 295 #include <stdio.h> 296 /* this function loads the collector dll (BistroJavaCollector) and the relevant functions. 297 ** on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1. 298 ** on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0. 299 */ 300 static int loadiJIT_Funcs() 301 { 302 static int bDllWasLoaded = 0; 303 char *dllName = (char*)rcsid; // !!! Just to avoid unused code elimination !!! 304 #if ITT_PLATFORM==ITT_PLATFORM_WIN 305 DWORD dNameLength = 0; 306 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 307 308 if(bDllWasLoaded) 309 {// dll was already loaded, no need to do it for the second time 310 return 1; 311 } 312 313 // Assumes that the DLL will not be found 314 iJIT_DLL_is_missing = 1; 315 FUNC_NotifyEvent = NULL; 316 317 if (m_libHandle) 318 { 319 #if ITT_PLATFORM==ITT_PLATFORM_WIN 320 FreeLibrary(m_libHandle); 321 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 322 dlclose(m_libHandle); 323 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 324 m_libHandle = NULL; 325 } 326 327 // try to get the dll name from the environment 328 #if ITT_PLATFORM==ITT_PLATFORM_WIN 329 dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0); 330 if (dNameLength) 331 { 332 DWORD envret = 0; 333 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); 334 envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, dllName, dNameLength); 335 if (envret) 336 { 337 // Try to load the dll from the PATH... 338 m_libHandle = LoadLibraryExA(dllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); 339 } 340 free(dllName); 341 } else { 342 // Try to use old VS_PROFILER variable 343 dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); 344 if (dNameLength) 345 { 346 DWORD envret = 0; 347 dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); 348 envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, dllName, dNameLength); 349 if (envret) 350 { 351 // Try to load the dll from the PATH... 352 m_libHandle = LoadLibraryA(dllName); 353 } 354 free(dllName); 355 } 356 } 357 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 358 dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); 359 if (!dllName) { 360 dllName = getenv(DLL_ENVIRONMENT_VAR); 361 } 362 #ifdef ANDROID 363 if (!dllName) 364 dllName = ANDROID_JIT_AGENT_PATH; 365 #endif 366 if (dllName) 367 { 368 // Try to load the dll from the PATH... 369 m_libHandle = dlopen(dllName, RTLD_LAZY); 370 } 371 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 372 373 if (!m_libHandle) 374 { 375 #if ITT_PLATFORM==ITT_PLATFORM_WIN 376 m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); 377 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 378 m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); 379 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 380 } 381 382 // if the dll wasn't loaded - exit. 383 if (!m_libHandle) 384 { 385 iJIT_DLL_is_missing = 1; // don't try to initialize JIT agent the second time 386 return 0; 387 } 388 #if ITT_PLATFORM==ITT_PLATFORM_WIN 389 FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent"); 390 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 391 FUNC_NotifyEvent = reinterpret_cast<TPNotify>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "NotifyEvent"))); 392 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 393 if (!FUNC_NotifyEvent) 394 { 395 FUNC_Initialize = NULL; 396 return 0; 397 } 398 399 #if ITT_PLATFORM==ITT_PLATFORM_WIN 400 FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize"); 401 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 402 FUNC_Initialize = reinterpret_cast<TPInitialize>(reinterpret_cast<intptr_t>(dlsym(m_libHandle, "Initialize"))); 403 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 404 if (!FUNC_Initialize) 405 { 406 FUNC_NotifyEvent = NULL; 407 return 0; 408 } 409 410 executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize(); 411 if (executionMode != iJIT_SAMPLING_ON) 412 executionMode = iJIT_SAMPLING_ON; 413 414 bDllWasLoaded = 1; 415 iJIT_DLL_is_missing = 0; // DLL is ok. 416 417 /* 418 ** Call Graph mode: init the thread local storage 419 ** (need to store the virtual stack there). 420 */ 421 if ( executionMode == iJIT_CALLGRAPH_ON ) 422 { 423 // Allocate a thread local storage slot for the thread "stack" 424 if (!threadLocalStorageHandle) 425 #if ITT_PLATFORM==ITT_PLATFORM_WIN 426 threadLocalStorageHandle = TlsAlloc(); 427 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 428 pthread_key_create(&threadLocalStorageHandle, NULL); 429 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 430 } 431 432 return 1; 433 } 434 435 /* 436 ** This function should be called by the user whenever a thread ends, to free the thread 437 ** "virtual stack" storage 438 */ 439 ITT_EXTERN_C void JITAPI FinalizeThread() 440 { 441 if (threadLocalStorageHandle) 442 { 443 #if ITT_PLATFORM==ITT_PLATFORM_WIN 444 pThreadStack threadStack = (pThreadStack)TlsGetValue (threadLocalStorageHandle); 445 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 446 pThreadStack threadStack = (pThreadStack)pthread_getspecific(threadLocalStorageHandle); 447 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 448 if (threadStack) 449 { 450 free (threadStack); 451 threadStack = NULL; 452 #if ITT_PLATFORM==ITT_PLATFORM_WIN 453 TlsSetValue (threadLocalStorageHandle, threadStack); 454 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 455 pthread_setspecific(threadLocalStorageHandle, threadStack); 456 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 457 } 458 } 459 } 460 461 /* 462 ** This function should be called by the user when the process ends, to free the local 463 ** storage index 464 */ 465 ITT_EXTERN_C void JITAPI FinalizeProcess() 466 { 467 if (m_libHandle) 468 { 469 #if ITT_PLATFORM==ITT_PLATFORM_WIN 470 FreeLibrary(m_libHandle); 471 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 472 dlclose(m_libHandle); 473 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 474 m_libHandle = NULL; 475 } 476 477 if (threadLocalStorageHandle) 478 #if ITT_PLATFORM==ITT_PLATFORM_WIN 479 TlsFree (threadLocalStorageHandle); 480 #else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 481 pthread_key_delete(threadLocalStorageHandle); 482 #endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ 483 } 484 485 /* 486 ** This function should be called by the user for any method once. 487 ** The function will return a unique method ID, the user should maintain the ID for each 488 ** method 489 */ 490 ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID() 491 { 492 static unsigned int methodID = 0x100000; 493 494 if (methodID == 0) 495 return 0; // ERROR : this is not a valid value 496 497 return methodID++; 498 } 499 500