516 |
517 |
518 | Something went wrong with that request. Please try again.
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='perfj'
2 |
--------------------------------------------------------------------------------
/src/main/java/info/minzhou/perfj/PerfJ.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This program is free software; you can redistribute it and/or modify
3 | * it under the terms of the GNU General Public License as published by
4 | * the Free Software Foundation; either version 2 of the License, or
5 | * (at your option) any later version.
6 | *
7 | * This program is distributed in the hope that it will be useful,
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | * GNU General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU General Public License along
13 | * with this program; if not, write to the Free Software Foundation, Inc.,
14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 | */
16 |
17 | package info.minzhou.perfj;
18 |
19 | import com.sun.tools.attach.VirtualMachine;
20 |
21 | import java.io.*;
22 | import java.util.Enumeration;
23 | import java.util.Properties;
24 | import java.util.UUID;
25 |
26 | public class PerfJ {
27 |
28 | public static final String PERFJ_SYSTEM_PROPERTIES_FILE = "info-minzhou-perfj.properties";
29 | public static final String KEY_PERFJ_LIB_PATH = "info.minzhou.perfj.lib.path";
30 | public static final String KEY_PERFJ_LIB_NAME = "info.minzhou.perfj.lib.name";
31 | public static final String KEY_PERFJ_TEMPDIR = "info.minzhou.perfj.tempdir";
32 | public static final String KEY_PERFJ_USE_SYSTEMLIB = "info.minzhou.perfj.use.systemlib";
33 |
34 |
35 | static {
36 | loadSystemProperties();
37 | }
38 |
39 | /**
40 | * load system properties when configuration file of the name
41 | * {@link #PERFJ_SYSTEM_PROPERTIES_FILE} is found
42 | */
43 | private static void loadSystemProperties() {
44 | try {
45 | InputStream is = Thread.currentThread().getContextClassLoader()
46 | .getResourceAsStream(PERFJ_SYSTEM_PROPERTIES_FILE);
47 |
48 | if (is == null) {
49 | return; // no configuration file is found
50 | }
51 |
52 | // Load property file
53 | Properties props = new Properties();
54 | props.load(is);
55 | is.close();
56 | Enumeration> names = props.propertyNames();
57 | while (names.hasMoreElements()) {
58 | String name = (String) names.nextElement();
59 | if (name.startsWith("info.minzhou.perfj.")) {
60 | if (System.getProperty(name) == null) {
61 | System.setProperty(name, props.getProperty(name));
62 | }
63 | }
64 | }
65 | } catch (Throwable ex) {
66 | System.err.println("Could not load '" + PERFJ_SYSTEM_PROPERTIES_FILE + "' from classpath: "
67 | + ex.toString());
68 | }
69 | }
70 |
71 |
72 |
73 | private static File findNativeLibrary() {
74 | boolean useSystemLib = Boolean.parseBoolean(System.getProperty(KEY_PERFJ_USE_SYSTEMLIB, "false"));
75 | if (useSystemLib) {
76 | return null; // Use a pre-installed libperfj
77 | }
78 |
79 | // Try to load the library in info.minzhou.perfj.lib.path */
80 | String perfjNativeLibraryPath = System.getProperty(KEY_PERFJ_LIB_PATH);
81 | String perfjNativeLibraryName = System.getProperty(KEY_PERFJ_LIB_NAME);
82 |
83 | // Resolve the library file name with a suffix (e.g., dll, .so, etc.)
84 | if (perfjNativeLibraryName == null) {
85 | perfjNativeLibraryName = System.mapLibraryName("perfj");
86 | }
87 |
88 | if (perfjNativeLibraryPath != null) {
89 | File nativeLib = new File(perfjNativeLibraryPath, perfjNativeLibraryName);
90 | if (nativeLib.exists()) {
91 | return nativeLib;
92 | }
93 | }
94 |
95 | // Load native library inside a jar file
96 | perfjNativeLibraryPath = "/info/minzhou/perfj/native";
97 | boolean hasNativeLib = hasResource(perfjNativeLibraryPath + "/" + perfjNativeLibraryName);
98 |
99 | if (!hasNativeLib) {
100 | throw new RuntimeException("no native library is found for perfj");
101 | }
102 |
103 | // Temporary folder for the native lib. Use the value of info.minzhou.perfj.tempdir or java.io.tmpdir
104 | File tempFolder = new File(System.getProperty(KEY_PERFJ_TEMPDIR, System.getProperty("java.io.tmpdir")));
105 | if (!tempFolder.exists()) {
106 | boolean created = tempFolder.mkdirs();
107 | if (!created) {
108 | // if created == false, it will fail eventually in the later part
109 | }
110 | }
111 |
112 | // Extract and load a native library inside the jar file
113 | return extractLibraryFile(perfjNativeLibraryPath, perfjNativeLibraryName, tempFolder.getAbsolutePath());
114 | }
115 |
116 | private static boolean hasResource(String path) {
117 | return PerfJ.class.getResource(path) != null;
118 | }
119 |
120 |
121 | /**
122 | * Extract the specified library file to the target folder
123 | *
124 | * @param libraryFolder
125 | * @param libraryFileName
126 | * @param targetFolder
127 | * @return
128 | */
129 | private static File extractLibraryFile(String libraryFolder, String libraryFileName, String targetFolder) {
130 | String nativeLibraryFilePath = libraryFolder + "/" + libraryFileName;
131 |
132 | // Attach UUID to the native library file to ensure multiple processes can read the libperfj multiple times.
133 | String uuid = UUID.randomUUID().toString();
134 | String extractedLibFileName = String.format("perfj-%s-%s", uuid, libraryFileName);
135 | File extractedLibFile = new File(targetFolder, extractedLibFileName);
136 |
137 | try {
138 | // Extract a native library file into the target directory
139 | InputStream reader = null;
140 | FileOutputStream writer = null;
141 | try {
142 | reader = PerfJ.class.getResourceAsStream(nativeLibraryFilePath);
143 | try {
144 | writer = new FileOutputStream(extractedLibFile);
145 |
146 | byte[] buffer = new byte[8192];
147 | int bytesRead = 0;
148 | while ((bytesRead = reader.read(buffer)) != -1) {
149 | writer.write(buffer, 0, bytesRead);
150 | }
151 | } finally {
152 | if (writer != null) {
153 | writer.close();
154 | }
155 | }
156 | } finally {
157 | if (reader != null) {
158 | reader.close();
159 | }
160 |
161 | // Delete the extracted lib file on JVM exit.
162 | extractedLibFile.deleteOnExit();
163 | }
164 |
165 | // Set executable (x) flag to enable Java to load the native library
166 | boolean success = extractedLibFile.setReadable(true) &&
167 | extractedLibFile.setWritable(true, true) &&
168 | extractedLibFile.setExecutable(true);
169 | if (!success) {
170 | // Setting file flag may fail, but in this case another error will be thrown in later phase
171 | }
172 |
173 | // Check whether the contents are properly copied from the resource folder
174 | {
175 | InputStream nativeIn = null;
176 | InputStream extractedLibIn = null;
177 | try {
178 | nativeIn = PerfJ.class.getResourceAsStream(nativeLibraryFilePath);
179 | extractedLibIn = new FileInputStream(extractedLibFile);
180 |
181 | if (!contentsEquals(nativeIn, extractedLibIn)) {
182 | throw new RuntimeException(String.format("Failed to write a native library file at %s", extractedLibFile));
183 | }
184 | } finally {
185 | if (nativeIn != null) {
186 | nativeIn.close();
187 | }
188 | if (extractedLibIn != null) {
189 | extractedLibIn.close();
190 | }
191 | }
192 | }
193 |
194 | return new File(targetFolder, extractedLibFileName);
195 | } catch (IOException e) {
196 | e.printStackTrace(System.err);
197 | return null;
198 | }
199 | }
200 |
201 | private static boolean contentsEquals(InputStream in1, InputStream in2)
202 | throws IOException {
203 | if (!(in1 instanceof BufferedInputStream)) {
204 | in1 = new BufferedInputStream(in1);
205 | }
206 | if (!(in2 instanceof BufferedInputStream)) {
207 | in2 = new BufferedInputStream(in2);
208 | }
209 |
210 | int ch = in1.read();
211 | while (ch != -1) {
212 | int ch2 = in2.read();
213 | if (ch != ch2) {
214 | return false;
215 | }
216 | ch = in1.read();
217 | }
218 | int ch2 = in2.read();
219 | return ch2 == -1;
220 | }
221 |
222 | private static void loadAgent(String pid, String options) throws Exception {
223 | VirtualMachine vm = VirtualMachine.attach(pid);
224 | try {
225 | vm.loadAgentPath(findNativeLibrary().getAbsolutePath(), options);
226 | } catch (com.sun.tools.attach.AgentInitializationException e) {
227 | // rethrow all but the expected exception
228 | if (!e.getMessage().equals("Agent_OnAttach failed")) throw e;
229 | } finally {
230 | vm.detach();
231 | }
232 | }
233 |
234 | public static void main(String[] args) throws Exception {
235 | String pid = args[0];
236 | String options = "";
237 | if (args.length > 1) options = args[1];
238 | loadAgent(pid, options);
239 | }
240 |
241 |
242 | }
243 |
244 |
--------------------------------------------------------------------------------
/src/perfj/c/perf-map-agent.c:
--------------------------------------------------------------------------------
1 | /*
2 | * libperfj: a JVM agent to create perf-