V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
jitprofiling.cc
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;
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