From 2d65b5386f710edee7685eaaee60e1c38351ae7c Mon Sep 17 00:00:00 2001 From: Michal Karm Babacek Date: Fri, 30 Jul 2021 15:16:51 +0200 Subject: [PATCH 1/2] Enables parsing units for maxsize in JfrManager.java Fixes #3638 Example: Unpatched --------- ``` $ export JAVA_HOME=/home/karm/X/JDKs/graalvm-ce-java11-21.2.0/;export PATH=${JAVA_HOME}/bin:${PATH} $ native-image --version GraalVM 21.2.0 Java 11 CE (Java Version 11.0.12+6-jvmci-21.2-b08) $ javac Main.java $ native-image -H:+AllowVMInspection Main $ java -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10M,filename=flight-java.jfr -Xlog:jfr Main [0.279s][info][jfr] Flight Recorder initialized [0.279s][info][jfr] Created repository /tmp/2021_07_30_15_11_00_295289 [0.309s][info][jfr] Creating thread sampler for java:20 ms, native 0 ms [0.309s][info][jfr] Enrolling thread sampler [0.309s][info][jfr] Enrolling thread sampler [0.309s][info][jfr] Updated thread sampler for java: 20 ms, native 0 ms [0.309s][info][jfr] Updated thread sampler for java: 20 ms, native 0 ms [0.309s][info][jfr] Updated thread sampler for java: 20 ms, native 20 ms [0.322s][info][jfr] Started recording "1" (1) {maxsize=10.0MB, dumponexit=true, filename=/tmp/rep/flight-java.jfr} Started recording 1. Use jcmd 295289 JFR.dump name=1 to copy recording data to file. Meh. [0.343s][info][jfr] Updated thread sampler for java: 0 ms, native 20 ms [0.344s][info][jfr] Disenrolling thread sampler [0.344s][info][jfr] Stopped recording "1" (1). Reason "Dump on exit". [0.382s][info][jfr] Wrote recording "1" (1) to /tmp/rep/flight-java.jfr [0.382s][info][jfr] Closed recording "1" (1) [0.383s][info][jfr] Removed repository /tmp/2021_07_30_15_11_00_295289 $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10M,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr Exception in thread "main" com.oracle.svm.core.util.UserError$UserException: Could not parse JFR argument 'maxsize=10M'. Expected a number. at com.oracle.svm.core.util.UserError.abort(UserError.java:68) at com.oracle.svm.jfr.JfrManager.parseLong(JfrManager.java:171) at com.oracle.svm.jfr.JfrManager.initRecording(JfrManager.java:107) at com.oracle.svm.jfr.JfrManager.setup(JfrManager.java:72) at com.oracle.svm.core.jdk.RuntimeSupport.executeHooks(RuntimeSupport.java:125) at com.oracle.svm.core.jdk.RuntimeSupport.executeStartupHooks(RuntimeSupport.java:75) ``` Patched ------- ``` $ export JAVA_HOME=/home/karm/tmp/mandrel-java11-21.3-SNAPSHOT/;export PATH=${JAVA_HOME}/bin:${PATH} $ native-image --version native-image 21.3.0-deveab4c4ec5cb5 Mandrel Distribution (Java Version 11.0.12+7) $ native-image -H:+AllowVMInspection Main $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10M,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_13_28_295949 [info][jfr] Started recording "1" (1) {maxsize=10.0MB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10m,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_13_55_296117 [info][jfr] Started recording "1" (1) {maxsize=10.0MB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10k,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_14_00_296178 [info][jfr] Started recording "1" (1) {maxsize=10.0kB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10K,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_14_05_296238 [info][jfr] Started recording "1" (1) {maxsize=10.0kB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10g,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_14_11_296302 [info][jfr] Started recording "1" (1) {maxsize=10.0GB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. $ ./main -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10G,filename=flight-native.jfr -XX:FlightRecorderLogging=jfr [info][jfr] Flight Recorder initialized [info][jfr] Created repository /tmp/2021_07_30_15_16_04_296529 [info][jfr] Started recording "1" (1) {maxsize=10.0GB, dumponexit=true, filename=/tmp/rep/flight-native.jfr} Meh. ``` Signed-off-by: Michal Karm Babacek --- .../src/com/oracle/svm/jfr/JfrManager.java | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java index 1a2543fd8b5d..c5d8a26b6fd3 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java @@ -104,7 +104,7 @@ private static void initRecording() { Boolean disk = parseBoolean(args, JfrStartArgument.Disk); String path = args.get(JfrStartArgument.Filename); Long maxAge = parseDuration(args, JfrStartArgument.MaxAge); - Long maxSize = parseLong(args, JfrStartArgument.MaxSize); + Long maxSize = parseMaxSize(args, JfrStartArgument.MaxSize); Boolean dumpOnExit = parseBoolean(args, JfrStartArgument.DumpOnExit); Boolean pathToGcRoots = parseBoolean(args, JfrStartArgument.PathToGCRoots); @@ -160,19 +160,6 @@ private static Boolean parseBoolean(Map args, JfrStart } } - private static Long parseLong(Map args, JfrStartArgument key) throws IllegalArgumentException { - String value = args.get(key); - if (value == null) { - return null; - } else { - try { - return Long.valueOf(value); - } catch (NumberFormatException ex) { - throw UserError.abort("Could not parse JFR argument '" + key.cmdLineKey + "=" + value + "'. Expected a number."); - } - } - } - private static Long parseDuration(Map args, JfrStartArgument key) { String value = args.get(key); if (value != null) { @@ -217,6 +204,44 @@ private static Long parseDuration(Map args, JfrStartAr return null; } + private static Long parseMaxSize(Map args, JfrStartArgument key) { + final String value = args.get(key); + if (value != null) { + try { + int idx = indexOfFirstNonDigitCharacter(value); + long number; + try { + number = Long.parseLong(value.substring(0, idx)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Expected a number."); + } + + // Missing unit, number is plain bytes + if (idx == value.length()) { + return number; + } + + final char unit = value.substring(idx).charAt(0); + switch (unit) { + case 'k': + case 'K': + return number * 1024; + case 'm': + case 'M': + return number * 1024 * 1024; + case 'g': + case 'G': + return number * 1024 * 1024 * 1024; + default: + return number; + } + } catch (IllegalArgumentException e) { + throw UserError.abort("Could not parse JFR argument '" + key.cmdLineKey + "=" + value + "'. " + e.getMessage()); + } + } + return null; + } + private static int indexOfFirstNonDigitCharacter(String durationText) { int idx = 0; while (idx < durationText.length() && Character.isDigit(durationText.charAt(idx))) { From 3e6f3af08a2bcd6079651c1451f90b87761d7237 Mon Sep 17 00:00:00 2001 From: Michal Karm Babacek Date: Tue, 3 Aug 2021 01:15:03 +0200 Subject: [PATCH 2/2] Fixes duration unit for days from 'f' to 'd' see: ``` java -XX:+FlightRecorder -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10000,maxage=10000m,delay=5f,filename=flight-native.jfr -Xlog:jfr Main java.lang.IllegalArgumentException: Integer parsing error nanotime value: illegal unit whereas java -XX:+FlightRecorder -XX:+FlightRecorder -XX:StartFlightRecording=maxsize=10000,maxage=10000m,delay=5d,filename=flight-native.jfr -Xlog:jfr Main [0.562s][info][jfr] Flight Recorder initialized [0.562s][info][jfr] Created repository /tmp/2021_08_03_01_16_07_454665 [0.567s][info][jfr] Scheduled recording "1" (1) to start at 2021-08-08T01:16:07.684825 ``` Signed-off-by: Michal Karm Babacek --- .../com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java index c5d8a26b6fd3..d09fa662ecff 100644 --- a/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java +++ b/substratevm/src/com.oracle.svm.jfr/src/com/oracle/svm/jfr/JfrManager.java @@ -193,7 +193,7 @@ private static Long parseDuration(Map args, JfrStartAr return Duration.ofMinutes(time).toNanos(); } else if ("h".equals(unit)) { return Duration.ofHours(time).toNanos(); - } else if ("f".equals(unit)) { + } else if ("d".equals(unit)) { return Duration.ofDays(time).toNanos(); } throw new IllegalArgumentException("Unit is invalid."); @@ -233,6 +233,7 @@ private static Long parseMaxSize(Map args, JfrStartArg case 'G': return number * 1024 * 1024 * 1024; default: + // Unknown unit, number is treated as plain bytes return number; } } catch (IllegalArgumentException e) {