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