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
iJIT_NotifyEvent(iJIT_JVM_EVENT event_type,void * EventSpecificData)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
iJIT_RegisterCallbackEx(void * userdata,iJIT_ModeChangedEx NewModeCallBackFuncEx)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 */
iJIT_IsProfilingActive()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 */
loadiJIT_Funcs()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 */
FinalizeThread()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 */
FinalizeProcess()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 */
iJIT_GetNewMethodID()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