This commit is contained in:
Staffan Larsen 2015-08-10 13:34:55 +00:00
commit 48c33a4389
68 changed files with 0 additions and 22758 deletions

View File

@ -1,37 +0,0 @@
#
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
include CopyCommon.gmk
################################################################################
HPROF_SRC := $(JDK_TOPDIR)/src/jdk.hprof.agent/share/native/libhprof/jvm.hprof.txt
$(LIB_DST_DIR)/jvm.hprof.txt: $(HPROF_SRC)
$(call install-file)
TARGETS := $(LIB_DST_DIR)/jvm.hprof.txt
################################################################################

View File

@ -1,94 +0,0 @@
#
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
include LibCommon.gmk
################################################################################
BUILD_LIBHPROF_SRC := $(call FindSrcDirsForLib, jdk.hprof.agent, hprof)
BUILD_LIBHPROF_CFLAGS := $(addprefix -I, $(BUILD_LIBHPROF_SRC)) \
-I$(JDK_TOPDIR)/src/demo/share/jvmti/java_crw_demo
BUILD_LIBHPROF_LDFLAGS :=
LIBHPROF_OPTIMIZATION := HIGHEST
ifneq ($(findstring $(OPENJDK_TARGET_OS), solaris linux), )
ifeq ($(ENABLE_DEBUG_SYMBOLS), true)
LIBHPROF_OPTIMIZATION := LOW
endif
endif
$(eval $(call SetupNativeCompilation,BUILD_LIBHPROF, \
LIBRARY := hprof, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
SRC := $(BUILD_LIBHPROF_SRC), \
OPTIMIZATION := $(LIBHPROF_OPTIMIZATION), \
CFLAGS := $(CFLAGS_JDKLIB) \
$(BUILD_LIBHPROF_CFLAGS), \
CFLAGS_debug := -DHPROF_LOGGING, \
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libhprof/mapfile-vers, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_windows := wsock32.lib winmm.lib advapi32.lib, \
LDFLAGS_SUFFIX_linux := $(LIBDL), \
LDFLAGS_SUFFIX_macosx := $(LIBDL), \
LDFLAGS_SUFFIX_solaris := -lsocket -lnsl $(LIBDL) -lc, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
RC_FLAGS := $(RC_FLAGS) \
-D "JDK_FNAME=hprof.dll" \
-D "JDK_INTERNAL_NAME=hprof" \
-D "JDK_FTYPE=0x2L", \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libhprof_jvmti, \
DEBUG_SYMBOLS := true))
TARGETS += $(BUILD_LIBHPROF)
################################################################################
LIBJAVA_CRW_DEMO_SRC := $(JDK_TOPDIR)/src/demo/share/jvmti/java_crw_demo
$(eval $(call SetupNativeCompilation,BUILD_LIBJAVA_CRW_DEMO, \
LIBRARY := java_crw_demo, \
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
SRC := $(LIBJAVA_CRW_DEMO_SRC), \
OPTIMIZATION := LOW, \
CFLAGS := $(CFLAGS_JDKLIB) \
$(addprefix -I, $(LIBJAVA_CRW_DEMO_SRC)), \
MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjava_crw_demo/mapfile-vers, \
LDFLAGS := $(LDFLAGS_JDKLIB) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_SUFFIX_solaris := -lc, \
VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
RC_FLAGS := $(RC_FLAGS) \
-D "JDK_FNAME=java_crw_demo.dll" \
-D "JDK_INTERNAL_NAME=java_crw_demo" \
-D "JDK_FTYPE=0x2L", \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjava_crw_demo, \
DEBUG_SYMBOLS := true))
TARGETS += $(BUILD_LIBJAVA_CRW_DEMO)
################################################################################

View File

@ -1,34 +0,0 @@
#
# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Define public interface.
SUNWprivate_1.1 {
global:
Agent_OnLoad;
Agent_OnUnload;
local:
*;
};

View File

@ -1,34 +0,0 @@
#
# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# Define public interface.
SUNWprivate_1.1 {
global:
java_crw_demo;
java_crw_demo_classname;
local:
*;
};

View File

@ -19,7 +19,6 @@ java.xml.crypto
jdk.charsets
jdk.deploy
jdk.deploy.osx
jdk.hprof.agent
jdk.httpserver
jdk.jfr
jdk.management

View File

@ -1082,15 +1082,6 @@ ParseArguments(int *pargc, char ***pargv,
AddOption("-Xverify:remote", NULL);
} else if (JLI_StrCmp(arg, "-noverify") == 0) {
AddOption("-Xverify:none", NULL);
} else if (JLI_StrCCmp(arg, "-prof") == 0) {
char *p = arg + 5;
char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 50);
if (*p) {
sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);
} else {
sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");
}
AddOption(tmp, NULL);
} else if (JLI_StrCCmp(arg, "-ss") == 0 ||
JLI_StrCCmp(arg, "-oss") == 0 ||
JLI_StrCCmp(arg, "-ms") == 0 ||

View File

@ -1,86 +0,0 @@
/*
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include <stdio.h>
#include <sys/ldr.h>
#include <errno.h>
#include "porting_aix.h"
static unsigned char dladdr_buffer[0x4000];
static void fill_dll_info(void) {
int rc = loadquery(L_GETINFO,dladdr_buffer, sizeof(dladdr_buffer));
if (rc == -1) {
fprintf(stderr, "loadquery failed (%d %s)", errno, strerror(errno));
fflush(stderr);
}
}
static int dladdr_dont_reload(void* addr, Dl_info* info) {
const struct ld_info* p = (struct ld_info*) dladdr_buffer;
info->dli_fbase = 0; info->dli_fname = 0;
info->dli_sname = 0; info->dli_saddr = 0;
for (;;) {
if (addr >= p->ldinfo_textorg &&
addr < (((char*)p->ldinfo_textorg) + p->ldinfo_textsize)) {
info->dli_fname = p->ldinfo_filename;
info->dli_fbase = p->ldinfo_textorg;
return 1; /* [sic] */
}
if (!p->ldinfo_next) {
break;
}
p = (struct ld_info*)(((char*)p) + p->ldinfo_next);
}
return 0; /* [sic] */
}
#ifdef __cplusplus
extern "C"
#endif
int dladdr(void *addr, Dl_info *info) {
static int loaded = 0;
if (!loaded) {
fill_dll_info();
loaded = 1;
}
if (!addr) {
return 0; /* [sic] */
}
/* Address could be AIX function descriptor? */
void* const addr0 = *( (void**) addr );
int rc = dladdr_dont_reload(addr, info);
if (rc == 0) {
rc = dladdr_dont_reload(addr0, info);
if (rc == 0) { /* [sic] */
fill_dll_info(); /* refill, maybe loadquery info is outdated */
rc = dladdr_dont_reload(addr, info);
if (rc == 0) {
rc = dladdr_dont_reload(addr0, info);
}
}
}
return rc;
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* Header file to contain porting-relevant code which does not have a
* home anywhere else.
* This is intially based on hotspot/src/os/aix/vm/{loadlib,porting}_aix.{hpp,cpp}
*/
/*
* Aix' own version of dladdr().
* This function tries to mimick dladdr(3) on Linux
* (see http://linux.die.net/man/3/dladdr)
* dladdr(3) is not POSIX but a GNU extension, and is not available on AIX.
*
* Differences between AIX dladdr and Linux dladdr:
*
* 1) Dl_info.dli_fbase: can never work, is disabled.
* A loaded image on AIX is divided in multiple segments, at least two
* (text and data) but potentially also far more. This is because the loader may
* load each member into an own segment, as for instance happens with the libC.a
* 2) Dl_info.dli_sname: This only works for code symbols (functions); for data, a
* zero-length string is returned ("").
* 3) Dl_info.dli_saddr: For code, this will return the entry point of the function,
* not the function descriptor.
*/
typedef struct {
const char *dli_fname; /* file path of loaded library */
void *dli_fbase; /* doesn't make sence on AIX */
const char *dli_sname; /* symbol name; "" if not known */
void *dli_saddr; /* address of *entry* of function; not function descriptor; */
} Dl_info;
#ifdef __cplusplus
extern "C"
#endif
int dladdr(void *addr, Dl_info *info);

View File

@ -1,124 +0,0 @@
/*
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.demo.jvmti.hprof;
/* This class and it's methods are used by hprof when injecting bytecodes
* into class file images.
* See the directory src/share/demo/jvmti/hprof and the file README.txt
* for more details.
*/
public class Tracker {
/* Master switch that activates calls to native functions. */
private static int engaged = 0;
/* To track memory allocated, we need to catch object init's and arrays. */
/* At the beginning of java.jang.Object.<init>(), a call to
* Tracker.ObjectInit() is injected.
*/
private static native void nativeObjectInit(Object thr, Object obj);
public static void ObjectInit(Object obj)
{
if ( engaged != 0) {
if (obj == null) {
throw new IllegalArgumentException("Null object.");
}
nativeObjectInit(Thread.currentThread(), obj);
}
}
/* Immediately following any of the newarray bytecodes, a call to
* Tracker.NewArray() is injected.
*/
private static native void nativeNewArray(Object thr, Object obj);
public static void NewArray(Object obj)
{
if ( engaged != 0) {
if (obj == null) {
throw new IllegalArgumentException("Null object.");
}
nativeNewArray(Thread.currentThread(), obj);
}
}
/* For cpu time spent in methods, we need to inject for every method. */
/* At the very beginning of every method, a call to
* Tracker.CallSite() is injected.
*/
private static native void nativeCallSite(Object thr, int cnum, int mnum);
public static void CallSite(int cnum, int mnum)
{
if ( engaged != 0 ) {
if (cnum < 0) {
throw new IllegalArgumentException("Negative class index");
}
if (mnum < 0) {
throw new IllegalArgumentException("Negative method index");
}
nativeCallSite(Thread.currentThread(), cnum, mnum);
}
}
/* Before any of the return bytecodes, a call to
* Tracker.ReturnSite() is injected.
*/
private static native void nativeReturnSite(Object thr, int cnum, int mnum);
public static void ReturnSite(int cnum, int mnum)
{
if ( engaged != 0 ) {
if (cnum < 0) {
throw new IllegalArgumentException("Negative class index");
}
if (mnum < 0) {
throw new IllegalArgumentException("Negative method index");
}
nativeReturnSite(Thread.currentThread(), cnum, mnum);
}
}
}

View File

@ -1,113 +0,0 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
README
------
Design and Implementation:
* The Tracker Class (Tracker.java & hprof_tracker.c)
It was added to the sun.tools.hprof.Tracker in JDK 5.0 FCS, then
moved to a package that didn't cause classload errors due to
the security manager not liking the sun.* package name.
5091195 detected that this class needs to be in com.sun.demo.jvmti.hprof.
The BCI code will call these static methods, which will in turn
(if engaged) call matching native methods in the hprof library,
with the additional current Thread argument (Thread.currentThread()).
Doing the currentThread call on the Java side was necessary due
to the difficulty of getting the current thread while inside one
of these Tracker native methods. This class lives in rt.jar.
* Byte Code Instrumentation (BCI)
Using the ClassFileLoadHook feature and a C language
implementation of a byte code injection transformer, the following
bytecodes get injections:
- On entry to the java.lang.Object <init> method,
a invokestatic call to
Tracker.ObjectInit(this);
is injected.
- On any newarray type opcode, immediately following it,
the array object is duplicated on the stack and an
invokestatic call to
Tracker.NewArray(obj);
is injected.
- On entry to all methods, a invokestatic call to
Tracker.CallSite(cnum,mnum);
is injected. The hprof agent can map the two integers
(cnum,mnum) to a method in a class. This is the BCI based
"method entry" event.
- On return from any method (any return opcode),
a invokestatic call to
Tracker.ReturnSite(cnum,mnum);
is injected.
All classes found via ClassFileLoadHook are injected with the
exception of some system class methods "<init>" and "finalize"
whose length is 1 and system class methods with name "<clinit>",
and also java.lang.Thread.currentThread() which is used in the
class Tracker (preventing nasty recursion issue).
System classes are currently defined as any class seen by the
ClassFileLoadHook prior to VM_INIT. This does mean that
objects created in the system classes inside <clinit> might not
get tracked initially.
See the java_crw_demo source and documentation for more info.
The injections are based on what the hprof options
are requesting, e.g. if heap=sites or heap=all is requested, the
newarray and Object.<init> method injections happen.
If cpu=times is requested, all methods get their entries and
returns tracked. Options like cpu=samples or monitor=y
do not require BCI.
* BCI Allocation Tags (hprof_tag.c)
The current jlong tag being used on allocated objects
is an ObjectIndex, or an index into the object table inside
the hprof code. Depending on whether heap=sites or heap=dump
was asked for, these ObjectIndex's might represent unique
objects, or unique allocation sites for types of objects.
The heap=dump option requires considerable more space
due to the one jobject per ObjectIndex mapping.
* BCI Performance
The cpu=times seems to have the most negative affect on
performance, this could be improved by not having the
Tracker class methods call native code directly, but accumulate
the data in a file or memory somehow and letting it buffer down
to the agent. The cpu=samples is probably a better way to
measure cpu usage, varying the interval as needed.
The heap=dump seems to use memory like crazy, but that's
partially the way it has always been.
* Sources in the JDK workspace
The sources and Makefiles live in:
src/jdk.hprof.agent/*
src/share/demo/jvmti/java_crw_demo/*
make/lib/Lib-jdk.hprof.agent.gmk
--------

View File

@ -1,769 +0,0 @@
/*
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* **************************************************************************
*
* Set of malloc/realloc/calloc/strdup/free replacement macros that
* insert some extra words around each allocation for debugging purposes
* and also attempt to detect invalid uses of the malloc heap through
* various tricks like inserting clobber words at the head and tail of
* the user's area, delayed free() calls, and setting the memory to
* a fixed pattern on allocation and when freed. The allocations also
* can include warrants so that when an area is clobbered, this
* package can report where the allocation took place.
* The macros included are:
* malloc(size)
* realloc(ptr,size)
* calloc(nelem,elsize)
* strdup(s1)
* free(ptr)
* malloc_police() <--- Not a system function
* The above macros match the standard behavior of the system functions.
*
* They should be used through the include file "debug_malloc.h".
*
* IMPORTANT: All source files that call any of these macros
* should include debug_malloc.h. This package will
* not work if the memory isn't allocated and freed
* by the macros in debug_malloc.h. The important issue
* is that any malloc() from debug_malloc.h must be
* freed by the free() in debug_malloc.h.
*
* The macros in debug_malloc.h will override the normal use of
* malloc, realloc, calloc, strdup, and free with the functions below.
*
* These functions include:
* void *debug_malloc(size_t, void*, int);
* void *debug_realloc(void*, size_t, void*, int);
* void *debug_calloc(size_t, size_t, void*, int);
* void debug_free(void *, void*, int);
*
* In addition the function debug_malloc_police() can be called to
* tell you what memory has not been freed.
* void debug_malloc_police(void*, int);
* The function debug_malloc_police() is available through the macro
* malloc_police(). Normally you would want to call this at exit()
* time to find out what memory is still allocated.
*
* The variable malloc_watch determines if the warrants are generated.
* warrants are structures that include the filename and line number
* of the caller who allocated the memory. This structure is stored
* at the tail of the malloc space, which is allocated large enough
* to hold some clobber words at the head and tail, the user's request
* and the warrant record (if malloc_watch is non-zero).
*
* The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation
* are set to (when the allocation is not a multiple of 8) on allocation.
* At free(0 time, these bytes are double checked to make sure they were
* not clobbered. To remove this feature #undef LEFT_OVER_CHAR.
*
* The memory freed will have the FREED_CHAR put into it. To remove this
* feature #undef FREED_CHAR.
*
* The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it
* at the time of allocation. To remove this feature #undef ALLOC_CHAR.
*
* The macro MAX_FREE_DELAY_COUNT controls how many free blocks will
* be kept around before being freed. This creates a delayed affect
* so that free space that gets clobbered just might get detected.
* The free() call will immediately set the user space to the FREED_CHAR,
* leaving the clobber words and warrant in place (making sure they
* haven't been clobbered). Then the free() pointer is added to a
* queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the
* oldest free()'d memory is actually freed, getting it's entire
* memory length set to the FREED_CHAR.
*
* WARNING: This can significantly slow down an application, depending
* on how many allocations are made. Also the additional memory
* needed for the clobber words and the warrants can be significant
* again, depending on how many allocations are made.
* In addition, the delayed free calls can create situations
* where you might run out of memory prematurely.
*
* **************************************************************************
*/
#ifdef DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include "hprof.h"
/* ***************************************************************************
* Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes):
*
* -----------------
* malloc/free get->| clobber Word | ---> contains -size requested by user
* -----------------
* User gets --->| user space |
* | |
* | | left_over | ---> left_over bytes will be <= 7
* -----------------
* | clobber Word | ---> contains -size requested by user
* -----------------
* | Warrant | ---> Optional (malloc_watch!=0)
* | | Contains filename and line number
* | | where allocation happened
* | |
* -----------------
***************************************************************************/
/*
* Flag that tells debug_malloc/debug_free/debug_realloc to police
* heap space usage. (This is a dynamic flag that can be turned on/off)
*/
static int malloc_watch = 1;
/* Character to stuff into freed space */
#define FREED_CHAR 'F'
/* Character to stuff into allocated space */
#define ALLOC_CHAR 'A'
/* Character to stuff into left over trailing bytes */
#define LEFT_OVER_CHAR 'Z'
/* Number of 'free' calls that will be delayed until the end */
#define MAX_FREE_DELAY_COUNT 1
#undef MAX_FREE_DELAY_COUNT
/* Maximum name of __FILE_ stored in each malloc'd area */
#define WARRANT_NAME_MAX (32-1) /* 1 less than multiple of 8 is best */
/* Macro to convert a user pointer to the malloc pointer */
#define user2malloc_(uptr) (((char*)(void*)uptr)-sizeof(Word))
/* Macro to convert a macro pointer to the user pointer */
#define malloc2user_(mptr) (((char*)(void*)(mptr))+sizeof(Word))
/* Size of the warrant record (this is dynamic) */
#define warrant_space ( malloc_watch?sizeof(Warrant_Record):0 )
/* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */
#define round_up_(n) \
((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word)))
/* Macro to calculate the needed malloc bytes from the user's request. */
#define rbytes_(nbytes) \
(size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space )
/* Macro to get the -size stored in space through the malloc pointer */
#define nsize1_(mptr) (((Word*)(void*)(mptr))->nsize1)
#define nsize2_(mptr) (((Word*)(void*)(mptr))->nsize2)
/* Macro to get the -size stored in the tail of the space through */
/* the malloc pointer */
#define tail_nsize1_(mptr) \
nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
#define tail_nsize2_(mptr) \
nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
/* Macro to get the -size stored in space through the user pointer */
#define user_nsize1_(uptr) nsize1_(user2malloc_(uptr))
#define user_nsize2_(uptr) nsize2_(user2malloc_(uptr))
/* Macro to get the -size stored in the tail of the space through */
/* the user pointer */
#define user_tail_nsize1_(uptr) tail_nsize1_(user2malloc_(uptr))
#define user_tail_nsize2_(uptr) tail_nsize2_(user2malloc_(uptr))
/* Macro to get the int* of the last 32bit word of user space */
#define last_user_word_(mptr) \
((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))))
/* Macros to get at the warrant contents from the malloc pointer */
#define warrant_(mptr) \
(*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2)))
/* This struct is allocated after the tail clobber word if malloc_watch */
/* is true. */
typedef struct {
void *link; /* Next mptr in list */
char name[WARRANT_NAME_MAX + 1]; /* Name of allocator */
int line; /* Line number where allocated */
int id; /* Nth allocation */
} Warrant_Record;
#define warrant_link_(mptr) warrant_(mptr).link
#define warrant_name_(mptr) warrant_(mptr).name
#define warrant_line_(mptr) warrant_(mptr).line
#define warrant_id_(mptr) warrant_(mptr).id
#define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?")
#define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0)
#define MID(mptr) (malloc_watch?warrant_id_(mptr):0)
/* This should be one machine word and is also the clobber word struct */
typedef struct {
int nsize1;
int nsize2;
} Word; /* Largest basic type , sizeof(double)? */
/* The first malloc pointer for the warrants */
static void *first_warrant_mptr = NULL;
/* Counter of allocations */
static int id_counter = 0;
static int largest_size = 0;
static void * largest_addr = NULL;
static void * smallest_addr = NULL;
/* Used to isolate what the error is */
static char *debug_check;
static void *clobbered_ptr;
/* Minimum macro */
#define minimum(a,b) ((a)<(b)?(a):(b))
/* Message routine */
static void
error_message(const char * format, ...)
{
FILE *error_fp = stderr; /* All debug_malloc.c messages */
va_list ap;
va_start(ap, format);
(void)fprintf(error_fp, "debug_malloc: ");
(void)vfprintf(error_fp, format, ap);
(void)fprintf(error_fp, "\n");
(void)fflush(error_fp);
va_end(ap);
}
/* This function prints out a memory error for the memory function
* 'name' which was called in file 'file' at line number 'line'. The malloc
* pointer with the error is in 'mptr'.
*/
static void
memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line)
{
char nice_words[512];
char temp[256];
int len;
void *mptr_walk;
if (name == NULL)
name = "UNKNOWN_NAME";
if (file == NULL)
file = "UNKNOWN_FILE";
md_system_error(temp, (int)sizeof(temp));
(void)strcpy(nice_words, temp);
if ( debug_check!=NULL ) {
(void)md_snprintf(nice_words, sizeof(nice_words),
"%s The %s at %p appears to have been hit.",
temp, debug_check, clobbered_ptr);
}
len = -nsize1_(mptr);
error_message("Error: "
"%s The malloc space #%d is at %p [user size=%d(0x%x)],"
" and was allocated from file \"%s\" at line %d."
" [The debug function %s() detected this error "
"in file \"%s\" at line %d.]",
nice_words, mid, mptr, len, len, mfile, mline,
name, file, line);
/* Print out contents of this allocation */
{
int i;
void *uptr = malloc2user_(mptr);
char *pmess;
pmess = temp;
for(i=0;i<(int)sizeof(temp);i++) {
int ch = ((unsigned char*)uptr)[i];
if ( isprint(ch) ) {
*pmess++ = ch;
} else {
*pmess++ = '\\';
*pmess++ = 'x';
(void)sprintf(pmess,"%02x",ch);
pmess+=2;
}
}
*pmess = 0;
error_message("Error: %p contains user data: %s", uptr, temp);
}
/* Try and print out table */
if (!malloc_watch) {
return;
}
mptr_walk = first_warrant_mptr;
if (mptr_walk != NULL) {
error_message("Active allocations: "
"count=%d, largest_size=%d, address range (%p,%p)",
id_counter, largest_size, smallest_addr, largest_addr);
do {
int size1;
int size2;
char *mfile_walk;
if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) {
error_message("Terminating list due to pointer corruption");
break;
}
size1 = -nsize1_(mptr_walk);
size2 = -nsize2_(mptr_walk);
mfile_walk = MFILE(mptr_walk);
error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d",
MID(mptr_walk), mptr_walk, size1, size2,
WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk));
if ( size1 != size2 || size1 > largest_size || size1 < 0 ) {
error_message("Terminating list due to size corruption");
break;
}
mptr_walk = warrant_link_(mptr_walk);
} while (mptr_walk != NULL);
}
abort();
}
/* This function sets the clobber word and sets up the warrant for the input
* malloc pointer "mptr".
*/
static void
setup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line)
{
register int nbytes;
/*LINTED*/
nbytes = (int)size;
if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes;
/*LINTED*/
if ( mptr > largest_addr ) largest_addr = mptr;
/*LINTED*/
if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr;
/* Must be done first: */
nsize1_(mptr) = -nbytes;
nsize2_(mptr) = -nbytes;
tail_nsize1_(mptr) = -nbytes;
tail_nsize2_(mptr) = -nbytes;
#ifdef LEFT_OVER_CHAR
/* Fill in those few extra bytes just before the tail Word structure */
{
register int trailing_extra_bytes;
/* LINTED */
trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
if ( trailing_extra_bytes > 0 ) {
register char *p;
register int i;
p = ((char *) mptr) + sizeof(Word) + nbytes;
for (i = 0; i < trailing_extra_bytes; i++)
p[i] = LEFT_OVER_CHAR;
}
}
#endif
/* Fill out warrant */
if (malloc_watch) {
static Warrant_Record zero_warrant;
register void *p1,
*p2;
size_t len;
int start_pos = 0;
warrant_(mptr) = zero_warrant;
p1 = warrant_name_(mptr);
len = strlen(file);
if ( len > WARRANT_NAME_MAX ) {
/*LINTED*/
start_pos = (int)len - WARRANT_NAME_MAX;
}
p2 = ((char*)file) + start_pos;
/*LINTED*/
(void) memcpy(p1, p2, minimum(((int)len), WARRANT_NAME_MAX));
warrant_line_(mptr) = line;
warrant_id_(mptr) = ++id_counter;
warrant_link_(mptr) = first_warrant_mptr;
first_warrant_mptr = mptr;
}
}
/* This function checks the clobber words at the beginning and end of the
* allocated space.
*/
static void
memory_check(void *uptr, int mid, const char *mfile, int mline, const char *file, int line)
{
int neg_nbytes;
int nbytes;
debug_check = "pointer value itself";
clobbered_ptr = uptr;
if (uptr == NULL)
memory_error((void *) NULL, "memory_check", mid, mfile, mline, file, line);
/* Check both Word structures */
debug_check = "first beginning clobber word";
clobbered_ptr = (char*)&user_nsize1_(uptr);
neg_nbytes = user_nsize1_(uptr);
if (neg_nbytes >= 0)
memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
debug_check = "second beginning clobber word";
clobbered_ptr = (char*)&user_nsize2_(uptr);
if (neg_nbytes != user_nsize2_(uptr))
memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
debug_check = "first ending clobber word";
clobbered_ptr = (char*)&user_tail_nsize1_(uptr);
if (neg_nbytes != user_tail_nsize1_(uptr))
memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
debug_check = "second ending clobber word";
clobbered_ptr = (char*)&user_tail_nsize2_(uptr);
if (neg_nbytes != user_tail_nsize2_(uptr))
memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
/* Get a positive count of bytes */
nbytes = -neg_nbytes;
#ifdef LEFT_OVER_CHAR
{
/* Check those few extra bytes just before the tail Word structure */
register int trailing_extra_bytes;
register int i;
register char *p;
/* LINTED */
trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
p = ((char *) (uptr)) + nbytes;
debug_check = "trailing left over area";
for (i = 0; i < trailing_extra_bytes; i++) {
clobbered_ptr = p+1;
if (p[i] != LEFT_OVER_CHAR) {
memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
}
}
}
#endif
/* Make sure debug_check is cleared */
debug_check = NULL;
}
/* This function looks for the given malloc pointer in the police line up
* and removes it from the warrant list.
* mptr The pointer to the malloc space being removed
*/
static int
remove_warrant(void *mptr)
{
void *mptr1,
*last_mptr1;
/* Free it up from the list */
if (malloc_watch && mptr != NULL) {
int found;
found = 0;
last_mptr1 = NULL;
mptr1 = first_warrant_mptr;
while (mptr1 != NULL) {
if (mptr1 == mptr) {
if (last_mptr1 == NULL)
first_warrant_mptr = warrant_link_(mptr1);
else
warrant_link_(last_mptr1) = warrant_link_(mptr1);
found = 1;
break;
}
last_mptr1 = mptr1;
mptr1 = warrant_link_(mptr1);
}
return found;
}
return 1;
}
static void
actual_free(void *uptr, const char *file, int line)
{
void *mptr;
const char *mfile;
int mline;
int mid;
if ( uptr == NULL )
return;
mptr = user2malloc_(uptr);
memory_check(uptr, (mid=MID(mptr)), (mfile=MFILE(mptr)), (mline=MLINE(mptr)), file, line);
if (malloc_watch && remove_warrant(mptr)==0 )
memory_check(uptr, mid, mfile, mline, file, line);
#ifdef FREED_CHAR
if ( mptr!=NULL ) {
size_t nbytes = -nsize1_(mptr);
/* LINTED */
(void)memset(mptr, FREED_CHAR, rbytes_(nbytes));
}
#endif
free(mptr);
}
#ifdef MAX_FREE_DELAY_COUNT
static void *free_delay[MAX_FREE_DELAY_COUNT];
static int free_delay_pos = 0;
static void
delayed_free(void *uptr, const char* file, int line)
{
void *mptr;
void *olduptr = free_delay[free_delay_pos];
size_t nbytes;
if ( uptr==NULL )
return;
mptr = user2malloc_(uptr);
memory_check(uptr, MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
if ( olduptr!=NULL ) {
actual_free(olduptr, file, line);
}
free_delay[free_delay_pos] = uptr;
free_delay_pos++;
free_delay_pos = free_delay_pos % MAX_FREE_DELAY_COUNT;
nbytes = -user_nsize1_(uptr);
#ifdef FREED_CHAR
(void)memset(uptr, FREED_CHAR, (size_t)nbytes);
#endif
}
static void
delayed_free_all(const char *file, int line)
{
int i;
for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) {
void *olduptr = free_delay[i];
free_delay[i] = NULL;
if ( olduptr!=NULL ) {
actual_free(olduptr, file, line);
}
}
}
#endif
void
debug_free(void *uptr, const char *file, int line)
{
int mid = 0;
if (uptr == NULL)
memory_error((void *) NULL, "debug_free", mid, file, line, file, line);
#ifdef MAX_FREE_DELAY_COUNT
delayed_free(uptr, file, line);
#else
actual_free(uptr, file, line);
#endif
}
/* This function calls malloc(). */
void *
debug_malloc(size_t nbytes, const char *file, int line)
{
void *mptr;
void *uptr;
int mid = id_counter;
/*LINTED*/
if ((int)nbytes <= 0)
memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
/* LINTED */
mptr = malloc(rbytes_(nbytes));
if (mptr == NULL)
memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
setup_space_and_issue_warrant(mptr, nbytes, file, line);
uptr = malloc2user_(mptr);
#ifdef ALLOC_CHAR
(void)memset(uptr, ALLOC_CHAR, (size_t)nbytes);
#endif
return uptr;
}
void *
debug_realloc(void *uptr, size_t nbytes, const char *file, int line)
{
void *mptr;
void *oldmptr;
void *newuptr;
size_t oldnbytes;
int mid = id_counter;
oldmptr = user2malloc_(uptr);
oldnbytes = 0;
if ((int)nbytes <= 0)
memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
if (uptr != NULL) {
memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
oldnbytes = -user_nsize1_(uptr);
if ( malloc_watch && remove_warrant(oldmptr)==0 )
memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
}
if (uptr == NULL) {
/* LINTED */
mptr = malloc(rbytes_(nbytes));
} else {
/* LINTED */
mptr = realloc(oldmptr, rbytes_(nbytes));
}
if (mptr == NULL)
memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
setup_space_and_issue_warrant(mptr, nbytes, file, line);
newuptr = malloc2user_(mptr);
#ifdef ALLOC_CHAR
if (uptr == NULL)
(void)memset(newuptr, ALLOC_CHAR, (size_t)nbytes);
else if ( nbytes > oldnbytes )
(void)memset(((char*)newuptr)+oldnbytes, ALLOC_CHAR, (size_t)nbytes-oldnbytes);
#endif
return newuptr;
}
/* This function calls calloc(). */
void *
debug_calloc(size_t nelem, size_t elsize, const char *file, int line)
{
void *mptr;
size_t nbytes;
int mid = id_counter;
nbytes = nelem*elsize;
/*LINTED*/
if ((int)nbytes <= 0)
memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
/* LINTED */
mptr = calloc(rbytes_(nbytes),1);
if (mptr == NULL)
memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
setup_space_and_issue_warrant(mptr, nbytes, file, line);
return malloc2user_(mptr);
}
/* This function replaces strdup(). */
char *
debug_strdup(const char *s1, const char *file, int line)
{
void *mptr;
void *uptr;
size_t nbytes;
int mid = id_counter;
if (s1 == NULL)
memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
nbytes = strlen(s1)+1;
/*LINTED*/
if ((int)nbytes < 0)
memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
/* LINTED */
mptr = malloc(rbytes_(nbytes));
if (mptr == NULL)
memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
setup_space_and_issue_warrant(mptr, nbytes, file, line);
uptr = malloc2user_(mptr);
(void)strcpy((char*)uptr, s1);
return (char*)uptr;
}
void
debug_malloc_verify(const char *file, int line)
{
void *mptr;
#ifdef MAX_FREE_DELAY_COUNT
delayed_free_all(file,line);
#endif
if (!malloc_watch) {
return;
}
mptr = first_warrant_mptr;
if (mptr != NULL) {
/* Check all this memory first */
do {
memory_check(malloc2user_(mptr), MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
mptr = warrant_link_(mptr);
} while (mptr != NULL);
}
}
/* Report outstanding space warrants to console. */
void
debug_malloc_police(const char *file, int line)
{
void *mptr;
#ifdef MAX_FREE_DELAY_COUNT
delayed_free_all(file,line);
#endif
if (!malloc_watch) {
return;
}
mptr = first_warrant_mptr;
if (mptr != NULL) {
debug_malloc_verify(file, line);
/* Now issue warrants */
mptr = first_warrant_mptr;
do {
error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d",
mptr, -nsize1_(mptr), warrant_name_(mptr),
warrant_line_(mptr), warrant_id_(mptr));
mptr = warrant_link_(mptr);
} while (mptr != NULL);
}
}
#else
void
debug_malloc_verify(const char *file, int line)
{
file = file;
line = line;
}
void
debug_malloc_police(const char *file, int line)
{
file = file;
line = line;
}
#endif

View File

@ -1,85 +0,0 @@
/*
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* ***********************************************************************
*
* The source file debug_malloc.c should be included with your sources.
*
* The object file debug_malloc.o should be included with your object files.
*
* WARNING: Any memory allocattion from things like memalign(), valloc(),
* or any memory not coming from these macros (malloc, realloc,
* calloc, and strdup) will fail miserably.
*
* ***********************************************************************
*/
#ifndef _DEBUG_MALLOC_H
#define _DEBUG_MALLOC_H
#ifdef DEBUG
#include <stdlib.h>
#include <string.h>
/* Use THIS_FILE when it is available. */
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
/* The real functions behind the macro curtains. */
void *debug_malloc(size_t, const char *, int);
void *debug_realloc(void *, size_t, const char *, int);
void *debug_calloc(size_t, size_t, const char *, int);
char *debug_strdup(const char *, const char *, int);
void debug_free(void *, const char *, int);
#endif
void debug_malloc_verify(const char*, int);
#undef malloc_verify
#define malloc_verify() debug_malloc_verify(THIS_FILE, __LINE__)
void debug_malloc_police(const char*, int);
#undef malloc_police
#define malloc_police() debug_malloc_police(THIS_FILE, __LINE__)
#endif

View File

@ -1,401 +0,0 @@
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Primary hprof #include file, should be included by most if not
* all hprof source files. Gives access to the global data structure
* and all global macros, and everything declared in the #include
* files of each of the source files.
*/
#ifndef HPROF_H
#define HPROF_H
/* Standard C functions used throughout. */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stddef.h>
#include <stdarg.h>
#include <limits.h>
#include <time.h>
#include <errno.h>
/* General JVM/Java functions, types and macros. */
#include <sys/types.h>
#include "jni.h"
#include "jvmti.h"
#include "classfile_constants.h"
#include "jvm_md.h"
/* Macros to extract the upper and lower 32 bits of a jlong */
#define jlong_high(a) ((jint)((a)>>32))
#define jlong_low(a) ((jint)(a))
#define jlong_to_jint(a) ((jint)(a))
#define jint_to_jlong(a) ((jlong)(a))
#define jlong_add(a, b) ((a) + (b))
/* The type used to contain a generic 32bit "serial number". */
typedef unsigned SerialNumber;
/* How the options get to OnLoad: */
#define AGENTNAME "hprof"
#define XRUN "-Xrun" AGENTNAME
#define AGENTLIB "-agentlib:" AGENTNAME
/* Name of prelude file, found at runtime relative to java binary location */
#define PRELUDE_FILE "jvm.hprof.txt"
/* File I/O buffer size to be used with any file i/o operation */
#define FILE_IO_BUFFER_SIZE (1024*64)
/* Machine dependent functions. */
#include "hprof_md.h"
/* Table index types */
typedef unsigned TableIndex;
typedef TableIndex ClassIndex;
typedef TableIndex FrameIndex;
typedef TableIndex IoNameIndex;
typedef TableIndex MonitorIndex;
typedef TableIndex ObjectIndex;
typedef TableIndex LoaderIndex;
typedef TableIndex RefIndex;
typedef TableIndex SiteIndex;
typedef TableIndex StringIndex;
typedef TableIndex TlsIndex;
typedef TableIndex TraceIndex;
/* Index for method tables in classes */
typedef int MethodIndex;
/* The different kinds of class status bits. */
enum ClassStatus {
CLASS_PREPARED = 0x00000001,
CLASS_LOADED = 0x00000002,
CLASS_UNLOADED = 0x00000004,
CLASS_SPECIAL = 0x00000008,
CLASS_IN_LOAD_LIST = 0x00000010,
CLASS_SYSTEM = 0x00000020,
CLASS_DUMPED = 0x00000040
};
typedef jint ClassStatus;
/* The different kind of objects we track with heap=dump */
typedef unsigned char ObjectKind;
enum {
OBJECT_NORMAL = 1,
OBJECT_CLASS = 2,
OBJECT_SYSTEM = 3,
OBJECT_HPROF = 4,
OBJECT_LOADER = 5
};
/* Used by site_write() when writing out the heap=sites data. */
enum {
SITE_DUMP_INCREMENTAL = 0x01,
SITE_SORT_BY_ALLOC = 0x02,
SITE_FORCE_GC = 0x04
};
/* Used to hold information about a field, and potentially a value too. */
typedef struct FieldInfo {
ClassIndex cnum;
StringIndex name_index;
StringIndex sig_index;
unsigned short modifiers;
unsigned char primType;
unsigned char primSize;
} FieldInfo;
/* Used to hold information about a constant pool entry value for a class. */
typedef struct ConstantPoolValue {
unsigned constant_pool_index;
StringIndex sig_index;
jvalue value;
} ConstantPoolValue;
/* All machine independent functions */
#include "hprof_error.h"
#include "hprof_util.h"
#include "hprof_blocks.h"
#include "hprof_stack.h"
#include "hprof_init.h"
#include "hprof_table.h"
#include "hprof_string.h"
#include "hprof_class.h"
#include "hprof_tracker.h"
#include "hprof_frame.h"
#include "hprof_monitor.h"
#include "hprof_trace.h"
#include "hprof_site.h"
#include "hprof_event.h"
#include "hprof_reference.h"
#include "hprof_object.h"
#include "hprof_loader.h"
#include "hprof_tls.h"
#include "hprof_check.h"
#include "hprof_io.h"
#include "hprof_listener.h"
#include "hprof_cpu.h"
#include "hprof_tag.h"
/* Global data structure */
struct LineTable;
typedef struct {
jvmtiEnv *jvmti; /* JVMTI env for this session */
JavaVM *jvm; /* JavaVM* for this session */
jint cachedJvmtiVersion; /* JVMTI version number */
char *header; /* "JAVA PROFILE 1.0.[12]" */
jboolean segmented; /* JNI_TRUE if 1.0.2 */
jlong maxHeapSegment;
jlong maxMemory;
/* Option settings */
char * options; /* option string copy */
char * utf8_output_filename;/* file=filename */
int net_port; /* net=hostname:port */
char * net_hostname; /* net=hostname:port */
char output_format; /* format=a|b */
int max_trace_depth; /* depth=max_trace_depth */
int prof_trace_depth; /* max_trace_depth or 2 (old) */
int sample_interval; /* interval=sample_interval (ms) */
double cutoff_point; /* cutoff=cutoff_point */
jboolean cpu_sampling; /* cpu=samples|y */
jboolean cpu_timing; /* cpu=times */
jboolean old_timing_format; /* cpu=old (old) output format */
jboolean heap_dump; /* heap=dump|all */
jboolean alloc_sites; /* heap=sites|all */
jboolean thread_in_traces; /* thread=y|n */
jboolean lineno_in_traces; /* lineno=y|n */
jboolean dump_on_exit; /* doe=y|n */
jboolean micro_state_accounting; /* msa=y|n */
jboolean force_output; /* force=y|n */
jboolean monitor_tracing; /* monitor=y|n */
jboolean gc_okay; /* gc_okay=y|n (Not used) */
unsigned logflags; /* logflags=bitmask */
#define DEBUGFLAG_UNPREPARED_CLASSES 0x001
unsigned debugflags; /* debugflags=bitmask */
jboolean coredump; /* coredump=y|n */
jboolean errorexit; /* errorexit=y|n */
jboolean pause; /* pause=y|n */
jboolean debug; /* debug=y|n */
jboolean verbose; /* verbose=y|n */
jboolean primfields; /* primfields=y|n */
jboolean primarrays; /* primarrays=y|n */
jint experiment; /* X=NUMBER */
int fd; /* file or socket (net=addr). */
jboolean socket; /* True if fd is a socket (net=addr). */
jboolean bci; /* True if any kind of BCI being done */
jboolean obj_watch; /* True if bci and watching allocs */
int bci_counter; /* Class BCI counter */
int heap_fd;
char *output_filename; /* file=filename */
char *heapfilename;
int check_fd;
char *checkfilename;
volatile jboolean dump_in_process; /* Dump in process */
volatile jboolean jvm_initializing; /* VMInit happening */
volatile jboolean jvm_initialized; /* VMInit happened */
volatile jboolean jvm_shut_down; /* VMDeath happened */
jboolean vm_death_callback_active; /* VMDeath happening */
/* Stack of objects freed during GC */
Stack * object_free_stack;
jrawMonitorID object_free_lock;
/* Lock for debug_malloc() */
jrawMonitorID debug_malloc_lock;
/* Count of classes that JVMTI thinks are active */
jint class_count;
/* Used to track callbacks for VM_DEATH */
jrawMonitorID callbackBlock;
jrawMonitorID callbackLock;
jint active_callbacks;
/* Running totals on all bytes allocated */
jlong total_alloced_bytes;
jlong total_alloced_instances;
jint total_live_bytes;
jint total_live_instances;
/* Running total on all time spent in GC (very rough estimate) */
jlong gc_start_time;
jlong time_in_gc;
/* Global Data access Lock */
jrawMonitorID data_access_lock;
/* Global Dump lock */
jrawMonitorID dump_lock;
/* Milli-second clock when hprof onload started */
jlong micro_sec_ticks;
/* Thread class (for starting agent threads) */
ClassIndex thread_cnum;
/* Agent threads started information */
jboolean listener_loop_running;
jrawMonitorID listener_loop_lock;
jboolean cpu_loop_running;
jrawMonitorID cpu_loop_lock;
jrawMonitorID cpu_sample_lock; /* cpu=samples loop */
jint gc_finish; /* Count of GC finish events */
jboolean gc_finish_active; /* True if thread active */
jboolean gc_finish_stop_request; /* True if we want it to stop */
jrawMonitorID gc_finish_lock;
jboolean pause_cpu_sampling; /* temp pause in cpu sampling */
/* Output buffer, position, size, and position in dump if reading */
char * write_buffer;
int write_buffer_index;
int write_buffer_size;
char * heap_buffer;
int heap_buffer_index;
int heap_buffer_size;
jlong heap_last_tag_position;
jlong heap_write_count;
char * check_buffer;
int check_buffer_index;
int check_buffer_size;
/* Serial number counters for tables (see hprof_table.c), classes,
* tls (thread local storage), and traces.
*/
SerialNumber table_serial_number_start;
SerialNumber class_serial_number_start;
SerialNumber thread_serial_number_start;
SerialNumber trace_serial_number_start;
SerialNumber object_serial_number_start;
SerialNumber frame_serial_number_start;
SerialNumber gref_serial_number_start;
SerialNumber table_serial_number_counter;
SerialNumber class_serial_number_counter;
SerialNumber thread_serial_number_counter;
SerialNumber trace_serial_number_counter;
SerialNumber object_serial_number_counter;
SerialNumber frame_serial_number_counter;
SerialNumber gref_serial_number_counter;
/* The methodID for the Object <init> method. */
jmethodID object_init_method;
/* Keeping track of the tracker class and it's methods */
volatile jint tracking_engaged; /* !=0 means it's on */
ClassIndex tracker_cnum;
int tracker_method_count;
struct {
StringIndex name; /* String index for name */
StringIndex sig; /* String index for signature */
jmethodID method; /* Method ID */
} tracker_methods[12]; /* MAX 12 Tracker class methods */
/* Index to some common items */
LoaderIndex system_loader;
SerialNumber unknown_thread_serial_num;
TraceIndex system_trace_index;
SiteIndex system_object_site_index;
jint system_class_size;
TraceIndex hprof_trace_index;
SiteIndex hprof_site_index;
/* Tables for strings, classes, sites, etc. */
struct LookupTable * string_table;
struct LookupTable * ioname_table;
struct LookupTable * class_table;
struct LookupTable * site_table;
struct LookupTable * object_table;
struct LookupTable * reference_table;
struct LookupTable * frame_table;
struct LookupTable * trace_table;
struct LookupTable * monitor_table;
struct LookupTable * tls_table;
struct LookupTable * loader_table;
/* Handles to java_crw_demo library */
void * java_crw_demo_library;
void * java_crw_demo_function;
void * java_crw_demo_classname_function;
/* Indication that the agent has been loaded */
jboolean isLoaded;
} GlobalData;
/* This should be the only 'extern' in the library (not exported). */
extern GlobalData * gdata;
#endif

View File

@ -1,371 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HPROF_B_SPEC_H
#define HPROF_B_SPEC_H
/* Hprof binary format enums and spec. */
/* Need to #define or typedef HprofId before including this file.
* hprof used ObjectIndex or 4 bytes, but it can be 4 or 8 byte type.
*/
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/*
* hprof binary format: (result either written to a file or sent over
* the network).
*
* WARNING: This format is still under development, and is subject to
* change without notice.
*
* header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" (0-terminated)
* u4 size of identifiers. Identifiers are used to represent
* UTF8 strings, objects, stack traces, etc. They usually
* have the same size as host pointers. For example, on
* Solaris and Win32, the size is 4.
* u4 high word
* u4 low word number of milliseconds since 0:00 GMT, 1/1/70
* [record]* a sequence of records.
*/
/*
* Record format:
*
* u1 a TAG denoting the type of the record
* u4 number of *microseconds* since the time stamp in the
* header. (wraps around in a little more than an hour)
* u4 number of bytes *remaining* in the record. Note that
* this number excludes the tag and the length field itself.
* [u1]* BODY of the record (a sequence of bytes)
*/
/*
* The following TAGs are supported:
*
* TAG BODY notes
*----------------------------------------------------------
* HPROF_UTF8 a UTF8-encoded name
*
* id name ID
* [u1]* UTF8 characters (no trailing zero)
*
* HPROF_LOAD_CLASS a newly loaded class
*
* u4 class serial number (> 0)
* id class object ID
* u4 stack trace serial number
* id class name ID
*
* HPROF_UNLOAD_CLASS an unloading class
*
* u4 class serial_number
*
* HPROF_FRAME a Java stack frame
*
* id stack frame ID
* id method name ID
* id method signature ID
* id source file name ID
* u4 class serial number
* i4 line number. >0: normal
* -1: unknown
* -2: compiled method
* -3: native method
*
* HPROF_TRACE a Java stack trace
*
* u4 stack trace serial number
* u4 thread serial number
* u4 number of frames
* [id]* stack frame IDs
*
*
* HPROF_ALLOC_SITES a set of heap allocation sites, obtained after GC
*
* u2 flags 0x0001: incremental vs. complete
* 0x0002: sorted by allocation vs. live
* 0x0004: whether to force a GC
* u4 cutoff ratio
* u4 total live bytes
* u4 total live instances
* u8 total bytes allocated
* u8 total instances allocated
* u4 number of sites that follow
* [u1 is_array: 0: normal object
* 2: object array
* 4: boolean array
* 5: char array
* 6: float array
* 7: double array
* 8: byte array
* 9: short array
* 10: int array
* 11: long array
* u4 class serial number (may be zero during startup)
* u4 stack trace serial number
* u4 number of bytes alive
* u4 number of instances alive
* u4 number of bytes allocated
* u4]* number of instance allocated
*
* HPROF_START_THREAD a newly started thread.
*
* u4 thread serial number (> 0)
* id thread object ID
* u4 stack trace serial number
* id thread name ID
* id thread group name ID
* id thread group parent name ID
*
* HPROF_END_THREAD a terminating thread.
*
* u4 thread serial number
*
* HPROF_HEAP_SUMMARY heap summary
*
* u4 total live bytes
* u4 total live instances
* u8 total bytes allocated
* u8 total instances allocated
*
* HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT denote a heap dump
*
* [heap dump sub-records]*
*
* There are four kinds of heap dump sub-records:
*
* u1 sub-record type
*
* HPROF_GC_ROOT_UNKNOWN unknown root
*
* id object ID
*
* HPROF_GC_ROOT_THREAD_OBJ thread object
*
* id thread object ID (may be 0 for a
* thread newly attached through JNI)
* u4 thread sequence number
* u4 stack trace sequence number
*
* HPROF_GC_ROOT_JNI_GLOBAL JNI global ref root
*
* id object ID
* id JNI global ref ID
*
* HPROF_GC_ROOT_JNI_LOCAL JNI local ref
*
* id object ID
* u4 thread serial number
* u4 frame # in stack trace (-1 for empty)
*
* HPROF_GC_ROOT_JAVA_FRAME Java stack frame
*
* id object ID
* u4 thread serial number
* u4 frame # in stack trace (-1 for empty)
*
* HPROF_GC_ROOT_NATIVE_STACK Native stack
*
* id object ID
* u4 thread serial number
*
* HPROF_GC_ROOT_STICKY_CLASS System class
*
* id object ID
*
* HPROF_GC_ROOT_THREAD_BLOCK Reference from thread block
*
* id object ID
* u4 thread serial number
*
* HPROF_GC_ROOT_MONITOR_USED Busy monitor
*
* id object ID
*
* HPROF_GC_CLASS_DUMP dump of a class object
*
* id class object ID
* u4 stack trace serial number
* id super class object ID
* id class loader object ID
* id signers object ID
* id protection domain object ID
* id reserved
* id reserved
*
* u4 instance size (in bytes)
*
* u2 size of constant pool
* [u2, constant pool index,
* ty, type
* 2: object
* 4: boolean
* 5: char
* 6: float
* 7: double
* 8: byte
* 9: short
* 10: int
* 11: long
* vl]* and value
*
* u2 number of static fields
* [id, static field name,
* ty, type,
* vl]* and value
*
* u2 number of inst. fields (not inc. super)
* [id, instance field name,
* ty]* type
*
* HPROF_GC_INSTANCE_DUMP dump of a normal object
*
* id object ID
* u4 stack trace serial number
* id class object ID
* u4 number of bytes that follow
* [vl]* instance field values (class, followed
* by super, super's super ...)
*
* HPROF_GC_OBJ_ARRAY_DUMP dump of an object array
*
* id array object ID
* u4 stack trace serial number
* u4 number of elements
* id array class ID
* [id]* elements
*
* HPROF_GC_PRIM_ARRAY_DUMP dump of a primitive array
*
* id array object ID
* u4 stack trace serial number
* u4 number of elements
* u1 element type
* 4: boolean array
* 5: char array
* 6: float array
* 7: double array
* 8: byte array
* 9: short array
* 10: int array
* 11: long array
* [u1]* elements
*
* HPROF_HEAP_DUMP_END terminates series of heap dump segments
*
* HPROF_CPU_SAMPLES a set of sample traces of running threads
*
* u4 total number of samples
* u4 # of traces
* [u4 # of samples
* u4]* stack trace serial number
*
* HPROF_CONTROL_SETTINGS the settings of on/off switches
*
* u4 0x00000001: alloc traces on/off
* 0x00000002: cpu sampling on/off
* u2 stack trace depth
*
*/
typedef enum HprofTag {
HPROF_UTF8 = 0x01,
HPROF_LOAD_CLASS = 0x02,
HPROF_UNLOAD_CLASS = 0x03,
HPROF_FRAME = 0x04,
HPROF_TRACE = 0x05,
HPROF_ALLOC_SITES = 0x06,
HPROF_HEAP_SUMMARY = 0x07,
HPROF_START_THREAD = 0x0A,
HPROF_END_THREAD = 0x0B,
HPROF_HEAP_DUMP = 0x0C,
HPROF_HEAP_DUMP_SEGMENT = 0x1C, /* 1.0.2 only */
HPROF_HEAP_DUMP_END = 0x2C, /* 1.0.2 only */
HPROF_CPU_SAMPLES = 0x0D,
HPROF_CONTROL_SETTINGS = 0x0E
} HprofTag;
/*
* Heap dump constants
*/
typedef enum HprofGcTag {
HPROF_GC_ROOT_UNKNOWN = 0xFF,
HPROF_GC_ROOT_JNI_GLOBAL = 0x01,
HPROF_GC_ROOT_JNI_LOCAL = 0x02,
HPROF_GC_ROOT_JAVA_FRAME = 0x03,
HPROF_GC_ROOT_NATIVE_STACK = 0x04,
HPROF_GC_ROOT_STICKY_CLASS = 0x05,
HPROF_GC_ROOT_THREAD_BLOCK = 0x06,
HPROF_GC_ROOT_MONITOR_USED = 0x07,
HPROF_GC_ROOT_THREAD_OBJ = 0x08,
HPROF_GC_CLASS_DUMP = 0x20,
HPROF_GC_INSTANCE_DUMP = 0x21,
HPROF_GC_OBJ_ARRAY_DUMP = 0x22,
HPROF_GC_PRIM_ARRAY_DUMP = 0x23
} HprofGcTag;
enum HprofType {
HPROF_ARRAY_OBJECT = 1,
HPROF_NORMAL_OBJECT = 2,
HPROF_BOOLEAN = 4,
HPROF_CHAR = 5,
HPROF_FLOAT = 6,
HPROF_DOUBLE = 7,
HPROF_BYTE = 8,
HPROF_SHORT = 9,
HPROF_INT = 10,
HPROF_LONG = 11
};
typedef unsigned char HprofType;
#define HPROF_TYPE_SIZES \
{ \
/*Object?*/ sizeof(HprofId), \
/*Object?*/ sizeof(HprofId), \
/*Array*/ sizeof(HprofId), \
/*Object?*/ sizeof(HprofId), \
/*jboolean*/ 1, \
/*jchar*/ 2, \
/*jfloat*/ 4, \
/*jdouble*/ 8, \
/*jbyte*/ 1, \
/*jshort*/ 2, \
/*jint*/ 4, \
/*jlong*/ 8 \
}
#define HPROF_TYPE_IS_PRIMITIVE(ty) ((ty)>=HPROF_BOOLEAN)
#endif

View File

@ -1,163 +0,0 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Allocations from large blocks, no individual free's */
#include "hprof.h"
/*
* This file contains some allocation code that allows you
* to have space allocated via larger blocks of space.
* The only free allowed is of all the blocks and all the elements.
* Elements can be of different alignments and fixed or variable sized.
* The space allocated never moves.
*
*/
/* Get the real size allocated based on alignment and bytes needed */
static int
real_size(int alignment, int nbytes)
{
if ( alignment > 1 ) {
int wasted;
wasted = alignment - ( nbytes % alignment );
if ( wasted != alignment ) {
nbytes += wasted;
}
}
return nbytes;
}
/* Add a new current_block to the Blocks* chain, adjust size if nbytes big. */
static void
add_block(Blocks *blocks, int nbytes)
{
int header_size;
int block_size;
BlockHeader *block_header;
HPROF_ASSERT(blocks!=NULL);
HPROF_ASSERT(nbytes>0);
header_size = real_size(blocks->alignment, sizeof(BlockHeader));
block_size = blocks->elem_size*blocks->population;
if ( nbytes > block_size ) {
block_size = real_size(blocks->alignment, nbytes);
}
block_header = (BlockHeader*)HPROF_MALLOC(block_size+header_size);
block_header->next = NULL;
block_header->bytes_left = block_size;
block_header->next_pos = header_size;
/* Link in new block */
if ( blocks->current_block != NULL ) {
blocks->current_block->next = block_header;
}
blocks->current_block = block_header;
if ( blocks->first_block == NULL ) {
blocks->first_block = block_header;
}
}
/* Initialize a new Blocks */
Blocks *
blocks_init(int alignment, int elem_size, int population)
{
Blocks *blocks;
HPROF_ASSERT(alignment>0);
HPROF_ASSERT(elem_size>0);
HPROF_ASSERT(population>0);
blocks = (Blocks*)HPROF_MALLOC(sizeof(Blocks));
blocks->alignment = alignment;
blocks->elem_size = elem_size;
blocks->population = population;
blocks->first_block = NULL;
blocks->current_block = NULL;
return blocks;
}
/* Allocate bytes from a Blocks area. */
void *
blocks_alloc(Blocks *blocks, int nbytes)
{
BlockHeader *block;
int pos;
void *ptr;
HPROF_ASSERT(blocks!=NULL);
HPROF_ASSERT(nbytes>=0);
if ( nbytes == 0 ) {
return NULL;
}
block = blocks->current_block;
nbytes = real_size(blocks->alignment, nbytes);
if ( block == NULL || block->bytes_left < nbytes ) {
add_block(blocks, nbytes);
block = blocks->current_block;
}
pos = block->next_pos;
ptr = (void*)(((char*)block)+pos);
block->next_pos += nbytes;
block->bytes_left -= nbytes;
return ptr;
}
/* Terminate the Blocks */
void
blocks_term(Blocks *blocks)
{
BlockHeader *block;
HPROF_ASSERT(blocks!=NULL);
block = blocks->first_block;
while ( block != NULL ) {
BlockHeader *next_block;
next_block = block->next;
HPROF_FREE(block);
block = next_block;
}
HPROF_FREE(blocks);
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_BLOCKS_H
#define HPROF_BLOCKS_H
typedef struct BlockHeader {
struct BlockHeader *next;
int bytes_left;
int next_pos;
} BlockHeader;
typedef struct Blocks {
BlockHeader *first_block; /* Pointer to first BlockHeader */
BlockHeader *current_block; /* Pointer to current BlockHeader */
int alignment; /* Data alignment, 1, 2, 4, 8, 16 */
int elem_size; /* Size in bytes, ==1 means variable sizes */
int population; /* Number of elements to allow for per Block */
} Blocks;
Blocks * blocks_init(int alignment, int elem_size, int population);
void * blocks_alloc(Blocks *blocks, int nbytes);
void blocks_term(Blocks *blocks);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_CHECK_H
#define HPROF_CHECK_H
#define CHECK_FOR_ERROR(condition) \
( (condition) ? \
(void)0 : \
HPROF_ERROR(JNI_TRUE, #condition) )
#define CHECK_SERIAL_NO(name, sno) \
CHECK_FOR_ERROR( (sno) >= gdata->name##_serial_number_start && \
(sno) < gdata->name##_serial_number_counter)
#define CHECK_CLASS_SERIAL_NO(sno) CHECK_SERIAL_NO(class,sno)
#define CHECK_THREAD_SERIAL_NO(sno) CHECK_SERIAL_NO(thread,sno)
#define CHECK_TRACE_SERIAL_NO(sno) CHECK_SERIAL_NO(trace,sno)
#define CHECK_OBJECT_SERIAL_NO(sno) CHECK_SERIAL_NO(object,sno)
void check_binary_file(char *filename);
#endif

View File

@ -1,686 +0,0 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Table of class information.
*
* Each element in this table is identified with a ClassIndex.
* Each element is uniquely identified by it's signature and loader.
* Every class load has a unique class serial number.
* While loaded, each element will have a cache of a global reference
* to it's jclass object, plus jmethodID's as needed.
* Method signatures and names are obtained via BCI.
* Methods can be identified with a ClassIndex and MethodIndex pair,
* where the MethodIndex matches the index of the method name and
* signature arrays obtained from the BCI pass.
* Strings are stored in the string table and a StringIndex is used.
* Class Loaders are stored in the loader table and a LoaderIndex is used.
* Since the jclass object is an object, at some point an object table
* entry may be allocated for the jclass as an ObjectIndex.
*/
#include "hprof.h"
/* Effectively represents a jclass object. */
/* These table elements are made unique by and sorted by signature name. */
typedef struct ClassKey {
StringIndex sig_string_index; /* Signature of class */
LoaderIndex loader_index; /* Index for class loader */
} ClassKey;
/* Each class could contain method information, gotten from BCI callback */
typedef struct MethodInfo {
StringIndex name_index; /* Method name, index into string table */
StringIndex sig_index; /* Method signature, index into string table */
jmethodID method_id; /* Method ID, possibly NULL at first */
} MethodInfo;
/* The basic class information we save */
typedef struct ClassInfo {
jclass classref; /* Global ref to jclass */
MethodInfo *method; /* Array of method data */
int method_count; /* Count of methods */
ObjectIndex object_index; /* Optional object index for jclass */
SerialNumber serial_num; /* Unique to the actual class load */
ClassStatus status; /* Current class status (bit mask) */
ClassIndex super; /* Super class in this table */
StringIndex name; /* Name of class */
jint inst_size; /* #bytes needed for instance fields */
jint field_count; /* Number of all fields */
FieldInfo *field; /* Pointer to all FieldInfo's */
} ClassInfo;
/* Private interfaces */
static ClassKey*
get_pkey(ClassIndex index)
{
void *key_ptr;
int key_len;
table_get_key(gdata->class_table, index, (void*)&key_ptr, &key_len);
HPROF_ASSERT(key_len==sizeof(ClassKey));
HPROF_ASSERT(key_ptr!=NULL);
return (ClassKey*)key_ptr;
}
static void
fillin_pkey(const char *sig, LoaderIndex loader_index, ClassKey *pkey)
{
static ClassKey empty_key;
HPROF_ASSERT(loader_index!=0);
*pkey = empty_key;
pkey->sig_string_index = string_find_or_create(sig);
pkey->loader_index = loader_index;
}
static ClassInfo *
get_info(ClassIndex index)
{
ClassInfo *info;
info = (ClassInfo*)table_get_info(gdata->class_table, index);
return info;
}
static void
fill_info(TableIndex index, ClassKey *pkey)
{
ClassInfo *info;
char *sig;
info = get_info(index);
info->serial_num = gdata->class_serial_number_counter++;
info->method_count = 0;
info->inst_size = -1;
info->field_count = -1;
info->field = NULL;
sig = string_get(pkey->sig_string_index);
if ( sig[0] != JVM_SIGNATURE_CLASS ) {
info->name = pkey->sig_string_index;
} else {
int len;
len = string_get_len(pkey->sig_string_index);
if ( len > 2 ) {
char *name;
/* Class signature looks like "Lname;", we want "name" here. */
name = HPROF_MALLOC(len-1);
(void)memcpy(name, sig+1, len-2);
name[len-2] = 0;
info->name = string_find_or_create(name);
HPROF_FREE(name);
} else {
/* This would be strange, a class signature not in "Lname;" form? */
info->name = pkey->sig_string_index;
}
}
}
static ClassIndex
find_entry(ClassKey *pkey)
{
ClassIndex index;
index = table_find_entry(gdata->class_table,
(void*)pkey, (int)sizeof(ClassKey));
return index;
}
static ClassIndex
create_entry(ClassKey *pkey)
{
ClassIndex index;
index = table_create_entry(gdata->class_table,
(void*)pkey, (int)sizeof(ClassKey), NULL);
fill_info(index, pkey);
return index;
}
static ClassIndex
find_or_create_entry(ClassKey *pkey)
{
ClassIndex index;
HPROF_ASSERT(pkey!=NULL);
HPROF_ASSERT(pkey->loader_index!=0);
index = find_entry(pkey);
if ( index == 0 ) {
index = create_entry(pkey);
}
return index;
}
static void
delete_classref(JNIEnv *env, ClassInfo *info, jclass klass)
{
jclass ref;
int i;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(info!=NULL);
for ( i = 0 ; i < info->method_count ; i++ ) {
info->method[i].method_id = NULL;
}
ref = info->classref;
if ( klass != NULL ) {
info->classref = newGlobalReference(env, klass);
} else {
info->classref = NULL;
}
if ( ref != NULL ) {
deleteGlobalReference(env, ref);
}
}
static void
cleanup_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
ClassInfo *info;
/* Cleanup any information in this ClassInfo structure. */
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(ClassKey));
HPROF_ASSERT(info_ptr!=NULL);
info = (ClassInfo *)info_ptr;
if ( info->method_count > 0 ) {
HPROF_FREE((void*)info->method);
info->method_count = 0;
info->method = NULL;
}
if ( info->field != NULL ) {
HPROF_FREE((void*)info->field);
info->field_count = 0;
info->field = NULL;
}
}
static void
delete_ref_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
delete_classref((JNIEnv*)arg, (ClassInfo*)info_ptr, NULL);
}
static void
list_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
ClassInfo *info;
ClassKey key;
char *sig;
int i;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(ClassKey));
HPROF_ASSERT(info_ptr!=NULL);
key = *((ClassKey*)key_ptr);
sig = string_get(key.sig_string_index);
info = (ClassInfo *)info_ptr;
debug_message(
"0x%08x: Class %s, SN=%u, status=0x%08x, ref=%p,"
" method_count=%d\n",
index,
(const char *)sig,
info->serial_num,
info->status,
(void*)info->classref,
info->method_count);
if ( info->method_count > 0 ) {
for ( i = 0 ; i < info->method_count ; i++ ) {
debug_message(
" Method %d: \"%s\", sig=\"%s\", method=%p\n",
i,
string_get(info->method[i].name_index),
string_get(info->method[i].sig_index),
(void*)info->method[i].method_id);
}
}
}
static void
all_status_remove(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
ClassInfo *info;
ClassStatus status;
HPROF_ASSERT(info_ptr!=NULL);
/*LINTED*/
status = (ClassStatus)(long)(ptrdiff_t)arg;
info = (ClassInfo *)info_ptr;
info->status &= (~status);
}
static void
unload_walker(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
ClassInfo *info;
HPROF_ASSERT(info_ptr!=NULL);
info = (ClassInfo *)info_ptr;
if ( ! ( info->status & CLASS_IN_LOAD_LIST ) ) {
if ( ! (info->status & (CLASS_SPECIAL|CLASS_SYSTEM|CLASS_UNLOADED)) ) {
io_write_class_unload(info->serial_num, info->object_index);
info->status |= CLASS_UNLOADED;
delete_classref((JNIEnv*)arg, info, NULL);
}
}
}
/* External interfaces */
void
class_init(void)
{
HPROF_ASSERT(gdata->class_table==NULL);
gdata->class_table = table_initialize("Class", 512, 512, 511,
(int)sizeof(ClassInfo));
}
ClassIndex
class_find_or_create(const char *sig, LoaderIndex loader_index)
{
ClassKey key;
fillin_pkey(sig, loader_index, &key);
return find_or_create_entry(&key);
}
ClassIndex
class_create(const char *sig, LoaderIndex loader_index)
{
ClassKey key;
fillin_pkey(sig, loader_index, &key);
return create_entry(&key);
}
void
class_prime_system_classes(void)
{
/* Prime System classes? Anything before VM_START is System class.
* Or classes loaded before env arg is non-NULL.
* Or any of the classes listed below.
*/
static const char * signatures[] =
{
"Ljava/lang/Object;",
"Ljava/io/Serializable;",
"Ljava/lang/String;",
"Ljava/lang/Class;",
"Ljava/lang/ClassLoader;",
"Ljava/lang/System;",
"Ljava/lang/Thread;",
"Ljava/lang/ThreadGroup;",
};
int n_signatures;
int i;
LoaderIndex loader_index;
n_signatures = (int)sizeof(signatures)/(int)sizeof(signatures[0]);
loader_index = loader_find_or_create(NULL, NULL);
for ( i = 0 ; i < n_signatures ; i++ ) {
ClassInfo *info;
ClassIndex index;
ClassKey key;
fillin_pkey(signatures[i], loader_index, &key);
index = find_or_create_entry(&key);
info = get_info(index);
info->status |= CLASS_SYSTEM;
}
}
void
class_add_status(ClassIndex index, ClassStatus status)
{
ClassInfo *info;
info = get_info(index);
info->status |= status;
}
ClassStatus
class_get_status(ClassIndex index)
{
ClassInfo *info;
info = get_info(index);
return info->status;
}
StringIndex
class_get_signature(ClassIndex index)
{
ClassKey *pkey;
pkey = get_pkey(index);
return pkey->sig_string_index;
}
SerialNumber
class_get_serial_number(ClassIndex index)
{
ClassInfo *info;
if ( index == 0 ) {
return 0;
}
info = get_info(index);
return info->serial_num;
}
void
class_all_status_remove(ClassStatus status)
{
table_walk_items(gdata->class_table, &all_status_remove,
(void*)(ptrdiff_t)(long)status);
}
void
class_do_unloads(JNIEnv *env)
{
table_walk_items(gdata->class_table, &unload_walker, (void*)env);
}
void
class_list(void)
{
debug_message(
"--------------------- Class Table ------------------------\n");
table_walk_items(gdata->class_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
class_cleanup(void)
{
table_cleanup(gdata->class_table, &cleanup_item, NULL);
gdata->class_table = NULL;
}
void
class_delete_global_references(JNIEnv* env)
{
table_walk_items(gdata->class_table, &delete_ref_item, (void*)env);
}
void
class_set_methods(ClassIndex index, const char **name, const char **sig,
int count)
{
ClassInfo *info;
int i;
info = get_info(index);
if ( info->method_count > 0 ) {
HPROF_FREE((void*)info->method);
info->method_count = 0;
info->method = NULL;
}
info->method_count = count;
if ( count > 0 ) {
info->method = (MethodInfo *)HPROF_MALLOC(count*(int)sizeof(MethodInfo));
for ( i = 0 ; i < count ; i++ ) {
info->method[i].name_index = string_find_or_create(name[i]);
info->method[i].sig_index = string_find_or_create(sig[i]);
info->method[i].method_id = NULL;
}
}
}
jclass
class_new_classref(JNIEnv *env, ClassIndex index, jclass classref)
{
ClassInfo *info;
HPROF_ASSERT(classref!=NULL);
info = get_info(index);
if ( ! isSameObject(env, classref, info->classref) ) {
delete_classref(env, info, classref);
}
return info->classref;
}
jclass
class_get_class(JNIEnv *env, ClassIndex index)
{
ClassInfo *info;
jclass clazz;
info = get_info(index);
clazz = info->classref;
if ( env != NULL && clazz == NULL ) {
WITH_LOCAL_REFS(env, 1) {
jclass new_clazz;
char *class_name;
class_name = string_get(info->name);
/* This really only makes sense for the bootclass classes,
* since FindClass doesn't provide a way to load a class in
* a specific class loader.
*/
new_clazz = findClass(env, class_name);
if ( new_clazz == NULL ) {
HPROF_ERROR(JNI_TRUE, "Cannot load class with findClass");
}
HPROF_ASSERT(new_clazz!=NULL);
clazz = class_new_classref(env, index, new_clazz);
} END_WITH_LOCAL_REFS;
HPROF_ASSERT(clazz!=NULL);
}
return clazz;
}
jmethodID
class_get_methodID(JNIEnv *env, ClassIndex index, MethodIndex mnum)
{
ClassInfo *info;
jmethodID method;
info = get_info(index);
if (mnum >= info->method_count) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, newExcCls, "Illegal mnum");
return NULL;
}
method = info->method[mnum].method_id;
if ( method == NULL ) {
char * name;
char * sig;
jclass clazz;
name = (char *)string_get(info->method[mnum].name_index);
if (name==NULL) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, newExcCls, "Name not found");
return NULL;
}
sig = (char *)string_get(info->method[mnum].sig_index);
HPROF_ASSERT(sig!=NULL);
clazz = class_get_class(env, index);
if ( clazz != NULL ) {
method = getMethodID(env, clazz, name, sig);
HPROF_ASSERT(method!=NULL);
info = get_info(index);
info->method[mnum].method_id = method;
}
}
return method;
}
void
class_set_inst_size(ClassIndex index, jint inst_size)
{
ClassInfo *info;
info = get_info(index);
info->inst_size = inst_size;
}
jint
class_get_inst_size(ClassIndex index)
{
ClassInfo *info;
info = get_info(index);
return info->inst_size;
}
void
class_set_object_index(ClassIndex index, ObjectIndex object_index)
{
ClassInfo *info;
info = get_info(index);
info->object_index = object_index;
}
ObjectIndex
class_get_object_index(ClassIndex index)
{
ClassInfo *info;
info = get_info(index);
return info->object_index;
}
ClassIndex
class_get_super(ClassIndex index)
{
ClassInfo *info;
info = get_info(index);
return info->super;
}
void
class_set_super(ClassIndex index, ClassIndex super)
{
ClassInfo *info;
info = get_info(index);
info->super = super;
}
LoaderIndex
class_get_loader(ClassIndex index)
{
ClassKey *pkey;
pkey = get_pkey(index);
HPROF_ASSERT(pkey->loader_index!=0);
return pkey->loader_index;
}
/* Get ALL class fields (supers too), return 1 on error, 0 if ok */
jint
class_get_all_fields(JNIEnv *env, ClassIndex index,
jint *pfield_count, FieldInfo **pfield)
{
ClassInfo *info;
FieldInfo *finfo;
jint count;
jint ret;
count = 0;
finfo = NULL;
ret = 1; /* Default is to return an error condition */
info = get_info(index);
if ( info != NULL ) {
if ( info->field_count >= 0 ) {
/* Get cache */
count = info->field_count;
finfo = info->field;
ret = 0; /* Return of cache data, no error */
} else {
jclass klass;
klass = info->classref;
if ( klass == NULL || isSameObject(env, klass, NULL) ) {
/* This is probably an error because this will cause the field
* index values to be off, but I'm hesitant to generate a
* fatal error here, so I will issue something and continue.
* I should have been holding a global reference to all the
* jclass, so I'm not sure how this could happen.
* Issuing a FindClass() here is just asking for trouble
* because if the class went away, we aren't even sure
* what ClassLoader to use.
*/
HPROF_ERROR(JNI_FALSE, "Missing jclass when fields needed");
} else {
jint status;
status = getClassStatus(klass);
if ( status &
(JVMTI_CLASS_STATUS_PRIMITIVE|JVMTI_CLASS_STATUS_ARRAY) ) {
/* Set cache */
info->field_count = count;
info->field = finfo;
ret = 0; /* Primitive or array ok */
} else if ( status & JVMTI_CLASS_STATUS_PREPARED ) {
/* Call JVMTI to get them */
getAllClassFieldInfo(env, klass, &count, &finfo);
/* Set cache */
info->field_count = count;
info->field = finfo;
ret = 0;
}
}
}
}
*pfield_count = count;
*pfield = finfo;
return ret;
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_CLASS_H
#define HPROF_CLASS_H
void class_init(void);
ClassIndex class_find_or_create(const char *sig, LoaderIndex loader);
ClassIndex class_create(const char *sig, LoaderIndex loader);
SerialNumber class_get_serial_number(ClassIndex index);
StringIndex class_get_signature(ClassIndex index);
ClassStatus class_get_status(ClassIndex index);
void class_add_status(ClassIndex index, ClassStatus status);
void class_all_status_remove(ClassStatus status);
void class_do_unloads(JNIEnv *env);
void class_list(void);
void class_delete_global_references(JNIEnv* env);
void class_cleanup(void);
void class_set_methods(ClassIndex index, const char**name,
const char**descr, int count);
jmethodID class_get_methodID(JNIEnv *env, ClassIndex index,
MethodIndex mnum);
jclass class_new_classref(JNIEnv *env, ClassIndex index,
jclass classref);
void class_delete_classref(JNIEnv *env, ClassIndex index);
jclass class_get_class(JNIEnv *env, ClassIndex index);
void class_set_inst_size(ClassIndex index, jint inst_size);
jint class_get_inst_size(ClassIndex index);
void class_set_object_index(ClassIndex index,
ObjectIndex object_index);
ObjectIndex class_get_object_index(ClassIndex index);
ClassIndex class_get_super(ClassIndex index);
void class_set_super(ClassIndex index, ClassIndex super);
void class_set_loader(ClassIndex index, LoaderIndex loader);
LoaderIndex class_get_loader(ClassIndex index);
void class_prime_system_classes(void);
jint class_get_all_fields(JNIEnv *env, ClassIndex cnum,
jint *pfield_count, FieldInfo **pfield);
#endif

View File

@ -1,238 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#include "hprof.h"
/* This file contains the cpu loop for the option cpu=samples */
/* The cpu_loop thread basically waits for gdata->sample_interval millisecs
* then wakes up, and for each running thread it gets their stack trace,
* and updates the traces with 'hits'.
*
* No threads are suspended or resumed, and the thread sampling is in the
* file hprof_tls.c, which manages all active threads. The sampling
* technique (what is sampled) is also in hprof_tls.c.
*
* No adjustments are made to the pause time or sample interval except
* by the user via the interval=n option (default is 10ms).
*
* This thread can cause havoc when started prematurely or not terminated
* properly, see cpu_sample_init() and cpu_term(), and their calls in hprof_init.c.
*
* The listener loop (hprof_listener.c) can dynamically turn on or off the
* sampling of all or selected threads.
*
*/
/* Private functions */
static void JNICALL
cpu_loop_function(jvmtiEnv *jvmti, JNIEnv *env, void *p)
{
int loop_trip_counter;
jboolean cpu_loop_running;
loop_trip_counter = 0;
rawMonitorEnter(gdata->cpu_loop_lock); {
gdata->cpu_loop_running = JNI_TRUE;
cpu_loop_running = gdata->cpu_loop_running;
/* Notify cpu_sample_init() that we have started */
rawMonitorNotifyAll(gdata->cpu_loop_lock);
} rawMonitorExit(gdata->cpu_loop_lock);
rawMonitorEnter(gdata->cpu_sample_lock); /* Only waits inside loop let go */
while ( cpu_loop_running ) {
++loop_trip_counter;
LOG3("cpu_loop()", "iteration", loop_trip_counter);
/* If a dump is in progress, we pause sampling. */
rawMonitorEnter(gdata->dump_lock); {
if (gdata->dump_in_process) {
gdata->pause_cpu_sampling = JNI_TRUE;
}
} rawMonitorExit(gdata->dump_lock);
/* Check to see if we need to pause sampling (listener_loop command) */
if (gdata->pause_cpu_sampling) {
/*
* Pause sampling for now. Reset sample controls if
* sampling is resumed again.
*/
rawMonitorWait(gdata->cpu_sample_lock, 0);
rawMonitorEnter(gdata->cpu_loop_lock); {
cpu_loop_running = gdata->cpu_loop_running;
} rawMonitorExit(gdata->cpu_loop_lock);
/* Continue the while loop, which will terminate if done. */
continue;
}
/* This is the normal short timed wait before getting a sample */
rawMonitorWait(gdata->cpu_sample_lock, (jlong)gdata->sample_interval);
/* Make sure we really want to continue */
rawMonitorEnter(gdata->cpu_loop_lock); {
cpu_loop_running = gdata->cpu_loop_running;
} rawMonitorExit(gdata->cpu_loop_lock);
/* Break out if we are done */
if ( !cpu_loop_running ) {
break;
}
/*
* If a dump request came in after we checked at the top of
* the while loop, then we catch that fact here. We
* don't want to perturb the data that is being dumped so
* we just ignore the data from this sampling loop.
*/
rawMonitorEnter(gdata->dump_lock); {
if (gdata->dump_in_process) {
gdata->pause_cpu_sampling = JNI_TRUE;
}
} rawMonitorExit(gdata->dump_lock);
/* Sample all the threads and update trace costs */
if ( !gdata->pause_cpu_sampling) {
tls_sample_all_threads(env);
}
/* Check to see if we need to finish */
rawMonitorEnter(gdata->cpu_loop_lock); {
cpu_loop_running = gdata->cpu_loop_running;
} rawMonitorExit(gdata->cpu_loop_lock);
}
rawMonitorExit(gdata->cpu_sample_lock);
rawMonitorEnter(gdata->cpu_loop_lock); {
/* Notify cpu_sample_term() that we are done. */
rawMonitorNotifyAll(gdata->cpu_loop_lock);
} rawMonitorExit(gdata->cpu_loop_lock);
LOG2("cpu_loop()", "clean termination");
}
/* External functions */
void
cpu_sample_init(JNIEnv *env)
{
gdata->cpu_sampling = JNI_TRUE;
/* Create the raw monitors needed */
gdata->cpu_loop_lock = createRawMonitor("HPROF cpu loop lock");
gdata->cpu_sample_lock = createRawMonitor("HPROF cpu sample lock");
rawMonitorEnter(gdata->cpu_loop_lock); {
createAgentThread(env, "HPROF cpu sampling thread",
&cpu_loop_function);
/* Wait for cpu_loop_function() to notify us it has started. */
rawMonitorWait(gdata->cpu_loop_lock, 0);
} rawMonitorExit(gdata->cpu_loop_lock);
}
void
cpu_sample_off(JNIEnv *env, ObjectIndex object_index)
{
jint count;
count = 1;
if (object_index != 0) {
tls_set_sample_status(object_index, 0);
count = tls_sum_sample_status();
}
if ( count == 0 ) {
gdata->pause_cpu_sampling = JNI_TRUE;
} else {
gdata->pause_cpu_sampling = JNI_FALSE;
}
}
void
cpu_sample_on(JNIEnv *env, ObjectIndex object_index)
{
if ( gdata->cpu_loop_lock == NULL ) {
cpu_sample_init(env);
}
if (object_index == 0) {
gdata->cpu_sampling = JNI_TRUE;
gdata->pause_cpu_sampling = JNI_FALSE;
} else {
jint count;
tls_set_sample_status(object_index, 1);
count = tls_sum_sample_status();
if ( count > 0 ) {
gdata->pause_cpu_sampling = JNI_FALSE;
}
}
/* Notify the CPU sampling thread that sampling is on */
rawMonitorEnter(gdata->cpu_sample_lock); {
rawMonitorNotifyAll(gdata->cpu_sample_lock);
} rawMonitorExit(gdata->cpu_sample_lock);
}
void
cpu_sample_term(JNIEnv *env)
{
gdata->pause_cpu_sampling = JNI_FALSE;
rawMonitorEnter(gdata->cpu_sample_lock); {
/* Notify the CPU sampling thread to get out of any sampling Wait */
rawMonitorNotifyAll(gdata->cpu_sample_lock);
} rawMonitorExit(gdata->cpu_sample_lock);
rawMonitorEnter(gdata->cpu_loop_lock); {
if ( gdata->cpu_loop_running ) {
gdata->cpu_loop_running = JNI_FALSE;
/* Wait for cpu_loop_function() thread to tell us it completed. */
rawMonitorWait(gdata->cpu_loop_lock, 0);
}
} rawMonitorExit(gdata->cpu_loop_lock);
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_CPU_H
#define HPROF_CPU_H
void cpu_sample_off(JNIEnv *env, ObjectIndex object_index);
void cpu_sample_on(JNIEnv *env, ObjectIndex object_index);
void cpu_sample_init(JNIEnv *env);
void cpu_sample_term(JNIEnv *env);
#endif

View File

@ -1,215 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#include "hprof.h"
/* The error handling logic. */
/*
* Most hprof error processing and error functions are kept here, along with
* termination functions and signal handling (used in debug version only).
*
*/
#include <signal.h>
static int p = 1; /* Used with pause=y|n option */
/* Private functions */
static void
error_message(const char * format, ...)
{
va_list ap;
va_start(ap, format);
(void)vfprintf(stderr, format, ap);
va_end(ap);
}
static void
error_abort(void)
{
/* Important to remove existing signal handler */
(void)signal(SIGABRT, NULL);
error_message("HPROF DUMPING CORE\n");
abort(); /* Sends SIGABRT signal, usually also caught by libjvm */
}
static void
signal_handler(int sig)
{
/* Caught a signal, most likely a SIGABRT */
error_message("HPROF SIGNAL %d TERMINATED PROCESS\n", sig);
error_abort();
}
static void
setup_signal_handler(int sig)
{
/* Only if debug version or debug=y */
if ( gdata->debug ) {
(void)signal(sig, (void(*)(int))(void*)&signal_handler);
}
}
static void
terminate_everything(jint exit_code)
{
if ( exit_code > 0 ) {
/* Could be a fatal error or assert error or a sanity error */
error_message("HPROF TERMINATED PROCESS\n");
if ( gdata->coredump || gdata->debug ) {
/* Core dump here by request */
error_abort();
}
}
/* Terminate the process */
error_exit_process(exit_code);
}
/* External functions */
void
error_setup(void)
{
setup_signal_handler(SIGABRT);
}
void
error_do_pause(void)
{
int pid = md_getpid();
int timeleft = 600; /* 10 minutes max */
int interval = 10; /* 10 second message check */
/*LINTED*/
error_message("\nHPROF pause for PID %d\n", (int)pid);
while ( p && timeleft > 0 ) {
md_sleep(interval); /* 'assign p=0' to stop pause loop */
timeleft -= interval;
}
if ( timeleft <= 0 ) {
error_message("\n HPROF pause got tired of waiting and gave up.\n");
}
}
void
error_exit_process(int exit_code)
{
exit(exit_code);
}
static const char *
source_basename(const char *file)
{
const char *p;
if ( file == NULL ) {
return "UnknownSourceFile";
}
p = strrchr(file, '/');
if ( p == NULL ) {
p = strrchr(file, '\\');
}
if ( p == NULL ) {
p = file;
} else {
p++; /* go past / */
}
return p;
}
void
error_assert(const char *condition, const char *file, int line)
{
error_message("ASSERTION FAILURE: %s [%s:%d]\n", condition,
source_basename(file), line);
error_abort();
}
void
error_handler(jboolean fatal, jvmtiError error,
const char *message, const char *file, int line)
{
char *error_name;
if ( message==NULL ) {
message = "";
}
if ( error != JVMTI_ERROR_NONE ) {
error_name = getErrorName(error);
if ( error_name == NULL ) {
error_name = "?";
}
error_message("HPROF ERROR: %s (JVMTI Error %s(%d)) [%s:%d]\n",
message, error_name, error,
source_basename(file), line);
} else {
error_message("HPROF ERROR: %s [%s:%d]\n", message,
source_basename(file), line);
}
if ( fatal || gdata->errorexit ) {
/* If it's fatal, or the user wants termination on any error, die */
terminate_everything(9);
}
}
void
debug_message(const char * format, ...)
{
va_list ap;
va_start(ap, format);
(void)vfprintf(stderr, format, ap);
va_end(ap);
}
void
verbose_message(const char * format, ...)
{
if ( gdata->verbose ) {
va_list ap;
va_start(ap, format);
(void)vfprintf(stderr, format, ap);
va_end(ap);
}
}

View File

@ -1,102 +0,0 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_ERROR_H
#define HPROF_ERROR_H
/* Use THIS_FILE when it is available. */
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
/* Macros over assert and error functions so we can capture the source loc. */
#define HPROF_BOOL(x) ((jboolean)((x)==0?JNI_FALSE:JNI_TRUE))
#define HPROF_ERROR(fatal,msg) \
error_handler(HPROF_BOOL(fatal), JVMTI_ERROR_NONE, msg, THIS_FILE, __LINE__)
#define HPROF_JVMTI_ERROR(error,msg) \
error_handler(HPROF_BOOL(error!=JVMTI_ERROR_NONE), \
error, msg, THIS_FILE, __LINE__)
#if defined(DEBUG) || !defined(NDEBUG)
#define HPROF_ASSERT(cond) \
(((int)(cond))?(void)0:error_assert(#cond, THIS_FILE, __LINE__))
#else
#define HPROF_ASSERT(cond)
#endif
#define LOG_DUMP_MISC 0x1 /* Misc. logging info */
#define LOG_DUMP_LISTS 0x2 /* Dump tables at vm init and death */
#define LOG_CHECK_BINARY 0x4 /* If format=b, verify binary format */
#ifdef HPROF_LOGGING
#define LOG_STDERR(args) \
{ \
if ( gdata != NULL && (gdata->logflags & LOG_DUMP_MISC) ) { \
(void)fprintf args ; \
} \
}
#else
#define LOG_STDERR(args)
#endif
#define LOG_FORMAT(format) "HPROF LOG: " format " [%s:%d]\n"
#define LOG1(str1) LOG_STDERR((stderr, LOG_FORMAT("%s"), \
str1, THIS_FILE, __LINE__ ))
#define LOG2(str1,str2) LOG_STDERR((stderr, LOG_FORMAT("%s %s"), \
str1, str2, THIS_FILE, __LINE__ ))
#define LOG3(str1,str2,num) LOG_STDERR((stderr, LOG_FORMAT("%s %s 0x%x"), \
str1, str2, num, THIS_FILE, __LINE__ ))
#define LOG(str) LOG1(str)
void error_handler(jboolean fatal, jvmtiError error,
const char *message, const char *file, int line);
void error_assert(const char *condition, const char *file, int line);
void error_exit_process(int exit_code);
void error_do_pause(void);
void error_setup(void);
void debug_message(const char * format, ...);
void verbose_message(const char * format, ...);
#endif

View File

@ -1,450 +0,0 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* This file contains all class, method and allocation event support functions,
* both JVMTI and BCI events.
* (See hprof_monitor.c for the monitor event handlers).
*/
#include "hprof.h"
/* Private internal functions. */
/* Return a TraceIndex for the given thread. */
static TraceIndex
get_current(TlsIndex tls_index, JNIEnv *env, jboolean skip_init)
{
TraceIndex trace_index;
trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, skip_init);
return trace_index;
}
/* Return a ClassIndex for the given jclass, loader supplied or looked up. */
static ClassIndex
find_cnum(JNIEnv *env, jclass klass, jobject loader)
{
LoaderIndex loader_index;
ClassIndex cnum;
char * signature;
HPROF_ASSERT(klass!=NULL);
/* Get the loader index */
loader_index = loader_find_or_create(env, loader);
/* Get the signature for this class */
getClassSignature(klass, &signature, NULL);
/* Find the ClassIndex for this class */
cnum = class_find_or_create(signature, loader_index);
/* Free the signature space */
jvmtiDeallocate(signature);
/* Make sure we save a global reference to this class in the table */
HPROF_ASSERT(cnum!=0);
(void)class_new_classref(env, cnum, klass);
return cnum;
}
/* Get the ClassIndex for the superClass of this jclass. */
static ClassIndex
get_super(JNIEnv *env, jclass klass)
{
ClassIndex super_cnum;
super_cnum = 0;
WITH_LOCAL_REFS(env, 1) {
jclass super_klass;
super_klass = getSuperclass(env, klass);
if ( super_klass != NULL ) {
super_cnum = find_cnum(env, super_klass,
getClassLoader(super_klass));
}
} END_WITH_LOCAL_REFS;
return super_cnum;
}
/* Record an allocation. Could be jobject, jclass, jarray or primitive type. */
static void
any_allocation(JNIEnv *env, SerialNumber thread_serial_num,
TraceIndex trace_index, jobject object)
{
SiteIndex site_index;
ClassIndex cnum;
jint size;
jclass klass;
/* NOTE: Normally the getObjectClass() and getClassLoader()
* would require a
* WITH_LOCAL_REFS(env, 1) {
* } END_WITH_LOCAL_REFS;
* but for performance reasons we skip it here.
*/
/* Get and tag the klass */
klass = getObjectClass(env, object);
cnum = find_cnum(env, klass, getClassLoader(klass));
site_index = site_find_or_create(cnum, trace_index);
tag_class(env, klass, cnum, thread_serial_num, site_index);
/* Tag the object */
size = (jint)getObjectSize(object);
tag_new_object(object, OBJECT_NORMAL, thread_serial_num, size, site_index);
}
/* Handle a java.lang.Object.<init> object allocation. */
void
event_object_init(JNIEnv *env, jthread thread, jobject object)
{
/* Called via BCI Tracker class */
/* Be very careful what is called here, watch out for recursion. */
jint *pstatus;
TraceIndex trace_index;
SerialNumber thread_serial_num;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(object!=NULL);
/* Prevent recursion into any BCI function for this thread (pstatus). */
if ( tls_get_tracker_status(env, thread, JNI_TRUE,
&pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) {
(*pstatus) = 1;
any_allocation(env, thread_serial_num, trace_index, object);
(*pstatus) = 0;
}
}
/* Handle any newarray opcode allocation. */
void
event_newarray(JNIEnv *env, jthread thread, jobject object)
{
/* Called via BCI Tracker class */
/* Be very careful what is called here, watch out for recursion. */
jint *pstatus;
TraceIndex trace_index;
SerialNumber thread_serial_num;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(object!=NULL);
/* Prevent recursion into any BCI function for this thread (pstatus). */
if ( tls_get_tracker_status(env, thread, JNI_FALSE,
&pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) {
(*pstatus) = 1;
any_allocation(env, thread_serial_num, trace_index, object);
(*pstatus) = 0;
}
}
/* Handle tracking of a method call. */
void
event_call(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum)
{
/* Called via BCI Tracker class */
/* Be very careful what is called here, watch out for recursion. */
TlsIndex tls_index;
jint *pstatus;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
if (cnum == 0 || cnum == gdata->tracker_cnum) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, newExcCls, "Illegal cnum.");
return;
}
/* Prevent recursion into any BCI function for this thread (pstatus). */
if ( tls_get_tracker_status(env, thread, JNI_FALSE,
&pstatus, &tls_index, NULL, NULL) == 0 ) {
jmethodID method;
(*pstatus) = 1;
method = class_get_methodID(env, cnum, mnum);
if (method != NULL) {
tls_push_method(tls_index, method);
}
(*pstatus) = 0;
}
}
/* Handle tracking of an exception catch */
void
event_exception_catch(JNIEnv *env, jthread thread, jmethodID method,
jlocation location, jobject exception)
{
/* Called via JVMTI_EVENT_EXCEPTION_CATCH callback */
/* Be very careful what is called here, watch out for recursion. */
TlsIndex tls_index;
jint *pstatus;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(method!=NULL);
/* Prevent recursion into any BCI function for this thread (pstatus). */
if ( tls_get_tracker_status(env, thread, JNI_FALSE,
&pstatus, &tls_index, NULL, NULL) == 0 ) {
(*pstatus) = 1;
tls_pop_exception_catch(tls_index, thread, method);
(*pstatus) = 0;
}
}
/* Handle tracking of a method return pop one (maybe more) methods. */
void
event_return(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum)
{
/* Called via BCI Tracker class */
/* Be very careful what is called here, watch out for recursion. */
TlsIndex tls_index;
jint *pstatus;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
if (cnum == 0 || cnum == gdata->tracker_cnum) {
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, newExcCls, "Illegal cnum.");
return;
}
/* Prevent recursion into any BCI function for this thread (pstatus). */
if ( tls_get_tracker_status(env, thread, JNI_FALSE,
&pstatus, &tls_index, NULL, NULL) == 0 ) {
jmethodID method;
(*pstatus) = 1;
method = class_get_methodID(env, cnum, mnum);
if (method != NULL) {
tls_pop_method(tls_index, thread, method);
}
(*pstatus) = 0;
}
}
/* Handle a class prepare (should have been already loaded) */
void
event_class_prepare(JNIEnv *env, jthread thread, jclass klass, jobject loader)
{
/* Called via JVMTI_EVENT_CLASS_PREPARE event */
ClassIndex cnum;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(klass!=NULL);
/* Find the ClassIndex for this class */
cnum = find_cnum(env, klass, loader);
class_add_status(cnum, CLASS_PREPARED);
}
/* Handle a class load (could have been already loaded) */
void
event_class_load(JNIEnv *env, jthread thread, jclass klass, jobject loader)
{
/* Called via JVMTI_EVENT_CLASS_LOAD event or reset_class_load_status() */
ClassIndex cnum;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(klass!=NULL);
/* Find the ClassIndex for this class */
cnum = find_cnum(env, klass, loader);
/* Always mark it as being in the load list */
class_add_status(cnum, CLASS_IN_LOAD_LIST);
/* If we are seeing this as a new loaded class, extra work */
if ( ! ( class_get_status(cnum) & CLASS_LOADED ) ) {
TraceIndex trace_index;
SiteIndex site_index;
ClassIndex super;
SerialNumber class_serial_num;
SerialNumber trace_serial_num;
SerialNumber thread_serial_num;
ObjectIndex class_object_index;
char *signature;
/* Get the TlsIndex and a TraceIndex for this location */
if ( thread == NULL ) {
/* This should be very rare, but if this class load was simulated
* from hprof_init.c due to a reset of the class load status,
* and it originated from a pre-VM_INIT event, the jthread
* would be NULL, or it was a jclass created that didn't get
* reported to us, like an array class or a primitive class?
*/
trace_index = gdata->system_trace_index;
thread_serial_num = gdata->unknown_thread_serial_num;
} else {
TlsIndex tls_index;
tls_index = tls_find_or_create(env, thread);
trace_index = get_current(tls_index, env, JNI_FALSE);
thread_serial_num = tls_get_thread_serial_number(tls_index);
}
/* Get the SiteIndex for this location and a java.lang.Class object */
/* Note that the target cnum, not the cnum for java.lang.Class. */
site_index = site_find_or_create(cnum, trace_index);
/* Tag this java.lang.Class object */
tag_class(env, klass, cnum, thread_serial_num, site_index);
class_add_status(cnum, CLASS_LOADED);
class_serial_num = class_get_serial_number(cnum);
class_object_index = class_get_object_index(cnum);
trace_serial_num = trace_get_serial_number(trace_index);
signature = string_get(class_get_signature(cnum));
rawMonitorEnter(gdata->data_access_lock); {
io_write_class_load(class_serial_num, class_object_index,
trace_serial_num, signature);
} rawMonitorExit(gdata->data_access_lock);
super = get_super(env, klass);
class_set_super(cnum, super);
}
}
/* Handle a thread start event */
void
event_thread_start(JNIEnv *env, jthread thread)
{
/* Called via JVMTI_EVENT_THREAD_START event */
TlsIndex tls_index;
ObjectIndex object_index;
TraceIndex trace_index;
jlong tag;
SerialNumber thread_serial_num;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
tls_index = tls_find_or_create(env, thread);
thread_serial_num = tls_get_thread_serial_number(tls_index);
trace_index = get_current(tls_index, env, JNI_FALSE);
tag = getTag(thread);
if ( tag == (jlong)0 ) {
SiteIndex site_index;
jint size;
size = (jint)getObjectSize(thread);
site_index = site_find_or_create(gdata->thread_cnum, trace_index);
/* We create a new object with this thread's serial number */
object_index = object_new(site_index, size, OBJECT_NORMAL,
thread_serial_num);
} else {
object_index = tag_extract(tag);
/* Normally the Thread object is created and tagged before we get
* here, but the thread_serial_number on this object isn't what
* we want. So we update it to the serial number of this thread.
*/
object_set_thread_serial_number(object_index, thread_serial_num);
}
tls_set_thread_object_index(tls_index, object_index);
WITH_LOCAL_REFS(env, 1) {
jvmtiThreadInfo threadInfo;
jvmtiThreadGroupInfo threadGroupInfo;
jvmtiThreadGroupInfo parentGroupInfo;
getThreadInfo(thread, &threadInfo);
getThreadGroupInfo(threadInfo.thread_group, &threadGroupInfo);
if ( threadGroupInfo.parent != NULL ) {
getThreadGroupInfo(threadGroupInfo.parent, &parentGroupInfo);
} else {
(void)memset(&parentGroupInfo, 0, sizeof(parentGroupInfo));
}
rawMonitorEnter(gdata->data_access_lock); {
io_write_thread_start(thread_serial_num,
object_index, trace_get_serial_number(trace_index),
threadInfo.name, threadGroupInfo.name, parentGroupInfo.name);
} rawMonitorExit(gdata->data_access_lock);
jvmtiDeallocate(threadInfo.name);
jvmtiDeallocate(threadGroupInfo.name);
jvmtiDeallocate(parentGroupInfo.name);
} END_WITH_LOCAL_REFS;
}
void
event_thread_end(JNIEnv *env, jthread thread)
{
/* Called via JVMTI_EVENT_THREAD_END event */
TlsIndex tls_index;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
tls_index = tls_find_or_create(env, thread);
rawMonitorEnter(gdata->data_access_lock); {
io_write_thread_end(tls_get_thread_serial_number(tls_index));
} rawMonitorExit(gdata->data_access_lock);
tls_thread_ended(env, tls_index);
setThreadLocalStorage(thread, (void*)NULL);
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_EVENT_H
#define HPROF_EVENT_H
/* From BCI: */
void event_object_init(JNIEnv *env, jthread thread, jobject obj);
void event_newarray(JNIEnv *env, jthread thread, jobject obj);
void event_call(JNIEnv *env, jthread thread,
ClassIndex cnum, MethodIndex mnum);
void event_return(JNIEnv *env, jthread thread,
ClassIndex cnum, MethodIndex mnum);
/* From JVMTI: */
void event_class_load(JNIEnv *env, jthread thread, jclass klass, jobject loader);
void event_class_prepare(JNIEnv *env, jthread thread, jclass klass, jobject loader);
void event_thread_start(JNIEnv *env_id, jthread thread);
void event_thread_end(JNIEnv *env_id, jthread thread);
void event_exception_catch(JNIEnv *env, jthread thread, jmethodID method,
jlocation location, jobject exception);
#endif

View File

@ -1,210 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* This file contains support for handling frames, or (method,location) pairs. */
#include "hprof.h"
/*
* Frames map 1-to-1 to (methodID,location) pairs.
* When no line number is known, -1 should be used.
*
* Frames are mostly used in traces (see hprof_trace.c) and will be marked
* with their status flag as they are written out to the hprof output file.
*
*/
enum LinenoState {
LINENUM_UNINITIALIZED = 0,
LINENUM_AVAILABLE = 1,
LINENUM_UNAVAILABLE = 2
};
typedef struct FrameKey {
jmethodID method;
jlocation location;
} FrameKey;
typedef struct FrameInfo {
unsigned short lineno;
unsigned char lineno_state; /* LinenoState */
unsigned char status;
SerialNumber serial_num;
} FrameInfo;
static FrameKey*
get_pkey(FrameIndex index)
{
void *key_ptr;
int key_len;
table_get_key(gdata->frame_table, index, &key_ptr, &key_len);
HPROF_ASSERT(key_len==sizeof(FrameKey));
HPROF_ASSERT(key_ptr!=NULL);
return (FrameKey*)key_ptr;
}
static FrameInfo *
get_info(FrameIndex index)
{
FrameInfo *info;
info = (FrameInfo*)table_get_info(gdata->frame_table, index);
return info;
}
static void
list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
FrameKey key;
FrameInfo *info;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(FrameKey));
HPROF_ASSERT(info_ptr!=NULL);
key = *((FrameKey*)key_ptr);
info = (FrameInfo*)info_ptr;
debug_message(
"Frame 0x%08x: method=%p, location=%d, lineno=%d(%d), status=%d \n",
i, (void*)key.method, (jint)key.location,
info->lineno, info->lineno_state, info->status);
}
void
frame_init(void)
{
gdata->frame_table = table_initialize("Frame",
1024, 1024, 1023, (int)sizeof(FrameInfo));
}
FrameIndex
frame_find_or_create(jmethodID method, jlocation location)
{
FrameIndex index;
static FrameKey empty_key;
FrameKey key;
jboolean new_one;
key = empty_key;
key.method = method;
key.location = location;
new_one = JNI_FALSE;
index = table_find_or_create_entry(gdata->frame_table,
&key, (int)sizeof(key), &new_one, NULL);
if ( new_one ) {
FrameInfo *info;
info = get_info(index);
info->lineno_state = LINENUM_UNINITIALIZED;
if ( location < 0 ) {
info->lineno_state = LINENUM_UNAVAILABLE;
}
info->serial_num = gdata->frame_serial_number_counter++;
}
return index;
}
void
frame_list(void)
{
debug_message(
"--------------------- Frame Table ------------------------\n");
table_walk_items(gdata->frame_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
frame_cleanup(void)
{
table_cleanup(gdata->frame_table, NULL, NULL);
gdata->frame_table = NULL;
}
void
frame_set_status(FrameIndex index, jint status)
{
FrameInfo *info;
info = get_info(index);
info->status = (unsigned char)status;
}
void
frame_get_location(FrameIndex index, SerialNumber *pserial_num,
jmethodID *pmethod, jlocation *plocation, jint *plineno)
{
FrameKey *pkey;
FrameInfo *info;
jint lineno;
pkey = get_pkey(index);
*pmethod = pkey->method;
*plocation = pkey->location;
info = get_info(index);
lineno = (jint)info->lineno;
if ( info->lineno_state == LINENUM_UNINITIALIZED ) {
info->lineno_state = LINENUM_UNAVAILABLE;
if ( gdata->lineno_in_traces ) {
if ( pkey->location >= 0 && !isMethodNative(pkey->method) ) {
lineno = getLineNumber(pkey->method, pkey->location);
if ( lineno >= 0 ) {
info->lineno = (unsigned short)lineno; /* save it */
info->lineno_state = LINENUM_AVAILABLE;
}
}
}
}
if ( info->lineno_state == LINENUM_UNAVAILABLE ) {
lineno = -1;
}
*plineno = lineno;
*pserial_num = info->serial_num;
}
jint
frame_get_status(FrameIndex index)
{
FrameInfo *info;
info = get_info(index);
return (jint)info->status;
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_FRAME_H
#define HPROF_FRAME_H
void frame_init(void);
FrameIndex frame_find_or_create(jmethodID method, jlocation location);
void frame_list(void);
void frame_cleanup(void);
void frame_get_location(FrameIndex frame_num, SerialNumber *serial_num,
jmethodID *pmethod,
jlocation *plocation, jint *plineno);
void frame_set_status(FrameIndex frame_num, jint status);
jint frame_get_status(FrameIndex frame_num);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_INIT_H
#define HPROF_INIT_H
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,169 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_IO_H
#define HPROF_IO_H
void io_flush(void);
void io_setup(void);
void io_cleanup(void);
void io_write_file_header(void);
void io_write_file_footer(void);
void io_write_class_load(SerialNumber class_serial_num, ObjectIndex index,
SerialNumber trace_serial_num, char *csig);
void io_write_class_unload(SerialNumber class_serial_num, ObjectIndex index);
void io_write_sites_header(const char * comment_str, jint flags,
double cutoff, jint total_live_bytes,
jint total_live_instances, jlong total_alloced_bytes,
jlong total_alloced_instances, jint count);
void io_write_sites_elem(jint index, double ratio, double accum_percent,
char *csig, SerialNumber class_serial_num,
SerialNumber trace_serial_num,
jint n_live_bytes, jint n_live_instances,
jint n_alloced_bytes, jint n_alloced_instances);
void io_write_sites_footer(void);
void io_write_thread_start(SerialNumber thread_serial_num, TlsIndex tls_index,
SerialNumber trace_serial_num, char *thread_name,
char *thread_group_name, char *thread_parent_name);
void io_write_thread_end(SerialNumber thread_serial_num);
void io_write_frame(FrameIndex index, SerialNumber serial_num,
char *mname, char *msig,
char *sname, SerialNumber class_serial_num,
jint lineno);
void io_write_trace_header(SerialNumber trace_serial_num,
SerialNumber thread_serial_num, jint n_frames,
char * phase_str);
void io_write_trace_elem(SerialNumber trace_serial_num,
FrameIndex frame_index, SerialNumber frame_serial_num,
char *csig, char *mname,
char *sname, jint lineno);
void io_write_trace_footer(SerialNumber trace_serial_num,
SerialNumber thread_serial_num, jint n_frames);
void io_write_cpu_samples_header(jlong total_cost, jint n_items);
void io_write_cpu_samples_elem(jint index, double percent, double accum,
jint num_hits, jlong cost,
SerialNumber trace_serial_num, jint n_frames,
char *csig, char *mname);
void io_write_cpu_samples_footer(void);
void io_write_heap_summary(jlong total_live_bytes, jlong total_live_instances,
jlong total_alloced_bytes,
jlong total_alloced_instances);
void io_write_oldprof_header(void);
void io_write_oldprof_elem(jint num_hits, jint num_frames, char *csig_callee,
char *mname_callee, char *msig_callee,
char *csig_caller, char *mname_caller,
char *msig_caller, jlong cost);
void io_write_oldprof_footer(void);
void io_write_monitor_header(jlong total_time);
void io_write_monitor_elem(jint index, double percent, double accum,
jint num_hits, SerialNumber trace_serial_num,
char *sig);
void io_write_monitor_footer(void);
void io_write_monitor_sleep(jlong timeout, SerialNumber thread_serial_num);
void io_write_monitor_wait(char *sig, jlong timeout,
SerialNumber thread_serial_num);
void io_write_monitor_waited(char *sig, jlong time_waited,
SerialNumber thread_serial_num);
void io_write_monitor_exit(char *sig, SerialNumber thread_serial_num);
void io_write_monitor_dump_header(void);
void io_write_monitor_dump_thread_state(SerialNumber thread_serial_num,
SerialNumber trace_serial_num,
jint threadState);
void io_write_monitor_dump_state(char *sig,
SerialNumber thread_serial_num, jint entry_count,
SerialNumber *waiters, jint waiter_count,
SerialNumber *notify_waiters, jint notify_waiter_count);
void io_write_monitor_dump_footer(void);
void io_heap_header(jlong total_live_instances, jlong total_live_bytes);
void io_heap_root_thread_object(ObjectIndex thread_id,
SerialNumber thread_serial_num,
SerialNumber trace_serial_num);
void io_heap_root_unknown(ObjectIndex obj_id);
void io_heap_root_jni_global(ObjectIndex obj_id, SerialNumber gref_serial_num,
SerialNumber trace_serial_num);
void io_heap_root_jni_local(ObjectIndex obj_id,
SerialNumber thread_serial_num, jint frame_depth);
void io_heap_root_system_class(ObjectIndex obj_id, char *sig, SerialNumber class_serial_num);
void io_heap_root_monitor(ObjectIndex obj_id);
void io_heap_root_thread(ObjectIndex obj_id,
SerialNumber thread_serial_num);
void io_heap_root_java_frame(ObjectIndex obj_id,
SerialNumber thread_serial_num, jint frame_depth);
void io_heap_root_native_stack(ObjectIndex obj_id,
SerialNumber thread_serial_num);
void io_heap_class_dump(ClassIndex cnum, char *sig, ObjectIndex class_id,
SerialNumber trace_serial_num,
ObjectIndex super_id, ObjectIndex loader_id,
ObjectIndex signers_id, ObjectIndex domain_id,
jint inst_size,
jint n_cpool, ConstantPoolValue *cpool,
jint n_fields, FieldInfo *fields, jvalue *fvalues);
void io_heap_instance_dump(ClassIndex cnum, ObjectIndex obj_id,
SerialNumber trace_serial_num,
ObjectIndex class_id, jint size,
char *sig, FieldInfo *fields,
jvalue *fvalues, jint n_fields);
void io_heap_object_array(ObjectIndex obj_id, SerialNumber trace_serial_num,
jint size, jint num_elements, char *sig,
ObjectIndex *values, ObjectIndex class_id);
void io_heap_prim_array(ObjectIndex obj_id, SerialNumber trace_serial_num,
jint size, jint num_elements, char *sig,
void *elements);
void io_heap_footer(void);
#endif

View File

@ -1,71 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Used to store strings written out to the binary format (see hprof_io.c) */
/* Probably could have used the basic string table, however, some strings
* would only be in this table, so it was isolated as a separate table
* of strings.
*/
#include "hprof.h"
#include "hprof_ioname.h"
void
ioname_init(void)
{
HPROF_ASSERT(gdata->ioname_table==NULL);
gdata->ioname_table = table_initialize("IoNames", 512, 512, 511, 0);
}
IoNameIndex
ioname_find_or_create(const char *name, jboolean *pnew_entry)
{
return table_find_or_create_entry(gdata->ioname_table,
(void*)name, (int)strlen(name)+1, pnew_entry, NULL);
}
void
ioname_cleanup(void)
{
table_cleanup(gdata->ioname_table, NULL, NULL);
gdata->ioname_table = NULL;
}

View File

@ -1,48 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_IONAME_H
#define HPROF_IONAME_H
void ioname_init(void);
IoNameIndex ioname_find_or_create(const char *name, jboolean *pnew_entry);
void ioname_cleanup(void);
#endif

View File

@ -1,436 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* The hprof listener loop thread. net=hostname:port option */
/*
* The option net=hostname:port causes all hprof output to be sent down
* a socket connection, and also allows for commands to come in over the
* socket. The commands are documented below.
*
* This thread can cause havoc when started prematurely or not terminated
* properly, see listener_init() and listener_term(), and their calls
* in hprof_init.c.
*
* The listener loop (hprof_listener.c) can dynamically turn on or off the
* sampling of all or selected threads.
*
* The specification of this command protocol is only here, in the comments
* below. The HAT tools uses this interface.
* It is also unknown how well these options work given the limited
* testing of this interface.
*
*/
#include "hprof.h"
/* When the hprof Agent in the VM is connected via a socket to the
* profiling client, the client may send the hprof Agent a set of commands.
* The commands have the following format:
*
* u1 a TAG denoting the type of the record
* u4 a serial number
* u4 number of bytes *remaining* in the record. Note that
* this number excludes the tag and the length field itself.
* [u1]* BODY of the record (a sequence of bytes)
*/
/* The following commands are presently supported:
*
* TAG BODY notes
* ----------------------------------------------------------
* HPROF_CMD_GC force a GC.
*
* HPROF_CMD_DUMP_HEAP obtain a heap dump
*
* HPROF_CMD_ALLOC_SITES obtain allocation sites
*
* u2 flags 0x0001: incremental vs. complete
* 0x0002: sorted by allocation vs. live
* 0x0004: whether to force a GC
* u4 cutoff ratio (0.0 ~ 1.0)
*
* HPROF_CMD_HEAP_SUMMARY obtain heap summary
*
* HPROF_CMD_DUMP_TRACES obtain all newly created traces
*
* HPROF_CMD_CPU_SAMPLES obtain a HPROF_CPU_SAMPLES record
*
* u2 ignored for now
* u4 cutoff ratio (0.0 ~ 1.0)
*
* HPROF_CMD_CONTROL changing settings
*
* u2 0x0001: alloc traces on
* 0x0002: alloc traces off
*
* 0x0003: CPU sampling on
*
* id: thread object id (NULL for all)
*
* 0x0004: CPU sampling off
*
* id: thread object id (NULL for all)
*
* 0x0005: CPU sampling clear
*
* 0x0006: clear alloc sites info
*
* 0x0007: set max stack depth in CPU samples
* and alloc traces
*
* u2: new depth
*/
typedef enum HprofCmd {
HPROF_CMD_GC = 0x01,
HPROF_CMD_DUMP_HEAP = 0x02,
HPROF_CMD_ALLOC_SITES = 0x03,
HPROF_CMD_HEAP_SUMMARY = 0x04,
HPROF_CMD_EXIT = 0x05,
HPROF_CMD_DUMP_TRACES = 0x06,
HPROF_CMD_CPU_SAMPLES = 0x07,
HPROF_CMD_CONTROL = 0x08,
HPROF_CMD_EOF = 0xFF
} HprofCmd;
static jint
recv_fully(int f, char *buf, int len)
{
jint nbytes;
nbytes = 0;
if ( f < 0 ) {
return nbytes;
}
while (nbytes < len) {
int res;
res = md_recv(f, buf + nbytes, (len - nbytes), 0);
if (res < 0) {
/*
* hprof was disabled before we returned from recv() above.
* This means the command socket is closed so we let that
* trickle back up the command processing stack.
*/
LOG("recv() returned < 0");
break;
}
nbytes += res;
}
return nbytes;
}
static unsigned char
recv_u1(void)
{
unsigned char c;
jint nbytes;
nbytes = recv_fully(gdata->fd, (char *)&c, (int)sizeof(unsigned char));
if (nbytes == 0) {
c = HPROF_CMD_EOF;
}
return c;
}
static unsigned short
recv_u2(void)
{
unsigned short s;
jint nbytes;
nbytes = recv_fully(gdata->fd, (char *)&s, (int)sizeof(unsigned short));
if (nbytes == 0) {
s = (unsigned short)-1;
}
return md_ntohs(s);
}
static unsigned
recv_u4(void)
{
unsigned i;
jint nbytes;
nbytes = recv_fully(gdata->fd, (char *)&i, (int)sizeof(unsigned));
if (nbytes == 0) {
i = (unsigned)-1;
}
return md_ntohl(i);
}
static ObjectIndex
recv_id(void)
{
ObjectIndex result;
jint nbytes;
nbytes = recv_fully(gdata->fd, (char *)&result, (int)sizeof(ObjectIndex));
if (nbytes == 0) {
result = (ObjectIndex)0;
}
return result;
}
static void JNICALL
listener_loop_function(jvmtiEnv *jvmti, JNIEnv *env, void *p)
{
jboolean keep_processing;
unsigned char tag;
jboolean kill_the_whole_process;
kill_the_whole_process = JNI_FALSE;
tag = 0;
rawMonitorEnter(gdata->listener_loop_lock); {
gdata->listener_loop_running = JNI_TRUE;
keep_processing = gdata->listener_loop_running;
/* Tell listener_init() that we have started */
rawMonitorNotifyAll(gdata->listener_loop_lock);
} rawMonitorExit(gdata->listener_loop_lock);
while ( keep_processing ) {
LOG("listener loop iteration");
tag = recv_u1(); /* This blocks here on the socket read, a close()
* on this fd will wake this up. And if recv_u1()
* can't read anything, it returns HPROF_CMD_EOF.
*/
LOG3("listener_loop", "command = ", tag);
if (tag == HPROF_CMD_EOF) {
/* The cmd socket has closed so the listener thread is done
* just fall out of loop and let the thread die.
*/
keep_processing = JNI_FALSE;
break;
}
/* seq_num not used */
(void)recv_u4();
/* length not used */
(void)recv_u4();
switch (tag) {
case HPROF_CMD_GC:
runGC();
break;
case HPROF_CMD_DUMP_HEAP: {
site_heapdump(env);
break;
}
case HPROF_CMD_ALLOC_SITES: {
unsigned short flags;
unsigned i_tmp;
float ratio;
flags = recv_u2();
i_tmp = recv_u4();
ratio = *(float *)(&i_tmp);
site_write(env, flags, ratio);
break;
}
case HPROF_CMD_HEAP_SUMMARY: {
rawMonitorEnter(gdata->data_access_lock); {
io_write_heap_summary( gdata->total_live_bytes,
gdata->total_live_instances,
gdata->total_alloced_bytes,
gdata->total_alloced_instances);
} rawMonitorExit(gdata->data_access_lock);
break;
}
case HPROF_CMD_EXIT:
keep_processing = JNI_FALSE;
kill_the_whole_process = JNI_TRUE;
verbose_message("HPROF: received exit event, exiting ...\n");
break;
case HPROF_CMD_DUMP_TRACES:
rawMonitorEnter(gdata->data_access_lock); {
trace_output_unmarked(env);
} rawMonitorExit(gdata->data_access_lock);
break;
case HPROF_CMD_CPU_SAMPLES: {
unsigned i_tmp;
float ratio;
/* flags not used */
(void)recv_u2();
i_tmp = recv_u4();
ratio = *(float *)(&i_tmp);
trace_output_cost(env, ratio);
break;
}
case HPROF_CMD_CONTROL: {
unsigned short cmd = recv_u2();
if (cmd == 0x0001) {
setEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL);
tracker_engage(env);
} else if (cmd == 0x0002) {
setEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_OBJECT_FREE, NULL);
tracker_disengage(env);
} else if (cmd == 0x0003) {
ObjectIndex thread_object_index;
thread_object_index = recv_id();
cpu_sample_on(env, thread_object_index);
} else if (cmd == 0x0004) {
ObjectIndex thread_object_index;
thread_object_index = recv_id();
cpu_sample_off(env, thread_object_index);
} else if (cmd == 0x0005) {
rawMonitorEnter(gdata->data_access_lock); {
trace_clear_cost();
} rawMonitorExit(gdata->data_access_lock);
} else if (cmd == 0x0006) {
rawMonitorEnter(gdata->data_access_lock); {
site_cleanup();
site_init();
} rawMonitorExit(gdata->data_access_lock);
} else if (cmd == 0x0007) {
gdata->max_trace_depth = recv_u2();
}
break;
}
default:{
char buf[80];
keep_processing = JNI_FALSE;
kill_the_whole_process = JNI_TRUE;
(void)md_snprintf(buf, sizeof(buf),
"failed to recognize cmd %d, exiting..", (int)tag);
buf[sizeof(buf)-1] = 0;
HPROF_ERROR(JNI_FALSE, buf);
break;
}
}
rawMonitorEnter(gdata->data_access_lock); {
io_flush();
} rawMonitorExit(gdata->data_access_lock);
rawMonitorEnter(gdata->listener_loop_lock); {
if ( !gdata->listener_loop_running ) {
keep_processing = JNI_FALSE;
}
} rawMonitorExit(gdata->listener_loop_lock);
}
/* If listener_term() is causing this loop to terminate, then
* you will block here until listener_term wants you to proceed.
*/
rawMonitorEnter(gdata->listener_loop_lock); {
if ( gdata->listener_loop_running ) {
/* We are terminating for our own reasons, maybe because of
* EOF (socket closed?), or EXIT request, or invalid command.
* Not from listener_term().
* We set gdata->listener_loop_running=FALSE so that any
* future call to listener_term() will do nothing.
*/
gdata->listener_loop_running = JNI_FALSE;
} else {
/* We assume that listener_term() is stopping us,
* now we need to tell it we understood.
*/
rawMonitorNotifyAll(gdata->listener_loop_lock);
}
} rawMonitorExit(gdata->listener_loop_lock);
LOG3("listener_loop", "finished command = ", tag);
/* If we got an explicit command request to die, die here */
if ( kill_the_whole_process ) {
error_exit_process(0);
}
}
/* External functions */
void
listener_init(JNIEnv *env)
{
/* Create the raw monitor */
gdata->listener_loop_lock = createRawMonitor("HPROF listener lock");
rawMonitorEnter(gdata->listener_loop_lock); {
createAgentThread(env, "HPROF listener thread",
&listener_loop_function);
/* Wait for listener_loop_function() to tell us it started. */
rawMonitorWait(gdata->listener_loop_lock, 0);
} rawMonitorExit(gdata->listener_loop_lock);
}
void
listener_term(JNIEnv *env)
{
rawMonitorEnter(gdata->listener_loop_lock); {
/* If we are in the middle of sending bytes down the socket, this
* at least keeps us blocked until that processing is done.
*/
rawMonitorEnter(gdata->data_access_lock); {
/* Make sure the socket gets everything */
io_flush();
/*
* Graceful shutdown of the socket will assure that all data
* sent is received before the socket close completes.
*/
(void)md_shutdown(gdata->fd, 2 /* disallow sends and receives */);
/* This close will cause the listener loop to possibly wake up
* from the recv_u1(), this is critical to get thread running again.
*/
md_close(gdata->fd);
} rawMonitorExit(gdata->data_access_lock);
/* It could have shut itself down, so we check the global flag */
if ( gdata->listener_loop_running ) {
/* It stopped because of something listener_term() did. */
gdata->listener_loop_running = JNI_FALSE;
/* Wait for listener_loop_function() to tell us it finished. */
rawMonitorWait(gdata->listener_loop_lock, 0);
}
} rawMonitorExit(gdata->listener_loop_lock);
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_LISTENER_H
#define HPROF_LISTENER_H
void listener_init(JNIEnv *env);
void listener_term(JNIEnv *env);
#endif

View File

@ -1,270 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* The Class Loader table. */
/*
* The Class Loader objects show up so early in the VM process that a
* separate table was designated for Class Loaders.
*
* The Class Loader is unique by way of it's jobject uniqueness, unfortunately
* use of JNI too early for jobject comparisons is problematic.
* It is assumed that the number of class loaders will be limited, and
* a simple linear search will be performed for now.
* That logic is isolated here and can be changed to use the standard
* table hash table search once we know JNI can be called safely.
*
* A weak global reference is created to keep tabs on loaders, and as
* each search for a loader happens, NULL weak global references will
* trigger the freedom of those entries.
*
*/
#include "hprof.h"
typedef struct {
jobject globalref; /* Weak Global reference for object */
ObjectIndex object_index;
} LoaderInfo;
static LoaderInfo *
get_info(LoaderIndex index)
{
return (LoaderInfo*)table_get_info(gdata->loader_table, index);
}
static void
delete_globalref(JNIEnv *env, LoaderInfo *info)
{
jobject ref;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(info!=NULL);
ref = info->globalref;
info->globalref = NULL;
if ( ref != NULL ) {
deleteWeakGlobalReference(env, ref);
}
info->object_index = 0;
}
static void
cleanup_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
}
static void
delete_ref_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
delete_globalref((JNIEnv*)arg, (LoaderInfo*)info_ptr);
}
static void
list_item(TableIndex index, void *key_ptr, int key_len,
void *info_ptr, void *arg)
{
LoaderInfo *info;
HPROF_ASSERT(info_ptr!=NULL);
info = (LoaderInfo*)info_ptr;
debug_message( "Loader 0x%08x: globalref=%p, object_index=%d\n",
index, (void*)info->globalref, info->object_index);
}
static void
free_entry(JNIEnv *env, LoaderIndex index)
{
LoaderInfo *info;
info = get_info(index);
delete_globalref(env, info);
table_free_entry(gdata->loader_table, index);
}
typedef struct SearchData {
JNIEnv *env;
jobject loader;
LoaderIndex found;
} SearchData;
static void
search_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
LoaderInfo *info;
SearchData *data;
HPROF_ASSERT(info_ptr!=NULL);
HPROF_ASSERT(arg!=NULL);
info = (LoaderInfo*)info_ptr;
data = (SearchData*)arg;
if ( data->loader == info->globalref ) {
/* Covers when looking for NULL too. */
HPROF_ASSERT(data->found==0); /* Did we find more than one? */
data->found = index;
} else if ( data->env != NULL && data->loader != NULL &&
info->globalref != NULL ) {
jobject lref;
lref = newLocalReference(data->env, info->globalref);
if ( lref == NULL ) {
/* Object went away, free reference and entry */
free_entry(data->env, index);
} else if ( isSameObject(data->env, data->loader, lref) ) {
HPROF_ASSERT(data->found==0); /* Did we find more than one? */
data->found = index;
}
if ( lref != NULL ) {
deleteLocalReference(data->env, lref);
}
}
}
static LoaderIndex
search(JNIEnv *env, jobject loader)
{
SearchData data;
data.env = env;
data.loader = loader;
data.found = 0;
table_walk_items(gdata->loader_table, &search_item, (void*)&data);
return data.found;
}
LoaderIndex
loader_find_or_create(JNIEnv *env, jobject loader)
{
LoaderIndex index;
/* See if we remembered the system loader */
if ( loader==NULL && gdata->system_loader != 0 ) {
return gdata->system_loader;
}
if ( loader==NULL ) {
env = NULL;
}
index = search(env, loader);
if ( index == 0 ) {
static LoaderInfo empty_info;
LoaderInfo info;
info = empty_info;
if ( loader != NULL ) {
HPROF_ASSERT(env!=NULL);
info.globalref = newWeakGlobalReference(env, loader);
info.object_index = 0;
}
index = table_create_entry(gdata->loader_table, NULL, 0, (void*)&info);
}
HPROF_ASSERT(search(env,loader)==index);
/* Remember the system loader */
if ( loader==NULL && gdata->system_loader == 0 ) {
gdata->system_loader = index;
}
return index;
}
void
loader_init(void)
{
gdata->loader_table = table_initialize("Loader",
16, 16, 0, (int)sizeof(LoaderInfo));
}
void
loader_list(void)
{
debug_message(
"--------------------- Loader Table ------------------------\n");
table_walk_items(gdata->loader_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
loader_cleanup(void)
{
table_cleanup(gdata->loader_table, &cleanup_item, NULL);
gdata->loader_table = NULL;
}
void
loader_delete_global_references(JNIEnv *env)
{
table_walk_items(gdata->loader_table, &delete_ref_item, (void*)env);
}
/* Get the object index for a class loader */
ObjectIndex
loader_object_index(JNIEnv *env, LoaderIndex index)
{
LoaderInfo *info;
ObjectIndex object_index;
jobject wref;
/* Assume no object index at first (default class loader) */
info = get_info(index);
object_index = info->object_index;
wref = info->globalref;
if ( wref != NULL && object_index == 0 ) {
jobject lref;
object_index = 0;
lref = newLocalReference(env, wref);
if ( lref != NULL && !isSameObject(env, lref, NULL) ) {
jlong tag;
/* Get the tag on the object and extract the object_index */
tag = getTag(lref);
if ( tag != (jlong)0 ) {
object_index = tag_extract(tag);
}
}
if ( lref != NULL ) {
deleteLocalReference(env, lref);
}
info->object_index = object_index;
}
return object_index;
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_LOADER_H
#define HPROF_LOADER_H
LoaderIndex loader_find_or_create(JNIEnv *env, jobject loader);
void loader_init(void);
void loader_list(void);
void loader_delete_global_references(JNIEnv *env);
void loader_cleanup(void);
ObjectIndex loader_object_index(JNIEnv *env, LoaderIndex index);
#endif

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_MD_H
#define HPROF_MD_H
void md_init(void);
int md_getpid(void);
void md_sleep(unsigned seconds);
int md_connect(char *hostname, unsigned short port);
int md_recv(int f, char *buf, int len, int option);
int md_shutdown(int filedes, int option);
int md_open(const char *filename);
int md_open_binary(const char *filename);
int md_creat(const char *filename);
int md_creat_binary(const char *filename);
jlong md_seek(int filedes, jlong cur);
void md_close(int filedes);
int md_send(int s, const char *msg, int len, int flags);
int md_write(int filedes, const void *buf, int nbyte);
int md_read(int filedes, void *buf, int nbyte);
jlong md_get_microsecs(void);
jlong md_get_timemillis(void);
jlong md_get_thread_cpu_timemillis(void);
void md_get_prelude_path(char *path, int path_len, char *filename);
int md_snprintf(char *s, int n, const char *format, ...);
int md_vsnprintf(char *s, int n, const char *format, va_list ap);
void md_system_error(char *buf, int len);
unsigned md_htons(unsigned short s);
unsigned md_htonl(unsigned l);
unsigned md_ntohs(unsigned short s);
unsigned md_ntohl(unsigned l);
void md_build_library_name(char *holder, int holderlen, const char *pname, const char *fname);
void * md_load_library(const char *name, char *err_buf, int err_buflen);
void md_unload_library(void *handle);
void * md_find_library_entry(void *handle, const char *name);
#endif

View File

@ -1,442 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Monitor contention tracking and monitor wait handling. */
/*
* Monitor's under contention are unique per trace and signature.
* Two monitors with the same trace and signature will be treated
* the same as far as accumulated contention time.
*
* The tls table (or thread table) will be used to store the monitor in
* contention or being waited on.
*
* Monitor wait activity is emitted as it happens.
*
* Monitor contention is tabulated and summarized at dump time.
*
*/
#include "hprof.h"
typedef struct MonitorKey {
TraceIndex trace_index;
StringIndex sig_index;
} MonitorKey;
typedef struct MonitorInfo {
jint num_hits;
jlong contended_time;
} MonitorInfo;
typedef struct IterateInfo {
MonitorIndex *monitors;
int count;
jlong total_contended_time;
} IterateInfo;
/* Private internal functions. */
static MonitorKey*
get_pkey(MonitorIndex index)
{
void * key_ptr;
int key_len;
table_get_key(gdata->monitor_table, index, &key_ptr, &key_len);
HPROF_ASSERT(key_len==sizeof(MonitorKey));
HPROF_ASSERT(key_ptr!=NULL);
return (MonitorKey*)key_ptr;
}
static MonitorInfo *
get_info(MonitorIndex index)
{
MonitorInfo * info;
HPROF_ASSERT(index!=0);
info = (MonitorInfo*)table_get_info(gdata->monitor_table, index);
HPROF_ASSERT(info!=NULL);
return info;
}
static MonitorIndex
find_or_create_entry(JNIEnv *env, TraceIndex trace_index, jobject object)
{
static MonitorKey empty_key;
MonitorKey key;
MonitorIndex index;
char *sig;
HPROF_ASSERT(object!=NULL);
WITH_LOCAL_REFS(env, 1) {
jclass clazz;
clazz = getObjectClass(env, object);
getClassSignature(clazz, &sig, NULL);
} END_WITH_LOCAL_REFS;
key = empty_key;
key.trace_index = trace_index;
key.sig_index = string_find_or_create(sig);
jvmtiDeallocate(sig);
index = table_find_or_create_entry(gdata->monitor_table, &key,
(int)sizeof(key), NULL, NULL);
return index;
}
static void
cleanup_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
}
static void
list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
MonitorInfo *info;
MonitorKey *pkey;
HPROF_ASSERT(key_len==sizeof(MonitorKey));
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(info_ptr!=NULL);
pkey = (MonitorKey*)key_ptr;
info = (MonitorInfo *)info_ptr;
debug_message(
"Monitor 0x%08x: trace=0x%08x, sig=0x%08x, "
"num_hits=%d, contended_time=(%d,%d)\n",
index,
pkey->trace_index,
pkey->sig_index,
info->num_hits,
jlong_high(info->contended_time),
jlong_low(info->contended_time));
}
static void
collect_iterator(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
MonitorInfo *info;
IterateInfo *iterate;
HPROF_ASSERT(key_len==sizeof(MonitorKey));
HPROF_ASSERT(info_ptr!=NULL);
HPROF_ASSERT(arg!=NULL);
iterate = (IterateInfo *)arg;
info = (MonitorInfo *)info_ptr;
iterate->monitors[iterate->count++] = index;
iterate->total_contended_time += info->contended_time;
}
static int
qsort_compare(const void *p_monitor1, const void *p_monitor2)
{
MonitorInfo * info1;
MonitorInfo * info2;
MonitorIndex monitor1;
MonitorIndex monitor2;
jlong result;
HPROF_ASSERT(p_monitor1!=NULL);
HPROF_ASSERT(p_monitor2!=NULL);
monitor1 = *(MonitorIndex *)p_monitor1;
monitor2 = *(MonitorIndex *)p_monitor2;
info1 = get_info(monitor1);
info2 = get_info(monitor2);
result = info2->contended_time - info1->contended_time;
if (result < (jlong)0) {
return -1;
} else if ( result > (jlong)0 ) {
return 1;
}
return info2->num_hits - info1->num_hits;
}
static void
clear_item(MonitorIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
MonitorInfo *info;
HPROF_ASSERT(key_len==sizeof(MonitorKey));
HPROF_ASSERT(info_ptr!=NULL);
info = (MonitorInfo *)info_ptr;
info->contended_time = 0;
}
static TraceIndex
get_trace(TlsIndex tls_index, JNIEnv *env)
{
TraceIndex trace_index;
trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, JNI_FALSE);
return trace_index;
}
/* External functions (called from hprof_init.c) */
void
monitor_init(void)
{
gdata->monitor_table = table_initialize("Monitor",
32, 32, 31, (int)sizeof(MonitorInfo));
}
void
monitor_list(void)
{
debug_message(
"------------------- Monitor Table ------------------------\n");
table_walk_items(gdata->monitor_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
monitor_cleanup(void)
{
table_cleanup(gdata->monitor_table, &cleanup_item, (void*)NULL);
gdata->monitor_table = NULL;
}
void
monitor_clear(void)
{
table_walk_items(gdata->monitor_table, &clear_item, NULL);
}
/* Contended monitor output */
void
monitor_write_contended_time(JNIEnv *env, double cutoff)
{
int n_entries;
n_entries = table_element_count(gdata->monitor_table);
if ( n_entries == 0 ) {
return;
}
rawMonitorEnter(gdata->data_access_lock); {
IterateInfo iterate;
int i;
int n_items;
jlong total_contended_time;
/* First write all trace we might refer to. */
trace_output_unmarked(env);
/* Looking for an array of monitor index values of interest */
iterate.monitors = HPROF_MALLOC(n_entries*(int)sizeof(MonitorIndex));
(void)memset(iterate.monitors, 0, n_entries*(int)sizeof(MonitorIndex));
/* Get a combined total and an array of monitor index numbers */
iterate.total_contended_time = 0;
iterate.count = 0;
table_walk_items(gdata->monitor_table, &collect_iterator, &iterate);
/* Sort that list */
n_entries = iterate.count;
if ( n_entries > 0 ) {
qsort(iterate.monitors, n_entries, sizeof(MonitorIndex),
&qsort_compare);
}
/* Apply the cutoff */
n_items = 0;
for (i = 0; i < n_entries; i++) {
MonitorIndex index;
MonitorInfo *info;
double percent;
index = iterate.monitors[i];
info = get_info(index);
percent = (double)info->contended_time /
(double)iterate.total_contended_time;
if (percent < cutoff) {
break;
}
iterate.monitors[n_items++] = index;
}
/* Output the items that make sense */
total_contended_time = iterate.total_contended_time / 1000000;
if ( n_items > 0 && total_contended_time > 0 ) {
double accum;
/* Output the info on this monitor enter site */
io_write_monitor_header(total_contended_time);
accum = 0.0;
for (i = 0; i < n_items; i++) {
MonitorIndex index;
MonitorInfo *info;
MonitorKey *pkey;
double percent;
char *sig;
index = iterate.monitors[i];
pkey = get_pkey(index);
info = get_info(index);
sig = string_get(pkey->sig_index);
percent = (double)info->contended_time /
(double)iterate.total_contended_time * 100.0;
accum += percent;
io_write_monitor_elem(i + 1, percent, accum,
info->num_hits,
trace_get_serial_number(pkey->trace_index),
sig);
}
io_write_monitor_footer();
}
HPROF_FREE(iterate.monitors);
} rawMonitorExit(gdata->data_access_lock);
}
void
monitor_contended_enter_event(JNIEnv *env, jthread thread, jobject object)
{
TlsIndex tls_index;
MonitorIndex index;
TraceIndex trace_index;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(object!=NULL);
tls_index = tls_find_or_create(env, thread);
HPROF_ASSERT(tls_get_monitor(tls_index)==0);
trace_index = get_trace(tls_index, env);
index = find_or_create_entry(env, trace_index, object);
tls_monitor_start_timer(tls_index);
tls_set_monitor(tls_index, index);
}
void
monitor_contended_entered_event(JNIEnv* env, jthread thread, jobject object)
{
TlsIndex tls_index;
MonitorInfo *info;
MonitorIndex index;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(object!=NULL);
HPROF_ASSERT(thread!=NULL);
tls_index = tls_find_or_create(env, thread);
HPROF_ASSERT(tls_index!=0);
index = tls_get_monitor(tls_index);
HPROF_ASSERT(index!=0);
info = get_info(index);
info->contended_time += tls_monitor_stop_timer(tls_index);
info->num_hits++;
tls_set_monitor(tls_index, 0);
}
void
monitor_wait_event(JNIEnv *env, jthread thread, jobject object, jlong timeout)
{
TlsIndex tls_index;
MonitorKey *pkey;
MonitorIndex index;
TraceIndex trace_index;
HPROF_ASSERT(env!=NULL);
HPROF_ASSERT(object!=NULL);
HPROF_ASSERT(thread!=NULL);
tls_index = tls_find_or_create(env, thread);
HPROF_ASSERT(tls_index!=0);
HPROF_ASSERT(tls_get_monitor(tls_index)==0);
trace_index = get_trace(tls_index, env);
index = find_or_create_entry(env, trace_index, object);
pkey = get_pkey(index);
tls_monitor_start_timer(tls_index);
tls_set_monitor(tls_index, index);
rawMonitorEnter(gdata->data_access_lock); {
io_write_monitor_wait(string_get(pkey->sig_index), timeout,
tls_get_thread_serial_number(tls_index));
} rawMonitorExit(gdata->data_access_lock);
}
void
monitor_waited_event(JNIEnv *env, jthread thread,
jobject object, jboolean timed_out)
{
TlsIndex tls_index;
MonitorIndex index;
jlong time_waited;
tls_index = tls_find_or_create(env, thread);
HPROF_ASSERT(tls_index!=0);
time_waited = tls_monitor_stop_timer(tls_index);
index = tls_get_monitor(tls_index);
if ( index ==0 ) {
/* As best as I can tell, on Solaris X86 (not SPARC) I sometimes
* get a "waited" event on a thread that I have never seen before
* at all, so how did I get a WAITED event? Perhaps when I
* did the VM_INIT handling, a thread I've never seen had already
* done the WAIT (which I never saw?), and now I see this thread
* for the first time, and also as it finishes it's WAIT?
* Only happening on faster processors?
*/
tls_set_monitor(tls_index, 0);
return;
}
HPROF_ASSERT(index!=0);
tls_set_monitor(tls_index, 0);
if (object == NULL) {
rawMonitorEnter(gdata->data_access_lock); {
io_write_monitor_sleep(time_waited,
tls_get_thread_serial_number(tls_index));
} rawMonitorExit(gdata->data_access_lock);
} else {
MonitorKey *pkey;
pkey = get_pkey(index);
rawMonitorEnter(gdata->data_access_lock); {
io_write_monitor_waited(string_get(pkey->sig_index), time_waited,
tls_get_thread_serial_number(tls_index));
} rawMonitorExit(gdata->data_access_lock);
}
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_MONITOR_H
#define HPROF_MONITOR_H
void monitor_init(void);
void monitor_list(void);
void monitor_cleanup(void);
void monitor_clear(void);
void monitor_write_contended_time(JNIEnv *env, double cutoff);
void monitor_contended_enter_event(JNIEnv *env_id, jthread thread,
jobject object);
void monitor_contended_entered_event(JNIEnv* env_id, jthread thread,
jobject object);
void monitor_wait_event(JNIEnv *env_id, jthread thread,
jobject object, jlong timeout);
void monitor_waited_event(JNIEnv *env_id, jthread thread,
jobject object, jboolean timed_out);
#endif

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Object table. */
/*
* An Object is unique by it's allocation site (SiteIndex), it's size,
* it's kind, and it's serial number. Normally only the serial number
* would have been necessary for heap=dump, and these other items
* could have been moved to the ObjectInfo. An optimization left
* to the reader. Lookups are not normally done on ObjectIndex's
* anyway because we typically know when to create them.
* Objects that have been tagged, are tagged with an ObjectIndex,
* Objects that are not tagged need a ObjectIndex, a lookup when
* heap=sites, and a new one when heap=dump.
* Objects that are freed, need the tag converted to an ObjectIndex,
* so they can be freed, but only when heap=dump.
* The thread serial number is for the thread associated with this
* object. If the object is a Thread object, it should be the serial
* number for that thread. The ThreadStart event is responsible
* for making sure the thread serial number is correct, but between the
* initial allocation of a Thread object and it's ThreadStart event
* the thread serial number could be for the thread that allocated
* the Thread object.
*
* This will likely be the largest table when using heap=dump, when
* there is one table entry per object.
*
* ObjectIndex entries differ between heap=dump and heap=sites.
* With heap=sites, each ObjectIndex represents a unique site, size,
* and kind of object, so many jobject's will map to a single ObjectIndex.
* With heap=dump, every ObjectIndex maps to a unique jobject.
*
* During processing of a heap dump, the references for the object
* this ObjectIndex represents is assigned to the references field
* of the ObjectInfo as a linked list. (see hprof_references.c).
* Once all the refernces are attached, they are processed into the
* appropriate hprof dump information.
*
* The references field is set and cleared as many times as the heap
* is dumped, as is the reference table.
*
*/
#include "hprof.h"
typedef struct ObjectKey {
SiteIndex site_index; /* Site of allocation */
jint size; /* Size of object as reported by VM */
ObjectKind kind; /* Kind of object, most are OBJECT_NORMAL */
SerialNumber serial_num; /* For heap=dump, a unique number. */
} ObjectKey;
typedef struct ObjectInfo {
RefIndex references; /* Linked list of refs in this object */
SerialNumber thread_serial_num; /* Thread serial number for allocation */
} ObjectInfo;
/* Private internal functions. */
static ObjectKey*
get_pkey(ObjectIndex index)
{
void *key_ptr;
int key_len;
table_get_key(gdata->object_table, index, (void*)&key_ptr, &key_len);
HPROF_ASSERT(key_len==(int)sizeof(ObjectKey));
HPROF_ASSERT(key_ptr!=NULL);
return (ObjectKey*)key_ptr;
}
static ObjectInfo *
get_info(ObjectIndex index)
{
ObjectInfo *info;
info = (ObjectInfo*)table_get_info(gdata->object_table, index);
return info;
}
static void
list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
ObjectKey *pkey;
ObjectInfo *info;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len!=0);
HPROF_ASSERT(info_ptr!=NULL);
info = (ObjectInfo*)info_ptr;
pkey = (ObjectKey*)key_ptr;
debug_message( "Object 0x%08x: site=0x%08x, SN=%u, "
" size=%d, kind=%d, refs=0x%x, threadSN=%u\n",
i, pkey->site_index, pkey->serial_num, pkey->size, pkey->kind,
info->references, info->thread_serial_num);
}
static void
clear_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
ObjectInfo *info;
HPROF_ASSERT(info_ptr!=NULL);
info = (ObjectInfo *)info_ptr;
info->references = 0;
}
static void
dump_class_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
ObjectInfo *info;
HPROF_ASSERT(info_ptr!=NULL);
info = (ObjectInfo *)info_ptr;
reference_dump_class((JNIEnv*)arg, i, info->references);
}
static void
dump_instance_references(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
ObjectInfo *info;
HPROF_ASSERT(info_ptr!=NULL);
info = (ObjectInfo *)info_ptr;
reference_dump_instance((JNIEnv*)arg, i, info->references);
}
/* External interfaces. */
ObjectIndex
object_new(SiteIndex site_index, jint size, ObjectKind kind, SerialNumber thread_serial_num)
{
ObjectIndex index;
ObjectKey key;
static ObjectKey empty_key;
key = empty_key;
key.site_index = site_index;
key.size = size;
key.kind = kind;
if ( gdata->heap_dump ) {
static ObjectInfo empty_info;
ObjectInfo i;
i = empty_info;
i.thread_serial_num = thread_serial_num;
key.serial_num = gdata->object_serial_number_counter++;
index = table_create_entry(gdata->object_table,
&key, (int)sizeof(ObjectKey), &i);
} else {
key.serial_num =
class_get_serial_number(site_get_class_index(site_index));
index = table_find_or_create_entry(gdata->object_table,
&key, (int)sizeof(ObjectKey), NULL, NULL);
}
site_update_stats(site_index, size, 1);
return index;
}
void
object_init(void)
{
jint bucket_count;
bucket_count = 511;
if ( gdata->heap_dump ) {
bucket_count = 0;
}
HPROF_ASSERT(gdata->object_table==NULL);
gdata->object_table = table_initialize("Object", 4096,
4096, bucket_count, (int)sizeof(ObjectInfo));
}
SiteIndex
object_get_site(ObjectIndex index)
{
ObjectKey *pkey;
pkey = get_pkey(index);
return pkey->site_index;
}
jint
object_get_size(ObjectIndex index)
{
ObjectKey *pkey;
pkey = get_pkey(index);
return pkey->size;
}
ObjectKind
object_get_kind(ObjectIndex index)
{
ObjectKey *pkey;
pkey = get_pkey(index);
return pkey->kind;
}
ObjectKind
object_free(ObjectIndex index)
{
ObjectKey *pkey;
ObjectKind kind;
pkey = get_pkey(index);
kind = pkey->kind;
/* Decrement allocations at this site. */
site_update_stats(pkey->site_index, -(pkey->size), -1);
if ( gdata->heap_dump ) {
table_free_entry(gdata->object_table, index);
}
return kind;
}
void
object_list(void)
{
debug_message(
"--------------------- Object Table ------------------------\n");
table_walk_items(gdata->object_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
object_cleanup(void)
{
table_cleanup(gdata->object_table, NULL, NULL);
gdata->object_table = NULL;
}
void
object_set_thread_serial_number(ObjectIndex index,
SerialNumber thread_serial_num)
{
ObjectInfo *info;
info = get_info(index);
info->thread_serial_num = thread_serial_num;
}
SerialNumber
object_get_thread_serial_number(ObjectIndex index)
{
ObjectInfo *info;
info = get_info(index);
return info->thread_serial_num;
}
RefIndex
object_get_references(ObjectIndex index)
{
ObjectInfo *info;
info = get_info(index);
return info->references;
}
void
object_set_references(ObjectIndex index, RefIndex ref_index)
{
ObjectInfo *info;
info = get_info(index);
info->references = ref_index;
}
void
object_clear_references(void)
{
table_walk_items(gdata->object_table, &clear_references, NULL);
}
void
object_reference_dump(JNIEnv *env)
{
table_walk_items(gdata->object_table, &dump_instance_references, (void*)env);
table_walk_items(gdata->object_table, &dump_class_references, (void*)env);
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_OBJECT_H
#define HPROF_OBJECT_H
void object_init(void);
ObjectIndex object_new(SiteIndex site_index, jint size, ObjectKind kind,
SerialNumber thread_serial_num);
SiteIndex object_get_site(ObjectIndex index);
jint object_get_size(ObjectIndex index);
ObjectKind object_get_kind(ObjectIndex index);
ObjectKind object_free(ObjectIndex index);
void object_list(void);
void object_cleanup(void);
void object_set_thread_serial_number(ObjectIndex index,
SerialNumber thread_serial_num);
SerialNumber object_get_thread_serial_number(ObjectIndex index);
RefIndex object_get_references(ObjectIndex index);
void object_set_references(ObjectIndex index, RefIndex ref_index);
void object_clear_references(void);
void object_reference_dump(JNIEnv *env);
#endif

View File

@ -1,814 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Object references table (used in hprof_object.c). */
/*
* This table is used by the object table to store object reference
* and primitive data information obtained from iterations over the
* heap (see hprof_site.c).
*
* Most of these table entries have no Key, but the key is used to store
* the primitive array and primitive field jvalue. None of these entries
* are ever looked up, there will be no hash table, use of the
* LookupTable was just an easy way to handle a unbounded table of
* entries. The object table (see hprof_object.c) will completely
* free this reference table after each heap dump or after processing the
* references and primitive data.
*
* The hprof format required this accumulation of all heap iteration
* references and primitive data from objects in order to compose an
* hprof records for it.
*
* This file contains detailed understandings of how an hprof CLASS
* and INSTANCE dump is constructed, most of this is derived from the
* original hprof code, but some has been derived by reading the HAT
* code that accepts this format.
*
*/
#include "hprof.h"
/* The flavor of data being saved in the RefInfo */
enum {
INFO_OBJECT_REF_DATA = 1,
INFO_PRIM_FIELD_DATA = 2,
INFO_PRIM_ARRAY_DATA = 3
};
/* Reference information, object reference or primitive data information */
typedef struct RefInfo {
ObjectIndex object_index; /* If an object reference, the referree index */
jint index; /* If array or field, array or field index */
jint length; /* If array the element count, if not -1 */
RefIndex next; /* The next table element */
unsigned flavor : 8; /* INFO_*, flavor of RefInfo */
unsigned refKind : 8; /* The kind of reference */
unsigned primType : 8; /* If primitive data involved, it's type */
} RefInfo;
/* Private internal functions. */
/* Get the RefInfo structure from an entry */
static RefInfo *
get_info(RefIndex index)
{
RefInfo *info;
info = (RefInfo*)table_get_info(gdata->reference_table, index);
return info;
}
/* Get a jvalue that was stored as the key. */
static jvalue
get_key_value(RefIndex index)
{
void *key;
int len;
jvalue value;
static jvalue empty_value;
key = NULL;
table_get_key(gdata->reference_table, index, &key, &len);
HPROF_ASSERT(key!=NULL);
HPROF_ASSERT(len==(int)sizeof(jvalue));
if ( key != NULL ) {
(void)memcpy(&value, key, (int)sizeof(jvalue));
} else {
value = empty_value;
}
return value;
}
/* Get size of a primitive type */
static jint
get_prim_size(jvmtiPrimitiveType primType)
{
jint size;
switch ( primType ) {
case JVMTI_PRIMITIVE_TYPE_BOOLEAN:
size = (jint)sizeof(jboolean);
break;
case JVMTI_PRIMITIVE_TYPE_BYTE:
size = (jint)sizeof(jbyte);
break;
case JVMTI_PRIMITIVE_TYPE_CHAR:
size = (jint)sizeof(jchar);
break;
case JVMTI_PRIMITIVE_TYPE_SHORT:
size = (jint)sizeof(jshort);
break;
case JVMTI_PRIMITIVE_TYPE_INT:
size = (jint)sizeof(jint);
break;
case JVMTI_PRIMITIVE_TYPE_FLOAT:
size = (jint)sizeof(jfloat);
break;
case JVMTI_PRIMITIVE_TYPE_LONG:
size = (jint)sizeof(jlong);
break;
case JVMTI_PRIMITIVE_TYPE_DOUBLE:
size = (jint)sizeof(jdouble);
break;
default:
HPROF_ASSERT(0);
size = 1;
break;
}
return size;
}
/* Get a void* elements array that was stored as the key. */
static void *
get_key_elements(RefIndex index, jvmtiPrimitiveType primType,
jint *nelements, jint *nbytes)
{
void *key;
jint byteLen;
HPROF_ASSERT(nelements!=NULL);
HPROF_ASSERT(nbytes!=NULL);
table_get_key(gdata->reference_table, index, &key, &byteLen);
HPROF_ASSERT(byteLen>=0);
HPROF_ASSERT(byteLen!=0?key!=NULL:key==NULL);
*nbytes = byteLen;
*nelements = byteLen / get_prim_size(primType);
return key;
}
/* Dump a RefInfo* structure */
static void
dump_ref_info(RefInfo *info)
{
debug_message("[%d]: flavor=%d"
", refKind=%d"
", primType=%d"
", object_index=0x%x"
", length=%d"
", next=0x%x"
"\n",
info->index,
info->flavor,
info->refKind,
info->primType,
info->object_index,
info->length,
info->next);
}
/* Dump a RefIndex list */
static void
dump_ref_list(RefIndex list)
{
RefInfo *info;
RefIndex index;
debug_message("\nFOLLOW REFERENCES RETURNED:\n");
index = list;
while ( index != 0 ) {
info = get_info(index);
dump_ref_info(info);
index = info->next;
}
}
/* Dump information about a field and what ref data we had on it */
static void
dump_field(FieldInfo *fields, jvalue *fvalues, int n_fields,
jint index, jvalue value, jvmtiPrimitiveType primType)
{
ClassIndex cnum;
StringIndex name;
StringIndex sig;
cnum = fields[index].cnum;
name = fields[index].name_index;
sig = fields[index].sig_index;
debug_message("[%d] %s \"%s\" \"%s\"",
index,
cnum!=0?string_get(class_get_signature(cnum)):"?",
name!=0?string_get(name):"?",
sig!=0?string_get(sig):"?");
if ( fields[index].primType!=0 || fields[index].primType!=primType ) {
debug_message(" (primType=%d(%c)",
fields[index].primType,
primTypeToSigChar(fields[index].primType));
if ( primType != fields[index].primType ) {
debug_message(", got %d(%c)",
primType,
primTypeToSigChar(primType));
}
debug_message(")");
} else {
debug_message("(ty=OBJ)");
}
if ( value.j != (jlong)0 || fvalues[index].j != (jlong)0 ) {
debug_message(" val=[0x%08x,0x%08x] or [0x%08x,0x%08x]",
jlong_high(value.j), jlong_low(value.j),
jlong_high(fvalues[index].j), jlong_low(fvalues[index].j));
}
debug_message("\n");
}
/* Dump all the fields of interest */
static void
dump_fields(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields)
{
int i;
debug_message("\nHPROF LIST OF ALL FIELDS:\n");
for ( i = 0 ; i < n_fields ; i++ ) {
if ( fields[i].name_index != 0 ) {
dump_field(fields, fvalues, n_fields, i, fvalues[i], fields[i].primType);
}
}
dump_ref_list(list);
}
/* Verify field data */
static void
verify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields,
jint index, jvalue value, jvmtiPrimitiveType primType)
{
HPROF_ASSERT(fvalues != NULL);
HPROF_ASSERT(n_fields > 0);
HPROF_ASSERT(index < n_fields);
HPROF_ASSERT(index >= 0 );
if ( primType!=fields[index].primType ) {
dump_fields(list, fields, fvalues, n_fields);
debug_message("\nPROBLEM WITH:\n");
dump_field(fields, fvalues, n_fields, index, value, primType);
debug_message("\n");
HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
}
if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN &&
( value.b != 1 && value.b != 0 ) ) {
dump_fields(list, fields, fvalues, n_fields);
debug_message("\nPROBLEM WITH:\n");
dump_field(fields, fvalues, n_fields, index, value, primType);
debug_message("\n");
HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data");
}
}
/* Fill in a field value, making sure the index is safe */
static void
fill_in_field_value(RefIndex list, FieldInfo *fields, jvalue *fvalues,
int n_fields, jint index, jvalue value,
jvmtiPrimitiveType primType)
{
HPROF_ASSERT(fvalues != NULL);
HPROF_ASSERT(n_fields > 0);
HPROF_ASSERT(index < n_fields);
HPROF_ASSERT(index >= 0 );
HPROF_ASSERT(fvalues[index].j==(jlong)0);
verify_field(list, fields, fvalues, n_fields, index, value, primType);
if (index >= 0 && index < n_fields) {
fvalues[index] = value;
}
}
/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */
static void
dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
SiteIndex site_index;
SerialNumber trace_serial_num;
RefIndex index;
ClassIndex super_cnum;
ObjectIndex super_index;
LoaderIndex loader_index;
ObjectIndex signers_index;
ObjectIndex domain_index;
FieldInfo *fields;
jvalue *fvalues;
jint n_fields;
jboolean skip_fields;
jint n_fields_set;
jlong size;
ClassIndex cnum;
char *sig;
ObjectKind kind;
TraceIndex trace_index;
Stack *cpool_values;
ConstantPoolValue *cpool;
jint cpool_count;
HPROF_ASSERT(object_index!=0);
kind = object_get_kind(object_index);
if ( kind != OBJECT_CLASS ) {
return;
}
site_index = object_get_site(object_index);
HPROF_ASSERT(site_index!=0);
cnum = site_get_class_index(site_index);
HPROF_ASSERT(cnum!=0);
if ( class_get_status(cnum) & CLASS_DUMPED ) {
return;
}
class_add_status(cnum, CLASS_DUMPED);
size = (jlong)object_get_size(object_index);
super_index = 0;
super_cnum = class_get_super(cnum);
if ( super_cnum != 0 ) {
super_index = class_get_object_index(super_cnum);
if ( super_index != 0 ) {
dump_class_and_supers(env, super_index,
object_get_references(super_index));
}
}
trace_index = site_get_trace_index(site_index);
HPROF_ASSERT(trace_index!=0);
trace_serial_num = trace_get_serial_number(trace_index);
sig = string_get(class_get_signature(cnum));
loader_index = class_get_loader(cnum);
signers_index = 0;
domain_index = 0;
/* Get field information */
n_fields = 0;
skip_fields = JNI_FALSE;
n_fields_set = 0;
fields = NULL;
fvalues = NULL;
if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
/* Problems getting all the fields, can't trust field index values */
skip_fields = JNI_TRUE;
/* Class with no references at all? (ok to be unprepared if list==0?) */
if ( list != 0 ) {
/* It is assumed that the reason why we didn't get the fields
* was because the class is not prepared.
*/
if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
dump_ref_list(list);
debug_message("Unprepared class with references: %s\n",
sig);
}
HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes");
}
/* Why would an unprepared class contain references? */
}
if ( n_fields > 0 ) {
fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
(void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
}
/* We use a Stack just because it will automatically expand as needed */
cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue));
cpool = NULL;
cpool_count = 0;
index = list;
while ( index != 0 ) {
RefInfo *info;
jvalue ovalue;
static jvalue empty_value;
info = get_info(index);
switch ( info->flavor ) {
case INFO_OBJECT_REF_DATA:
switch ( info->refKind ) {
case JVMTI_HEAP_REFERENCE_FIELD:
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
/* Should never be seen on a class dump */
HPROF_ASSERT(0);
break;
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
if ( skip_fields == JNI_TRUE ) {
break;
}
ovalue = empty_value;
ovalue.i = info->object_index;
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, 0);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: {
ConstantPoolValue cpv;
ObjectIndex cp_object_index;
SiteIndex cp_site_index;
ClassIndex cp_cnum;
cp_object_index = info->object_index;
HPROF_ASSERT(cp_object_index!=0);
cp_site_index = object_get_site(cp_object_index);
HPROF_ASSERT(cp_site_index!=0);
cp_cnum = site_get_class_index(cp_site_index);
cpv.constant_pool_index = info->index;
cpv.sig_index = class_get_signature(cp_cnum);
cpv.value.i = cp_object_index;
stack_push(cpool_values, (void*)&cpv);
cpool_count++;
break;
}
case JVMTI_HEAP_REFERENCE_SIGNERS:
signers_index = info->object_index;
break;
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
domain_index = info->object_index;
break;
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_INTERFACE:
default:
/* Ignore, not needed */
break;
}
break;
case INFO_PRIM_FIELD_DATA:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(info->primType!=0);
HPROF_ASSERT(info->length==-1);
HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD);
ovalue = get_key_value(index);
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, info->primType);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case INFO_PRIM_ARRAY_DATA:
default:
/* Should never see these */
HPROF_ASSERT(0);
break;
}
index = info->next;
}
/* Get constant pool data if we have any */
HPROF_ASSERT(cpool_count==stack_depth(cpool_values));
if ( cpool_count > 0 ) {
cpool = (ConstantPoolValue*)stack_element(cpool_values, 0);
}
io_heap_class_dump(cnum, sig, object_index, trace_serial_num,
super_index,
loader_object_index(env, loader_index),
signers_index, domain_index,
(jint)size, cpool_count, cpool, n_fields, fields, fvalues);
stack_term(cpool_values);
if ( fvalues != NULL ) {
HPROF_FREE(fvalues);
}
}
/* Walk all references for an ObjectIndex and construct the hprof INST dump. */
static void
dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
jvmtiPrimitiveType primType;
SiteIndex site_index;
SerialNumber trace_serial_num;
RefIndex index;
ObjectIndex class_index;
jlong size;
ClassIndex cnum;
char *sig;
void *elements;
jint num_elements;
jint num_bytes;
ObjectIndex *values;
FieldInfo *fields;
jvalue *fvalues;
jint n_fields;
jboolean skip_fields;
jint n_fields_set;
ObjectKind kind;
TraceIndex trace_index;
jboolean is_array;
jboolean is_prim_array;
HPROF_ASSERT(object_index!=0);
kind = object_get_kind(object_index);
if ( kind == OBJECT_CLASS ) {
return;
}
site_index = object_get_site(object_index);
HPROF_ASSERT(site_index!=0);
cnum = site_get_class_index(site_index);
HPROF_ASSERT(cnum!=0);
size = (jlong)object_get_size(object_index);
trace_index = site_get_trace_index(site_index);
HPROF_ASSERT(trace_index!=0);
trace_serial_num = trace_get_serial_number(trace_index);
sig = string_get(class_get_signature(cnum));
class_index = class_get_object_index(cnum);
values = NULL;
elements = NULL;
num_elements = 0;
num_bytes = 0;
n_fields = 0;
skip_fields = JNI_FALSE;
n_fields_set = 0;
fields = NULL;
fvalues = NULL;
index = list;
is_array = JNI_FALSE;
is_prim_array = JNI_FALSE;
if ( sig[0] != JVM_SIGNATURE_ARRAY ) {
if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) {
/* Trouble getting all the fields, can't trust field index values */
skip_fields = JNI_TRUE;
/* It is assumed that the reason why we didn't get the fields
* was because the class is not prepared.
*/
if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) {
if ( list != 0 ) {
dump_ref_list(list);
debug_message("Instance of unprepared class with refs: %s\n",
sig);
} else {
debug_message("Instance of unprepared class without refs: %s\n",
sig);
}
HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances");
}
}
if ( n_fields > 0 ) {
fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue));
(void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue));
}
} else {
is_array = JNI_TRUE;
if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) {
is_prim_array = JNI_TRUE;
}
}
while ( index != 0 ) {
RefInfo *info;
jvalue ovalue;
static jvalue empty_value;
info = get_info(index);
/* Process reference objects, many not used right now. */
switch ( info->flavor ) {
case INFO_OBJECT_REF_DATA:
switch ( info->refKind ) {
case JVMTI_HEAP_REFERENCE_SIGNERS:
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_INTERFACE:
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
/* Should never be seen on an instance dump */
HPROF_ASSERT(0);
break;
case JVMTI_HEAP_REFERENCE_FIELD:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(is_array!=JNI_TRUE);
ovalue = empty_value;
ovalue.i = info->object_index;
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, 0);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
/* We get each object element one at a time. */
HPROF_ASSERT(is_array==JNI_TRUE);
HPROF_ASSERT(is_prim_array!=JNI_TRUE);
if ( num_elements <= info->index ) {
int nbytes;
if ( values == NULL ) {
num_elements = info->index + 1;
nbytes = num_elements*(int)sizeof(ObjectIndex);
values = (ObjectIndex*)HPROF_MALLOC(nbytes);
(void)memset(values, 0, nbytes);
} else {
void *new_values;
int new_size;
int obytes;
obytes = num_elements*(int)sizeof(ObjectIndex);
new_size = info->index + 1;
nbytes = new_size*(int)sizeof(ObjectIndex);
new_values = (void*)HPROF_MALLOC(nbytes);
(void)memcpy(new_values, values, obytes);
(void)memset(((char*)new_values)+obytes, 0,
nbytes-obytes);
HPROF_FREE(values);
num_elements = new_size;
values = new_values;
}
}
HPROF_ASSERT(values[info->index]==0);
values[info->index] = info->object_index;
break;
default:
/* Ignore, not needed */
break;
}
break;
case INFO_PRIM_FIELD_DATA:
if ( skip_fields == JNI_TRUE ) {
break;
}
HPROF_ASSERT(info->primType!=0);
HPROF_ASSERT(info->length==-1);
HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD);
HPROF_ASSERT(is_array!=JNI_TRUE);
ovalue = get_key_value(index);
fill_in_field_value(list, fields, fvalues, n_fields,
info->index, ovalue, info->primType);
n_fields_set++;
HPROF_ASSERT(n_fields_set <= n_fields);
break;
case INFO_PRIM_ARRAY_DATA:
/* Should only be one, and it's handled below */
HPROF_ASSERT(info->refKind==0);
/* We assert that nothing else was saved with this array */
HPROF_ASSERT(index==list&&info->next==0);
HPROF_ASSERT(is_array==JNI_TRUE);
HPROF_ASSERT(is_prim_array==JNI_TRUE);
primType = info->primType;
elements = get_key_elements(index, primType,
&num_elements, &num_bytes);
HPROF_ASSERT(info->length==num_elements);
size = num_bytes;
break;
default:
HPROF_ASSERT(0);
break;
}
index = info->next;
}
if ( is_array == JNI_TRUE ) {
if ( is_prim_array == JNI_TRUE ) {
HPROF_ASSERT(values==NULL);
io_heap_prim_array(object_index, trace_serial_num,
(jint)size, num_elements, sig, elements);
} else {
HPROF_ASSERT(elements==NULL);
io_heap_object_array(object_index, trace_serial_num,
(jint)size, num_elements, sig, values, class_index);
}
} else {
io_heap_instance_dump(cnum, object_index, trace_serial_num,
class_index, (jint)size, sig, fields, fvalues, n_fields);
}
if ( values != NULL ) {
HPROF_FREE(values);
}
if ( fvalues != NULL ) {
HPROF_FREE(fvalues);
}
if ( elements != NULL ) {
/* Do NOT free elements, it's a key in the table, leave it be */
}
}
/* External interfaces. */
void
reference_init(void)
{
HPROF_ASSERT(gdata->reference_table==NULL);
gdata->reference_table = table_initialize("Ref", 2048, 4096, 0,
(int)sizeof(RefInfo));
}
/* Save away a reference to an object */
RefIndex
reference_obj(RefIndex next, jvmtiHeapReferenceKind refKind,
ObjectIndex object_index, jint index, jint length)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
info = empty_info;
info.flavor = INFO_OBJECT_REF_DATA;
info.refKind = refKind;
info.object_index = object_index;
info.index = index;
info.length = length;
info.next = next;
entry = table_create_entry(gdata->reference_table, NULL, 0, (void*)&info);
return entry;
}
/* Save away some primitive field data */
RefIndex
reference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind,
jvmtiPrimitiveType primType, jvalue field_value, jint field_index)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
HPROF_ASSERT(primType==JVMTI_PRIMITIVE_TYPE_BOOLEAN?(field_value.b==1||field_value.b==0):1);
info = empty_info;
info.flavor = INFO_PRIM_FIELD_DATA;
info.refKind = refKind;
info.primType = primType;
info.index = field_index;
info.length = -1;
info.next = next;
entry = table_create_entry(gdata->reference_table,
(void*)&field_value, (int)sizeof(jvalue), (void*)&info);
return entry;
}
/* Save away some primitive array data */
RefIndex
reference_prim_array(RefIndex next, jvmtiPrimitiveType primType,
const void *elements, jint elementCount)
{
static RefInfo empty_info;
RefIndex entry;
RefInfo info;
HPROF_ASSERT(next == 0);
HPROF_ASSERT(elementCount >= 0);
HPROF_ASSERT(elements != NULL);
info = empty_info;
info.flavor = INFO_PRIM_ARRAY_DATA;
info.refKind = 0;
info.primType = primType;
info.index = 0;
info.length = elementCount;
info.next = next;
entry = table_create_entry(gdata->reference_table, (void*)elements,
elementCount * get_prim_size(primType), (void*)&info);
return entry;
}
void
reference_cleanup(void)
{
if ( gdata->reference_table == NULL ) {
return;
}
table_cleanup(gdata->reference_table, NULL, NULL);
gdata->reference_table = NULL;
}
void
reference_dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
dump_instance(env, object_index, list);
}
void
reference_dump_class(JNIEnv *env, ObjectIndex object_index, RefIndex list)
{
dump_class_and_supers(env, object_index, list);
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_REFERENCE_H
#define HPROF_REFERENCE_H
void reference_init(void);
RefIndex reference_obj(RefIndex next, jvmtiHeapReferenceKind kind,
ObjectIndex object_index, jint index, jint length);
RefIndex reference_prim_field(RefIndex next, jvmtiHeapReferenceKind refKind,
jvmtiPrimitiveType primType, jvalue value, jint field_index);
RefIndex reference_prim_array(RefIndex next, jvmtiPrimitiveType element_type,
const void *elements, jint count);
void reference_cleanup(void);
void reference_dump_class(JNIEnv *env, ObjectIndex object_index,
RefIndex list);
void reference_dump_instance(JNIEnv *env, ObjectIndex object_index,
RefIndex list);
#endif

View File

@ -1,905 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Allocation site table. */
/*
* Every object allocation will have a place where it was allocated,
* this is the purpose of the SiteIndex.
*
* The allocation site or SiteIndex is unique via a (class,trace) pair.
*
* The allocation statistics are accumulated in the SiteInfo for each
* site.
*
* This file also contains the heap iterate logic, which is closely
* associated with the site table, the object table, and the
* reference table. Each object has an element in the object table
* and as the heap is traversed, and information contained in each
* object is saved as a linked list of references.
*
*/
#include "hprof.h"
typedef struct SiteKey {
ClassIndex cnum; /* Unique class number */
TraceIndex trace_index; /* Trace number */
} SiteKey;
typedef struct SiteInfo {
int changed; /* Objects at this site changed? */
unsigned n_alloced_instances; /* Total allocated instances */
unsigned n_alloced_bytes; /* Total bytes allocated from here */
unsigned n_live_instances; /* Live instances for this site. */
unsigned n_live_bytes; /* Live byte count for this site. */
} SiteInfo;
typedef struct IterateInfo {
SiteIndex * site_nums;
int count;
int changed_only;
} IterateInfo;
/* Private internal functions. */
static SiteKey*
get_pkey(SiteIndex index)
{
void *key_ptr;
int key_len;
table_get_key(gdata->site_table, index, &key_ptr, &key_len);
HPROF_ASSERT(key_len==sizeof(SiteKey));
HPROF_ASSERT(key_ptr!=NULL);
return (SiteKey*)key_ptr;
}
ClassIndex
site_get_class_index(SiteIndex index)
{
SiteKey *pkey;
pkey = get_pkey(index);
return pkey->cnum;
}
TraceIndex
site_get_trace_index(SiteIndex index)
{
SiteKey *pkey;
pkey = get_pkey(index);
return pkey->trace_index;
}
static SiteInfo *
get_info(SiteIndex index)
{
SiteInfo *info;
info = (SiteInfo*)table_get_info(gdata->site_table, index);
return info;
}
static void
list_item(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
SiteKey *pkey;
jlong n_alloced_instances;
jlong n_alloced_bytes;
jlong n_live_instances;
jlong n_live_bytes;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(SiteKey));
pkey = (SiteKey*)key_ptr;
if ( info_ptr != NULL ) {
SiteInfo *info;
info = (SiteInfo *)info_ptr;
n_alloced_instances = info->n_alloced_instances;
n_alloced_bytes = info->n_alloced_bytes;
n_live_instances = info->n_live_instances;
n_live_bytes = info->n_live_bytes;
} else {
n_alloced_instances = 0;
n_alloced_bytes = 0;
n_live_instances = 0;
n_live_bytes = 0;
}
debug_message( "Site 0x%08x: class=0x%08x, trace=0x%08x, "
"Ninst=(%d,%d), Nbytes=(%d,%d), "
"Nlive=(%d,%d), NliveBytes=(%d,%d)\n",
i,
pkey->cnum,
pkey->trace_index,
jlong_high(n_alloced_instances), jlong_low(n_alloced_instances),
jlong_high(n_alloced_bytes), jlong_low(n_alloced_bytes),
jlong_high(n_live_instances), jlong_low(n_live_instances),
jlong_high(n_live_bytes), jlong_low(n_live_bytes));
}
static void
collect_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
IterateInfo *iterate;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(SiteKey));
HPROF_ASSERT(arg!=NULL);
iterate = (IterateInfo *)arg;
if ( iterate->changed_only ) {
SiteInfo *info;
info = (SiteInfo *)info_ptr;
if ( info==NULL || !info->changed ) {
return;
}
}
iterate->site_nums[iterate->count++] = i;
}
static void
mark_unchanged_iterator(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
SiteInfo *info;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len==sizeof(SiteKey));
info = (SiteInfo *)info_ptr;
if ( info != NULL ) {
info->changed = 0;
}
}
static int
qsort_compare_allocated_bytes(const void *p_site1, const void *p_site2)
{
SiteIndex site1;
SiteIndex site2;
SiteInfo *info1;
SiteInfo *info2;
HPROF_ASSERT(p_site1!=NULL);
HPROF_ASSERT(p_site2!=NULL);
site1 = *(SiteIndex *)p_site1;
site2 = *(SiteIndex *)p_site2;
info1 = get_info(site1);
info2 = get_info(site2);
return info2->n_alloced_bytes - info1->n_alloced_bytes;
}
static int
qsort_compare_live_bytes(const void *p_site1, const void *p_site2)
{
SiteIndex site1;
SiteIndex site2;
SiteInfo *info1;
SiteInfo *info2;
HPROF_ASSERT(p_site1!=NULL);
HPROF_ASSERT(p_site2!=NULL);
site1 = *(SiteIndex *)p_site1;
site2 = *(SiteIndex *)p_site2;
info1 = get_info(site1);
info2 = get_info(site2);
return info2->n_live_bytes - info1->n_live_bytes;
}
static ClassIndex
find_cnum(jlong class_tag)
{
ClassIndex cnum;
ObjectIndex class_object_index;
SiteIndex class_site_index;
SiteKey *pkey;
HPROF_ASSERT(class_tag!=(jlong)0);
class_object_index = tag_extract(class_tag);
class_site_index = object_get_site(class_object_index);
pkey = get_pkey(class_site_index);
cnum = pkey->cnum;
return cnum;
}
/* Create tag and object entry for an untagged object (should be rare) */
static jlong
make_new_tag(jlong class_tag, jlong size, TraceIndex trace_index,
SerialNumber thread_serial_num,
ObjectIndex *pindex, SiteIndex *psite)
{
ObjectIndex object_index;
SiteIndex object_site_index;
HPROF_ASSERT(class_tag!=(jlong)0);
object_site_index = site_find_or_create(find_cnum(class_tag), trace_index);
object_index = object_new(object_site_index, (jint)size,
OBJECT_SYSTEM, thread_serial_num);
if ( pindex != NULL ) {
*pindex = object_index;
}
if ( psite != NULL ) {
*psite = object_site_index;
}
return tag_create(object_index);
}
/* Setup tag on root object, if tagged return object index and site index */
static void
setup_tag_on_root(jlong *tag_ptr, jlong class_tag, jlong size,
SerialNumber thread_serial_num,
ObjectIndex *pindex, SiteIndex *psite)
{
HPROF_ASSERT(class_tag!=(jlong)0);
if ( (*tag_ptr) != (jlong)0 ) {
if ( pindex != NULL ) {
*pindex = tag_extract(*tag_ptr);
}
if ( psite != NULL ) {
*psite = object_get_site(tag_extract(*tag_ptr));
}
} else {
/* Create and set the tag. */
*tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,
thread_serial_num, pindex, psite);
}
}
/* External interfaces */
SiteIndex
site_find_or_create(ClassIndex cnum, TraceIndex trace_index)
{
SiteIndex index;
static SiteKey empty_key;
SiteKey key;
key = empty_key;
HPROF_ASSERT(cnum!=0);
HPROF_ASSERT(trace_index!=0);
key.cnum = cnum;
key.trace_index = trace_index;
index = table_find_or_create_entry(gdata->site_table,
&key, (int)sizeof(key), NULL, NULL);
return index;
}
void
site_init(void)
{
HPROF_ASSERT(gdata->site_table==NULL);
gdata->site_table = table_initialize("Site",
1024, 1024, 511, (int)sizeof(SiteInfo));
}
void
site_list(void)
{
debug_message(
"--------------------- Site Table ------------------------\n");
table_walk_items(gdata->site_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
site_cleanup(void)
{
table_cleanup(gdata->site_table, NULL, NULL);
gdata->site_table = NULL;
}
void
site_update_stats(SiteIndex index, jint size, jint hits)
{
SiteInfo *info;
table_lock_enter(gdata->site_table); {
info = get_info(index);
info->n_live_instances += hits;
info->n_live_bytes += size;
info->changed = 1;
gdata->total_live_bytes += size;
gdata->total_live_instances += hits;
if ( size > 0 ) {
info->n_alloced_instances += hits;
info->n_alloced_bytes += size;
gdata->total_alloced_bytes =
jlong_add(gdata->total_alloced_bytes, jint_to_jlong(size));
gdata->total_alloced_instances =
jlong_add(gdata->total_alloced_instances, jint_to_jlong(hits));
}
} table_lock_exit(gdata->site_table);
}
/* Output allocation sites, up to the given cut-off point, and according
* to the given flags:
*
* SITE_DUMP_INCREMENTAL only dump what's changed since last dump.
* SITE_SORT_BY_ALLOC sort sites by total allocation rather
* than live data.
* SITE_FORCE_GC force a GC before the site dump.
*/
void
site_write(JNIEnv *env, int flags, double cutoff)
{
HPROF_ASSERT(gdata->site_table!=NULL);
LOG3("site_write", "flags", flags);
if (flags & SITE_FORCE_GC) {
runGC();
}
HPROF_ASSERT(gdata->total_live_bytes!=0);
rawMonitorEnter(gdata->data_access_lock); {
IterateInfo iterate;
int site_table_size;
double accum_percent;
void * comment_str;
int i;
int cutoff_count;
int nbytes;
accum_percent = 0;
site_table_size = table_element_count(gdata->site_table);
(void)memset(&iterate, 0, sizeof(iterate));
nbytes = site_table_size * (int)sizeof(SiteIndex);
if ( nbytes > 0 ) {
iterate.site_nums = HPROF_MALLOC(nbytes);
(void)memset(iterate.site_nums, 0, nbytes);
}
iterate.count = 0;
iterate.changed_only = flags & SITE_DUMP_INCREMENTAL;
table_walk_items(gdata->site_table, &collect_iterator, &iterate);
site_table_size = iterate.count;
if (flags & SITE_SORT_BY_ALLOC) {
comment_str = "allocated bytes";
qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),
&qsort_compare_allocated_bytes);
} else {
comment_str = "live bytes";
qsort(iterate.site_nums, site_table_size, sizeof(SiteIndex),
&qsort_compare_live_bytes);
}
trace_output_unmarked(env);
cutoff_count = 0;
for (i = 0; i < site_table_size; i++) {
SiteInfo *info;
SiteIndex index;
double ratio;
index= iterate.site_nums[i];
HPROF_ASSERT(index!=0);
info = get_info(index);
ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes;
if (ratio < cutoff) {
break;
}
cutoff_count++;
}
io_write_sites_header( comment_str,
flags,
cutoff,
gdata->total_live_bytes,
gdata->total_live_instances,
gdata->total_alloced_bytes,
gdata->total_alloced_instances,
cutoff_count);
for (i = 0; i < cutoff_count; i++) {
SiteInfo *info;
SiteKey *pkey;
SiteIndex index;
char *class_signature;
double ratio;
index = iterate.site_nums[i];
pkey = get_pkey(index);
info = get_info(index);
ratio = (double)info->n_live_bytes / (double)gdata->total_live_bytes;
accum_percent += ratio;
class_signature = string_get(class_get_signature(pkey->cnum));
io_write_sites_elem(i + 1,
ratio,
accum_percent,
class_signature,
class_get_serial_number(pkey->cnum),
trace_get_serial_number(pkey->trace_index),
info->n_live_bytes,
info->n_live_instances,
info->n_alloced_bytes,
info->n_alloced_instances);
}
io_write_sites_footer();
table_walk_items(gdata->site_table, &mark_unchanged_iterator, NULL);
if ( iterate.site_nums != NULL ) {
HPROF_FREE(iterate.site_nums);
}
} rawMonitorExit(gdata->data_access_lock);
}
/* Primitive array data callback for FollowReferences */
static jint JNICALL
cbPrimArrayData(jlong class_tag, jlong size, jlong* tag_ptr,
jint element_count, jvmtiPrimitiveType element_type,
const void* elements, void* user_data)
{
ObjectIndex object_index;
RefIndex ref_index;
RefIndex prev_ref_index;
HPROF_ASSERT(tag_ptr!=NULL);
HPROF_ASSERT(class_tag!=(jlong)0);
HPROF_ASSERT((*tag_ptr)!=(jlong)0);
if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {
/* We can't do anything with a class_tag==0, just skip it */
return JVMTI_VISIT_OBJECTS;
}
/* Assume object has been tagged, get object index */
object_index = tag_extract((*tag_ptr));
/* Save string data */
prev_ref_index = object_get_references(object_index);
ref_index = reference_prim_array(prev_ref_index,
element_type, elements, element_count);
object_set_references(object_index, ref_index);
return JVMTI_VISIT_OBJECTS;
}
/* Primitive field data callback for FollowReferences */
static jint JNICALL
cbPrimFieldData(jvmtiHeapReferenceKind reference_kind,
const jvmtiHeapReferenceInfo* reference_info, jlong class_tag,
jlong* tag_ptr, jvalue value, jvmtiPrimitiveType value_type,
void* user_data)
{
ObjectIndex object_index;
jint field_index;
RefIndex ref_index;
RefIndex prev_ref_index;
HPROF_ASSERT(tag_ptr!=NULL);
HPROF_ASSERT(class_tag!=(jlong)0);
HPROF_ASSERT((*tag_ptr)!=(jlong)0);
if ( class_tag == (jlong)0 || (*tag_ptr) == (jlong)0 ) {
/* We can't do anything with a class_tag==0, just skip it */
return JVMTI_VISIT_OBJECTS;
}
/* If the field is 0, just skip it, we assume 0 */
if ( value.j == (jlong)0 ) {
return JVMTI_VISIT_OBJECTS;
}
/* Get field index */
field_index = reference_info->field.index;
/* We assume the object was tagged */
object_index = tag_extract((*tag_ptr));
/* Save primitive field data */
prev_ref_index = object_get_references(object_index);
ref_index = reference_prim_field(prev_ref_index, reference_kind,
value_type, value, field_index);
object_set_references(object_index, ref_index);
return JVMTI_VISIT_OBJECTS;
}
static SerialNumber
checkThreadSerialNumber(SerialNumber thread_serial_num)
{
TlsIndex tls_index;
if ( thread_serial_num == gdata->unknown_thread_serial_num ) {
return thread_serial_num;
}
tls_index = tls_find(thread_serial_num);
if ( tls_index != 0 && tls_get_in_heap_dump(tls_index) != 0 ) {
return thread_serial_num;
}
return gdata->unknown_thread_serial_num;
}
/* Get the object index and thread serial number for this local object */
static void
localReference(jlong *tag_ptr, jlong class_tag, jlong thread_tag,
jlong size, ObjectIndex *pobject_index, SerialNumber *pthread_serial_num)
{
ObjectIndex object_index;
SerialNumber thread_serial_num;
HPROF_ASSERT(pobject_index!=NULL);
HPROF_ASSERT(pthread_serial_num!=NULL);
HPROF_ASSERT(tag_ptr!=NULL);
HPROF_ASSERT(class_tag!=(jlong)0);
if ( (*tag_ptr) != (jlong)0 ) {
object_index = tag_extract(*tag_ptr);
thread_serial_num = object_get_thread_serial_number(object_index);
thread_serial_num = checkThreadSerialNumber(thread_serial_num);
} else {
if ( thread_tag != (jlong)0 ) {
ObjectIndex thread_object_index;
thread_object_index = tag_extract(thread_tag);
thread_serial_num =
object_get_thread_serial_number(thread_object_index);
thread_serial_num = checkThreadSerialNumber(thread_serial_num);
} else {
thread_serial_num = gdata->unknown_thread_serial_num;
}
/* Create and set the tag. */
*tag_ptr = make_new_tag(class_tag, size, gdata->system_trace_index,
thread_serial_num, &object_index, NULL);
}
HPROF_ASSERT(thread_serial_num!=0);
HPROF_ASSERT(object_index!=0);
*pobject_index = object_index;
*pthread_serial_num = thread_serial_num;
}
/* Store away plain object reference information */
static jint
objectReference(jvmtiHeapReferenceKind reference_kind,
const jvmtiHeapReferenceInfo* reference_info,
jlong class_tag, jlong size, jlong* tag_ptr,
jlong* referrer_tag_ptr, jint length)
{
ObjectIndex object_index;
jint reference_index;
RefIndex ref_index;
RefIndex prev_ref_index;
ObjectIndex referrer_object_index;
jlong object_tag;
HPROF_ASSERT(tag_ptr!=NULL);
HPROF_ASSERT(class_tag!=(jlong)0);
HPROF_ASSERT(referrer_tag_ptr!=NULL);
HPROF_ASSERT((*referrer_tag_ptr)!=(jlong)0);
if ( class_tag == (jlong)0 || (*referrer_tag_ptr) == (jlong)0 ) {
/* We can't do anything with a class_tag==0, just skip it */
return JVMTI_VISIT_OBJECTS;
}
switch ( reference_kind ) {
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_INTERFACE:
default:
/* Currently we don't need these */
return JVMTI_VISIT_OBJECTS;
case JVMTI_HEAP_REFERENCE_FIELD:
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
reference_index = reference_info->field.index;
break;
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
reference_index = reference_info->array.index;
break;
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
reference_index = reference_info->constant_pool.index;
break;
case JVMTI_HEAP_REFERENCE_SIGNERS:
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
reference_index = 0;
break;
}
/* We assume the referrer is tagged */
referrer_object_index = tag_extract((*referrer_tag_ptr));
/* Now check the referree */
object_tag = *tag_ptr;
if ( object_tag != (jlong)0 ) {
object_index = tag_extract(object_tag);
} else {
/* Create and set the tag. */
object_tag = make_new_tag(class_tag, size, gdata->system_trace_index,
gdata->unknown_thread_serial_num,
&object_index, NULL);
*tag_ptr = object_tag;
}
HPROF_ASSERT(object_index!=0);
/* Save reference information */
prev_ref_index = object_get_references(referrer_object_index);
ref_index = reference_obj(prev_ref_index, reference_kind,
object_index, reference_index, length);
object_set_references(referrer_object_index, ref_index);
return JVMTI_VISIT_OBJECTS;
}
/* FollowReferences heap_reference_callback */
static jint JNICALL
cbReference(jvmtiHeapReferenceKind reference_kind,
const jvmtiHeapReferenceInfo* reference_info,
jlong class_tag, jlong referrer_class_tag,
jlong size, jlong* tag_ptr,
jlong* referrer_tag_ptr, jint length, void* user_data)
{
ObjectIndex object_index;
/* Only calls to Allocate, Deallocate, RawMonitorEnter & RawMonitorExit
* are allowed here (see the JVMTI Spec).
*/
HPROF_ASSERT(tag_ptr!=NULL);
HPROF_ASSERT(class_tag!=(jlong)0);
if ( class_tag == (jlong)0 ) {
/* We can't do anything with a class_tag==0, just skip it */
return JVMTI_VISIT_OBJECTS;
}
switch ( reference_kind ) {
case JVMTI_HEAP_REFERENCE_FIELD:
case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
case JVMTI_HEAP_REFERENCE_CLASS_LOADER:
case JVMTI_HEAP_REFERENCE_SIGNERS:
case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN:
case JVMTI_HEAP_REFERENCE_INTERFACE:
case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
return objectReference(reference_kind, reference_info,
class_tag, size, tag_ptr, referrer_tag_ptr, length);
case JVMTI_HEAP_REFERENCE_JNI_GLOBAL: {
SerialNumber trace_serial_num;
SerialNumber gref_serial_num;
TraceIndex trace_index;
SiteIndex object_site_index;
setup_tag_on_root(tag_ptr, class_tag, size,
gdata->unknown_thread_serial_num,
&object_index, &object_site_index);
if ( object_site_index != 0 ) {
SiteKey *pkey;
pkey = get_pkey(object_site_index);
trace_index = pkey->trace_index;
} else {
trace_index = gdata->system_trace_index;
}
trace_serial_num = trace_get_serial_number(trace_index);
gref_serial_num = gdata->gref_serial_number_counter++;
io_heap_root_jni_global(object_index, gref_serial_num,
trace_serial_num);
}
break;
case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: {
char *sig;
SerialNumber class_serial_num;
SiteIndex object_site_index;
setup_tag_on_root(tag_ptr, class_tag, size,
gdata->unknown_thread_serial_num,
&object_index, &object_site_index);
sig = "Unknown";
class_serial_num = 0;
if ( object_site_index != 0 ) {
SiteKey *pkey;
pkey = get_pkey(object_site_index);
sig = string_get(class_get_signature(pkey->cnum));
class_serial_num = class_get_serial_number(pkey->cnum);
}
io_heap_root_system_class(object_index, sig, class_serial_num);
}
break;
case JVMTI_HEAP_REFERENCE_MONITOR:
setup_tag_on_root(tag_ptr, class_tag, size,
gdata->unknown_thread_serial_num,
&object_index, NULL);
io_heap_root_monitor(object_index);
break;
case JVMTI_HEAP_REFERENCE_STACK_LOCAL: {
SerialNumber thread_serial_num;
jlong thread_tag;
thread_tag = reference_info->stack_local.thread_tag;
localReference(tag_ptr, class_tag, thread_tag, size,
&object_index, &thread_serial_num);
io_heap_root_java_frame(object_index, thread_serial_num,
reference_info->stack_local.depth);
}
break;
case JVMTI_HEAP_REFERENCE_JNI_LOCAL: {
SerialNumber thread_serial_num;
jlong thread_tag;
thread_tag = reference_info->jni_local.thread_tag;
localReference(tag_ptr, class_tag, thread_tag, size,
&object_index, &thread_serial_num);
io_heap_root_jni_local(object_index, thread_serial_num,
reference_info->jni_local.depth);
}
break;
case JVMTI_HEAP_REFERENCE_THREAD: {
SerialNumber thread_serial_num;
SerialNumber trace_serial_num;
TraceIndex trace_index;
SiteIndex object_site_index;
TlsIndex tls_index;
/* It is assumed that tag_ptr is referring to a
* java.lang.Thread object here.
*/
if ( (*tag_ptr) != (jlong)0 ) {
setup_tag_on_root(tag_ptr, class_tag, size, 0,
&object_index, &object_site_index);
trace_index = site_get_trace_index(object_site_index);
/* Hopefully the ThreadStart event put this thread's
* correct serial number on it's object.
*/
thread_serial_num = object_get_thread_serial_number(object_index);
} else {
/* Rare situation that a Thread object is not tagged.
* Create special unique thread serial number in this
* case, probably means we never saw a thread start
* or thread end, or even an allocation of the thread
* object.
*/
thread_serial_num = gdata->thread_serial_number_counter++;
setup_tag_on_root(tag_ptr, class_tag, size,
thread_serial_num,
&object_index, &object_site_index);
trace_index = gdata->system_trace_index;
}
/* Get tls_index and set in_heap_dump, if we find it. */
tls_index = tls_find(thread_serial_num);
if ( tls_index != 0 ) {
tls_set_in_heap_dump(tls_index, 1);
}
trace_serial_num = trace_get_serial_number(trace_index);
/* Issue thread object (must be before thread root) */
io_heap_root_thread_object(object_index,
thread_serial_num, trace_serial_num);
/* Issue thread root */
io_heap_root_thread(object_index, thread_serial_num);
}
break;
case JVMTI_HEAP_REFERENCE_OTHER:
setup_tag_on_root(tag_ptr, class_tag, size,
gdata->unknown_thread_serial_num,
&object_index, NULL);
io_heap_root_unknown(object_index);
break;
default:
/* Ignore anything else */
break;
}
return JVMTI_VISIT_OBJECTS;
}
void
site_heapdump(JNIEnv *env)
{
rawMonitorEnter(gdata->data_access_lock); {
jvmtiHeapCallbacks heapCallbacks;
/* Remove class dumped status, all classes must be dumped */
class_all_status_remove(CLASS_DUMPED);
/* Clear in_heap_dump flag */
tls_clear_in_heap_dump();
/* Dump the last thread traces and get the lists back we need */
tls_dump_traces(env);
/* Write header for heap dump */
io_heap_header(gdata->total_live_instances, gdata->total_live_bytes);
/* Setup a clean reference table */
reference_init();
/* Walk over all reachable objects and dump out roots */
gdata->gref_serial_number_counter = gdata->gref_serial_number_start;
/* Issue thread object for fake non-existent unknown thread
* just in case someone refers to it. Real threads are handled
* during iterate over reachable objects.
*/
io_heap_root_thread_object(0, gdata->unknown_thread_serial_num,
trace_get_serial_number(gdata->system_trace_index));
/* Iterate over heap and get the real stuff */
(void)memset(&heapCallbacks, 0, sizeof(heapCallbacks));
/* Select callbacks */
heapCallbacks.heap_reference_callback = &cbReference;
if ( gdata->primfields == JNI_TRUE ) {
heapCallbacks.primitive_field_callback = &cbPrimFieldData;
}
if ( gdata->primarrays == JNI_TRUE ) {
heapCallbacks.array_primitive_value_callback = &cbPrimArrayData;
}
followReferences(&heapCallbacks, (void*)NULL);
/* Process reference information. */
object_reference_dump(env);
object_clear_references();
reference_cleanup();
/* Dump the last thread traces and get the lists back we need */
tls_dump_traces(env);
/* Write out footer for heap dump */
io_heap_footer();
} rawMonitorExit(gdata->data_access_lock);
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_SITE_H
#define HPROF_SITE_H
void site_init(void);
SiteIndex site_find_or_create(ClassIndex cnum, TraceIndex trace_index);
TraceIndex site_get_trace_index(SiteIndex index);
ClassIndex site_get_class_index(SiteIndex index);
void site_list(void);
void site_cleanup(void);
void site_update_stats(SiteIndex index, jint size, jint hits);
void site_write(JNIEnv *env, int flags, double cutoff);
void site_heapdump(JNIEnv *env);
#endif

View File

@ -1,170 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Simple stack storage mechanism (or simple List). */
/*
* Stack is any depth (grows as it needs to), elements are arbitrary
* length but known at stack init time.
*
* Stack elements can be accessed via pointers (be careful, if stack
* moved while you point into stack you have problems)
*
* Pointers to stack elements passed in are copied.
*
* Since the stack can be inspected, it can be used for more than just
* a simple stack.
*
*/
#include "hprof.h"
static void
resize(Stack *stack)
{
void *old_elements;
void *new_elements;
int old_size;
int new_size;
HPROF_ASSERT(stack!=NULL);
HPROF_ASSERT(stack->elements!=NULL);
HPROF_ASSERT(stack->size>0);
HPROF_ASSERT(stack->elem_size>0);
HPROF_ASSERT(stack->incr_size>0);
old_size = stack->size;
old_elements = stack->elements;
if ( (stack->resizes % 10) && stack->incr_size < (old_size >> 2) ) {
stack->incr_size = old_size >> 2; /* 1/4 the old_size */
}
new_size = old_size + stack->incr_size;
new_elements = HPROF_MALLOC(new_size*stack->elem_size);
(void)memcpy(new_elements, old_elements, old_size*stack->elem_size);
stack->size = new_size;
stack->elements = new_elements;
HPROF_FREE(old_elements);
stack->resizes++;
}
Stack *
stack_init(int init_size, int incr_size, int elem_size)
{
Stack *stack;
void *elements;
HPROF_ASSERT(init_size>0);
HPROF_ASSERT(elem_size>0);
HPROF_ASSERT(incr_size>0);
stack = (Stack*)HPROF_MALLOC((int)sizeof(Stack));
elements = HPROF_MALLOC(init_size*elem_size);
stack->size = init_size;
stack->incr_size = incr_size;
stack->elem_size = elem_size;
stack->count = 0;
stack->elements = elements;
stack->resizes = 0;
return stack;
}
void *
stack_element(Stack *stack, int i)
{
HPROF_ASSERT(stack!=NULL);
HPROF_ASSERT(stack->elements!=NULL);
HPROF_ASSERT(stack->count>i);
HPROF_ASSERT(i>=0);
return (void*)(((char*)stack->elements) + i * stack->elem_size);
}
void *
stack_top(Stack *stack)
{
void *element;
HPROF_ASSERT(stack!=NULL);
element = NULL;
if ( stack->count > 0 ) {
element = stack_element(stack, (stack->count-1));
}
return element;
}
int
stack_depth(Stack *stack)
{
HPROF_ASSERT(stack!=NULL);
return stack->count;
}
void *
stack_pop(Stack *stack)
{
void *element;
element = stack_top(stack);
if ( element != NULL ) {
stack->count--;
}
return element;
}
void
stack_push(Stack *stack, void *element)
{
void *top_element;
HPROF_ASSERT(stack!=NULL);
if ( stack->count >= stack->size ) {
resize(stack);
}
stack->count++;
top_element = stack_top(stack);
(void)memcpy(top_element, element, stack->elem_size);
}
void
stack_term(Stack *stack)
{
HPROF_ASSERT(stack!=NULL);
if ( stack->elements != NULL ) {
HPROF_FREE(stack->elements);
}
HPROF_FREE(stack);
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_STACK_H
#define HPROF_STACK_H
typedef struct Stack {
int elem_size;
int incr_size;
int size;
int count;
int resizes;
void *elements;
} Stack;
Stack *stack_init(int init_size, int incr_size, int elem_size);
void *stack_element(Stack *stack, int i);
void *stack_top(Stack *stack);
int stack_depth(Stack *stack);
void *stack_pop(Stack *stack);
void stack_push(Stack *stack, void *element);
void stack_term(Stack *stack);
#endif

View File

@ -1,115 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Table of byte arrays (e.g. char* string + NULL byte) */
/*
* Strings are unique by their own contents, since the string itself
* is the Key, and the hprof_table.c guarantees that keys don't move,
* this works out perfect. Any key in this table can be used as
* an char*.
*
* This does mean that this table has dynamically sized keys.
*
* Care needs to be taken to make sure the NULL byte is included, not for
* the sake of hprof_table.c, but so that the key can be used as a char*.
*
*/
#include "hprof.h"
void
string_init(void)
{
HPROF_ASSERT(gdata->string_table==NULL);
gdata->string_table = table_initialize("Strings", 4096, 4096, 1024, 0);
}
StringIndex
string_find_or_create(const char *str)
{
return table_find_or_create_entry(gdata->string_table,
(void*)str, (int)strlen(str)+1, NULL, NULL);
}
static void
list_item(TableIndex index, void *str, int len, void *info_ptr, void *arg)
{
debug_message( "0x%08x: String \"%s\"\n", index, (const char *)str);
}
void
string_list(void)
{
debug_message(
"-------------------- String Table ------------------------\n");
table_walk_items(gdata->string_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
string_cleanup(void)
{
table_cleanup(gdata->string_table, NULL, NULL);
gdata->string_table = NULL;
}
char *
string_get(StringIndex index)
{
void *key;
int key_len;
table_get_key(gdata->string_table, index, &key, &key_len);
HPROF_ASSERT(key_len>0);
return (char*)key;
}
int
string_get_len(StringIndex index)
{
void *key;
int key_len;
table_get_key(gdata->string_table, index, &key, &key_len);
HPROF_ASSERT(key_len>0);
return key_len-1;
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_STRING_H
#define HPROF_STRING_H
void string_init(void);
StringIndex string_find_or_create(const char *name);
char * string_get(StringIndex index);
int string_get_len(StringIndex index);
void string_list(void);
void string_cleanup(void);
#endif

View File

@ -1,954 +0,0 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Lookup Table of generic elements. */
/*
* Each table has a unique lock, all accesses are protected.
*
* Table elements are identified with a 32bit unsigned int.
* (Also see HARE trick below, which makes the TableIndex unique per table).
*
* Each element has a key (N bytes) and possible additional info.
*
* Two elements with the same key should be the same element.
*
* The storage for the Key and Info cannot move, the table itself can.
*
* The hash table will only be allocated if we have keys, and will resize
* when the table needs to resize. The hash buckets just provide the
* reference to the first TableIndex in the hash bucket, the next
* field of the TableElement takes you to the next item in the hash
* bucket. Lookups will drift the looked up item to the head of the
* list.
*
* The full 32bit hashcode and key length is saved for comparisons, the
* last thing done is the actual comparison of the Key contents with
* keys_equal().
*
* Freed elements (not many tables actually free items) are managed with
* a bit vector and a low index where a freed element might be found.
* Bytes are inspected until a non-zero byte indicates a freed bit is
* set. A count of freed elements is also kept.
*
*/
#include "hprof.h"
/* Macros for bit vectors: unsigned char 2^3==8 OR unsigned int 2^5==32 */
#define BV_CHUNK_POWER_2 3 /* 2 to this power == BV_CHUNK_BITSIZE */
#define BV_CHUNK_TYPE unsigned char
#define BV_CHUNK_BITSIZE (((int)sizeof(BV_CHUNK_TYPE))<<3) /* x8 */
#define BV_CHUNK_INDEX_MASK ( (1 << BV_CHUNK_POWER_2) - 1 )
#define BV_ELEMENT_COUNT(nelems) ((((nelems+1)) >> BV_CHUNK_POWER_2) + 1)
#define BV_CHUNK_ROUND(i) ((i) & ~(BV_CHUNK_INDEX_MASK))
#define BV_CHUNK(ptr, i) \
(((BV_CHUNK_TYPE*)(ptr))[(i) >> BV_CHUNK_POWER_2])
#define BV_CHUNK_MASK(i) \
(1 << ((i) & BV_CHUNK_INDEX_MASK))
/* Hash code value */
typedef unsigned HashCode;
/* Basic key for an element. What makes the element unique. */
typedef struct TableKey {
void *ptr; /* Pointer to arbitrary data that forms the key. */
int len; /* Length in bytes of this key. */
} TableKey;
/* Basic TableElement (but only allocated if keys are used) */
typedef struct TableElement {
TableKey key; /* The element key. */
HashCode hcode; /* The full 32bit hashcode for the key. */
TableIndex next; /* The next TableElement in the hash bucket chain. */
void *info; /* Info pointer */
} TableElement;
/* Generic Lookup Table structure */
typedef struct LookupTable {
char name[48]; /* Name of table. */
void *table; /* Pointer to array of elements. */
TableIndex *hash_buckets; /* Pointer to hash bucket chains. */
Blocks *info_blocks; /* Blocks space for info */
Blocks *key_blocks; /* Blocks space for keys */
TableIndex next_index; /* Next element available. */
TableIndex table_size; /* Current size of table. */
TableIndex table_incr; /* Suggested increment size. */
TableIndex hash_bucket_count; /* Number of hash buckets. */
int elem_size; /* Size of element. */
int info_size; /* Size of info structure (can be 0). */
void *freed_bv; /* Freed element bit vector */
int freed_count; /* Count of freed'd elements */
TableIndex freed_start; /* First freed in table */
int resizes; /* Count of table resizes done. */
unsigned bucket_walks; /* Count of bucket walks. */
jrawMonitorID lock; /* Lock for table access. */
SerialNumber serial_num; /* Table serial number. */
TableIndex hare; /* Rabbit (HARE) trick. */
} LookupTable;
/* To get a pointer to an element, regardless of element size. */
#define ELEMENT_PTR(ltable, i) \
((void*)(((char*)(ltable)->table) + (ltable)->elem_size * (i)))
/* Sanity, check all the time. */
#define SANITY_CHECK(condition) ( (condition) ? (void)0 : \
HPROF_ERROR(JNI_FALSE, "SANITY IN QUESTION: " #condition))
/* To see if an index is valid. */
#define SANITY_CHECK_INDEX(ltable,i) SANITY_CHECK((i) < ltable->next_index)
/* Small rabbits (hares) can be hidden in the index value returned.
* Only the right rabbits are allowed in certain pens (LookupTables).
* When herding rabbits it's important to keep them separate,
* there are lots of rabbits, all different kinds and sizes,
* keeping them all separate is important to avoid cross breeding.
*/
#define _SANITY_USE_HARE
#ifdef _SANITY_USE_HARE
#define SANITY_ADD_HARE(i,hare) (SANITY_REMOVE_HARE(i) | (hare))
#define SANITY_REMOVE_HARE(i) ((i) & 0x0FFFFFFF)
#define SANITY_CHECK_HARE(i,hare) SANITY_CHECK(SANITY_ADD_HARE(i,hare)==(i))
#else
#define SANITY_ADD_HARE(i,hare) (i)
#define SANITY_REMOVE_HARE(i) (i)
#define SANITY_CHECK_HARE(i,hare)
#endif
static jrawMonitorID
lock_create(char *name)
{
jrawMonitorID stanley;
stanley = createRawMonitor(name);
return stanley;
}
static void
lock_destroy(jrawMonitorID stanley)
{
if ( stanley != NULL ) {
destroyRawMonitor(stanley);
}
}
static void
lock_enter(jrawMonitorID stanley)
{
if ( stanley != NULL ) {
rawMonitorEnter(stanley);
}
}
static void
lock_exit(jrawMonitorID stanley)
{
if ( stanley != NULL ) {
rawMonitorExit(stanley);
}
}
static void
get_key(LookupTable *ltable, TableIndex index, void **pkey_ptr, int *pkey_len)
{
*pkey_ptr = ((TableElement*)ELEMENT_PTR(ltable,index))->key.ptr;
*pkey_len = ((TableElement*)ELEMENT_PTR(ltable,index))->key.len;
}
static void *
get_info(LookupTable *ltable, TableIndex index)
{
TableElement *element;
element = (TableElement*)ELEMENT_PTR(ltable,index);
return element->info;
}
static void
hash_out(LookupTable *ltable, TableIndex index)
{
if ( ltable->hash_bucket_count > 0 ) {
TableElement *element;
TableElement *prev_e;
TableIndex bucket;
TableIndex i;
element = (TableElement*)ELEMENT_PTR(ltable,index);
bucket = (element->hcode % ltable->hash_bucket_count);
i = ltable->hash_buckets[bucket];
HPROF_ASSERT(i!=0);
prev_e = NULL;
while ( i != 0 && i != index ) {
prev_e = (TableElement*)ELEMENT_PTR(ltable,i);
i = prev_e->next;
}
HPROF_ASSERT(i==index);
if ( prev_e == NULL ) {
ltable->hash_buckets[bucket] = element->next;
} else {
prev_e->next = element->next;
}
element->next = 0;
element->hcode = 0;
}
}
static jboolean
is_freed_entry(LookupTable *ltable, TableIndex index)
{
if ( ltable->freed_bv == NULL ) {
return JNI_FALSE;
}
if ( ( BV_CHUNK(ltable->freed_bv, index) & BV_CHUNK_MASK(index) ) != 0 ) {
return JNI_TRUE;
}
return JNI_FALSE;
}
static void
set_freed_bit(LookupTable *ltable, TableIndex index)
{
void *p;
HPROF_ASSERT(!is_freed_entry(ltable, index));
p = ltable->freed_bv;
if ( p == NULL ) {
int size;
/* First time for a free */
HPROF_ASSERT(ltable->freed_start==0);
HPROF_ASSERT(ltable->freed_start==0);
size = BV_ELEMENT_COUNT(ltable->table_size);
p = HPROF_MALLOC(size*(int)sizeof(BV_CHUNK_TYPE));
ltable->freed_bv = p;
(void)memset(p, 0, size*(int)sizeof(BV_CHUNK_TYPE));
}
BV_CHUNK(p, index) |= BV_CHUNK_MASK(index);
ltable->freed_count++;
if ( ltable->freed_count == 1 ) {
/* Set freed_start for first time. */
HPROF_ASSERT(ltable->freed_start==0);
ltable->freed_start = index;
} else if ( index < ltable->freed_start ) {
/* Set freed_start to smaller value so we can be smart about search */
HPROF_ASSERT(ltable->freed_start!=0);
ltable->freed_start = index;
}
HPROF_ASSERT(ltable->freed_start!=0);
HPROF_ASSERT(ltable->freed_start < ltable->next_index);
HPROF_ASSERT(is_freed_entry(ltable, index));
}
static TableIndex
find_freed_entry(LookupTable *ltable)
{
if ( ltable->freed_count > 0 ) {
TableIndex i;
TableIndex istart;
void *p;
BV_CHUNK_TYPE chunk;
HPROF_ASSERT(BV_CHUNK_BITSIZE==(1<<BV_CHUNK_POWER_2));
p = ltable->freed_bv;
HPROF_ASSERT(p!=NULL);
/* Go to beginning of chunk */
HPROF_ASSERT(ltable->freed_start!=0);
HPROF_ASSERT(ltable->freed_start < ltable->next_index);
istart = BV_CHUNK_ROUND(ltable->freed_start);
/* Find chunk with any bit set */
chunk = 0;
for( ; istart < ltable->next_index ; istart += BV_CHUNK_BITSIZE ) {
chunk = BV_CHUNK(p, istart);
if ( chunk != 0 ) {
break;
}
}
HPROF_ASSERT(chunk!=0);
HPROF_ASSERT(chunk==BV_CHUNK(p,istart));
HPROF_ASSERT(istart < ltable->next_index);
/* Find bit in chunk and return index of freed item */
for( i = istart ; i < (istart+BV_CHUNK_BITSIZE) ; i++) {
BV_CHUNK_TYPE mask;
mask = BV_CHUNK_MASK(i);
if ( (chunk & mask) != 0 ) {
HPROF_ASSERT(chunk==BV_CHUNK(p,i));
chunk &= ~mask;
BV_CHUNK(p, i) = chunk;
ltable->freed_count--;
HPROF_ASSERT(i < ltable->next_index);
if ( ltable->freed_count > 0 ) {
/* Set freed_start so we can be smart about search */
HPROF_ASSERT((i+1) < ltable->next_index);
ltable->freed_start = i+1;
} else {
/* Clear freed_start because there are no freed entries */
ltable->freed_start = 0;
}
HPROF_ASSERT(!is_freed_entry(ltable, i));
return i;
}
}
HPROF_ASSERT(0);
}
return 0;
}
static void
free_entry(LookupTable *ltable, TableIndex index)
{
set_freed_bit(ltable, index);
hash_out(ltable, index);
}
/* Fairly generic hash code generator (not a hash table index) */
static HashCode
hashcode(void *key_ptr, int key_len)
{
unsigned char * p;
HashCode hcode;
int i;
hcode = 0;
if ( key_ptr == NULL || key_len == 0 ) {
return hcode;
}
i = 0;
p = (unsigned char*)key_ptr;
for ( ; i < key_len-3 ; i += 4 ) {
/* Do a little loop unrolling */
hcode += (
( (unsigned)(p[i]) << 24 ) |
( (unsigned)(p[i+1]) << 16 ) |
( (unsigned)(p[i+2]) << 8 ) |
( (unsigned)(p[i+3]) )
);
}
for ( ; i < key_len ; i++ ) {
hcode += (unsigned)(p[i]);
}
return hcode;
}
static void
hash_in(LookupTable *ltable, TableIndex index, HashCode hcode)
{
if ( ltable->hash_bucket_count > 0 ) {
TableElement *element;
TableIndex bucket;
bucket = (hcode % ltable->hash_bucket_count);
element = (TableElement*)ELEMENT_PTR(ltable, index);
element->hcode = hcode;
element->next = ltable->hash_buckets[bucket];
ltable->hash_buckets[bucket] = index;
}
}
static void
resize_hash_buckets(LookupTable *ltable)
{
/* Don't want to do this too often. */
/* Hash table needs resizing when it's smaller than 1/16 the number of
* elements used in the table. This is just a guess.
*/
if ( ( ltable->hash_bucket_count < (ltable->next_index >> 4) )
&& ( ltable->hash_bucket_count > 0 )
&& ( ( ltable->resizes % 10 ) == 0 )
&& ( ltable->bucket_walks > 1000*ltable->hash_bucket_count )
) {
int old_size;
int new_size;
TableIndex *new_buckets;
TableIndex *old_buckets;
int bucket;
/* Increase size of hash_buckets array, and rehash all elements */
LOG3("Table resize", ltable->name, ltable->resizes);
old_size = ltable->hash_bucket_count;
old_buckets = ltable->hash_buckets;
new_size = (ltable->next_index >> 3); /* 1/8 current used count */
SANITY_CHECK(new_size > old_size);
new_buckets = HPROF_MALLOC(new_size*(int)sizeof(TableIndex));
(void)memset(new_buckets, 0, new_size*(int)sizeof(TableIndex));
ltable->hash_bucket_count = new_size;
ltable->hash_buckets = new_buckets;
for ( bucket = 0 ; bucket < old_size ; bucket++ ) {
TableIndex index;
index = old_buckets[bucket];
while ( index != 0 ) {
TableElement *element;
TableIndex next;
element = (TableElement*)ELEMENT_PTR(ltable, index);
next = element->next;
element->next = 0;
hash_in(ltable, index, element->hcode);
index = next;
}
}
HPROF_FREE(old_buckets);
ltable->bucket_walks = 0;
}
}
static void
resize(LookupTable *ltable)
{
int old_size;
int new_size;
void *old_table;
void *new_table;
int nbytes;
int obytes;
LOG3("Table resize", ltable->name, ltable->resizes);
/* Adjust increment on every resize
* Minimum is 1/4 the size of the current table or 512.
*/
old_size = ltable->table_size;
if ( ltable->table_incr < (unsigned)(old_size >> 2) ) {
ltable->table_incr = (old_size >> 2);
}
if ( ltable->table_incr < 512 ) {
ltable->table_incr = 512;
}
new_size = old_size + ltable->table_incr;
/* Basic table element array */
obytes = old_size * ltable->elem_size;
nbytes = new_size * ltable->elem_size;
old_table = ltable->table;
new_table = HPROF_MALLOC(nbytes);
(void)memcpy(new_table, old_table, obytes);
(void)memset(((char*)new_table)+obytes, 0, nbytes-obytes);
ltable->table = new_table;
ltable->table_size = new_size;
HPROF_FREE(old_table);
/* Then bit vector for freed entries */
if ( ltable->freed_bv != NULL ) {
void *old_bv;
void *new_bv;
obytes = BV_ELEMENT_COUNT(old_size)*(int)sizeof(BV_CHUNK_TYPE);
nbytes = BV_ELEMENT_COUNT(new_size)*(int)sizeof(BV_CHUNK_TYPE);
old_bv = ltable->freed_bv;
new_bv = HPROF_MALLOC(nbytes);
(void)memcpy(new_bv, old_bv, obytes);
(void)memset(((char*)new_bv)+obytes, 0, nbytes-obytes);
ltable->freed_bv = new_bv;
HPROF_FREE(old_bv);
}
/* Check to see if the hash table needs resizing */
resize_hash_buckets(ltable);
ltable->resizes++;
}
static jboolean
keys_equal(void *key_ptr1, void *key_ptr2, int key_len)
{
unsigned char * p1;
unsigned char * p2;
int i;
if ( key_len == 0 ) {
return JNI_TRUE;
}
/* We know these are aligned because we malloc'd them. */
/* Compare word by word, then byte by byte */
p1 = (unsigned char*)key_ptr1;
p2 = (unsigned char*)key_ptr2;
for ( i = 0 ; i < key_len-3 ; i += 4 ) {
/*LINTED*/
if ( *(unsigned*)(p1+i) != *(unsigned*)(p2+i) ) {
return JNI_FALSE;
}
}
for ( ; i < key_len ; i++ ) {
if ( p1[i] != p2[i] ) {
return JNI_FALSE;
}
}
return JNI_TRUE;
}
static TableIndex
find_entry(LookupTable *ltable, void *key_ptr, int key_len, HashCode hcode)
{
TableIndex index;
HPROF_ASSERT(ltable!=NULL);
index = 0;
if ( ltable->hash_bucket_count > 0 ) {
TableIndex bucket;
TableIndex prev_index;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len>0);
prev_index = 0;
bucket = (hcode % ltable->hash_bucket_count);
index = ltable->hash_buckets[bucket];
while ( index != 0 ) {
TableElement *element;
TableElement *prev_element;
element = (TableElement*)ELEMENT_PTR(ltable, index);
if ( hcode == element->hcode &&
key_len == element->key.len &&
keys_equal(key_ptr, element->key.ptr, key_len) ) {
/* Place this guy at the head of the bucket list */
if ( prev_index != 0 ) {
prev_element = (TableElement*)ELEMENT_PTR(ltable, prev_index);
prev_element->next = element->next;
element->next = ltable->hash_buckets[bucket];
ltable->hash_buckets[bucket] = index;
}
break;
}
prev_index = index;
index = element->next;
ltable->bucket_walks++;
}
}
return index;
}
static TableIndex
setup_new_entry(LookupTable *ltable, void *key_ptr, int key_len, void *info_ptr)
{
TableIndex index;
TableElement *element;
void *info;
void *dup_key;
/* Assume we need new allocations for key and info */
dup_key = NULL;
info = NULL;
/* Look for a freed element */
index = 0;
if ( ltable->freed_count > 0 ) {
index = find_freed_entry(ltable);
}
if ( index != 0 ) {
int old_key_len;
/* Found a freed element, re-use what we can but clean it up. */
element = (TableElement*)ELEMENT_PTR(ltable, index);
dup_key = element->key.ptr;
old_key_len = element->key.len;
info = element->info;
(void)memset(element, 0, ltable->elem_size);
/* Toss the key space if size is too small to hold new key */
if ( key_ptr != NULL ) {
if ( old_key_len < key_len ) {
/* This could leak space in the Blocks if keys are variable
* in size AND the table does frees of elements.
*/
dup_key = NULL;
}
}
} else {
/* Brand new table element */
if ( ltable->next_index >= ltable->table_size ) {
resize(ltable);
}
index = ltable->next_index++;
element = (TableElement*)ELEMENT_PTR(ltable, index);
}
/* Setup info area */
if ( ltable->info_size > 0 ) {
if ( info == NULL ) {
info = blocks_alloc(ltable->info_blocks, ltable->info_size);
}
if ( info_ptr==NULL ) {
(void)memset(info, 0, ltable->info_size);
} else {
(void)memcpy(info, info_ptr, ltable->info_size);
}
}
/* Setup key area if one was provided */
if ( key_ptr != NULL ) {
if ( dup_key == NULL ) {
dup_key = blocks_alloc(ltable->key_blocks, key_len);
}
(void)memcpy(dup_key, key_ptr, key_len);
}
/* Fill in element */
element->key.ptr = dup_key;
element->key.len = key_len;
element->info = info;
return index;
}
LookupTable *
table_initialize(const char *name, int size, int incr, int bucket_count,
int info_size)
{
LookupTable * ltable;
char lock_name[80];
int elem_size;
int key_size;
HPROF_ASSERT(name!=NULL);
HPROF_ASSERT(size>0);
HPROF_ASSERT(incr>0);
HPROF_ASSERT(bucket_count>=0);
HPROF_ASSERT(info_size>=0);
key_size = 1;
ltable = (LookupTable *)HPROF_MALLOC((int)sizeof(LookupTable));
(void)memset(ltable, 0, (int)sizeof(LookupTable));
(void)strncpy(ltable->name, name, sizeof(ltable->name));
elem_size = (int)sizeof(TableElement);
ltable->next_index = 1; /* Never use index 0 */
ltable->table_size = size;
ltable->table_incr = incr;
ltable->hash_bucket_count = bucket_count;
ltable->elem_size = elem_size;
ltable->info_size = info_size;
if ( info_size > 0 ) {
ltable->info_blocks = blocks_init(8, info_size, incr);
}
if ( key_size > 0 ) {
ltable->key_blocks = blocks_init(8, key_size, incr);
}
ltable->table = HPROF_MALLOC(size * elem_size);
(void)memset(ltable->table, 0, size * elem_size);
if ( bucket_count > 0 ) {
int nbytes;
nbytes = (int)(bucket_count*sizeof(TableIndex));
ltable->hash_buckets = (TableIndex*)HPROF_MALLOC(nbytes);
(void)memset(ltable->hash_buckets, 0, nbytes);
}
(void)md_snprintf(lock_name, sizeof(lock_name),
"HPROF %s table lock", name);
lock_name[sizeof(lock_name)-1] = 0;
ltable->lock = lock_create(lock_name);
ltable->serial_num = gdata->table_serial_number_counter++;
ltable->hare = (ltable->serial_num << 28);
LOG3("Table initialized", ltable->name, ltable->table_size);
return ltable;
}
int
table_element_count(LookupTable *ltable)
{
int nelems;
HPROF_ASSERT(ltable!=NULL);
lock_enter(ltable->lock); {
nelems = ltable->next_index-1;
} lock_exit(ltable->lock);
return nelems;
}
void
table_free_entry(LookupTable *ltable, TableIndex index)
{
HPROF_ASSERT(ltable!=NULL);
SANITY_CHECK_HARE(index, ltable->hare);
index = SANITY_REMOVE_HARE(index);
SANITY_CHECK_INDEX(ltable, index);
lock_enter(ltable->lock); {
HPROF_ASSERT(!is_freed_entry(ltable, index));
free_entry(ltable, index);
} lock_exit(ltable->lock);
}
void
table_walk_items(LookupTable *ltable, LookupTableIterator func, void* arg)
{
if ( ltable == NULL || ltable->next_index <= 1 ) {
return;
}
HPROF_ASSERT(func!=NULL);
lock_enter(ltable->lock); {
TableIndex index;
int fcount;
LOG3("table_walk_items() count+free", ltable->name, ltable->next_index);
fcount = 0;
for ( index = 1 ; index < ltable->next_index ; index++ ) {
if ( ! is_freed_entry(ltable, index) ) {
void *key_ptr;
int key_len;
void *info;
get_key(ltable, index, &key_ptr, &key_len);
if ( ltable->info_size == 0 ) {
info = NULL;
} else {
info = get_info(ltable, index);
}
(*func)(SANITY_ADD_HARE(index, ltable->hare), key_ptr, key_len, info, arg);
if ( is_freed_entry(ltable, index) ) {
fcount++;
}
} else {
fcount++;
}
}
LOG3("table_walk_items() count-free", ltable->name, ltable->next_index);
HPROF_ASSERT(fcount==ltable->freed_count);
} lock_exit(ltable->lock);
}
void
table_cleanup(LookupTable *ltable, LookupTableIterator func, void *arg)
{
if ( ltable == NULL ) {
return;
}
if ( func != NULL ) {
table_walk_items(ltable, func, arg);
}
lock_enter(ltable->lock); {
HPROF_FREE(ltable->table);
if ( ltable->hash_buckets != NULL ) {
HPROF_FREE(ltable->hash_buckets);
}
if ( ltable->freed_bv != NULL ) {
HPROF_FREE(ltable->freed_bv);
}
if ( ltable->info_blocks != NULL ) {
blocks_term(ltable->info_blocks);
ltable->info_blocks = NULL;
}
if ( ltable->key_blocks != NULL ) {
blocks_term(ltable->key_blocks);
ltable->key_blocks = NULL;
}
} lock_exit(ltable->lock);
lock_destroy(ltable->lock);
ltable->lock = NULL;
HPROF_FREE(ltable);
ltable = NULL;
}
TableIndex
table_create_entry(LookupTable *ltable, void *key_ptr, int key_len, void *info_ptr)
{
TableIndex index;
HashCode hcode;
HPROF_ASSERT(ltable!=NULL);
/* Create hash code if needed */
hcode = 0;
if ( ltable->hash_bucket_count > 0 ) {
hcode = hashcode(key_ptr, key_len);
}
/* Create a new entry */
lock_enter(ltable->lock); {
/* Need to create a new entry */
index = setup_new_entry(ltable, key_ptr, key_len, info_ptr);
/* Add to hash table if we have one */
if ( ltable->hash_bucket_count > 0 ) {
hash_in(ltable, index, hcode);
}
} lock_exit(ltable->lock);
return SANITY_ADD_HARE(index, ltable->hare);
}
TableIndex
table_find_entry(LookupTable *ltable, void *key_ptr, int key_len)
{
TableIndex index;
HashCode hcode;
/* Create hash code if needed */
hcode = 0;
if ( ltable->hash_bucket_count > 0 ) {
hcode = hashcode(key_ptr, key_len);
}
/* Look for element */
lock_enter(ltable->lock); {
index = find_entry(ltable, key_ptr, key_len, hcode);
} lock_exit(ltable->lock);
return index==0 ? index : SANITY_ADD_HARE(index, ltable->hare);
}
TableIndex
table_find_or_create_entry(LookupTable *ltable, void *key_ptr, int key_len,
jboolean *pnew_entry, void *info_ptr)
{
TableIndex index;
HashCode hcode;
/* Assume it is NOT a new entry for now */
if ( pnew_entry ) {
*pnew_entry = JNI_FALSE;
}
/* Create hash code if needed */
hcode = 0;
if ( ltable->hash_bucket_count > 0 ) {
hcode = hashcode(key_ptr, key_len);
}
/* Look for element */
index = 0;
lock_enter(ltable->lock); {
if ( ltable->hash_bucket_count > 0 ) {
index = find_entry(ltable, key_ptr, key_len, hcode);
}
if ( index == 0 ) {
/* Need to create a new entry */
index = setup_new_entry(ltable, key_ptr, key_len, info_ptr);
/* Add to hash table if we have one */
if ( ltable->hash_bucket_count > 0 ) {
hash_in(ltable, index, hcode);
}
if ( pnew_entry ) {
*pnew_entry = JNI_TRUE;
}
}
} lock_exit(ltable->lock);
return SANITY_ADD_HARE(index, ltable->hare);
}
void *
table_get_info(LookupTable *ltable, TableIndex index)
{
void *info;
HPROF_ASSERT(ltable!=NULL);
HPROF_ASSERT(ltable->info_size > 0);
SANITY_CHECK_HARE(index, ltable->hare);
index = SANITY_REMOVE_HARE(index);
SANITY_CHECK_INDEX(ltable, index);
lock_enter(ltable->lock); {
HPROF_ASSERT(!is_freed_entry(ltable, index));
info = get_info(ltable,index);
} lock_exit(ltable->lock);
return info;
}
void
table_get_key(LookupTable *ltable, TableIndex index, void **pkey_ptr, int *pkey_len)
{
HPROF_ASSERT(ltable!=NULL);
HPROF_ASSERT(pkey_ptr!=NULL);
HPROF_ASSERT(pkey_len!=NULL);
SANITY_CHECK_HARE(index, ltable->hare);
HPROF_ASSERT(ltable->elem_size!=0);
index = SANITY_REMOVE_HARE(index);
SANITY_CHECK_INDEX(ltable, index);
lock_enter(ltable->lock); {
HPROF_ASSERT(!is_freed_entry(ltable, index));
get_key(ltable, index, pkey_ptr, pkey_len);
} lock_exit(ltable->lock);
}
void
table_lock_enter(LookupTable *ltable)
{
lock_enter(ltable->lock);
}
void
table_lock_exit(LookupTable *ltable)
{
lock_exit(ltable->lock);
}

View File

@ -1,75 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_TABLE_H
#define HPROF_TABLE_H
/* Key based generic lookup table */
struct LookupTable;
typedef void (*LookupTableIterator)
(TableIndex, void *key_ptr, int key_len, void*, void*);
struct LookupTable * table_initialize(const char *name, int size,
int incr, int buckets, int esize);
int table_element_count(struct LookupTable *ltable);
TableIndex table_create_entry(struct LookupTable *ltable,
void *key_ptr, int key_len, void *info_ptr);
TableIndex table_find_entry(struct LookupTable *ltable,
void *key_ptr, int key_len);
TableIndex table_find_or_create_entry(struct LookupTable *ltable,
void *key_ptr, int key_len,
jboolean *pnew_entry, void *info_ptr);
void table_free_entry(struct LookupTable *ltable,
TableIndex index);
void table_cleanup(struct LookupTable *ltable,
LookupTableIterator func, void *arg);
void table_walk_items(struct LookupTable *ltable,
LookupTableIterator func, void *arg);
void * table_get_info(struct LookupTable *ltable,
TableIndex index);
void table_get_key(struct LookupTable *ltable,
TableIndex index, void **pkey_ptr,
int *pkey_len);
void table_lock_enter(struct LookupTable *ltable);
void table_lock_exit(struct LookupTable *ltable);
#endif

View File

@ -1,134 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* JVMTI tag definitions. */
/*
* JVMTI tags are jlongs (64 bits) and how the hprof information is
* turned into a tag and/or extracted from a tag is here.
*
* Currently a special TAG_CHECK is placed in the high order 32 bits of
* the tag as a check.
*
*/
#include "hprof.h"
#define TAG_CHECK 0xfad4dead
jlong
tag_create(ObjectIndex object_index)
{
jlong tag;
HPROF_ASSERT(object_index != 0);
tag = TAG_CHECK;
tag = (tag << 32) | object_index;
return tag;
}
ObjectIndex
tag_extract(jlong tag)
{
HPROF_ASSERT(tag != (jlong)0);
if ( ((tag >> 32) & 0xFFFFFFFF) != TAG_CHECK) {
HPROF_ERROR(JNI_TRUE, "JVMTI tag value is not 0 and missing TAG_CHECK");
}
return (ObjectIndex)(tag & 0xFFFFFFFF);
}
/* Tag a new jobject */
void
tag_new_object(jobject object, ObjectKind kind, SerialNumber thread_serial_num,
jint size, SiteIndex site_index)
{
ObjectIndex object_index;
jlong tag;
HPROF_ASSERT(site_index!=0);
/* New object for this site. */
object_index = object_new(site_index, size, kind, thread_serial_num);
/* Create and set the tag. */
tag = tag_create(object_index);
setTag(object, tag);
LOG3("tag_new_object", "tag", (int)tag);
}
/* Tag a jclass jobject if it hasn't been tagged. */
void
tag_class(JNIEnv *env, jclass klass, ClassIndex cnum,
SerialNumber thread_serial_num, SiteIndex site_index)
{
ObjectIndex object_index;
/* If the ClassIndex has an ObjectIndex, then we have tagged it. */
object_index = class_get_object_index(cnum);
if ( object_index == 0 ) {
jint size;
jlong tag;
HPROF_ASSERT(site_index!=0);
/* If we don't know the size of a java.lang.Class object, get it */
size = gdata->system_class_size;
if ( size == 0 ) {
size = (jint)getObjectSize(klass);
gdata->system_class_size = size;
}
/* Tag this java.lang.Class object if it hasn't been already */
tag = getTag(klass);
if ( tag == (jlong)0 ) {
/* New object for this site. */
object_index = object_new(site_index, size, OBJECT_CLASS,
thread_serial_num);
/* Create and set the tag. */
tag = tag_create(object_index);
setTag(klass, tag);
} else {
/* Get the ObjectIndex from the tag. */
object_index = tag_extract(tag);
}
/* Record this object index in the Class table */
class_set_object_index(cnum, object_index);
}
}

View File

@ -1,53 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_TAG_H
#define HPROF_TAG_H
jlong tag_create(ObjectIndex object_index);
ObjectIndex tag_extract(jlong tag);
void tag_new_object(jobject object, ObjectKind kind,
SerialNumber thread_serial_num,
jint size, SiteIndex site_index);
void tag_class(JNIEnv *env, jclass klass, ClassIndex cnum,
SerialNumber thread_serial_num, SiteIndex site_index);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_TLS_H
#define HPROF_TLS_H
void tls_init(void);
TlsIndex tls_find_or_create(JNIEnv *env, jthread thread);
void tls_agent_thread(JNIEnv *env, jthread thread);
SerialNumber tls_get_thread_serial_number(TlsIndex index);
void tls_list(void);
void tls_delete_global_references(JNIEnv *env);
void tls_garbage_collect(JNIEnv *env);
void tls_cleanup(void);
void tls_thread_ended(JNIEnv *env, TlsIndex index);
void tls_sample_all_threads(JNIEnv *env);
MonitorIndex tls_get_monitor(TlsIndex index);
void tls_set_monitor(TlsIndex index, MonitorIndex monitor_index);
void tls_set_thread_object_index(TlsIndex index,
ObjectIndex thread_object_index);
jint tls_get_tracker_status(JNIEnv *env, jthread thread,
jboolean skip_init, jint **ppstatus, TlsIndex* pindex,
SerialNumber *pthread_serial_num,
TraceIndex *ptrace_index);
void tls_set_sample_status(ObjectIndex object_index, jint sample_status);
jint tls_sum_sample_status(void);
void tls_dump_traces(JNIEnv *env);
void tls_monitor_start_timer(TlsIndex index);
jlong tls_monitor_stop_timer(TlsIndex index);
void tls_dump_monitor_state(JNIEnv *env);
void tls_push_method(TlsIndex index, jmethodID method);
void tls_pop_method(TlsIndex index, jthread thread, jmethodID method);
void tls_pop_exception_catch(TlsIndex index, jthread thread, jmethodID method);
TraceIndex tls_get_trace(TlsIndex index, JNIEnv *env,
int depth, jboolean skip_init);
void tls_set_in_heap_dump(TlsIndex index, jint in_heap_dump);
jint tls_get_in_heap_dump(TlsIndex index);
void tls_clear_in_heap_dump(void);
TlsIndex tls_find(SerialNumber thread_serial_num);
#endif

View File

@ -1,869 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Trace table. */
/*
* A trace is an optional thread serial number plus N frames.
*
* The thread serial number is added to the key only if the user asks for
* threads in traces, which will cause many more traces to be created.
* Without it all threads share the traces.
*
* This is a variable length Key, depending on the number of frames.
* The frames are FrameIndex values into the frame table.
*
* It is important that the thread serial number is used and not the
* TlsIndex, threads come and go, and TlsIndex values are re-used
* but the thread serial number is unique per thread.
*
* The cpu=times and cpu=samples dumps rely heavily on traces, the trace
* dump preceeds the cpu information and uses the trace information.
* Depending on the cpu= request, different sorts are applied to the
* traces that are dumped.
*
*/
#include "hprof.h"
typedef struct TraceKey {
SerialNumber thread_serial_num; /* Thread serial number */
short n_frames; /* Number of frames that follow. */
jvmtiPhase phase : 8; /* Makes some traces unique */
FrameIndex frames[1]; /* Variable length */
} TraceKey;
typedef struct TraceInfo {
SerialNumber serial_num; /* Trace serial number */
jint num_hits; /* Number of hits this trace has */
jlong total_cost; /* Total cost associated with trace */
jlong self_cost; /* Total cost without children cost */
jint status; /* Status of dump of trace */
} TraceInfo;
typedef struct IterateInfo {
TraceIndex* traces;
int count;
jlong grand_total_cost;
} IterateInfo;
/* Private internal functions. */
static TraceKey*
get_pkey(TraceIndex index)
{
void * pkey;
int key_len;
table_get_key(gdata->trace_table, index, &pkey, &key_len);
HPROF_ASSERT(pkey!=NULL);
HPROF_ASSERT(key_len>=(int)sizeof(TraceKey));
HPROF_ASSERT(((TraceKey*)pkey)->n_frames<=1?key_len==(int)sizeof(TraceKey) :
key_len==(int)sizeof(TraceKey)+
(int)sizeof(FrameIndex)*(((TraceKey*)pkey)->n_frames-1));
return (TraceKey*)pkey;
}
static TraceInfo *
get_info(TraceIndex index)
{
TraceInfo * info;
info = (TraceInfo*)table_get_info(gdata->trace_table, index);
return info;
}
static TraceIndex
find_or_create(SerialNumber thread_serial_num, jint n_frames,
FrameIndex *frames, jvmtiPhase phase, TraceKey *trace_key_buffer)
{
TraceInfo * info;
TraceKey * pkey;
int key_len;
TraceIndex index;
jboolean new_one;
static TraceKey empty_key;
HPROF_ASSERT(frames!=NULL);
HPROF_ASSERT(trace_key_buffer!=NULL);
key_len = (int)sizeof(TraceKey);
if ( n_frames > 1 ) {
key_len += (int)((n_frames-1)*(int)sizeof(FrameIndex));
}
pkey = trace_key_buffer;
*pkey = empty_key;
pkey->thread_serial_num = (gdata->thread_in_traces ? thread_serial_num : 0);
pkey->n_frames = (short)n_frames;
pkey->phase = phase;
if ( n_frames > 0 ) {
(void)memcpy(pkey->frames, frames, (n_frames*(int)sizeof(FrameIndex)));
}
new_one = JNI_FALSE;
index = table_find_or_create_entry(gdata->trace_table,
pkey, key_len, &new_one, NULL);
if ( new_one ) {
info = get_info(index);
info->serial_num = gdata->trace_serial_number_counter++;
}
return index;
}
static void
list_item(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
TraceInfo *info;
TraceKey *key;
int i;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len>0);
HPROF_ASSERT(info_ptr!=NULL);
key = (TraceKey*)key_ptr;
info = (TraceInfo *)info_ptr;
debug_message( "Trace 0x%08x: SN=%u, threadSN=%u, n_frames=%d, frames=(",
index,
info->serial_num,
key->thread_serial_num,
key->n_frames);
for ( i = 0 ; i < key->n_frames ; i++ ) {
debug_message( "0x%08x, ", key->frames[i]);
}
debug_message( "), traceSN=%u, num_hits=%d, self_cost=(%d,%d), "
"total_cost=(%d,%d), status=0x%08x\n",
info->serial_num,
info->num_hits,
jlong_high(info->self_cost),
jlong_low(info->self_cost),
jlong_high(info->total_cost),
jlong_low(info->total_cost),
info->status);
}
static void
clear_cost(TableIndex i, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
TraceInfo *info;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len>0);
HPROF_ASSERT(info_ptr!=NULL);
info = (TraceInfo *)info_ptr;
info->num_hits = 0;
info->total_cost = 0;
info->self_cost = 0;
}
/* Get the names for a frame in order to dump it. */
static void
get_frame_details(JNIEnv *env, FrameIndex frame_index,
SerialNumber *frame_serial_num, char **pcsig, ClassIndex *pcnum,
char **pmname, char **pmsig, char **psname, jint *plineno)
{
jmethodID method;
jlocation location;
jint lineno;
HPROF_ASSERT(frame_index!=0);
*pmname = NULL;
*pmsig = NULL;
*pcsig = NULL;
if ( psname != NULL ) {
*psname = NULL;
}
if ( plineno != NULL ) {
*plineno = -1;
}
if ( pcnum != NULL ) {
*pcnum = 0;
}
frame_get_location(frame_index, frame_serial_num, &method, &location, &lineno);
if ( plineno != NULL ) {
*plineno = lineno;
}
WITH_LOCAL_REFS(env, 1) {
jclass klass;
getMethodClass(method, &klass);
getClassSignature(klass, pcsig, NULL);
if ( pcnum != NULL ) {
LoaderIndex loader_index;
jobject loader;
loader = getClassLoader(klass);
loader_index = loader_find_or_create(env, loader);
*pcnum = class_find_or_create(*pcsig, loader_index);
(void)class_new_classref(env, *pcnum, klass);
}
if ( psname != NULL ) {
getSourceFileName(klass, psname);
}
} END_WITH_LOCAL_REFS;
getMethodName(method, pmname, pmsig);
}
/* Write out a stack trace. */
static void
output_trace(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
TraceKey *key;
TraceInfo *info;
SerialNumber serial_num;
SerialNumber thread_serial_num;
jint n_frames;
JNIEnv *env;
int i;
char *phase_str;
struct FrameNames {
SerialNumber serial_num;
char * sname;
char * csig;
char * mname;
int lineno;
} *finfo;
info = (TraceInfo*)info_ptr;
if ( info->status != 0 ) {
return;
}
env = (JNIEnv*)arg;
key = (TraceKey*)key_ptr;
thread_serial_num = key->thread_serial_num;
serial_num = info->serial_num;
info->status = 1;
finfo = NULL;
n_frames = (jint)key->n_frames;
if ( n_frames > 0 ) {
finfo = (struct FrameNames *)HPROF_MALLOC(n_frames*(int)sizeof(struct FrameNames));
/* Write frames, but save information for trace later */
for (i = 0; i < n_frames; i++) {
FrameIndex frame_index;
char *msig;
ClassIndex cnum;
frame_index = key->frames[i];
get_frame_details(env, frame_index, &finfo[i].serial_num,
&finfo[i].csig, &cnum,
&finfo[i].mname, &msig, &finfo[i].sname, &finfo[i].lineno);
if (frame_get_status(frame_index) == 0) {
io_write_frame(frame_index, finfo[i].serial_num,
finfo[i].mname, msig,
finfo[i].sname, class_get_serial_number(cnum),
finfo[i].lineno);
frame_set_status(frame_index, 1);
}
jvmtiDeallocate(msig);
}
}
/* Find phase string */
if ( key->phase == JVMTI_PHASE_LIVE ) {
phase_str = NULL; /* Normal trace, no phase annotation */
} else {
phase_str = phaseString(key->phase);
}
io_write_trace_header(serial_num, thread_serial_num, n_frames, phase_str);
for (i = 0; i < n_frames; i++) {
io_write_trace_elem(serial_num, key->frames[i], finfo[i].serial_num,
finfo[i].csig,
finfo[i].mname, finfo[i].sname, finfo[i].lineno);
jvmtiDeallocate(finfo[i].csig);
jvmtiDeallocate(finfo[i].mname);
jvmtiDeallocate(finfo[i].sname);
}
io_write_trace_footer(serial_num, thread_serial_num, n_frames);
if ( finfo != NULL ) {
HPROF_FREE(finfo);
}
}
/* Output a specific list of traces. */
static void
output_list(JNIEnv *env, TraceIndex *list, jint count)
{
rawMonitorEnter(gdata->data_access_lock); {
int i;
for ( i = 0; i < count ; i++ ) {
TraceIndex index;
TraceInfo *info;
void * pkey;
int key_len;
index = list[i];
table_get_key(gdata->trace_table, index, &pkey, &key_len);
info = get_info(index);
output_trace(index, pkey, key_len, info, (void*)env);
}
} rawMonitorExit(gdata->data_access_lock);
}
static void
collect_iterator(TableIndex index, void *key_ptr, int key_len, void *info_ptr, void *arg)
{
TraceInfo *info;
IterateInfo *iterate;
HPROF_ASSERT(key_ptr!=NULL);
HPROF_ASSERT(key_len>0);
HPROF_ASSERT(arg!=NULL);
HPROF_ASSERT(info_ptr!=NULL);
iterate = (IterateInfo *)arg;
info = (TraceInfo *)info_ptr;
iterate->traces[iterate->count++] = index;
iterate->grand_total_cost += info->self_cost;
}
static int
qsort_compare_cost(const void *p_trace1, const void *p_trace2)
{
TraceIndex trace1;
TraceIndex trace2;
TraceInfo * info1;
TraceInfo * info2;
HPROF_ASSERT(p_trace1!=NULL);
HPROF_ASSERT(p_trace2!=NULL);
trace1 = *(TraceIndex *)p_trace1;
trace2 = *(TraceIndex *)p_trace2;
info1 = get_info(trace1);
info2 = get_info(trace2);
/*LINTED*/
return (int)(info2->self_cost - info1->self_cost);
}
static int
qsort_compare_num_hits(const void *p_trace1, const void *p_trace2)
{
TraceIndex trace1;
TraceIndex trace2;
TraceInfo * info1;
TraceInfo * info2;
HPROF_ASSERT(p_trace1!=NULL);
HPROF_ASSERT(p_trace2!=NULL);
trace1 = *(TraceIndex *)p_trace1;
trace2 = *(TraceIndex *)p_trace2;
info1 = get_info(trace1);
info2 = get_info(trace2);
return info2->num_hits - info1->num_hits;
}
/* External interfaces. */
void
trace_init(void)
{
gdata->trace_table = table_initialize("Trace",
256, 256, 511, (int)sizeof(TraceInfo));
}
void
trace_list(void)
{
debug_message(
"--------------------- Trace Table ------------------------\n");
table_walk_items(gdata->trace_table, &list_item, NULL);
debug_message(
"----------------------------------------------------------\n");
}
void
trace_cleanup(void)
{
table_cleanup(gdata->trace_table, NULL, NULL);
gdata->trace_table = NULL;
}
SerialNumber
trace_get_serial_number(TraceIndex index)
{
TraceInfo *info;
if ( index == 0 ) {
return 0;
}
info = get_info(index);
return info->serial_num;
}
void
trace_increment_cost(TraceIndex index, jint num_hits, jlong self_cost, jlong total_cost)
{
TraceInfo *info;
table_lock_enter(gdata->trace_table); {
info = get_info(index);
info->num_hits += num_hits;
info->self_cost += self_cost;
info->total_cost += total_cost;
} table_lock_exit(gdata->trace_table);
}
TraceIndex
trace_find_or_create(SerialNumber thread_serial_num, jint n_frames, FrameIndex *frames, jvmtiFrameInfo *jframes_buffer)
{
return find_or_create(thread_serial_num, n_frames, frames, getPhase(),
(TraceKey*)jframes_buffer);
}
/* We may need to ask for more frames than the user asked for */
static int
get_real_depth(int depth, jboolean skip_init)
{
int extra_frames;
extra_frames = 0;
/* This is only needed if we are doing BCI */
if ( gdata->bci && depth > 0 ) {
/* Account for Java and native Tracker methods */
extra_frames = 2;
if ( skip_init ) {
/* Also allow for ignoring the java.lang.Object.<init> method */
extra_frames += 1;
}
}
return depth + extra_frames;
}
/* Fill in FrameIndex array from jvmtiFrameInfo array, return n_frames */
static int
fill_frame_buffer(int depth, int real_depth,
int frame_count, jboolean skip_init,
jvmtiFrameInfo *jframes_buffer, FrameIndex *frames_buffer)
{
int n_frames;
jint topframe;
/* If real_depth is 0, just return 0 */
if ( real_depth == 0 ) {
return 0;
}
/* Assume top frame index is 0 for now */
topframe = 0;
/* Possible top frames belong to the hprof Tracker class, remove them */
if ( gdata->bci ) {
while ( ( ( frame_count - topframe ) > 0 ) &&
( topframe < (real_depth-depth) ) &&
( tracker_method(jframes_buffer[topframe].method) ||
( skip_init
&& jframes_buffer[topframe].method==gdata->object_init_method ) )
) {
topframe++;
}
}
/* Adjust count to match depth request */
if ( ( frame_count - topframe ) > depth ) {
frame_count = depth + topframe;
}
/* The actual frame count we will process */
n_frames = frame_count - topframe;
if ( n_frames > 0 ) {
int i;
for (i = 0; i < n_frames; i++) {
jmethodID method;
jlocation location;
method = jframes_buffer[i+topframe].method;
location = jframes_buffer[i+topframe].location;
frames_buffer[i] = frame_find_or_create(method, location);
}
}
return n_frames;
}
/* Get the trace for the supplied thread */
TraceIndex
trace_get_current(jthread thread, SerialNumber thread_serial_num,
int depth, jboolean skip_init,
FrameIndex *frames_buffer,
jvmtiFrameInfo *jframes_buffer)
{
TraceIndex index;
jint frame_count;
int real_depth;
int n_frames;
HPROF_ASSERT(thread!=NULL);
HPROF_ASSERT(frames_buffer!=NULL);
HPROF_ASSERT(jframes_buffer!=NULL);
/* We may need to ask for more frames than the user asked for */
real_depth = get_real_depth(depth, skip_init);
/* Get the stack trace for this one thread */
frame_count = 0;
if ( real_depth > 0 ) {
getStackTrace(thread, jframes_buffer, real_depth, &frame_count);
}
/* Create FrameIndex's */
n_frames = fill_frame_buffer(depth, real_depth, frame_count, skip_init,
jframes_buffer, frames_buffer);
/* Lookup or create new TraceIndex */
index = find_or_create(thread_serial_num, n_frames, frames_buffer,
getPhase(), (TraceKey*)jframes_buffer);
return index;
}
/* Get traces for all threads in list (traces[i]==0 if thread not running) */
void
trace_get_all_current(jint thread_count, jthread *threads,
SerialNumber *thread_serial_nums,
int depth, jboolean skip_init,
TraceIndex *traces, jboolean always_care)
{
jvmtiStackInfo *stack_info;
int nbytes;
int real_depth;
int i;
FrameIndex *frames_buffer;
TraceKey *trace_key_buffer;
jvmtiPhase phase;
HPROF_ASSERT(threads!=NULL);
HPROF_ASSERT(thread_serial_nums!=NULL);
HPROF_ASSERT(traces!=NULL);
HPROF_ASSERT(thread_count > 0);
/* Find out what the phase is for all these traces */
phase = getPhase();
/* We may need to ask for more frames than the user asked for */
real_depth = get_real_depth(depth, skip_init);
/* Get the stack traces for all the threads */
getThreadListStackTraces(thread_count, threads, real_depth, &stack_info);
/* Allocate a frames_buffer and trace key buffer */
nbytes = (int)sizeof(FrameIndex)*real_depth;
frames_buffer = (FrameIndex*)HPROF_MALLOC(nbytes);
nbytes += (int)sizeof(TraceKey);
trace_key_buffer = (TraceKey*)HPROF_MALLOC(nbytes);
/* Loop over the stack traces we have for these 'thread_count' threads */
for ( i = 0 ; i < thread_count ; i++ ) {
int n_frames;
/* Assume 0 at first (no trace) */
traces[i] = 0;
/* If thread has frames, is runnable, and isn't suspended, we care */
if ( always_care ||
( stack_info[i].frame_count > 0
&& (stack_info[i].state & JVMTI_THREAD_STATE_RUNNABLE)!=0
&& (stack_info[i].state & JVMTI_THREAD_STATE_SUSPENDED)==0
&& (stack_info[i].state & JVMTI_THREAD_STATE_INTERRUPTED)==0 )
) {
/* Create FrameIndex's */
n_frames = fill_frame_buffer(depth, real_depth,
stack_info[i].frame_count,
skip_init,
stack_info[i].frame_buffer,
frames_buffer);
/* Lookup or create new TraceIndex */
traces[i] = find_or_create(thread_serial_nums[i],
n_frames, frames_buffer, phase, trace_key_buffer);
}
}
/* Make sure we free the space */
HPROF_FREE(frames_buffer);
HPROF_FREE(trace_key_buffer);
jvmtiDeallocate(stack_info);
}
/* Increment the trace costs for all the threads (for cpu=samples) */
void
trace_increment_all_sample_costs(jint thread_count, jthread *threads,
SerialNumber *thread_serial_nums,
int depth, jboolean skip_init)
{
TraceIndex *traces;
int nbytes;
HPROF_ASSERT(threads!=NULL);
HPROF_ASSERT(thread_serial_nums!=NULL);
HPROF_ASSERT(thread_count > 0);
HPROF_ASSERT(depth >= 0);
if ( depth == 0 ) {
return;
}
/* Allocate a traces array */
nbytes = (int)sizeof(TraceIndex)*thread_count;
traces = (TraceIndex*)HPROF_MALLOC(nbytes);
/* Get all the current traces for these threads */
trace_get_all_current(thread_count, threads, thread_serial_nums,
depth, skip_init, traces, JNI_FALSE);
/* Increment the cpu=samples cost on these traces */
table_lock_enter(gdata->trace_table); {
int i;
for ( i = 0 ; i < thread_count ; i++ ) {
/* Each trace gets a hit and an increment of it's total cost */
if ( traces[i] != 0 ) {
TraceInfo *info;
info = get_info(traces[i]);
info->num_hits += 1;
info->self_cost += (jlong)1;
info->total_cost += (jlong)1;
}
}
} table_lock_exit(gdata->trace_table);
/* Free up the memory allocated */
HPROF_FREE(traces);
}
void
trace_output_unmarked(JNIEnv *env)
{
rawMonitorEnter(gdata->data_access_lock); {
table_walk_items(gdata->trace_table, &output_trace, (void*)env);
} rawMonitorExit(gdata->data_access_lock);
}
/* output info on the cost associated with traces */
void
trace_output_cost(JNIEnv *env, double cutoff)
{
IterateInfo iterate;
int i, trace_table_size, n_items;
double accum;
int n_entries;
rawMonitorEnter(gdata->data_access_lock); {
n_entries = table_element_count(gdata->trace_table);
iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
iterate.count = 0;
iterate.grand_total_cost = 0;
table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
trace_table_size = iterate.count;
/* sort all the traces according to the cost */
qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
&qsort_compare_cost);
n_items = 0;
for (i = 0; i < trace_table_size; i++) {
TraceInfo *info;
TraceIndex trace_index;
double percent;
trace_index = iterate.traces[i];
info = get_info(trace_index);
/* As soon as a trace with zero hits is seen, we need no others */
if (info->num_hits == 0 ) {
break;
}
percent = (double)info->self_cost / (double)iterate.grand_total_cost;
if (percent < cutoff) {
break;
}
n_items++;
}
/* Now write all trace we might refer to. */
output_list(env, iterate.traces, n_items);
io_write_cpu_samples_header(iterate.grand_total_cost, n_items);
accum = 0;
for (i = 0; i < n_items; i++) {
SerialNumber frame_serial_num;
TraceInfo *info;
TraceKey *key;
TraceIndex trace_index;
double percent;
char *csig;
char *mname;
char *msig;
trace_index = iterate.traces[i];
info = get_info(trace_index);
key = get_pkey(trace_index);
percent = ((double)info->self_cost / (double)iterate.grand_total_cost) * 100.0;
accum += percent;
csig = NULL;
mname = NULL;
msig = NULL;
if (key->n_frames > 0) {
get_frame_details(env, key->frames[0], &frame_serial_num,
&csig, NULL, &mname, &msig, NULL, NULL);
}
io_write_cpu_samples_elem(i+1, percent, accum, info->num_hits,
(jint)info->self_cost, info->serial_num,
key->n_frames, csig, mname);
jvmtiDeallocate(csig);
jvmtiDeallocate(mname);
jvmtiDeallocate(msig);
}
io_write_cpu_samples_footer();
HPROF_FREE(iterate.traces);
} rawMonitorExit(gdata->data_access_lock);
}
/* output the trace cost in old prof format */
void
trace_output_cost_in_prof_format(JNIEnv *env)
{
IterateInfo iterate;
int i, trace_table_size;
int n_entries;
rawMonitorEnter(gdata->data_access_lock); {
n_entries = table_element_count(gdata->trace_table);
iterate.traces = HPROF_MALLOC(n_entries*(int)sizeof(TraceIndex)+1);
iterate.count = 0;
iterate.grand_total_cost = 0;
table_walk_items(gdata->trace_table, &collect_iterator, &iterate);
trace_table_size = iterate.count;
/* sort all the traces according to the number of hits */
qsort(iterate.traces, trace_table_size, sizeof(TraceIndex),
&qsort_compare_num_hits);
io_write_oldprof_header();
for (i = 0; i < trace_table_size; i++) {
SerialNumber frame_serial_num;
TraceInfo *info;
TraceKey *key;
TraceIndex trace_index;
int num_frames;
int num_hits;
char *csig_callee;
char *mname_callee;
char *msig_callee;
char *csig_caller;
char *mname_caller;
char *msig_caller;
trace_index = iterate.traces[i];
key = get_pkey(trace_index);
info = get_info(trace_index);
num_hits = info->num_hits;
if (num_hits == 0) {
break;
}
csig_callee = NULL;
mname_callee = NULL;
msig_callee = NULL;
csig_caller = NULL;
mname_caller = NULL;
msig_caller = NULL;
num_frames = (int)key->n_frames;
if (num_frames >= 1) {
get_frame_details(env, key->frames[0], &frame_serial_num,
&csig_callee, NULL,
&mname_callee, &msig_callee, NULL, NULL);
}
if (num_frames > 1) {
get_frame_details(env, key->frames[1], &frame_serial_num,
&csig_caller, NULL,
&mname_caller, &msig_caller, NULL, NULL);
}
io_write_oldprof_elem(info->num_hits, num_frames,
csig_callee, mname_callee, msig_callee,
csig_caller, mname_caller, msig_caller,
(int)info->total_cost);
jvmtiDeallocate(csig_callee);
jvmtiDeallocate(mname_callee);
jvmtiDeallocate(msig_callee);
jvmtiDeallocate(csig_caller);
jvmtiDeallocate(mname_caller);
jvmtiDeallocate(msig_caller);
}
io_write_oldprof_footer();
HPROF_FREE(iterate.traces);
} rawMonitorExit(gdata->data_access_lock);
}
void
trace_clear_cost(void)
{
table_walk_items(gdata->trace_table, &clear_cost, NULL);
}

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_TRACE_H
#define HPROF_TRACE_H
void trace_increment_all_sample_costs(jint count, jthread *threads,
SerialNumber *thread_serial_nums, int depth,
jboolean skip_init);
void trace_get_all_current(jint count, jthread *threads,
SerialNumber *thread_serial_nums, int depth,
jboolean skip_init, TraceIndex *traces,
jboolean always_care);
TraceIndex trace_get_current(jthread thread,
SerialNumber thread_serial_num, int depth,
jboolean skip_init,
FrameIndex *frames_buffer,
jvmtiFrameInfo *jframes_buffer);
void trace_init(void);
TraceIndex trace_find_or_create(SerialNumber thread_serial_num,
jint n_frames, FrameIndex *frames,
jvmtiFrameInfo *jframes_buffer);
SerialNumber trace_get_serial_number(TraceIndex index);
void trace_increment_cost(TraceIndex index,
jint num_hits, jlong self_cost, jlong total_cost);
void trace_list(void);
void trace_cleanup(void);
void trace_clear_cost(void);
void trace_output_unmarked(JNIEnv *env);
void trace_output_cost(JNIEnv *env, double cutoff);
void trace_output_cost_in_prof_format(JNIEnv *env);
#endif

View File

@ -1,320 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
/* Tracker class support functions. */
/*
* This file contains the native support calls for the Tracker
* class. These native methods are registered and not made extern.
* Tracking is engaged by using JNI to assign to a static field in the
* Tracker class.
*
* Just like JVMTI callbacks, it's best that we keep track of these so that
* when the VM_DEATH happens we know to wait for them to complete.
*
* This file also contains the functions that will initialize the Tracker
* interface for BCI and identify the Tracker methods to make sure
* they are not included in any stack traces obtained from JVMTI.
*
* RFE: The performance of the java injected code calling native methods
* could be an issue here, cpu=times seems to be the worst where
* a native call is made for entry and exit, even on the smallest
* Java method. The alternative would be to cache the data on
* the Java side, and either push it out to the native side, or
* use some kind of pull from the native side, or even using
* shared memory or a socket. However having said that, the
* current performance issues are more around sheer memory needed,
* and repeated calls to GetThreadCpuTime(), which is being investigated.
*
*/
#include "hprof.h"
/* Macros to surround tracker based callback code.
* Also see BEGIN_CALLBACK and END_CALLBACK in hprof_init.c.
* If the VM_DEATH callback is active in the begining, then this callback
* just blocks (it is assumed we don't want to return to the VM).
* If the VM_DEATH callback is active at the end, then this callback
* will notify the VM_DEATH callback if it's the last one.
*
* WARNING: No not 'return' or 'goto' out of the BEGIN_TRACKER_CALLBACK/END_TRACKER_CALLBACK
* block, this will mess up the count.
*/
#define BEGIN_TRACKER_CALLBACK() \
{ /* BEGIN OF TRACKER_CALLBACK */ \
jboolean bypass = JNI_TRUE; \
rawMonitorEnter(gdata->callbackLock); { \
if ( gdata->tracking_engaged != 0 ) { \
if (!gdata->vm_death_callback_active) { \
gdata->active_callbacks++; \
bypass = JNI_FALSE; \
} \
} \
} rawMonitorExit(gdata->callbackLock); \
if ( !bypass ) { \
/* BODY OF TRACKER_CALLBACK CODE */
#define END_TRACKER_CALLBACK() /* Part of bypass if body */ \
rawMonitorEnter(gdata->callbackLock); { \
gdata->active_callbacks--; \
if (gdata->active_callbacks < 0) { \
HPROF_ERROR(JNI_TRUE, "Problems tracking callbacks"); \
} \
if (gdata->vm_death_callback_active) { \
if (gdata->active_callbacks == 0) { \
rawMonitorNotifyAll(gdata->callbackLock); \
} \
} \
} rawMonitorExit(gdata->callbackLock); \
} \
} /* END OF TRACKER_CALLBACK */
/*
* Class: Tracker
* Method: nativeNewArray
* Signature: (Ljava/lang/Object;Ljava/lang/Object;)V
*/
static void JNICALL
Tracker_nativeNewArray
(JNIEnv *env, jclass clazz, jobject thread, jobject obj)
{
BEGIN_TRACKER_CALLBACK() {
event_newarray(env, thread, obj);
} END_TRACKER_CALLBACK();
}
/*
* Class: Tracker
* Method: nativeObjectInit
* Signature: (Ljava/lang/Object;Ljava/lang/Object;)V
*/
static void JNICALL
Tracker_nativeObjectInit
(JNIEnv *env, jclass clazz, jobject thread, jobject obj)
{
BEGIN_TRACKER_CALLBACK() {
event_object_init(env, thread, obj);
} END_TRACKER_CALLBACK();
}
/*
* Class: Tracker
* Method: nativeCallSite
* Signature: (Ljava/lang/Object;II)V
*/
static void JNICALL
Tracker_nativeCallSite
(JNIEnv *env, jclass clazz, jobject thread, jint cnum, jint mnum)
{
BEGIN_TRACKER_CALLBACK() {
event_call(env, thread, cnum, mnum);
} END_TRACKER_CALLBACK();
}
/*
* Class: Tracker
* Method: nativeReturnSite
* Signature: (Ljava/lang/Object;II)V
*/
static void JNICALL
Tracker_nativeReturnSite
(JNIEnv *env, jclass clazz, jobject thread, jint cnum, jint mnum)
{
BEGIN_TRACKER_CALLBACK() {
event_return(env, thread, cnum, mnum);
} END_TRACKER_CALLBACK();
}
/* ------------------------------------------------------------------- */
/* Set Java static field to turn on native code calls in Tracker. */
static void
set_engaged(JNIEnv *env, jint engaged)
{
LOG3("set_engaged()", "engaging tracking", engaged);
if ( ! gdata->bci ) {
return;
}
rawMonitorEnter(gdata->callbackLock); {
if ( gdata->tracking_engaged != engaged ) {
jfieldID field;
jclass tracker_class;
tracker_class = class_get_class(env, gdata->tracker_cnum);
gdata->tracking_engaged = 0;
/* Activate or deactivate the injection code on the Java side */
HPROF_ASSERT(tracker_class!=NULL);
exceptionClear(env);
field = getStaticFieldID(env, tracker_class,
TRACKER_ENGAGED_NAME, TRACKER_ENGAGED_SIG);
setStaticIntField(env, tracker_class, field, engaged);
exceptionClear(env);
LOG3("set_engaged()", "tracking engaged", engaged);
gdata->tracking_engaged = engaged;
}
} rawMonitorExit(gdata->callbackLock);
}
void
tracker_engage(JNIEnv *env)
{
set_engaged(env, 0xFFFF);
}
void
tracker_disengage(JNIEnv *env)
{
set_engaged(env, 0);
}
jboolean
tracker_method(jmethodID method)
{
int i;
if ( ! gdata->bci ) {
return JNI_FALSE;
}
HPROF_ASSERT(method!=NULL);
HPROF_ASSERT(gdata->tracker_method_count > 0);
for ( i = 0 ; i < gdata->tracker_method_count ; i++ ) {
HPROF_ASSERT(gdata->tracker_methods[i].method!=NULL);
if ( method == gdata->tracker_methods[i].method ) {
return JNI_TRUE;
}
}
return JNI_FALSE;
}
static JNINativeMethod registry[4] =
{
{ TRACKER_NEWARRAY_NATIVE_NAME, TRACKER_NEWARRAY_NATIVE_SIG,
(void*)&Tracker_nativeNewArray },
{ TRACKER_OBJECT_INIT_NATIVE_NAME, TRACKER_OBJECT_INIT_NATIVE_SIG,
(void*)&Tracker_nativeObjectInit },
{ TRACKER_CALL_NATIVE_NAME, TRACKER_CALL_NATIVE_SIG,
(void*)&Tracker_nativeCallSite },
{ TRACKER_RETURN_NATIVE_NAME, TRACKER_RETURN_NATIVE_SIG,
(void*)&Tracker_nativeReturnSite }
};
static struct {
char *name;
char *sig;
} tracker_methods[] =
{
{ TRACKER_NEWARRAY_NAME, TRACKER_NEWARRAY_SIG },
{ TRACKER_OBJECT_INIT_NAME, TRACKER_OBJECT_INIT_SIG },
{ TRACKER_CALL_NAME, TRACKER_CALL_SIG },
{ TRACKER_RETURN_NAME, TRACKER_RETURN_SIG },
{ TRACKER_NEWARRAY_NATIVE_NAME, TRACKER_NEWARRAY_NATIVE_SIG },
{ TRACKER_OBJECT_INIT_NATIVE_NAME, TRACKER_OBJECT_INIT_NATIVE_SIG },
{ TRACKER_CALL_NATIVE_NAME, TRACKER_CALL_NATIVE_SIG },
{ TRACKER_RETURN_NATIVE_NAME, TRACKER_RETURN_NATIVE_SIG }
};
void
tracker_setup_class(void)
{
ClassIndex cnum;
LoaderIndex loader_index;
HPROF_ASSERT(gdata->tracker_cnum==0);
loader_index = loader_find_or_create(NULL,NULL);
cnum = class_find_or_create(TRACKER_CLASS_SIG, loader_index);
gdata->tracker_cnum = cnum;
HPROF_ASSERT(cnum!=0);
class_add_status(cnum, CLASS_SPECIAL);
}
void
tracker_setup_methods(JNIEnv *env)
{
ClassIndex cnum;
LoaderIndex loader_index;
int i;
jclass object_class;
jclass tracker_class;
if ( ! gdata->bci ) {
return;
}
loader_index = loader_find_or_create(NULL,NULL);
cnum = class_find_or_create(OBJECT_CLASS_SIG, loader_index);
object_class = class_get_class(env, cnum);
tracker_class = class_get_class(env, gdata->tracker_cnum);
CHECK_EXCEPTIONS(env) {
registerNatives(env, tracker_class, registry,
(int)sizeof(registry)/(int)sizeof(registry[0]));
} END_CHECK_EXCEPTIONS;
HPROF_ASSERT(tracker_class!=NULL);
gdata->tracker_method_count =
(int)sizeof(tracker_methods)/(int)sizeof(tracker_methods[0]);
HPROF_ASSERT(gdata->tracker_method_count <=
(int)(sizeof(gdata->tracker_methods)/sizeof(gdata->tracker_methods[0])));
CHECK_EXCEPTIONS(env) {
gdata->object_init_method = getMethodID(env, object_class,
OBJECT_INIT_NAME, OBJECT_INIT_SIG);
for ( i=0 ; i < gdata->tracker_method_count ; i++ ) {
gdata->tracker_methods[i].name =
string_find_or_create(tracker_methods[i].name);
gdata->tracker_methods[i].sig =
string_find_or_create(tracker_methods[i].sig);
gdata->tracker_methods[i].method =
getStaticMethodID(env, tracker_class,
tracker_methods[i].name, tracker_methods[i].sig);
HPROF_ASSERT(gdata->tracker_methods[i].method!=NULL);
LOG2("tracker_setup_methods(): Found", tracker_methods[i].name);
}
} END_CHECK_EXCEPTIONS;
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_TRACKER_H
#define HPROF_TRACKER_H
/* The internal qualified classname */
#define OBJECT_CLASS_SIG "Ljava/lang/Object;"
#define OBJECT_INIT_NAME "<init>"
#define OBJECT_INIT_SIG "()V"
#define TRACKER_PACKAGE "com/sun/demo/jvmti/hprof"
#define TRACKER_CLASS_NAME TRACKER_PACKAGE "/Tracker"
#define TRACKER_CLASS_SIG "L" TRACKER_CLASS_NAME ";"
#define TRACKER_NEWARRAY_NAME "NewArray"
#define TRACKER_NEWARRAY_SIG "(Ljava/lang/Object;)V"
#define TRACKER_NEWARRAY_NATIVE_NAME "nativeNewArray"
#define TRACKER_NEWARRAY_NATIVE_SIG "(Ljava/lang/Object;Ljava/lang/Object;)V"
#define TRACKER_OBJECT_INIT_NAME "ObjectInit"
#define TRACKER_OBJECT_INIT_SIG "(Ljava/lang/Object;)V"
#define TRACKER_OBJECT_INIT_NATIVE_NAME "nativeObjectInit"
#define TRACKER_OBJECT_INIT_NATIVE_SIG "(Ljava/lang/Object;Ljava/lang/Object;)V"
#define TRACKER_CALL_NAME "CallSite"
#define TRACKER_CALL_SIG "(II)V"
#define TRACKER_CALL_NATIVE_NAME "nativeCallSite"
#define TRACKER_CALL_NATIVE_SIG "(Ljava/lang/Object;II)V"
#define TRACKER_RETURN_NAME "ReturnSite"
#define TRACKER_RETURN_SIG "(II)V"
#define TRACKER_RETURN_NATIVE_NAME "nativeReturnSite"
#define TRACKER_RETURN_NATIVE_SIG "(Ljava/lang/Object;II)V"
#define TRACKER_ENGAGED_NAME "engaged"
#define TRACKER_ENGAGED_SIG "I"
void tracker_setup_class(void);
void tracker_setup_methods(JNIEnv *env);
void tracker_engage(JNIEnv *env);
void tracker_disengage(JNIEnv *env);
jboolean tracker_method(jmethodID method);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,199 +0,0 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#ifndef HPROF_UTIL_H
#define HPROF_UTIL_H
/* Use THIS_FILE when it is available. */
#ifndef THIS_FILE
#define THIS_FILE __FILE__
#endif
/* Macros that protect code from accidently using a local ref improperly */
#define WITH_LOCAL_REFS(env, number) \
{ \
JNIEnv *_env = (env); \
pushLocalFrame(_env, number); \
{ /* BEGINNING OF WITH SCOPE */
#define END_WITH_LOCAL_REFS \
} /* END OF WITH SCOPE */ \
popLocalFrame(_env, NULL); \
}
/* Macro to check for exceptions after JNI calls. */
#define CHECK_EXCEPTIONS(env) \
{ \
JNIEnv *_env = (env); \
jobject _exception; \
_exception = exceptionOccurred(_env); \
if ( _exception != NULL ) { \
exceptionDescribe(_env); \
HPROF_ERROR(JNI_TRUE, "Unexpected Exception found beforehand");\
} \
{
#define END_CHECK_EXCEPTIONS \
} \
_exception = exceptionOccurred(_env); \
if ( _exception != NULL ) { \
exceptionDescribe(_env); \
HPROF_ERROR(JNI_TRUE, "Unexpected Exception found afterward");\
} \
}
JNIEnv * getEnv(void);
/* JNI support functions */
jobject newGlobalReference(JNIEnv *env, jobject object);
jobject newWeakGlobalReference(JNIEnv *env, jobject object);
void deleteGlobalReference(JNIEnv *env, jobject object);
jobject newLocalReference(JNIEnv *env, jobject object);
void deleteLocalReference(JNIEnv *env, jobject object);
void deleteWeakGlobalReference(JNIEnv *env, jobject object);
jclass getObjectClass(JNIEnv *env, jobject object);
jmethodID getMethodID(JNIEnv *env, jclass clazz, const char* name,
const char *sig);
jclass getSuperclass(JNIEnv *env, jclass klass);
jmethodID getStaticMethodID(JNIEnv *env, jclass clazz, const char* name,
const char *sig);
jfieldID getStaticFieldID(JNIEnv *env, jclass clazz, const char* name,
const char *sig);
jclass findClass(JNIEnv *env, const char *name);
void setStaticIntField(JNIEnv *env, jclass clazz, jfieldID field,
jint value);
jboolean isSameObject(JNIEnv *env, jobject o1, jobject o2);
void pushLocalFrame(JNIEnv *env, jint capacity);
void popLocalFrame(JNIEnv *env, jobject ret);
jobject exceptionOccurred(JNIEnv *env);
void exceptionDescribe(JNIEnv *env);
void exceptionClear(JNIEnv *env);
void registerNatives(JNIEnv *env, jclass clazz,
JNINativeMethod *methods, jint count);
/* More JVMTI support functions */
char * getErrorName(jvmtiError error_number);
jvmtiPhase getPhase(void);
char * phaseString(jvmtiPhase phase);
void disposeEnvironment(void);
jlong getObjectSize(jobject object);
jobject getClassLoader(jclass klass);
jint getClassStatus(jclass klass);
jlong getTag(jobject object);
void setTag(jobject object, jlong tag);
void getObjectMonitorUsage(jobject object, jvmtiMonitorUsage *uinfo);
void getOwnedMonitorInfo(jthread thread, jobject **ppobjects,
jint *pcount);
void getSystemProperty(const char *name, char **value);
void getClassSignature(jclass klass, char**psignature,
char **pgeneric_signature);
void getSourceFileName(jclass klass, char** src_name_ptr);
jvmtiPrimitiveType sigToPrimType(char *sig);
int sigToPrimSize(char *sig);
char primTypeToSigChar(jvmtiPrimitiveType primType);
void getAllClassFieldInfo(JNIEnv *env, jclass klass,
jint* field_count_ptr, FieldInfo** fields_ptr);
void getMethodName(jmethodID method, char** name_ptr,
char** signature_ptr);
void getMethodClass(jmethodID method, jclass *pclazz);
jboolean isMethodNative(jmethodID method);
void getPotentialCapabilities(jvmtiCapabilities *capabilities);
void addCapabilities(jvmtiCapabilities *capabilities);
void setEventCallbacks(jvmtiEventCallbacks *pcallbacks);
void setEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event,
jthread thread);
void * getThreadLocalStorage(jthread thread);
void setThreadLocalStorage(jthread thread, void *ptr);
void getThreadState(jthread thread, jint *threadState);
void getThreadInfo(jthread thread, jvmtiThreadInfo *info);
void getThreadGroupInfo(jthreadGroup thread_group, jvmtiThreadGroupInfo *info);
void getLoadedClasses(jclass **ppclasses, jint *pcount);
jint getLineNumber(jmethodID method, jlocation location);
jlong getMaxMemory(JNIEnv *env);
void createAgentThread(JNIEnv *env, const char *name,
jvmtiStartFunction func);
jlong getThreadCpuTime(jthread thread);
void getStackTrace(jthread thread, jvmtiFrameInfo *pframes, jint depth,
jint *pcount);
void getThreadListStackTraces(jint count, jthread *threads,
jint depth, jvmtiStackInfo **stack_info);
void getFrameCount(jthread thread, jint *pcount);
void followReferences(jvmtiHeapCallbacks *pHeapCallbacks, void *user_data);
/* GC control */
void runGC(void);
/* Get initial JVMTI environment */
void getJvmti(void);
/* Get current runtime JVMTI version */
jint jvmtiVersion(void);
/* Raw monitor functions */
jrawMonitorID createRawMonitor(const char *str);
void rawMonitorEnter(jrawMonitorID m);
void rawMonitorWait(jrawMonitorID m, jlong pause_time);
void rawMonitorNotifyAll(jrawMonitorID m);
void rawMonitorExit(jrawMonitorID m);
void destroyRawMonitor(jrawMonitorID m);
/* JVMTI alloc/dealloc */
void * jvmtiAllocate(int size);
void jvmtiDeallocate(void *ptr);
/* System malloc/free */
void * hprof_malloc(int size);
void hprof_free(void *ptr);
#include "debug_malloc.h"
#ifdef DEBUG
void * hprof_debug_malloc(int size, char *file, int line);
void hprof_debug_free(void *ptr, char *file, int line);
#define HPROF_MALLOC(size) hprof_debug_malloc(size, THIS_FILE, __LINE__)
#define HPROF_FREE(ptr) hprof_debug_free(ptr, THIS_FILE, __LINE__)
#else
#define HPROF_MALLOC(size) hprof_malloc(size)
#define HPROF_FREE(ptr) hprof_free(ptr)
#endif
#endif

View File

@ -1,86 +0,0 @@
Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of Oracle nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Header for -agentlib:hprof (or -Xrunhprof) ASCII Output (JDK 5.0 JVMTI based)
WARNING! This file format is under development, and is subject to
change without notice.
This file contains the following types of records:
THREAD START
THREAD END mark the lifetime of Java threads
TRACE represents a Java stack trace. Each trace consists
of a series of stack frames. Other records refer to
TRACEs to identify (1) where object allocations have
taken place, (2) the frames in which GC roots were
found, and (3) frequently executed methods.
HEAP DUMP is a complete snapshot of all live objects in the Java
heap. Following distinctions are made:
ROOT root set as determined by GC
CLS classes
OBJ instances
ARR arrays
SITES is a sorted list of allocation sites. This identifies
the most heavily allocated object types, and the TRACE
at which those allocations occurred.
CPU SAMPLES is a statistical profile of program execution. The VM
periodically samples all running threads, and assigns
a quantum to active TRACEs in those threads. Entries
in this record are TRACEs ranked by the percentage of
total quanta they consumed; top-ranked TRACEs are
typically hot spots in the program.
CPU TIME is a profile of program execution obtained by measuring
the time spent in individual methods (excluding the time
spent in callees), as well as by counting the number of
times each method is called. Entries in this record are
TRACEs ranked by the percentage of total CPU time. The
"count" field indicates the number of times each TRACE
is invoked.
MONITOR TIME is a profile of monitor contention obtained by measuring
the time spent by a thread waiting to enter a monitor.
Entries in this record are TRACEs ranked by the percentage
of total monitor contention time and a brief description
of the monitor. The "count" field indicates the number of
times the monitor was contended at that TRACE.
MONITOR DUMP is a complete snapshot of all the monitors and threads in
the System.
HEAP DUMP, SITES, CPU SAMPLES|TIME and MONITOR DUMP|TIME records are generated
at program exit. They can also be obtained during program execution by typing
Ctrl-\ (on Solaris) or by typing Ctrl-Break (on Win32).

File diff suppressed because it is too large Load Diff

View File

@ -1,453 +0,0 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) && !defined(AIX)
#include <procfs.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <time.h>
#include "jni.h"
#include "jvm_md.h"
#include "hprof.h"
#ifdef AIX
#include "porting_aix.h" /* For the 'dladdr' function. */
#endif
int
md_getpid(void)
{
static int pid = -1;
if ( pid >= 0 ) {
return pid;
}
pid = getpid();
return pid;
}
void
md_sleep(unsigned seconds)
{
sleep(seconds);
}
void
md_init(void)
{
#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX)
/* No Hi-Res timer option? */
#else
if ( gdata->micro_state_accounting ) {
char proc_ctl_fn[48];
int procfd;
/* Turn on micro state accounting, once per process */
(void)md_snprintf(proc_ctl_fn, sizeof(proc_ctl_fn),
"/proc/%d/ctl", md_getpid());
procfd = open(proc_ctl_fn, O_WRONLY);
if (procfd >= 0) {
long ctl_op[2];
ctl_op[0] = PCSET;
ctl_op[1] = PR_MSACCT;
(void)write(procfd, ctl_op, sizeof(ctl_op));
(void)close(procfd);
}
}
#endif
}
int
md_connect(char *hostname, unsigned short port)
{
struct hostent *hentry;
struct sockaddr_in s;
int fd;
/* create a socket */
fd = socket(AF_INET, SOCK_STREAM, 0);
if ( fd < 0 ) {
return -1;
}
/* find remote host's addr from name */
if ((hentry = gethostbyname(hostname)) == NULL) {
(void)close(fd);
return -1;
}
(void)memset((char *)&s, 0, sizeof(s));
/* set remote host's addr; its already in network byte order */
(void)memcpy(&s.sin_addr.s_addr, *(hentry->h_addr_list),
(int)sizeof(s.sin_addr.s_addr));
/* set remote host's port */
s.sin_port = htons(port);
s.sin_family = AF_INET;
/* now try connecting */
if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
(void)close(fd);
return 0;
}
return fd;
}
int
md_recv(int f, char *buf, int len, int option)
{
return recv(f, buf, len, option);
}
int
md_shutdown(int filedes, int option)
{
return shutdown(filedes, option);
}
int
md_open(const char *filename)
{
return open(filename, O_RDONLY);
}
int
md_open_binary(const char *filename)
{
return md_open(filename);
}
int
md_creat(const char *filename)
{
return open(filename, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
int
md_creat_binary(const char *filename)
{
return md_creat(filename);
}
jlong
md_seek(int filedes, jlong cur)
{
jlong new_pos;
if ( cur == (jlong)-1 ) {
new_pos = lseek(filedes, 0, SEEK_END);
} else {
new_pos = lseek(filedes, cur, SEEK_SET);
}
return new_pos;
}
void
md_close(int filedes)
{
(void)close(filedes);
}
int
md_send(int s, const char *msg, int len, int flags)
{
int res;
do {
res = send(s, msg, len, flags);
} while ((res < 0) && (errno == EINTR));
return res;
}
int
md_write(int filedes, const void *buf, int nbyte)
{
int res;
do {
res = write(filedes, buf, nbyte);
} while ((res < 0) && (errno == EINTR));
return res;
}
int
md_read(int filedes, void *buf, int nbyte)
{
int res;
do {
res = read(filedes, buf, nbyte);
} while ((res < 0) && (errno == EINTR));
return res;
}
/* Time of day in milli-seconds */
static jlong
md_timeofday(void)
{
struct timeval tv;
if ( gettimeofday(&tv, (void *)0) != 0 ) {
return (jlong)0; /* EOVERFLOW ? */
}
/*LINTED*/
return ((jlong)tv.tv_sec * (jlong)1000) + (jlong)(tv.tv_usec / 1000);
}
/* Hi-res timer in micro-seconds */
jlong
md_get_microsecs(void)
{
#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX)
return (jlong)(md_timeofday() * (jlong)1000); /* Milli to micro */
#else
return (jlong)(gethrtime()/(hrtime_t)1000); /* Nano seconds to micro seconds */
#endif
}
/* Time of day in milli-seconds */
jlong
md_get_timemillis(void)
{
return md_timeofday();
}
/* Current CPU hi-res CPU time used */
jlong
md_get_thread_cpu_timemillis(void)
{
#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX)
return md_timeofday();
#else
return (jlong)(gethrvtime()/1000); /* Nano seconds to milli seconds */
#endif
}
void
md_get_prelude_path(char *path, int path_len, char *filename)
{
void *addr;
char libdir[FILENAME_MAX+1];
Dl_info dlinfo;
libdir[0] = 0;
addr = (void*)&md_get_prelude_path;
/* Use dladdr() to get the full path to libhprof.so, which we use to find
* the prelude file.
*/
dlinfo.dli_fname = NULL;
(void)dladdr(addr, &dlinfo);
if ( dlinfo.dli_fname != NULL ) {
char * lastSlash;
/* Full path to library name, need to move up one directory to 'lib' */
(void)strcpy(libdir, (char *)dlinfo.dli_fname);
lastSlash = strrchr(libdir, '/');
if ( lastSlash != NULL ) {
*lastSlash = '\0';
}
#ifndef __APPLE__
// not sure why other platforms have to go up two levels, but on macos we only need up one
lastSlash = strrchr(libdir, '/');
if ( lastSlash != NULL ) {
*lastSlash = '\0';
}
#endif /* __APPLE__ */
}
(void)snprintf(path, path_len, "%s/%s", libdir, filename);
}
int
md_vsnprintf(char *s, int n, const char *format, va_list ap)
{
return vsnprintf(s, n, format, ap);
}
int
md_snprintf(char *s, int n, const char *format, ...)
{
int ret;
va_list ap;
va_start(ap, format);
ret = md_vsnprintf(s, n, format, ap);
va_end(ap);
return ret;
}
void
md_system_error(char *buf, int len)
{
char *p;
buf[0] = 0;
p = strerror(errno);
if ( p != NULL ) {
(void)strcpy(buf, p);
}
}
unsigned
md_htons(unsigned short s)
{
return htons(s);
}
unsigned
md_htonl(unsigned l)
{
return htonl(l);
}
unsigned
md_ntohs(unsigned short s)
{
return ntohs(s);
}
unsigned
md_ntohl(unsigned l)
{
return ntohl(l);
}
static void dll_build_name(char* buffer, size_t buflen,
const char* paths, const char* fname) {
char *path, *paths_copy, *next_token;
paths_copy = strdup(paths);
if (paths_copy == NULL) {
return;
}
next_token = NULL;
path = strtok_r(paths_copy, ":", &next_token);
while (path != NULL) {
snprintf(buffer, buflen, "%s/lib%s" JNI_LIB_SUFFIX, path, fname);
if (access(buffer, F_OK) == 0) {
break;
}
*buffer = '\0';
path = strtok_r(NULL, ":", &next_token);
}
free(paths_copy);
}
/* Create the actual fill filename for a dynamic library. */
void
md_build_library_name(char *holder, int holderlen, const char *pname, const char *fname)
{
int pnamelen;
/* Length of options directory location. */
pnamelen = pname ? strlen(pname) : 0;
*holder = '\0';
/* Quietly truncate on buffer overflow. Should be an error. */
if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
return;
}
/* Construct path to library */
if (pnamelen == 0) {
(void)snprintf(holder, holderlen, "lib%s" JNI_LIB_SUFFIX, fname);
} else {
dll_build_name(holder, holderlen, pname, fname);
}
}
/* Load this library (return NULL on error, and error message in err_buf) */
void *
md_load_library(const char *name, char *err_buf, int err_buflen)
{
void * result;
result = dlopen(name, RTLD_LAZY);
if (result == NULL) {
(void)strncpy(err_buf, dlerror(), err_buflen-2);
err_buf[err_buflen-1] = '\0';
}
return result;
}
/* Unload this library */
void
md_unload_library(void *handle)
{
(void)dlclose(handle);
}
/* Find an entry point inside this library (return NULL if not found) */
void *
md_find_library_entry(void *handle, const char *name)
{
void * sym;
sym = dlsym(handle, name);
return sym;
}

View File

@ -1,450 +0,0 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
// To ensure winsock2.h is used, it has to be included ahead of
// windows.h, which includes winsock.h by default.
#include <winsock2.h>
#include <windows.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <mmsystem.h>
#include <fcntl.h>
#include <process.h>
#include "jni.h"
#include "hprof.h"
int
md_getpid(void)
{
static int pid = -1;
if ( pid >= 0 ) {
return pid;
}
pid = getpid();
return pid;
}
void
md_sleep(unsigned seconds)
{
Sleep((DWORD)seconds*1000);
}
void
md_init(void)
{
}
int
md_connect(char *hostname, unsigned short port)
{
struct hostent *hentry;
struct sockaddr_in s;
int fd;
/* find remote host's addr from name */
if ((hentry = gethostbyname(hostname)) == NULL) {
return -1;
}
(void)memset((char *)&s, 0, sizeof(s));
/* set remote host's addr; its already in network byte order */
(void)memcpy(&s.sin_addr.s_addr, *(hentry->h_addr_list),
(int)sizeof(s.sin_addr.s_addr));
/* set remote host's port */
s.sin_port = htons(port);
s.sin_family = AF_INET;
/* create a socket */
fd = (int)socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == fd) {
return 0;
}
/* now try connecting */
if (SOCKET_ERROR == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
closesocket(fd);
return 0;
}
return fd;
}
int
md_recv(int f, char *buf, int len, int option)
{
return recv(f, buf, len, option);
}
int
md_shutdown(int filedes, int option)
{
return shutdown(filedes, option);
}
int
md_open(const char *filename)
{
return open(filename, O_RDONLY);
}
int
md_open_binary(const char *filename)
{
return open(filename, O_RDONLY|O_BINARY);
}
int
md_creat(const char *filename)
{
return open(filename, O_CREAT | O_WRONLY | O_TRUNC,
_S_IREAD | _S_IWRITE);
}
int
md_creat_binary(const char *filename)
{
return open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
_S_IREAD | _S_IWRITE);
}
jlong
md_seek(int filedes, jlong pos)
{
jlong new_pos;
if ( pos == (jlong)-1 ) {
new_pos = _lseeki64(filedes, 0L, SEEK_END);
} else {
new_pos = _lseeki64(filedes, pos, SEEK_SET);
}
return new_pos;
}
void
md_close(int filedes)
{
(void)closesocket(filedes);
}
int
md_send(int s, const char *msg, int len, int flags)
{
return send(s, msg, len, flags);
}
int
md_read(int filedes, void *buf, int nbyte)
{
return read(filedes, buf, nbyte);
}
int
md_write(int filedes, const void *buf, int nbyte)
{
return write(filedes, buf, nbyte);
}
jlong
md_get_microsecs(void)
{
return (jlong)(timeGetTime())*(jlong)1000;
}
#define FT2JLONG(ft) \
((jlong)(ft).dwHighDateTime << 32 | (jlong)(ft).dwLowDateTime)
jlong
md_get_timemillis(void)
{
static jlong fileTime_1_1_70 = 0;
SYSTEMTIME st0;
FILETIME ft0;
if (fileTime_1_1_70 == 0) {
/* Initialize fileTime_1_1_70 -- the Win32 file time of midnight
* 1/1/70.
*/
memset(&st0, 0, sizeof(st0));
st0.wYear = 1970;
st0.wMonth = 1;
st0.wDay = 1;
SystemTimeToFileTime(&st0, &ft0);
fileTime_1_1_70 = FT2JLONG(ft0);
}
GetSystemTime(&st0);
SystemTimeToFileTime(&st0, &ft0);
return (FT2JLONG(ft0) - fileTime_1_1_70) / 10000;
}
jlong
md_get_thread_cpu_timemillis(void)
{
return md_get_timemillis();
}
HINSTANCE hJavaInst;
static int nError = 0;
BOOL WINAPI
DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
WSADATA wsaData;
switch (reason) {
case DLL_PROCESS_ATTACH:
hJavaInst = hinst;
nError = WSAStartup(MAKEWORD(2,0), &wsaData);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
hJavaInst = NULL;
default:
break;
}
return TRUE;
}
void
md_get_prelude_path(char *path, int path_len, char *filename)
{
char libdir[FILENAME_MAX+1];
char *lastSlash;
GetModuleFileName(hJavaInst, libdir, FILENAME_MAX);
/* This is actually in the bin directory, so move above bin for lib */
lastSlash = strrchr(libdir, '\\');
if ( lastSlash != NULL ) {
*lastSlash = '\0';
}
lastSlash = strrchr(libdir, '\\');
if ( lastSlash != NULL ) {
*lastSlash = '\0';
}
(void)md_snprintf(path, path_len, "%s\\lib\\%s", libdir, filename);
}
int
md_vsnprintf(char *s, int n, const char *format, va_list ap)
{
return _vsnprintf(s, n, format, ap);
}
int
md_snprintf(char *s, int n, const char *format, ...)
{
int ret;
va_list ap;
va_start(ap, format);
ret = md_vsnprintf(s, n, format, ap);
va_end(ap);
return ret;
}
void
md_system_error(char *buf, int len)
{
long errval;
errval = GetLastError();
buf[0] = '\0';
if (errval != 0) {
int n;
n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errval,
0, buf, len, NULL);
if (n > 3) {
/* Drop final '.', CR, LF */
if (buf[n - 1] == '\n') n--;
if (buf[n - 1] == '\r') n--;
if (buf[n - 1] == '.') n--;
buf[n] = '\0';
}
}
}
unsigned
md_htons(unsigned short s)
{
return htons(s);
}
unsigned
md_htonl(unsigned l)
{
return htonl(l);
}
unsigned
md_ntohs(unsigned short s)
{
return ntohs(s);
}
unsigned
md_ntohl(unsigned l)
{
return ntohl(l);
}
static int
get_last_error_string(char *buf, int len)
{
long errval;
errval = GetLastError();
if (errval != 0) {
/* DOS error */
int n;
n = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errval,
0, buf, len, NULL);
if (n > 3) {
/* Drop final '.', CR, LF */
if (buf[n - 1] == '\n') n--;
if (buf[n - 1] == '\r') n--;
if (buf[n - 1] == '.') n--;
buf[n] = '\0';
}
return n;
}
if (errno != 0) {
/* C runtime error that has no corresponding DOS error code */
const char *s;
int n;
s = strerror(errno);
n = (int)strlen(s);
if (n >= len) {
n = len - 1;
}
(void)strncpy(buf, s, n);
buf[n] = '\0';
return n;
}
return 0;
}
static void dll_build_name(char* buffer, size_t buflen,
const char* paths, const char* fname) {
char *path, *paths_copy, *next_token;
paths_copy = strdup(paths);
if (paths_copy == NULL) {
return;
}
next_token = NULL;
path = strtok_s(paths_copy, ";", &next_token);
while (path != NULL) {
_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
if (_access(buffer, 0) == 0) {
break;
}
*buffer = '\0';
path = strtok_s(NULL, ";", &next_token);
}
free(paths_copy);
}
/* Build a machine dependent library name out of a path and file name. */
void
md_build_library_name(char *holder, int holderlen, const char *pname, const char *fname)
{
int pnamelen;
pnamelen = pname ? (int)strlen(pname) : 0;
*holder = '\0';
/* Quietly truncates on buffer overflow. Should be an error. */
if (pnamelen + strlen(fname) + 10 > (unsigned int)holderlen) {
return;
}
if (pnamelen == 0) {
sprintf(holder, "%s.dll", fname);
} else {
dll_build_name(holder, holderlen, pname, fname);
}
}
void *
md_load_library(const char * name, char *err_buf, int err_buflen)
{
void *result;
result = LoadLibrary(name);
if (result == NULL) {
/* Error message is pretty lame, try to make a better guess. */
long errcode;
errcode = GetLastError();
if (errcode == ERROR_MOD_NOT_FOUND) {
strncpy(err_buf, "Can't find dependent libraries", err_buflen-2);
err_buf[err_buflen-1] = '\0';
} else {
get_last_error_string(err_buf, err_buflen);
}
}
return result;
}
void
md_unload_library(void *handle)
{
FreeLibrary(handle);
}
void *
md_find_library_entry(void *handle, const char *name)
{
return GetProcAddress(handle, name);
}

View File

@ -110,7 +110,6 @@ public class CommandLineTests {
ps.println("pack.pass.file.2=java/lang/Object.class");
ps.println("pack.pass.file.3=java/lang/Throwable.class");
ps.println("pack.pass.file.4=java/lang/VerifyError.class");
ps.println("pack.pass.file.5=com/sun/demo/jvmti/hprof/Tracker.class");
} finally {
Utils.close(ps);
Utils.close(fos);