mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-28 19:20:33 +00:00
Merge
This commit is contained in:
commit
48c33a4389
@ -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
|
||||
|
||||
################################################################################
|
||||
@ -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)
|
||||
|
||||
################################################################################
|
||||
@ -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:
|
||||
*;
|
||||
};
|
||||
@ -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:
|
||||
*;
|
||||
};
|
||||
@ -19,7 +19,6 @@ java.xml.crypto
|
||||
jdk.charsets
|
||||
jdk.deploy
|
||||
jdk.deploy.osx
|
||||
jdk.hprof.agent
|
||||
jdk.httpserver
|
||||
jdk.jfr
|
||||
jdk.management
|
||||
|
||||
@ -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 ||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
--------
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
@ -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
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
@ -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
|
||||
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user