# HG changeset patch # User ghaug # Date 1527683171 -7200 # Wed May 30 14:26:11 2018 +0200 # Node ID 419b5367669f2328f940fbe43ea3877f145ec434 # Parent fd2fccf3b0792b392c4f286de253ea81c0ab5793 Thread Dump Extension (memory allocation) diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -197,6 +197,9 @@ ClassFileStream* old_stream = stream; + // increment counter + THREAD->statistic_info().incr_define_class_count(); + // Skip this processing for VM anonymous classes if (host_klass == NULL) { stream = check_class_file_load_hook(stream, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -661,6 +661,9 @@ product(bool, PrintCompilation, false, \ "Print compilations") \ \ + product(bool, PrintExtendedThreadInfo, false, \ + "Print more informatiuon in thread dump") \ + \ diagnostic(bool, TraceNMethodInstalls, false, \ "Trace nmethod installation") \ \ diff --git a/src/hotspot/share/runtime/osThread.cpp b/src/hotspot/share/runtime/osThread.cpp --- a/src/hotspot/share/runtime/osThread.cpp +++ b/src/hotspot/share/runtime/osThread.cpp @@ -40,6 +40,18 @@ // Printing void OSThread::print_on(outputStream *st) const { st->print("nid=0x%x ", thread_id()); + +#ifdef _AIX + if (PrintExtendedThreadInfo) { st->print("ktid=" UINT64_FORMAT " ", kernel_thread_id()); } +#endif + +#if defined(LINUX) || defined(BSD) + if (PrintExtendedThreadInfo) { st->print("pthread-id=0x%lx ", (unsigned long) pthread_id()); } +#endif +#if defined(__sun) + if (PrintExtendedThreadInfo) { st->print("lwp-id=0x%lx ", lwp_id()); } +#endif + switch (_state) { case ALLOCATED: st->print("allocated "); break; case INITIALIZED: st->print("initialized "); break; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -237,6 +237,9 @@ set_free_handle_block(NULL); set_last_handle_mark(NULL); + _statistic_info.setStartTime(os::javaTimeMillis()); + _statistic_info.setDefineClassCount(0); + // This initial value ==> never claimed. _oops_do_parity = 0; _threads_hazard_ptr = NULL; @@ -876,6 +879,21 @@ if (os::get_native_priority(this, &os_prio) == OS_OK) { st->print("os_prio=%d ", os_prio); } + + if (PrintExtendedThreadInfo && os::is_thread_cpu_time_supported()) { + st->print("cpu=%.2fms ", + os::thread_cpu_time(const_cast(this), true) / 1000000.0 + ); + st->print("elapsed=%.2fs ", + _statistic_info.getElepsedTime() / 1000.0); + } + + if (PrintExtendedThreadInfo && is_Java_thread()) { + jlong allocated_bytes = const_cast(this)->cooked_allocated_bytes(); + st->print("allocated=" JLONG_FORMAT "B ", allocated_bytes); + st->print("defined_classes=" INT64_FORMAT " ", _statistic_info.getDefineClassCount()); + } + st->print("tid=" INTPTR_FORMAT " ", p2i(this)); osthread()->print_on(st); } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -53,6 +53,7 @@ #if INCLUDE_JFR #include "jfr/support/jfrThreadExtension.hpp" #endif +#include "runtime/threadStatisticInfo.hpp" class SafeThreadsListPtr; @@ -339,6 +340,8 @@ jlong _allocated_bytes; // Cumulative number of bytes allocated on // the Java heap + ThreadStatisticInfo _statistic_info; // Statistic info about the thread + JFR_ONLY(DEFINE_THREAD_LOCAL_FIELD_JFR;) // Thread-local data for jfr int _vm_operation_started_count; // VM_Operation support @@ -517,6 +520,8 @@ void incr_allocated_bytes(jlong size) { _allocated_bytes += size; } inline jlong cooked_allocated_bytes(); + ThreadStatisticInfo& statistic_info() { return _statistic_info; } + JFR_ONLY(DEFINE_THREAD_LOCAL_ACCESSOR_JFR;) bool is_trace_suspend() { return (_suspend_flags & _trace_flag) != 0; } diff --git a/src/hotspot/share/runtime/threadStatisticInfo.hpp b/src/hotspot/share/runtime/threadStatisticInfo.hpp new file mode 100644 --- /dev/null +++ b/src/hotspot/share/runtime/threadStatisticInfo.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018 SAP SE. 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. + * + */ + +class ThreadStatisticInfo { + // The time stamp the thread was started. + uint64_t _start_time_stamp; + uint64_t _define_class_count; + +public: + uint64_t getStartTime() const { return _start_time_stamp; } + void setStartTime(uint64_t timeStamp) { _start_time_stamp = timeStamp; } + uint64_t getDefineClassCount() const { return _define_class_count; } + void setDefineClassCount(uint64_t defineClassCount) { _define_class_count = defineClassCount; } + void incr_define_class_count() { _define_class_count += 1; } + uint64_t getElepsedTime() const { return os::javaTimeMillis() - getStartTime(); } +}; diff --git a/src/hotspot/share/runtime/vm_operations.cpp b/src/hotspot/share/runtime/vm_operations.cpp --- a/src/hotspot/share/runtime/vm_operations.cpp +++ b/src/hotspot/share/runtime/vm_operations.cpp @@ -219,7 +219,17 @@ } void VM_PrintThreads::doit() { + bool need_reset = false; + if (_extended_thread_info && FLAG_IS_DEFAULT(PrintExtendedThreadInfo) && !PrintExtendedThreadInfo) { + need_reset = true; + FLAG_SET_DEFAULT(PrintExtendedThreadInfo, true); + } + Threads::print_on(_out, true, false, _print_concurrent_locks); + + if (need_reset) { + FLAG_SET_DEFAULT(PrintExtendedThreadInfo, false); + } } void VM_PrintThreads::doit_epilogue() { diff --git a/src/hotspot/share/runtime/vm_operations.hpp b/src/hotspot/share/runtime/vm_operations.hpp --- a/src/hotspot/share/runtime/vm_operations.hpp +++ b/src/hotspot/share/runtime/vm_operations.hpp @@ -370,10 +370,14 @@ private: outputStream* _out; bool _print_concurrent_locks; + bool _extended_thread_info; public: - VM_PrintThreads() { _out = tty; _print_concurrent_locks = PrintConcurrentLocks; } - VM_PrintThreads(outputStream* out, bool print_concurrent_locks) { _out = out; _print_concurrent_locks = print_concurrent_locks; } - VMOp_Type type() const { return VMOp_PrintThreads; } + VM_PrintThreads() + { _out = tty; _print_concurrent_locks = PrintConcurrentLocks; ; _extended_thread_info = false; } + VM_PrintThreads(outputStream* out, bool print_concurrent_locks, bool extended_thread_info) + { _out = out; _print_concurrent_locks = print_concurrent_locks; _extended_thread_info = extended_thread_info; } + VMOp_Type type() const + { return VMOp_PrintThreads; } void doit(); bool doit_prologue(); void doit_epilogue(); diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -168,12 +168,20 @@ // static jint thread_dump(AttachOperation* op, outputStream* out) { bool print_concurrent_locks = false; - if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) { - print_concurrent_locks = true; + bool extended_thread_info = false; + if (op->arg(0) != NULL) { + for (int i = 0; op->arg(0)[i] != 0; ++i) { + if (op->arg(0)[i] == 'l') { + print_concurrent_locks = true; + } + if (op->arg(0)[i] == 'e') { + extended_thread_info = true; + } + } } // thread stacks - VM_PrintThreads op1(out, print_concurrent_locks); + VM_PrintThreads op1(out, print_concurrent_locks, extended_thread_info); VMThread::execute(&op1); // JNI global handles diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -610,13 +610,15 @@ ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), - _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") { + _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false"), + _extended("-e", "print extended thread information", "BOOLEAN", false, "false") { _dcmdparser.add_dcmd_option(&_locks); + _dcmdparser.add_dcmd_option(&_extended); } void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) { // thread stacks - VM_PrintThreads op1(output(), _locks.value()); + VM_PrintThreads op1(output(), _locks.value(), _extended.value()); VMThread::execute(&op1); // JNI global handles diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -446,6 +446,7 @@ class ThreadDumpDCmd : public DCmdWithParser { protected: DCmdArgument _locks; + DCmdArgument _extended; public: ThreadDumpDCmd(outputStream* output, bool heap); static const char* name() { return "Thread.print"; } diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java b/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java --- a/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java +++ b/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java @@ -48,6 +48,7 @@ checkForUnsupportedOptions(args); boolean locks = false; + boolean extended = false; // Parse the options (arguments starting with "-" ) int optionCount = 0; @@ -67,7 +68,11 @@ if (arg.equals("-l")) { locks = true; } else { - usage(1); + if (arg.equals("-e")) { + extended = true; + } else { + usage(1); + } } } optionCount++; @@ -81,12 +86,14 @@ // pass -l to thread dump operation to get extra lock info String pidArg = args[optionCount]; - String params[]; + String params[]= new String[] { "" }; + if (extended) { + params[0] += "-e "; + } if (locks) { - params = new String[] { "-l" }; - } else { - params = new String[0]; + params[0] += "-l"; } + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg); Collection pids = ap.getVirtualMachinePids(JStack.class); @@ -170,11 +177,12 @@ // print usage message private static void usage(int exit) { System.err.println("Usage:"); - System.err.println(" jstack [-l] "); + System.err.println(" jstack [-l][-e] "); System.err.println(" (to connect to running process)"); System.err.println(""); System.err.println("Options:"); System.err.println(" -l long listing. Prints additional information about locks"); + System.err.println(" -e extended listing. Prints additional information about threads"); System.err.println(" -? -h --help -help to print this help message"); System.exit(exit); }