|
1 | 1 | /* |
2 | | - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. |
3 | | - * Copyright (c) 2023, 2023, Red Hat Inc. All rights reserved. |
| 2 | + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. |
| 3 | + * Copyright (c) 2023, 2024, Red Hat Inc. All rights reserved. |
4 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
5 | 5 | * |
6 | 6 | * This code is free software; you can redistribute it and/or modify it |
|
28 | 28 |
|
29 | 29 | import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE; |
30 | 30 |
|
| 31 | +import com.oracle.svm.core.Sigusr1Handler; |
| 32 | +import com.oracle.svm.core.SubstrateOptions; |
31 | 33 | import org.graalvm.nativeimage.ImageSingletons; |
32 | 34 | import org.graalvm.nativeimage.Platform; |
33 | 35 | import org.graalvm.nativeimage.Platforms; |
| 36 | +import org.graalvm.nativeimage.ProcessProperties; |
34 | 37 | import org.graalvm.nativeimage.c.struct.SizeOf; |
35 | 38 | import org.graalvm.word.Pointer; |
36 | 39 | import org.graalvm.word.PointerBase; |
|
45 | 48 |
|
46 | 49 | import jdk.graal.compiler.api.replacements.Fold; |
47 | 50 |
|
| 51 | +import java.io.FileWriter; |
| 52 | +import java.io.IOException; |
| 53 | +import java.nio.file.Files; |
| 54 | +import java.nio.file.Paths; |
| 55 | + |
48 | 56 | /** |
49 | 57 | * This class implements native memory tracking (NMT). There are two components to NMT: tracking |
50 | 58 | * memory allocations (malloc/realloc/calloc), and tracking virtual memory usage (not supported |
@@ -197,28 +205,66 @@ private NmtMallocMemoryInfo getInfo(int category) { |
197 | 205 | return categories[category]; |
198 | 206 | } |
199 | 207 |
|
| 208 | + public static RuntimeSupport.Hook startupHook() { |
| 209 | + return isFirstIsolate -> { |
| 210 | + if (isFirstIsolate && SubstrateOptions.EnableSignalHandling.getValue()) { |
| 211 | + Sigusr1Handler.install(); |
| 212 | + } |
| 213 | + }; |
| 214 | + } |
| 215 | + |
200 | 216 | public static RuntimeSupport.Hook shutdownHook() { |
201 | 217 | return isFirstIsolate -> NativeMemoryTracking.singleton().printStatistics(); |
202 | 218 | } |
203 | 219 |
|
204 | | - private void printStatistics() { |
| 220 | + public void printStatistics() { |
205 | 221 | if (VMInspectionOptions.PrintNMTStatistics.getValue()) { |
206 | | - System.out.println(); |
207 | | - System.out.println("Native memory tracking"); |
208 | | - System.out.println(" Peak total used memory: " + getPeakTotalUsedMemory() + " bytes"); |
209 | | - System.out.println(" Total alive allocations at peak usage: " + getCountAtTotalPeakUsage()); |
210 | | - System.out.println(" Total used memory: " + getTotalUsedMemory() + " bytes"); |
211 | | - System.out.println(" Total alive allocations: " + getTotalCount()); |
212 | | - |
213 | | - for (int i = 0; i < NmtCategory.values().length; i++) { |
214 | | - String name = NmtCategory.values()[i].getName(); |
215 | | - NmtMallocMemoryInfo info = getInfo(i); |
216 | | - |
217 | | - System.out.println(" " + name + " peak used memory: " + info.getPeakUsed() + " bytes"); |
218 | | - System.out.println(" " + name + " alive allocations at peak: " + info.getCountAtPeakUsage()); |
219 | | - System.out.println(" " + name + " currently used memory: " + info.getUsed() + " bytes"); |
220 | | - System.out.println(" " + name + " currently alive allocations: " + info.getCount()); |
221 | | - } |
| 222 | + System.out.println(generateReportString()); |
| 223 | + } |
| 224 | + } |
| 225 | + |
| 226 | + public void dumpReport() throws IOException { |
| 227 | + String path = reportPath(); |
| 228 | + FileWriter writer = new FileWriter(path); |
| 229 | + writer.write(generateReportString()); |
| 230 | + writer.close(); |
| 231 | + |
| 232 | + } |
| 233 | + |
| 234 | + private String reportPath() { |
| 235 | + String time = Long.toString(System.currentTimeMillis()); |
| 236 | + String pid = Long.toString(ProcessProperties.getProcessID()); |
| 237 | + String defaultFilename = "nmt_report_" + pid + "_" + time + ".txt"; |
| 238 | + |
| 239 | + String filenameOrDirectory = VMInspectionOptions.NmtDumpPath.getValue(); |
| 240 | + if (filenameOrDirectory.isEmpty()) { |
| 241 | + return defaultFilename; |
| 242 | + } |
| 243 | + var targetPath = Paths.get(filenameOrDirectory); |
| 244 | + if (Files.isDirectory(targetPath)) { |
| 245 | + targetPath = targetPath.resolve(defaultFilename); |
| 246 | + } |
| 247 | + return targetPath.toFile().getAbsolutePath(); |
| 248 | + } |
| 249 | + |
| 250 | + private String generateReportString() { |
| 251 | + StringBuilder stringBuilder = new StringBuilder(2500); |
| 252 | + stringBuilder.append("\n"); |
| 253 | + stringBuilder.append("Native memory tracking\n"); |
| 254 | + stringBuilder.append(" Peak total used memory: " + getPeakTotalUsedMemory() + " bytes\n"); |
| 255 | + stringBuilder.append(" Total alive allocations at peak usage: " + getCountAtTotalPeakUsage() + "\n"); |
| 256 | + stringBuilder.append(" Total used memory: " + getTotalUsedMemory() + " bytes\n"); |
| 257 | + stringBuilder.append(" Total alive allocations: " + getTotalCount() + "\n"); |
| 258 | + |
| 259 | + for (int i = 0; i < NmtCategory.values().length; i++) { |
| 260 | + String name = NmtCategory.values()[i].getName(); |
| 261 | + NmtMallocMemoryInfo info = getInfo(i); |
| 262 | + |
| 263 | + stringBuilder.append(" " + name + " peak used memory: " + info.getPeakUsed() + " bytes\n"); |
| 264 | + stringBuilder.append(" " + name + " alive allocations at peak: " + info.getCountAtPeakUsage() + "\n"); |
| 265 | + stringBuilder.append(" " + name + " currently used memory: " + info.getUsed() + " bytes\n"); |
| 266 | + stringBuilder.append(" " + name + " currently alive allocations: " + info.getCount() + "\n"); |
222 | 267 | } |
| 268 | + return stringBuilder.toString(); |
223 | 269 | } |
224 | 270 | } |
0 commit comments