From b594b509befef9cbbac1763358cbe78fc35668f9 Mon Sep 17 00:00:00 2001
Date: Mon, 11 May 2026 10:51:51 +0800
Subject: 8314029: Add file name parameter to Compiler.perfmap

---
 src/hotspot/share/code/codeCache.cpp          | 14 ++++++----
 src/hotspot/share/code/codeCache.hpp          |  2 +-
 .../share/services/diagnosticCommand.cpp      |  9 +++++-
 .../share/services/diagnosticCommand.hpp      |  7 +++--
 src/jdk.jcmd/share/man/jcmd.1                 | 12 +++++++-
 .../dcmd/compiler/PerfMapTest.java            | 28 +++++++++++++------
 6 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
index a227818aa..44b9d116e 100644
--- a/src/hotspot/share/code/codeCache.cpp
+++ b/src/hotspot/share/code/codeCache.cpp
@@ -1821,16 +1821,20 @@ void CodeCache::log_state(outputStream* st) {
 }
 
 #ifdef LINUX
-void CodeCache::write_perf_map() {
+void CodeCache::write_perf_map(const char* filename) {
   MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
 
-  // Perf expects to find the map file at /tmp/perf-<pid>.map.
+  // Perf expects to find the map file at /tmp/perf-<pid>.map
+  // if the file name is not specified.
   char fname[32];
-  jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
+  if (filename == nullptr) {
+    jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
+    filename = fname;
+  }
 
-  fileStream fs(fname, "w");
+  fileStream fs(filename, "w");
   if (!fs.is_open()) {
-    log_warning(codecache)("Failed to create %s for perf map", fname);
+    log_warning(codecache)("Failed to create %s for perf map", filename);
     return;
   }
 
diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp
index df38664e7..420d83a18 100644
--- a/src/hotspot/share/code/codeCache.hpp
+++ b/src/hotspot/share/code/codeCache.hpp
@@ -237,7 +237,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();)
+  LINUX_ONLY(static void write_perf_map(const char* filename = nullptr);)
   static const char* get_code_heap_name(CodeBlobType code_blob_type)  { return (heap_available(code_blob_type) ? get_code_heap(code_blob_type)->name() : "Unused"); }
   static void report_codemem_full(CodeBlobType code_blob_type, bool print);
 
diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp
index 852dad4c8..1774a450e 100644
--- a/src/hotspot/share/services/diagnosticCommand.cpp
+++ b/src/hotspot/share/services/diagnosticCommand.cpp
@@ -974,8 +974,15 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
 }
 
 #ifdef LINUX
+PerfMapDCmd::PerfMapDCmd(outputStream* output, bool heap) :
+             DCmdWithParser(output, heap),
+  _filename("filename", "Name of the map file", "STRING", false)
+{
+  _dcmdparser.add_dcmd_argument(&_filename);
+}
+
 void PerfMapDCmd::execute(DCmdSource source, TRAPS) {
-  CodeCache::write_perf_map();
+  CodeCache::write_perf_map(_filename.value());
 }
 #endif // LINUX
 
diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp
index 75fc9a43d..f317e4d4d 100644
--- a/src/hotspot/share/services/diagnosticCommand.hpp
+++ b/src/hotspot/share/services/diagnosticCommand.hpp
@@ -647,9 +647,12 @@ public:
 };
 
 #ifdef LINUX
-class PerfMapDCmd : public DCmd {
+class PerfMapDCmd : public DCmdWithParser {
+protected:
+  DCmdArgument<char*> _filename;
 public:
-  PerfMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
+  static int num_arguments() { return 1; }
+  PerfMapDCmd(outputStream* output, bool heap);
   static const char* name() {
     return "Compiler.perfmap";
   }
diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1
index f3e254be9..6b6b6496d 100644
--- a/src/jdk.jcmd/share/man/jcmd.1
+++ b/src/jdk.jcmd/share/man/jcmd.1
@@ -178,11 +178,21 @@ Prints all compiled methods in code cache that are alive.
 Impact: Medium
 .RE
 .TP
-\f[V]Compiler.perfmap\f[R] (Linux only)
+\f[V]Compiler.perfmap\f[R] [\f[I]arguments\f[R]] (Linux only)
 Write map file for Linux perf tool.
 .RS
 .PP
 Impact: Low
+.PP
+\f[I]arguments\f[R]:
+.IP \[bu] 2
+\f[V]filename\f[R]: (Optional) Name of the map file (STRING, no default
+value)
+.PP
+If \f[V]filename\f[R] is not specified, a default file name is chosen
+using the pid of the target JVM process.
+For example, if the pid is \f[V]12345\f[R], then the default
+\f[V]filename\f[R] will be \f[V]/tmp/perf-12345.map\f[R].
 .RE
 .TP
 \f[V]Compiler.queue\f[R]
diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java
index f4da5e979..ef05468bc 100644
--- a/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java
+++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/PerfMapTest.java
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, 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
@@ -46,6 +46,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -58,15 +59,12 @@ public class PerfMapTest {
     static final Pattern LINE_PATTERN =
         Pattern.compile("^((?:0x)?\\p{XDigit}+)\\s+((?:0x)?\\p{XDigit}+)\\s+(.*)$");
 
-    public void run(CommandExecutor executor) {
-        OutputAnalyzer output = executor.execute("Compiler.perfmap");
+    public void run(CommandExecutor executor, String cmd, Path path) {
+        OutputAnalyzer output = executor.execute(cmd);
 
         output.stderrShouldBeEmpty();
         output.stdoutShouldBeEmpty();
 
-        final long pid = ProcessHandle.current().pid();
-        final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid));
-
         Assert.assertTrue(Files.exists(path));
 
         // Sanity check the file contents
@@ -81,7 +79,19 @@ public class PerfMapTest {
     }
 
     @Test
-    public void jmx() {
-        run(new JMXExecutor());
+    public void defaultMapFile() {
+        final long pid = ProcessHandle.current().pid();
+        final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid));
+        run(new JMXExecutor(), "Compiler.perfmap", path);
+    }
+
+    @Test
+    public void specifiedMapFile() {
+        String test_dir = System.getProperty("test.dir", ".");
+        Path path = null;
+        do {
+            path = Paths.get(String.format("%s/%s.map", test_dir, UUID.randomUUID().toString()));
+        } while(Files.exists(path));
+        run(new JMXExecutor(), "Compiler.perfmap " + path.toString(), path);
     }
 }
-- 
2.17.1