278 lines
10 KiB
Diff
278 lines
10 KiB
Diff
|
|
From 6a5759c82b869c4d931273609aa19eb1a84df8db Mon Sep 17 00:00:00 2001
|
||
|
|
Date: Thu, 21 Sep 2023 15:12:51 +0800
|
||
|
|
Subject: 8254723-Add-diagnostic-command-to-write-Linux-perf-m.patch
|
||
|
|
|
||
|
|
---
|
||
|
|
hotspot/src/os/linux/vm/globals_linux.hpp | 5 +-
|
||
|
|
hotspot/src/os/linux/vm/os_linux.cpp | 6 ++
|
||
|
|
hotspot/src/share/vm/code/codeCache.cpp | 36 ++++++++
|
||
|
|
hotspot/src/share/vm/code/codeCache.hpp | 1 +
|
||
|
|
hotspot/src/share/vm/runtime/java.cpp | 6 ++
|
||
|
|
.../share/vm/services/diagnosticCommand.cpp | 7 ++
|
||
|
|
.../share/vm/services/diagnosticCommand.hpp | 23 +++++
|
||
|
|
.../test/serviceability/dcmd/PerfMapTest.java | 84 +++++++++++++++++++
|
||
|
|
8 files changed, 167 insertions(+), 1 deletion(-)
|
||
|
|
create mode 100644 hotspot/test/serviceability/dcmd/PerfMapTest.java
|
||
|
|
|
||
|
|
diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp
|
||
|
|
index f98bde41a..5cbe686d3 100644
|
||
|
|
--- a/hotspot/src/os/linux/vm/globals_linux.hpp
|
||
|
|
+++ b/hotspot/src/os/linux/vm/globals_linux.hpp
|
||
|
|
@@ -55,7 +55,10 @@
|
||
|
|
product(bool, PreferContainerQuotaForCPUCount, true, \
|
||
|
|
"Calculate the container CPU availability based on the value" \
|
||
|
|
" of quotas (if set), when true. Otherwise, use the CPU" \
|
||
|
|
- " shares value, provided it is less than quota.")
|
||
|
|
+ " shares value, provided it is less than quota.") \
|
||
|
|
+ \
|
||
|
|
+ diagnostic(bool, DumpPerfMapAtExit, false, \
|
||
|
|
+ "Write map file for Linux perf tool at exit")
|
||
|
|
|
||
|
|
//
|
||
|
|
// Defines Linux-specific default values. The flags are available on all
|
||
|
|
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
|
||
|
|
index a1cc85ca3..197b5c193 100644
|
||
|
|
--- a/hotspot/src/os/linux/vm/os_linux.cpp
|
||
|
|
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
|
||
|
|
@@ -5648,6 +5648,12 @@ jint os::init_2(void)
|
||
|
|
// initialize thread priority policy
|
||
|
|
prio_init();
|
||
|
|
|
||
|
|
+ if (DumpPerfMapAtExit && FLAG_IS_DEFAULT(UseCodeCacheFlushing)) {
|
||
|
|
+ // Disable code cache flushing to ensure the map file written at
|
||
|
|
+ // exit contains all nmethods generated during execution.
|
||
|
|
+ FLAG_SET_DEFAULT(UseCodeCacheFlushing, false);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
return JNI_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
|
||
|
|
index 37f24b5e9..97ad3ba79 100644
|
||
|
|
--- a/hotspot/src/share/vm/code/codeCache.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/code/codeCache.cpp
|
||
|
|
@@ -1033,3 +1033,39 @@ void CodeCache::log_state(outputStream* st) {
|
||
|
|
unallocated_capacity());
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef LINUX
|
||
|
|
+void CodeCache::write_perf_map() {
|
||
|
|
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||
|
|
+
|
||
|
|
+ // Perf expects to find the map file at /tmp/perf-<pid>.map.
|
||
|
|
+ char fname[32];
|
||
|
|
+ jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
|
||
|
|
+
|
||
|
|
+ fileStream fs(fname, "w");
|
||
|
|
+ if (!fs.is_open()) {
|
||
|
|
+ DEBUG_ONLY(warning("[codecache] Failed to create %s for perf map", fname));
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ FOR_ALL_ALIVE_BLOBS(cb) {
|
||
|
|
+ if (cb->is_nmethod()) {
|
||
|
|
+ nmethod *nm = (nmethod *) cb;
|
||
|
|
+ assert(!nm->is_unloaded(), "Tautology");
|
||
|
|
+ ResourceMark rm;
|
||
|
|
+ const char* method_name = nm->method()->name_and_sig_as_C_string();
|
||
|
|
+ fs.print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %s",
|
||
|
|
+ (intptr_t)cb->code_begin(), (intptr_t)cb->code_size(),
|
||
|
|
+ method_name);
|
||
|
|
+ }
|
||
|
|
+ if (cb->is_runtime_stub()) {
|
||
|
|
+ RuntimeStub *stub = (RuntimeStub *) cb;
|
||
|
|
+ ResourceMark rm;
|
||
|
|
+ const char* method_name = stub->name();
|
||
|
|
+ fs.print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %s",
|
||
|
|
+ (intptr_t)cb->code_begin(), (intptr_t)cb->code_size(),
|
||
|
|
+ method_name);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+#endif // LINUX
|
||
|
|
diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp
|
||
|
|
index ab1417b19..0aad2d648 100644
|
||
|
|
--- a/hotspot/src/share/vm/code/codeCache.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/code/codeCache.hpp
|
||
|
|
@@ -158,6 +158,7 @@ class CodeCache : AllStatic {
|
||
|
|
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
|
||
|
|
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||
|
|
static void log_state(outputStream* st);
|
||
|
|
+ LINUX_ONLY(static void write_perf_map();)
|
||
|
|
|
||
|
|
// Dcmd (Diagnostic commands)
|
||
|
|
static void print_codelist(outputStream* st);
|
||
|
|
diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp
|
||
|
|
index 5a628b73e..fec8fb94d 100644
|
||
|
|
--- a/hotspot/src/share/vm/runtime/java.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/runtime/java.cpp
|
||
|
|
@@ -537,6 +537,12 @@ void before_exit(JavaThread * thread) {
|
||
|
|
BytecodeHistogram::print();
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef LINUX
|
||
|
|
+ if (DumpPerfMapAtExit) {
|
||
|
|
+ CodeCache::write_perf_map();
|
||
|
|
+ }
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
if (JvmtiExport::should_post_thread_life()) {
|
||
|
|
JvmtiExport::post_thread_end(thread);
|
||
|
|
}
|
||
|
|
diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp
|
||
|
|
index 416dc77ce..f8f6ad546 100644
|
||
|
|
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp
|
||
|
|
@@ -36,6 +36,7 @@
|
||
|
|
#include "services/management.hpp"
|
||
|
|
#include "utilities/macros.hpp"
|
||
|
|
#include "oops/objArrayOop.hpp"
|
||
|
|
+#include "code/codeCache.hpp"
|
||
|
|
|
||
|
|
#ifdef LINUX
|
||
|
|
#include "trimCHeapDCmd.hpp"
|
||
|
|
@@ -81,6 +82,7 @@ void DCmdRegistrant::register_dcmds(){
|
||
|
|
#ifdef LINUX
|
||
|
|
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TrimCLibcHeapDCmd>(full_export, true, false));
|
||
|
|
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<MallocInfoDcmd>(full_export, true, false));
|
||
|
|
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PerfMapDCmd>(full_export, true, false));
|
||
|
|
#endif // LINUX
|
||
|
|
|
||
|
|
// Enhanced JMX Agent Support
|
||
|
|
@@ -868,3 +870,8 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
|
||
|
|
VMThread::execute(&printCodeCacheOp);
|
||
|
|
}
|
||
|
|
|
||
|
|
+#ifdef LINUX
|
||
|
|
+void PerfMapDCmd::execute(DCmdSource source, TRAPS) {
|
||
|
|
+ CodeCache::write_perf_map();
|
||
|
|
+}
|
||
|
|
+#endif // LINUX
|
||
|
|
\ No newline at end of file
|
||
|
|
diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp
|
||
|
|
index 3733fa7f7..d446aab4e 100644
|
||
|
|
--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp
|
||
|
|
@@ -590,4 +590,27 @@ public:
|
||
|
|
virtual void execute(DCmdSource source, TRAPS);
|
||
|
|
};
|
||
|
|
|
||
|
|
+#ifdef LINUX
|
||
|
|
+class PerfMapDCmd : public DCmd {
|
||
|
|
+public:
|
||
|
|
+ PerfMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||
|
|
+ static const char* name() {
|
||
|
|
+ return "Compiler.perfmap";
|
||
|
|
+ }
|
||
|
|
+ static const char* description() {
|
||
|
|
+ return "Write map file for Linux perf tool.";
|
||
|
|
+ }
|
||
|
|
+ static const char* impact() {
|
||
|
|
+ return "Low";
|
||
|
|
+ }
|
||
|
|
+ static const JavaPermission permission() {
|
||
|
|
+ JavaPermission p = {"java.lang.management.ManagementPermission",
|
||
|
|
+ "monitor", NULL};
|
||
|
|
+ return p;
|
||
|
|
+ }
|
||
|
|
+ static int num_arguments() { return 0; }
|
||
|
|
+ virtual void execute(DCmdSource source, TRAPS);
|
||
|
|
+};
|
||
|
|
+#endif // LINUX
|
||
|
|
+
|
||
|
|
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
|
||
|
|
diff --git a/hotspot/test/serviceability/dcmd/PerfMapTest.java b/hotspot/test/serviceability/dcmd/PerfMapTest.java
|
||
|
|
new file mode 100644
|
||
|
|
index 000000000..1807b2a7f
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/hotspot/test/serviceability/dcmd/PerfMapTest.java
|
||
|
|
@@ -0,0 +1,84 @@
|
||
|
|
+/*
|
||
|
|
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||
|
|
+ * Copyright (c) 2020, Arm Limited. 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.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * @test PerfMapTest
|
||
|
|
+ * @bug 8254723
|
||
|
|
+ * @requires os.family == "linux"
|
||
|
|
+ * @library /testlibrary
|
||
|
|
+ * @run testng/othervm PerfMapTest
|
||
|
|
+ * @summary Test of diagnostic command Compiler.perfmap
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+import org.testng.annotations.Test;
|
||
|
|
+import org.testng.Assert;
|
||
|
|
+
|
||
|
|
+import com.oracle.java.testlibrary.OutputAnalyzer;
|
||
|
|
+import com.oracle.java.testlibrary.CommandExecutor;
|
||
|
|
+import com.oracle.java.testlibrary.JMXExecutor;
|
||
|
|
+import com.oracle.java.testlibrary.ProcessTools;
|
||
|
|
+
|
||
|
|
+import java.io.IOException;
|
||
|
|
+import java.nio.file.Files;
|
||
|
|
+import java.nio.file.Path;
|
||
|
|
+import java.nio.file.Paths;
|
||
|
|
+import java.util.regex.Matcher;
|
||
|
|
+import java.util.regex.Pattern;
|
||
|
|
+
|
||
|
|
+/**
|
||
|
|
+ * Call jcmd Compiler.perfmap and check the output file has the expected
|
||
|
|
+ * format.
|
||
|
|
+ */
|
||
|
|
+public class PerfMapTest {
|
||
|
|
+
|
||
|
|
+ static final Pattern LINE_PATTERN =
|
||
|
|
+ Pattern.compile("^((?:0x)?\\p{XDigit}+)\\s+((?:0x)?\\p{XDigit}+)\\s+(.*)$");
|
||
|
|
+
|
||
|
|
+ public void run(CommandExecutor executor) throws Exception {
|
||
|
|
+ OutputAnalyzer output = executor.execute("Compiler.perfmap");
|
||
|
|
+
|
||
|
|
+ output.stderrShouldBeEmpty();
|
||
|
|
+ output.stdoutShouldBeEmpty();
|
||
|
|
+
|
||
|
|
+ final long pid = ProcessTools.getProcessId();
|
||
|
|
+ final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid));
|
||
|
|
+
|
||
|
|
+ Assert.assertTrue(Files.exists(path));
|
||
|
|
+
|
||
|
|
+ // Sanity check the file contents
|
||
|
|
+ try {
|
||
|
|
+ for (String entry : Files.readAllLines(path)) {
|
||
|
|
+ Matcher m = LINE_PATTERN.matcher(entry);
|
||
|
|
+ Assert.assertTrue(m.matches(), "Invalid file format: " + entry);
|
||
|
|
+ }
|
||
|
|
+ } catch (IOException e) {
|
||
|
|
+ Assert.fail(e.toString());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ @Test
|
||
|
|
+ public void jmx() throws Exception {
|
||
|
|
+ run(new JMXExecutor());
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
--
|
||
|
|
2.22.0
|
||
|
|
|