8303077: JFR: Add example usage to jdk.jfr

Reviewed-by: mgronlun
This commit is contained in:
Erik Gahlin 2023-03-01 22:54:03 +00:00
parent 394eac850c
commit d10d40a5b2
8 changed files with 299 additions and 25 deletions

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,8 +31,14 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Event field annotation, specifies that the value is a boolean flag, a {@code true} or
* {@code false} value.
* Event field annotation, specifies that the value is a boolean flag, a
* {@code true} or {@code false} value.
* <p>
* The following example shows how the {@code BooleanFlag} annotation can be
* used to describe that a setting is a boolean value. This information can be
* used by a graphical user interface to display the setting as a checkbox.
*
* {@snippet class = "Snippets" region = "BooleanFlagOverview"}
*
* @since 9
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -40,6 +40,11 @@ import jdk.jfr.internal.jfc.JFC;
/**
* A collection of settings and metadata describing the configuration.
* <p>
* The following example shows how the {@code Configuration} class can be used
* to list available configurations and how to pass a configuration object to a
* {@code Recording}.
* {@snippet class = "Snippets" region = "ConfigurationxsOverview"}
*
* @since 9
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -32,6 +32,11 @@ import java.lang.annotation.Target;
/**
* Event field annotation, specifies that a value represents an amount of data (for example, bytes).
* <p>
* The following example shows how the {@code DataAmount} annotation can be used to
* set the units {@code BITS} and {@code BYTES} to event fields.
*
* {@snippet class="Snippets" region="DataAmountOverview"}
*
* @since 9
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,19 @@ import java.lang.annotation.Target;
/**
* Event annotation, determines if an event should be enabled by default.
* <p>
* If an event doesn't have the annotation, then by default the event is enabled.
* If an event doesn't have the annotation, then by default the event is
* enabled.
* <p>
* The following example shows how the {@code Enabled} annotation can be used to
* create a disabled event. A disabled event will at most have the overhead of
* an allocation, or none if the runtime JIT compiler is able to eliminate it.
*
* {@snippet class = "Snippets" region = "EnabledOverview"}
*
* The event can be enabled programmatically, or on command line when needed,
* for example:
*
* {@snippet class = "Snippets" region = "EnabledOverviewCommandLine"}
*
* @since 9
*/

@ -40,6 +40,11 @@ import jdk.jfr.internal.Utils;
/**
* Describes an event, its fields, settings and annotations.
* <p>
* The following example shows how the {@code EventType} class can
* be used to print metadata about an event.
*
* {@snippet class="Snippets" region="EventTypeOverview"}
*
* @since 9
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,11 @@ import java.lang.annotation.Target;
/**
* Event annotation, specifies the default setting value for a periodic event.
* <p>
* The following example shows how the {@code Period} annotation can be used
* to emit events at different intervals.
*
* {@snippet class = "Snippets" region = "PeriodOverview"}
*
* @since 9
*/

@ -36,6 +36,11 @@ import jdk.jfr.internal.Utils;
/**
* Describes the event fields and annotation elements.
* <p>
* The following example shows how the {@code ValueDescriptor} class can
* be used to list field information of all types.
*
* {@snippet class="Snippets" region="ValueDescriptorOverview"}
*
* @since 9
*/

@ -25,12 +25,16 @@
package jdk.jfr.snippets;
import jdk.jfr.AnnotationElement;
import jdk.jfr.BooleanFlag;
import jdk.jfr.ValueDescriptor;
import jdk.jfr.EventFactory;
import jdk.jfr.EventType;
import jdk.jfr.Event;
import jdk.jfr.Name;
import jdk.jfr.Label;
import jdk.jfr.DataAmount;
import jdk.jfr.Description;
import jdk.jfr.Enabled;
import jdk.jfr.Category;
import jdk.jfr.ContentType;
import jdk.jfr.Period;
@ -39,6 +43,7 @@ import jdk.jfr.StackTrace;
import jdk.jfr.MetadataDefinition;
import jdk.jfr.Relational;
import jdk.jfr.consumer.RecordingFile;
import jdk.jfr.consumer.RecordingStream;
import jdk.jfr.Configuration;
import jdk.jfr.SettingDefinition;
import jdk.jfr.SettingControl;
@ -53,10 +58,13 @@ import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@ -83,6 +91,77 @@ public class Snippets {
// @end
}
// @start region="BooleanFlagOverview"
@BooleanFlag
@Name("example.Rollback")
@Label("Rollback")
@Description("Include transactions that are rollbacked")
public static class RollbackSetting extends SettingControl {
private boolean value = true;
@Override
public String combine(Set<String> values) {
return values.contains("true") ? "true" : "false";
}
@Override
public void setValue(String settingValue) {
value = "true".equals(settingValue);
}
@Override
public String getValue() {
return Boolean.toString(value);
}
public boolean shouldEmit() {
return value;
}
}
@Name("example.Transaction")
public static class TransactionEvent extends Event {
@Label("Context")
String context;
@Label("Rollback")
boolean rollback;
@SettingDefinition
@Name("rollback")
public boolean rollback(RollbackSetting rollbackSetting) {
return rollback && rollbackSetting.shouldEmit();
}
}
// @end
static class ConfigurationOverview {
// @start region="ConfigurationxsOverview"
public static void main(String... args) throws Exception {
if (args.length == 0) {
System.out.println("Configurations:");
for (Configuration c : Configuration.getConfigurations()) {
System.out.println("Name: " + c.getName());
System.out.println("Label: " + c.getLabel());
System.out.println("Description: " + c.getDescription());
System.out.println("Provider: " + c.getProvider());
System.out.println();
}
} else {
String name = args[0];
Configuration c = Configuration.getConfiguration(name);
try (Recording r = new Recording(c)) {
System.out.println("Starting recording with settings:");
for (Map.Entry<String, String> setting : c.getSettings().entrySet()) {
System.out.println(setting.getKey() + " = " + setting.getValue());
}
r.start();
}
}
}
// @end
}
record CPU(String id, float temperature) {
}
@ -161,6 +240,47 @@ public class Snippets {
}
// @end
// @start region="DataAmountOverview"
@Name("com.example.ImageRender")
@Label("Image Render")
public class ImageRender extends Event {
@Label("Height")
long height;
@Label("Width")
long width;
@Label("Color Depth")
@DataAmount(DataAmount.BITS)
int colorDepth;
@Label("Memory Size")
@DataAmount // bytes by default
long memorySize;
}
// @end
// @start region="EnabledOverview"
@Name("StopWatch")
@Label("Stop Watch")
@Category("Debugging")
@StackTrace(false)
@Enabled(false)
static public class StopWatchEvent extends Event {
}
public void update() {
StopWatchEvent e = new StopWatchEvent();
e.begin();
code: // @replace regex='code:' replacement="..."
e.commit();
}
// @end
/*
// @start region="EnabledOverviewCommandLine"
java -XX:StartFlightRecording:StopWatch#enabled=true ...
// @end
*/
// @start region="EventOverview"
public class Example {
@ -205,16 +325,40 @@ public class Snippets {
void EventSettingOverview() throws Exception {
// @start region="EventSettingOverview"
Recording r = new Recording();
r.enable("jdk.CPULoad")
.withPeriod(Duration.ofSeconds(1));
r.enable("jdk.FileWrite")
.withoutStackTrace()
.withThreshold(Duration.ofNanos(10));
r.start();
Thread.sleep(10_000);
r.stop();
r.dump(Files.createTempFile("recording", ".jfr"));
try (Recording r = new Recording()) {
r.enable("jdk.CPULoad")
.withPeriod(Duration.ofSeconds(1));
r.enable("jdk.FileWrite")
.withoutStackTrace()
.withThreshold(Duration.ofNanos(10));
r.start();
Thread.sleep(10_000);
r.stop();
r.dump(Files.createTempFile("recording", ".jfr"));
}
// @end
}
void EventTypeOverview() {
// @start region="EventTypeOverview"
for (EventType eventType : FlightRecorder.getFlightRecorder().getEventTypes()) {
System.out.println("Event Type: " + eventType.getName());
if (eventType.getLabel() != null) {
System.out.println("Label: " + eventType.getLabel());
}
if (eventType.getDescription() != null) {
System.out.println("Description: " + eventType.getDescription());
}
StringJoiner s = new StringJoiner(" / ");
for (String category : eventType.getCategoryNames()) {
s.add(category);
}
System.out.println("Category: " + s);
System.out.println("Fields: " + eventType.getFields().size());
System.out.println("Annotations: " + eventType.getAnnotationElements().size());
System.out.println("Settings: " + eventType.getSettingDescriptors().size());
System.out.println("Enabled: " + eventType.isEnabled());
System.out.println();
}
// @end
}
@ -261,6 +405,54 @@ public class Snippets {
}
// @end
void PeriodOverview() {
// @start region = "PeriodOverview"
@Period("1 s")
@Name("Counter")
class CountEvent extends Event {
int count;
}
@Period("3 s")
@Name("Fizz")
class FizzEvent extends Event {
}
@Period("5 s")
@Name("Buzz")
class BuzzEvent extends Event {
}
var counter = new AtomicInteger();
FlightRecorder.addPeriodicEvent(CountEvent.class, () -> {
CountEvent event = new CountEvent();
event.count = counter.incrementAndGet();
event.commit();
});
FlightRecorder.addPeriodicEvent(FizzEvent.class, () -> {
new FizzEvent().commit();
});
FlightRecorder.addPeriodicEvent(BuzzEvent.class, () -> {
new BuzzEvent().commit();
});
var sb = new StringBuilder();
var last = new AtomicInteger();
var current = new AtomicInteger();
try (var r = new RecordingStream()) {
r.onEvent("Counter", e -> current.set(e.getValue("count")));
r.onEvent("Fizz", e -> sb.append("Fizz"));
r.onEvent("Buzz", e -> sb.append("Buzz"));
r.onFlush(() -> {
if (current.get() != last.get()) {
System.out.println(sb.isEmpty() ? current : sb);
last.set(current.get());
sb.setLength(0);
}
});
r.start();
}
// @end
}
// @start region="RelationalOverview"
@MetadataDefinition
@Relational
@ -303,12 +495,13 @@ public class Snippets {
void RecordingnOverview() throws Exception {
// @start region="RecordingOverview"
Configuration c = Configuration.getConfiguration("default");
Recording r = new Recording(c);
r.start();
System.gc();
Thread.sleep(5000);
r.stop();
r.dump(Files.createTempFile("my-recording", ".jfr"));
try (Recording r = new Recording(c)) {
r.start();
System.gc();
Thread.sleep(5000);
r.stop();
r.dump(Files.createTempFile("my-recording", ".jfr"));
}
// @end
}
@ -410,4 +603,42 @@ public class Snippets {
}
}
// @end
static class ValueDsecriptorOverview {
// @start region="ValueDescriptorOverview"
void printTypes() {
Map<String, List<ValueDescriptor>> typeMap = new LinkedHashMap<>();
for (EventType eventType : FlightRecorder.getFlightRecorder().getEventTypes()) {
findTypes(typeMap, eventType.getName(), eventType.getFields());
}
for (String type : typeMap.keySet()) {
System.out.println("Type: " + type);
for (ValueDescriptor field : typeMap.get(type)) {
System.out.println(" Field: " + field.getName());
String arrayBrackets = field.isArray() ? "[]" : "";
System.out.println(" Type: " + field.getTypeName() + arrayBrackets);
if (field.getLabel() != null) {
System.out.println(" Label: " + field.getLabel());
}
if (field.getDescription() != null) {
System.out.println(" Description: " + field.getDescription());
}
if (field.getContentType() != null) {
System.out.println(" Content Types: " + field.getContentType());
}
}
System.out.println();
}
}
void findTypes(Map<String, List<ValueDescriptor>> typeMap, String typeName, List<ValueDescriptor> fields) {
if (!typeMap.containsKey(typeName)) {
typeMap.put(typeName, fields);
for (ValueDescriptor subField : fields) {
findTypes(typeMap, subField.getTypeName(), subField.getFields());
}
}
}
// @end
}
}