23
23
24
24
package openj9 .internal .tools .attach .target ;
25
25
26
+ import java .io .File ;
26
27
import java .io .PrintWriter ;
27
28
import java .io .StringWriter ;
29
+ import java .nio .file .InvalidPathException ;
30
+ import java .nio .file .Path ;
31
+ import java .nio .file .Paths ;
28
32
import java .util .Arrays ;
29
33
import java .util .HashMap ;
30
34
import java .util .Map ;
@@ -144,6 +148,9 @@ public class DiagnosticUtils {
144
148
private static final String DIAGNOSTICS_JFR_START = "JFR.start" ;
145
149
private static final String DIAGNOSTICS_JFR_DUMP = "JFR.dump" ;
146
150
private static final String DIAGNOSTICS_JFR_STOP = "JFR.stop" ;
151
+
152
+ private static final int ERROR_NO_TIME_UNIT = -1 ;
153
+ private static final int ERROR_NO_TIME_DURATION = -2 ;
147
154
/*[ENDIF] JFR_SUPPORT */
148
155
149
156
/**
@@ -209,6 +216,35 @@ public static String makeThreadPrintCommand(boolean lockedSynchronizers) {
209
216
* @return formatted string
210
217
*/
211
218
public static String makeJcmdCommand (String [] options , int skip ) {
219
+ /*[IF JFR_SUPPORT]*/
220
+ if (options .length >= 2 ) {
221
+ // there is a jcmd command
222
+ if (DIAGNOSTICS_JFR_START .equalsIgnoreCase (options [1 ])) {
223
+ // search JFR.start options
224
+ for (int i = 2 ; i < options .length ; i ++) {
225
+ String option = options [i ];
226
+ IPC .logMessage ("makeJcmdCommand: option = " , option );
227
+ if (option .startsWith ("filename=" )) {
228
+ String fileName = option .substring (option .indexOf ("=" ) + 1 );
229
+ try {
230
+ Path filePath = Paths .get (fileName );
231
+ if (!filePath .isAbsolute ()) {
232
+ // default recording file path is jcmd current working directory
233
+ String jcmdPWD = Paths .get ("" ).toAbsolutePath ().toString ();
234
+ fileName = jcmdPWD + File .separator + fileName ;
235
+ IPC .logMessage ("makeJcmdCommand: absolute filename = " , fileName );
236
+ // replace existing entry with an absolute jcmd pwd path for the target VM
237
+ options [i ] = "filename=" + fileName ;
238
+ }
239
+ } catch (InvalidPathException ipe ) {
240
+ // ignore this exception and keep the original entry
241
+ IPC .logMessage ("makeJcmdCommand: ipe = " , ipe .getMessage ());
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ /*[ENDIF] JFR_SUPPORT */
212
248
String cmd = String .join (DIAGNOSTICS_OPTION_SEPARATOR , Arrays .asList (options ).subList (skip , options .length ));
213
249
return cmd ;
214
250
}
@@ -415,13 +451,25 @@ private static long convertToMilliseconds(String timeValue) {
415
451
timeInMilli = TimeUnit .DAYS .toMillis (time );
416
452
break ;
417
453
default :
418
- // no unit or unrecognized unit, assume milliseconds
419
- timeInMilli = time ;
454
+ // no unit or unrecognized unit, return ERROR_NO_TIME_UNIT
455
+ timeInMilli = ERROR_NO_TIME_UNIT ;
420
456
break ;
421
457
}
422
458
return timeInMilli ;
423
459
}
424
460
461
+ /**
462
+ * Parse a time parameter, and return the duration in milliseconds.
463
+ * If the time unit is missing, ERROR_NO_TIME_UNIT is returned.
464
+ * If the paramName is not in parameters, ERROR_NO_TIME_DURATION is returned.
465
+ *
466
+ * @param paramName the parameter name
467
+ * @param parameters the parameter array
468
+ *
469
+ * @return the duration in milliseconds,
470
+ * ERROR_NO_TIME_UNIT if no time unit,
471
+ * ERROR_NO_TIME_DURATION if paramName wasn't found.
472
+ */
425
473
private static long parseTimeParameter (String paramName , String [] parameters ) {
426
474
for (String param : parameters ) {
427
475
if (param .startsWith (paramName + "=" )) {
@@ -431,7 +479,7 @@ private static long parseTimeParameter(String paramName, String[] parameters) {
431
479
}
432
480
}
433
481
}
434
- return - 1 ;
482
+ return ERROR_NO_TIME_DURATION ;
435
483
}
436
484
437
485
private static String parseStringParameter (String paramName , String [] parameters , String defaultValue ) {
@@ -448,35 +496,33 @@ private static String parseStringParameter(String paramName, String[] parameters
448
496
449
497
private static DiagnosticProperties doJFR (String diagnosticCommand ) {
450
498
DiagnosticProperties result = null ;
451
-
452
499
// split the command and arguments
453
500
String [] parts = diagnosticCommand .split (DIAGNOSTICS_OPTION_SEPARATOR );
454
501
IPC .logMessage ("doJFR: " , diagnosticCommand );
455
-
456
502
// ensure there's at least one part for the command
457
503
if (parts .length == 0 ) {
458
504
return DiagnosticProperties .makeErrorProperties ("Error: No JFR command specified" );
459
505
}
460
-
461
506
String command = parts [0 ].trim ();
462
507
String [] parameters = Arrays .copyOfRange (parts , 1 , parts .length );
463
-
464
508
String fileName = parseStringParameter ("filename" , parameters , null );
465
509
IPC .logMessage ("doJFR: filename = " , fileName );
466
- boolean setFileName = (fileName != null ) && !fileName .isEmpty ();
467
- if (setFileName ) {
468
- if (!VM .setJFRRecordingFileName (fileName )) {
469
- return DiagnosticProperties .makeErrorProperties ("setJFRRecordingFileName failed" );
470
- } else {
471
- jfrRecordingFileName = fileName ;
472
- }
473
- }
474
510
475
511
try {
476
512
if (command .equalsIgnoreCase (DIAGNOSTICS_JFR_START )) {
477
513
if (VM .isJFRRecordingStarted ()) {
478
514
result = DiagnosticProperties .makeErrorProperties ("One JFR recording is in progress [" + jfrRecordingFileName + "], only one recording is allowed at a time." );
479
515
} else {
516
+ // only JFR.start command is allowed to change the recording filename
517
+ boolean setFileName = (fileName != null ) && !fileName .isEmpty ();
518
+ if (setFileName ) {
519
+ // the recording filename should be set before VM.startJFR() which invokes JFRWriter:openJFRFile()
520
+ if (!VM .setJFRRecordingFileName (fileName )) {
521
+ return DiagnosticProperties .makeErrorProperties ("setJFRRecordingFileName() failed" );
522
+ } else {
523
+ jfrRecordingFileName = fileName ;
524
+ }
525
+ }
480
526
VM .startJFR ();
481
527
long duration = parseTimeParameter ("duration" , parameters );
482
528
IPC .logMessage ("doJFR: duration = " + duration );
@@ -488,6 +534,8 @@ public void run() {
488
534
}
489
535
};
490
536
timer .schedule (jfrDumpTask , duration );
537
+ } if (duration == ERROR_NO_TIME_UNIT ) {
538
+ return DiagnosticProperties .makeErrorProperties ("The duration doesn't have a time unit." );
491
539
} else {
492
540
// the recording is on until JFR.stop
493
541
}
0 commit comments