Skip to content

Commit 50357d1

Browse files
committed
8254723: add diagnostic command to write Linux perf map file
Reviewed-by: ysuenaga, sspitsyn
1 parent f97ec35 commit 50357d1

File tree

8 files changed

+170
-2
lines changed

8 files changed

+170
-2
lines changed

src/hotspot/os/linux/globals_linux.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@
7979
"be dumped into the corefile.") \
8080
\
8181
product(bool, UseCpuAllocPath, false, DIAGNOSTIC, \
82-
"Use CPU_ALLOC code path in os::active_processor_count ")
82+
"Use CPU_ALLOC code path in os::active_processor_count ") \
83+
\
84+
product(bool, DumpPerfMapAtExit, false, DIAGNOSTIC, \
85+
"Write map file for Linux perf tool at exit")
8386

8487
// end of RUNTIME_OS_FLAGS
8588

src/hotspot/os/linux/os_linux.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4635,6 +4635,12 @@ jint os::init_2(void) {
46354635
set_coredump_filter(FILE_BACKED_SHARED_BIT);
46364636
}
46374637

4638+
if (DumpPerfMapAtExit && FLAG_IS_DEFAULT(UseCodeCacheFlushing)) {
4639+
// Disable code cache flushing to ensure the map file written at
4640+
// exit contains all nmethods generated during execution.
4641+
FLAG_SET_DEFAULT(UseCodeCacheFlushing, false);
4642+
}
4643+
46384644
return JNI_OK;
46394645
}
46404646

src/hotspot/share/code/codeCache.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,34 @@ void CodeCache::log_state(outputStream* st) {
15591559
unallocated_capacity());
15601560
}
15611561

1562+
#ifdef LINUX
1563+
void CodeCache::write_perf_map() {
1564+
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
1565+
1566+
// Perf expects to find the map file at /tmp/perf-<pid>.map.
1567+
char fname[32];
1568+
jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id());
1569+
1570+
fileStream fs(fname, "w");
1571+
if (!fs.is_open()) {
1572+
log_warning(codecache)("Failed to create %s for perf map", fname);
1573+
return;
1574+
}
1575+
1576+
AllCodeBlobsIterator iter(AllCodeBlobsIterator::only_alive_and_not_unloading);
1577+
while (iter.next()) {
1578+
CodeBlob *cb = iter.method();
1579+
ResourceMark rm;
1580+
const char* method_name =
1581+
cb->is_compiled() ? cb->as_compiled_method()->method()->external_name()
1582+
: cb->name();
1583+
fs.print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %s",
1584+
(intptr_t)cb->code_begin(), (intptr_t)cb->code_size(),
1585+
method_name);
1586+
}
1587+
}
1588+
#endif // LINUX
1589+
15621590
//---< BEGIN >--- CodeHeap State Analytics.
15631591

15641592
void CodeCache::aggregate(outputStream *out, size_t granularity) {

src/hotspot/share/code/codeCache.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class CodeCache : AllStatic {
191191
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
192192
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
193193
static void log_state(outputStream* st);
194+
LINUX_ONLY(static void write_perf_map();)
194195
static const char* get_code_heap_name(int code_blob_type) { return (heap_available(code_blob_type) ? get_code_heap(code_blob_type)->name() : "Unused"); }
195196
static void report_codemem_full(int code_blob_type, bool print);
196197

@@ -409,7 +410,13 @@ struct NMethodFilter {
409410
static const GrowableArray<CodeHeap*>* heaps() { return CodeCache::nmethod_heaps(); }
410411
};
411412

413+
struct AllCodeBlobsFilter {
414+
static bool apply(CodeBlob* cb) { return true; }
415+
static const GrowableArray<CodeHeap*>* heaps() { return CodeCache::heaps(); }
416+
};
417+
412418
typedef CodeBlobIterator<CompiledMethod, CompiledMethodFilter> CompiledMethodIterator;
413419
typedef CodeBlobIterator<nmethod, NMethodFilter> NMethodIterator;
420+
typedef CodeBlobIterator<CodeBlob, AllCodeBlobsFilter> AllCodeBlobsIterator;
414421

415422
#endif // SHARE_CODE_CODECACHE_HPP

src/hotspot/share/runtime/java.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,12 @@ void before_exit(JavaThread* thread) {
478478
BytecodeHistogram::print();
479479
}
480480

481+
#ifdef LINUX
482+
if (DumpPerfMapAtExit) {
483+
CodeCache::write_perf_map();
484+
}
485+
#endif
486+
481487
if (JvmtiExport::should_post_thread_life()) {
482488
JvmtiExport::post_thread_end(thread);
483489
}

src/hotspot/share/services/diagnosticCommand.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ void DCmdRegistrant::register_dcmds(){
110110
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
111111
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
112112
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
113+
#ifdef LINUX
114+
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PerfMapDCmd>(full_export, true, false));
115+
#endif // LINUX
113116
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
114117
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeHeapAnalyticsDCmd>(full_export, true, false));
115118

@@ -893,6 +896,12 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
893896
CodeCache::print_layout(output());
894897
}
895898

899+
#ifdef LINUX
900+
void PerfMapDCmd::execute(DCmdSource source, TRAPS) {
901+
CodeCache::write_perf_map();
902+
}
903+
#endif // LINUX
904+
896905
//---< BEGIN >--- CodeHeap State Analytics.
897906
CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
898907
DCmdWithParser(output, heap),

src/hotspot/share/services/diagnosticCommand.hpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,29 @@ class CompileQueueDCmd : public DCmd {
577577
virtual void execute(DCmdSource source, TRAPS);
578578
};
579579

580+
#ifdef LINUX
581+
class PerfMapDCmd : public DCmd {
582+
public:
583+
PerfMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
584+
static const char* name() {
585+
return "Compiler.perfmap";
586+
}
587+
static const char* description() {
588+
return "Write map file for Linux perf tool.";
589+
}
590+
static const char* impact() {
591+
return "Low";
592+
}
593+
static const JavaPermission permission() {
594+
JavaPermission p = {"java.lang.management.ManagementPermission",
595+
"monitor", NULL};
596+
return p;
597+
}
598+
static int num_arguments() { return 0; }
599+
virtual void execute(DCmdSource source, TRAPS);
600+
};
601+
#endif // LINUX
602+
580603
class CodeListDCmd : public DCmd {
581604
public:
582605
CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
@@ -598,7 +621,6 @@ class CodeListDCmd : public DCmd {
598621
virtual void execute(DCmdSource source, TRAPS);
599622
};
600623

601-
602624
class CodeCacheDCmd : public DCmd {
603625
public:
604626
CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2020, Arm Limited. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
/*
26+
* @test PerfMapTest
27+
* @bug 8254723
28+
* @requires os.family == "linux"
29+
* @library /test/lib
30+
* @modules java.base/jdk.internal.misc
31+
* java.compiler
32+
* java.management
33+
* jdk.internal.jvmstat/sun.jvmstat.monitor
34+
* @run testng/othervm PerfMapTest
35+
* @summary Test of diagnostic command Compiler.perfmap
36+
*/
37+
38+
import org.testng.annotations.Test;
39+
import org.testng.Assert;
40+
41+
import jdk.test.lib.process.OutputAnalyzer;
42+
import jdk.test.lib.dcmd.CommandExecutor;
43+
import jdk.test.lib.dcmd.JMXExecutor;
44+
45+
import java.io.IOException;
46+
import java.nio.file.Files;
47+
import java.nio.file.Path;
48+
import java.nio.file.Paths;
49+
import java.util.regex.Matcher;
50+
import java.util.regex.Pattern;
51+
52+
/**
53+
* Call jcmd Compiler.perfmap and check the output file has the expected
54+
* format.
55+
*/
56+
public class PerfMapTest {
57+
58+
static final Pattern LINE_PATTERN =
59+
Pattern.compile("^((?:0x)?\\p{XDigit}+)\\s+((?:0x)?\\p{XDigit}+)\\s+(.*)$");
60+
61+
public void run(CommandExecutor executor) {
62+
OutputAnalyzer output = executor.execute("Compiler.perfmap");
63+
64+
output.stderrShouldBeEmpty();
65+
output.stdoutShouldBeEmpty();
66+
67+
final long pid = ProcessHandle.current().pid();
68+
final Path path = Paths.get(String.format("/tmp/perf-%d.map", pid));
69+
70+
Assert.assertTrue(Files.exists(path));
71+
72+
// Sanity check the file contents
73+
try {
74+
for (String entry : Files.readAllLines(path)) {
75+
Matcher m = LINE_PATTERN.matcher(entry);
76+
Assert.assertTrue(m.matches(), "Invalid file format: " + entry);
77+
}
78+
} catch (IOException e) {
79+
Assert.fail(e.toString());
80+
}
81+
}
82+
83+
@Test
84+
public void jmx() {
85+
run(new JMXExecutor());
86+
}
87+
}

0 commit comments

Comments
 (0)