-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathProfile.java
More file actions
103 lines (84 loc) · 3.56 KB
/
Profile.java
File metadata and controls
103 lines (84 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalTime;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Profile {
private static final String NOW = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
private static final Path LOG_FILE_NAME = Paths.get("log" + NOW + ".jfr").toAbsolutePath();
private static final Path CONFIG_FILE_NAME = Paths.get("config.jfc").toAbsolutePath();
private static final String PROFILING_NAME = "temp";
private static final Duration DEFAULT_DURATION = Duration.ofSeconds(30);
public static void main(String[] args) {
try {
run(args);
} catch (Exception throwable) {
throwable.printStackTrace();
exit(99, "Encountered exception: " + throwable.getMessage());
}
}
private static void run(String[] args) throws IOException, InterruptedException {
if (args.length < 1) {
exit(1, "expected pid to profile");
}
final int pid = findProcessPid(args[0]);
var duration = args.length == 2 ?
Duration.ofSeconds(Integer.parseInt(args[1])) :
DEFAULT_DURATION;
run("jcmd %d JFR.start name=%s settings=%s".formatted(pid, PROFILING_NAME, CONFIG_FILE_NAME));
println("Started profiling process %d for %d seconds".formatted(pid, duration.getSeconds()));
final LocalTime deadline = LocalTime.now().plus(duration);
while (LocalTime.now().isBefore(deadline)) {
TimeUnit.SECONDS.sleep(1);
System.out.print(".");
}
println("Stopping profiling");
run("jcmd %d JFR.dump name=%s filename=%s".formatted(pid, PROFILING_NAME, LOG_FILE_NAME));
run("jcmd %d JFR.stop name=%s".formatted(pid, PROFILING_NAME));
println("Starting JavaFlames");
run("java JavaFlames.java %s".formatted(LOG_FILE_NAME));
Files.deleteIfExists(LOG_FILE_NAME);
}
private static int findProcessPid(String javaProcess) throws IOException {
if(javaProcess.matches("[0-9]+")){
return Integer.parseInt(javaProcess);
}
final Process jps = new ProcessBuilder("jps").start();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(jps.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.endsWith(javaProcess)) {
return Integer.parseInt(line.split(" ")[0]);
}
}
}
throw new IllegalStateException("Failed to find pid for process: " + javaProcess);
}
private static void println(String s) {
System.out.println(s);
}
private static void run(String command) throws IOException, InterruptedException {
println("> " + command);
final int exitCode = new ProcessBuilder(command.split(" "))
.inheritIO()
.start()
.waitFor();
if (exitCode != 0) {
throw new IllegalStateException("Command \"%s\" exited with code %d".formatted(command, exitCode));
}
}
private static void exit(int code, String message) {
println(message);
usage();
System.exit(code);
}
private static void usage() {
println("Usage: java Profile.java <pid> [<duration in seconds>]");
}
}