Skip to content

Commit

Permalink
Merge pull request #488 from gradle/sg/report-jmap
Browse files Browse the repository at this point in the history
  • Loading branch information
big-guy authored Jun 21, 2023
2 parents 024660a + 067a2d1 commit 79e5118
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 13 deletions.
12 changes: 9 additions & 3 deletions src/main/java/org/gradle/profiler/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class Main {
public static void main(String[] args) {
Expand Down Expand Up @@ -167,10 +169,14 @@ private static void printResultFileSummaries(File outputDir, Profiler profiler)
if (outputDir == null) {
return;
}
for (File file : outputDir.listFiles()) {
profiler.summarizeResultFile(file, line -> System.out.println(" " + line));
// Report results in a predictable order
List<File> results = Arrays.stream(outputDir.listFiles()).sorted().collect(Collectors.toList());
for (File file : results) {
if (file.isFile()) {
profiler.summarizeResultFile(file, line -> System.out.println(" " + line));
}
}
for (File file : outputDir.listFiles()) {
for (File file : results) {
if (file.isDirectory()) {
printResultFileSummaries(file, profiler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ protected void generateInitScriptBody(PrintWriter writer) {

@Override
public void summarizeResultFile(File resultFile, Consumer<String> consumer) {
if (resultFile.getName().endsWith(".hprof")) {
if (resultFile.getName().endsWith(".hprof") || resultFile.getName().endsWith(".jmap")) {
consumer.accept(resultFile.getAbsolutePath());
}
}
Expand Down
63 changes: 59 additions & 4 deletions src/test/groovy/org/gradle/profiler/HeapDumpIntegrationTest.groovy
Original file line number Diff line number Diff line change
@@ -1,6 +1,45 @@
package org.gradle.profiler

class HeapDumpIntegrationTest extends AbstractProfilerIntegrationTest {
def "can generate heap dump"() {
given:
instrumentedBuildScript()

when:
new Main().run("--project-dir", projectDir.absolutePath,
"--output-dir", outputDir.absolutePath,
"--gradle-version", latestSupportedGradleVersion,
"--iterations", "0",
"--warmups", "1",
"--profile", "heap-dump", "assemble")

then:
// just run one build
assertIsHprof("heap-1.hprof")
assertIsJmap("heap-1.jmap")
}

private void assertIsHprof(String partialName) {
assertHasFile(partialName)
// Check the header of the file to see if it looks like a hprof
byte[] header = new byte[12]
mkFile(partialName).withInputStream {
it.read(header)
}
assert new String(header) == "JAVA PROFILE"
}

private void assertIsJmap(String partialName) {
assertHasFile(partialName)
def lines = mkFile(partialName).readLines().grep { !it.empty }

def firstLine = lines.first()
assert firstLine.startsWith(" num #instances #bytes")

def lastLine = lines.last()
assert lastLine.startsWith("Total ")
}

def "generates a heap dump when run with tooling API and warm daemon"() {
given:
instrumentedBuildScript()
Expand All @@ -10,8 +49,10 @@ class HeapDumpIntegrationTest extends AbstractProfilerIntegrationTest {

then:
// 2 warm ups and 1 measured build
new File(outputDir, "${latestSupportedGradleVersion}-heap-3.hprof").file
!new File(outputDir, "${latestSupportedGradleVersion}-heap-4.hprof").file
assertHasFile("heap-3.hprof")
assertHasFile("heap-3.jmap")
assertDoesNotHaveFile("heap-4.hprof")
assertDoesNotHaveFile("heap-4.jmap")
}

def "generates a heap dump when run with tooling API and warm daemon and multiple iterations"() {
Expand All @@ -23,7 +64,21 @@ class HeapDumpIntegrationTest extends AbstractProfilerIntegrationTest {

then:
// 2 warm ups and 2 measured builds
new File(outputDir, "${latestSupportedGradleVersion}-heap-3.hprof").file
new File(outputDir, "${latestSupportedGradleVersion}-heap-4.hprof").file
assertHasFile("heap-3.hprof")
assertHasFile("heap-3.jmap")
assertHasFile("heap-4.hprof")
assertHasFile("heap-4.jmap")
}

private void assertHasFile(String partialName) {
assert mkFile(partialName).file
}

private void assertDoesNotHaveFile(String partialName) {
assert !mkFile(partialName).exists()
}

private File mkFile(String partialName) {
new File(outputDir, "${latestSupportedGradleVersion}-${partialName}")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
import org.gradle.tooling.events.OperationCompletionListener;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.util.Collections;

public class HeapDump {

Expand All @@ -41,12 +43,26 @@ public void onFinish(FinishEvent event) {
@Override
public void close() {
try {
File dumpFile = new File(getParameters().getBaseFile().get() + "-heap-" + (++counter) + ".hprof");
dumpFile.getParentFile().mkdirs();
String dumpFileBase = getParameters().getBaseFile().get() + "-heap-" + (++counter);
File hprofFile = new File(dumpFileBase + ".hprof");
File jmapFile = new File(dumpFileBase + ".jmap");
hprofFile.getParentFile().mkdirs();

MBeanServer server = ManagementFactory.getPlatformMBeanServer();

// Dump heap into hprof file
HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(dumpFile.getAbsolutePath(), true);
} catch (IOException e) {
mxBean.dumpHeap(hprofFile.getAbsolutePath(), true);

// Dump class histogram to .jmap file
// This should be the same output as running jmap -histo:live <pid>
String histogram = (String) server.invoke(
new ObjectName("com.sun.management:type=DiagnosticCommand"),
"gcClassHistogram",
new Object[]{null},
new String[]{"[Ljava.lang.String;"});
Files.write(jmapFile.toPath(), Collections.singleton(histogram));
} catch (Exception e) {
throw UncheckedException.throwAsUncheckedException(e);
}
}
Expand Down

0 comments on commit 79e5118

Please sign in to comment.