feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
420
jdkSrc/jdk8/jdk/jfr/AnnotationElement.java
Normal file
420
jdkSrc/jdk8/jdk/jfr/AnnotationElement.java
Normal file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.TypeLibrary;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Describes event metadata, such as labels, descriptions and units.
|
||||
* <p>
|
||||
* The following example shows how {@code AnnotationElement} can be used to dynamically define events.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* List{@literal <}AnnotationElement{@literal >} typeAnnotations = new ArrayList{@literal <}{@literal >}();
|
||||
* typeannotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld");
|
||||
* typeAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
|
||||
* typeAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
|
||||
*
|
||||
* List{@literal <}AnnotationElement{@literal >} fieldAnnotations = new ArrayList{@literal <}{@literal >}();
|
||||
* fieldAnnotations.add(new AnnotationElement(Label.class, "Message"));
|
||||
*
|
||||
* List{@literal <}ValueDescriptor{@literal >} fields = new ArrayList{@literal <}{@literal >}();
|
||||
* fields.add(new ValueDescriptor(String.class, "message", fieldAnnotations));
|
||||
*
|
||||
* EventFactory f = EventFactory.create(typeAnnotations, fields);
|
||||
* Event event = f.newEvent();
|
||||
* event.commit();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class AnnotationElement {
|
||||
private final Type type;
|
||||
private final List<Object> annotationValues;
|
||||
private final List<String> annotationNames;
|
||||
private final boolean inBootClassLoader;
|
||||
|
||||
// package private
|
||||
AnnotationElement(Type type, List<Object> objects, boolean boot) {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(objects);
|
||||
this.type = type;
|
||||
if (objects.size() != type.getFields().size()) {
|
||||
StringJoiner descriptors = new StringJoiner(",", "[", "]");
|
||||
for (ValueDescriptor v : type.getFields()) {
|
||||
descriptors.add(v.getName());
|
||||
}
|
||||
StringJoiner values = new StringJoiner(",", "[", "]");
|
||||
for (Object object : objects) {
|
||||
descriptors.add(String.valueOf(object));
|
||||
}
|
||||
throw new IllegalArgumentException("Annotation " + descriptors + " for " + type.getName() + " doesn't match number of values " + values);
|
||||
}
|
||||
|
||||
List<String> n = new ArrayList<>();
|
||||
List<Object> v = new ArrayList<>();
|
||||
int index = 0;
|
||||
for (ValueDescriptor valueDescriptor : type.getFields()) {
|
||||
Object object = objects.get(index);
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("Annotation value can't be null");
|
||||
}
|
||||
Class<?> valueType = object.getClass();
|
||||
if (valueDescriptor.isArray()) {
|
||||
valueType = valueType.getComponentType();
|
||||
}
|
||||
checkType(Utils.unboxType(valueType));
|
||||
n.add(valueDescriptor.getName());
|
||||
v.add(object);
|
||||
index++;
|
||||
}
|
||||
this.annotationValues = Utils.smallUnmodifiable(v);
|
||||
this.annotationNames = Utils.smallUnmodifiable(n);
|
||||
this.inBootClassLoader = boot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an annotation element to use for dynamically defined events.
|
||||
* <p>
|
||||
* Supported value types are {@code byte}, {@code int}, {@code short},
|
||||
* {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
|
||||
* and {@code String}. Enums, arrays and classes, are not supported.
|
||||
* <p>
|
||||
* If {@code annotationType} has annotations (directly present, indirectly
|
||||
* present, or associated), then those annotation are recursively included.
|
||||
* However, both the {@code annotationType} and any annotation found recursively
|
||||
* must have the {@link MetadataDefinition} annotation.
|
||||
* <p>
|
||||
* To statically define events, see {@link Event} class.
|
||||
*
|
||||
* @param annotationType interface extending
|
||||
* {@code java.lang.annotation.Annotation}, not {@code null}
|
||||
* @param values a {@code Map} with keys that match method names of the specified
|
||||
* annotation interface
|
||||
* @throws IllegalArgumentException if value/key is {@code null}, an unsupported
|
||||
* value type is used, or a value/key is used that doesn't match the
|
||||
* signatures in the {@code annotationType}
|
||||
*/
|
||||
public AnnotationElement(Class<? extends Annotation> annotationType, Map<String, Object> values) {
|
||||
Objects.requireNonNull(annotationType);
|
||||
Objects.requireNonNull(values);
|
||||
Utils.checkRegisterPermission();
|
||||
// copy values to avoid modification after validation
|
||||
HashMap<String, Object> map = new HashMap<>(values);
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
if (entry.getKey() == null) {
|
||||
throw new NullPointerException("Name of annotation method can't be null");
|
||||
}
|
||||
if (entry.getValue() == null) {
|
||||
throw new NullPointerException("Return value for annotation method can't be null");
|
||||
}
|
||||
}
|
||||
|
||||
if (AnnotationElement.class.isAssignableFrom(annotationType) && annotationType.isInterface()) {
|
||||
throw new IllegalArgumentException("Must be interface extending " + Annotation.class.getName());
|
||||
}
|
||||
if (!isKnownJFRAnnotation(annotationType) && annotationType.getAnnotation(MetadataDefinition.class) == null) {
|
||||
throw new IllegalArgumentException("Annotation class must be annotated with jdk.jfr.MetadataDefinition to be valid");
|
||||
}
|
||||
if (isKnownJFRAnnotation(annotationType)) {
|
||||
this.type = new Type(annotationType.getCanonicalName(), Type.SUPER_TYPE_ANNOTATION, Type.getTypeId(annotationType));
|
||||
} else {
|
||||
this.type = TypeLibrary.createAnnotationType(annotationType);
|
||||
}
|
||||
Method[] methods = annotationType.getDeclaredMethods();
|
||||
if (methods.length != map.size()) {
|
||||
throw new IllegalArgumentException("Number of declared methods must match size of value map");
|
||||
}
|
||||
List<String> n = new ArrayList<>();
|
||||
List<Object> v = new ArrayList<>();
|
||||
Set<String> nameSet = new HashSet<>();
|
||||
for (Method method : methods) {
|
||||
String fieldName = method.getName();
|
||||
Object object = map.get(fieldName);
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("No method in annotation interface " + annotationType.getName() + " matching name " + fieldName);
|
||||
}
|
||||
Class<?> fieldType = object.getClass();
|
||||
|
||||
if (fieldType == Class.class) {
|
||||
throw new IllegalArgumentException("Annotation value for " + fieldName + " can't be class");
|
||||
}
|
||||
if (object instanceof Enum) {
|
||||
throw new IllegalArgumentException("Annotation value for " + fieldName + " can't be enum");
|
||||
}
|
||||
if (!fieldType.equals(object.getClass())) {
|
||||
throw new IllegalArgumentException("Return type of annotation " + fieldType.getName() + " must match type of object" + object.getClass());
|
||||
}
|
||||
|
||||
if (fieldType.isArray()) {
|
||||
Class<?> componentType = fieldType.getComponentType();
|
||||
checkType(componentType);
|
||||
if (componentType.equals(String.class)) {
|
||||
String[] stringArray = (String[]) object;
|
||||
for (int i = 0; i < stringArray.length; i++) {
|
||||
if (stringArray[i] == null) {
|
||||
throw new IllegalArgumentException("Annotation value for " + fieldName + " contains null");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fieldType = Utils.unboxType(object.getClass());
|
||||
checkType(fieldType);
|
||||
}
|
||||
if (nameSet.contains(fieldName)) {
|
||||
throw new IllegalArgumentException("Value with name '" + fieldName + "' already exists");
|
||||
}
|
||||
if (isKnownJFRAnnotation(annotationType)) {
|
||||
ValueDescriptor vd = new ValueDescriptor(fieldType, fieldName, Collections.emptyList(), true);
|
||||
type.add(vd);
|
||||
}
|
||||
n.add(fieldName);
|
||||
v.add(object);
|
||||
}
|
||||
this.annotationValues = Utils.smallUnmodifiable(v);
|
||||
this.annotationNames = Utils.smallUnmodifiable(n);
|
||||
this.inBootClassLoader = annotationType.getClassLoader() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an annotation element to use for dynamically defined events.
|
||||
* <p>
|
||||
* Supported value types are {@code byte}, {@code int}, {@code short},
|
||||
* {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
|
||||
* and {@code String}. Enums, arrays, and classes are not supported.
|
||||
* <p>
|
||||
* If {@code annotationType} has annotations (directly present, indirectly
|
||||
* present, or associated), then those annotations are recursively included.
|
||||
* However, both {@code annotationType} and any annotation found recursively
|
||||
* must have the {@link MetadataDefinition} annotation.
|
||||
* <p>
|
||||
* To statically define events, see {@link Event} class.
|
||||
*
|
||||
* @param annotationType interface extending
|
||||
* {@code java.lang.annotation.Annotation,} not {@code null}
|
||||
* @param value the value that matches the {@code value} method of the specified
|
||||
* {@code annotationType}
|
||||
* @throws IllegalArgumentException if value/key is {@code null}, an unsupported
|
||||
* value type is used, or a value/key is used that doesn't match the
|
||||
* signatures in the {@code annotationType}
|
||||
*/
|
||||
public AnnotationElement(Class<? extends Annotation> annotationType, Object value) {
|
||||
this(annotationType, Collections.singletonMap("value", Objects.requireNonNull(value)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an annotation element to use for dynamically defined events.
|
||||
* <p>
|
||||
* Supported value types are {@code byte}, {@code short}, {@code int},
|
||||
* {@code long}, {@code double}, {@code float}, {@code boolean}, {@code char},
|
||||
* and {@code String}. Enums, arrays, and classes are not supported.
|
||||
* <p>
|
||||
* If {@code annotationType} has annotations (directly present, indirectly
|
||||
* present or associated), then those annotation are recursively included.
|
||||
* However, both {@code annotationType} and any annotation found recursively
|
||||
* must have the {@link MetadataDefinition} annotation.
|
||||
* <p>
|
||||
* To statically define events, see {@link Event} class.
|
||||
*
|
||||
* @param annotationType interface extending java.lang.annotation.Annotation,
|
||||
* not {@code null}
|
||||
*/
|
||||
public AnnotationElement(Class<? extends Annotation> annotationType) {
|
||||
this(annotationType, Collections.emptyMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of annotation values in an order that matches the
|
||||
* value descriptors for this {@code AnnotationElement}.
|
||||
*
|
||||
* @return list of values, not {@code null}
|
||||
*/
|
||||
public List<Object> getValues() {
|
||||
return annotationValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of descriptors that describes the annotation values
|
||||
* for this {@code AnnotationElement}.
|
||||
*
|
||||
* @return the list of value descriptors for this {@code Annotation}, not
|
||||
* {@code null}
|
||||
*/
|
||||
public List<ValueDescriptor> getValueDescriptors() {
|
||||
return Collections.unmodifiableList(type.getFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of annotation elements for this
|
||||
* {@code AnnotationElement}.
|
||||
*
|
||||
* @return a list of meta annotation, not {@code null}
|
||||
*/
|
||||
public List<AnnotationElement> getAnnotationElements() {
|
||||
return type.getAnnotationElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified name of the annotation type that corresponds to
|
||||
* this {@code AnnotationElement} (for example, {@code "jdk.jfr.Label"}).
|
||||
*
|
||||
* @return type name, not {@code null}
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value for this {@code AnnotationElement}.
|
||||
*
|
||||
* @param name the name of the method in the annotation interface, not
|
||||
* {@code null}.
|
||||
*
|
||||
* @return the annotation value, not {@code null}.
|
||||
*
|
||||
* @throws IllegalArgumentException if a method with the specified name does
|
||||
* not exist in the annotation
|
||||
*/
|
||||
public Object getValue(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
int index = 0;
|
||||
for (String n : annotationNames) {
|
||||
if (name.equals(n)) {
|
||||
return annotationValues.get(index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
StringJoiner valueNames = new StringJoiner(",", "[", "]");
|
||||
for (ValueDescriptor v : type.getFields()) {
|
||||
valueNames.add(v.getName());
|
||||
}
|
||||
throw new IllegalArgumentException("No value with name '" + name + "'. Valid names are " + valueNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if an annotation value with the specified name exists in
|
||||
* this {@code AnnotationElement}.
|
||||
*
|
||||
* @param name name of the method in the annotation interface to find, not
|
||||
* {@code null}
|
||||
*
|
||||
* @return {@code true} if method exists, {@code false} otherwise
|
||||
*/
|
||||
public boolean hasValue(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
for (String n : annotationNames) {
|
||||
if (name.equals(n)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first annotation for the specified type if an
|
||||
* {@code AnnotationElement} with the same name exists, else {@code null}.
|
||||
*
|
||||
* @param <A> the type of the annotation to query for and return if it exists
|
||||
* @param annotationType the {@code Class object} corresponding to the annotation type,
|
||||
* not {@code null}
|
||||
* @return this element's annotation for the specified annotation type if
|
||||
* it it exists, else {@code null}
|
||||
*/
|
||||
public final <A> A getAnnotation(Class<? extends Annotation> annotationType) {
|
||||
Objects.requireNonNull(annotationType);
|
||||
return type.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type ID for this {@code AnnotationElement}.
|
||||
* <p>
|
||||
* The ID is a unique identifier for the type in the Java Virtual Machine (JVM). The ID might not
|
||||
* be the same between JVM instances.
|
||||
*
|
||||
* @return the type ID, not negative
|
||||
*/
|
||||
public long getTypeId() {
|
||||
return type.getId();
|
||||
}
|
||||
|
||||
// package private
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private static void checkType(Class<?> type) {
|
||||
if (type.isPrimitive()) {
|
||||
return;
|
||||
}
|
||||
if (type == String.class) {
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("Only primitives types or java.lang.String are allowed");
|
||||
}
|
||||
|
||||
// Whitelist of annotation classes that are allowed, even though
|
||||
// they don't have @MetadataDefinition.
|
||||
private static boolean isKnownJFRAnnotation(Class<? extends Annotation> annotationType) {
|
||||
if (annotationType == Registered.class) {
|
||||
return true;
|
||||
}
|
||||
if (annotationType == Threshold.class) {
|
||||
return true;
|
||||
}
|
||||
if (annotationType == StackTrace.class) {
|
||||
return true;
|
||||
}
|
||||
if (annotationType == Period.class) {
|
||||
return true;
|
||||
}
|
||||
if (annotationType == Enabled.class) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// package private
|
||||
boolean isInBoot() {
|
||||
return inBootClassLoader;
|
||||
}
|
||||
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/BooleanFlag.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/BooleanFlag.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
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
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Flag")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface BooleanFlag {
|
||||
}
|
||||
130
jdkSrc/jdk8/jdk/jfr/Category.java
Normal file
130
jdkSrc/jdk8/jdk/jfr/Category.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event annotation, to associate the event type with a category, in the format
|
||||
* of a human-readable path.
|
||||
* <p>
|
||||
* The category determines how an event is presented to the user. Events that
|
||||
* are in the same category are typically displayed together in graphs and
|
||||
* trees. To avoid the overlap of durational events in graphical
|
||||
* representations, overlapping events must be in separate categories.
|
||||
* <p>
|
||||
* For example, to monitor image uploads to a web server with a separate thread
|
||||
* for each upload, an event called File Upload starts when the user uploads a
|
||||
* file and ends when the upload is complete. For advanced diagnostics about
|
||||
* image uploads, more detailed events are created (for example, Image Read,
|
||||
* Image Resize, and Image Write). During these detailed events. other low
|
||||
* level-events could occur (for example, Socket Read and File Write).
|
||||
* <p>
|
||||
* The following example shows a visualization that avoids overlaps:
|
||||
*
|
||||
* <pre>
|
||||
* -------------------------------------------------------------------
|
||||
* | File Upload |
|
||||
* ------------------------------------------------------------------
|
||||
* | Image Read | Image Resize | Image Write |
|
||||
* ------------------------------------------------------------------
|
||||
* | Socket Read | Socket Read | | File Write |
|
||||
* -------------------------------------------------------------------
|
||||
* </pre>
|
||||
*
|
||||
* The example can be achieved by using the following categories:
|
||||
*
|
||||
* <table class="striped">
|
||||
* <caption>Recording options and their purpose.</caption> <thead>
|
||||
* <tr>
|
||||
* <th scope="col">Event Name</th>
|
||||
* <th scope="col">Annotation</th>
|
||||
* </tr>
|
||||
* </thead> <tbody>
|
||||
* <tr>
|
||||
* <th scope="row">File Upload</th>
|
||||
* <td><code>@Category("Upload")</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">Image Read</th>
|
||||
* <td><code>@Category({"Upload", "Image Upload"})</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">Image Resize</th>
|
||||
* <td><code>@Category({"Upload", "Image Upload"})</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">Image Write</th>
|
||||
* <td><code>@Category({"Upload", "Image Upload"})</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">Socket Read</th>
|
||||
* <td><code>@Category("Java Application")</code></td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">File Write</th>
|
||||
* <td><code>@Category("Java Application")</code></td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
* <p>
|
||||
* The File Upload, Image Read, and Socket Read events happen concurrently (in
|
||||
* the same thread), but the events are in different categories so they do not
|
||||
* overlap in the visualization.
|
||||
* <p>
|
||||
* The following examples shows how the category is used to determine how events
|
||||
* are visualized in a tree:
|
||||
*
|
||||
* <pre>
|
||||
* |- Java Application
|
||||
* | |- Socket Read
|
||||
* | |- File Write
|
||||
* |- Upload
|
||||
* |- File Upload
|
||||
* |- Image Upload
|
||||
* |- Image Read
|
||||
* |- Image Resize
|
||||
* |- File Write
|
||||
* </pre>
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE })
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Category {
|
||||
/**
|
||||
* Returns the category names for this annotation, starting with the root.
|
||||
*
|
||||
* @return the category names
|
||||
*/
|
||||
String[] value();
|
||||
}
|
||||
197
jdkSrc/jdk8/jdk/jfr/Configuration.java
Normal file
197
jdkSrc/jdk8/jdk/jfr/Configuration.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.JVMSupport;
|
||||
import jdk.jfr.internal.jfc.JFC;
|
||||
|
||||
/**
|
||||
* A collection of settings and metadata describing the configuration.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class Configuration {
|
||||
private final Map<String, String> settings;
|
||||
private final String label;
|
||||
private final String description;
|
||||
private final String provider;
|
||||
private final String contents;
|
||||
private final String name;
|
||||
|
||||
// package private
|
||||
Configuration(String name, String label, String description, String provider, Map<String, String> settings, String contents) {
|
||||
this.name = name;
|
||||
this.label = label;
|
||||
this.description = description;
|
||||
this.provider = provider;
|
||||
this.settings = settings;
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings that specifies how a recording is configured.
|
||||
* <p>
|
||||
* Modifying the returned {@code Map} object doesn't change the
|
||||
* configuration.
|
||||
*
|
||||
* @return settings, not {@code null}
|
||||
*/
|
||||
public Map<String, String> getSettings() {
|
||||
return new LinkedHashMap<String, String>(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an identifying name (for example, {@code "default" or "profile")}.
|
||||
*
|
||||
* @return the name, or {@code null} if it doesn't exist
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name (for example, {@code "Continuous" or "Profiling"}}.
|
||||
*
|
||||
* @return the label, or {@code null} if it doesn't exist
|
||||
*/
|
||||
public String getLabel() {
|
||||
return this.label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a short sentence that describes the configuration (for example
|
||||
* {@code "Low
|
||||
* overhead configuration safe for continuous use in production
|
||||
* environments"})
|
||||
*
|
||||
* @return the description, or {@code null} if it doesn't exist
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns who created the configuration (for example {@code "OpenJDK"}).
|
||||
*
|
||||
* @return the provider, or {@code null} if it doesn't exist
|
||||
*/
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual representation of the configuration (for example, the
|
||||
* contents of a JFC file).
|
||||
*
|
||||
* @return contents, or {@code null} if it doesn't exist
|
||||
*
|
||||
* @see Configuration#getContents()
|
||||
*/
|
||||
public String getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a configuration from a file.
|
||||
*
|
||||
* @param path the file that contains the configuration, not {@code null}
|
||||
* @return the read {@link Configuration}, not {@code null}
|
||||
* @throws ParseException if the file can't be parsed
|
||||
* @throws IOException if the file can't be read
|
||||
* @throws SecurityException if a security manager exists and its
|
||||
* {@code checkRead} method denies read access to the file.
|
||||
*
|
||||
* @see java.io.File#getPath()
|
||||
* @see java.lang.SecurityManager#checkRead(java.lang.String)
|
||||
*/
|
||||
public static Configuration create(Path path) throws IOException, ParseException {
|
||||
Objects.requireNonNull(path);
|
||||
JVMSupport.ensureWithIOException();
|
||||
try (Reader reader = Files.newBufferedReader(path)) {
|
||||
return JFC.create(JFC.nameFromPath(path), reader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a configuration from a character stream.
|
||||
*
|
||||
* @param reader a {@code Reader} that provides the configuration contents, not
|
||||
* {@code null}
|
||||
* @return a configuration, not {@code null}
|
||||
* @throws IOException if an I/O error occurs while trying to read contents
|
||||
* from the {@code Reader}
|
||||
* @throws ParseException if the file can't be parsed
|
||||
*/
|
||||
public static Configuration create(Reader reader) throws IOException, ParseException {
|
||||
Objects.requireNonNull(reader);
|
||||
JVMSupport.ensureWithIOException();
|
||||
return JFC.create(null, reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a predefined configuration.
|
||||
* <p>
|
||||
* See {@link Configuration#getConfigurations()} for available configuration
|
||||
* names.
|
||||
*
|
||||
* @param name the name of the configuration (for example, {@code "default"} or
|
||||
* {@code "profile"})
|
||||
* @return a configuration, not {@code null}
|
||||
*
|
||||
* @throws IOException if a configuration with the given name does not
|
||||
* exist, or if an I/O error occurs while reading the
|
||||
* configuration file
|
||||
* @throws ParseException if the configuration file can't be parsed
|
||||
*/
|
||||
public static Configuration getConfiguration(String name) throws IOException, ParseException {
|
||||
JVMSupport.ensureWithIOException();
|
||||
return JFC.getPredefined(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of predefined configurations for this Java Virtual Machine (JVM).
|
||||
*
|
||||
* @return the list of predefined configurations, not {@code null}
|
||||
*/
|
||||
public static List<Configuration> getConfigurations() {
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return Collections.unmodifiableList(JFC.getConfigurations());
|
||||
}
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/ContentType.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/ContentType.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Meta annotation, specifies that an annotation represents a content type, such
|
||||
* as a time span or a frequency.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Label("Content Type")
|
||||
@Description("Semantic meaning of a value")
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ContentType {
|
||||
}
|
||||
60
jdkSrc/jdk8/jdk/jfr/DataAmount.java
Normal file
60
jdkSrc/jdk8/jdk/jfr/DataAmount.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that a value represents an amount of data (for example, bytes).
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Data Amount")
|
||||
@Description("Amount of data")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface DataAmount {
|
||||
/**
|
||||
* Unit for bits
|
||||
*/
|
||||
public static final String BITS = "BITS";
|
||||
/**
|
||||
* Unit for bytes
|
||||
*/
|
||||
public static final String BYTES = "BYTES";
|
||||
|
||||
/**
|
||||
* Returns the unit for the data amount, by default bytes.
|
||||
*
|
||||
* @return the data amount unit, default {@code BYTES}, not {@code null}
|
||||
*/
|
||||
String value() default BYTES;
|
||||
}
|
||||
52
jdkSrc/jdk8/jdk/jfr/Description.java
Normal file
52
jdkSrc/jdk8/jdk/jfr/Description.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that describes an element by using a sentence or two.
|
||||
* <p>
|
||||
* Use sentence-style capitalization, capitalize the first letter of the first
|
||||
* word, and any proper names such as the word Java. If the description is one
|
||||
* sentence, a period should not be included.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Description {
|
||||
/**
|
||||
* Returns a sentence or two that describes the annotated element.
|
||||
*
|
||||
* @return a description, not {@code null}
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
58
jdkSrc/jdk8/jdk/jfr/Enabled.java
Normal file
58
jdkSrc/jdk8/jdk/jfr/Enabled.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
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.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@MetadataDefinition
|
||||
public @interface Enabled {
|
||||
/**
|
||||
* Setting name {@code "enabled"}, signifies that the event should be
|
||||
* recorded.
|
||||
*/
|
||||
public final static String NAME = "enabled";
|
||||
|
||||
/**
|
||||
* Returns {@code true} if by default the event should be enabled, {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if by default the event should be enabled by default, {@code false} otherwise
|
||||
*/
|
||||
boolean value() default true;
|
||||
}
|
||||
171
jdkSrc/jdk8/jdk/jfr/Event.java
Normal file
171
jdkSrc/jdk8/jdk/jfr/Event.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
/**
|
||||
* Base class for events, to be subclassed in order to define events and their
|
||||
* fields.
|
||||
* <p>
|
||||
* The following example shows how to implement an {@code Event} class.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* import jdk.jfr.Event;
|
||||
* import jdk.jfr.Description;
|
||||
* import jdk.jfr.Label;
|
||||
*
|
||||
* public class Example {
|
||||
*
|
||||
* @Label("Hello World")
|
||||
* @Description("Helps programmer getting started")
|
||||
* static class HelloWorld extends Event {
|
||||
* @Label("Message")
|
||||
* String message;
|
||||
* }
|
||||
*
|
||||
* public static void main(String... args) {
|
||||
* HelloWorld event = new HelloWorld();
|
||||
* event.message = "hello, world!";
|
||||
* event.commit();
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* After an event is allocated and its field members are populated, it can be
|
||||
* written to the Flight Recorder system by using the {@code #commit()} method.
|
||||
* <p>
|
||||
* By default, an event is enabled. To disable an event annotate the
|
||||
* {@link Event} class with {@code @Enabled(false)}.
|
||||
* <p>
|
||||
* Supported field types are the Java primitives: {@code boolean}, {@code char},
|
||||
* {@code byte}, {@code short}, {@code int}, {@code long}, {@code float}, and
|
||||
* {@code double}. Supported reference types are: {@code String}, {@code Thread}
|
||||
* and {@code Class}. Arrays, enums, and other reference types are silently
|
||||
* ignored and not included. Fields that are of the supported types can be
|
||||
* excluded by using the transient modifier. Static fields, even of the
|
||||
* supported types, are not included.
|
||||
* <p>
|
||||
* Tools can visualize data in a meaningful way when annotations are used (for
|
||||
* example, {@code Label}, {@code Description}, and {@code Timespan}).
|
||||
* Annotations applied to an {@link Event} class or its fields are included if
|
||||
* they are present (indirectly, directly, or associated), have the
|
||||
* {@code MetadataDefinition} annotation, and they do not contain enums, arrays,
|
||||
* or classes.
|
||||
* <p>
|
||||
* Gathering data to store in an event can be expensive. The
|
||||
* {@link Event#shouldCommit()} method can be used to verify whether an event
|
||||
* instance would actually be written to the system when the
|
||||
* {@code Event#commit()commit} method is invoked. If
|
||||
* {@link Event#shouldCommit()} returns false, then those operations can be
|
||||
* avoided.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Enabled(true)
|
||||
@StackTrace(true)
|
||||
@Registered(true)
|
||||
abstract public class Event {
|
||||
/**
|
||||
* Sole constructor, for invocation by subclass constructors, typically
|
||||
* implicit.
|
||||
*/
|
||||
protected Event() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timing of this event.
|
||||
*/
|
||||
final public void begin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the timing of this event.
|
||||
*
|
||||
* The {@code end} method must be invoked after the {@code begin} method.
|
||||
*/
|
||||
final public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the field values, time stamp, and event duration to the Flight
|
||||
* Recorder system.
|
||||
* <p>
|
||||
* If the event starts with an invocation of the {@code begin} method, but does
|
||||
* not end with an explicit invocation of the {@code end} method, then the event
|
||||
* ends when the {@code commit} method is invoked.
|
||||
*/
|
||||
final public void commit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if at least one recording is running, and the
|
||||
* enabled setting for this event is set to {@code true}, otherwise
|
||||
* {@code false} is returned.
|
||||
*
|
||||
* @return {@code true} if event is enabled, {@code false} otherwise
|
||||
*/
|
||||
final public boolean isEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the enabled setting for this event is set to
|
||||
* {@code true} and if the duration is within the threshold for the event,
|
||||
* {@code false} otherwise. The threshold is the minimum threshold for all
|
||||
* running recordings.
|
||||
*
|
||||
* @return {@code true} if the event can be written to the Flight Recorder
|
||||
* system, {@code false} otherwise
|
||||
*/
|
||||
final public boolean shouldCommit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a field value.
|
||||
* <p>
|
||||
* Applicable only if the event is dynamically defined using the
|
||||
* {@code EventFactory} class.
|
||||
* <p>
|
||||
* The supplied {@code index} corresponds to the index of the
|
||||
* {@link ValueDescriptor} object passed to the factory method of the
|
||||
* {@code EventFactory} class.
|
||||
*
|
||||
* @param index the index of the field that is passed to
|
||||
* {@code EventFactory#create(String, java.util.List, java.util.List)}
|
||||
* @param value value to set, can be {@code null}
|
||||
* @throws UnsupportedOperationException if it's not a dynamically generated
|
||||
* event
|
||||
* @throws IndexOutOfBoundsException if {@code index} is less than {@code 0} or
|
||||
* greater than or equal to the number of fields specified for the event
|
||||
*
|
||||
* @see EventType#getFields()
|
||||
* @see EventFactory
|
||||
*/
|
||||
final public void set(int index, Object value) {
|
||||
}
|
||||
}
|
||||
251
jdkSrc/jdk8/jdk/jfr/EventFactory.java
Normal file
251
jdkSrc/jdk8/jdk/jfr/EventFactory.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.jfr.internal.EventClassBuilder;
|
||||
import jdk.jfr.internal.JVMSupport;
|
||||
import jdk.jfr.internal.MetadataRepository;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Class for defining an event at runtime.
|
||||
* <p>
|
||||
* It's highly recommended that the event is defined at compile time, if the
|
||||
* field layout is known, so the Java Virtual Machine (JVM) can optimize the
|
||||
* code, possibly remove all instrumentation if Flight Recorder is inactive or
|
||||
* if the enabled setting for this event is set to {@code false}.
|
||||
* <p>
|
||||
* To define an event at compile time, see {@link Event}.
|
||||
* <p>
|
||||
* The following example shows how to implement a dynamic {@code Event} class.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* List<ValueDescriptor> fields = new ArrayList<>();
|
||||
* List<AnnotationElement> messageAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Message"));
|
||||
* fields.add(new ValueDescriptor(String.class, "message", messageAnnotations));
|
||||
* List<AnnotationElement> numberAnnotations = Collections.singletonList(new AnnotationElement(Label.class, "Number"));
|
||||
* fields.add(new ValueDescriptor(int.class, "number", numberAnnotations));
|
||||
*
|
||||
* String[] category = { "Example", "Getting Started" };
|
||||
* List<AnnotationElement> eventAnnotations = new ArrayList<>();
|
||||
* eventAnnotations.add(new AnnotationElement(Name.class, "com.example.HelloWorld"));
|
||||
* eventAnnotations.add(new AnnotationElement(Label.class, "Hello World"));
|
||||
* eventAnnotations.add(new AnnotationElement(Description.class, "Helps programmer getting started"));
|
||||
* eventAnnotations.add(new AnnotationElement(Category.class, category));
|
||||
*
|
||||
* EventFactory f = EventFactory.create(eventAnnotations, fields);
|
||||
*
|
||||
* Event event = f.newEvent();
|
||||
* event.set(0, "hello, world!");
|
||||
* event.set(1, 4711);
|
||||
* event.commit();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class EventFactory {
|
||||
|
||||
private static final long REGISTERED_ID = Type.getTypeId(Registered.class);
|
||||
|
||||
private final Class<? extends Event> eventClass;
|
||||
private final MethodHandle constructorHandle;
|
||||
private final List<AnnotationElement> sanitizedAnnotation;
|
||||
private final List<ValueDescriptor> sanitizedFields;
|
||||
|
||||
private EventFactory(Class<? extends Event> eventClass, List<AnnotationElement> sanitizedAnnotation, List<ValueDescriptor> sanitizedFields) throws IllegalAccessException, NoSuchMethodException, SecurityException {
|
||||
this.constructorHandle = MethodHandles.lookup().unreflectConstructor(eventClass.getConstructor());
|
||||
this.eventClass = eventClass;
|
||||
this.sanitizedAnnotation = sanitizedAnnotation;
|
||||
this.sanitizedFields = sanitizedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@code EventFactory} object.
|
||||
* <p>
|
||||
* The order of the value descriptors specifies the index to use when setting
|
||||
* event values.
|
||||
*
|
||||
* @param annotationElements list of annotation elements that describes the
|
||||
* annotations on the event, not {@code null}
|
||||
*
|
||||
* @param fields list of descriptors that describes the fields of the event, not
|
||||
* {@code null}
|
||||
*
|
||||
* @return event factory, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the input is not valid. For example,
|
||||
* input might not be valid if the field type or name is not valid in
|
||||
* the Java language or an annotation element references a type that
|
||||
* can't be found.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller does
|
||||
* not have {@code FlightRecorderPermission("registerEvent")}
|
||||
*
|
||||
* @see Event#set(int, Object)
|
||||
*/
|
||||
public static EventFactory create(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
|
||||
Objects.requireNonNull(fields);
|
||||
Objects.requireNonNull(annotationElements);
|
||||
JVMSupport.ensureWithInternalError();
|
||||
|
||||
Utils.checkRegisterPermission();
|
||||
|
||||
List<AnnotationElement> sanitizedAnnotation = Utils.sanitizeNullFreeList(annotationElements, AnnotationElement.class);
|
||||
List<ValueDescriptor> sanitizedFields = Utils.sanitizeNullFreeList(fields, ValueDescriptor.class);
|
||||
Set<String> nameSet = new HashSet<>();
|
||||
for (ValueDescriptor v : sanitizedFields) {
|
||||
String name = v.getName();
|
||||
if (v.isArray()) {
|
||||
throw new IllegalArgumentException("Array types are not allowed for fields");
|
||||
}
|
||||
if (!Type.isValidJavaFieldType(v.getTypeName())) {
|
||||
throw new IllegalArgumentException(v.getTypeName() + " is not a valid type for an event field");
|
||||
}
|
||||
if (!Type.isValidJavaIdentifier(v.getName())) {
|
||||
throw new IllegalArgumentException(name + " is not a valid name for an event field");
|
||||
}
|
||||
if (nameSet.contains(name)) {
|
||||
throw new IllegalArgumentException("Name of fields must be unique. Found two instances of " + name);
|
||||
}
|
||||
nameSet.add(name);
|
||||
}
|
||||
|
||||
// Prevent event from being registered in <clinit>
|
||||
// and only use annotations that can be resolved (those in boot class loader)
|
||||
boolean needRegister = true;
|
||||
List<AnnotationElement> bootAnnotations = new ArrayList<>();
|
||||
for (AnnotationElement ae : sanitizedAnnotation) {
|
||||
long id = ae.getTypeId();
|
||||
if (ae.isInBoot()) {
|
||||
if (id == REGISTERED_ID) {
|
||||
if (Boolean.FALSE.equals(ae.getValue("value"))) {
|
||||
needRegister = false;
|
||||
}
|
||||
} else {
|
||||
bootAnnotations.add(ae);
|
||||
}
|
||||
}
|
||||
}
|
||||
bootAnnotations.add(new AnnotationElement(Registered.class, false));
|
||||
|
||||
EventClassBuilder ecb = new EventClassBuilder(bootAnnotations, sanitizedFields);
|
||||
Class<? extends Event> eventClass = ecb.build();
|
||||
|
||||
if (needRegister) {
|
||||
MetadataRepository.getInstance().register(eventClass, sanitizedAnnotation, sanitizedFields);
|
||||
}
|
||||
try {
|
||||
return new EventFactory(eventClass, sanitizedAnnotation, sanitizedFields);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalAccessError("Could not accees constructor of generated event handler, " + e.getMessage());
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new InternalError("Could not find constructor in generated event handler, " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates an event, so it can be populated with data and written to the
|
||||
* Flight Recorder system.
|
||||
* <p>
|
||||
* Use the {@link Event#set(int, Object)} method to set a value.
|
||||
*
|
||||
* @return an event instance, not {@code null}
|
||||
*/
|
||||
public Event newEvent() {
|
||||
try {
|
||||
return (Event) constructorHandle.invoke();
|
||||
} catch (Throwable e) {
|
||||
throw new InstantiationError("Could not instantaite dynamically generated event class " + eventClass.getName() + ". " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type that is associated with this event factory.
|
||||
*
|
||||
* @return event type that is associated with this event factory, not
|
||||
* {@code null}
|
||||
*
|
||||
* @throws java.lang.IllegalStateException if the event factory is created with
|
||||
* the {@code Registered(false)} annotation and the event class is not
|
||||
* manually registered before the invocation of this method
|
||||
*/
|
||||
public EventType getEventType() {
|
||||
return EventType.getEventType(eventClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an unregistered event.
|
||||
* <p>
|
||||
* By default, the event class associated with this event factory is registered
|
||||
* when the event factory is created, unless the event has the
|
||||
* {@link Registered} annotation.
|
||||
* <p>
|
||||
* A registered event class can write data to Flight Recorder and event metadata
|
||||
* can be obtained by invoking {@link FlightRecorder#getEventTypes()}.
|
||||
* <p>
|
||||
* If the event class associated with this event factory is already registered,
|
||||
* the call to this method is ignored.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have {@code FlightRecorderPermission("registerEvent")}
|
||||
* @see Registered
|
||||
* @see FlightRecorder#register(Class)
|
||||
*/
|
||||
public void register() {
|
||||
MetadataRepository.getInstance().register(eventClass, sanitizedAnnotation, sanitizedFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the event that is associated with this event factory.
|
||||
* <p>
|
||||
* A unregistered event class can't write data to Flight Recorder and event
|
||||
* metadata can't be obtained by invoking
|
||||
* {@link FlightRecorder#getEventTypes()}.
|
||||
* <p>
|
||||
* If the event class associated with this event factory is not already
|
||||
* registered, the call to this method is ignored.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller does
|
||||
* not have {@code FlightRecorderPermission("registerEvent")}
|
||||
* @see Registered
|
||||
* @see FlightRecorder#unregister(Class)
|
||||
*/
|
||||
public void unregister() {
|
||||
MetadataRepository.getInstance().unregister(eventClass);
|
||||
}
|
||||
|
||||
}
|
||||
141
jdkSrc/jdk8/jdk/jfr/EventSettings.java
Normal file
141
jdkSrc/jdk8/jdk/jfr/EventSettings.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Convenience class for applying event settings to a recording.
|
||||
* <p>
|
||||
* An {@code EventSettings} object for a recording can be obtained by invoking
|
||||
* the {@link Recording#enable(String)} method which is configured using method
|
||||
* chaining.
|
||||
* <p>
|
||||
* The following example shows how to use the {@code EventSettings} class.
|
||||
* <pre>
|
||||
* {@code
|
||||
* 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"));
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
* @since 8
|
||||
*/
|
||||
public abstract class EventSettings {
|
||||
|
||||
// package private
|
||||
EventSettings() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables stack traces for the event that is associated with this event setting.
|
||||
* <p>
|
||||
* Equivalent to invoking the {@code with("stackTrace", "true")} method.
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
final public EventSettings withStackTrace() {
|
||||
return with(StackTrace.NAME, "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables stack traces for the event that is associated with this event setting.
|
||||
* <p>
|
||||
* Equivalent to invoking the {@code with("stackTrace", "false")} method.
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
final public EventSettings withoutStackTrace() {
|
||||
return with(StackTrace.NAME, "false");
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a threshold is not used.
|
||||
* <p>
|
||||
* This is a convenience method, equivalent to invoking the
|
||||
* {@code with("threshold", "0 s")} method.
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
final public EventSettings withoutThreshold() {
|
||||
return with(Threshold.NAME, "0 s");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval for the event that is associated with this event setting.
|
||||
*
|
||||
* @param duration the duration, not {@code null}
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
final public EventSettings withPeriod(Duration duration) {
|
||||
return with(Period.NAME, duration.toNanos() + " ns");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the threshold for the event that is associated with this event setting.
|
||||
*
|
||||
* @param duration the duration, or {@code null} if no duration is used
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
final public EventSettings withThreshold(Duration duration) {
|
||||
if (duration == null) {
|
||||
return with(Threshold.NAME, "0 ns");
|
||||
} else {
|
||||
return with(Threshold.NAME, duration.toNanos() + " ns");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a setting value for the event that is associated with this event setting.
|
||||
*
|
||||
* @param name the name of the setting (for example, {@code "threshold"})
|
||||
*
|
||||
* @param value the value to set (for example {@code "20 ms"} not
|
||||
* {@code null})
|
||||
*
|
||||
* @return event settings object for further configuration, not {@code null}
|
||||
*/
|
||||
abstract public EventSettings with(String name, String value);
|
||||
|
||||
/**
|
||||
* Creates a settings {@code Map} for the event that is associated with this
|
||||
* event setting.
|
||||
*
|
||||
* @return a settings {@code Map}, not {@code null}
|
||||
*/
|
||||
abstract Map<String, String> toMap();
|
||||
}
|
||||
237
jdkSrc/jdk8/jdk/jfr/EventType.java
Normal file
237
jdkSrc/jdk8/jdk/jfr/EventType.java
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.JVMSupport;
|
||||
import jdk.jfr.internal.MetadataRepository;
|
||||
import jdk.jfr.internal.PlatformEventType;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Describes an event, its fields, settings and annotations.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class EventType {
|
||||
private final PlatformEventType platformEventType;
|
||||
private final List<String> UNCATEGORIZED = Collections.singletonList("Uncategorized");
|
||||
private Map<String, ValueDescriptor> cache; // create lazy to avoid memory overhead
|
||||
// helper constructor
|
||||
EventType(PlatformEventType platformEventType) {
|
||||
this.platformEventType = platformEventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of descriptors that describe the event fields of
|
||||
* this event type.
|
||||
*
|
||||
* @return the list of field descriptors, not {@code null}
|
||||
*/
|
||||
public List<ValueDescriptor> getFields() {
|
||||
return platformEventType.getFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the field with the specified name, or {@code null} if it doesn't
|
||||
* exist.
|
||||
*
|
||||
* @return a value descriptor that describes the field, or <code>null</code> if
|
||||
* the field with the specified name doesn't exist
|
||||
*
|
||||
* @return a value descriptor, or <code>null</code> if it doesn't exist
|
||||
*/
|
||||
public ValueDescriptor getField(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
if (cache == null) {
|
||||
List<ValueDescriptor> fields = getFields();
|
||||
Map<String, ValueDescriptor> newCache = new LinkedHashMap<String, ValueDescriptor>(fields.size());
|
||||
for (ValueDescriptor v :fields) {
|
||||
newCache.put(v.getName(), v);
|
||||
}
|
||||
cache = newCache;
|
||||
}
|
||||
return cache.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an identifier for the event (for example,
|
||||
* {@code "jdk.CPULoad"}).
|
||||
* <p>
|
||||
* The identifier is the fully qualified name of the event class, if not set using
|
||||
* the {@link Name} annotation.
|
||||
*
|
||||
* @return the name, not {@code null}
|
||||
*
|
||||
* @see Name
|
||||
*/
|
||||
public String getName() {
|
||||
return platformEventType.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name (for example, {@code "CPU Load"}).
|
||||
* <p>
|
||||
* The label of an event class can be set with {@link Label}.
|
||||
*
|
||||
* @return the label, or {@code null} if a label is not set
|
||||
*
|
||||
* @see Label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return platformEventType.getLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for this event type in the Java Virtual Machine (JVM).
|
||||
*
|
||||
* @return the ID that is used in the JVM
|
||||
*/
|
||||
public long getId() {
|
||||
return platformEventType.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of annotation elements for this event type.
|
||||
*
|
||||
* @return an immutable list of annotations or an empty list if no
|
||||
* annotations exists, not {@code null}
|
||||
*/
|
||||
public List<AnnotationElement> getAnnotationElements() {
|
||||
return platformEventType.getAnnotationElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the event is enabled and at least one recording is
|
||||
* running, {@code false} otherwise.
|
||||
* <p>
|
||||
* By default, the event is enabled. The event can be enabled or disabled by
|
||||
* setting the enabled setting to {@code true} or {@code false}, programmatically or by using a
|
||||
* configuration file. The event can also be disabled by annotating event with
|
||||
* the {@code @Enabled(false)} annotation.
|
||||
*
|
||||
* @return true if event is enabled, false otherwise
|
||||
*
|
||||
* @see Enabled
|
||||
* @see Recording#enable(Class)
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return platformEventType.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a short sentence that describes the event class.
|
||||
* <p>
|
||||
* The description of an event class can be set with {@link Description}.
|
||||
*
|
||||
* @return the description, or {@code null} if no description exists
|
||||
*
|
||||
* @see Description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return platformEventType.getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first annotation for the specified type if an annotation
|
||||
* element with the same name is directly present, otherwise {@code null}.
|
||||
*
|
||||
* @param <A> the type of the annotation to query for and return if present
|
||||
* @param annotationClass the {@code Class} object that corresponds to the
|
||||
* annotation type, not {@code null}
|
||||
* @return this element's annotation for the specified annotation type if
|
||||
* directly present, else {@code null}
|
||||
*/
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
return platformEventType.getAnnotation(annotationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type for an event class, or {@code null} if it doesn't
|
||||
* exist.
|
||||
*
|
||||
* @param eventClass the event class, not {@code null}
|
||||
* @return the event class, or null if class doesn't exist
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code eventClass} is an abstract class
|
||||
*
|
||||
* @throws IllegalStateException if the class is annotated with
|
||||
* {@code Registered(false)}, but not manually registered
|
||||
*/
|
||||
public static EventType getEventType(Class<? extends Event> eventClass) {
|
||||
Objects.requireNonNull(eventClass);
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
JVMSupport.ensureWithInternalError();
|
||||
return MetadataRepository.getInstance().getEventType(eventClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of the setting descriptors that describe the available
|
||||
* event settings for this event type.
|
||||
*
|
||||
* @return the list of setting descriptors for this event type, not
|
||||
* {@code null}
|
||||
*/
|
||||
public List<SettingDescriptor> getSettingDescriptors() {
|
||||
return Collections.unmodifiableList(platformEventType.getSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of human-readable names that makes up the categories for
|
||||
* this event type (for example, {@code "Java Application"}, {@code "Statistics"}).
|
||||
*
|
||||
* @return an immutable list of category names, or a list with the name
|
||||
* {@code "Uncategorized"} if no category is set
|
||||
*
|
||||
* @see Category
|
||||
*/
|
||||
public List<String> getCategoryNames() {
|
||||
Category c = platformEventType.getAnnotation(Category.class);
|
||||
if (c == null) {
|
||||
return UNCATEGORIZED;
|
||||
}
|
||||
return Collections.unmodifiableList(Arrays.asList(c.value()));
|
||||
}
|
||||
|
||||
// package private
|
||||
Type getType() {
|
||||
return platformEventType;
|
||||
}
|
||||
|
||||
// package private
|
||||
PlatformEventType getPlatformEventType() {
|
||||
return platformEventType;
|
||||
}
|
||||
}
|
||||
59
jdkSrc/jdk8/jdk/jfr/Experimental.java
Normal file
59
jdkSrc/jdk8/jdk/jfr/Experimental.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that specifies that an element is experimental and may change
|
||||
* without notice.
|
||||
* <p>
|
||||
* Clients that visualize Flight Recorder events should <em>not</em> show the
|
||||
* events or fields annotated with the {@code Experimental} annotation by
|
||||
* default. This annotation allows event producers the freedom to try out new
|
||||
* events without committing to them.
|
||||
* <p>
|
||||
* Clients may provide a check box (for example, in a preference page) where a
|
||||
* user can opt-in to display experimental data. If the user decide to do so,
|
||||
* the user interface should mark experimental events or fields so users can
|
||||
* distinguish them from non-experimental events.
|
||||
* <p>
|
||||
* This annotation is inherited.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Label("Experimental")
|
||||
@Description("Element is not to be shown to a user by default")
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
public @interface Experimental {
|
||||
}
|
||||
353
jdkSrc/jdk8/jdk/jfr/FlightRecorder.java
Normal file
353
jdkSrc/jdk8/jdk/jfr/FlightRecorder.java
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import static jdk.jfr.internal.LogLevel.DEBUG;
|
||||
import static jdk.jfr.internal.LogLevel.INFO;
|
||||
import static jdk.jfr.internal.LogTag.JFR;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.JVM;
|
||||
import jdk.jfr.internal.JVMSupport;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.MetadataRepository;
|
||||
import jdk.jfr.internal.Options;
|
||||
import jdk.jfr.internal.PlatformRecorder;
|
||||
import jdk.jfr.internal.PlatformRecording;
|
||||
import jdk.jfr.internal.Repository;
|
||||
import jdk.jfr.internal.RequestEngine;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Class for accessing, controlling, and managing Flight Recorder.
|
||||
* <p>
|
||||
* This class provides the methods necessary for creating, starting, stopping,
|
||||
* and destroying recordings.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class FlightRecorder {
|
||||
private static volatile FlightRecorder platformRecorder;
|
||||
private static volatile boolean initialized;
|
||||
private final PlatformRecorder internal;
|
||||
|
||||
private FlightRecorder(PlatformRecorder internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of the available recordings.
|
||||
* <p>
|
||||
* A recording becomes available when it is created. It becomes unavailable when it
|
||||
* is in the {@code CLOSED} state, typically after a call to
|
||||
* {@link Recording#close()}.
|
||||
*
|
||||
* @return a list of recordings, not {@code null}
|
||||
*/
|
||||
public List<Recording> getRecordings() {
|
||||
List<Recording> recs = new ArrayList<>();
|
||||
for (PlatformRecording r : internal.getRecordings()) {
|
||||
recs.add(r.getRecording());
|
||||
}
|
||||
return Collections.unmodifiableList(recs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a snapshot of all available recorded data.
|
||||
* <p>
|
||||
* A snapshot is a synthesized recording in a {@code STOPPPED} state. If no data is
|
||||
* available, a recording with size {@code 0} is returned.
|
||||
* <p>
|
||||
* A snapshot provides stable access to data for later operations (for example,
|
||||
* operations to change the interval or to reduce the data size).
|
||||
* <p>
|
||||
* The following example shows how to create a snapshot and write a subset of the data to a file.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* try (Recording snapshot = FlightRecorder.getFlightRecorder().takeSnapshot()) {
|
||||
* if (snapshot.getSize() > 0) {
|
||||
* snapshot.setMaxSize(100_000_000);
|
||||
* snapshot.setMaxAge(Duration.ofMinutes(5));
|
||||
* snapshot.dump(Paths.get("snapshot.jfr"));
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The caller must close the recording when access to the data is no longer
|
||||
* needed.
|
||||
*
|
||||
* @return a snapshot of all available recording data, not {@code null}
|
||||
*/
|
||||
public Recording takeSnapshot() {
|
||||
Recording snapshot = new Recording();
|
||||
snapshot.setName("Snapshot");
|
||||
internal.fillWithRecordedData(snapshot.getInternal(), null);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an event class.
|
||||
* <p>
|
||||
* If the event class is already registered, then the invocation of this method is
|
||||
* ignored.
|
||||
*
|
||||
* @param eventClass the event class to register, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if class is abstract or not a subclass
|
||||
* of {@link Event}
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have {@code FlightRecorderPermission("registerEvent")}
|
||||
*/
|
||||
public static void register(Class<? extends Event> eventClass) {
|
||||
Objects.requireNonNull(eventClass);
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return;
|
||||
}
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
MetadataRepository.getInstance().register(eventClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters an event class.
|
||||
* <p>
|
||||
* If the event class is not registered, then the invocation of this method is
|
||||
* ignored.
|
||||
*
|
||||
* @param eventClass the event class to unregistered, not {@code null}
|
||||
* @throws IllegalArgumentException if a class is abstract or not a subclass
|
||||
* of {@link Event}
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have {@code FlightRecorderPermission("registerEvent")}
|
||||
*/
|
||||
public static void unregister(Class<? extends Event> eventClass) {
|
||||
Objects.requireNonNull(eventClass);
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return;
|
||||
}
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
MetadataRepository.getInstance().unregister(eventClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Flight Recorder for the platform.
|
||||
*
|
||||
* @return a Flight Recorder instance, not {@code null}
|
||||
*
|
||||
* @throws IllegalStateException if Flight Recorder can't be created (for
|
||||
* example, if the Java Virtual Machine (JVM) lacks Flight Recorder
|
||||
* support, or if the file repository can't be created or accessed)
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller does
|
||||
* not have {@code FlightRecorderPermission("accessFlightRecorder")}
|
||||
*/
|
||||
public static FlightRecorder getFlightRecorder() throws IllegalStateException, SecurityException {
|
||||
synchronized (PlatformRecorder.class) {
|
||||
Utils.checkAccessFlightRecorder();
|
||||
JVMSupport.ensureWithIllegalStateException();
|
||||
if (platformRecorder == null) {
|
||||
try {
|
||||
platformRecorder = new FlightRecorder(new PlatformRecorder());
|
||||
} catch (IllegalStateException ise) {
|
||||
throw ise;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Can't create Flight Recorder. " + e.getMessage(), e);
|
||||
}
|
||||
// Must be in synchronized block to prevent instance leaking out
|
||||
// before initialization is done
|
||||
initialized = true;
|
||||
Logger.log(JFR, INFO, "Flight Recorder initialized");
|
||||
Logger.log(JFR, DEBUG, "maxchunksize: " + Options.getMaxChunkSize()+ " bytes");
|
||||
Logger.log(JFR, DEBUG, "memorysize: " + Options.getMemorySize()+ " bytes");
|
||||
Logger.log(JFR, DEBUG, "globalbuffersize: " + Options.getGlobalBufferSize()+ " bytes");
|
||||
Logger.log(JFR, DEBUG, "globalbuffercount: " + Options.getGlobalBufferCount());
|
||||
Logger.log(JFR, DEBUG, "dumppath: " + Options.getDumpPath());
|
||||
Logger.log(JFR, DEBUG, "samplethreads: " + Options.getSampleThreads());
|
||||
Logger.log(JFR, DEBUG, "stackdepth: " + Options.getStackDepth());
|
||||
Logger.log(JFR, DEBUG, "threadbuffersize: " + Options.getThreadBufferSize());
|
||||
Logger.log(JFR, LogLevel.INFO, "Created repository " + Repository.getRepository().getRepositoryPath().toString());
|
||||
PlatformRecorder.notifyRecorderInitialized(platformRecorder);
|
||||
}
|
||||
}
|
||||
return platformRecorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a hook for a periodic event.
|
||||
* <p>
|
||||
* The implementation of the hook should return as soon as possible, to
|
||||
* avoid blocking other Flight Recorder operations. The hook should emit
|
||||
* one or more events of the specified type. When a hook is added, the
|
||||
* interval at which the call is invoked is configurable using the
|
||||
* {@code "period"} setting.
|
||||
*
|
||||
* @param eventClass the class that the hook should run for, not {@code null}
|
||||
* @param hook the hook, not {@code null}
|
||||
* @throws IllegalArgumentException if a class is not a subclass of
|
||||
* {@link Event}, is abstract, or the hook is already added
|
||||
* @throws IllegalStateException if the event class has the
|
||||
* {@code Registered(false)} annotation and is not registered manually
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have {@code FlightRecorderPermission("registerEvent")}
|
||||
*/
|
||||
public static void addPeriodicEvent(Class<? extends Event> eventClass, Runnable hook) throws SecurityException {
|
||||
Objects.requireNonNull(eventClass);
|
||||
Objects.requireNonNull(hook);
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
Utils.checkRegisterPermission();
|
||||
AccessControlContext acc = AccessController.getContext();
|
||||
RequestEngine.addHook(acc, EventType.getEventType(eventClass).getPlatformEventType(), hook);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a hook for a periodic event.
|
||||
*
|
||||
* @param hook the hook to remove, not {@code null}
|
||||
* @return {@code true} if hook is removed, {@code false} otherwise
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have {@code FlightRecorderPermission("registerEvent")}
|
||||
*/
|
||||
public static boolean removePeriodicEvent(Runnable hook) throws SecurityException {
|
||||
Objects.requireNonNull(hook);
|
||||
Utils.checkRegisterPermission();
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return false;
|
||||
}
|
||||
return RequestEngine.removeHook(hook);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list that contains all currently registered events.
|
||||
* <p>
|
||||
* By default, events are registered when they are first used, typically
|
||||
* when an event object is allocated. To ensure an event is visible early,
|
||||
* registration can be triggered by invoking the
|
||||
* {@link FlightRecorder#register(Class)} method.
|
||||
*
|
||||
* @return list of events, not {@code null}
|
||||
*/
|
||||
public List<EventType> getEventTypes() {
|
||||
return Collections.unmodifiableList(MetadataRepository.getInstance().getRegisteredEventTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a recorder listener and captures the {@code AccessControlContext} to
|
||||
* use when invoking the listener.
|
||||
* <p>
|
||||
* If Flight Recorder is already initialized when the listener is added, then the method
|
||||
* {@link FlightRecorderListener#recorderInitialized(FlightRecorder)} method is
|
||||
* invoked before returning from this method.
|
||||
*
|
||||
* @param changeListener the listener to add, not {@code null}
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have
|
||||
* {@code FlightRecorderPermission("accessFlightRecorder")}
|
||||
*/
|
||||
public static void addListener(FlightRecorderListener changeListener) {
|
||||
Objects.requireNonNull(changeListener);
|
||||
Utils.checkAccessFlightRecorder();
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return;
|
||||
}
|
||||
PlatformRecorder.addListener(changeListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a recorder listener.
|
||||
* <p>
|
||||
* If the same listener is added multiple times, only one instance is
|
||||
* removed.
|
||||
*
|
||||
* @param changeListener listener to remove, not {@code null}
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* does not have
|
||||
* {@code FlightRecorderPermission("accessFlightRecorder")}
|
||||
*
|
||||
* @return {@code true}, if the listener could be removed, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
public static boolean removeListener(FlightRecorderListener changeListener) {
|
||||
Objects.requireNonNull(changeListener);
|
||||
Utils.checkAccessFlightRecorder();
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return PlatformRecorder.removeListener(changeListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the Java Virtual Machine (JVM) has Flight Recorder capabilities.
|
||||
* <p>
|
||||
* This method can quickly check whether Flight Recorder can be
|
||||
* initialized, without actually doing the initialization work. The value may
|
||||
* change during runtime and it is not safe to cache it.
|
||||
*
|
||||
* @return {@code true}, if Flight Recorder is available, {@code false}
|
||||
* otherwise
|
||||
*
|
||||
* @see FlightRecorderListener for callback when Flight Recorder is
|
||||
* initialized
|
||||
*/
|
||||
public static boolean isAvailable() {
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return false;
|
||||
}
|
||||
return JVM.getJVM().isAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if Flight Recorder is initialized.
|
||||
*
|
||||
* @return {@code true}, if Flight Recorder is initialized,
|
||||
* {@code false} otherwise
|
||||
*
|
||||
* @see FlightRecorderListener for callback when Flight Recorder is
|
||||
* initialized
|
||||
*/
|
||||
public static boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
PlatformRecorder getInternal() {
|
||||
return internal;
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/jdk/jfr/FlightRecorderListener.java
Normal file
80
jdkSrc/jdk8/jdk/jfr/FlightRecorderListener.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
|
||||
/**
|
||||
* Callback interface to monitor Flight Recorder's life cycle.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public interface FlightRecorderListener {
|
||||
|
||||
/**
|
||||
* Receives notification when Flight Recorder is initialized.
|
||||
* <p>
|
||||
* This method is also be invoked when a listener is added to an already
|
||||
* initialized Flight Recorder.
|
||||
* <p>
|
||||
* This method allows clients to implement their own initialization mechanism
|
||||
* that is executed before a {@code FlightRecorder} instance is returned by
|
||||
* {@code FlightRecorder#getFlightRecorder()}.
|
||||
*
|
||||
* @implNote This method should return as soon as possible, to avoid blocking
|
||||
* initialization of Flight Recorder. To avoid deadlocks or unexpected
|
||||
* behavior, this method should not call
|
||||
* {@link FlightRecorder#getFlightRecorder()} or start new recordings.
|
||||
*
|
||||
* @implSpec The default implementation of this method is empty.
|
||||
*
|
||||
* @param recorder Flight Recorder instance, not {@code null}
|
||||
*
|
||||
* @see FlightRecorder#addListener(FlightRecorderListener)
|
||||
*/
|
||||
default void recorderInitialized(FlightRecorder recorder) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives notification when the state of a recording changes.
|
||||
* <p>
|
||||
* Callback is invoked when a recording reaches the {@code RUNNING},
|
||||
* {@code STOPPED} and {@code CLOSED} state.
|
||||
*
|
||||
* @implNote The implementation of this method should return as soon as possible
|
||||
* to avoid blocking normal operation of Flight Recorder.
|
||||
*
|
||||
* @implSpec The default implementation of this method is empty.
|
||||
*
|
||||
* @param recording the recording where the state change occurred, not
|
||||
* {@code null}
|
||||
*
|
||||
* @see FlightRecorder#addListener(FlightRecorderListener)
|
||||
* @see RecordingState
|
||||
*
|
||||
*/
|
||||
default void recordingStateChanged(Recording recording) {
|
||||
}
|
||||
}
|
||||
211
jdkSrc/jdk8/jdk/jfr/FlightRecorderPermission.java
Normal file
211
jdkSrc/jdk8/jdk/jfr/FlightRecorderPermission.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.PlatformEventType;
|
||||
import jdk.jfr.internal.PlatformRecorder;
|
||||
import jdk.jfr.internal.PlatformRecording;
|
||||
import jdk.jfr.internal.PrivateAccess;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Permission for controlling access to Flight Recorder.
|
||||
* <p>
|
||||
* The following table provides a summary of what the permission
|
||||
* allows, and the risks of granting code the permission.
|
||||
*
|
||||
* <table class="striped">
|
||||
* <caption style="display:none">Table shows permission target name,
|
||||
* what the permission allows, and associated risks</caption>
|
||||
* <thead>
|
||||
* <tr>
|
||||
* <th scope="col">Permission Target Name</th>
|
||||
* <th scope="col">What the Permission Allows</th>
|
||||
* <th scope="col">Risks of Allowing this Permission</th>
|
||||
* </tr>
|
||||
* </thead>
|
||||
*
|
||||
* <tbody>
|
||||
* <tr>
|
||||
* <th scope="row">{@code accessFlightRecorder}</th>
|
||||
* <td>Ability to create a Flight Recorder instance, register callbacks to
|
||||
* monitor the Flight Recorder life cycle, and control an existing instance
|
||||
* of Flight Recorder, which can record and dump runtime information, such as
|
||||
* stack traces, class names, and data in user defined events.</td>
|
||||
* <td>A malicious user may be able to extract sensitive information that is stored in
|
||||
* events and interrupt Flight Recorder by installing listeners or hooks that
|
||||
* never finish.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <th scope="row">{@code registerEvent}</th>
|
||||
* <td>Ability to register events, write data to the Flight Recorder buffers,
|
||||
* and execute code in a callback function for periodic events.
|
||||
*
|
||||
* <td>A malicious user may be able to write sensitive information to Flight
|
||||
* Recorder buffers.</td>
|
||||
* </tr>
|
||||
* </tbody>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* Typically, programmers do not create {@code FlightRecorderPermission} objects
|
||||
* directly. Instead the objects are created by the security policy code that is based on
|
||||
* reading the security policy file.
|
||||
*
|
||||
* @since 8
|
||||
*
|
||||
* @see java.security.BasicPermission
|
||||
* @see java.security.Permission
|
||||
* @see java.security.Permissions
|
||||
* @see java.security.PermissionCollection
|
||||
* @see java.lang.SecurityManager
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public final class FlightRecorderPermission extends java.security.BasicPermission {
|
||||
|
||||
// Purpose of InternalAccess is to give classes in jdk.jfr.internal
|
||||
// access to package private methods in this package (jdk.jfr).
|
||||
//
|
||||
// The initialization could be done in any class in this package,
|
||||
// but this one was chosen because it is light weight and
|
||||
// lacks dependencies on other public classes.
|
||||
static {
|
||||
PrivateAccess.setPrivateAccess(new InternalAccess());
|
||||
}
|
||||
|
||||
private final static class InternalAccess extends PrivateAccess {
|
||||
|
||||
@Override
|
||||
public Type getType(Object o) {
|
||||
if (o instanceof AnnotationElement) {
|
||||
return ((AnnotationElement) o).getType();
|
||||
}
|
||||
if (o instanceof EventType) {
|
||||
return ((EventType) o).getType();
|
||||
}
|
||||
if (o instanceof ValueDescriptor) {
|
||||
return ((ValueDescriptor) o).getType();
|
||||
}
|
||||
if (o instanceof SettingDescriptor) {
|
||||
return ((SettingDescriptor) o).getType();
|
||||
}
|
||||
throw new Error("Unknown type " + o.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration newConfiguration(String name, String label, String description, String provider, Map<String, String> settings, String contents) {
|
||||
return new Configuration(name, label, description, provider, settings, contents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType newEventType(PlatformEventType platformEventType) {
|
||||
return new EventType(platformEventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationElement newAnnotation(Type annotationType, List<Object> values, boolean boot) {
|
||||
return new AnnotationElement(annotationType, values, boot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueDescriptor newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annos, int dimension, boolean constantPool, String fieldName) {
|
||||
return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformRecording getPlatformRecording(Recording r) {
|
||||
return r.getInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformEventType getPlatformEventType(EventType eventType) {
|
||||
return eventType.getPlatformEventType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstantPool(ValueDescriptor v) {
|
||||
return v.isConstantPool();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnnotations(ValueDescriptor v, List<AnnotationElement> a) {
|
||||
v.setAnnotations(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAnnotations(SettingDescriptor s, List<AnnotationElement> a) {
|
||||
s.setAnnotations(a);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldName(ValueDescriptor v) {
|
||||
return v.getJavaFieldName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueDescriptor newValueDescriptor(Class<?> type, String name) {
|
||||
return new ValueDescriptor(type, name, Collections.emptyList(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingDescriptor newSettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
|
||||
return new SettingDescriptor(type, name, defaultValue, annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnsigned(ValueDescriptor v) {
|
||||
return v.isUnsigned();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformRecorder getPlatformRecorder() {
|
||||
return FlightRecorder.getFlightRecorder().getInternal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code FlightRecorderPermission} with the specified name.
|
||||
*
|
||||
* @param name the permission name, must be either
|
||||
* {@code "accessFlightRecorder"} or {@code "registerEvent"}, not
|
||||
* {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code name} is empty or not valid
|
||||
*/
|
||||
public FlightRecorderPermission(String name) {
|
||||
super(Objects.requireNonNull(name));
|
||||
if (!name.equals(Utils.ACCESS_FLIGHT_RECORDER) && !name.equals(Utils.REGISTER_EVENT)) {
|
||||
throw new IllegalArgumentException("name: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/Frequency.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/Frequency.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the value is a frequency, measured in Hz.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Frequency")
|
||||
@Description("Measure of how often something occurs, in Hertz")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
public @interface Frequency {
|
||||
}
|
||||
55
jdkSrc/jdk8/jdk/jfr/Label.java
Normal file
55
jdkSrc/jdk8/jdk/jfr/Label.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that sets a human-readable name for an element (for example,
|
||||
* {@code "Maximum Throughput"}).
|
||||
* <p>
|
||||
* Use headline-style capitalization, capitalize the first and last words, and
|
||||
* all nouns, pronouns, adjectives, verbs and adverbs. Do not include ending
|
||||
* punctuation.
|
||||
* <p>
|
||||
* The label should not be used as an identifier, see {@link Name}.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Label {
|
||||
/**
|
||||
* Returns a human-readable name for the annotated element.
|
||||
*
|
||||
* @return a human-readable name, not {@code null}
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/MemoryAddress.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/MemoryAddress.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the value is a memory address.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Memory Address")
|
||||
@Description("Represents a physical memory address")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD })
|
||||
public @interface MemoryAddress {
|
||||
}
|
||||
81
jdkSrc/jdk8/jdk/jfr/MetadataDefinition.java
Normal file
81
jdkSrc/jdk8/jdk/jfr/MetadataDefinition.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Meta annotation for defining new types of event metadata.
|
||||
* <p>
|
||||
* In the following example, a transaction event is defined with two
|
||||
* user-defined annotations, {@code @Severity} and {@code @TransactionId}.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
*{@literal @}MetadataDefinition
|
||||
*{@literal @}Label("Severity")
|
||||
*{@literal @}Description("Value between 0 and 100 that indicates severity. 100 is most severe.")
|
||||
*{@literal @}Retention(RetentionPolicy.RUNTIME)
|
||||
*{@literal @}Target({ ElementType.TYPE })
|
||||
* public {@literal @}interface {@literal @}Severity {
|
||||
* int value() default 50;
|
||||
* }
|
||||
*
|
||||
*{@literal @}MetadataDefinition
|
||||
*{@literal @}Label("Transaction Id")
|
||||
*{@literal @}Relational
|
||||
*{@literal @}Retention(RetentionPolicy.RUNTIME)
|
||||
*{@literal @}Target({ ElementType.FIELD })
|
||||
* public {@literal @}interface {@literal @}Severity {
|
||||
* }
|
||||
*
|
||||
*{@literal @}Severity(80)
|
||||
*{@literal @}Label("Transaction Blocked");
|
||||
* class TransactionBlocked extends Event {
|
||||
* {@literal @}TransactionId
|
||||
* {@literal @}Label("Transaction");
|
||||
* long transactionId;
|
||||
*
|
||||
* {@literal @}TransactionId
|
||||
* {@literal @}Label("Transaction Blocker");
|
||||
* long transactionId;
|
||||
* }
|
||||
*
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Adding {@code @MetadataDefinition} to the declaration of {@code @Severity} and {@code @TransactionId}
|
||||
* ensures the information is saved by Flight Recorder.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.TYPE })
|
||||
public @interface MetadataDefinition {
|
||||
}
|
||||
53
jdkSrc/jdk8/jdk/jfr/Name.java
Normal file
53
jdkSrc/jdk8/jdk/jfr/Name.java
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that overrides the default name for an element (for example, when
|
||||
* the default package for an event is not appropriate).
|
||||
* <p>
|
||||
* The name must be a valid identifiers in the Java language (for example,
|
||||
* {@code "com.example.MyEvent"} for an event class or {@code "message"} for an
|
||||
* event field).
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@MetadataDefinition
|
||||
public @interface Name {
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
50
jdkSrc/jdk8/jdk/jfr/Percentage.java
Normal file
50
jdkSrc/jdk8/jdk/jfr/Percentage.java
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation to use on fractions, typically between {@code 0.0}
|
||||
* and {@code 1.0}, to specify that the value is a percentage.
|
||||
* <p>
|
||||
* For example, a field with the value {@code 0.5} annotated by this annotation,
|
||||
* should be interpreted as {@code 50%} and rendered in a graphical user
|
||||
* interface with a percentage sign to avoid confusion with {@code 0.005%}.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Percentage")
|
||||
@Description("Percentage, represented as a number between 0 and 1")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface Percentage {
|
||||
}
|
||||
72
jdkSrc/jdk8/jdk/jfr/Period.java
Normal file
72
jdkSrc/jdk8/jdk/jfr/Period.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event annotation, specifies the default setting value for a periodic event.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Period {
|
||||
/**
|
||||
* Settings name {@code "period"} for configuring periodic events
|
||||
*/
|
||||
public final static String NAME = "period";
|
||||
|
||||
/**
|
||||
* Returns the default setting value for a periodic setting.
|
||||
* <p>
|
||||
* String representation of a positive {@code Long} value followed by an empty
|
||||
* space and one of the following units:<br>
|
||||
* <br>
|
||||
* {@code "ns"} (nanoseconds)<br>
|
||||
* {@code "us"} (microseconds)<br>
|
||||
* {@code "ms"} (milliseconds)<br>
|
||||
* {@code "s"} (seconds)<br>
|
||||
* {@code "m"} (minutes)<br>
|
||||
* {@code "h"} (hours)<br>
|
||||
* {@code "d"} (days)<br>
|
||||
* <p>
|
||||
* Example values: {@code "0 ns"}, {@code "10 ms"}, and {@code "1 s"}.
|
||||
* <p>
|
||||
* A period may also be <code>"everyChunk"</code> to specify that it occurs at
|
||||
* least once for every recording file. The number of events that are emitted
|
||||
* depends on how many times the file rotations occur when data is recorded.
|
||||
*
|
||||
* @return the default setting value, not {@code null}
|
||||
*/
|
||||
String value() default "everyChunk";
|
||||
}
|
||||
676
jdkSrc/jdk8/jdk/jfr/Recording.java
Normal file
676
jdkSrc/jdk8/jdk/jfr/Recording.java
Normal file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.PlatformRecorder;
|
||||
import jdk.jfr.internal.PlatformRecording;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.Utils;
|
||||
import jdk.jfr.internal.WriteableUserPath;
|
||||
|
||||
/**
|
||||
* Provides means to configure, start, stop and dump recording data to disk.
|
||||
* <p>
|
||||
* The following example shows how configure, start, stop and dump recording data to disk.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* 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"));
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class Recording implements Closeable {
|
||||
|
||||
private static class RecordingSettings extends EventSettings {
|
||||
|
||||
private final Recording recording;
|
||||
private final String identifier;
|
||||
|
||||
RecordingSettings(Recording r, String identifier) {
|
||||
this.recording = r;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
RecordingSettings(Recording r, Class<? extends Event> eventClass) {
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
this.recording = r;
|
||||
this.identifier = String.valueOf(Type.getTypeId(eventClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventSettings with(String name, String value) {
|
||||
Objects.requireNonNull(value);
|
||||
recording.setSetting(identifier + "#" + name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> toMap() {
|
||||
return recording.getSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private final PlatformRecording internal;
|
||||
|
||||
public Recording(Map<String, String> settings) {
|
||||
PlatformRecorder r = FlightRecorder.getFlightRecorder().getInternal();
|
||||
synchronized (r) {
|
||||
this.internal = r.newRecording(settings);
|
||||
this.internal.setRecording(this);
|
||||
if (internal.getRecording() != this) {
|
||||
throw new InternalError("Internal recording not properly setup");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a recording without any settings.
|
||||
* <p>
|
||||
* A newly created recording is in the {@link RecordingState#NEW} state. To start
|
||||
* the recording, invoke the {@link Recording#start()} method.
|
||||
*
|
||||
* @throws IllegalStateException if Flight Recorder can't be created (for
|
||||
* example, if the Java Virtual Machine (JVM) lacks Flight Recorder
|
||||
* support, or if the file repository can't be created or accessed)
|
||||
*
|
||||
* @throws SecurityException If a security manager is used and
|
||||
* FlightRecorderPermission "accessFlightRecorder" is not set.
|
||||
*/
|
||||
public Recording() {
|
||||
this(new HashMap<String, String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a recording with settings from a configuration.
|
||||
* <p>
|
||||
* The following example shows how create a recording that uses a predefined configuration.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* Recording r = new Recording(Configuration.getConfiguration("default"));
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The newly created recording is in the {@link RecordingState#NEW} state. To
|
||||
* start the recording, invoke the {@link Recording#start()} method.
|
||||
*
|
||||
* @param configuration configuration that contains the settings to be use, not
|
||||
* {@code null}
|
||||
*
|
||||
* @throws IllegalStateException if Flight Recorder can't be created (for
|
||||
* example, if the Java Virtual Machine (JVM) lacks Flight Recorder
|
||||
* support, or if the file repository can't be created or accessed)
|
||||
*
|
||||
* @throws SecurityException if a security manager is used and
|
||||
* FlightRecorderPermission "accessFlightRecorder" is not set.
|
||||
*
|
||||
* @see Configuration
|
||||
*/
|
||||
public Recording(Configuration configuration) {
|
||||
this(configuration.getSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this recording.
|
||||
* <p>
|
||||
* It's recommended that the recording options and event settings are configured
|
||||
* before calling this method. The benefits of doing so are a more consistent
|
||||
* state when analyzing the recorded data, and improved performance because the
|
||||
* configuration can be applied atomically.
|
||||
* <p>
|
||||
* After a successful invocation of this method, this recording is in the
|
||||
* {@code RUNNING} state.
|
||||
*
|
||||
* @throws IllegalStateException if recording is already started or is in the
|
||||
* {@code CLOSED} state
|
||||
*/
|
||||
public void start() {
|
||||
internal.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this recording after a delay.
|
||||
* <p>
|
||||
* After a successful invocation of this method, this recording is in the
|
||||
* {@code DELAYED} state.
|
||||
*
|
||||
* @param delay the time to wait before starting this recording, not
|
||||
* {@code null}
|
||||
* @throws IllegalStateException if the recording is not it the {@code NEW} state
|
||||
*/
|
||||
public void scheduleStart(Duration delay) {
|
||||
Objects.requireNonNull(delay);
|
||||
internal.scheduleStart(delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops this recording.
|
||||
* <p>
|
||||
* When a recording is stopped it can't be restarted. If this
|
||||
* recording has a destination, data is written to that destination and
|
||||
* the recording is closed. After a recording is closed, the data is no longer
|
||||
* available.
|
||||
* <p>
|
||||
* After a successful invocation of this method, this recording will be
|
||||
* in the {@code STOPPED} state.
|
||||
*
|
||||
* @return {@code true} if recording is stopped, {@code false} otherwise
|
||||
*
|
||||
* @throws IllegalStateException if the recording is not started or is already stopped
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* doesn't have {@code FilePermission} to write to the destination
|
||||
* path
|
||||
*
|
||||
* @see #setDestination(Path)
|
||||
*
|
||||
*/
|
||||
public boolean stop() {
|
||||
return internal.stop("Stopped by user");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns settings used by this recording.
|
||||
* <p>
|
||||
* Modifying the returned {@code Map} will not change the settings for this recording.
|
||||
* <p>
|
||||
* If no settings are set for this recording, an empty {@code Map} is
|
||||
* returned.
|
||||
*
|
||||
* @return recording settings, not {@code null}
|
||||
*/
|
||||
public Map<String, String> getSettings() {
|
||||
return new HashMap<>(internal.getSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current size of this recording in the disk repository,
|
||||
* measured in bytes.
|
||||
* <p>
|
||||
* The size is updated when recording buffers are flushed. If the recording is
|
||||
* not written to the disk repository the returned size is always {@code 0}.
|
||||
*
|
||||
* @return amount of recorded data, measured in bytes, or {@code 0} if the
|
||||
* recording is not written to the disk repository
|
||||
*/
|
||||
public long getSize() {
|
||||
return internal.getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time when this recording was stopped.
|
||||
*
|
||||
* @return the time, or {@code null} if this recording is not stopped
|
||||
*/
|
||||
public Instant getStopTime() {
|
||||
return internal.getStopTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time when this recording was started.
|
||||
*
|
||||
* @return the the time, or {@code null} if this recording is not started
|
||||
*/
|
||||
public Instant getStartTime() {
|
||||
return internal.getStartTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum size, measured in bytes, at which data is no longer kept in the disk repository.
|
||||
*
|
||||
* @return maximum size in bytes, or {@code 0} if no maximum size is set
|
||||
*/
|
||||
public long getMaxSize() {
|
||||
return internal.getMaxSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of time that the data is kept in the disk repository
|
||||
* before it is removed.
|
||||
*
|
||||
* @return maximum length of time, or {@code null} if no maximum length of time
|
||||
* has been set
|
||||
*/
|
||||
public Duration getMaxAge() {
|
||||
return internal.getMaxAge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this recording.
|
||||
* <p>
|
||||
* By default, the name is the same as the recording ID.
|
||||
*
|
||||
* @return the recording name, not {@code null}
|
||||
*/
|
||||
public String getName() {
|
||||
return internal.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all settings for this recording.
|
||||
* <p>
|
||||
* The following example shows how to set event settings for a recording.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* Map{@literal <}String, String{@literal >} settings = new HashMap{@literal <}{@literal >}();
|
||||
* settings.putAll(EventSettings.enabled("jdk.CPUSample").withPeriod(Duration.ofSeconds(2)).toMap());
|
||||
* settings.putAll(EventSettings.enabled(MyEvent.class).withThreshold(Duration.ofSeconds(2)).withoutStackTrace().toMap());
|
||||
* settings.put("jdk.ExecutionSample#period", "10 ms");
|
||||
* recording.setSettings(settings);
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The following example shows how to merge settings.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Map<String, String> settings = recording.getSettings();
|
||||
* settings.putAll(additionalSettings);
|
||||
* recording.setSettings(settings);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param settings the settings to set, not {@code null}
|
||||
*/
|
||||
public void setSettings(Map<String, String> settings) {
|
||||
Objects.requireNonNull(settings);
|
||||
Map<String, String> sanitized = Utils.sanitizeNullFreeStringMap(settings);
|
||||
internal.setSettings(sanitized);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recording state that this recording is currently in.
|
||||
*
|
||||
* @return the recording state, not {@code null}
|
||||
*
|
||||
* @see RecordingState
|
||||
*/
|
||||
public RecordingState getState() {
|
||||
return internal.getState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all data that is associated with this recording.
|
||||
* <p>
|
||||
* After a successful invocation of this method, this recording is in the
|
||||
* {@code CLOSED} state.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
internal.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of this recording, with a new recording ID and name.
|
||||
*
|
||||
* Clones are useful for dumping data without stopping the recording. After
|
||||
* a clone is created, the amount of data to copy is constrained
|
||||
* with the {@link #setMaxAge(Duration)} method and the {@link #setMaxSize(long)}method.
|
||||
*
|
||||
* @param stop {@code true} if the newly created copy should be stopped
|
||||
* immediately, {@code false} otherwise
|
||||
* @return the recording copy, not {@code null}
|
||||
*/
|
||||
public Recording copy(boolean stop) {
|
||||
return internal.newCopy(stop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes recording data to a file.
|
||||
* <p>
|
||||
* Recording must be started, but not necessarily stopped.
|
||||
*
|
||||
* @param destination the location where recording data is written, not
|
||||
* {@code null}
|
||||
*
|
||||
* @throws IOException if the recording can't be copied to the specified
|
||||
* location
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller doesn't
|
||||
* have {@code FilePermission} to write to the destination path
|
||||
*/
|
||||
public void dump(Path destination) throws IOException {
|
||||
Objects.requireNonNull(destination);
|
||||
internal.dump(new WriteableUserPath(destination));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this recording uses the disk repository, {@code false} otherwise.
|
||||
* <p>
|
||||
* If no value is set, {@code true} is returned.
|
||||
*
|
||||
* @return {@code true} if the recording uses the disk repository, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
public boolean isToDisk() {
|
||||
return internal.isToDisk();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how much data is kept in the disk repository.
|
||||
* <p>
|
||||
* To control the amount of recording data that is stored on disk, the maximum
|
||||
* amount of data to retain can be specified. When the maximum limit is
|
||||
* exceeded, the Java Virtual Machine (JVM) removes the oldest chunk to make
|
||||
* room for a more recent chunk.
|
||||
* <p>
|
||||
* If neither maximum limit or the maximum age is set, the size of the
|
||||
* recording may grow indefinitely.
|
||||
*
|
||||
* @param maxSize the amount of data to retain, {@code 0} if infinite
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>maxSize</code> is negative
|
||||
*
|
||||
* @throws IllegalStateException if the recording is in {@code CLOSED} state
|
||||
*/
|
||||
public void setMaxSize(long maxSize) {
|
||||
if (maxSize < 0) {
|
||||
throw new IllegalArgumentException("Max size of recording can't be negative");
|
||||
}
|
||||
internal.setMaxSize(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how far back data is kept in the disk repository.
|
||||
* <p>
|
||||
* To control the amount of recording data stored on disk, the maximum length of
|
||||
* time to retain the data can be specified. Data stored on disk that is older
|
||||
* than the specified length of time is removed by the Java Virtual Machine (JVM).
|
||||
* <p>
|
||||
* If neither maximum limit or the maximum age is set, the size of the
|
||||
* recording may grow indefinitely.
|
||||
*
|
||||
* @param maxAge the length of time that data is kept, or {@code null} if infinite
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>maxAge</code> is negative
|
||||
*
|
||||
* @throws IllegalStateException if the recording is in the {@code CLOSED} state
|
||||
*/
|
||||
public void setMaxAge(Duration maxAge) {
|
||||
if (maxAge != null && maxAge.isNegative()) {
|
||||
throw new IllegalArgumentException("Max age of recording can't be negative");
|
||||
}
|
||||
internal.setMaxAge(maxAge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a location where data is written on recording stop, or
|
||||
* {@code null} if data is not to be dumped.
|
||||
* <p>
|
||||
* If a destination is set, this recording is automatically closed
|
||||
* after data is successfully copied to the destination path.
|
||||
* <p>
|
||||
* If a destination is <em>not</em> set, Flight Recorder retains the
|
||||
* recording data until this recording is closed. Use the {@link #dump(Path)} method to
|
||||
* manually write data to a file.
|
||||
*
|
||||
* @param destination the destination path, or {@code null} if recording should
|
||||
* not be dumped at stop
|
||||
*
|
||||
* @throws IllegalStateException if recording is in the {@code STOPPED} or
|
||||
* {@code CLOSED} state.
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and the caller
|
||||
* doesn't have {@code FilePermission} to read, write, and delete the
|
||||
* {@code destination} file
|
||||
*
|
||||
* @throws IOException if the path is not writable
|
||||
*/
|
||||
public void setDestination(Path destination) throws IOException {
|
||||
internal.setDestination(destination != null ? new WriteableUserPath(destination) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the destination file, where recording data is written when the
|
||||
* recording stops, or {@code null} if no destination is set.
|
||||
*
|
||||
* @return the destination file, or {@code null} if not set.
|
||||
*/
|
||||
public Path getDestination() {
|
||||
WriteableUserPath usp = internal.getDestination();
|
||||
if (usp == null) {
|
||||
return null;
|
||||
} else {
|
||||
return usp.getPotentiallyMaliciousOriginal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for this recording.
|
||||
*
|
||||
* @return the recording ID
|
||||
*/
|
||||
public long getId() {
|
||||
return internal.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a human-readable name (for example, {@code "My Recording"}).
|
||||
*
|
||||
* @param name the recording name, not {@code null}
|
||||
*
|
||||
* @throws IllegalStateException if the recording is in {@code CLOSED} state
|
||||
*/
|
||||
public void setName(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
internal.setName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this recording is dumped to disk when the JVM exits.
|
||||
*
|
||||
* @param dumpOnExit if this recording should be dumped when the JVM exits
|
||||
*/
|
||||
public void setDumpOnExit(boolean dumpOnExit) {
|
||||
internal.setDumpOnExit(dumpOnExit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this recording is dumped to disk when the JVM exits.
|
||||
* <p>
|
||||
* If dump on exit is not set, {@code false} is returned.
|
||||
*
|
||||
* @return {@code true} if the recording is dumped on exit, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean getDumpOnExit() {
|
||||
return internal.getDumpOnExit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this recording is continuously flushed to the disk
|
||||
* repository or data is constrained to what is available in memory buffers.
|
||||
*
|
||||
* @param disk {@code true} if this recording is written to disk,
|
||||
* {@code false} if in-memory
|
||||
*
|
||||
*/
|
||||
public void setToDisk(boolean disk) {
|
||||
internal.setToDisk(disk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a data stream for a specified interval.
|
||||
* <p>
|
||||
* The stream may contain some data outside the specified range.
|
||||
*
|
||||
* @param the start start time for the stream, or {@code null} to get data from
|
||||
* start time of the recording
|
||||
*
|
||||
* @param the end end time for the stream, or {@code null} to get data until the
|
||||
* present time.
|
||||
*
|
||||
* @return an input stream, or {@code null} if no data is available in the
|
||||
* interval.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code end} happens before
|
||||
* {@code start}
|
||||
*
|
||||
* @throws IOException if a stream can't be opened
|
||||
*/
|
||||
public InputStream getStream(Instant start, Instant end) throws IOException {
|
||||
if (start != null && end != null && end.isBefore(start)) {
|
||||
throw new IllegalArgumentException("End time of requested stream must not be before start time");
|
||||
}
|
||||
return internal.open(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified duration for this recording, or {@code null} if no
|
||||
* duration is set.
|
||||
* <p>
|
||||
* The duration can be set only when the recording is in the
|
||||
* {@link RecordingState#NEW} state.
|
||||
*
|
||||
* @return the desired duration of the recording, or {@code null} if no duration
|
||||
* has been set.
|
||||
*/
|
||||
public Duration getDuration() {
|
||||
return internal.getDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a duration for how long a recording runs before it stops.
|
||||
* <p>
|
||||
* By default, a recording has no duration ({@code null}).
|
||||
*
|
||||
* @param duration the duration, or {@code null} if no duration is set
|
||||
*
|
||||
* @throws IllegalStateException if recording is in the {@code STOPPED} or {@code CLOSED} state
|
||||
*/
|
||||
public void setDuration(Duration duration) {
|
||||
internal.setDuration(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the event with the specified name.
|
||||
* <p>
|
||||
* If multiple events have the same name (for example, the same class is loaded
|
||||
* in different class loaders), then all events that match the name are enabled. To
|
||||
* enable a specific class, use the {@link #enable(Class)} method or a {@code String}
|
||||
* representation of the event type ID.
|
||||
*
|
||||
* @param name the settings for the event, not {@code null}
|
||||
*
|
||||
* @return an event setting for further configuration, not {@code null}
|
||||
*
|
||||
* @see EventType
|
||||
*/
|
||||
public EventSettings enable(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
RecordingSettings rs = new RecordingSettings(this, name);
|
||||
rs.with("enabled", "true");
|
||||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables event with the specified name.
|
||||
* <p>
|
||||
* If multiple events with same name (for example, the same class is loaded
|
||||
* in different class loaders), then all events that match the
|
||||
* name is disabled. To disable a specific class, use the
|
||||
* {@link #disable(Class)} method or a {@code String} representation of the event
|
||||
* type ID.
|
||||
*
|
||||
* @param name the settings for the event, not {@code null}
|
||||
*
|
||||
* @return an event setting for further configuration, not {@code null}
|
||||
*
|
||||
*/
|
||||
public EventSettings disable(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
RecordingSettings rs = new RecordingSettings(this, name);
|
||||
rs.with("enabled", "false");
|
||||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables event.
|
||||
*
|
||||
* @param eventClass the event to enable, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code eventClass} is an abstract
|
||||
* class or not a subclass of {@link Event}
|
||||
*
|
||||
* @return an event setting for further configuration, not {@code null}
|
||||
*/
|
||||
public EventSettings enable(Class<? extends Event> eventClass) {
|
||||
Objects.requireNonNull(eventClass);
|
||||
RecordingSettings rs = new RecordingSettings(this, eventClass);
|
||||
rs.with("enabled", "true");
|
||||
return rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables event.
|
||||
*
|
||||
* @param eventClass the event to enable, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code eventClass} is an abstract
|
||||
* class or not a subclass of {@link Event}
|
||||
*
|
||||
* @return an event setting for further configuration, not {@code null}
|
||||
*
|
||||
*/
|
||||
public EventSettings disable(Class<? extends Event> eventClass) {
|
||||
Objects.requireNonNull(eventClass);
|
||||
RecordingSettings rs = new RecordingSettings(this, eventClass);
|
||||
rs.with("enabled", "false");
|
||||
return rs;
|
||||
}
|
||||
|
||||
// package private
|
||||
PlatformRecording getInternal() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
private void setSetting(String id, String value) {
|
||||
Objects.requireNonNull(id);
|
||||
Objects.requireNonNull(value);
|
||||
internal.setSetting(id, value);
|
||||
}
|
||||
|
||||
}
|
||||
71
jdkSrc/jdk8/jdk/jfr/RecordingState.java
Normal file
71
jdkSrc/jdk8/jdk/jfr/RecordingState.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
/**
|
||||
* Indicates a state in the life cycle of a recording.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public enum RecordingState {
|
||||
|
||||
/**
|
||||
* The initial state when a {@code Recording} is created.
|
||||
*/
|
||||
NEW,
|
||||
|
||||
/**
|
||||
* The recording is scheduled to start with a start time in the future.
|
||||
* <p>
|
||||
* An invocation of the {@link Recording#start()} method will transition the
|
||||
* recording to the {@code RUNNING} state.
|
||||
*/
|
||||
DELAYED,
|
||||
|
||||
/**
|
||||
* The recording is recording data and an invocation of the {@link Recording#stop()}
|
||||
* method will transition the recording to the {@code STOPPED} state.
|
||||
*/
|
||||
RUNNING,
|
||||
|
||||
/**
|
||||
* The recording is stopped and is holding recorded data that can be dumped to
|
||||
* disk.
|
||||
* <p>
|
||||
* An invocation of the {@link Recording#close()} method will release the
|
||||
* data and transition the recording to the {@code CLOSED} state.
|
||||
*/
|
||||
STOPPED,
|
||||
|
||||
/**
|
||||
* The recording is closed and all resources that are associated with the
|
||||
* recording are released.
|
||||
* <p>
|
||||
* Nothing that can be done with a recording from this point, and it's
|
||||
* no longer retrievable from the {@code FlightRrecorder.getRecordings()} method.
|
||||
*/
|
||||
CLOSED;
|
||||
}
|
||||
55
jdkSrc/jdk8/jdk/jfr/Registered.java
Normal file
55
jdkSrc/jdk8/jdk/jfr/Registered.java
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event annotation, for programmatic event registration.
|
||||
* <p>
|
||||
* Events are automatically registered when they are first used. This annotation
|
||||
* can be used to override that registration. To register
|
||||
* events programmatically, use {@link FlightRecorder#register(Class)}.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Target({ ElementType.TYPE })
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Registered {
|
||||
/**
|
||||
* Returns {@code true} if the event is to be registered when the event class is
|
||||
* first used, {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if the event is to be registered when the event class is
|
||||
* first used, {@code false} otherwise.
|
||||
*/
|
||||
public boolean value() default true;
|
||||
}
|
||||
43
jdkSrc/jdk8/jdk/jfr/Relational.java
Normal file
43
jdkSrc/jdk8/jdk/jfr/Relational.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Meta annotation for relational annotations, to be used on an annotation.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Label("Relation")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface Relational {
|
||||
}
|
||||
220
jdkSrc/jdk8/jdk/jfr/SettingControl.java
Normal file
220
jdkSrc/jdk8/jdk/jfr/SettingControl.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.jfr.internal.Control;
|
||||
|
||||
/**
|
||||
* Base class to extend to create setting controls.
|
||||
* <p>
|
||||
* The following example shows a naive implementation of a setting control for
|
||||
* regular expressions:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* final class RegExpControl extends SettingControl {
|
||||
* private Pattern pattern = Pattern.compile(".*");
|
||||
*
|
||||
* {@literal @}Override
|
||||
* public void setValue(String value) {
|
||||
* this.pattern = Pattern.compile(value);
|
||||
* }
|
||||
*
|
||||
* {@literal @}Override
|
||||
* public String combine(Set{@literal <}String{@literal >} values) {
|
||||
* return String.join("|", values);
|
||||
* }
|
||||
*
|
||||
* {@literal @}Override
|
||||
* public String getValue() {
|
||||
* return pattern.toString();
|
||||
* }
|
||||
*
|
||||
* public String matches(String s) {
|
||||
* return pattern.matcher(s).find();
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The {@code setValue(String)}, {@code getValue()} and
|
||||
* {@code combine(Set<String>)} methods are invoked when a setting value
|
||||
* changes, which typically happens when a recording is started or stopped. The
|
||||
* {@code combine(Set<String>)} method is invoked to resolve what value to use
|
||||
* when multiple recordings are running at the same time.
|
||||
* <p>
|
||||
* The setting control must have a default constructor that can be invoked when
|
||||
* the event is registered.
|
||||
* <p>
|
||||
* To use a setting control with an event, add a method that returns a
|
||||
* {@code boolean} value and takes the setting control as a parameter. Annotate
|
||||
* the method with the {@code @SettingDefinition} annotation. By default, the
|
||||
* method name is used as the setting name, but the name can be set explicitly
|
||||
* by using the {@code @Name} annotation. If the method returns {@code true},
|
||||
* the event will be committed.
|
||||
* <p>
|
||||
* It is recommended that the {@code setValue(String)} method updates an
|
||||
* efficient data structure that can be quickly checked when the event is
|
||||
* committed.
|
||||
* <p>
|
||||
* The following example shows how to create an event that uses the
|
||||
* regular expression filter defined above.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* abstract class HTTPRequest extends Event {
|
||||
* {@literal @}Label("Request URI")
|
||||
* protected String uri;
|
||||
*
|
||||
* {@literal @}Label("Servlet URI Filter")
|
||||
* {@literal @}SettingDefinition
|
||||
* protected boolean uriFilter(RegExpControl regExp) {
|
||||
* return regExp.matches(uri);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* {@literal @}Label("HTTP Get Request")
|
||||
* class HTTPGetRequest extends HTTPRequest {
|
||||
* }
|
||||
*
|
||||
* {@literal @}Label("HTTP Post Request")
|
||||
* class HTTPPostRequest extends HTTPRequest {
|
||||
* }
|
||||
*
|
||||
* class ExampleServlet extends HTTPServlet {
|
||||
* protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
|
||||
* HTTPGetRequest request = new HTTPGetRequest();
|
||||
* request.begin();
|
||||
* request.uri = req.getRequestURI();
|
||||
* ...
|
||||
* request.commit();
|
||||
* }
|
||||
*
|
||||
* protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
|
||||
* HTTPPostRequest request = new HTTPPostRequest();
|
||||
* request.begin();
|
||||
* request.uri = req.getRequestURI();
|
||||
* ...
|
||||
* request.commit();
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* The following example shows how an event can be filtered by assigning the
|
||||
* {@code "uriFilter"} setting with the specified regular expressions.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* Recording r = new Recording();
|
||||
* r.enable("HTTPGetRequest").with("uriFilter", "https://www.example.com/list/.*");
|
||||
* r.enable("HTTPPostRequest").with("uriFilter", "https://www.example.com/login/.*");
|
||||
* r.start();
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*
|
||||
* @see SettingDefinition
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
public abstract class SettingControl extends Control {
|
||||
|
||||
/**
|
||||
* Constructor for invocation by subclass constructors.
|
||||
*/
|
||||
protected SettingControl() {
|
||||
super(AccessController.getContext());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the setting values for all running recordings into one value when
|
||||
* multiple recordings are running at the same time,
|
||||
* <p>
|
||||
* The semantics of how setting values are combined depends on the setting
|
||||
* control that is implemented, but all recordings should get at least all the
|
||||
* events they request.
|
||||
* <p>
|
||||
* This method should have no side effects, because the caller might cache values.
|
||||
* This method should never return {@code null} or throw an exception. If a
|
||||
* value is not valid for this setting control, the value should be ignored.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <p>
|
||||
* if the setting control represents a threshold and three recordings are
|
||||
* running at the same time with the setting values {@code "10 ms"},
|
||||
* {@code "8 s"}, and {@code "1 ms"}, this method returns {@code "1 ms"}
|
||||
* because it means that all recordings get at least all the requested data.
|
||||
* <p>
|
||||
* If the setting control represents a set of names and two recordings are
|
||||
* running at the same time with the setting values {@code "Smith, Jones"} and {@code "Jones,
|
||||
* Williams"} the returned value is {@code "Smith, Jones, Williams"} because all names would be accepted.
|
||||
* <p>
|
||||
* If the setting control represents a boolean condition and four recordings are
|
||||
* running at the same time with the following values {@code "true"}, {@code "false"}, {@code "false"}, and
|
||||
* {@code "incorrect"}, this method returns {@code "true"}, because all
|
||||
* recordings get at least all the requested data.
|
||||
*
|
||||
* @param settingValues the set of values, not {@code null}
|
||||
*
|
||||
* @return the value to use, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public abstract String combine(Set<String> settingValues);
|
||||
|
||||
/**
|
||||
* Sets the value for this setting.
|
||||
* <p>
|
||||
* If the setting value is not valid for this setting, this method
|
||||
* does not throw an exception. Instead, the value is ignored.
|
||||
*
|
||||
* @param settingValue the string value, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public abstract void setValue(String settingValue);
|
||||
|
||||
/**
|
||||
* Returns the currently used value for this setting, not {@code null}.
|
||||
* <p>
|
||||
* The value returned by this method is valid as an argument to both
|
||||
* the {@code setValue(String)} method and {@code combine(Set)} method.
|
||||
* <p>
|
||||
* This method is invoked when an event is registered to obtain the
|
||||
* default value. It is therefore important that a valid value can be
|
||||
* returned immediately after an instance of this class is created. It is
|
||||
* not valid to return {@code null}.
|
||||
*
|
||||
* @return the setting value, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public abstract String getValue();
|
||||
}
|
||||
70
jdkSrc/jdk8/jdk/jfr/SettingDefinition.java
Normal file
70
jdkSrc/jdk8/jdk/jfr/SettingDefinition.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that specifies that a method in an event class should be used to
|
||||
* filter out events.
|
||||
* <p>
|
||||
* For the method to be valid it must return a {@code SettingControl} and only have one
|
||||
* parameter, which should be a non-abstract subclass of {@link SettingControl}
|
||||
* <p>
|
||||
* The return value of the method specifies whether the event is to be
|
||||
* written to the Flight Recorder system or not.
|
||||
* <p>
|
||||
* The following example shows how to annotate a method in an event class.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* class HelloWorld extend Event {
|
||||
*
|
||||
* {@literal @}Label("Message");
|
||||
* String message;
|
||||
*
|
||||
* {@literal @}SettingDefinition;
|
||||
* {@literal @}Label("Message Filter");
|
||||
* public boolean filter(RegExpControl regExp) {
|
||||
* return regExp.matches(message);
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* For an example of how the setting controls are defined, see
|
||||
* {@link SettingControl}.
|
||||
*
|
||||
* @see SettingControl
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD })
|
||||
public @interface SettingDefinition {
|
||||
}
|
||||
215
jdkSrc/jdk8/jdk/jfr/SettingDescriptor.java
Normal file
215
jdkSrc/jdk8/jdk/jfr/SettingDescriptor.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.AnnotationConstruct;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* Describes an event setting.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class SettingDescriptor {
|
||||
|
||||
private final AnnotationConstruct annotationConstruct;
|
||||
private final Type type;
|
||||
private final String name;
|
||||
private final String defaultValue;
|
||||
|
||||
// package private, invoked by jdk.internal.
|
||||
SettingDescriptor(Type type, String name, String defaultValue, List<AnnotationElement> annotations) {
|
||||
Objects.requireNonNull(annotations);
|
||||
this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
|
||||
this.type = Objects.requireNonNull(type);
|
||||
this.annotationConstruct = new AnnotationConstruct(annotations);
|
||||
this.defaultValue = Objects.requireNonNull(defaultValue);
|
||||
}
|
||||
|
||||
// package private
|
||||
void setAnnotations(List<AnnotationElement> as) {
|
||||
annotationConstruct.setAnnotationElements(as);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the setting (for example, {@code "threshold"}).
|
||||
*
|
||||
* @return the name, not {@code null}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name that describes the setting (for example,
|
||||
* {@code "Threshold"}).
|
||||
* <p>
|
||||
* If the setting lacks a label, the label for the type that is associated with this
|
||||
* setting is returned, or {@code null} if doesn't exist
|
||||
*
|
||||
* @return a human-readable name, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getLabel() {
|
||||
String label = annotationConstruct.getLabel();
|
||||
if (label == null) {
|
||||
label = type.getLabel();
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sentence that describes the setting (for example
|
||||
* {@code "Record event with duration
|
||||
* above or equal to threshold"}).
|
||||
* <p>
|
||||
* If the setting lacks a description, the description for the type that is
|
||||
* associated with this setting is returned, or {@code null} if doesn't exist.
|
||||
*
|
||||
* @return the description, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getDescription() {
|
||||
String description = annotationConstruct.getDescription();
|
||||
if (description == null) {
|
||||
description = type.getDescription();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual identifier that specifies how a value that is represented by
|
||||
* this {@code SettingDescriptor} object is interpreted or formatted.
|
||||
* <p>
|
||||
* For example, if the setting descriptor represents a percentage, then
|
||||
* {@code "jdk.jfr.Percentage"} hints to a client that a value of "0.5"
|
||||
* is formatted as "50%".
|
||||
* <p>
|
||||
* The JDK provides the following predefined content types:
|
||||
* <ul>
|
||||
* <li>jdk.jfr.Percentage</li>
|
||||
* <li>jdk.jfr.Timespan</li>
|
||||
* <li>jdk.jfr.Timestamp</li>
|
||||
* <li>jdk.jfr.Frequency</li>
|
||||
* <li>jdk.jfr.Flag</li>
|
||||
* <li>jdk.jfr.MemoryAddress</li>
|
||||
* <li>jdk.jfr.DataAmount</li>
|
||||
* <li>jdk.jfr.NetworkAddress</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* User-defined content types can be created by using {@link ContentType}.
|
||||
* <p>
|
||||
* If the setting lacks a content type, the content type for the type
|
||||
* that is associated with this setting is returned, or {@code null} if not
|
||||
* available.
|
||||
*
|
||||
* @return the content type, or {@code null} if doesn't exist
|
||||
*
|
||||
* @see ContentType
|
||||
*/
|
||||
public String getContentType() {
|
||||
for (AnnotationElement anno : getAnnotationElements()) {
|
||||
for (AnnotationElement meta : anno.getAnnotationElements()) {
|
||||
if (meta.getTypeName().equals(ContentType.class.getName())) {
|
||||
return anno.getTypeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (AnnotationElement anno : type.getAnnotationElements()) {
|
||||
for (AnnotationElement meta : anno.getAnnotationElements()) {
|
||||
if (meta.getTypeName().equals(ContentType.class.getName())) {
|
||||
return anno.getTypeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified class name of the type that is associated with this
|
||||
* setting descriptor.
|
||||
*
|
||||
* @return the type name, not {@code null}
|
||||
*
|
||||
* @see SettingDescriptor#getTypeId()
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for the type in the Java Virtual Machine (JVM).
|
||||
* <p>
|
||||
* The ID might not be the same between JVM instances.
|
||||
*
|
||||
* @return the type ID, not negative
|
||||
*/
|
||||
public long getTypeId() {
|
||||
return type.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first annotation for the specified type if an annotation
|
||||
* element with the same name is available, {@code null} otherwise.
|
||||
*
|
||||
* @param <A> the type of the annotation to query for and return if available
|
||||
* @param annotationType the Class object that corresponds to the annotation
|
||||
* type, not {@code null}
|
||||
* @return this element's annotation for the specified annotation type if
|
||||
* available, {@code null} otherwise
|
||||
*/
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
|
||||
Objects.requireNonNull(annotationType);
|
||||
return annotationConstruct.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of annotation elements for this value
|
||||
* descriptor.
|
||||
*
|
||||
* @return a list of annotations, not {@code null}
|
||||
*/
|
||||
public List<AnnotationElement> getAnnotationElements() {
|
||||
return Collections.unmodifiableList(annotationConstruct.getUnmodifiableAnnotationElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default value for this setting descriptor.
|
||||
*
|
||||
* @return the default value, not {@code null}
|
||||
*/
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// package private
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
57
jdkSrc/jdk8/jdk/jfr/StackTrace.java
Normal file
57
jdkSrc/jdk8/jdk/jfr/StackTrace.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event annotation, determines whether an event by default has a stack trace
|
||||
* or not.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE })
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface StackTrace {
|
||||
/**
|
||||
* Settings name {@code "stackTrace"} to be used for enabling event stack traces.
|
||||
*/
|
||||
public final static String NAME = "stackTrace";
|
||||
|
||||
/**
|
||||
* Returns if the stack trace from the {@code Event#commit()} method should be recorded.
|
||||
*
|
||||
* @return {@code true} if the stack trace should be recorded, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
boolean value() default true;
|
||||
}
|
||||
69
jdkSrc/jdk8/jdk/jfr/Threshold.java
Normal file
69
jdkSrc/jdk8/jdk/jfr/Threshold.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event annotation, specifies the default duration below which an event is not
|
||||
* recorded (for example, {@code "20 ms"}).
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE })
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Threshold {
|
||||
/**
|
||||
* Setting name {@code "threshold"} for configuring event thresholds.
|
||||
*/
|
||||
public final static String NAME = "threshold";
|
||||
|
||||
/**
|
||||
* The threshold (for example, {@code "20 ms"}).
|
||||
* <p>
|
||||
* A {@code String} representation of a positive {@code Long} value followed by an
|
||||
* empty space and one of the following units:<br>
|
||||
* <br>
|
||||
* {@code "ns"} (nanoseconds)<br>
|
||||
* {@code "us"} (microseconds)<br>
|
||||
* {@code "ms"} (milliseconds)<br>
|
||||
* {@code "s"} (seconds)<br>
|
||||
* {@code "m"} (minutes)<br>
|
||||
* {@code "h"} (hours)<br>
|
||||
* {@code "d"} (days)<br>
|
||||
* <p>
|
||||
* Example values are {@code "0 ns"}, {@code "10 ms"}, and {@code "1 s"}.
|
||||
*
|
||||
* @return the threshold, default {@code "0 ns"}, not {@code null}
|
||||
*/
|
||||
String value() default "0 ns";
|
||||
}
|
||||
75
jdkSrc/jdk8/jdk/jfr/Timespan.java
Normal file
75
jdkSrc/jdk8/jdk/jfr/Timespan.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the value is a duration.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Timespan")
|
||||
@Description("A duration, measured in nanoseconds by default")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface Timespan {
|
||||
/**
|
||||
* Unit for ticks.
|
||||
*/
|
||||
public static final String TICKS = "TICKS";
|
||||
/**
|
||||
* Unit for seconds.
|
||||
*/
|
||||
public static final String SECONDS = "SECONDS";
|
||||
/**
|
||||
* Unit for milliseconds.
|
||||
*/
|
||||
public static final String MILLISECONDS = "MILLISECONDS";
|
||||
/**
|
||||
* Unit for nanoseconds.
|
||||
*/
|
||||
public static final String NANOSECONDS = "NANOSECONDS";
|
||||
|
||||
/**
|
||||
* Unit for microseconds.
|
||||
*/
|
||||
public static final String MICROSECONDS = "MICROSECONDS";
|
||||
|
||||
/**
|
||||
* Returns the unit of measure for the time span.
|
||||
* <p>
|
||||
* By default, the unit is nanoseconds.
|
||||
*
|
||||
* @return the time span unit, default {@code #NANOSECONDS}, not {@code null}
|
||||
*/
|
||||
String value() default NANOSECONDS;
|
||||
}
|
||||
63
jdkSrc/jdk8/jdk/jfr/Timestamp.java
Normal file
63
jdkSrc/jdk8/jdk/jfr/Timestamp.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the value is a point in time.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Timestamp")
|
||||
@Description("A point in time")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
|
||||
public @interface Timestamp {
|
||||
/**
|
||||
* The unit for the difference, measured in milliseconds, between the current
|
||||
* time and midnight, January 1, 1970 UTC.
|
||||
*/
|
||||
public final static String MILLISECONDS_SINCE_EPOCH = "MILLISECONDS_SINCE_EPOCH";
|
||||
|
||||
/**
|
||||
* The unit for the number of ticks that have transpired since some arbitrary
|
||||
* starting date.
|
||||
*/
|
||||
public final static String TICKS = "TICKS";
|
||||
|
||||
/**
|
||||
* Unit for the time stamp.
|
||||
*
|
||||
* @return time stamp unit, not {@code null}
|
||||
*/
|
||||
String value() default Timestamp.MILLISECONDS_SINCE_EPOCH;
|
||||
}
|
||||
43
jdkSrc/jdk8/jdk/jfr/TransitionFrom.java
Normal file
43
jdkSrc/jdk8/jdk/jfr/TransitionFrom.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the event transitioned from a thread.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Label("Transition From")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface TransitionFrom {
|
||||
}
|
||||
43
jdkSrc/jdk8/jdk/jfr/TransitionTo.java
Normal file
43
jdkSrc/jdk8/jdk/jfr/TransitionTo.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the event will soon transition to a thread.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Label("Transition To")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface TransitionTo {
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/Unsigned.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/Unsigned.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Event field annotation, specifies that the value is of an unsigned data type.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@ContentType
|
||||
@Label("Unsigned Value")
|
||||
@Description("Value should be interpreted as unsigned data type")
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
public @interface Unsigned {
|
||||
}
|
||||
322
jdkSrc/jdk8/jdk/jfr/ValueDescriptor.java
Normal file
322
jdkSrc/jdk8/jdk/jfr/ValueDescriptor.java
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.internal.AnnotationConstruct;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.Utils;
|
||||
|
||||
/**
|
||||
* Describes the event fields and annotation elements.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class ValueDescriptor {
|
||||
|
||||
private final AnnotationConstruct annotationConstruct;
|
||||
private final Type type;
|
||||
private final String name;
|
||||
private final boolean isArray;
|
||||
private final boolean constantPool;
|
||||
private final String javaFieldName;
|
||||
|
||||
// package private, invoked by jdk.internal.
|
||||
ValueDescriptor(Type type, String name, List<AnnotationElement> annotations, int dimension, boolean constantPool, String fieldName) {
|
||||
Objects.requireNonNull(annotations);
|
||||
if (dimension < 0) {
|
||||
throw new IllegalArgumentException("Dimension must be positive");
|
||||
}
|
||||
this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
|
||||
this.type = Objects.requireNonNull(type);
|
||||
this.isArray = dimension > 0;
|
||||
this.constantPool = constantPool;
|
||||
this.annotationConstruct = new AnnotationConstruct(annotations);
|
||||
this.javaFieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructs a value descriptor, useful for dynamically creating event types and
|
||||
* annotations.
|
||||
* <P>
|
||||
* The following types are supported:
|
||||
* <ul>
|
||||
* <li>{@code byte.class}
|
||||
* <li>{@code short.class}
|
||||
* <li>{@code int.class}
|
||||
* <li>{@code long.class}
|
||||
* <li>{@code char.class}
|
||||
* <li>{@code float.class}
|
||||
* <li>{@code double.class}
|
||||
* <li>{@code boolean.class}
|
||||
* <li>{@code String.class}
|
||||
* <li>{@code Class.class}
|
||||
* <li>{@code Thread.class}
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
|
||||
* Java Language Specification for more information.
|
||||
*
|
||||
* @param type the type, not {@code null}
|
||||
* @param name the name, not {@code null}
|
||||
*
|
||||
* @throws SecurityException if a security manager is present and the caller
|
||||
* doesn't have {@code FlightRecorderPermission("registerEvent")}
|
||||
*
|
||||
*/
|
||||
public ValueDescriptor(Class<?> type, String name) {
|
||||
this(type, name, Collections.<AnnotationElement> emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Constructs a value descriptor, useful for dynamically creating event types and
|
||||
* annotations.
|
||||
* <P>
|
||||
* The following types are supported:
|
||||
* <ul>
|
||||
* <li>{@code byte.class}
|
||||
* <li>{@code short.class}
|
||||
* <li>{@code int.class}
|
||||
* <li>{@code long.class}
|
||||
* <li>{@code char.class}
|
||||
* <li>{@code float.class}
|
||||
* <li>{@code double.class}
|
||||
* <li>{@code boolean.class}
|
||||
* <li>{@code String.class}
|
||||
* <li>{@code Class.class}
|
||||
* <li>{@code Thread.class}
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The name must be a valid Java identifier (for example, {@code "maxThroughput"}). See 3.8
|
||||
* Java Language Specification for more information.
|
||||
*
|
||||
* @param type the type, not {@code null}
|
||||
* @param name the name, not {@code null}
|
||||
* @param annotations the annotations on the value descriptors, not
|
||||
* {@code null}
|
||||
*
|
||||
* @throws SecurityException if a security manager is present and the caller
|
||||
* doesn't have {@code FlightRecorderPermission("registerEvent")}
|
||||
*/
|
||||
public ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annotations) {
|
||||
this(type, name, new ArrayList<>(annotations), false);
|
||||
}
|
||||
|
||||
|
||||
ValueDescriptor(Class<?> type, String name, List<AnnotationElement> annotations, boolean allowArray) {
|
||||
Objects.requireNonNull(annotations);
|
||||
Utils.checkRegisterPermission();
|
||||
if (!allowArray) {
|
||||
if (type.isArray()) {
|
||||
throw new IllegalArgumentException("Array types are not allowed");
|
||||
}
|
||||
}
|
||||
this.name = Objects.requireNonNull(name, "Name of value descriptor can't be null");
|
||||
this.type = Objects.requireNonNull(Utils.getValidType(Objects.requireNonNull(type), Objects.requireNonNull(name)));
|
||||
this.annotationConstruct = new AnnotationConstruct(annotations);
|
||||
this.javaFieldName = name; // Needed for dynamic events
|
||||
this.isArray = type.isArray();
|
||||
// Assume we always want to store String and Thread in constant pool
|
||||
this.constantPool = type == Class.class || type == Thread.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable name that describes the value (for example,
|
||||
* {@code "Maximum Throughput"}).
|
||||
*
|
||||
* @return a human-readable name, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getLabel() {
|
||||
return annotationConstruct.getLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the value (for example, {@code "maxThroughput"}).
|
||||
*
|
||||
* @return the name, not {@code null}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sentence describing the value (for example, {@code "Maximum
|
||||
* throughput in the transaction system. Value is reset after each new
|
||||
* batch."}).
|
||||
*
|
||||
* @return the description, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getDescription() {
|
||||
return annotationConstruct.getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual identifier that specifies how a value represented by
|
||||
* this {@link ValueDescriptor} is interpreted or formatted.
|
||||
* <p>
|
||||
* For example, if the value descriptor's type is {@code float} and the
|
||||
* event value is {@code 0.5f}, a content type of
|
||||
* {@code "jdk.jfr.Percentage"} hints to a client that the value is a
|
||||
* percentage and that it should be rendered as {@code "50%"}.
|
||||
* <p>
|
||||
* The JDK provides the following predefined content types:
|
||||
* <ul>
|
||||
* <li>jdk.jfr.Percentage</li>
|
||||
* <li>jdk.jfr.Timespan</li>
|
||||
* <li>jdk.jfr.Timestamp</li>
|
||||
* <li>jdk.jfr.Frequency</li>
|
||||
* <li>jdk.jfr.Flag</li>
|
||||
* <li>jdk.jfr.MemoryAddress</li>
|
||||
* <li>jdk.jfr.DataAmount</li>
|
||||
* <li>jdk.jfr.NetworkAddress</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* User-defined content types can be created by using the {@link ContentType} class.
|
||||
*
|
||||
* @return the content type, or {@code null} if doesn't exist
|
||||
*
|
||||
* @see ContentType
|
||||
*/
|
||||
public String getContentType() {
|
||||
for (AnnotationElement anno : getAnnotationElements()) {
|
||||
for (AnnotationElement meta : anno.getAnnotationElements()) {
|
||||
if (meta.getTypeName().equals(ContentType.class.getName())) {
|
||||
return anno.getTypeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified class name of the type that is associated with
|
||||
* this value descriptor.
|
||||
*
|
||||
* @return the type name, not {@code null}
|
||||
*
|
||||
* @see ValueDescriptor#getTypeId()
|
||||
*/
|
||||
public String getTypeName() {
|
||||
if (type.isSimpleType()) {
|
||||
return type.getFields().get(0).getTypeName();
|
||||
}
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for the type in the Java virtual Machine (JVM).
|
||||
*
|
||||
* The ID might not be the same between JVM instances.
|
||||
*
|
||||
* @return the type ID, not negative
|
||||
*/
|
||||
public long getTypeId() {
|
||||
return type.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this value descriptor is an array type.
|
||||
*
|
||||
* @return {@code true} if it is an array type, {@code false} otherwise
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return isArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first annotation for the specified type if an annotation
|
||||
* element with the same name is directly present for this value descriptor,
|
||||
* {@code null} otherwise.
|
||||
*
|
||||
* @param <A> the type of the annotation to query for and return if present
|
||||
* @param annotationType the Class object that corresponds to the annotation
|
||||
* type, not {@code null}
|
||||
* @return this element's annotation for the specified annotation type if
|
||||
* directly present, else {@code null}
|
||||
*/
|
||||
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
|
||||
Objects.requireNonNull(annotationType);
|
||||
return annotationConstruct.getAnnotation(annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of annotation elements for this value
|
||||
* descriptor.
|
||||
*
|
||||
* @return a list of annotations, not {@code null}
|
||||
*/
|
||||
public List<AnnotationElement> getAnnotationElements() {
|
||||
return annotationConstruct.getUnmodifiableAnnotationElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of value descriptors if the type is complex,
|
||||
* else an empty list.
|
||||
*
|
||||
* @return a list of value descriptors, not {@code null}
|
||||
*/
|
||||
public List<ValueDescriptor> getFields() {
|
||||
if (type.isSimpleType()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return type.getFields();
|
||||
}
|
||||
|
||||
// package private
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
// package private
|
||||
void setAnnotations(List<AnnotationElement> anno) {
|
||||
annotationConstruct.setAnnotationElements(anno);
|
||||
}
|
||||
|
||||
// package private
|
||||
boolean isConstantPool() {
|
||||
return constantPool;
|
||||
}
|
||||
|
||||
// package private
|
||||
String getJavaFieldName() {
|
||||
return javaFieldName;
|
||||
}
|
||||
|
||||
// package private
|
||||
boolean isUnsigned() {
|
||||
return annotationConstruct.hasUnsigned();
|
||||
}
|
||||
|
||||
}
|
||||
174
jdkSrc/jdk8/jdk/jfr/consumer/ChunkParser.java
Normal file
174
jdkSrc/jdk8/jdk/jfr/consumer/ChunkParser.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.MetadataDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.consumer.ChunkHeader;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Parses a chunk.
|
||||
*
|
||||
*/
|
||||
final class ChunkParser {
|
||||
private static final long CONSTANT_POOL_TYPE_ID = 1;
|
||||
private final RecordingInput input;
|
||||
private final LongMap<Parser> parsers;
|
||||
private final ChunkHeader chunkHeader;
|
||||
private final long absoluteChunkEnd;
|
||||
private final MetadataDescriptor metadata;
|
||||
private final LongMap<Type> typeMap;
|
||||
private final TimeConverter timeConverter;
|
||||
|
||||
public ChunkParser(RecordingInput input) throws IOException {
|
||||
this(new ChunkHeader(input));
|
||||
}
|
||||
|
||||
private ChunkParser(ChunkHeader header) throws IOException {
|
||||
this.input = header.getInput();
|
||||
this.chunkHeader = header;
|
||||
this.metadata = header.readMetadata();
|
||||
this.absoluteChunkEnd = header.getEnd();
|
||||
this.timeConverter = new TimeConverter(chunkHeader, metadata.getGMTOffset());
|
||||
|
||||
ParserFactory factory = new ParserFactory(metadata, timeConverter);
|
||||
LongMap<ConstantMap> constantPools = factory.getConstantPools();
|
||||
parsers = factory.getParsers();
|
||||
typeMap = factory.getTypeMap();
|
||||
|
||||
fillConstantPools(parsers, constantPools);
|
||||
constantPools.forEach(ConstantMap::setIsResolving);
|
||||
constantPools.forEach(ConstantMap::resolve);
|
||||
constantPools.forEach(ConstantMap::setResolved);
|
||||
|
||||
input.position(chunkHeader.getEventStart());
|
||||
}
|
||||
|
||||
public RecordedEvent readEvent() throws IOException {
|
||||
while (input.position() < absoluteChunkEnd) {
|
||||
long pos = input.position();
|
||||
int size = input.readInt();
|
||||
if (size == 0) {
|
||||
throw new IOException("Event can't have zero size");
|
||||
}
|
||||
long typeId = input.readLong();
|
||||
if (typeId > CONSTANT_POOL_TYPE_ID) { // also skips metadata (id=0)
|
||||
Parser ep = parsers.get(typeId);
|
||||
if (ep instanceof EventParser) {
|
||||
return (RecordedEvent) ep.parse(input);
|
||||
}
|
||||
}
|
||||
input.position(pos + size);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fillConstantPools(LongMap<Parser> typeParser, LongMap<ConstantMap> constantPools) throws IOException {
|
||||
long nextCP = chunkHeader.getAbsoluteChunkStart();
|
||||
long deltaToNext = chunkHeader.getConstantPoolPosition();
|
||||
while (deltaToNext != 0) {
|
||||
nextCP += deltaToNext;
|
||||
input.position(nextCP);
|
||||
final long position = nextCP;
|
||||
int size = input.readInt(); // size
|
||||
long typeId = input.readLong();
|
||||
if (typeId != CONSTANT_POOL_TYPE_ID) {
|
||||
throw new IOException("Expected check point event (id = 1) at position " + nextCP + ", but found type id = " + typeId);
|
||||
}
|
||||
input.readLong(); // timestamp
|
||||
input.readLong(); // duration
|
||||
deltaToNext = input.readLong();
|
||||
final long delta = deltaToNext;
|
||||
boolean flush = input.readBoolean();
|
||||
int poolCount = input.readInt();
|
||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> {
|
||||
return "New constant pool: startPosition=" + position + ", size=" + size + ", deltaToNext=" + delta + ", flush=" + flush + ", poolCount=" + poolCount;
|
||||
});
|
||||
|
||||
for (int i = 0; i < poolCount; i++) {
|
||||
long id = input.readLong(); // type id
|
||||
ConstantMap pool = constantPools.get(id);
|
||||
Type type = typeMap.get(id);
|
||||
if (pool == null) {
|
||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Found constant pool(" + id + ") that is never used");
|
||||
if (type == null) {
|
||||
throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]");
|
||||
}
|
||||
pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
|
||||
constantPools.put(type.getId(), pool);
|
||||
}
|
||||
Parser parser = typeParser.get(id);
|
||||
if (parser == null) {
|
||||
throw new IOException("Could not find constant pool type with id = " + id);
|
||||
}
|
||||
try {
|
||||
int count = input.readInt();
|
||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, () -> "Constant: " + getName(id) + "[" + count + "]");
|
||||
for (int j = 0; j < count; j++) {
|
||||
long key = input.readLong();
|
||||
Object value = parser.parse(input);
|
||||
pool.put(key, value);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Error parsing constant pool type " + getName(id) + " at position " + input.position() + " at check point between [" + nextCP + ", " + nextCP + size + "]", e);
|
||||
}
|
||||
}
|
||||
if (input.position() != nextCP + size) {
|
||||
throw new IOException("Size of check point event doesn't match content");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getName(long id) {
|
||||
Type type = typeMap.get(id);
|
||||
return type == null ? ("unknown(" + id + ")") : type.getName();
|
||||
}
|
||||
|
||||
public Collection<Type> getTypes() {
|
||||
return metadata.getTypes();
|
||||
}
|
||||
|
||||
public List<EventType> getEventTypes() {
|
||||
return metadata.getEventTypes();
|
||||
}
|
||||
|
||||
public boolean isLastChunk() {
|
||||
return chunkHeader.isLastChunk();
|
||||
}
|
||||
|
||||
public ChunkParser nextChunkParser() throws IOException {
|
||||
return new ChunkParser(chunkHeader.nextHeader());
|
||||
}
|
||||
}
|
||||
139
jdkSrc/jdk8/jdk/jfr/consumer/ConstantMap.java
Normal file
139
jdkSrc/jdk8/jdk/jfr/consumer/ConstantMap.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds mapping between a set of keys and their corresponding object.
|
||||
*
|
||||
* If the type is a known type, i.e. {@link RecordedThread}, an
|
||||
* {@link ObjectFactory} can be supplied which will instantiate a typed object.
|
||||
*/
|
||||
final class ConstantMap {
|
||||
private final static class Reference {
|
||||
private final long key;
|
||||
private final ConstantMap pool;
|
||||
|
||||
Reference(ConstantMap pool, long key) {
|
||||
this.pool = pool;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
Object resolve() {
|
||||
return pool.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
private final ObjectFactory<?> factory;
|
||||
private final LongMap<Object> objects;
|
||||
|
||||
private LongMap<Boolean> isResolving;
|
||||
private boolean allResolved;
|
||||
private String name;
|
||||
|
||||
ConstantMap(ObjectFactory<?> factory, String name) {
|
||||
this.name = name;
|
||||
this.objects = new LongMap<>();
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
Object get(long id) {
|
||||
// fast path, all objects in pool resolved
|
||||
if (allResolved) {
|
||||
return objects.get(id);
|
||||
}
|
||||
// referenced from a pool, deal with this later
|
||||
if (isResolving == null) {
|
||||
return new Reference(this, id);
|
||||
}
|
||||
|
||||
Boolean beingResolved = isResolving.get(id);
|
||||
|
||||
// we are resolved (but not the whole pool)
|
||||
if (Boolean.FALSE.equals(beingResolved)) {
|
||||
return objects.get(id);
|
||||
}
|
||||
|
||||
// resolving ourself, abort to avoid infinite recursion
|
||||
if (Boolean.TRUE.equals(beingResolved)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// resolve me!
|
||||
isResolving.put(id, Boolean.TRUE);
|
||||
Object resolved = resolve(objects.get(id));
|
||||
isResolving.put(id, Boolean.FALSE);
|
||||
if (factory != null) {
|
||||
Object factorized = factory.createObject(id, resolved);
|
||||
objects.put(id, factorized);
|
||||
return factorized;
|
||||
} else {
|
||||
objects.put(id, resolved);
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object resolve(Object o) {
|
||||
if (o instanceof Reference) {
|
||||
return resolve(((Reference) o).resolve());
|
||||
}
|
||||
if (o != null && o.getClass().isArray()) {
|
||||
final Object[] array = (Object[]) o;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = resolve(array[i]);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public void resolve() {
|
||||
List<Long> keyList = new ArrayList<>();
|
||||
objects.keys().forEachRemaining(keyList::add);
|
||||
for (Long l : keyList) {
|
||||
get(l);
|
||||
}
|
||||
}
|
||||
|
||||
public void put(long key, Object value) {
|
||||
objects.put(key, value);
|
||||
}
|
||||
|
||||
public void setIsResolving() {
|
||||
isResolving = new LongMap<>();
|
||||
}
|
||||
|
||||
public void setResolved() {
|
||||
allResolved = true;
|
||||
isResolving = null; // pool finished, release memory
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
72
jdkSrc/jdk8/jdk/jfr/consumer/EventParser.java
Normal file
72
jdkSrc/jdk8/jdk/jfr/consumer/EventParser.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import static jdk.jfr.internal.EventInstrumentation.FIELD_DURATION;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Parses an event and returns a {@link RecordedEvent}.
|
||||
*
|
||||
*/
|
||||
final class EventParser extends Parser {
|
||||
private final Parser[] parsers;
|
||||
private final EventType eventType;
|
||||
private final TimeConverter timeConverter;
|
||||
private final boolean hasDuration;
|
||||
private final List<ValueDescriptor> valueDescriptors;
|
||||
|
||||
EventParser(TimeConverter timeConverter, EventType type, Parser[] parsers) {
|
||||
this.timeConverter = timeConverter;
|
||||
this.parsers = parsers;
|
||||
this.eventType = type;
|
||||
this.hasDuration = type.getField(FIELD_DURATION) != null;
|
||||
this.valueDescriptors = type.getFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
Object[] values = new Object[parsers.length];
|
||||
for (int i = 0; i < parsers.length; i++) {
|
||||
values[i] = parsers[i].parse(input);
|
||||
}
|
||||
Long startTicks = (Long) values[0];
|
||||
long startTime = timeConverter.convertTimestamp(startTicks);
|
||||
if (hasDuration) {
|
||||
long durationTicks = (Long) values[1];
|
||||
long endTime = timeConverter.convertTimestamp(startTicks + durationTicks);
|
||||
return new RecordedEvent(eventType, valueDescriptors, values, startTime, endTime, timeConverter);
|
||||
} else {
|
||||
return new RecordedEvent(eventType, valueDescriptors, values, startTime, startTime, timeConverter);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/jdk/jfr/consumer/LongMap.java
Normal file
61
jdkSrc/jdk8/jdk/jfr/consumer/LongMap.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Commonly used data structure for looking up objects given an id (long value)
|
||||
*
|
||||
* TODO: Implement without using Map and Long objects, to minimize allocation
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
final class LongMap<T> implements Iterable<T> {
|
||||
private final HashMap<Long, T> map;
|
||||
|
||||
LongMap() {
|
||||
map = new HashMap<>(101);
|
||||
}
|
||||
|
||||
void put(long id, T object) {
|
||||
map.put(id, object);
|
||||
}
|
||||
|
||||
T get(long id) {
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return map.values().iterator();
|
||||
}
|
||||
|
||||
Iterator<Long> keys() {
|
||||
return map.keySet().iterator();
|
||||
}
|
||||
}
|
||||
85
jdkSrc/jdk8/jdk/jfr/consumer/ObjectFactory.java
Normal file
85
jdkSrc/jdk8/jdk/jfr/consumer/ObjectFactory.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* Abstract factory for creating specialized types
|
||||
*/
|
||||
abstract class ObjectFactory<T> {
|
||||
|
||||
final static String TYPE_PREFIX_VERSION_1 = "com.oracle.jfr.types.";
|
||||
final static String TYPE_PREFIX_VERSION_2 = Type.TYPES_PREFIX;
|
||||
final static String STACK_FRAME_VERSION_1 = TYPE_PREFIX_VERSION_1 + "StackFrame";
|
||||
final static String STACK_FRAME_VERSION_2 = TYPE_PREFIX_VERSION_2 + "StackFrame";
|
||||
|
||||
public static ObjectFactory<?> create(Type type, TimeConverter timeConverter) {
|
||||
switch (type.getName()) {
|
||||
case "java.lang.Thread":
|
||||
return RecordedThread.createFactory(type, timeConverter);
|
||||
case TYPE_PREFIX_VERSION_1 + "StackFrame":
|
||||
case TYPE_PREFIX_VERSION_2 + "StackFrame":
|
||||
return RecordedFrame.createFactory(type, timeConverter);
|
||||
case TYPE_PREFIX_VERSION_1 + "Method":
|
||||
case TYPE_PREFIX_VERSION_2 + "Method":
|
||||
return RecordedMethod.createFactory(type, timeConverter);
|
||||
case TYPE_PREFIX_VERSION_1 + "ThreadGroup":
|
||||
case TYPE_PREFIX_VERSION_2 + "ThreadGroup":
|
||||
return RecordedThreadGroup.createFactory(type, timeConverter);
|
||||
case TYPE_PREFIX_VERSION_1 + "StackTrace":
|
||||
case TYPE_PREFIX_VERSION_2 + "StackTrace":
|
||||
return RecordedStackTrace.createFactory(type, timeConverter);
|
||||
case TYPE_PREFIX_VERSION_1 + "ClassLoader":
|
||||
case TYPE_PREFIX_VERSION_2 + "ClassLoader":
|
||||
return RecordedClassLoader.createFactory(type, timeConverter);
|
||||
case "java.lang.Class":
|
||||
return RecordedClass.createFactory(type, timeConverter);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final List<ValueDescriptor> valueDescriptors;
|
||||
|
||||
ObjectFactory(Type type) {
|
||||
this.valueDescriptors = type.getFields();
|
||||
}
|
||||
|
||||
T createObject(long id, Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Object[]) {
|
||||
return createTyped(valueDescriptors, id, (Object[]) value);
|
||||
}
|
||||
throw new InternalError("Object factory must have struct type");
|
||||
}
|
||||
|
||||
abstract T createTyped(List<ValueDescriptor> valueDescriptors, long id, Object[] values);
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/consumer/Parser.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/consumer/Parser.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Base class for parsing data from a {@link RecordingInput}.
|
||||
*/
|
||||
abstract class Parser {
|
||||
/**
|
||||
* Parses data from a {@link RecordingInput} and return an object.
|
||||
*
|
||||
* @param input input to read from
|
||||
* @return an object
|
||||
* @throws IOException if operation couldn't be completed due to I/O
|
||||
* problems
|
||||
*/
|
||||
abstract Object parse(RecordingInput input) throws IOException;
|
||||
}
|
||||
304
jdkSrc/jdk8/jdk/jfr/consumer/ParserFactory.java
Normal file
304
jdkSrc/jdk8/jdk/jfr/consumer/ParserFactory.java
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2021, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.MetadataDescriptor;
|
||||
import jdk.jfr.internal.PrivateAccess;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Class that create parsers suitable for reading events and constant pools
|
||||
*/
|
||||
final class ParserFactory {
|
||||
private final LongMap<Parser> parsers = new LongMap<>();
|
||||
private final TimeConverter timeConverter;
|
||||
private final LongMap<Type> types = new LongMap<>();
|
||||
private final LongMap<ConstantMap> constantPools;
|
||||
|
||||
public ParserFactory(MetadataDescriptor metadata, TimeConverter timeConverter) throws IOException {
|
||||
this.constantPools = new LongMap<>();
|
||||
this.timeConverter = timeConverter;
|
||||
for (Type t : metadata.getTypes()) {
|
||||
types.put(t.getId(), t);
|
||||
}
|
||||
for (Type t : types) {
|
||||
if (!t.getFields().isEmpty()) { // Avoid primitives
|
||||
CompositeParser cp = createCompositeParser(t);
|
||||
if (t.isSimpleType()) { // Reduce to nested parser
|
||||
parsers.put(t.getId(), cp.parsers[0]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Override event types with event parsers
|
||||
for (EventType t : metadata.getEventTypes()) {
|
||||
parsers.put(t.getId(), createEventParser(t));
|
||||
}
|
||||
}
|
||||
|
||||
public LongMap<Parser> getParsers() {
|
||||
return parsers;
|
||||
}
|
||||
|
||||
public LongMap<ConstantMap> getConstantPools() {
|
||||
return constantPools;
|
||||
}
|
||||
|
||||
public LongMap<Type> getTypeMap() {
|
||||
return types;
|
||||
}
|
||||
|
||||
private EventParser createEventParser(EventType eventType) throws IOException {
|
||||
List<Parser> parsers = new ArrayList<Parser>();
|
||||
for (ValueDescriptor f : eventType.getFields()) {
|
||||
parsers.add(createParser(f));
|
||||
}
|
||||
return new EventParser(timeConverter, eventType, parsers.toArray(new Parser[0]));
|
||||
}
|
||||
|
||||
private Parser createParser(ValueDescriptor v) throws IOException {
|
||||
boolean constantPool = PrivateAccess.getInstance().isConstantPool(v);
|
||||
if (v.isArray()) {
|
||||
Type valueType = PrivateAccess.getInstance().getType(v);
|
||||
ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null);
|
||||
return new ArrayParser(createParser(element));
|
||||
}
|
||||
long id = v.getTypeId();
|
||||
Type type = types.get(id);
|
||||
if (type == null) {
|
||||
throw new IOException("Type '" + v.getTypeName() + "' is not defined");
|
||||
}
|
||||
if (constantPool) {
|
||||
ConstantMap pool = constantPools.get(id);
|
||||
if (pool == null) {
|
||||
pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
|
||||
constantPools.put(id, pool);
|
||||
}
|
||||
return new ConstantMapValueParser(pool);
|
||||
}
|
||||
Parser parser = parsers.get(id);
|
||||
if (parser == null) {
|
||||
if (!v.getFields().isEmpty()) {
|
||||
return createCompositeParser(type);
|
||||
} else {
|
||||
return registerParserType(type, createPrimitiveParser(type));
|
||||
}
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
private Parser createPrimitiveParser(Type type) throws IOException {
|
||||
switch (type.getName()) {
|
||||
case "int":
|
||||
return new IntegerParser();
|
||||
case "long":
|
||||
return new LongParser();
|
||||
case "float":
|
||||
return new FloatParser();
|
||||
case "double":
|
||||
return new DoubleParser();
|
||||
case "char":
|
||||
return new CharacterParser();
|
||||
case "boolean":
|
||||
return new BooleanParser();
|
||||
case "short":
|
||||
return new ShortParser();
|
||||
case "byte":
|
||||
return new ByteParser();
|
||||
case "java.lang.String":
|
||||
ConstantMap pool = new ConstantMap(ObjectFactory.create(type, timeConverter), type.getName());
|
||||
constantPools.put(type.getId(), pool);
|
||||
return new StringParser(pool);
|
||||
default:
|
||||
throw new IOException("Unknown primitive type " + type.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private Parser registerParserType(Type t, Parser parser) {
|
||||
Parser p = parsers.get(t.getId());
|
||||
// check if parser exists (known type)
|
||||
if (p != null) {
|
||||
return p;
|
||||
}
|
||||
parsers.put(t.getId(), parser);
|
||||
return parser;
|
||||
}
|
||||
|
||||
private CompositeParser createCompositeParser(Type type) throws IOException {
|
||||
List<ValueDescriptor> vds = type.getFields();
|
||||
Parser[] parsers = new Parser[vds.size()];
|
||||
CompositeParser composite = new CompositeParser(parsers);
|
||||
// need to pre-register so recursive types can be handled
|
||||
registerParserType(type, composite);
|
||||
|
||||
int index = 0;
|
||||
for (ValueDescriptor vd : vds) {
|
||||
parsers[index++] = createParser(vd);
|
||||
}
|
||||
return composite;
|
||||
}
|
||||
|
||||
private static final class BooleanParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ByteParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Byte.valueOf(input.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LongParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Long.valueOf(input.readLong());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IntegerParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Integer.valueOf(input.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ShortParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Short.valueOf(input.readShort());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CharacterParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Character.valueOf(input.readChar());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FloatParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Float.valueOf(input.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DoubleParser extends Parser {
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return Double.valueOf(input.readDouble());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class StringParser extends Parser {
|
||||
private final ConstantMap stringConstantMap;
|
||||
private String last;
|
||||
|
||||
StringParser(ConstantMap stringConstantMap) {
|
||||
this.stringConstantMap = stringConstantMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
String s = parseEncodedString(input);
|
||||
if (!Objects.equals(s, last)) {
|
||||
last = s;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
|
||||
private String parseEncodedString(RecordingInput input) throws IOException {
|
||||
byte encoding = input.readByte();
|
||||
if (encoding == RecordingInput.STRING_ENCODING_CONSTANT_POOL) {
|
||||
long id = input.readLong();
|
||||
return (String) stringConstantMap.get(id);
|
||||
} else {
|
||||
return input.readEncodedString(encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ArrayParser extends Parser {
|
||||
private final Parser elementParser;
|
||||
|
||||
public ArrayParser(Parser elementParser) {
|
||||
this.elementParser = elementParser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
final int size = input.readInt();
|
||||
input.require(size, "Array size %d exceeds available data" );
|
||||
final Object[] array = new Object[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
array[i] = elementParser.parse(input);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
private final static class CompositeParser extends Parser {
|
||||
private final Parser[] parsers;
|
||||
|
||||
public CompositeParser(Parser[] valueParsers) {
|
||||
this.parsers = valueParsers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
final Object[] values = new Object[parsers.length];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = parsers[i].parse(input);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ConstantMapValueParser extends Parser {
|
||||
private final ConstantMap pool;
|
||||
|
||||
ConstantMapValueParser(ConstantMap pool) {
|
||||
this.pool = pool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(RecordingInput input) throws IOException {
|
||||
return pool.get(input.readLong());
|
||||
}
|
||||
}
|
||||
}
|
||||
103
jdkSrc/jdk8/jdk/jfr/consumer/RecordedClass.java
Normal file
103
jdkSrc/jdk8/jdk/jfr/consumer/RecordedClass.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded Java type, such as a class or an interface.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedClass extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedClass> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedClass>(type) {
|
||||
@Override
|
||||
RecordedClass createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedClass(desc, id, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final long uniqueId;
|
||||
|
||||
// package private
|
||||
private RecordedClass(List<ValueDescriptor> descriptors, long id, Object[] values, TimeConverter timeConverter) {
|
||||
super(descriptors, values, timeConverter);
|
||||
this.uniqueId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modifiers of the class.
|
||||
* <p>
|
||||
* See {@link java.lang.reflect.Modifier}
|
||||
*
|
||||
* @return the modifiers
|
||||
*
|
||||
* @see Modifier
|
||||
*/
|
||||
public int getModifiers() {
|
||||
return getTyped("modifiers", Integer.class, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class loader that defined the class.
|
||||
* <P>
|
||||
* If the bootstrap class loader is represented as {@code null} in the Java
|
||||
* Virtual Machine (JVM), then {@code null} is also the return value of this method.
|
||||
*
|
||||
* @return the class loader defining this class, can be {@code null}
|
||||
*/
|
||||
public RecordedClassLoader getClassLoader() {
|
||||
return getTyped("classLoader", RecordedClassLoader.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fully qualified name of the class (for example,
|
||||
* {@code "java.lang.String"}).
|
||||
*
|
||||
* @return the class name, not {@code null}
|
||||
*/
|
||||
public String getName() {
|
||||
return getTyped("name", String.class, null).replace("/", ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for the class.
|
||||
* <p>
|
||||
* The ID might not be the same between Java Virtual Machine (JVM) instances.
|
||||
*
|
||||
* @return a unique ID
|
||||
*/
|
||||
public long getId() {
|
||||
return uniqueId;
|
||||
}
|
||||
}
|
||||
90
jdkSrc/jdk8/jdk/jfr/consumer/RecordedClassLoader.java
Normal file
90
jdkSrc/jdk8/jdk/jfr/consumer/RecordedClassLoader.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded Java class loader.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedClassLoader extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedClassLoader> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedClassLoader>(type) {
|
||||
@Override
|
||||
RecordedClassLoader createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedClassLoader(desc, id, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final long uniqueId;
|
||||
|
||||
// package private
|
||||
private RecordedClassLoader(List<ValueDescriptor> descriptors, long id, Object[] values, TimeConverter timeConverter) {
|
||||
super(descriptors, values, timeConverter);
|
||||
this.uniqueId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the class loader.
|
||||
* <P>
|
||||
* If the bootstrap class loader is represented as {@code null} in the Java
|
||||
* Virtual Machine (JVM), then {@code null} is also the return value of this
|
||||
* method.
|
||||
*
|
||||
* @return class of the class loader, can be {@code null}
|
||||
*/
|
||||
public RecordedClass getType() {
|
||||
return getTyped("type", RecordedClass.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the class loader (for example, "boot", "platform", and
|
||||
* "app").
|
||||
*
|
||||
* @return the class loader name, can be {@code null}
|
||||
*/
|
||||
public String getName() {
|
||||
return getTyped("name", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for the class loader.
|
||||
* <p>
|
||||
* The ID might not be the same between Java Virtual Machine (JVM) instances.
|
||||
*
|
||||
* @return a unique ID
|
||||
*/
|
||||
public long getId() {
|
||||
return uniqueId;
|
||||
}
|
||||
}
|
||||
124
jdkSrc/jdk8/jdk/jfr/consumer/RecordedEvent.java
Normal file
124
jdkSrc/jdk8/jdk/jfr/consumer/RecordedEvent.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.EventInstrumentation;
|
||||
|
||||
/**
|
||||
* A recorded event.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedEvent extends RecordedObject {
|
||||
private final EventType eventType;
|
||||
private final long startTime;
|
||||
// package private needed for efficient sorting
|
||||
final long endTime;
|
||||
|
||||
// package private
|
||||
RecordedEvent(EventType type, List<ValueDescriptor> vds, Object[] values, long startTime, long endTime, TimeConverter timeConverter) {
|
||||
super(vds, values, timeConverter);
|
||||
this.eventType = type;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stack trace that was created when the event was committed, or
|
||||
* {@code null} if the event lacks a stack trace.
|
||||
*
|
||||
* @return stack trace, or {@code null} if doesn't exist for the event
|
||||
*/
|
||||
public RecordedStackTrace getStackTrace() {
|
||||
return getTyped(EventInstrumentation.FIELD_STACK_TRACE, RecordedStackTrace.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thread from which the event was committed, or {@code null} if
|
||||
* the thread was not recorded.
|
||||
*
|
||||
* @return thread, or {@code null} if doesn't exist for the event
|
||||
*/
|
||||
public RecordedThread getThread() {
|
||||
return getTyped(EventInstrumentation.FIELD_EVENT_THREAD, RecordedThread.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event type that describes the event.
|
||||
*
|
||||
* @return the event type, not {@code null}
|
||||
*/
|
||||
public EventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start time of the event.
|
||||
* <p>
|
||||
* If the event is an instant event, then the start time and end time are the same.
|
||||
*
|
||||
* @return the start time, not {@code null}
|
||||
*/
|
||||
public Instant getStartTime() {
|
||||
return Instant.ofEpochSecond(0, startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end time of the event.
|
||||
* <p>
|
||||
* If the event is an instant event, then the start time and end time are the same.
|
||||
*
|
||||
* @return the end time, not {@code null}
|
||||
*/
|
||||
public Instant getEndTime() {
|
||||
return Instant.ofEpochSecond(0, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of the event, measured in nanoseconds.
|
||||
*
|
||||
* @return the duration in nanoseconds, not {@code null}
|
||||
*/
|
||||
public Duration getDuration() {
|
||||
return Duration.ofNanos(endTime - startTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of descriptors that describes the fields of the event.
|
||||
*
|
||||
* @return descriptors, not {@code null}
|
||||
*/
|
||||
@Override
|
||||
public List<ValueDescriptor> getFields() {
|
||||
return getEventType().getFields();
|
||||
}
|
||||
}
|
||||
113
jdkSrc/jdk8/jdk/jfr/consumer/RecordedFrame.java
Normal file
113
jdkSrc/jdk8/jdk/jfr/consumer/RecordedFrame.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded frame in a stack trace.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedFrame extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedFrame> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedFrame>(type) {
|
||||
@Override
|
||||
RecordedFrame createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedFrame(desc, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// package private
|
||||
RecordedFrame(List<ValueDescriptor> desc, Object[] objects, TimeConverter timeConverter) {
|
||||
super(desc, objects, timeConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a Java frame, {@code false} otherwise.
|
||||
* <p>
|
||||
* A Java method that has a native modifier is considered a Java frame.
|
||||
*
|
||||
* @return {@code true} if this is a Java frame, {@code false} otherwise
|
||||
*
|
||||
* @see Modifier#isNative(int)
|
||||
*/
|
||||
public boolean isJavaFrame() {
|
||||
// Only Java frames exist today, but this allows
|
||||
// API to be extended for native frame in the future.
|
||||
if (hasField("javaFrame")) {
|
||||
return getTyped("javaFrame", Boolean.class, Boolean.TRUE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytecode index for the execution point that is represented by
|
||||
* this recorded frame.
|
||||
*
|
||||
* @return byte code index, or {@code -1} if doesn't exist
|
||||
*/
|
||||
public int getBytecodeIndex() {
|
||||
return getTyped("bytecodeIndex", Integer.class, Integer.valueOf(-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line number for the execution point that is represented by this
|
||||
* recorded frame, or {@code -1} if doesn't exist
|
||||
*
|
||||
* @return the line number, or {@code -1} if doesn't exist
|
||||
*/
|
||||
public int getLineNumber() {
|
||||
return getTyped("lineNumber", Integer.class, Integer.valueOf(-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frame type for the execution point that is represented by this
|
||||
* recorded frame (for example, {@code "Interpreted"}, {@code "JIT compiled"} or
|
||||
* {@code "Inlined"}).
|
||||
*
|
||||
* @return the frame type, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getType() {
|
||||
return getTyped("type", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method for the execution point that is represented by this
|
||||
* recorded frame.
|
||||
*
|
||||
* @return the method, not {@code null}
|
||||
*/
|
||||
public RecordedMethod getMethod() {
|
||||
return getTyped("method", RecordedMethod.class, null);
|
||||
}
|
||||
}
|
||||
120
jdkSrc/jdk8/jdk/jfr/consumer/RecordedMethod.java
Normal file
120
jdkSrc/jdk8/jdk/jfr/consumer/RecordedMethod.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded method.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedMethod extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedMethod> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedMethod>(type) {
|
||||
@Override
|
||||
RecordedMethod createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedMethod(desc, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RecordedMethod(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
|
||||
super(descriptors, objects, timeConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class this method belongs to, if it belong to a Java frame.
|
||||
* <p>
|
||||
* To ensure this is a Java frame, use the {@link RecordedFrame#isJavaFrame()}
|
||||
* method.
|
||||
*
|
||||
* @return the class, may be {@code null} if not a Java frame
|
||||
*
|
||||
* @see RecordedFrame#isJavaFrame()
|
||||
*/
|
||||
public RecordedClass getType() {
|
||||
return getTyped("type", RecordedClass.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this method, for example {@code "toString"}.
|
||||
* <p>
|
||||
* If this method doesn't belong to a Java frame the result is undefined.
|
||||
*
|
||||
* @return method name, or {@code null} if doesn't exist
|
||||
*
|
||||
* @see RecordedFrame#isJavaFrame()
|
||||
*/
|
||||
public String getName() {
|
||||
return getTyped("name", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method descriptor for this method (for example,
|
||||
* {@code "(Ljava/lang/String;)V"}).
|
||||
* <p>
|
||||
* See Java Virtual Machine Specification, 4.3
|
||||
* <p>
|
||||
* If this method doesn't belong to a Java frame then the the result is undefined.
|
||||
*
|
||||
* @return method descriptor.
|
||||
*
|
||||
* @see RecordedFrame#isJavaFrame()
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return getTyped("descriptor", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modifiers for this method.
|
||||
* <p>
|
||||
* If this method doesn't belong to a Java frame, then the result is undefined.
|
||||
*
|
||||
* @return the modifiers
|
||||
*
|
||||
* @see Modifier
|
||||
* @see RecordedFrame#isJavaFrame
|
||||
*/
|
||||
public int getModifiers() {
|
||||
return getTyped("modifiers", Integer.class, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this method is hidden (for example, wrapper code in a lambda
|
||||
* expressions).
|
||||
*
|
||||
* @return {@code true} if method is hidden, {@code false} otherwise
|
||||
*/
|
||||
public boolean isHidden() {
|
||||
return getTyped("hidden", Boolean.class, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
903
jdkSrc/jdk8/jdk/jfr/consumer/RecordedObject.java
Normal file
903
jdkSrc/jdk8/jdk/jfr/consumer/RecordedObject.java
Normal file
@@ -0,0 +1,903 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.Timestamp;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.PrivateAccess;
|
||||
import jdk.jfr.internal.tool.PrettyWriter;
|
||||
|
||||
/**
|
||||
* A complex data type that consists of one or more fields.
|
||||
* <p>
|
||||
* This class provides methods to select and query nested objects by passing a
|
||||
* dot {@code "."} delimited {@code String} object (for instance,
|
||||
* {@code "aaa.bbb"}). A method evaluates a nested object from left to right,
|
||||
* and if a part is {@code null}, it throws {@code NullPointerException}.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public class RecordedObject {
|
||||
|
||||
private final static class UnsignedValue {
|
||||
private final Object o;
|
||||
|
||||
UnsignedValue(Object o) {
|
||||
this.o = o;
|
||||
}
|
||||
|
||||
Object value() {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
private final Object[] objects;
|
||||
private final List<ValueDescriptor> descriptors;
|
||||
private final TimeConverter timeConverter;
|
||||
|
||||
// package private, not to be subclassed outside this package
|
||||
RecordedObject(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
|
||||
this.descriptors = descriptors;
|
||||
this.objects = objects;
|
||||
this.timeConverter = timeConverter;
|
||||
}
|
||||
|
||||
// package private
|
||||
final <T> T getTyped(String name, Class<T> clazz, T defaultValue) {
|
||||
// Unnecessary to check field presence twice, but this
|
||||
// will do for now.
|
||||
if (!hasField(name)) {
|
||||
return defaultValue;
|
||||
}
|
||||
T object = getValue(name);
|
||||
if (object == null || object.getClass().isAssignableFrom(clazz)) {
|
||||
return object;
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a field with the given name exists, {@code false}
|
||||
* otherwise.
|
||||
*
|
||||
* @param name name of the field to get, not {@code null}
|
||||
*
|
||||
* @return {@code true} if the field exists, {@code false} otherwise.
|
||||
*
|
||||
* @see #getFields()
|
||||
*/
|
||||
public boolean hasField(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (v.getName().equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
int dotIndex = name.indexOf(".");
|
||||
if (dotIndex > 0) {
|
||||
String structName = name.substring(0, dotIndex);
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
|
||||
RecordedObject child = getValue(structName);
|
||||
if (child != null) {
|
||||
return child.hasField(name.substring(dotIndex + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the field with the given name.
|
||||
* <p>
|
||||
* The return type may be a primitive type or a subclass of
|
||||
* {@link RecordedObject}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object by using {@code "."} (for
|
||||
* instance {@code "thread.group.parent.name}").
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
* <p>
|
||||
* Example
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* if (event.hasField("intValue")) {
|
||||
* int intValue = event.getValue("intValue");
|
||||
* System.out.println("Int value: " + intValue);
|
||||
* }
|
||||
*
|
||||
* if (event.hasField("objectClass")) {
|
||||
* RecordedClass clazz = event.getValue("objectClass");
|
||||
* System.out.println("Class name: " + clazz.getName());
|
||||
* }
|
||||
*
|
||||
* if (event.hasField("sampledThread")) {
|
||||
* RecordedThread sampledThread = event.getValue("sampledThread");
|
||||
* System.out.println("Sampled thread: " + sampledThread.getName());
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the return type
|
||||
* @param name of the field to get, not {@code null}
|
||||
* @throws IllegalArgumentException if no field called {@code name} exists
|
||||
*
|
||||
* @return the value, can be {@code null}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
*
|
||||
*/
|
||||
final public <T> T getValue(String name) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T t = (T) getValue(name, false);
|
||||
return t;
|
||||
}
|
||||
|
||||
private Object getValue(String name, boolean allowUnsigned) {
|
||||
Objects.requireNonNull(name);
|
||||
int index = 0;
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (name.equals(v.getName())) {
|
||||
Object object = objects[index];
|
||||
if (object == null) {
|
||||
// error or missing
|
||||
return null;
|
||||
}
|
||||
if (v.getFields().isEmpty()) {
|
||||
if (allowUnsigned && PrivateAccess.getInstance().isUnsigned(v)) {
|
||||
// Types that are meaningless to widen
|
||||
if (object instanceof Character || object instanceof Long) {
|
||||
return object;
|
||||
}
|
||||
return new UnsignedValue(object);
|
||||
}
|
||||
return object; // primitives and primitive arrays
|
||||
} else {
|
||||
if (object instanceof RecordedObject) {
|
||||
// known types from factory
|
||||
return object;
|
||||
}
|
||||
// must be array type
|
||||
Object[] array = (Object[]) object;
|
||||
if (v.isArray()) {
|
||||
// struct array
|
||||
return structifyArray(v, array, 0);
|
||||
}
|
||||
// struct
|
||||
return new RecordedObject(v.getFields(), (Object[]) object, timeConverter);
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
int dotIndex = name.indexOf(".");
|
||||
if (dotIndex > 0) {
|
||||
String structName = name.substring(0, dotIndex);
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (!v.getFields().isEmpty() && v.getName().equals(structName)) {
|
||||
RecordedObject child = getValue(structName);
|
||||
String subName = name.substring(dotIndex + 1);
|
||||
if (child != null) {
|
||||
return child.getValue(subName, allowUnsigned);
|
||||
} else {
|
||||
// Call getValueDescriptor to trigger IllegalArgumentException if the name is
|
||||
// incorrect. Type can't be validate due to type erasure
|
||||
getValueDescriptor(v.getFields(), subName, null);
|
||||
throw new NullPointerException("Field value for \"" + structName + "\" was null. Can't access nested field \"" + subName + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Could not find field with name " + name);
|
||||
}
|
||||
|
||||
// Returns the leaf value descriptor matches both name or value, or throws an
|
||||
// IllegalArgumentException
|
||||
private ValueDescriptor getValueDescriptor(List<ValueDescriptor> descriptors, String name, String leafType) {
|
||||
int dotIndex = name.indexOf(".");
|
||||
if (dotIndex > 0) {
|
||||
String first = name.substring(0, dotIndex);
|
||||
String second = name.substring(dotIndex + 1);
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (v.getName().equals(first)) {
|
||||
List<ValueDescriptor> fields = v.getFields();
|
||||
if (!fields.isEmpty()) {
|
||||
return getValueDescriptor(v.getFields(), second, leafType);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Attempt to get unknown field \"" + first + "\"");
|
||||
}
|
||||
for (ValueDescriptor v : descriptors) {
|
||||
if (v.getName().equals(name)) {
|
||||
if (leafType != null && !v.getTypeName().equals(leafType)) {
|
||||
throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal data type conversion " + leafType);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("\"Attempt to get unknown field \"" + name + "\"");
|
||||
}
|
||||
|
||||
// Gets a value, but checks that type and name is correct first
|
||||
// This is to prevent a call to getString on a thread field, that is
|
||||
// null to succeed.
|
||||
private <T> T getTypedValue(String name, String typeName) {
|
||||
Objects.requireNonNull(name);
|
||||
// Validate name and type first
|
||||
getValueDescriptor(descriptors, name, typeName);
|
||||
return getValue(name);
|
||||
}
|
||||
|
||||
private Object[] structifyArray(ValueDescriptor v, Object[] array, int dimension) {
|
||||
if (array == null) {
|
||||
return null;
|
||||
}
|
||||
Object[] structArray = new Object[array.length];
|
||||
for (int i = 0; i < structArray.length; i++) {
|
||||
Object arrayElement = array[i];
|
||||
if (dimension == 0) {
|
||||
// No general way to handle structarrays
|
||||
// without invoking ObjectFactory for every instance (which may require id)
|
||||
if (isStackFrameType(v.getTypeName())) {
|
||||
structArray[i] = new RecordedFrame(v.getFields(), (Object[]) arrayElement, timeConverter);
|
||||
} else {
|
||||
structArray[i] = new RecordedObject(v.getFields(), (Object[]) arrayElement, timeConverter);
|
||||
}
|
||||
} else {
|
||||
structArray[i] = structifyArray(v, (Object[]) arrayElement, dimension - 1);
|
||||
}
|
||||
}
|
||||
return structArray;
|
||||
}
|
||||
|
||||
private boolean isStackFrameType(String typeName) {
|
||||
if (ObjectFactory.STACK_FRAME_VERSION_1.equals(typeName)) {
|
||||
return true;
|
||||
}
|
||||
if (ObjectFactory.STACK_FRAME_VERSION_2.equals(typeName)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list of the fields for this object.
|
||||
*
|
||||
* @return the fields, not {@code null}
|
||||
*/
|
||||
public List<ValueDescriptor> getFields() {
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code boolean}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field, {@code true} or {@code false}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field is
|
||||
* not of type {@code boolean}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @see #getValue(String)
|
||||
*/
|
||||
public final boolean getBoolean(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Boolean) {
|
||||
return ((Boolean) o).booleanValue();
|
||||
}
|
||||
throw newIllegalArgumentException(name, "boolean");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code byte}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "foo.bar"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field is
|
||||
* not of type {@code byte}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @see #getValue(String)
|
||||
*/
|
||||
public final byte getByte(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).byteValue();
|
||||
}
|
||||
throw newIllegalArgumentException(name, "byte");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code char}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field as a {@code char}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field is
|
||||
* not of type {@code char}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @see #getValue(String)
|
||||
*/
|
||||
public final char getChar(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Character) {
|
||||
return ((Character) o).charValue();
|
||||
}
|
||||
|
||||
throw newIllegalArgumentException(name, "char");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code short} or of another primitive
|
||||
* type convertible to type {@code short} by a widening conversion.
|
||||
* <p>
|
||||
* This method can be used on the following types: {@code short} and {@code byte}.
|
||||
* <p>
|
||||
* If the field has the {@code @Unsigned} annotation and is of a narrower type
|
||||
* than {@code short}, then the value is returned as an unsigned.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field converted to type {@code short}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to the type {@code short} by a widening
|
||||
* conversion
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final short getShort(String name) {
|
||||
Object o = getValue(name, true);
|
||||
if (o instanceof Short) {
|
||||
return ((Short) o).shortValue();
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).byteValue();
|
||||
}
|
||||
if (o instanceof UnsignedValue) {
|
||||
Object u = ((UnsignedValue) o).value();
|
||||
if (u instanceof Short) {
|
||||
return ((Short) u).shortValue();
|
||||
}
|
||||
if (u instanceof Byte) {
|
||||
return (short) Byte.toUnsignedInt(((Byte) u));
|
||||
}
|
||||
}
|
||||
throw newIllegalArgumentException(name, "short");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code int} or of another primitive type
|
||||
* that is convertible to type {@code int} by a widening conversion.
|
||||
* <p>
|
||||
* This method can be used on fields of the following types: {@code int},
|
||||
* {@code short}, {@code char}, and {@code byte}.
|
||||
* <p>
|
||||
* If the field has the {@code @Unsigned} annotation and is of a narrower type
|
||||
* than {@code int}, then the value will be returned as an unsigned.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field converted to type {@code int}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to the type {@code int} by a widening
|
||||
* conversion
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final int getInt(String name) {
|
||||
Object o = getValue(name, true);
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).intValue();
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return ((Short) o).intValue();
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return ((Character) o).charValue();
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).intValue();
|
||||
}
|
||||
if (o instanceof UnsignedValue) {
|
||||
Object u = ((UnsignedValue) o).value();
|
||||
if (u instanceof Integer) {
|
||||
return ((Integer) u).intValue();
|
||||
}
|
||||
if (u instanceof Short) {
|
||||
return Short.toUnsignedInt(((Short) u));
|
||||
}
|
||||
if (u instanceof Byte) {
|
||||
return Byte.toUnsignedInt(((Byte) u));
|
||||
}
|
||||
}
|
||||
throw newIllegalArgumentException(name, "int");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code float} or of another primitive
|
||||
* type convertible to type {@code float} by a widening conversion.
|
||||
* <p>
|
||||
* This method can be used on fields of the following types: {@code float},
|
||||
* {@code long}, {@code int}, {@code short}, {@code char}, and {@code byte}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field converted to type {@code float}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to the type {@code float} by a widening
|
||||
* conversion
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final float getFloat(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Float) {
|
||||
return ((Float) o).floatValue();
|
||||
}
|
||||
if (o instanceof Long) {
|
||||
return ((Long) o).floatValue();
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).floatValue();
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return ((Short) o).floatValue();
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).byteValue();
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return ((Character) o).charValue();
|
||||
}
|
||||
throw newIllegalArgumentException(name, "float");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code long} or of another primitive
|
||||
* type that is convertible to type {@code long} by a widening conversion.
|
||||
* <p>
|
||||
* This method can be used on fields of the following types: {@code long},
|
||||
* {@code int}, {@code short}, {@code char}, and {@code byte}.
|
||||
* <p>
|
||||
* If the field has the {@code @Unsigned} annotation and is of a narrower type
|
||||
* than {@code long}, then the value will be returned as an unsigned.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field converted to type {@code long}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to the type {@code long} via a widening
|
||||
* conversion
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final long getLong(String name) {
|
||||
Object o = getValue(name, true);
|
||||
if (o instanceof Long) {
|
||||
return ((Long) o).longValue();
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).longValue();
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return ((Short) o).longValue();
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return ((Character) o).charValue();
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).longValue();
|
||||
}
|
||||
if (o instanceof UnsignedValue) {
|
||||
Object u = ((UnsignedValue) o).value();
|
||||
if (u instanceof Integer) {
|
||||
return Integer.toUnsignedLong(((Integer) u));
|
||||
}
|
||||
if (u instanceof Short) {
|
||||
return Short.toUnsignedLong(((Short) u));
|
||||
}
|
||||
if (u instanceof Byte) {
|
||||
return Byte.toUnsignedLong(((Byte) u));
|
||||
}
|
||||
}
|
||||
throw newIllegalArgumentException(name, "long");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code double} or of another primitive
|
||||
* type that is convertible to type {@code double} by a widening conversion.
|
||||
* <p>
|
||||
* This method can be used on fields of the following types: {@code double}, {@code float},
|
||||
* {@code long}, {@code int}, {@code short}, {@code char}, and {@code byte}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field converted to type {@code double}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to the type {@code double} by a widening
|
||||
* conversion
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final double getDouble(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Double) {
|
||||
return ((Double) o).doubleValue();
|
||||
}
|
||||
if (o instanceof Float) {
|
||||
return ((Float) o).doubleValue();
|
||||
}
|
||||
if (o instanceof Long) {
|
||||
return ((Long) o).doubleValue();
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return ((Integer) o).doubleValue();
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return ((Short) o).doubleValue();
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return ((Byte) o).byteValue();
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return ((Character) o).charValue();
|
||||
}
|
||||
throw newIllegalArgumentException(name, "double");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code String}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "foo.bar"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field as a {@code String}, can be {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* isn't of type {@code String}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final String getString(String name) {
|
||||
return getTypedValue(name, "java.lang.String");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a timespan field.
|
||||
* <p>
|
||||
* This method can be used on fields annotated with {@code @Timespan}, and of
|
||||
* the following types: {@code long}, {@code int}, {@code short}, {@code char},
|
||||
* and {@code byte}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return a time span represented as a {@code Duration}, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to a {@code Duration} object
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final Duration getDuration(String name) {
|
||||
Object o = getValue(name);
|
||||
if (o instanceof Long) {
|
||||
return getDuration(((Long) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return getDuration(((Integer) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return getDuration(((Short) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return getDuration(((Character) o).charValue(), name);
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return getDuration(((Byte) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof UnsignedValue) {
|
||||
Object u = ((UnsignedValue) o).value();
|
||||
if (u instanceof Integer) {
|
||||
return getDuration(Integer.toUnsignedLong((Integer) u), name);
|
||||
}
|
||||
if (u instanceof Short) {
|
||||
return getDuration(Short.toUnsignedLong((Short) u), name);
|
||||
}
|
||||
if (u instanceof Byte) {
|
||||
return getDuration(Short.toUnsignedLong((Byte) u), name);
|
||||
}
|
||||
}
|
||||
throw newIllegalArgumentException(name, "java,time.Duration");
|
||||
}
|
||||
|
||||
private Duration getDuration(long timespan, String name) throws InternalError {
|
||||
ValueDescriptor v = getValueDescriptor(descriptors, name, null);
|
||||
if (timespan == Long.MIN_VALUE) {
|
||||
return Duration.ofSeconds(Long.MIN_VALUE, 0);
|
||||
}
|
||||
Timespan ts = v.getAnnotation(Timespan.class);
|
||||
if (ts != null) {
|
||||
switch (ts.value()) {
|
||||
case Timespan.MICROSECONDS:
|
||||
return Duration.ofNanos(1000 * timespan);
|
||||
case Timespan.SECONDS:
|
||||
return Duration.ofSeconds(timespan);
|
||||
case Timespan.MILLISECONDS:
|
||||
return Duration.ofMillis(timespan);
|
||||
case Timespan.NANOSECONDS:
|
||||
return Duration.ofNanos(timespan);
|
||||
case Timespan.TICKS:
|
||||
return Duration.ofNanos(timeConverter.convertTimespan(timespan));
|
||||
}
|
||||
throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timespan unit " + ts.value());
|
||||
}
|
||||
throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timespan");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a timestamp field.
|
||||
* <p>
|
||||
* This method can be used on fields annotated with {@code @Timestamp}, and of
|
||||
* the following types: {@code long}, {@code int}, {@code short}, {@code char}
|
||||
* and {@code byte}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return a timstamp represented as an {@code Instant}, not {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* value can't be converted to an {@code Instant} object
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final Instant getInstant(String name) {
|
||||
Object o = getValue(name, true);
|
||||
if (o instanceof Long) {
|
||||
return getInstant(((Long) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Integer) {
|
||||
return getInstant(((Integer) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Short) {
|
||||
return getInstant(((Short) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof Character) {
|
||||
return getInstant(((Character) o).charValue(), name);
|
||||
}
|
||||
if (o instanceof Byte) {
|
||||
return getInstant(((Byte) o).longValue(), name);
|
||||
}
|
||||
if (o instanceof UnsignedValue) {
|
||||
Object u = ((UnsignedValue) o).value();
|
||||
if (u instanceof Integer) {
|
||||
return getInstant(Integer.toUnsignedLong((Integer) u), name);
|
||||
}
|
||||
if (u instanceof Short) {
|
||||
return getInstant(Short.toUnsignedLong((Short) u), name);
|
||||
}
|
||||
if (u instanceof Byte) {
|
||||
return getInstant(Short.toUnsignedLong((Byte) u), name);
|
||||
}
|
||||
}
|
||||
throw newIllegalArgumentException(name, "java.time.Instant");
|
||||
}
|
||||
|
||||
private Instant getInstant(long timestamp, String name) {
|
||||
ValueDescriptor v = getValueDescriptor(descriptors, name, null);
|
||||
Timestamp ts = v.getAnnotation(Timestamp.class);
|
||||
if (ts != null) {
|
||||
if (timestamp == Long.MIN_VALUE) {
|
||||
return Instant.MIN;
|
||||
}
|
||||
switch (ts.value()) {
|
||||
case Timestamp.MILLISECONDS_SINCE_EPOCH:
|
||||
return Instant.ofEpochMilli(timestamp);
|
||||
case Timestamp.TICKS:
|
||||
return Instant.ofEpochSecond(0, timeConverter.convertTimestamp(timestamp));
|
||||
}
|
||||
throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with illegal timestamp unit " + ts.value());
|
||||
}
|
||||
throw new IllegalArgumentException("Attempt to get " + v.getTypeName() + " field \"" + name + "\" with missing @Timestamp");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code Class}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "aaa.bbb"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field as a {@code RecordedClass}, can be
|
||||
* {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* isn't of type {@code Class}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final RecordedClass getClass(String name) {
|
||||
return getTypedValue(name, "java.lang.Class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a field of type {@code Thread}.
|
||||
* <p>
|
||||
* It's possible to index into a nested object using {@code "."} (for example,
|
||||
* {@code "foo.bar"}).
|
||||
* <p>
|
||||
* A field might change or be removed in a future JDK release. A best practice
|
||||
* for callers of this method is to validate the field before attempting access.
|
||||
*
|
||||
* @param name of the field to get, not {@code null}
|
||||
*
|
||||
* @return the value of the field as a {@code RecordedThread} object, can be
|
||||
* {@code null}
|
||||
*
|
||||
* @throws IllegalArgumentException if the field doesn't exist, or the field
|
||||
* isn't of type {@code Thread}
|
||||
*
|
||||
* @see #hasField(String)
|
||||
* @set #getValue(String)
|
||||
*/
|
||||
public final RecordedThread getThread(String name) {
|
||||
return getTypedValue(name, "java.lang.Thread");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a textual representation of this object.
|
||||
*
|
||||
* @return textual description of this object
|
||||
*/
|
||||
@Override
|
||||
final public String toString() {
|
||||
StringWriter s = new StringWriter();
|
||||
PrettyWriter p = new PrettyWriter(new PrintWriter(s));
|
||||
p.setStackDepth(5);
|
||||
if (this instanceof RecordedEvent) {
|
||||
p.print((RecordedEvent) this);
|
||||
} else {
|
||||
p.print(this, "");
|
||||
}
|
||||
p.flush(true);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
// package private for now. Used by EventWriter
|
||||
OffsetDateTime getOffsetDateTime(String name) {
|
||||
Instant instant = getInstant(name);
|
||||
if (instant.equals(Instant.MIN)) {
|
||||
return OffsetDateTime.MIN;
|
||||
}
|
||||
return OffsetDateTime.ofInstant(getInstant(name), timeConverter.getZoneOffset());
|
||||
}
|
||||
|
||||
private static IllegalArgumentException newIllegalArgumentException(String name, String typeName) {
|
||||
return new IllegalArgumentException("Attempt to get field \"" + name + "\" with illegal data type conversion " + typeName);
|
||||
}
|
||||
}
|
||||
80
jdkSrc/jdk8/jdk/jfr/consumer/RecordedStackTrace.java
Normal file
80
jdkSrc/jdk8/jdk/jfr/consumer/RecordedStackTrace.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded stack trace.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedStackTrace extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedStackTrace> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedStackTrace>(type) {
|
||||
@Override
|
||||
RecordedStackTrace createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedStackTrace(desc, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RecordedStackTrace(List<ValueDescriptor> desc, Object[] values, TimeConverter timeConverter) {
|
||||
super(desc, values, timeConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the frames in the stack trace.
|
||||
*
|
||||
* @return a list of Java stack frames, not {@code null}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<RecordedFrame> getFrames() {
|
||||
Object[] array = getTyped("frames", Object[].class, null);
|
||||
if (array == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List<?> list = Arrays.asList(array);
|
||||
return (List<RecordedFrame>) list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the stack trace is truncated due to its size,
|
||||
* {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if the stack trace is truncated, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
public boolean isTruncated() {
|
||||
return getTyped("truncated", Boolean.class, true);
|
||||
}
|
||||
}
|
||||
118
jdkSrc/jdk8/jdk/jfr/consumer/RecordedThread.java
Normal file
118
jdkSrc/jdk8/jdk/jfr/consumer/RecordedThread.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded thread.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedThread extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedThread> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedThread>(type) {
|
||||
@Override
|
||||
RecordedThread createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedThread(desc, id, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private final long uniqueId;
|
||||
|
||||
private RecordedThread(List<ValueDescriptor> descriptors, long id, Object[] values, TimeConverter timeConverter) {
|
||||
super(descriptors, values, timeConverter);
|
||||
this.uniqueId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thread name used by the operating system.
|
||||
*
|
||||
* @return the OS thread name, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getOSName() {
|
||||
return getTyped("osName", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thread ID used by the operating system.
|
||||
*
|
||||
* @return The Java thread ID, or {@code -1} if doesn't exist
|
||||
*/
|
||||
public long getOSThreadId() {
|
||||
Long l = getTyped("osThreadId", Long.class, -1L);
|
||||
return l.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java thread group, if available.
|
||||
*
|
||||
* @return the thread group, or {@code null} if doesn't exist
|
||||
*/
|
||||
public RecordedThreadGroup getThreadGroup() {
|
||||
return getTyped("group", RecordedThreadGroup.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java thread name, or {@code null} if if doesn't exist.
|
||||
* <p>
|
||||
* Returns {@code java.lang.Thread.getName()} if the thread has a Java
|
||||
* representation. {@code null} otherwise.
|
||||
*
|
||||
* @return the Java thread name, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getJavaName() {
|
||||
return getTyped("javaName", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java thread ID, or {@code -1} if it's not a Java thread.
|
||||
*
|
||||
* @return the Java thread ID, or {@code -1} if it's not a Java thread
|
||||
*/
|
||||
public long getJavaThreadId() {
|
||||
Long l = getTyped("javaThreadId", Long.class, -1L);
|
||||
return l.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID for both native threads and Java threads that can't be
|
||||
* reused within the lifespan of the JVM.
|
||||
* <p>
|
||||
* See {@link #getJavaThreadId()} for the ID that is returned by
|
||||
* {@code java.lang.Thread.getId()}
|
||||
*
|
||||
* @return a unique ID for the thread
|
||||
*/
|
||||
public long getId() {
|
||||
return uniqueId;
|
||||
}
|
||||
}
|
||||
70
jdkSrc/jdk8/jdk/jfr/consumer/RecordedThreadGroup.java
Normal file
70
jdkSrc/jdk8/jdk/jfr/consumer/RecordedThreadGroup.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
/**
|
||||
* A recorded Java thread group.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordedThreadGroup extends RecordedObject {
|
||||
|
||||
static ObjectFactory<RecordedThreadGroup> createFactory(Type type, TimeConverter timeConverter) {
|
||||
return new ObjectFactory<RecordedThreadGroup>(type) {
|
||||
@Override
|
||||
RecordedThreadGroup createTyped(List<ValueDescriptor> desc, long id, Object[] object) {
|
||||
return new RecordedThreadGroup(desc, object, timeConverter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RecordedThreadGroup(List<ValueDescriptor> descriptors, Object[] objects, TimeConverter timeConverter) {
|
||||
super(descriptors, objects, timeConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the thread group, or {@code null} if doesn't exist.
|
||||
*
|
||||
* @return the thread group name, or {@code null} if doesn't exist
|
||||
*/
|
||||
public String getName() {
|
||||
return getTyped("name", String.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent thread group, or {@code null} if it doesn't exist.
|
||||
*
|
||||
* @return parent thread group, or {@code null} if it doesn't exist.
|
||||
*/
|
||||
public RecordedThreadGroup getParent() {
|
||||
return getTyped("parent", RecordedThreadGroup.class, null);
|
||||
}
|
||||
}
|
||||
269
jdkSrc/jdk8/jdk/jfr/consumer/RecordingFile.java
Normal file
269
jdkSrc/jdk8/jdk/jfr/consumer/RecordingFile.java
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.internal.MetadataDescriptor;
|
||||
import jdk.jfr.internal.Type;
|
||||
import jdk.jfr.internal.consumer.ChunkHeader;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
import jdk.jfr.internal.consumer.RecordingInternals;
|
||||
|
||||
/**
|
||||
* A recording file.
|
||||
* <p>
|
||||
* The following example shows how read and print all events in a recording file.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* try (RecordingFile recordingFile = new RecordingFile(Paths.get("recording.jfr"))) {
|
||||
* while (recordingFile.hasMoreEvents()) {
|
||||
* RecordedEvent event = recordingFile.readEvent();
|
||||
* System.out.println(event);
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
public final class RecordingFile implements Closeable {
|
||||
static{
|
||||
RecordingInternals.INSTANCE = new RecordingInternals() {
|
||||
public List<Type> readTypes(RecordingFile file) throws IOException {
|
||||
return file.readTypes();
|
||||
}
|
||||
|
||||
public boolean isLastEventInChunk(RecordingFile file) {
|
||||
return file.isLastEventInChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOffsetDataTime(RecordedObject event, String name) {
|
||||
return event.getOffsetDateTime(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(List<RecordedEvent> events) {
|
||||
Collections.sort(events, (e1, e2) -> Long.compare(e1.endTime, e2.endTime));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isLastEventInChunk;
|
||||
private final File file;
|
||||
private RecordingInput input;
|
||||
private ChunkParser chunkParser;
|
||||
private RecordedEvent nextEvent;
|
||||
private boolean eof;
|
||||
|
||||
/**
|
||||
* Creates a recording file.
|
||||
*
|
||||
* @param file the path of the file to open, not {@code null}
|
||||
* @throws IOException if it's not a valid recording file, or an I/O error
|
||||
* occurred
|
||||
* @throws NoSuchFileException if the {@code file} can't be located
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and its
|
||||
* {@code checkRead} method denies read access to the file.
|
||||
*/
|
||||
public RecordingFile(Path file) throws IOException {
|
||||
this.file = file.toFile();
|
||||
this.input = new RecordingInput(this.file);
|
||||
findNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next event in the recording.
|
||||
*
|
||||
* @return the next event, not {@code null}
|
||||
*
|
||||
* @throws EOFException if no more events exist in the recording file
|
||||
* @throws IOException if an I/O error occurs.
|
||||
*
|
||||
* @see #hasMoreEvents()
|
||||
*/
|
||||
public RecordedEvent readEvent() throws IOException {
|
||||
if (eof) {
|
||||
ensureOpen();
|
||||
throw new EOFException();
|
||||
}
|
||||
isLastEventInChunk = false;
|
||||
RecordedEvent event = nextEvent;
|
||||
nextEvent = chunkParser.readEvent();
|
||||
if (nextEvent == null) {
|
||||
isLastEventInChunk = true;
|
||||
findNext();
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if unread events exist in the recording file,
|
||||
* {@code false} otherwise.
|
||||
*
|
||||
* @return {@code true} if unread events exist in the recording, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean hasMoreEvents() {
|
||||
return !eof;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all event types in this recording.
|
||||
*
|
||||
* @return a list of event types, not {@code null}
|
||||
* @throws IOException if an I/O error occurred while reading from the file
|
||||
*
|
||||
* @see #hasMoreEvents()
|
||||
*/
|
||||
public List<EventType> readEventTypes() throws IOException {
|
||||
ensureOpen();
|
||||
List<EventType> types = new ArrayList<>();
|
||||
HashSet<Long> foundIds = new HashSet<>();
|
||||
try (RecordingInput ri = new RecordingInput(file)) {
|
||||
ChunkHeader ch = new ChunkHeader(ri);
|
||||
aggregateEventTypeForChunk(ch, types, foundIds);
|
||||
while (!ch.isLastChunk()) {
|
||||
ch = ch.nextHeader();
|
||||
aggregateEventTypeForChunk(ch, types, foundIds);
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
List<Type> readTypes() throws IOException {
|
||||
ensureOpen();
|
||||
List<Type> types = new ArrayList<>();
|
||||
HashSet<Long> foundIds = new HashSet<>();
|
||||
try (RecordingInput ri = new RecordingInput(file)) {
|
||||
ChunkHeader ch = new ChunkHeader(ri);
|
||||
aggregateTypeForChunk(ch, types, foundIds);
|
||||
while (!ch.isLastChunk()) {
|
||||
ch = ch.nextHeader();
|
||||
aggregateTypeForChunk(ch, types, foundIds);
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
private void aggregateTypeForChunk(ChunkHeader ch, List<Type> types, HashSet<Long> foundIds) throws IOException {
|
||||
MetadataDescriptor m = ch.readMetadata();
|
||||
for (Type t : m.getTypes()) {
|
||||
if (!foundIds.contains(t.getId())) {
|
||||
types.add(t);
|
||||
foundIds.add(t.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void aggregateEventTypeForChunk(ChunkHeader ch, List<EventType> types, HashSet<Long> foundIds) throws IOException {
|
||||
MetadataDescriptor m = ch.readMetadata();
|
||||
for (EventType t : m.getEventTypes()) {
|
||||
if (!foundIds.contains(t.getId())) {
|
||||
types.add(t);
|
||||
foundIds.add(t.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this recording file and releases any system resources that are
|
||||
* associated with it.
|
||||
*
|
||||
* @throws IOException if an I/O error occurred
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (input != null) {
|
||||
eof = true;
|
||||
input.close();
|
||||
chunkParser = null;
|
||||
input = null;
|
||||
nextEvent = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all events in a file.
|
||||
* <p>
|
||||
* This method is intended for simple cases where it's convenient to read all
|
||||
* events in a single operation. It isn't intended for reading large files.
|
||||
*
|
||||
* @param path the path to the file, not {@code null}
|
||||
*
|
||||
* @return the events from the file as a {@code List} object; whether the
|
||||
* {@code List} is modifiable or not is implementation dependent and
|
||||
* therefore not specified, not {@code null}
|
||||
*
|
||||
* @throws IOException if an I/O error occurred, it's not a Flight Recorder
|
||||
* file or a version of a JFR file that can't be parsed
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and its
|
||||
* {@code checkRead} method denies read access to the file.
|
||||
*/
|
||||
public static List<RecordedEvent> readAllEvents(Path path) throws IOException {
|
||||
try (RecordingFile r = new RecordingFile(path)) {
|
||||
List<RecordedEvent> list = new ArrayList<>();
|
||||
while (r.hasMoreEvents()) {
|
||||
list.add(r.readEvent());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// either sets next to an event or sets eof to true
|
||||
private void findNext() throws IOException {
|
||||
while (nextEvent == null) {
|
||||
if (chunkParser == null) {
|
||||
chunkParser = new ChunkParser(input);
|
||||
} else if (!chunkParser.isLastChunk()) {
|
||||
chunkParser = chunkParser.nextChunkParser();
|
||||
} else {
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
nextEvent = chunkParser.readEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (input == null) {
|
||||
throw new IOException("Stream Closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
72
jdkSrc/jdk8/jdk/jfr/consumer/TimeConverter.java
Normal file
72
jdkSrc/jdk8/jdk/jfr/consumer/TimeConverter.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.consumer;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.ZoneOffset;
|
||||
|
||||
import jdk.jfr.internal.LogLevel;
|
||||
import jdk.jfr.internal.LogTag;
|
||||
import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.consumer.ChunkHeader;
|
||||
|
||||
/**
|
||||
* Converts ticks to nanoseconds
|
||||
*/
|
||||
final class TimeConverter {
|
||||
private final long startTicks;
|
||||
private final long startNanos;
|
||||
private final double divisor;
|
||||
private final ZoneOffset zoneOffet;
|
||||
|
||||
TimeConverter(ChunkHeader chunkHeader, int rawOffset) {
|
||||
this.startTicks = chunkHeader.getStartTicks();
|
||||
this.startNanos = chunkHeader.getStartNanos();
|
||||
this.divisor = chunkHeader.getTicksPerSecond() / 1000_000_000L;
|
||||
this.zoneOffet = zoneOfSet(rawOffset);
|
||||
}
|
||||
|
||||
private ZoneOffset zoneOfSet(int rawOffset) {
|
||||
try {
|
||||
return ZoneOffset.ofTotalSeconds(rawOffset / 1000);
|
||||
} catch (DateTimeException dte) {
|
||||
Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Could not create ZoneOffset from raw offset " + rawOffset);
|
||||
}
|
||||
return ZoneOffset.UTC;
|
||||
}
|
||||
|
||||
public long convertTimestamp(long ticks) {
|
||||
return startNanos + (long) ((ticks - startTicks) / divisor);
|
||||
}
|
||||
|
||||
public long convertTimespan(long ticks) {
|
||||
return (long) (ticks / divisor);
|
||||
}
|
||||
|
||||
public ZoneOffset getZoneOffset() {
|
||||
return zoneOffet;
|
||||
}
|
||||
}
|
||||
82
jdkSrc/jdk8/jdk/jfr/consumer/package-info.java
Normal file
82
jdkSrc/jdk8/jdk/jfr/consumer/package-info.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains classes for consuming Flight Recorder data.
|
||||
* <p>
|
||||
* In the following example, the program prints a histogram of all method samples in a recording.
|
||||
* <pre>
|
||||
* <code>
|
||||
* public static void main(String[] args) {
|
||||
* if (args.length != 0) {
|
||||
* System.out.println("Must specify recording file.");
|
||||
* return;
|
||||
* }
|
||||
* try (RecordingFile f = new RecordingFile(Paths.get(args[0]))) {
|
||||
* Map{@literal <}String, SimpleEntry{@literal <}String, Integer{@literal >}{@literal >} histogram = new HashMap{@literal <}{@literal >}();
|
||||
* int total = 0;
|
||||
* while (f.hasMoreEvents()) {
|
||||
* RecordedEvent event = f.readEvent();
|
||||
* if (event.getEventType().getName().equals("jdk.ExecutionSample")) {
|
||||
* RecordedStackTrace s = event.getStackTrace();
|
||||
* if (s != null) {
|
||||
* RecordedFrame topFrame= s.getFrames().get(0);
|
||||
* if (topFrame.isJavaFrame()) {
|
||||
* RecordedMethod method = topFrame.getMethod();
|
||||
* String methodName = method.getType().getName() + "#" + method.getName() + " " + method.getDescriptor();
|
||||
* Entry entry = histogram.computeIfAbsent(methodName, u -{@literal >} new SimpleEntry{@literal <}String, Integer{@literal >}(methodName, 0));
|
||||
* entry.setValue(entry.getValue() + 1);
|
||||
* total++;
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* List{@literal <}SimpleEntry{@literal <}String, Integer{@literal >}{@literal >} entries = new ArrayList{@literal <}{@literal >}(histogram.values());
|
||||
* entries.sort((u, v) -{@literal >} v.getValue().compareTo(u.getValue()));
|
||||
* for (SimpleEntry{@literal <}String, Integer{@literal >} c : entries) {
|
||||
* System.out.printf("%2.0f%% %s\n", 100 * (float) c.getValue() / total, c.getKey());
|
||||
* }
|
||||
* System.out.println("\nSample count: " + total);
|
||||
* } catch (IOException ioe) {
|
||||
* System.out.println("Error reading file " + args[0] + ". " + ioe.getMessage());
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Null-handling</b>
|
||||
* <p>
|
||||
* All methods define whether they accept or return {@code null} in the Javadoc.
|
||||
* Typically this is expressed as {@code "not null"}. If a {@code null}
|
||||
* parameter is used where it is not allowed, a
|
||||
* {@code java.lang.NullPointerException} is thrown. If a {@code null}
|
||||
* parameters is passed to a method that throws other exceptions, such as
|
||||
* {@code java.io.IOException}, the {@code java.lang.NullPointerException} takes
|
||||
* precedence, unless the Javadoc for the method explicitly states how
|
||||
* {@code null} is handled, i.e. by throwing {@code java.lang.IllegalArgumentException}.
|
||||
*
|
||||
* @since 8
|
||||
*/
|
||||
package jdk.jfr.consumer;
|
||||
37
jdkSrc/jdk8/jdk/jfr/events/AbstractJDKEvent.java
Normal file
37
jdkSrc/jdk8/jdk/jfr/events/AbstractJDKEvent.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Registered;
|
||||
import jdk.jfr.StackTrace;
|
||||
|
||||
@Registered(false)
|
||||
@Enabled(false)
|
||||
@StackTrace(false)
|
||||
abstract class AbstractJDKEvent extends Event {
|
||||
}
|
||||
67
jdkSrc/jdk8/jdk/jfr/events/ActiveRecordingEvent.java
Normal file
67
jdkSrc/jdk8/jdk/jfr/events/ActiveRecordingEvent.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.Timestamp;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ActiveRecording")
|
||||
@Label("Flight Recording")
|
||||
@Category("Flight Recorder")
|
||||
@StackTrace(false)
|
||||
public final class ActiveRecordingEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Id")
|
||||
public long id;
|
||||
|
||||
@Label("Name")
|
||||
public String name;
|
||||
|
||||
@Label("Destination")
|
||||
public String destination;
|
||||
|
||||
@Label("Max Age")
|
||||
@Timespan(Timespan.MILLISECONDS)
|
||||
public long maxAge;
|
||||
|
||||
@Label("Max Size")
|
||||
@DataAmount
|
||||
public long maxSize;
|
||||
|
||||
@Label("Start Time")
|
||||
@Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
|
||||
public long recordingStart;
|
||||
|
||||
@Label("Recording Duration")
|
||||
@Timespan(Timespan.MILLISECONDS)
|
||||
public long recordingDuration;
|
||||
}
|
||||
48
jdkSrc/jdk8/jdk/jfr/events/ActiveSettingEvent.java
Normal file
48
jdkSrc/jdk8/jdk/jfr/events/ActiveSettingEvent.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ActiveSetting")
|
||||
@Label("Recording Setting")
|
||||
@Category("Flight Recorder")
|
||||
@StackTrace(false)
|
||||
public final class ActiveSettingEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Event Id")
|
||||
public long id;
|
||||
|
||||
@Label("Setting Name")
|
||||
public String name;
|
||||
|
||||
@Label("Setting Value")
|
||||
public String value;
|
||||
}
|
||||
44
jdkSrc/jdk8/jdk/jfr/events/ErrorThrownEvent.java
Normal file
44
jdkSrc/jdk8/jdk/jfr/events/ErrorThrownEvent.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "JavaErrorThrow")
|
||||
@Label("Java Error")
|
||||
@Category("Java Application")
|
||||
@Description("An object derived from java.lang.Error has been created. OutOfMemoryErrors are ignored")
|
||||
public final class ErrorThrownEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Message")
|
||||
public String message;
|
||||
|
||||
@Label("Class")
|
||||
public Class<?> thrownClass;
|
||||
}
|
||||
44
jdkSrc/jdk8/jdk/jfr/events/ExceptionStatisticsEvent.java
Normal file
44
jdkSrc/jdk8/jdk/jfr/events/ExceptionStatisticsEvent.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ExceptionStatistics")
|
||||
@Label("Exception Statistics")
|
||||
@Category({ "Java Application", "Statistics" })
|
||||
@Description("Number of objects derived from java.lang.Throwable that have been created")
|
||||
@StackTrace(false)
|
||||
public final class ExceptionStatisticsEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Exceptions Created")
|
||||
public long throwables;
|
||||
}
|
||||
45
jdkSrc/jdk8/jdk/jfr/events/ExceptionThrownEvent.java
Normal file
45
jdkSrc/jdk8/jdk/jfr/events/ExceptionThrownEvent.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "JavaExceptionThrow")
|
||||
@Label("Java Exception")
|
||||
@Category("Java Application")
|
||||
@Description("An object derived from java.lang.Exception has been created")
|
||||
public final class ExceptionThrownEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Message")
|
||||
public String message;
|
||||
|
||||
@Label("Class")
|
||||
public Class<?> thrownClass;
|
||||
}
|
||||
59
jdkSrc/jdk8/jdk/jfr/events/FileForceEvent.java
Normal file
59
jdkSrc/jdk8/jdk/jfr/events/FileForceEvent.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "FileForce")
|
||||
@Label("File Force")
|
||||
@Category("Java Application")
|
||||
@Description("Force updates to be written to file")
|
||||
public final class FileForceEvent extends AbstractJDKEvent {
|
||||
|
||||
public static final ThreadLocal<FileForceEvent> EVENT =
|
||||
new ThreadLocal<FileForceEvent>() {
|
||||
@Override protected FileForceEvent initialValue() {
|
||||
return new FileForceEvent();
|
||||
}
|
||||
};
|
||||
|
||||
@Label("Path")
|
||||
@Description("Full path of the file")
|
||||
public String path;
|
||||
|
||||
@Label("Update Metadata")
|
||||
@Description("Whether the file metadata is updated")
|
||||
public boolean metaData;
|
||||
|
||||
public void reset() {
|
||||
path = null;
|
||||
metaData = false;
|
||||
}
|
||||
}
|
||||
66
jdkSrc/jdk8/jdk/jfr/events/FileReadEvent.java
Normal file
66
jdkSrc/jdk8/jdk/jfr/events/FileReadEvent.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "FileRead")
|
||||
@Label("File Read")
|
||||
@Category("Java Application")
|
||||
@Description("Reading data from a file")
|
||||
public final class FileReadEvent extends AbstractJDKEvent {
|
||||
|
||||
public static final ThreadLocal<FileReadEvent> EVENT =
|
||||
new ThreadLocal<FileReadEvent>() {
|
||||
@Override protected FileReadEvent initialValue() {
|
||||
return new FileReadEvent();
|
||||
}
|
||||
};
|
||||
|
||||
@Label("Path")
|
||||
@Description("Full path of the file")
|
||||
public String path;
|
||||
|
||||
@Label("Bytes Read")
|
||||
@Description("Number of bytes read from the file (possibly 0)")
|
||||
@DataAmount
|
||||
public long bytesRead;
|
||||
|
||||
@Label("End of File")
|
||||
@Description("If end of file was reached")
|
||||
public boolean endOfFile;
|
||||
|
||||
public void reset() {
|
||||
path = null;
|
||||
endOfFile = false;
|
||||
bytesRead = 0;
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/jdk/jfr/events/FileWriteEvent.java
Normal file
61
jdkSrc/jdk8/jdk/jfr/events/FileWriteEvent.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "FileWrite")
|
||||
@Label("File Write")
|
||||
@Category("Java Application")
|
||||
@Description("Writing data to a file")
|
||||
public final class FileWriteEvent extends AbstractJDKEvent {
|
||||
|
||||
public static final ThreadLocal<FileWriteEvent> EVENT =
|
||||
new ThreadLocal<FileWriteEvent>() {
|
||||
@Override protected FileWriteEvent initialValue() {
|
||||
return new FileWriteEvent();
|
||||
}
|
||||
};
|
||||
|
||||
@Label("Path")
|
||||
@Description("Full path of the file")
|
||||
public String path;
|
||||
|
||||
@Label("Bytes Written")
|
||||
@Description("Number of bytes written to the file")
|
||||
@DataAmount
|
||||
public long bytesWritten;
|
||||
|
||||
public void reset() {
|
||||
path = null;
|
||||
bytesWritten = 0;
|
||||
}
|
||||
}
|
||||
79
jdkSrc/jdk8/jdk/jfr/events/SocketReadEvent.java
Normal file
79
jdkSrc/jdk8/jdk/jfr/events/SocketReadEvent.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "SocketRead")
|
||||
@Label("Socket Read")
|
||||
@Category("Java Application")
|
||||
@Description("Reading data from a socket")
|
||||
public final class SocketReadEvent extends AbstractJDKEvent {
|
||||
|
||||
public static final ThreadLocal<SocketReadEvent> EVENT =
|
||||
new ThreadLocal<SocketReadEvent>() {
|
||||
@Override protected SocketReadEvent initialValue() {
|
||||
return new SocketReadEvent();
|
||||
}
|
||||
};
|
||||
|
||||
@Label("Remote Host")
|
||||
public String host;
|
||||
|
||||
@Label("Remote Address")
|
||||
public String address;
|
||||
|
||||
@Label("Remote Port")
|
||||
public int port;
|
||||
|
||||
@Label("Timeout Value")
|
||||
@Timespan(Timespan.MILLISECONDS)
|
||||
public long timeout;
|
||||
|
||||
@Label("Bytes Read")
|
||||
@Description("Number of bytes read from the socket")
|
||||
@DataAmount
|
||||
public long bytesRead;
|
||||
|
||||
@Label("End of Stream")
|
||||
@Description("If end of stream was reached")
|
||||
public boolean endOfStream;
|
||||
|
||||
public void reset() {
|
||||
host = null;
|
||||
address = null;
|
||||
port = 0;
|
||||
timeout = 0;
|
||||
bytesRead = 0L;
|
||||
endOfStream = false;
|
||||
}
|
||||
}
|
||||
68
jdkSrc/jdk8/jdk/jfr/events/SocketWriteEvent.java
Normal file
68
jdkSrc/jdk8/jdk/jfr/events/SocketWriteEvent.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "SocketWrite")
|
||||
@Label("Socket Write")
|
||||
@Category("Java Application")
|
||||
@Description("Writing data to a socket")
|
||||
public final class SocketWriteEvent extends AbstractJDKEvent {
|
||||
|
||||
public static final ThreadLocal<SocketWriteEvent> EVENT =
|
||||
new ThreadLocal<SocketWriteEvent>() {
|
||||
@Override protected SocketWriteEvent initialValue() {
|
||||
return new SocketWriteEvent();
|
||||
}
|
||||
};
|
||||
|
||||
@Label("Remote Host")
|
||||
public String host;
|
||||
|
||||
@Label("Remote Address")
|
||||
public String address;
|
||||
|
||||
@Label("Remote Port")
|
||||
public int port;
|
||||
|
||||
@Label("Bytes Written")
|
||||
@Description("Number of bytes written to the socket")
|
||||
@DataAmount
|
||||
public long bytesWritten;
|
||||
|
||||
public void reset() {
|
||||
host = null;
|
||||
address = null;
|
||||
port = 0;
|
||||
bytesWritten = 0;
|
||||
}
|
||||
}
|
||||
162
jdkSrc/jdk8/jdk/jfr/internal/ASMToolkit.java
Normal file
162
jdkSrc/jdk8/jdk/jfr/internal/ASMToolkit.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.EventInstrumentation.FieldInfo;
|
||||
|
||||
final class ASMToolkit {
|
||||
private static Type TYPE_STRING = Type.getType(String.class);
|
||||
private static Type Type_THREAD = Type.getType(Thread.class);
|
||||
private static Type TYPE_CLASS = Type.getType(Class.class);
|
||||
|
||||
public static void invokeSpecial(MethodVisitor methodVisitor, String className, Method m) {
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, m.getName(), m.getDescriptor(), false);
|
||||
}
|
||||
|
||||
public static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) {
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false);
|
||||
}
|
||||
|
||||
public static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) {
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false);
|
||||
}
|
||||
|
||||
|
||||
public static Type toType(ValueDescriptor v) {
|
||||
String typeName = v.getTypeName();
|
||||
|
||||
switch (typeName) {
|
||||
case "byte":
|
||||
return Type.BYTE_TYPE;
|
||||
case "short":
|
||||
return Type.SHORT_TYPE;
|
||||
case "int":
|
||||
return Type.INT_TYPE;
|
||||
case "long":
|
||||
return Type.LONG_TYPE;
|
||||
case "double":
|
||||
return Type.DOUBLE_TYPE;
|
||||
case "float":
|
||||
return Type.FLOAT_TYPE;
|
||||
case "char":
|
||||
return Type.CHAR_TYPE;
|
||||
case "boolean":
|
||||
return Type.BOOLEAN_TYPE;
|
||||
case "java.lang.String":
|
||||
return TYPE_STRING;
|
||||
case "java.lang.Thread":
|
||||
return Type_THREAD;
|
||||
case "java.lang.Class":
|
||||
return TYPE_CLASS;
|
||||
}
|
||||
// Add support for SettingControl?
|
||||
throw new Error("Not a valid type " + v.getTypeName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts "int" into "I" and "java.lang.String" into "Ljava/lang/String;"
|
||||
*
|
||||
* @param typeName
|
||||
* type
|
||||
*
|
||||
* @return descriptor
|
||||
*/
|
||||
public static String getDescriptor(String typeName) {
|
||||
if ("int".equals(typeName)) {
|
||||
return "I";
|
||||
}
|
||||
if ("long".equals(typeName)) {
|
||||
return "J";
|
||||
}
|
||||
if ("boolean".equals(typeName)) {
|
||||
return "Z";
|
||||
}
|
||||
if ("float".equals(typeName)) {
|
||||
return "F";
|
||||
}
|
||||
if ("double".equals(typeName)) {
|
||||
return "D";
|
||||
}
|
||||
if ("short".equals(typeName)) {
|
||||
return "S";
|
||||
}
|
||||
if ("char".equals(typeName)) {
|
||||
return "C";
|
||||
}
|
||||
if ("byte".equals(typeName)) {
|
||||
return "B";
|
||||
}
|
||||
String internal = getInternalName(typeName);
|
||||
return Type.getObjectType(internal).getDescriptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts java.lang.String into java/lang/String
|
||||
*
|
||||
* @param className
|
||||
*
|
||||
* @return internal name
|
||||
*/
|
||||
public static String getInternalName(String className) {
|
||||
return className.replace(".", "/");
|
||||
}
|
||||
|
||||
public static Method makeWriteMethod(List<FieldInfo> fields) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (FieldInfo v : fields) {
|
||||
if (!v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD) && !v.fieldName.equals(EventInstrumentation.FIELD_STACK_TRACE)) {
|
||||
sb.append(v.fieldDescriptor);
|
||||
}
|
||||
}
|
||||
sb.append(")V");
|
||||
return new Method("write", sb.toString());
|
||||
}
|
||||
|
||||
public static void logASM(String className, byte[] bytes) {
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className);
|
||||
Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, () -> {
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PrintWriter w = new PrintWriter(baos);
|
||||
w.println("Bytecode:");
|
||||
cr.accept(new TraceClassVisitor(w), 0);
|
||||
return baos.toString();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
136
jdkSrc/jdk8/jdk/jfr/internal/AnnotationConstruct.java
Normal file
136
jdkSrc/jdk8/jdk/jfr/internal/AnnotationConstruct.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Unsigned;
|
||||
|
||||
public final class AnnotationConstruct {
|
||||
|
||||
private static final class AnnotationInvokationHandler implements InvocationHandler {
|
||||
|
||||
private final AnnotationElement annotationElement;
|
||||
|
||||
AnnotationInvokationHandler(AnnotationElement a) {
|
||||
this.annotationElement = a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
String methodName = method.getName();
|
||||
int parameters = method.getTypeParameters().length;
|
||||
if (parameters == 0 && annotationElement.hasValue(methodName)) {
|
||||
return annotationElement.getValue(methodName);
|
||||
}
|
||||
throw new UnsupportedOperationException("Flight Recorder proxy only supports members declared in annotation interfaces, i.e. not toString, equals etc.");
|
||||
}
|
||||
}
|
||||
|
||||
private List<AnnotationElement> annotationElements = Collections.emptyList();
|
||||
private byte unsignedFlag = -1;
|
||||
public AnnotationConstruct(List<AnnotationElement> ann) {
|
||||
this.annotationElements = ann;
|
||||
}
|
||||
|
||||
public AnnotationConstruct() {
|
||||
}
|
||||
|
||||
public void setAnnotationElements(List<AnnotationElement> elements) {
|
||||
annotationElements = Utils.smallUnmodifiable(elements);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
Label label = getAnnotation(Label.class);
|
||||
if (label == null) {
|
||||
return null;
|
||||
}
|
||||
return label.value();
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
Description description = getAnnotation(Description.class);
|
||||
if (description == null) {
|
||||
return null;
|
||||
}
|
||||
return description.value();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T> T getAnnotation(Class<? extends Annotation> clazz) {
|
||||
AnnotationElement ae = getAnnotationElement(clazz);
|
||||
if (ae != null) {
|
||||
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, new AnnotationInvokationHandler(ae));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<AnnotationElement> getUnmodifiableAnnotationElements() {
|
||||
return annotationElements;
|
||||
}
|
||||
|
||||
// package private
|
||||
boolean remove(AnnotationElement annotation) {
|
||||
return annotationElements.remove(annotation);
|
||||
}
|
||||
|
||||
private AnnotationElement getAnnotationElement(Class<? extends Annotation> clazz) {
|
||||
// if multiple annotation elements with the same name exists, prioritize
|
||||
// the one with the same id. Note, id alone is not a guarantee, since it
|
||||
// may differ between JVM instances.
|
||||
long id = Type.getTypeId(clazz);
|
||||
String className = clazz.getName();
|
||||
for (AnnotationElement a : getUnmodifiableAnnotationElements()) {
|
||||
if (a.getTypeId() == id && a.getTypeName().equals(className)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
for (AnnotationElement a : getUnmodifiableAnnotationElements()) {
|
||||
if (a.getTypeName().equals(className)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasUnsigned() {
|
||||
// Must be initialized lazily since some annotation elements
|
||||
// are added after construction
|
||||
if (unsignedFlag < 0) {
|
||||
Unsigned unsigned = getAnnotation(Unsigned.class);
|
||||
unsignedFlag = (byte) (unsigned == null ? 0 :1);
|
||||
}
|
||||
return unsignedFlag == (byte)1 ? true : false;
|
||||
}
|
||||
}
|
||||
227
jdkSrc/jdk8/jdk/jfr/internal/Bits.java
Normal file
227
jdkSrc/jdk8/jdk/jfr/internal/Bits.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
final class Bits { // package-private
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
// XXX TODO proper value (e.g. copy from java.nio.Bits)
|
||||
private static final boolean unalignedAccess = false/*unsafe.unalignedAccess()*/;
|
||||
private static final boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
|
||||
private Bits() { }
|
||||
|
||||
// -- Swapping --
|
||||
|
||||
private static short swap(short x) {
|
||||
return Short.reverseBytes(x);
|
||||
}
|
||||
|
||||
private static char swap(char x) {
|
||||
return Character.reverseBytes(x);
|
||||
}
|
||||
|
||||
private static int swap(int x) {
|
||||
return Integer.reverseBytes(x);
|
||||
}
|
||||
|
||||
private static long swap(long x) {
|
||||
return Long.reverseBytes(x);
|
||||
}
|
||||
|
||||
private static float swap(float x) {
|
||||
return Float.intBitsToFloat(swap(Float.floatToIntBits(x)));
|
||||
}
|
||||
|
||||
private static double swap(double x) {
|
||||
return Double.longBitsToDouble(swap(Double.doubleToLongBits(x)));
|
||||
}
|
||||
|
||||
// -- Alignment --
|
||||
|
||||
private static boolean isAddressAligned(long a, int datumSize) {
|
||||
return (a & datumSize - 1) == 0;
|
||||
}
|
||||
|
||||
// -- Primitives stored per byte
|
||||
|
||||
private static byte char1(char x) { return (byte)(x >> 8); }
|
||||
private static byte char0(char x) { return (byte)(x ); }
|
||||
|
||||
private static byte short1(short x) { return (byte)(x >> 8); }
|
||||
private static byte short0(short x) { return (byte)(x ); }
|
||||
|
||||
private static byte int3(int x) { return (byte)(x >> 24); }
|
||||
private static byte int2(int x) { return (byte)(x >> 16); }
|
||||
private static byte int1(int x) { return (byte)(x >> 8); }
|
||||
private static byte int0(int x) { return (byte)(x ); }
|
||||
|
||||
private static byte long7(long x) { return (byte)(x >> 56); }
|
||||
private static byte long6(long x) { return (byte)(x >> 48); }
|
||||
private static byte long5(long x) { return (byte)(x >> 40); }
|
||||
private static byte long4(long x) { return (byte)(x >> 32); }
|
||||
private static byte long3(long x) { return (byte)(x >> 24); }
|
||||
private static byte long2(long x) { return (byte)(x >> 16); }
|
||||
private static byte long1(long x) { return (byte)(x >> 8); }
|
||||
private static byte long0(long x) { return (byte)(x ); }
|
||||
|
||||
private static void putCharBigEndianUnaligned(long a, char x) {
|
||||
putByte_(a , char1(x));
|
||||
putByte_(a + 1, char0(x));
|
||||
}
|
||||
|
||||
private static void putShortBigEndianUnaligned(long a, short x) {
|
||||
putByte_(a , short1(x));
|
||||
putByte_(a + 1, short0(x));
|
||||
}
|
||||
|
||||
private static void putIntBigEndianUnaligned(long a, int x) {
|
||||
putByte_(a , int3(x));
|
||||
putByte_(a + 1, int2(x));
|
||||
putByte_(a + 2, int1(x));
|
||||
putByte_(a + 3, int0(x));
|
||||
}
|
||||
|
||||
private static void putLongBigEndianUnaligned(long a, long x) {
|
||||
putByte_(a , long7(x));
|
||||
putByte_(a + 1, long6(x));
|
||||
putByte_(a + 2, long5(x));
|
||||
putByte_(a + 3, long4(x));
|
||||
putByte_(a + 4, long3(x));
|
||||
putByte_(a + 5, long2(x));
|
||||
putByte_(a + 6, long1(x));
|
||||
putByte_(a + 7, long0(x));
|
||||
}
|
||||
|
||||
private static void putFloatBigEndianUnaligned(long a, float x) {
|
||||
putIntBigEndianUnaligned(a, Float.floatToRawIntBits(x));
|
||||
}
|
||||
|
||||
private static void putDoubleBigEndianUnaligned(long a, double x) {
|
||||
putLongBigEndianUnaligned(a, Double.doubleToRawLongBits(x));
|
||||
}
|
||||
|
||||
private static void putByte_(long a, byte b) {
|
||||
unsafe.putByte(a, b);
|
||||
}
|
||||
|
||||
private static void putBoolean_(long a, boolean x) {
|
||||
unsafe.putBoolean(null, a, x);
|
||||
}
|
||||
|
||||
private static void putChar_(long a, char x) {
|
||||
unsafe.putChar(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
private static void putShort_(long a, short x) {
|
||||
unsafe.putShort(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
private static void putInt_(long a, int x) {
|
||||
unsafe.putInt(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
private static void putLong_(long a, long x) {
|
||||
unsafe.putLong(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
private static void putFloat_(long a, float x) {
|
||||
unsafe.putFloat(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
private static void putDouble_(long a, double x) {
|
||||
unsafe.putDouble(a, bigEndian ? x : swap(x));
|
||||
}
|
||||
|
||||
// external api
|
||||
static int putByte(long a, byte x) {
|
||||
putByte_(a, x);
|
||||
return Byte.BYTES;
|
||||
}
|
||||
|
||||
static int putBoolean(long a, boolean x) {
|
||||
putBoolean_(a, x);
|
||||
return Byte.BYTES;
|
||||
}
|
||||
|
||||
static int putChar(long a, char x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Character.BYTES)) {
|
||||
putChar_(a, x);
|
||||
return Character.BYTES;
|
||||
}
|
||||
putCharBigEndianUnaligned(a, x);
|
||||
return Character.BYTES;
|
||||
}
|
||||
|
||||
static int putShort(long a, short x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Short.BYTES)) {
|
||||
putShort_(a, x);
|
||||
return Short.BYTES;
|
||||
}
|
||||
putShortBigEndianUnaligned(a, x);
|
||||
return Short.BYTES;
|
||||
}
|
||||
|
||||
static int putInt(long a, int x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Integer.BYTES)) {
|
||||
putInt_(a, x);
|
||||
return Integer.BYTES;
|
||||
}
|
||||
putIntBigEndianUnaligned(a, x);
|
||||
return Integer.BYTES;
|
||||
}
|
||||
|
||||
static int putLong(long a, long x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Long.BYTES)) {
|
||||
putLong_(a, x);
|
||||
return Long.BYTES;
|
||||
}
|
||||
putLongBigEndianUnaligned(a, x);
|
||||
return Long.BYTES;
|
||||
}
|
||||
|
||||
static int putFloat(long a, float x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Float.BYTES)) {
|
||||
putFloat_(a, x);
|
||||
return Float.BYTES;
|
||||
}
|
||||
putFloatBigEndianUnaligned(a, x);
|
||||
return Float.BYTES;
|
||||
}
|
||||
|
||||
static int putDouble(long a, double x) {
|
||||
if (unalignedAccess || isAddressAligned(a, Double.BYTES)) {
|
||||
putDouble_(a, x);
|
||||
return Double.BYTES;
|
||||
}
|
||||
putDoubleBigEndianUnaligned(a, x);
|
||||
return Double.BYTES;
|
||||
}
|
||||
}
|
||||
116
jdkSrc/jdk8/jdk/jfr/internal/ChunkInputStream.java
Normal file
116
jdkSrc/jdk8/jdk/jfr/internal/ChunkInputStream.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
final class ChunkInputStream extends InputStream {
|
||||
private final Iterator<RepositoryChunk> chunks;
|
||||
private RepositoryChunk currentChunk;
|
||||
private InputStream stream;
|
||||
|
||||
ChunkInputStream(List<RepositoryChunk> chunks) throws IOException {
|
||||
List<RepositoryChunk> l = new ArrayList<>(chunks.size());
|
||||
for (RepositoryChunk c : chunks) {
|
||||
c.use(); // keep alive while we're reading.
|
||||
l.add(c);
|
||||
}
|
||||
|
||||
this.chunks = l.iterator();
|
||||
nextStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
if (stream != null) {
|
||||
return stream.available();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean nextStream() throws IOException {
|
||||
if (!nextChunk()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
stream = new BufferedInputStream(SecuritySupport.newFileInputStream(currentChunk.getFile()));
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean nextChunk() {
|
||||
if (!chunks.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
currentChunk = chunks.next();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
while (true) {
|
||||
if (stream != null) {
|
||||
int r = stream.read();
|
||||
if (r != -1) {
|
||||
return r;
|
||||
}
|
||||
stream.close();
|
||||
currentChunk.release();
|
||||
stream = null;
|
||||
currentChunk = null;
|
||||
}
|
||||
if (!nextStream()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
stream = null;
|
||||
}
|
||||
while (currentChunk != null) {
|
||||
currentChunk.release();
|
||||
currentChunk = null;
|
||||
if (!nextChunk()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close();
|
||||
}
|
||||
}
|
||||
148
jdkSrc/jdk8/jdk/jfr/internal/ChunksChannel.java
Normal file
148
jdkSrc/jdk8/jdk/jfr/internal/ChunksChannel.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
final class ChunksChannel implements ReadableByteChannel {
|
||||
private final Iterator<RepositoryChunk> chunks;
|
||||
private RepositoryChunk current;
|
||||
private ReadableByteChannel channel;
|
||||
|
||||
public ChunksChannel(List<RepositoryChunk> chunks) throws IOException {
|
||||
if (chunks.isEmpty()) {
|
||||
throw new FileNotFoundException("No chunks");
|
||||
}
|
||||
List<RepositoryChunk> l = new ArrayList<>(chunks.size());
|
||||
for (RepositoryChunk c : chunks) {
|
||||
c.use(); // keep alive while we're reading.
|
||||
l.add(c);
|
||||
}
|
||||
this.chunks = l.iterator();
|
||||
nextChannel();
|
||||
}
|
||||
|
||||
private boolean nextChunk() {
|
||||
if (!chunks.hasNext()) {
|
||||
return false;
|
||||
}
|
||||
current = chunks.next();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean nextChannel() throws IOException {
|
||||
if (!nextChunk()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
channel = current.newChannel();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer dst) throws IOException {
|
||||
for (;;) {
|
||||
if (channel != null) {
|
||||
assert current != null;
|
||||
int r = channel.read(dst);
|
||||
if (r != -1) {
|
||||
return r;
|
||||
}
|
||||
channel.close();
|
||||
current.release();
|
||||
channel = null;
|
||||
current = null;
|
||||
}
|
||||
if (!nextChannel()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long transferTo(FileChannel out) throws IOException {
|
||||
long pos = 0;
|
||||
for (;;) {
|
||||
if (channel != null) {
|
||||
assert current != null;
|
||||
|
||||
long rem = current.getSize();
|
||||
while (rem > 0) {
|
||||
long n = Math.min(rem, 1024 * 1024);
|
||||
long w = out.transferFrom(channel, pos, n);
|
||||
// Prevent endless loop
|
||||
if (w == 0) {
|
||||
return out.size();
|
||||
}
|
||||
pos += w;
|
||||
rem -= w;
|
||||
}
|
||||
|
||||
channel.close();
|
||||
current.release();
|
||||
|
||||
channel = null;
|
||||
current = null;
|
||||
}
|
||||
if (!nextChannel()) {
|
||||
return out.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (channel != null) {
|
||||
channel.close();
|
||||
channel = null;
|
||||
}
|
||||
while (current != null) {
|
||||
current.release();
|
||||
current = null;
|
||||
if (!nextChunk()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return channel != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
close();
|
||||
}
|
||||
}
|
||||
209
jdkSrc/jdk8/jdk/jfr/internal/Control.java
Normal file
209
jdkSrc/jdk8/jdk/jfr/internal/Control.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
// User must never be able to subclass directly.
|
||||
//
|
||||
// Never put Control or Setting Control in a collections
|
||||
// so overridable versions of hashCode or equals are
|
||||
// executed in the wrong context. TODO: wrap this class
|
||||
// in SsecureControl directly when it is instantiated and
|
||||
// forward calls using AccessControlContext
|
||||
abstract public class Control {
|
||||
private final AccessControlContext context;
|
||||
private final static int CACHE_SIZE = 5;
|
||||
private final Set<?>[] cachedUnions = new HashSet<?>[CACHE_SIZE];
|
||||
private final String[] cachedValues = new String[CACHE_SIZE];
|
||||
private String defaultValue;
|
||||
private String lastValue;
|
||||
|
||||
// called by exposed subclass in external API
|
||||
public Control(AccessControlContext acc) {
|
||||
Objects.requireNonNull(acc);
|
||||
this.context = acc;
|
||||
|
||||
}
|
||||
|
||||
// only to be called by trusted VM code
|
||||
public Control(String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.context = null;
|
||||
}
|
||||
|
||||
// For user code to override, must never be called from jdk.jfr.internal
|
||||
// for user defined settings
|
||||
public abstract String combine(Set<String> values);
|
||||
|
||||
// For user code to override, must never be called from jdk.jfr.internal
|
||||
// for user defined settings
|
||||
public abstract void setValue(String value);
|
||||
|
||||
// For user code to override, must never be called from jdk.jfr.internal
|
||||
// for user defined settings
|
||||
public abstract String getValue();
|
||||
|
||||
// Package private, user code should not have access to this method
|
||||
final void apply(Set<String> values) {
|
||||
setValueSafe(findCombineSafe(values));
|
||||
}
|
||||
|
||||
// Package private, user code should not have access to this method.
|
||||
// Only called during event registration
|
||||
final void setDefault() {
|
||||
if (defaultValue == null) {
|
||||
defaultValue = getValueSafe();
|
||||
}
|
||||
apply(defaultValue);
|
||||
}
|
||||
|
||||
final String getValueSafe() {
|
||||
if (context == null) {
|
||||
// VM events requires no access control context
|
||||
return getValue();
|
||||
} else {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
try {
|
||||
return getValue();
|
||||
} catch (Throwable t) {
|
||||
// Prevent malicious user to propagate exception callback in the wrong context
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when trying to get value for " + getClass());
|
||||
}
|
||||
return defaultValue != null ? defaultValue : ""; // Need to return something
|
||||
}
|
||||
}, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void apply(String value) {
|
||||
if (lastValue != null && Objects.equals(value, lastValue)) {
|
||||
return;
|
||||
}
|
||||
setValueSafe(value);
|
||||
}
|
||||
|
||||
final void setValueSafe(String value) {
|
||||
if (context == null) {
|
||||
// VM events requires no access control context
|
||||
try {
|
||||
setValue(value);
|
||||
} catch (Throwable t) {
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when setting value \"" + value + "\" for " + getClass());
|
||||
}
|
||||
} else {
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
try {
|
||||
setValue(value);
|
||||
} catch (Throwable t) {
|
||||
// Prevent malicious user to propagate exception callback in the wrong context
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when setting value \"" + value + "\" for " + getClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, context);
|
||||
}
|
||||
lastValue = value;
|
||||
}
|
||||
|
||||
|
||||
private String combineSafe(Set<String> values) {
|
||||
if (context == null) {
|
||||
// VM events requires no access control context
|
||||
return combine(values);
|
||||
}
|
||||
return AccessController.doPrivileged(new PrivilegedAction<String>() {
|
||||
@Override
|
||||
public String run() {
|
||||
try {
|
||||
combine(Collections.unmodifiableSet(values));
|
||||
} catch (Throwable t) {
|
||||
// Prevent malicious user to propagate exception callback in the wrong context
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occured when combining " + values + " for " + getClass());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}, context);
|
||||
}
|
||||
|
||||
private final String findCombineSafe(Set<String> values) {
|
||||
if (values.size() == 1) {
|
||||
return values.iterator().next();
|
||||
}
|
||||
for (int i = 0; i < CACHE_SIZE; i++) {
|
||||
if (Objects.equals(cachedUnions[i], values)) {
|
||||
return cachedValues[i];
|
||||
}
|
||||
}
|
||||
String result = combineSafe(values);
|
||||
for (int i = 0; i < CACHE_SIZE - 1; i++) {
|
||||
cachedUnions[i + 1] = cachedUnions[i];
|
||||
cachedValues[i + 1] = cachedValues[i];
|
||||
}
|
||||
cachedValues[0] = result;
|
||||
cachedUnions[0] = values;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// package private, user code should not have access to this method
|
||||
final String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// package private, user code should not have access to this method
|
||||
final String getLastValue() {
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
// Precaution to prevent a malicious user from instantiating instances
|
||||
// of a control where the context has not been set up.
|
||||
@Override
|
||||
public final Object clone() throws java.lang.CloneNotSupportedException {
|
||||
throw new CloneNotSupportedException();
|
||||
}
|
||||
|
||||
private final void writeObject(ObjectOutputStream out) throws IOException {
|
||||
throw new IOException("Object cannot be serialized");
|
||||
}
|
||||
|
||||
private final void readObject(ObjectInputStream in) throws IOException {
|
||||
throw new IOException("Class cannot be deserialized");
|
||||
}
|
||||
}
|
||||
75
jdkSrc/jdk8/jdk/jfr/internal/Cutoff.java
Normal file
75
jdkSrc/jdk8/jdk/jfr/internal/Cutoff.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import jdk.jfr.MetadataDefinition;
|
||||
|
||||
/**
|
||||
* Event annotation, determines the cutoff above which an event should not be
|
||||
* recorded, i.e. {@code "20 ms"}.
|
||||
*
|
||||
* This settings is only supported for JVM events,
|
||||
*
|
||||
* @Since 8
|
||||
*/
|
||||
@MetadataDefinition
|
||||
@Target({ ElementType.TYPE })
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Cutoff {
|
||||
/**
|
||||
* Settings name {@code "cutoff"} for configuring event cutoffs.
|
||||
*/
|
||||
public final static String NAME = "cutoff";
|
||||
public final static String INIFITY = "infinity";
|
||||
|
||||
/**
|
||||
* Cutoff, for example {@code "20 ms"}.
|
||||
* <p>
|
||||
* String representation of a positive {@code Long} value followed by an empty
|
||||
* space and one of the following units<br>
|
||||
* <br>
|
||||
* {@code "ns"} (nanoseconds)<br>
|
||||
* {@code "us"} (microseconds)<br>
|
||||
* {@code "ms"} (milliseconds)<br>
|
||||
* {@code "s"} (seconds)<br>
|
||||
* {@code "m"} (minutes)<br>
|
||||
* {@code "h"} (hours)<br>
|
||||
* {@code "d"} (days)<br>
|
||||
* <p>
|
||||
* Example values, {@code "0 ns"}, {@code "10 ms"} and {@code "1 s"}. If the
|
||||
* events has an infinite timespan, the text {@code"infinity"} should be used.
|
||||
*
|
||||
* @return the threshold, default {@code "0 ns"} not {@code null}
|
||||
*/
|
||||
String value() default "inifity";
|
||||
}
|
||||
142
jdkSrc/jdk8/jdk/jfr/internal/EventClassBuilder.java
Normal file
142
jdkSrc/jdk8/jdk/jfr/internal/EventClassBuilder.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter;
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
|
||||
|
||||
// Helper class for building dynamic events
|
||||
public final class EventClassBuilder {
|
||||
|
||||
private static final Type TYPE_EVENT = Type.getType(Event.class);
|
||||
private static final Type TYPE_IOBE = Type.getType(IndexOutOfBoundsException.class);
|
||||
private static final Method DEFAULT_CONSTRUCTOR = Method.getMethod("void <init> ()");
|
||||
private static final Method SET_METHOD = Method.getMethod("void set (int, java.lang.Object)");
|
||||
private static final AtomicLong idCounter = new AtomicLong();
|
||||
private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
private final String fullClassName;
|
||||
private final Type type;
|
||||
private final List<ValueDescriptor> fields;
|
||||
private final List<AnnotationElement> annotationElements;
|
||||
|
||||
public EventClassBuilder(List<AnnotationElement> annotationElements, List<ValueDescriptor> fields) {
|
||||
this.fullClassName = "jdk.jfr.DynamicEvent" + idCounter.incrementAndGet();
|
||||
this.type = Type.getType(fullClassName.replace(".", "/"));
|
||||
this.fields = fields;
|
||||
this.annotationElements = annotationElements;
|
||||
}
|
||||
|
||||
public Class<? extends Event> build() {
|
||||
buildClassInfo();
|
||||
buildConstructor();
|
||||
buildFields();
|
||||
buildSetMethod();
|
||||
endClass();
|
||||
byte[] bytes = classWriter.toByteArray();
|
||||
ASMToolkit.logASM(fullClassName, bytes);
|
||||
return SecuritySupport.defineClass(type.getInternalName(), bytes, Event.class.getClassLoader()).asSubclass(Event.class);
|
||||
}
|
||||
|
||||
private void endClass() {
|
||||
classWriter.visitEnd();
|
||||
}
|
||||
|
||||
private void buildSetMethod() {
|
||||
GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, SET_METHOD, null, null, classWriter);
|
||||
int index = 0;
|
||||
for (ValueDescriptor v : fields) {
|
||||
ga.loadArg(0);
|
||||
ga.visitLdcInsn(index);
|
||||
Label notEqual = new Label();
|
||||
ga.ifICmp(GeneratorAdapter.NE, notEqual);
|
||||
ga.loadThis();
|
||||
ga.loadArg(1);
|
||||
Type fieldType = ASMToolkit.toType(v);
|
||||
ga.unbox(ASMToolkit.toType(v));
|
||||
ga.putField(type, v.getName(), fieldType);
|
||||
ga.visitInsn(Opcodes.RETURN);
|
||||
ga.visitLabel(notEqual);
|
||||
index++;
|
||||
}
|
||||
ga.throwException(TYPE_IOBE, "Index must between 0 and " + fields.size());
|
||||
ga.endMethod();
|
||||
}
|
||||
|
||||
private void buildConstructor() {
|
||||
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null);
|
||||
mv.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
ASMToolkit.invokeSpecial(mv, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
}
|
||||
|
||||
private void buildClassInfo() {
|
||||
String internalSuperName = ASMToolkit.getInternalName(Event.class.getName());
|
||||
String internalClassName = type.getInternalName();
|
||||
classWriter.visit(52, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
|
||||
|
||||
for (AnnotationElement a : annotationElements) {
|
||||
String descriptor = ASMToolkit.getDescriptor(a.getTypeName());
|
||||
AnnotationVisitor av = classWriter.visitAnnotation(descriptor, true);
|
||||
for (ValueDescriptor v : a.getValueDescriptors()) {
|
||||
Object value = a.getValue(v.getName());
|
||||
String name = v.getName();
|
||||
if (v.isArray()) {
|
||||
AnnotationVisitor arrayVisitor = av.visitArray(name);
|
||||
Object[] array = (Object[]) value;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
arrayVisitor.visit(null, array[i]);
|
||||
}
|
||||
arrayVisitor.visitEnd();
|
||||
} else {
|
||||
av.visit(name, value);
|
||||
}
|
||||
}
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFields() {
|
||||
for (ValueDescriptor v : fields) {
|
||||
String internal = ASMToolkit.getDescriptor(v.getTypeName());
|
||||
classWriter.visitField(Opcodes.ACC_PRIVATE, v.getName(), internal, null, null);
|
||||
// No need to store annotations on field since they will be replaced anyway.
|
||||
}
|
||||
}
|
||||
}
|
||||
291
jdkSrc/jdk8/jdk/jfr/internal/EventControl.java
Normal file
291
jdkSrc/jdk8/jdk/jfr/internal/EventControl.java
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.SettingControl;
|
||||
import jdk.jfr.SettingDefinition;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.events.ActiveSettingEvent;
|
||||
import jdk.jfr.internal.EventInstrumentation.SettingInfo;
|
||||
import jdk.jfr.internal.settings.CutoffSetting;
|
||||
import jdk.jfr.internal.settings.EnabledSetting;
|
||||
import jdk.jfr.internal.settings.PeriodSetting;
|
||||
import jdk.jfr.internal.settings.StackTraceSetting;
|
||||
import jdk.jfr.internal.settings.ThresholdSetting;
|
||||
|
||||
// This class can't have a hard reference from PlatformEventType, since it
|
||||
// holds SettingControl instances that need to be released
|
||||
// when a class is unloaded (to avoid memory leaks).
|
||||
public final class EventControl {
|
||||
|
||||
static final String FIELD_SETTING_PREFIX = "setting";
|
||||
private static final Type TYPE_ENABLED = TypeLibrary.createType(EnabledSetting.class);
|
||||
private static final Type TYPE_THRESHOLD = TypeLibrary.createType(ThresholdSetting.class);
|
||||
private static final Type TYPE_STACK_TRACE = TypeLibrary.createType(StackTraceSetting.class);
|
||||
private static final Type TYPE_PERIOD = TypeLibrary.createType(PeriodSetting.class);
|
||||
private static final Type TYPE_CUTOFF = TypeLibrary.createType(CutoffSetting.class);
|
||||
|
||||
private final List<SettingInfo> settingInfos = new ArrayList<>();
|
||||
private final Map<String, Control> eventControls = new HashMap<>(5);
|
||||
private final PlatformEventType type;
|
||||
private final String idName;
|
||||
|
||||
EventControl(PlatformEventType eventType) {
|
||||
eventControls.put(Enabled.NAME, defineEnabled(eventType));
|
||||
if (eventType.hasDuration()) {
|
||||
eventControls.put(Threshold.NAME, defineThreshold(eventType));
|
||||
}
|
||||
if (eventType.hasStackTrace()) {
|
||||
eventControls.put(StackTrace.NAME, defineStackTrace(eventType));
|
||||
}
|
||||
if (eventType.hasPeriod()) {
|
||||
eventControls.put(Period.NAME, definePeriod(eventType));
|
||||
}
|
||||
if (eventType.hasCutoff()) {
|
||||
eventControls.put(Cutoff.NAME, defineCutoff(eventType));
|
||||
}
|
||||
|
||||
ArrayList<AnnotationElement> aes = new ArrayList<>(eventType.getAnnotationElements());
|
||||
remove(eventType, aes, Threshold.class);
|
||||
remove(eventType, aes, Period.class);
|
||||
remove(eventType, aes, Enabled.class);
|
||||
remove(eventType, aes, StackTrace.class);
|
||||
remove(eventType, aes, Cutoff.class);
|
||||
aes.trimToSize();
|
||||
eventType.setAnnotations(aes);
|
||||
this.type = eventType;
|
||||
this.idName = String.valueOf(eventType.getId());
|
||||
}
|
||||
|
||||
static void remove(PlatformEventType type, List<AnnotationElement> aes, Class<? extends java.lang.annotation.Annotation> clazz) {
|
||||
long id = Type.getTypeId(clazz);
|
||||
for (AnnotationElement a : type.getAnnotationElements()) {
|
||||
if (a.getTypeId() == id && a.getTypeName().equals(clazz.getName())) {
|
||||
aes.remove(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EventControl(PlatformEventType es, Class<? extends Event> eventClass) {
|
||||
this(es);
|
||||
defineSettings(eventClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void defineSettings(Class<?> eventClass) {
|
||||
// Iterate up the class hierarchy and let
|
||||
// subclasses shadow base classes.
|
||||
boolean allowPrivateMethod = true;
|
||||
while (eventClass != null) {
|
||||
for (Method m : eventClass.getDeclaredMethods()) {
|
||||
boolean isPrivate = Modifier.isPrivate(m.getModifiers());
|
||||
if (m.getReturnType() == Boolean.TYPE && m.getParameterCount() == 1 && (!isPrivate || allowPrivateMethod)) {
|
||||
SettingDefinition se = m.getDeclaredAnnotation(SettingDefinition.class);
|
||||
if (se != null) {
|
||||
Class<?> settingClass = m.getParameters()[0].getType();
|
||||
if (!Modifier.isAbstract(settingClass.getModifiers()) && SettingControl.class.isAssignableFrom(settingClass)) {
|
||||
String name = m.getName();
|
||||
Name n = m.getAnnotation(Name.class);
|
||||
if (n != null) {
|
||||
name = n.value();
|
||||
}
|
||||
if (!eventControls.containsKey(name)) {
|
||||
defineSetting((Class<? extends SettingControl>) settingClass, m, type, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
eventClass = eventClass.getSuperclass();
|
||||
allowPrivateMethod = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void defineSetting(Class<? extends SettingControl> settingsClass, Method method, PlatformEventType eventType, String settingName) {
|
||||
try {
|
||||
int index = settingInfos.size();
|
||||
SettingInfo si = new SettingInfo(FIELD_SETTING_PREFIX + index, index);
|
||||
si.settingControl = instantiateSettingControl(settingsClass);
|
||||
Control c = si.settingControl;
|
||||
c.setDefault();
|
||||
String defaultValue = c.getValueSafe();
|
||||
if (defaultValue != null) {
|
||||
Type settingType = TypeLibrary.createType(settingsClass);
|
||||
ArrayList<AnnotationElement> aes = new ArrayList<>();
|
||||
for (Annotation a : method.getDeclaredAnnotations()) {
|
||||
AnnotationElement ae = TypeLibrary.createAnnotation(a);
|
||||
if (ae != null) {
|
||||
aes.add(ae);
|
||||
}
|
||||
}
|
||||
aes.trimToSize();
|
||||
eventControls.put(settingName, si.settingControl);
|
||||
eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, settingName, defaultValue, aes));
|
||||
settingInfos.add(si);
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
// Programming error by user, fail fast
|
||||
throw new InstantiationError("Could not instantiate setting " + settingsClass.getName() + " for event " + eventType.getLogName() + ". " + e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
// Programming error by user, fail fast
|
||||
throw new IllegalAccessError("Could not access setting " + settingsClass.getName() + " for event " + eventType.getLogName() + ". " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private SettingControl instantiateSettingControl(Class<? extends SettingControl> settingControlClass) throws IllegalAccessException, InstantiationException {
|
||||
SecuritySupport.makeVisibleToJFR(settingControlClass);
|
||||
final Constructor<?> cc;
|
||||
try {
|
||||
cc = settingControlClass.getDeclaredConstructors()[0];
|
||||
} catch (Exception e) {
|
||||
throw (Error) new InternalError("Could not get constructor for " + settingControlClass.getName()).initCause(e);
|
||||
}
|
||||
SecuritySupport.setAccessible(cc);
|
||||
try {
|
||||
return (SettingControl) cc.newInstance();
|
||||
} catch (IllegalArgumentException | InvocationTargetException e) {
|
||||
throw (Error) new InternalError("Could not instantiate setting for class " + settingControlClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static Control defineEnabled(PlatformEventType type) {
|
||||
Enabled enabled = type.getAnnotation(Enabled.class);
|
||||
// Java events are enabled by default,
|
||||
// JVM events are not, maybe they should be? Would lower learning curve
|
||||
// there too.
|
||||
String def = type.isJVM() ? "false" : "true";
|
||||
if (enabled != null) {
|
||||
def = Boolean.toString(enabled.value());
|
||||
}
|
||||
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_ENABLED, Enabled.NAME, def, Collections.emptyList()));
|
||||
return new EnabledSetting(type, def);
|
||||
}
|
||||
|
||||
private static Control defineThreshold(PlatformEventType type) {
|
||||
Threshold threshold = type.getAnnotation(Threshold.class);
|
||||
String def = "0 ns";
|
||||
if (threshold != null) {
|
||||
def = threshold.value();
|
||||
}
|
||||
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_THRESHOLD, Threshold.NAME, def, Collections.emptyList()));
|
||||
return new ThresholdSetting(type, def);
|
||||
}
|
||||
|
||||
private static Control defineStackTrace(PlatformEventType type) {
|
||||
StackTrace stackTrace = type.getAnnotation(StackTrace.class);
|
||||
String def = "true";
|
||||
if (stackTrace != null) {
|
||||
def = Boolean.toString(stackTrace.value());
|
||||
}
|
||||
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_STACK_TRACE, StackTrace.NAME, def, Collections.emptyList()));
|
||||
return new StackTraceSetting(type, def);
|
||||
}
|
||||
|
||||
private static Control defineCutoff(PlatformEventType type) {
|
||||
Cutoff cutoff = type.getAnnotation(Cutoff.class);
|
||||
String def = Cutoff.INIFITY;
|
||||
if (cutoff != null) {
|
||||
def = cutoff.value();
|
||||
}
|
||||
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_CUTOFF, Cutoff.NAME, def, Collections.emptyList()));
|
||||
return new CutoffSetting(type, def);
|
||||
}
|
||||
|
||||
|
||||
private static Control definePeriod(PlatformEventType type) {
|
||||
Period period = type.getAnnotation(Period.class);
|
||||
String def = "everyChunk";
|
||||
if (period != null) {
|
||||
def = period.value();
|
||||
}
|
||||
type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_PERIOD, PeriodSetting.NAME, def, Collections.emptyList()));
|
||||
return new PeriodSetting(type, def);
|
||||
}
|
||||
|
||||
void disable() {
|
||||
for (Control c : eventControls.values()) {
|
||||
if (c instanceof EnabledSetting) {
|
||||
c.setValueSafe("false");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeActiveSettingEvent() {
|
||||
if (!type.isRegistered()) {
|
||||
return;
|
||||
}
|
||||
for (Map.Entry<String, Control> entry : eventControls.entrySet()) {
|
||||
Control c = entry.getValue();
|
||||
if (Utils.isSettingVisible(c, type.hasEventHook())) {
|
||||
String value = c.getLastValue();
|
||||
if (value == null) {
|
||||
value = c.getDefaultValue();
|
||||
}
|
||||
ActiveSettingEvent ase = new ActiveSettingEvent();
|
||||
ase.id = type.getId();
|
||||
ase.name = entry.getKey();
|
||||
ase.value = value;
|
||||
ase.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Entry<String, Control>> getEntries() {
|
||||
return eventControls.entrySet();
|
||||
}
|
||||
|
||||
public PlatformEventType getEventType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getSettingsId() {
|
||||
return idName;
|
||||
}
|
||||
|
||||
public List<SettingInfo> getSettingInfos() {
|
||||
return settingInfos;
|
||||
}
|
||||
}
|
||||
338
jdkSrc/jdk8/jdk/jfr/internal/EventHandlerCreator.java
Normal file
338
jdkSrc/jdk8/jdk/jfr/internal/EventHandlerCreator.java
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.SettingControl;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.EventInstrumentation.FieldInfo;
|
||||
import jdk.jfr.internal.EventInstrumentation.SettingInfo;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
|
||||
final class EventHandlerCreator {
|
||||
// TODO:
|
||||
// How can we find out class version without loading a
|
||||
// class as resource in a privileged block and use ASM to inspect
|
||||
// the contents. Using '52' even though we know later versions
|
||||
// are available. The reason for this is compatibility aspects
|
||||
// with for example WLS.
|
||||
private static final int CLASS_VERSION = 52;
|
||||
|
||||
// This is needed so a new EventHandler is automatically generated in MetadataRespoistory
|
||||
// if a user Event class is loaded using APPCDS/CDS.
|
||||
private static final String SUFFIX = "_" + System.currentTimeMillis() + "-" + JVM.getJVM().getPid();
|
||||
|
||||
private static final String FIELD_EVENT_TYPE = "platformEventType";
|
||||
private static final String FIELD_PREFIX_STRING_POOL = "stringPool";
|
||||
|
||||
private final static Class<? extends EventHandler> eventHandlerProxy = EventHandlerProxyCreator.proxyClass;
|
||||
private final static Type TYPE_STRING_POOL = Type.getType(StringPool.class);
|
||||
private final static Type TYPE_EVENT_WRITER = Type.getType(EventWriter.class);
|
||||
private final static Type TYPE_PLATFORM_EVENT_TYPE = Type.getType(PlatformEventType.class);
|
||||
private final static Type TYPE_EVENT_HANDLER = Type.getType(eventHandlerProxy);
|
||||
private final static Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
|
||||
private final static Type TYPE_EVENT_TYPE = Type.getType(EventType.class);
|
||||
private final static Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class);
|
||||
private final static String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V";
|
||||
private final static Method METHOD_GET_EVENT_WRITER = new Method("getEventWriter", "()" + TYPE_EVENT_WRITER.getDescriptor());
|
||||
private final static Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("<init>", DESCRIPTOR_EVENT_HANDLER);
|
||||
private final static Method METHOD_RESET = new Method("reset", "()V");
|
||||
|
||||
private final ClassWriter classWriter;
|
||||
private final String className;
|
||||
private final String internalClassName;
|
||||
private final List<SettingInfo> settingInfos;
|
||||
private final List<FieldInfo> fields;
|
||||
|
||||
public EventHandlerCreator(long id, List<SettingInfo> settingInfos, List<FieldInfo> fields) {
|
||||
this.classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
this.className = makeEventHandlerName(id);
|
||||
this.internalClassName = ASMToolkit.getInternalName(className);
|
||||
this.settingInfos = settingInfos;
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public static String makeEventHandlerName(long id) {
|
||||
return eventHandlerProxy.getName() + id + SUFFIX;
|
||||
}
|
||||
|
||||
public EventHandlerCreator(long id, List<SettingInfo> settingInfos, EventType type, Class<? extends Event> eventClass) {
|
||||
this(id, settingInfos, createFieldInfos(eventClass, type));
|
||||
}
|
||||
|
||||
private static List<FieldInfo> createFieldInfos(Class<? extends Event> eventClass, EventType type) throws Error {
|
||||
List<FieldInfo> fieldInfos = new ArrayList<>();
|
||||
for (ValueDescriptor v : type.getFields()) {
|
||||
// Only value descriptors that are not fields on the event class.
|
||||
if (v != TypeLibrary.STACK_TRACE_FIELD && v != TypeLibrary.THREAD_FIELD) {
|
||||
String fieldName = PrivateAccess.getInstance().getFieldName(v);
|
||||
String fieldDescriptor = ASMToolkit.getDescriptor(v.getTypeName());
|
||||
Class<?> c = eventClass;
|
||||
String internalName = null;
|
||||
while (c != Event.class) {
|
||||
try {
|
||||
Field field = c.getDeclaredField(fieldName);
|
||||
if (c == eventClass || !Modifier.isPrivate(field.getModifiers())) {
|
||||
internalName = ASMToolkit.getInternalName(c.getName());
|
||||
break;
|
||||
}
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
// ignore
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
if (internalName != null) {
|
||||
fieldInfos.add(new FieldInfo(fieldName, fieldDescriptor, internalName));
|
||||
} else {
|
||||
throw new InternalError("Could not locate field " + fieldName + " for event type" + type.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldInfos;
|
||||
}
|
||||
|
||||
public Class<? extends EventHandler> makeEventHandlerClass() {
|
||||
buildClassInfo();
|
||||
buildConstructor();
|
||||
buildWriteMethod();
|
||||
byte[] bytes = classWriter.toByteArray();
|
||||
ASMToolkit.logASM(className, bytes);
|
||||
return SecuritySupport.defineClass(className, bytes, Event.class.getClassLoader()).asSubclass(EventHandler.class);
|
||||
}
|
||||
|
||||
public static EventHandler instantiateEventHandler(Class<? extends EventHandler> handlerClass, boolean registered, EventType eventType, EventControl eventControl) throws Error {
|
||||
final Constructor<?> cc;
|
||||
try {
|
||||
cc = handlerClass.getDeclaredConstructors()[0];
|
||||
} catch (Exception e) {
|
||||
throw (Error) new InternalError("Could not get handler constructor for " + eventType.getName()).initCause(e);
|
||||
}
|
||||
// Users should not be allowed to create instances of the event handler
|
||||
// so we need to unlock it here.
|
||||
SecuritySupport.setAccessible(cc);
|
||||
try {
|
||||
List<SettingInfo> settingInfos = eventControl.getSettingInfos();
|
||||
Object[] arguments = new Object[3 + settingInfos.size()];
|
||||
arguments[0] = registered;
|
||||
arguments[1] = eventType;
|
||||
arguments[2] = eventControl;
|
||||
for (SettingInfo si : settingInfos) {
|
||||
arguments[si.index + 3] = si.settingControl;
|
||||
}
|
||||
return (EventHandler) cc.newInstance(arguments);
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
throw (Error) new InternalError("Could not instantiate event handler for " + eventType.getName() + ". " + e.getMessage()).initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildConstructor() {
|
||||
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PRIVATE, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(settingInfos), null, null);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0); // this
|
||||
mv.visitVarInsn(Opcodes.ILOAD, 1); // registered
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 2); // event type
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 3); // event control
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(eventHandlerProxy), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false);
|
||||
for (SettingInfo si : settingInfos) {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0); // this
|
||||
mv.visitVarInsn(Opcodes.ALOAD, si.index + 4); // Setting Control
|
||||
mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
|
||||
}
|
||||
// initialized string field writers
|
||||
int fieldIndex = 0;
|
||||
for (FieldInfo field : fields) {
|
||||
if (field.isString()) {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(eventHandlerProxy), "createStringFieldWriter", "()" + TYPE_STRING_POOL.getDescriptor(), false);
|
||||
mv.visitFieldInsn(Opcodes.PUTFIELD, internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
|
||||
}
|
||||
fieldIndex++;
|
||||
}
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void buildClassInfo() {
|
||||
String internalSuperName = ASMToolkit.getInternalName(eventHandlerProxy.getName());
|
||||
classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
|
||||
for (SettingInfo si : settingInfos) {
|
||||
classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor(), null, null);
|
||||
}
|
||||
int fieldIndex = 0;
|
||||
for (FieldInfo field : fields) {
|
||||
if (field.isString()) {
|
||||
classWriter.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, FIELD_PREFIX_STRING_POOL+ fieldIndex, TYPE_STRING_POOL.getDescriptor(), null, null);
|
||||
}
|
||||
fieldIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
private void visitMethod(final MethodVisitor mv, final int opcode, final Type type, final Method method) {
|
||||
mv.visitMethodInsn(opcode, type.getInternalName(), method.getName(), method.getDescriptor(), false);
|
||||
}
|
||||
|
||||
private void buildWriteMethod() {
|
||||
int argIndex = 0; // // indexes the argument type array, the argument type array does not include 'this'
|
||||
int slotIndex = 1; // indexes the proper slot in the local variable table, takes type size into account, therefore sometimes argIndex != slotIndex
|
||||
int fieldIndex = 0;
|
||||
Method desc = ASMToolkit.makeWriteMethod(fields);
|
||||
Type[] argumentTypes = Type.getArgumentTypes(desc.getDescriptor());
|
||||
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, desc.getName(), desc.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
Label start = new Label();
|
||||
Label endTryBlock = new Label();
|
||||
Label exceptionHandler = new Label();
|
||||
mv.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable");
|
||||
mv.visitLabel(start);
|
||||
visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
|
||||
// stack: [BW]
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
// write begin event
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
// stack: [BW], [BW], [this]
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, TYPE_EVENT_HANDLER.getInternalName(), FIELD_EVENT_TYPE, TYPE_PLATFORM_EVENT_TYPE.getDescriptor());
|
||||
// stack: [BW], [BW], [BS]
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM());
|
||||
// stack: [BW], [integer]
|
||||
Label recursive = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, recursive);
|
||||
// stack: [BW]
|
||||
// write startTime
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
|
||||
// stack: [BW], [BW], [long]
|
||||
slotIndex += argumentTypes[argIndex++].getSize();
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
|
||||
// stack: [BW]
|
||||
fieldIndex++;
|
||||
// write duration
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
|
||||
// stack: [BW], [BW], [long]
|
||||
slotIndex += argumentTypes[argIndex++].getSize();
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM());
|
||||
// stack: [BW]
|
||||
fieldIndex++;
|
||||
// write eventThread
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM());
|
||||
// stack: [BW]
|
||||
// write stackTrace
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM());
|
||||
// stack: [BW]
|
||||
// write custom fields
|
||||
while (fieldIndex < fields.size()) {
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [BW], [BW]
|
||||
mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex);
|
||||
// stack:[BW], [BW], [field]
|
||||
slotIndex += argumentTypes[argIndex++].getSize();
|
||||
FieldInfo field = fields.get(fieldIndex);
|
||||
if (field.isString()) {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
// stack:[BW], [BW], [field], [this]
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, this.internalClassName, FIELD_PREFIX_STRING_POOL + fieldIndex, TYPE_STRING_POOL.getDescriptor());
|
||||
// stack:[BW], [BW], [field], [string]
|
||||
}
|
||||
EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field);
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, eventMethod.asASM());
|
||||
// stack: [BW]
|
||||
fieldIndex++;
|
||||
}
|
||||
// stack: [BW]
|
||||
// write end event (writer already on stack)
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM());
|
||||
// stack [integer]
|
||||
// notified -> restart event write attempt
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, start);
|
||||
// stack:
|
||||
mv.visitLabel(endTryBlock);
|
||||
Label end = new Label();
|
||||
mv.visitJumpInsn(Opcodes.GOTO, end);
|
||||
mv.visitLabel(exceptionHandler);
|
||||
// stack: [ex]
|
||||
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
|
||||
visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
|
||||
// stack: [ex] [BW]
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [ex] [BW] [BW]
|
||||
Label rethrow = new Label();
|
||||
mv.visitJumpInsn(Opcodes.IFNULL, rethrow);
|
||||
// stack: [ex] [BW]
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
// stack: [ex] [BW] [BW]
|
||||
visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET);
|
||||
mv.visitLabel(rethrow);
|
||||
// stack:[ex] [BW]
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] {"java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName()});
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
// stack:[ex]
|
||||
mv.visitInsn(Opcodes.ATHROW);
|
||||
mv.visitLabel(recursive);
|
||||
// stack: [BW]
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName()} );
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
mv.visitLabel(end);
|
||||
// stack:
|
||||
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static String makeConstructorDescriptor(List<SettingInfo> settingsInfos) {
|
||||
StringJoiner constructordescriptor = new StringJoiner("", "(", ")V");
|
||||
constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor());
|
||||
constructordescriptor.add(Type.getType(EventType.class).getDescriptor());
|
||||
constructordescriptor.add(Type.getType(EventControl.class).getDescriptor());
|
||||
for (int i = 0; i < settingsInfos.size(); i++) {
|
||||
constructordescriptor.add(TYPE_SETTING_CONTROL.getDescriptor());
|
||||
}
|
||||
return constructordescriptor.toString();
|
||||
}
|
||||
}
|
||||
126
jdkSrc/jdk8/jdk/jfr/internal/EventHandlerProxyCreator.java
Normal file
126
jdkSrc/jdk8/jdk/jfr/internal/EventHandlerProxyCreator.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Red Hat, Inc.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
|
||||
/*
|
||||
* Generates an EventHandler subclass dynamically, named EventHandlerProxy.
|
||||
* EventHandlerProxy is located in a publicly accessible package (jdk.jfr)
|
||||
* and is used as a superclass for classes generated by EventHandlerCreator.
|
||||
* The rationale behind this scheme is to block access to jdk.jfr.internal
|
||||
* package and sub-packages when there is a SecurityManager installed, while
|
||||
* allowing application-defined event classes to invoke the required internal
|
||||
* APIs.
|
||||
*/
|
||||
final class EventHandlerProxyCreator {
|
||||
private static final int CLASS_VERSION = 52;
|
||||
|
||||
private final static Type TYPE_EVENT_TYPE = Type.getType(EventType.class);
|
||||
private final static Type TYPE_EVENT_CONTROL = Type.getType(EventControl.class);
|
||||
private final static String DESCRIPTOR_EVENT_HANDLER = "(" + Type.BOOLEAN_TYPE.getDescriptor() + TYPE_EVENT_TYPE.getDescriptor() + TYPE_EVENT_CONTROL.getDescriptor() + ")V";
|
||||
private final static Method METHOD_EVENT_HANDLER_CONSTRUCTOR = new Method("<init>", DESCRIPTOR_EVENT_HANDLER);
|
||||
private final static String DESCRIPTOR_TIME_STAMP = "()" + Type.LONG_TYPE.getDescriptor();
|
||||
private final static Method METHOD_TIME_STAMP = new Method("timestamp", DESCRIPTOR_TIME_STAMP);
|
||||
private final static String DESCRIPTOR_DURATION = "(" + Type.LONG_TYPE.getDescriptor() + ")" + Type.LONG_TYPE.getDescriptor();
|
||||
private final static Method METHOD_DURATION = new Method("duration", DESCRIPTOR_DURATION);
|
||||
|
||||
private final static ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
private final static String className = "jdk.jfr.proxy.internal.EventHandlerProxy";
|
||||
private final static String internalClassName = ASMToolkit.getInternalName(className);
|
||||
|
||||
// Create the Proxy class instance after all the previous static fields were initialized (textual order)
|
||||
static final Class<? extends EventHandler> proxyClass = EventHandlerProxyCreator.makeEventHandlerProxyClass();
|
||||
|
||||
static void ensureInitialized() {
|
||||
// trigger clinit which will setup the EventHandlerProxy class.
|
||||
}
|
||||
|
||||
public static Class<? extends EventHandler> makeEventHandlerProxyClass() {
|
||||
buildClassInfo();
|
||||
buildConstructor();
|
||||
buildTimestampMethod();
|
||||
buildDurationMethod();
|
||||
byte[] bytes = classWriter.toByteArray();
|
||||
ASMToolkit.logASM(className, bytes);
|
||||
return SecuritySupport.defineClass(className, bytes, Event.class.getClassLoader()).asSubclass(EventHandler.class);
|
||||
}
|
||||
|
||||
private static void buildConstructor() {
|
||||
MethodVisitor mv = classWriter.visitMethod(0x0, METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), makeConstructorDescriptor(), null, null);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0); // this
|
||||
mv.visitVarInsn(Opcodes.ILOAD, 1); // registered
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 2); // event type
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 3); // event control
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(EventHandler.class), METHOD_EVENT_HANDLER_CONSTRUCTOR.getName(), METHOD_EVENT_HANDLER_CONSTRUCTOR.getDescriptor(), false);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static void buildClassInfo() {
|
||||
String internalSuperName = ASMToolkit.getInternalName(EventHandler.class.getName());
|
||||
classWriter.visit(CLASS_VERSION, Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null);
|
||||
}
|
||||
|
||||
private static void buildTimestampMethod() {
|
||||
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
|
||||
mv.visitInsn(Opcodes.LRETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static void buildDurationMethod() {
|
||||
MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), null, null);
|
||||
mv.visitCode();
|
||||
mv.visitVarInsn(Opcodes.LLOAD, 0);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(EventHandler.class), METHOD_DURATION.getName(), METHOD_DURATION.getDescriptor(), false);
|
||||
mv.visitInsn(Opcodes.LRETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private static String makeConstructorDescriptor() {
|
||||
StringJoiner constructordescriptor = new StringJoiner("", "(", ")V");
|
||||
constructordescriptor.add(Type.BOOLEAN_TYPE.getDescriptor());
|
||||
constructordescriptor.add(Type.getType(EventType.class).getDescriptor());
|
||||
constructordescriptor.add(Type.getType(EventControl.class).getDescriptor());
|
||||
return constructordescriptor.toString();
|
||||
}
|
||||
}
|
||||
528
jdkSrc/jdk8/jdk/jfr/internal/EventInstrumentation.java
Normal file
528
jdkSrc/jdk8/jdk/jfr/internal/EventInstrumentation.java
Normal file
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.internal.org.objectweb.asm.tree.AnnotationNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.ClassNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.FieldNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Registered;
|
||||
import jdk.jfr.SettingControl;
|
||||
import jdk.jfr.SettingDefinition;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
|
||||
/**
|
||||
* Class responsible for adding instrumentation to a subclass of {@link Event}.
|
||||
*
|
||||
*/
|
||||
public final class EventInstrumentation {
|
||||
static final class SettingInfo {
|
||||
private String methodName;
|
||||
private String internalSettingName;
|
||||
private String settingDescriptor;
|
||||
final String fieldName;
|
||||
final int index;
|
||||
// Used when instantiating Setting
|
||||
SettingControl settingControl;
|
||||
|
||||
public SettingInfo(String fieldName, int index) {
|
||||
this.fieldName = fieldName;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
|
||||
static final class FieldInfo {
|
||||
private final static Type STRING = Type.getType(String.class);
|
||||
final String fieldName;
|
||||
final String fieldDescriptor;
|
||||
final String internalClassName;
|
||||
|
||||
public FieldInfo(String fieldName, String fieldDescriptor, String internalClassName) {
|
||||
this.fieldName = fieldName;
|
||||
this.fieldDescriptor = fieldDescriptor;
|
||||
this.internalClassName = internalClassName;
|
||||
}
|
||||
|
||||
public boolean isString() {
|
||||
return STRING.getDescriptor().equals(fieldDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
public static final String FIELD_EVENT_THREAD = "eventThread";
|
||||
public static final String FIELD_STACK_TRACE = "stackTrace";
|
||||
public static final String FIELD_DURATION = "duration";
|
||||
|
||||
static final String FIELD_EVENT_HANDLER = "eventHandler";
|
||||
static final String FIELD_START_TIME = "startTime";
|
||||
|
||||
private static final Class<? extends EventHandler> eventHandlerProxy = EventHandlerProxyCreator.proxyClass;
|
||||
private static final Type ANNOTATION_TYPE_NAME = Type.getType(Name.class);
|
||||
private static final Type ANNOTATION_TYPE_REGISTERED = Type.getType(Registered.class);
|
||||
private static final Type ANNOTATION_TYPE_ENABLED = Type.getType(Enabled.class);
|
||||
private static final Type TYPE_EVENT_HANDLER = Type.getType(eventHandlerProxy);
|
||||
private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class);
|
||||
private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]);
|
||||
private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]);
|
||||
private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]);
|
||||
private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]);
|
||||
private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]);
|
||||
private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]);
|
||||
private static final Method METHOD_EVENT_HANDLER_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE });
|
||||
private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE });
|
||||
|
||||
private final ClassNode classNode;
|
||||
private final List<SettingInfo> settingInfos;
|
||||
private final List<FieldInfo> fieldInfos;;
|
||||
private final Method writeMethod;
|
||||
private final String eventHandlerXInternalName;
|
||||
private final String eventName;
|
||||
private boolean guardHandlerReference;
|
||||
private Class<?> superClass;
|
||||
|
||||
EventInstrumentation(Class<?> superClass, byte[] bytes, long id) {
|
||||
this.superClass = superClass;
|
||||
this.classNode = createClassNode(bytes);
|
||||
this.settingInfos = buildSettingInfos(superClass, classNode);
|
||||
this.fieldInfos = buildFieldInfos(superClass, classNode);
|
||||
this.writeMethod = makeWriteMethod(fieldInfos);
|
||||
this.eventHandlerXInternalName = ASMToolkit.getInternalName(EventHandlerCreator.makeEventHandlerName(id));
|
||||
String n = annotationValue(classNode, ANNOTATION_TYPE_NAME.getDescriptor(), String.class);
|
||||
this.eventName = n == null ? classNode.name.replace("/", ".") : n;
|
||||
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return classNode.name.replace("/",".");
|
||||
}
|
||||
|
||||
private ClassNode createClassNode(byte[] bytes) {
|
||||
ClassNode classNode = new ClassNode();
|
||||
ClassReader classReader = new ClassReader(bytes);
|
||||
classReader.accept(classNode, 0);
|
||||
return classNode;
|
||||
}
|
||||
|
||||
boolean isRegistered() {
|
||||
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_REGISTERED.getDescriptor(), Boolean.class);
|
||||
if (result != null) {
|
||||
return result.booleanValue();
|
||||
}
|
||||
if (superClass != null) {
|
||||
Registered r = superClass.getAnnotation(Registered.class);
|
||||
if (r != null) {
|
||||
return r.value();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean isEnabled() {
|
||||
Boolean result = annotationValue(classNode, ANNOTATION_TYPE_ENABLED.getDescriptor(), Boolean.class);
|
||||
if (result != null) {
|
||||
return result.booleanValue();
|
||||
}
|
||||
if (superClass != null) {
|
||||
Enabled e = superClass.getAnnotation(Enabled.class);
|
||||
if (e != null) {
|
||||
return e.value();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T annotationValue(ClassNode classNode, String typeDescriptor, Class<?> type) {
|
||||
if (classNode.visibleAnnotations != null) {
|
||||
for (AnnotationNode a : classNode.visibleAnnotations) {
|
||||
if (typeDescriptor.equals(a.desc)) {
|
||||
List<Object> values = a.values;
|
||||
if (values != null && values.size() == 2) {
|
||||
Object key = values.get(0);
|
||||
Object value = values.get(1);
|
||||
if (key instanceof String && value != null) {
|
||||
if (type == value.getClass()) {
|
||||
String keyName = (String) key;
|
||||
if ("value".equals(keyName)) {
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static List<SettingInfo> buildSettingInfos(Class<?> superClass, ClassNode classNode) {
|
||||
Set<String> methodSet = new HashSet<>();
|
||||
List<SettingInfo> settingInfos = new ArrayList<>();
|
||||
String settingDescriptor = Type.getType(SettingDefinition.class).getDescriptor();
|
||||
for (MethodNode m : classNode.methods) {
|
||||
if (m.visibleAnnotations != null) {
|
||||
for (AnnotationNode an : m.visibleAnnotations) {
|
||||
// We can't really validate the method at this
|
||||
// stage. We would need to check that the parameter
|
||||
// is an instance of SettingControl.
|
||||
if (settingDescriptor.equals(an.desc)) {
|
||||
Type returnType = Type.getReturnType(m.desc);
|
||||
if (returnType.equals(Type.getType(Boolean.TYPE))) {
|
||||
Type[] args = Type.getArgumentTypes(m.desc);
|
||||
if (args.length == 1) {
|
||||
Type paramType = args[0];
|
||||
String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
|
||||
int index = settingInfos.size();
|
||||
SettingInfo si = new SettingInfo(fieldName, index);
|
||||
si.methodName = m.name;
|
||||
si.settingDescriptor = paramType.getDescriptor();
|
||||
si.internalSettingName = paramType.getInternalName();
|
||||
methodSet.add(m.name);
|
||||
settingInfos.add(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
|
||||
for (java.lang.reflect.Method method : c.getDeclaredMethods()) {
|
||||
if (!methodSet.contains(method.getName())) {
|
||||
// skip private method in base classes
|
||||
if (!Modifier.isPrivate(method.getModifiers())) {
|
||||
if (method.getReturnType().equals(Boolean.TYPE)) {
|
||||
if (method.getParameterCount() == 1) {
|
||||
Parameter param = method.getParameters()[0];
|
||||
Type paramType = Type.getType(param.getType());
|
||||
String fieldName = EventControl.FIELD_SETTING_PREFIX + settingInfos.size();
|
||||
int index = settingInfos.size();
|
||||
SettingInfo si = new SettingInfo(fieldName, index);
|
||||
si.methodName = method.getName();
|
||||
si.settingDescriptor = paramType.getDescriptor();
|
||||
si.internalSettingName = paramType.getInternalName();
|
||||
methodSet.add(method.getName());
|
||||
settingInfos.add(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return settingInfos;
|
||||
|
||||
}
|
||||
|
||||
private static List<FieldInfo> buildFieldInfos(Class<?> superClass, ClassNode classNode) {
|
||||
Set<String> fieldSet = new HashSet<>();
|
||||
List<FieldInfo> fieldInfos = new ArrayList<>(classNode.fields.size());
|
||||
// These two field are added by native as transient so they will be
|
||||
// ignored by the loop below.
|
||||
// The benefit of adding them manually is that we can
|
||||
// control in which order they occur and we can add @Name, @Description
|
||||
// in Java, instead of in native. It also means code for adding implicit
|
||||
// fields for native can be reused by Java.
|
||||
fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||
fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor(), classNode.name));
|
||||
for (FieldNode field : classNode.fields) {
|
||||
String className = Type.getType(field.desc).getClassName();
|
||||
if (!fieldSet.contains(field.name) && isValidField(field.access, className)) {
|
||||
FieldInfo fi = new FieldInfo(field.name, field.desc, classNode.name);
|
||||
fieldInfos.add(fi);
|
||||
fieldSet.add(field.name);
|
||||
}
|
||||
}
|
||||
for (Class<?> c = superClass; c != Event.class; c = c.getSuperclass()) {
|
||||
for (Field field : c.getDeclaredFields()) {
|
||||
// skip private field in base classes
|
||||
if (!Modifier.isPrivate(field.getModifiers())) {
|
||||
if (isValidField(field.getModifiers(), field.getType().getName())) {
|
||||
String fieldName = field.getName();
|
||||
if (!fieldSet.contains(fieldName)) {
|
||||
Type fieldType = Type.getType(field.getType());
|
||||
String internalClassName = ASMToolkit.getInternalName(c.getName());
|
||||
fieldInfos.add(new FieldInfo(fieldName, fieldType.getDescriptor(), internalClassName));
|
||||
fieldSet.add(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldInfos;
|
||||
}
|
||||
|
||||
public static boolean isValidField(int access, String className) {
|
||||
if (Modifier.isTransient(access) || Modifier.isStatic(access)) {
|
||||
return false;
|
||||
}
|
||||
return jdk.jfr.internal.Type.isValidJavaFieldType(className);
|
||||
}
|
||||
|
||||
public byte[] buildInstrumented() {
|
||||
makeInstrumented();
|
||||
return toByteArray();
|
||||
}
|
||||
|
||||
private byte[] toByteArray() {
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
classNode.accept(cw);
|
||||
cw.visitEnd();
|
||||
byte[] result = cw.toByteArray();
|
||||
Utils.writeGeneratedASM(classNode.name, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte[] builUninstrumented() {
|
||||
makeUninstrumented();
|
||||
return toByteArray();
|
||||
}
|
||||
|
||||
private void makeInstrumented() {
|
||||
// MyEvent#isEnabled()
|
||||
updateMethod(METHOD_IS_ENABLED, methodVisitor -> {
|
||||
Label nullLabel = new Label();
|
||||
if (guardHandlerReference) {
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel);
|
||||
}
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, TYPE_EVENT_HANDLER.getDescriptor());
|
||||
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_IS_ENABLED);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
if (guardHandlerReference) {
|
||||
methodVisitor.visitLabel(nullLabel);
|
||||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
methodVisitor.visitInsn(Opcodes.ICONST_0);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
}
|
||||
});
|
||||
|
||||
// MyEvent#begin()
|
||||
updateMethod(METHOD_BEGIN, methodVisitor -> {
|
||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP);
|
||||
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
});
|
||||
|
||||
// MyEvent#end()
|
||||
updateMethod(METHOD_END, methodVisitor -> {
|
||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
|
||||
ASMToolkit.invokeStatic(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_DURATION);
|
||||
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
methodVisitor.visitMaxs(0, 0);
|
||||
});
|
||||
|
||||
// MyEvent#commit() - Java event writer
|
||||
updateMethod(METHOD_COMMIT, methodVisitor -> {
|
||||
// if (!isEnable()) {
|
||||
// return;
|
||||
// }
|
||||
methodVisitor.visitCode();
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false);
|
||||
Label l0 = new Label();
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNE, l0);
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
methodVisitor.visitLabel(l0);
|
||||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
// if (startTime == 0) {
|
||||
// startTime = EventWriter.timestamp();
|
||||
// } else {
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
|
||||
methodVisitor.visitInsn(Opcodes.LCONST_0);
|
||||
methodVisitor.visitInsn(Opcodes.LCMP);
|
||||
Label durationalEvent = new Label();
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent);
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(),
|
||||
METHOD_TIME_STAMP.getDescriptor(), false);
|
||||
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J");
|
||||
Label commit = new Label();
|
||||
methodVisitor.visitJumpInsn(Opcodes.GOTO, commit);
|
||||
// if (duration == 0) {
|
||||
// duration = EventWriter.timestamp() - startTime;
|
||||
// }
|
||||
// }
|
||||
methodVisitor.visitLabel(durationalEvent);
|
||||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
||||
methodVisitor.visitInsn(Opcodes.LCONST_0);
|
||||
methodVisitor.visitInsn(Opcodes.LCMP);
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNE, commit);
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_HANDLER.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false);
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J");
|
||||
methodVisitor.visitInsn(Opcodes.LSUB);
|
||||
methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
||||
methodVisitor.visitLabel(commit);
|
||||
// if (shouldCommit()) {
|
||||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT.getName(), METHOD_EVENT_SHOULD_COMMIT.getDescriptor(), false);
|
||||
Label end = new Label();
|
||||
// eventHandler.write(...);
|
||||
// }
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFEQ, end);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy));
|
||||
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||
for (FieldInfo fi : fieldInfos) {
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, fi.internalClassName, fi.fieldName, fi.fieldDescriptor);
|
||||
}
|
||||
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, eventHandlerXInternalName, writeMethod.getName(), writeMethod.getDescriptor(), false);
|
||||
methodVisitor.visitLabel(end);
|
||||
methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
methodVisitor.visitEnd();
|
||||
});
|
||||
|
||||
// MyEvent#shouldCommit()
|
||||
updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> {
|
||||
Label fail = new Label();
|
||||
// if (!eventHandler.shoouldCommit(duration) goto fail;
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy));
|
||||
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J");
|
||||
ASMToolkit.invokeVirtual(methodVisitor, TYPE_EVENT_HANDLER.getInternalName(), METHOD_EVENT_HANDLER_SHOULD_COMMIT);
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
|
||||
for (SettingInfo si : settingInfos) {
|
||||
// if (!settingsMethod(eventHandler.settingX)) goto fail;
|
||||
methodVisitor.visitIntInsn(Opcodes.ALOAD, 0);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_HANDLER, Type.getDescriptor(eventHandlerProxy));
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, eventHandlerXInternalName);
|
||||
methodVisitor.visitFieldInsn(Opcodes.GETFIELD, eventHandlerXInternalName, si.fieldName, TYPE_SETTING_CONTROL.getDescriptor());
|
||||
methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.internalSettingName);
|
||||
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.settingDescriptor + ")Z", false);
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail);
|
||||
}
|
||||
// return true
|
||||
methodVisitor.visitInsn(Opcodes.ICONST_1);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
// return false
|
||||
methodVisitor.visitLabel(fail);
|
||||
methodVisitor.visitInsn(Opcodes.ICONST_0);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
});
|
||||
}
|
||||
|
||||
private void makeUninstrumented() {
|
||||
updateExistingWithReturnFalse(METHOD_EVENT_SHOULD_COMMIT);
|
||||
updateExistingWithReturnFalse(METHOD_IS_ENABLED);
|
||||
updateExistingWithEmptyVoidMethod(METHOD_COMMIT);
|
||||
updateExistingWithEmptyVoidMethod(METHOD_BEGIN);
|
||||
updateExistingWithEmptyVoidMethod(METHOD_END);
|
||||
}
|
||||
|
||||
private final void updateExistingWithEmptyVoidMethod(Method voidMethod) {
|
||||
updateMethod(voidMethod, methodVisitor -> {
|
||||
methodVisitor.visitInsn(Opcodes.RETURN);
|
||||
});
|
||||
}
|
||||
|
||||
private final void updateExistingWithReturnFalse(Method voidMethod) {
|
||||
updateMethod(voidMethod, methodVisitor -> {
|
||||
methodVisitor.visitInsn(Opcodes.ICONST_0);
|
||||
methodVisitor.visitInsn(Opcodes.IRETURN);
|
||||
});
|
||||
}
|
||||
|
||||
private MethodNode getMethodNode(Method method) {
|
||||
for (MethodNode m : classNode.methods) {
|
||||
if (m.name.equals(method.getName()) && m.desc.equals(method.getDescriptor())) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final void updateMethod(Method method, Consumer<MethodVisitor> code) {
|
||||
MethodNode old = getMethodNode(method);
|
||||
int index = classNode.methods.indexOf(old);
|
||||
classNode.methods.remove(old);
|
||||
MethodVisitor mv = classNode.visitMethod(old.access, old.name, old.desc, null, null);
|
||||
mv.visitCode();
|
||||
code.accept(mv);
|
||||
mv.visitMaxs(0, 0);
|
||||
MethodNode newMethod = getMethodNode(method);
|
||||
classNode.methods.remove(newMethod);
|
||||
classNode.methods.add(index, newMethod);
|
||||
}
|
||||
|
||||
public static Method makeWriteMethod(List<FieldInfo> fields) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("(");
|
||||
for (FieldInfo v : fields) {
|
||||
sb.append(v.fieldDescriptor);
|
||||
}
|
||||
sb.append(")V");
|
||||
return new Method("write", sb.toString());
|
||||
}
|
||||
|
||||
private String getInternalClassName() {
|
||||
return classNode.name;
|
||||
}
|
||||
|
||||
public List<SettingInfo> getSettingInfos() {
|
||||
return settingInfos;
|
||||
}
|
||||
|
||||
public List<FieldInfo> getFieldInfos() {
|
||||
return fieldInfos;
|
||||
}
|
||||
|
||||
public String getEventName() {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
public void setGuardHandler(boolean guardHandlerReference) {
|
||||
this.guardHandlerReference = guardHandlerReference;
|
||||
}
|
||||
}
|
||||
355
jdkSrc/jdk8/jdk/jfr/internal/EventWriter.java
Normal file
355
jdkSrc/jdk8/jdk/jfr/internal/EventWriter.java
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Class must reside in a package with package restriction.
|
||||
*
|
||||
* Users should not have direct access to underlying memory.
|
||||
*
|
||||
*/
|
||||
public final class EventWriter {
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private final static JVM jvm = JVM.getJVM();
|
||||
|
||||
private long startPosition;
|
||||
private long startPositionAddress;
|
||||
private long currentPosition;
|
||||
private long maxPosition;
|
||||
private final long threadID;
|
||||
private PlatformEventType eventType;
|
||||
private int maxEventSize;
|
||||
private boolean started;
|
||||
private boolean valid;
|
||||
private boolean flushOnEnd;
|
||||
// set by the JVM, not private to avoid being optimized out
|
||||
boolean notified;
|
||||
|
||||
public static EventWriter getEventWriter() {
|
||||
EventWriter ew = (EventWriter)JVM.getEventWriter();
|
||||
return ew != null ? ew : JVM.newEventWriter();
|
||||
}
|
||||
|
||||
public void putBoolean(boolean i) {
|
||||
if (isValidForSize(Byte.BYTES)) {
|
||||
currentPosition += Bits.putBoolean(currentPosition, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void putByte(byte i) {
|
||||
if (isValidForSize(Byte.BYTES)) {
|
||||
unsafe.putByte(currentPosition, i);
|
||||
++currentPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public void putChar(char v) {
|
||||
if (isValidForSize(Character.BYTES + 1)) {
|
||||
putUncheckedLong(v);
|
||||
}
|
||||
}
|
||||
|
||||
private void putUncheckedChar(char v) {
|
||||
putUncheckedLong(v);
|
||||
}
|
||||
|
||||
public void putShort(short v) {
|
||||
if (isValidForSize(Short.BYTES + 1)) {
|
||||
putUncheckedLong(v & 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
public void putInt(int v) {
|
||||
if (isValidForSize(Integer.BYTES + 1)) {
|
||||
putUncheckedLong(v & 0x00000000ffffffffL);
|
||||
}
|
||||
}
|
||||
|
||||
private void putUncheckedInt(int v) {
|
||||
putUncheckedLong(v & 0x00000000ffffffffL);
|
||||
}
|
||||
|
||||
public void putFloat(float i) {
|
||||
if (isValidForSize(Float.BYTES)) {
|
||||
currentPosition += Bits.putFloat(currentPosition, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void putLong(long v) {
|
||||
if (isValidForSize(Long.BYTES + 1)) {
|
||||
putUncheckedLong(v);
|
||||
}
|
||||
}
|
||||
|
||||
public void putDouble(double i) {
|
||||
if (isValidForSize(Double.BYTES)) {
|
||||
currentPosition += Bits.putDouble(currentPosition, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void putString(String s, StringPool pool) {
|
||||
if (s == null) {
|
||||
putByte(RecordingInput.STRING_ENCODING_NULL);
|
||||
return;
|
||||
}
|
||||
int length = s.length();
|
||||
if (length == 0) {
|
||||
putByte(RecordingInput.STRING_ENCODING_EMPTY_STRING);
|
||||
return;
|
||||
}
|
||||
if (length > StringPool.MIN_LIMIT && length < StringPool.MAX_LIMIT) {
|
||||
long l = StringPool.addString(s);
|
||||
if (l > 0) {
|
||||
putByte(RecordingInput.STRING_ENCODING_CONSTANT_POOL);
|
||||
putLong(l);
|
||||
return;
|
||||
}
|
||||
}
|
||||
putStringValue(s);
|
||||
return;
|
||||
}
|
||||
|
||||
private void putStringValue(String s) {
|
||||
int length = s.length();
|
||||
if (isValidForSize(1 + 5 + 3 * length)) {
|
||||
putUncheckedByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // 1 byte
|
||||
putUncheckedInt(length); // max 5 bytes
|
||||
for (int i = 0; i < length; i++) {
|
||||
putUncheckedChar(s.charAt(i)); // max 3 bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void putEventThread() {
|
||||
putLong(threadID);
|
||||
}
|
||||
|
||||
public void putThread(Thread athread) {
|
||||
if (athread == null) {
|
||||
putLong(0L);
|
||||
} else {
|
||||
putLong(jvm.getThreadId(athread));
|
||||
}
|
||||
}
|
||||
|
||||
public void putClass(Class<?> aClass) {
|
||||
if (aClass == null) {
|
||||
putLong(0L);
|
||||
} else {
|
||||
putLong(JVM.getClassIdNonIntrinsic(aClass));
|
||||
}
|
||||
}
|
||||
|
||||
public void putStackTrace() {
|
||||
if (eventType.getStackTraceEnabled()) {
|
||||
putLong(jvm.getStackTraceId(eventType.getStackTraceOffset()));
|
||||
} else {
|
||||
putLong(0L);
|
||||
}
|
||||
}
|
||||
|
||||
private void reserveEventSizeField() {
|
||||
// move currentPosition Integer.Bytes offset from start position
|
||||
if (isValidForSize(Integer.BYTES)) {
|
||||
currentPosition += Integer.BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
currentPosition = startPosition;
|
||||
if (flushOnEnd) {
|
||||
flushOnEnd = flush();
|
||||
}
|
||||
valid = true;
|
||||
started = false;
|
||||
}
|
||||
|
||||
private boolean isValidForSize(int requestedSize) {
|
||||
if (!valid) {
|
||||
return false;
|
||||
}
|
||||
if (currentPosition + requestedSize > maxPosition) {
|
||||
flushOnEnd = flush(usedSize(), requestedSize);
|
||||
// retry
|
||||
if (currentPosition + requestedSize > maxPosition) {
|
||||
Logger.log(LogTag.JFR_SYSTEM,
|
||||
LogLevel.WARN, () ->
|
||||
"Unable to commit. Requested size " + requestedSize + " too large");
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isNotified() {
|
||||
return notified;
|
||||
}
|
||||
|
||||
private void resetNotified() {
|
||||
notified = false;
|
||||
}
|
||||
|
||||
private int usedSize() {
|
||||
return (int) (currentPosition - startPosition);
|
||||
}
|
||||
|
||||
private boolean flush() {
|
||||
return flush(usedSize(), 0);
|
||||
}
|
||||
|
||||
private boolean flush(int usedSize, int requestedSize) {
|
||||
return JVM.flush(this, usedSize, requestedSize);
|
||||
}
|
||||
|
||||
public boolean beginEvent(PlatformEventType eventType) {
|
||||
if (started) {
|
||||
// recursive write attempt
|
||||
return false;
|
||||
}
|
||||
started = true;
|
||||
this.eventType = eventType;
|
||||
reserveEventSizeField();
|
||||
putLong(eventType.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean endEvent() {
|
||||
if (!valid) {
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
final int eventSize = usedSize();
|
||||
if (eventSize > maxEventSize) {
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
Bits.putInt(startPosition, makePaddedInt(eventSize));
|
||||
if (isNotified()) {
|
||||
resetNotified();
|
||||
reset();
|
||||
// returning false will trigger restart of the event write attempt
|
||||
return false;
|
||||
}
|
||||
startPosition = currentPosition;
|
||||
unsafe.putAddress(startPositionAddress, startPosition);
|
||||
// the event is now committed
|
||||
if (flushOnEnd) {
|
||||
flushOnEnd = flush();
|
||||
}
|
||||
started = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private EventWriter(long startPos, long maxPos, long startPosAddress, long threadID, boolean valid) {
|
||||
startPosition = currentPosition = startPos;
|
||||
maxPosition = maxPos;
|
||||
startPositionAddress = startPosAddress;
|
||||
this.threadID = threadID;
|
||||
started = false;
|
||||
flushOnEnd = false;
|
||||
this.valid = valid;
|
||||
notified = false;
|
||||
// event may not exceed size for a padded integer
|
||||
maxEventSize = (1 << 28) -1;
|
||||
}
|
||||
|
||||
private static int makePaddedInt(int v) {
|
||||
// bit 0-6 + pad => bit 24 - 31
|
||||
long b1 = (((v >>> 0) & 0x7F) | 0x80) << 24;
|
||||
|
||||
// bit 7-13 + pad => bit 16 - 23
|
||||
long b2 = (((v >>> 7) & 0x7F) | 0x80) << 16;
|
||||
|
||||
// bit 14-20 + pad => bit 8 - 15
|
||||
long b3 = (((v >>> 14) & 0x7F) | 0x80) << 8;
|
||||
|
||||
// bit 21-28 => bit 0 - 7
|
||||
long b4 = (((v >>> 21) & 0x7F)) << 0;
|
||||
|
||||
return (int) (b1 + b2 + b3 + b4);
|
||||
}
|
||||
|
||||
private void putUncheckedLong(long v) {
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 0-6
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 0-6
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 7-13
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 7-13
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 14-20
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 14-20
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 21-27
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 21-27
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 28-34
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 28-34
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 35-41
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 35-41
|
||||
v >>>= 7;
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 42-48
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 42-48
|
||||
v >>>= 7;
|
||||
|
||||
if ((v & ~0x7FL) == 0L) {
|
||||
putUncheckedByte((byte) v); // 49-55
|
||||
return;
|
||||
}
|
||||
putUncheckedByte((byte) (v | 0x80L)); // 49-55
|
||||
putUncheckedByte((byte) (v >>> 7)); // 56-63, last byte as is.
|
||||
}
|
||||
|
||||
private void putUncheckedByte(byte i) {
|
||||
unsafe.putByte(currentPosition, i);
|
||||
++currentPosition;
|
||||
}
|
||||
}
|
||||
81
jdkSrc/jdk8/jdk/jfr/internal/EventWriterMethod.java
Normal file
81
jdkSrc/jdk8/jdk/jfr/internal/EventWriterMethod.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.commons.Method;
|
||||
import jdk.jfr.internal.EventInstrumentation.FieldInfo;
|
||||
|
||||
public enum EventWriterMethod {
|
||||
|
||||
BEGIN_EVENT("(" + jdk.internal.org.objectweb.asm.Type.getType(PlatformEventType.class).getDescriptor() + ")Z", "???", "beginEvent"),
|
||||
END_EVENT("()Z", "???", "endEvent"),
|
||||
PUT_BYTE("(B)V", "byte", "putByte"),
|
||||
PUT_SHORT("(S)V", "short", "putShort"),
|
||||
PUT_INT("(I)V", "int", "putInt"),
|
||||
PUT_LONG("(J)V", "long", "putLong"),
|
||||
PUT_FLOAT("(F)V", "float", "putFloat"),
|
||||
PUT_DOUBLE("(D)V", "double", "putDouble"),
|
||||
PUT_CHAR("(C)V", "char", "putChar"),
|
||||
PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"),
|
||||
PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"),
|
||||
PUT_CLASS("(Ljava/lang/Class;)V", Type.CLASS.getName(), "putClass"),
|
||||
PUT_STRING("(Ljava/lang/String;Ljdk/jfr/internal/StringPool;)V", Type.STRING.getName(), "putString"),
|
||||
PUT_EVENT_THREAD("()V", Type.THREAD.getName(), "putEventThread"),
|
||||
PUT_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace");
|
||||
|
||||
private final Method asmMethod;
|
||||
private final String typeDescriptor;
|
||||
|
||||
EventWriterMethod(String paramSignature, String typeName, String methodName) {
|
||||
this.typeDescriptor = ASMToolkit.getDescriptor(typeName);
|
||||
this.asmMethod = new Method(methodName, paramSignature);
|
||||
}
|
||||
|
||||
public Method asASM() {
|
||||
return asmMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return method in {@link EventWriter} class to use when writing event of
|
||||
* a certain type.
|
||||
*
|
||||
* @param v field info
|
||||
*
|
||||
* @return the method
|
||||
*/
|
||||
public static EventWriterMethod lookupMethod(FieldInfo v) {
|
||||
// event thread
|
||||
if (v.fieldName.equals(EventInstrumentation.FIELD_EVENT_THREAD)) {
|
||||
return EventWriterMethod.PUT_EVENT_THREAD;
|
||||
}
|
||||
for (EventWriterMethod m : EventWriterMethod.values()) {
|
||||
if (v.fieldDescriptor.equals(m.typeDescriptor)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
throw new Error("Unknown type " + v.fieldDescriptor);
|
||||
}
|
||||
}
|
||||
535
jdkSrc/jdk8/jdk/jfr/internal/JVM.java
Normal file
535
jdkSrc/jdk8/jdk/jfr/internal/JVM.java
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
|
||||
/**
|
||||
* Interface against the JVM.
|
||||
*
|
||||
*/
|
||||
public final class JVM {
|
||||
private static final JVM jvm = new JVM();
|
||||
|
||||
// JVM signals file changes by doing Object#notifu on this object
|
||||
static final Object FILE_DELTA_CHANGE = new Object();
|
||||
|
||||
static final long RESERVED_CLASS_ID_LIMIT = 400;
|
||||
|
||||
private volatile boolean recording;
|
||||
private volatile boolean nativeOK;
|
||||
|
||||
private static native void registerNatives();
|
||||
|
||||
static {
|
||||
registerNatives();
|
||||
// XXX
|
||||
// for (LogTag tag : LogTag.values()) {
|
||||
// subscribeLogLevel(tag, tag.id);
|
||||
// }
|
||||
Options.ensureInitialized();
|
||||
EventHandlerProxyCreator.ensureInitialized();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the one and only JVM.
|
||||
*
|
||||
* @return the JVM
|
||||
*/
|
||||
public static JVM getJVM() {
|
||||
return jvm;
|
||||
}
|
||||
|
||||
private JVM() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin recording events
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*/
|
||||
public native void beginRecording();
|
||||
|
||||
/**
|
||||
* Return ticks
|
||||
*
|
||||
* @return the time, in ticks
|
||||
*
|
||||
*/
|
||||
// @HotSpotIntrinsicCandidate
|
||||
public static native long counterTime();
|
||||
|
||||
|
||||
/**
|
||||
* Emits native periodic event.
|
||||
*
|
||||
* @param eventTypeId type id
|
||||
*
|
||||
* @param timestamp commit time for event
|
||||
* @param when when it is being done {@link Periodic.When}
|
||||
*
|
||||
* @return true if the event was committed
|
||||
*/
|
||||
public native boolean emitEvent(long eventTypeId, long timestamp, long when);
|
||||
|
||||
/**
|
||||
* End recording events, which includes flushing data in thread buffers
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*
|
||||
*/
|
||||
public native void endRecording();
|
||||
|
||||
/**
|
||||
* Return a list of all classes deriving from {@link Event}
|
||||
*
|
||||
* @return list of event classes.
|
||||
*/
|
||||
public native List<Class<? extends Event>> getAllEventClasses();
|
||||
|
||||
/**
|
||||
* Return a count of the number of unloaded classes deriving from {@link Event}
|
||||
*
|
||||
* @return number of unloaded event classes.
|
||||
*/
|
||||
public native long getUnloadedEventClassCount();
|
||||
|
||||
/**
|
||||
* Return a unique identifier for a class. The class is marked as being
|
||||
* "in use" in JFR.
|
||||
*
|
||||
* @param clazz clazz
|
||||
*
|
||||
* @return a unique class identifier
|
||||
*/
|
||||
// @HotSpotIntrinsicCandidate
|
||||
public static native long getClassId(Class<?> clazz);
|
||||
|
||||
// temporary workaround until we solve intrinsics supporting epoch shift tagging
|
||||
public static native long getClassIdNonIntrinsic(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Return process identifier.
|
||||
*
|
||||
* @return process identifier
|
||||
*/
|
||||
public native String getPid();
|
||||
|
||||
/**
|
||||
* Return unique identifier for stack trace.
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*
|
||||
* @param skipCount number of frames to skip
|
||||
* @return a unique stack trace identifier
|
||||
*/
|
||||
public native long getStackTraceId(int skipCount);
|
||||
|
||||
/**
|
||||
* Return identifier for thread
|
||||
*
|
||||
* @param t thread
|
||||
* @return a unique thread identifier
|
||||
*/
|
||||
public native long getThreadId(Thread t);
|
||||
|
||||
/**
|
||||
* Frequency, ticks per second
|
||||
*
|
||||
* @return frequency
|
||||
*/
|
||||
public native long getTicksFrequency();
|
||||
|
||||
/**
|
||||
* Write message to log. Should swallow null or empty message, and be able
|
||||
* to handle any Java character and not crash with very large message
|
||||
*
|
||||
* @param tagSetId the tagset id
|
||||
* @param level on level
|
||||
* @param message log message
|
||||
*
|
||||
*/
|
||||
public static native void log(int tagSetId, int level, String message);
|
||||
|
||||
/**
|
||||
* Check whether the logger would output on the given level
|
||||
*
|
||||
* @param level on level
|
||||
* @return {@literal true} if the logger would output on the given level
|
||||
*/
|
||||
public static native boolean shouldLog(int level);
|
||||
|
||||
/**
|
||||
* Subscribe to LogLevel updates for LogTag
|
||||
*
|
||||
* @param lt the log tag to subscribe
|
||||
* @param tagSetId the tagset id
|
||||
*/
|
||||
public static native void subscribeLogLevel(LogTag lt, int tagSetId);
|
||||
|
||||
/**
|
||||
* Call to invoke event tagging and retransformation of the passed classes
|
||||
*
|
||||
* @param classes
|
||||
*/
|
||||
public native synchronized void retransformClasses(Class<?>[] classes);
|
||||
|
||||
/**
|
||||
* Enable event
|
||||
*
|
||||
* @param eventTypeId event type id
|
||||
*
|
||||
* @param enabled enable event
|
||||
*/
|
||||
public native void setEnabled(long eventTypeId, boolean enabled);
|
||||
|
||||
/**
|
||||
* Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE}
|
||||
*
|
||||
* @param delta number of bytes, reset after file rotation
|
||||
*/
|
||||
public native void setFileNotification(long delta);
|
||||
|
||||
/**
|
||||
* Set the number of global buffers to use
|
||||
*
|
||||
* @param count
|
||||
*
|
||||
* @throws IllegalArgumentException if count is not within a valid range
|
||||
* @throws IllegalStateException if value can't be changed
|
||||
*/
|
||||
public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Set size of a global buffer
|
||||
*
|
||||
* @param size
|
||||
*
|
||||
* @throws IllegalArgumentException if buffer size is not within a valid
|
||||
* range
|
||||
*/
|
||||
public native void setGlobalBufferSize(long size) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Set overall memory size
|
||||
*
|
||||
* @param size
|
||||
*
|
||||
* @throws IllegalArgumentException if memory size is not within a valid
|
||||
* range
|
||||
*/
|
||||
public native void setMemorySize(long size) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Set interval for method samples, in milliseconds.
|
||||
*
|
||||
* Setting interval to 0 turns off the method sampler.
|
||||
*
|
||||
* @param intervalMillis the sampling interval
|
||||
*/
|
||||
public native void setMethodSamplingInterval(long type, long intervalMillis);
|
||||
|
||||
/**
|
||||
* Sets the file where data should be written.
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*
|
||||
* <pre>
|
||||
* Recording Previous Current Action
|
||||
* ==============================================
|
||||
* true null null Ignore, keep recording in-memory
|
||||
* true null file1 Start disk recording
|
||||
* true file null Copy out metadata to disk and continue in-memory recording
|
||||
* true file1 file2 Copy out metadata and start with new File (file2)
|
||||
* false * null Ignore, but start recording to memory with {@link #beginRecording()}
|
||||
* false * file Ignore, but start recording to disk with {@link #beginRecording()}
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* recording can be set to true/false with {@link #beginRecording()}
|
||||
* {@link #endRecording()}
|
||||
*
|
||||
* @param file the file where data should be written, or null if it should
|
||||
* not be copied out (in memory).
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public native void setOutput(String file);
|
||||
|
||||
/**
|
||||
* Controls if a class deriving from jdk.jfr.Event should
|
||||
* always be instrumented on class load.
|
||||
*
|
||||
* @param force, true to force initialization, false otherwise
|
||||
*/
|
||||
public native void setForceInstrumentation(boolean force);
|
||||
|
||||
/**
|
||||
* Turn on/off thread sampling.
|
||||
*
|
||||
* @param sampleThreads true if threads should be sampled, false otherwise.
|
||||
*
|
||||
* @throws IllegalStateException if state can't be changed.
|
||||
*/
|
||||
public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Turn on/off compressed integers.
|
||||
*
|
||||
* @param compressed true if compressed integers should be used, false
|
||||
* otherwise.
|
||||
*
|
||||
* @throws IllegalStateException if state can't be changed.
|
||||
*/
|
||||
public native void setCompressedIntegers(boolean compressed) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Set stack depth.
|
||||
*
|
||||
* @param depth
|
||||
*
|
||||
* @throws IllegalArgumentException if not within a valid range
|
||||
* @throws IllegalStateException if depth can't be changed
|
||||
*/
|
||||
public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Turn on stack trace for an event
|
||||
*
|
||||
* @param eventTypeId the event id
|
||||
*
|
||||
* @param enabled if stack traces should be enabled
|
||||
*/
|
||||
public native void setStackTraceEnabled(long eventTypeId, boolean enabled);
|
||||
|
||||
/**
|
||||
* Set thread buffer size.
|
||||
*
|
||||
* @param size
|
||||
*
|
||||
* @throws IllegalArgumentException if size is not within a valid range
|
||||
* @throws IllegalStateException if size can't be changed
|
||||
*/
|
||||
public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException;
|
||||
|
||||
/**
|
||||
* Set threshold for event,
|
||||
*
|
||||
* Long.MAXIMUM_VALUE = no limit
|
||||
*
|
||||
* @param eventTypeId the id of the event type
|
||||
* @param ticks threshold in ticks,
|
||||
* @return true, if it could be set
|
||||
*/
|
||||
public native boolean setThreshold(long eventTypeId, long ticks);
|
||||
|
||||
/**
|
||||
* Store the metadata descriptor that is to be written at the end of a
|
||||
* chunk, data should be written after GMT offset and size of metadata event
|
||||
* should be adjusted
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*
|
||||
* @param bytes binary representation of metadata descriptor
|
||||
*
|
||||
* @param binary representation of descriptor
|
||||
*/
|
||||
public native void storeMetadataDescriptor(byte[] bytes);
|
||||
|
||||
public void endRecording_() {
|
||||
endRecording();
|
||||
recording = false;
|
||||
}
|
||||
|
||||
public void beginRecording_() {
|
||||
beginRecording();
|
||||
recording = true;
|
||||
}
|
||||
|
||||
public boolean isRecording() {
|
||||
return recording;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the JVM supports JVM TI and retransformation has not been disabled this
|
||||
* method will return true. This flag can not change during the lifetime of
|
||||
* the JVM.
|
||||
*
|
||||
* @return if transform is allowed
|
||||
*/
|
||||
public native boolean getAllowedToDoEventRetransforms();
|
||||
|
||||
/**
|
||||
* Set up native resources, data structures, threads etc. for JFR
|
||||
*
|
||||
* @param simulateFailure simulate a initialization failure and rollback in
|
||||
* native, used for testing purposes
|
||||
*
|
||||
* @throws IllegalStateException if native part of JFR could not be created.
|
||||
*
|
||||
*/
|
||||
private native boolean createJFR(boolean simulateFailure) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Destroys native part of JFR. If already destroy, call is ignored.
|
||||
*
|
||||
* Requires that JFR has been started with {@link #createNativeJFR()}
|
||||
*
|
||||
* @return if an instance was actually destroyed.
|
||||
*
|
||||
*/
|
||||
private native boolean destroyJFR();
|
||||
|
||||
public boolean createFailedNativeJFR() throws IllegalStateException {
|
||||
return createJFR(true);
|
||||
}
|
||||
|
||||
public void createNativeJFR() {
|
||||
nativeOK = createJFR(false);
|
||||
}
|
||||
|
||||
public boolean destroyNativeJFR() {
|
||||
boolean result = destroyJFR();
|
||||
nativeOK = !result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean hasNativeJFR() {
|
||||
return nativeOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cheap test to check if JFR functionality is available.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public native boolean isAvailable();
|
||||
|
||||
/**
|
||||
* To convert ticks to wall clock time.
|
||||
*/
|
||||
public native double getTimeConversionFactor();
|
||||
|
||||
/**
|
||||
* Return a unique identifier for a class. Compared to {@link #getClassId()}
|
||||
* , this method does not tag the class as being "in-use".
|
||||
*
|
||||
* @param clazz class
|
||||
*
|
||||
* @return a unique class identifier
|
||||
*/
|
||||
public native long getTypeId(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Fast path fetching the EventWriter using VM intrinsics
|
||||
*
|
||||
* @return thread local EventWriter
|
||||
*/
|
||||
// @HotSpotIntrinsicCandidate
|
||||
public static native Object getEventWriter();
|
||||
|
||||
/**
|
||||
* Create a new EventWriter
|
||||
*
|
||||
* @return thread local EventWriter
|
||||
*/
|
||||
public static native EventWriter newEventWriter();
|
||||
|
||||
/**
|
||||
* Flushes the EventWriter for this thread.
|
||||
*/
|
||||
public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
|
||||
|
||||
/**
|
||||
* Sets the location of the disk repository, to be used at an emergency
|
||||
* dump.
|
||||
*
|
||||
* @param dirText
|
||||
*/
|
||||
public native void setRepositoryLocation(String dirText);
|
||||
|
||||
/**
|
||||
* Access to VM termination support.
|
||||
*
|
||||
*@param errorMsg descriptive message to be include in VM termination sequence
|
||||
*/
|
||||
public native void abort(String errorMsg);
|
||||
|
||||
/**
|
||||
* Adds a string to the string constant pool.
|
||||
*
|
||||
* If the same string is added twice, two entries will be created.
|
||||
*
|
||||
* @param id identifier associated with the string, not negative
|
||||
*
|
||||
* @param s string constant to be added, not null
|
||||
*
|
||||
* @return the current epoch of this insertion attempt
|
||||
*/
|
||||
public static native boolean addStringConstant(boolean epoch, long id, String s);
|
||||
/**
|
||||
* Gets the address of the jboolean epoch.
|
||||
*
|
||||
* The epoch alternates every checkpoint.
|
||||
*
|
||||
* @return The address of the jboolean.
|
||||
*/
|
||||
public native long getEpochAddress();
|
||||
|
||||
public native void uncaughtException(Thread thread, Throwable t);
|
||||
/**
|
||||
* Sets cutoff for event.
|
||||
*
|
||||
* Determines how long the event should be allowed to run.
|
||||
*
|
||||
* Long.MAXIMUM_VALUE = no limit
|
||||
*
|
||||
* @param eventTypeId the id of the event type
|
||||
* @param cutoffTicks cutoff in ticks,
|
||||
* @return true, if it could be set
|
||||
*/
|
||||
public native boolean setCutoff(long eventTypeId, long cutoffTicks);
|
||||
|
||||
/**
|
||||
* Emit old object sample events.
|
||||
*
|
||||
* @param cutoff the cutoff in ticks
|
||||
* @param emitAll emit all samples in old object queue
|
||||
*/
|
||||
public native void emitOldObjectSamples(long cutoff, boolean emitAll);
|
||||
|
||||
/**
|
||||
* Test if a chunk rotation is warranted.
|
||||
*
|
||||
* @return if it is time to perform a chunk rotation
|
||||
*/
|
||||
public native boolean shouldRotateDisk();
|
||||
}
|
||||
86
jdkSrc/jdk8/jdk/jfr/internal/JVMSupport.java
Normal file
86
jdkSrc/jdk8/jdk/jfr/internal/JVMSupport.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Checks if the running VM supports Flight Recorder.
|
||||
*
|
||||
* Purpose of this helper class is to detect early and cleanly if the VM has
|
||||
* support for Flight Recorder, i.e. not throw {@link UnsatisfiedLinkError} in
|
||||
* unexpected places.
|
||||
* <p>
|
||||
* This is needed so a disabled-jfr.jar can be built for non Oracle JDKs.
|
||||
*/
|
||||
public final class JVMSupport {
|
||||
|
||||
private static final String UNSUPPORTED_VM_MESSAGE = "Flight Recorder is not supported on this VM";
|
||||
private static final boolean notAvailable = !checkAvailability();
|
||||
|
||||
private static boolean checkAvailability() {
|
||||
// set jfr.unsupported.vm to true to test API on an unsupported VM
|
||||
try {
|
||||
if (SecuritySupport.getBooleanProperty("jfr.unsupported.vm")) {
|
||||
return false;
|
||||
}
|
||||
} catch (NoClassDefFoundError cnfe) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
// Will typically throw UnsatisfiedLinkError if
|
||||
// there is no native implementation
|
||||
JVM.getJVM().isAvailable();
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureWithInternalError() {
|
||||
if (notAvailable) {
|
||||
throw new InternalError(UNSUPPORTED_VM_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureWithIOException() throws IOException {
|
||||
if (notAvailable) {
|
||||
throw new IOException(UNSUPPORTED_VM_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureWithIllegalStateException() {
|
||||
if (notAvailable) {
|
||||
throw new IllegalStateException(UNSUPPORTED_VM_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNotAvailable() {
|
||||
return notAvailable;
|
||||
}
|
||||
|
||||
public static void tryToInitializeJVM() {
|
||||
}
|
||||
}
|
||||
152
jdkSrc/jdk8/jdk/jfr/internal/JVMUpcalls.java
Normal file
152
jdkSrc/jdk8/jdk/jfr/internal/JVMUpcalls.java
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
|
||||
/**
|
||||
* All upcalls from the JVM should go through this class.
|
||||
*
|
||||
*/
|
||||
// Called by native
|
||||
final class JVMUpcalls {
|
||||
/**
|
||||
* Called by the JVM when a retransform happens on a tagged class
|
||||
*
|
||||
* @param traceId
|
||||
* Id of the class
|
||||
* @param dummy
|
||||
* (not used but needed since invoke infrastructure in native
|
||||
* uses same signature bytesForEagerInstrumentation)
|
||||
* @param clazz
|
||||
* class being retransformed
|
||||
* @param oldBytes
|
||||
* byte code
|
||||
* @return byte code to use
|
||||
* @throws Throwable
|
||||
*/
|
||||
static byte[] onRetransform(long traceId, boolean dummy, Class<?> clazz, byte[] oldBytes) throws Throwable {
|
||||
try {
|
||||
if (Event.class.isAssignableFrom(clazz) && !Modifier.isAbstract(clazz.getModifiers())) {
|
||||
EventHandler handler = Utils.getHandler(clazz.asSubclass(Event.class));
|
||||
if (handler == null) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "No event handler found for " + clazz.getName() + ". Ignoring instrumentation request.");
|
||||
// Probably triggered by some other agent
|
||||
return oldBytes;
|
||||
}
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform");
|
||||
EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId);
|
||||
byte[] bytes = ei.buildInstrumented();
|
||||
ASMToolkit.logASM(clazz.getName(), bytes);
|
||||
return bytes;
|
||||
}
|
||||
return JDKEvents.retransformCallback(clazz, oldBytes);
|
||||
} catch (Throwable t) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation to event class " + clazz.getName());
|
||||
}
|
||||
return oldBytes;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the JVM when requested to do an "eager" instrumentation. Would
|
||||
* normally happen when JVMTI retransform capabilities are not available.
|
||||
*
|
||||
* @param traceId
|
||||
* Id of the class
|
||||
* @param forceInstrumentation
|
||||
* add instrumentation regardless if event is enabled or not.
|
||||
* @param superClazz
|
||||
* the super class of the class being processed
|
||||
* @param oldBytes
|
||||
* byte code
|
||||
* @return byte code to use
|
||||
* @throws Throwable
|
||||
*/
|
||||
static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrumentation, Class<?> superClass, byte[] oldBytes) throws Throwable {
|
||||
if (JVMSupport.isNotAvailable()) {
|
||||
return oldBytes;
|
||||
}
|
||||
String eventName = "<Unknown>";
|
||||
try {
|
||||
EventInstrumentation ei = new EventInstrumentation(superClass, oldBytes, traceId);
|
||||
eventName = ei.getEventName();
|
||||
if (!forceInstrumentation) {
|
||||
// Assume we are recording
|
||||
MetadataRepository mr = MetadataRepository.getInstance();
|
||||
// No need to generate bytecode if:
|
||||
// 1) Event class is disabled, and there is not an external configuration that overrides.
|
||||
// 2) Event class has @Registered(false)
|
||||
if (!mr.isEnabled(ei.getEventName()) && !ei.isEnabled() || !ei.isRegistered()) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Skipping instrumentation for event type " + eventName + " since event was disabled on class load");
|
||||
return oldBytes;
|
||||
}
|
||||
}
|
||||
// Corner case when we are forced to generate bytecode. We can't reference the event
|
||||
// handler in #isEnabled() before event class has been registered, so we add a
|
||||
// guard against a null reference.
|
||||
ei.setGuardHandler(true);
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load");
|
||||
EventHandlerCreator eh = new EventHandlerCreator(traceId, ei.getSettingInfos(), ei.getFieldInfos());
|
||||
// Handler class must be loaded before instrumented event class can
|
||||
// be used
|
||||
eh.makeEventHandlerClass();
|
||||
byte[] bytes = ei.buildInstrumented();
|
||||
ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes);
|
||||
return bytes;
|
||||
} catch (Throwable t) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName);
|
||||
return oldBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the JVM to create the recorder thread.
|
||||
*
|
||||
* @param systemThreadGroup
|
||||
* the system thread group
|
||||
*
|
||||
* @param contextClassLoader
|
||||
* the context class loader.
|
||||
*
|
||||
* @return a new thread
|
||||
*/
|
||||
static Thread createRecorderThread(ThreadGroup systemThreadGroup, ClassLoader contextClassLoader) {
|
||||
return SecuritySupport.createRecorderThread(systemThreadGroup, contextClassLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the JVM to initialize the EventHandlerProxy class.
|
||||
*
|
||||
* @return the EventHandlerProxy class
|
||||
*/
|
||||
static Class<? extends EventHandler> getEventHandlerProxyClass() {
|
||||
return EventHandlerProxyCreator.proxyClass;
|
||||
}
|
||||
}
|
||||
41
jdkSrc/jdk8/jdk/jfr/internal/LogLevel.java
Normal file
41
jdkSrc/jdk8/jdk/jfr/internal/LogLevel.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
public enum LogLevel {
|
||||
TRACE(1),
|
||||
DEBUG(2),
|
||||
INFO(3),
|
||||
WARN(4),
|
||||
ERROR(5);
|
||||
// must be in sync with JVM levels.
|
||||
|
||||
final int level;
|
||||
|
||||
LogLevel(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
}
|
||||
90
jdkSrc/jdk8/jdk/jfr/internal/LogTag.java
Normal file
90
jdkSrc/jdk8/jdk/jfr/internal/LogTag.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
/* Mapped against c++ enum in jfrLogTagSet.hpp */
|
||||
public enum LogTag {
|
||||
/**
|
||||
* Covers
|
||||
* <ul>
|
||||
* <li>Initialization of Flight Recorder
|
||||
* <li> recording life cycle (start, stop and dump)
|
||||
* <li> repository life cycle
|
||||
* <li>loading of configuration files.
|
||||
* </ul>
|
||||
* Target audience: operations
|
||||
*/
|
||||
JFR(0),
|
||||
/**
|
||||
* Covers general implementation aspects of JFR (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM(1),
|
||||
/**
|
||||
* Covers JVM/JDK events (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM_EVENT(2),
|
||||
/**
|
||||
* Covers setting for the JVM/JDK (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM_SETTING(3),
|
||||
/**
|
||||
* Covers generated bytecode (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM_BYTECODE(4),
|
||||
/**
|
||||
* Covers XML parsing (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM_PARSER(5),
|
||||
/**
|
||||
* Covers metadata for JVM/JDK (for Hotspot developers)
|
||||
*/
|
||||
JFR_SYSTEM_METADATA(6),
|
||||
/**
|
||||
* Covers metadata for Java user (for Hotspot developers)
|
||||
*/
|
||||
JFR_METADATA(7),
|
||||
/**
|
||||
* Covers events (for users of the JDK)
|
||||
*/
|
||||
JFR_EVENT(8),
|
||||
/**
|
||||
* Covers setting (for users of the JDK)
|
||||
*/
|
||||
JFR_SETTING(9),
|
||||
/**
|
||||
* Covers usage of jcmd with JFR
|
||||
*/
|
||||
JFR_DCMD(10);
|
||||
|
||||
/* set from native side */
|
||||
volatile int tagSetLevel = 100; // prevent logging if JVM log system has not been initialized
|
||||
|
||||
final int id;
|
||||
|
||||
LogTag(int tagId) {
|
||||
id = tagId;
|
||||
}
|
||||
}
|
||||
67
jdkSrc/jdk8/jdk/jfr/internal/Logger.java
Normal file
67
jdkSrc/jdk8/jdk/jfr/internal/Logger.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* JFR logger
|
||||
*
|
||||
*/
|
||||
|
||||
public final class Logger {
|
||||
|
||||
private final static int MAX_SIZE = 10000;
|
||||
static {
|
||||
// This will try to initialize the JVM logging system
|
||||
JVMSupport.tryToInitializeJVM();
|
||||
}
|
||||
|
||||
|
||||
public static void log(LogTag logTag, LogLevel logLevel, String message) {
|
||||
if (shouldLog(logTag, logLevel)) {
|
||||
logInternal(logTag, logLevel, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void log(LogTag logTag, LogLevel logLevel, Supplier<String> messageSupplier) {
|
||||
if (shouldLog(logTag, logLevel)) {
|
||||
logInternal(logTag, logLevel, messageSupplier.get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void logInternal(LogTag logTag, LogLevel logLevel, String message) {
|
||||
if (message == null || message.length() < MAX_SIZE) {
|
||||
JVM.log(logTag.id, logLevel.level, message);
|
||||
} else {
|
||||
JVM.log(logTag.id, logLevel.level, message.substring(0, MAX_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldLog(LogTag tag, LogLevel level) {
|
||||
return JVM.shouldLog(level.level);
|
||||
}
|
||||
}
|
||||
273
jdkSrc/jdk8/jdk/jfr/internal/MetadataDescriptor.java
Normal file
273
jdkSrc/jdk8/jdk/jfr/internal/MetadataDescriptor.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
|
||||
/**
|
||||
* Metadata about a chunk
|
||||
*/
|
||||
public final class MetadataDescriptor {
|
||||
|
||||
static final class Attribute {
|
||||
final String name;
|
||||
final String value;
|
||||
|
||||
private Attribute(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
static final class Element {
|
||||
final String name;
|
||||
final List<Element> elements = new ArrayList<>();
|
||||
final List<Attribute> attributes = new ArrayList<>();
|
||||
|
||||
Element(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
long longValue(String name) {
|
||||
String v = attribute(name);
|
||||
if (v != null)
|
||||
return Long.parseLong(v);
|
||||
else
|
||||
throw new IllegalArgumentException(name);
|
||||
}
|
||||
|
||||
String attribute(String name) {
|
||||
for (Attribute a : attributes) {
|
||||
if (a.name.equals(name)) {
|
||||
return a.value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
prettyPrintXML(sb, "", this);
|
||||
} catch (IOException e) {
|
||||
// should not happen
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
long attribute(String name, long defaultValue) {
|
||||
String text = attribute(name);
|
||||
if (text == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return Long.parseLong(text);
|
||||
}
|
||||
|
||||
String attribute(String name, String defaultValue) {
|
||||
String text = attribute(name);
|
||||
if (text == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
List<Element> elements(String... names) {
|
||||
List<Element> filteredElements = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
for (Element e : elements) {
|
||||
if (e.name.equals(name)) {
|
||||
filteredElements.add(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filteredElements;
|
||||
}
|
||||
|
||||
void add(Element element) {
|
||||
elements.add(element);
|
||||
}
|
||||
|
||||
void addAttribute(String name, Object value) {
|
||||
attributes.add(new Attribute(name, String.valueOf(value)));
|
||||
}
|
||||
|
||||
Element newChild(String name) {
|
||||
Element e = new Element(name);
|
||||
elements.add(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
public void addArrayAttribute(Element element, String name, Object value) {
|
||||
String typeName = value.getClass().getComponentType().getName();
|
||||
switch (typeName) {
|
||||
case "int":
|
||||
int[] ints = (int[]) value;
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
addAttribute(name + "-" + i , ints[i]);
|
||||
}
|
||||
break;
|
||||
case "long":
|
||||
long[] longs = (long[]) value;
|
||||
for (int i = 0; i < longs.length; i++) {
|
||||
addAttribute(name + "-" + i , longs[i]);
|
||||
}
|
||||
break;
|
||||
case "float":
|
||||
float[] floats = (float[]) value;
|
||||
for (int i = 0; i < floats.length; i++) {
|
||||
addAttribute(name + "-" + i , floats[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "double":
|
||||
double[] doubles = (double[]) value;
|
||||
for (int i = 0; i < doubles.length; i++) {
|
||||
addAttribute(name + "-" + i , doubles[i]);
|
||||
}
|
||||
break;
|
||||
case "short":
|
||||
short[] shorts = (short[]) value;
|
||||
for (int i = 0; i < shorts.length; i++) {
|
||||
addAttribute(name + "-" + i , shorts[i]);
|
||||
}
|
||||
break;
|
||||
case "char":
|
||||
char[] chars = (char[]) value;
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
addAttribute(name + "-" + i , chars[i]);
|
||||
}
|
||||
break;
|
||||
case "byte":
|
||||
byte[] bytes = (byte[]) value;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
addAttribute(name + "-" + i , bytes[i]);
|
||||
}
|
||||
break;
|
||||
case "boolean":
|
||||
boolean[] booleans = (boolean[]) value;
|
||||
for (int i = 0; i < booleans.length; i++) {
|
||||
addAttribute(name + "-" + i , booleans[i]);
|
||||
}
|
||||
break;
|
||||
case "java.lang.String":
|
||||
String[] strings = (String[]) value;
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
addAttribute(name + "-" + i , strings[i]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Array type of " + typeName + " is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final String ATTRIBUTE_ID = "id";
|
||||
static final String ATTRIBUTE_SIMPLE_TYPE = "simpleType";
|
||||
static final String ATTRIBUTE_GMT_OFFSET = "gmtOffset";
|
||||
static final String ATTRIBUTE_LOCALE = "locale";
|
||||
static final String ELEMENT_TYPE = "class";
|
||||
static final String ELEMENT_SETTING = "setting";
|
||||
static final String ELEMENT_ANNOTATION = "annotation";
|
||||
static final String ELEMENT_FIELD = "field";
|
||||
static final String ATTRIBUTE_SUPER_TYPE = "superType";
|
||||
static final String ATTRIBUTE_TYPE_ID = "class";
|
||||
static final String ATTRIBUTE_DIMENSION = "dimension";
|
||||
static final String ATTRIBUTE_NAME = "name";
|
||||
static final String ATTRIBUTE_CONSTANT_POOL = "constantPool";
|
||||
static final String ATTRIBUTE_DEFAULT_VALUE = "defaultValue";
|
||||
|
||||
final List<EventType> eventTypes = new ArrayList<>();
|
||||
final Collection<Type> types = new ArrayList<>();
|
||||
long gmtOffset;
|
||||
String locale;
|
||||
Element root;
|
||||
|
||||
// package private
|
||||
MetadataDescriptor() {
|
||||
}
|
||||
|
||||
private static void prettyPrintXML(Appendable sb, String indent, Element e) throws IOException {
|
||||
sb.append(indent + "<" + e.name);
|
||||
for (Attribute a : e.attributes) {
|
||||
sb.append(" ").append(a.name).append("=\"").append(a.value).append("\"");
|
||||
}
|
||||
if (e.elements.size() == 0) {
|
||||
sb.append("/");
|
||||
}
|
||||
sb.append(">\n");
|
||||
for (Element child : e.elements) {
|
||||
prettyPrintXML(sb, indent + " ", child);
|
||||
}
|
||||
if (e.elements.size() != 0) {
|
||||
sb.append(indent).append("</").append(e.name).append(">\n");
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Type> getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public List<EventType> getEventTypes() {
|
||||
return eventTypes;
|
||||
}
|
||||
|
||||
public int getGMTOffset() {
|
||||
return (int) gmtOffset;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public static MetadataDescriptor read(DataInput input) throws IOException {
|
||||
MetadataReader r = new MetadataReader(input);
|
||||
return r.getDescriptor();
|
||||
}
|
||||
|
||||
static void write(List<Type> types, DataOutput output) throws IOException {
|
||||
MetadataDescriptor m = new MetadataDescriptor();
|
||||
m.locale = Locale.getDefault().toString();
|
||||
m.gmtOffset = TimeZone.getDefault().getRawOffset();
|
||||
m.types.addAll(types);
|
||||
MetadataWriter w = new MetadataWriter(m);
|
||||
w.writeBinary(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return root.toString();
|
||||
}
|
||||
}
|
||||
421
jdkSrc/jdk8/jdk/jfr/internal/MetadataHandler.java
Normal file
421
jdkSrc/jdk8/jdk/jfr/internal/MetadataHandler.java
Normal file
@@ -0,0 +1,421 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.org.xml.sax.Attributes;
|
||||
import jdk.internal.org.xml.sax.EntityResolver;
|
||||
import jdk.internal.org.xml.sax.SAXException;
|
||||
import jdk.internal.org.xml.sax.helpers.DefaultHandler;
|
||||
import jdk.internal.util.xml.SAXParser;
|
||||
import jdk.internal.util.xml.impl.SAXParserImpl;
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Experimental;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.Relational;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.TransitionFrom;
|
||||
import jdk.jfr.TransitionTo;
|
||||
import jdk.jfr.Unsigned;
|
||||
|
||||
final class MetadataHandler extends DefaultHandler implements EntityResolver {
|
||||
|
||||
static class TypeElement {
|
||||
List<FieldElement> fields = new ArrayList<>();
|
||||
String name;
|
||||
String label;
|
||||
String description;
|
||||
String category;
|
||||
String superType;
|
||||
String period;
|
||||
boolean thread;
|
||||
boolean startTime;
|
||||
boolean stackTrace;
|
||||
boolean cutoff;
|
||||
boolean isEvent;
|
||||
boolean experimental;
|
||||
boolean valueType;
|
||||
}
|
||||
|
||||
static class FieldElement {
|
||||
TypeElement referenceType;
|
||||
String name;
|
||||
String label;
|
||||
String description;
|
||||
String contentType;
|
||||
String typeName;
|
||||
String transition;
|
||||
String relation;
|
||||
boolean struct;
|
||||
boolean array;
|
||||
boolean experimental;
|
||||
boolean unsigned;
|
||||
}
|
||||
|
||||
static class XmlType {
|
||||
String name;
|
||||
String javaType;
|
||||
String contentType;
|
||||
boolean unsigned;
|
||||
}
|
||||
|
||||
final Map<String, TypeElement> types = new LinkedHashMap<>(200);
|
||||
final Map<String, XmlType> xmlTypes = new HashMap<>(20);
|
||||
final Map<String, List<AnnotationElement>> xmlContentTypes = new HashMap<>(20);
|
||||
final List<String> relations = new ArrayList<>();
|
||||
long eventTypeId = 255;
|
||||
long structTypeId = 33;
|
||||
FieldElement currentField;
|
||||
TypeElement currentType;
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
switch (qName) {
|
||||
case "XmlType":
|
||||
XmlType xmlType = new XmlType();
|
||||
xmlType.name = attributes.getValue("name");
|
||||
xmlType.javaType = attributes.getValue("javaType");
|
||||
xmlType.contentType = attributes.getValue("contentType");
|
||||
xmlType.unsigned = Boolean.valueOf(attributes.getValue("unsigned"));
|
||||
xmlTypes.put(xmlType.name, xmlType);
|
||||
break;
|
||||
case "Type":
|
||||
case "Event":
|
||||
currentType = new TypeElement();
|
||||
currentType.name = attributes.getValue("name");
|
||||
currentType.label = attributes.getValue("label");
|
||||
currentType.description = attributes.getValue("description");
|
||||
currentType.category = attributes.getValue("category");
|
||||
currentType.thread = getBoolean(attributes, "thread", false);
|
||||
currentType.stackTrace = getBoolean(attributes, "stackTrace", false);
|
||||
currentType.startTime = getBoolean(attributes, "startTime", true);
|
||||
currentType.period = attributes.getValue("period");
|
||||
currentType.cutoff = getBoolean(attributes, "cutoff", false);
|
||||
currentType.experimental = getBoolean(attributes, "experimental", false);
|
||||
currentType.isEvent = qName.equals("Event");
|
||||
break;
|
||||
case "Field":
|
||||
currentField = new FieldElement();
|
||||
currentField.struct = getBoolean(attributes, "struct", false);
|
||||
currentField.array = getBoolean(attributes, "array", false);
|
||||
currentField.name = attributes.getValue("name");
|
||||
currentField.label = attributes.getValue("label");
|
||||
currentField.typeName = attributes.getValue("type");
|
||||
currentField.description = attributes.getValue("description");
|
||||
currentField.experimental = getBoolean(attributes, "experimental", false);
|
||||
currentField.contentType = attributes.getValue("contentType");
|
||||
currentField.relation = attributes.getValue("relation");
|
||||
currentField.transition = attributes.getValue("transition");
|
||||
break;
|
||||
case "XmlContentType":
|
||||
String name = attributes.getValue("name");
|
||||
String annotation = attributes.getValue("annotation");
|
||||
xmlContentTypes.put(name, createAnnotationElements(annotation));
|
||||
break;
|
||||
case "Relation":
|
||||
String n = attributes.getValue("name");
|
||||
relations.add(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private List<AnnotationElement> createAnnotationElements(String annotation) throws InternalError {
|
||||
String[] annotations = annotation.split(",");
|
||||
List<AnnotationElement> annotationElements = new ArrayList<>();
|
||||
for (String a : annotations) {
|
||||
a = a.trim();
|
||||
int leftParenthesis = a.indexOf("(");
|
||||
if (leftParenthesis == -1) {
|
||||
annotationElements.add(new AnnotationElement(createAnnotationClass(a)));
|
||||
} else {
|
||||
int rightParenthesis = a.lastIndexOf(")");
|
||||
if (rightParenthesis == -1) {
|
||||
throw new InternalError("Expected closing parenthesis for 'XMLContentType'");
|
||||
}
|
||||
String value = a.substring(leftParenthesis + 1, rightParenthesis);
|
||||
String type = a.substring(0, leftParenthesis);
|
||||
annotationElements.add(new AnnotationElement(createAnnotationClass(type), value));
|
||||
}
|
||||
}
|
||||
return annotationElements;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<? extends Annotation> createAnnotationClass(String type) {
|
||||
try {
|
||||
if (!type.startsWith("jdk.jfr.")) {
|
||||
throw new IllegalStateException("Incorrect type " + type + ". Annotation class must be located in jdk.jfr package.");
|
||||
}
|
||||
Class<?> c = Class.forName(type, true, null);
|
||||
return (Class<? extends Annotation>) c;
|
||||
} catch (ClassNotFoundException cne) {
|
||||
throw new IllegalStateException(cne);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getBoolean(Attributes attributes, String name, boolean defaultValue) {
|
||||
String value = attributes.getValue(name);
|
||||
return value == null ? defaultValue : Boolean.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) {
|
||||
switch (qName) {
|
||||
case "Type":
|
||||
case "Event":
|
||||
types.put(currentType.name, currentType);
|
||||
currentType = null;
|
||||
break;
|
||||
case "Field":
|
||||
currentType.fields.add(currentField);
|
||||
currentField = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Type> createTypes() throws IOException {
|
||||
SAXParser parser = new SAXParserImpl();
|
||||
MetadataHandler t = new MetadataHandler();
|
||||
try (InputStream is = new BufferedInputStream(SecuritySupport.getResourceAsStream("/jdk/jfr/internal/types/metadata.xml"))) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, () -> "Parsing metadata.xml");
|
||||
try {
|
||||
parser.parse(is, t);
|
||||
return t.buildTypes();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Type> buildTypes() {
|
||||
removeXMLConvenience();
|
||||
Map<String, Type> typeMap = buildTypeMap();
|
||||
Map<String, AnnotationElement> relationMap = buildRelationMap(typeMap);
|
||||
addFields(typeMap, relationMap);
|
||||
return trimTypes(typeMap);
|
||||
}
|
||||
|
||||
private Map<String, AnnotationElement> buildRelationMap(Map<String, Type> typeMap) {
|
||||
Map<String, AnnotationElement> relationMap = new HashMap<>();
|
||||
for (String relation : relations) {
|
||||
Type relationType = new Type(Type.TYPES_PREFIX + relation, Type.SUPER_TYPE_ANNOTATION, eventTypeId++);
|
||||
relationType.setAnnotations(Collections.singletonList(new AnnotationElement(Relational.class)));
|
||||
AnnotationElement ae = PrivateAccess.getInstance().newAnnotation(relationType, Collections.emptyList(), true);
|
||||
relationMap.put(relation, ae);
|
||||
typeMap.put(relationType.getName(), relationType);
|
||||
}
|
||||
return relationMap;
|
||||
}
|
||||
|
||||
private List<Type> trimTypes(Map<String, Type> lookup) {
|
||||
List<Type> trimmedTypes = new ArrayList<>(lookup.size());
|
||||
for (Type t : lookup.values()) {
|
||||
t.trimFields();
|
||||
trimmedTypes.add(t);
|
||||
}
|
||||
return trimmedTypes;
|
||||
}
|
||||
|
||||
private void addFields(Map<String, Type> lookup, Map<String, AnnotationElement> relationMap) {
|
||||
for (TypeElement te : types.values()) {
|
||||
Type type = lookup.get(te.name);
|
||||
if (te.isEvent) {
|
||||
boolean periodic = te.period!= null;
|
||||
TypeLibrary.addImplicitFields(type, periodic, te.startTime && !periodic, te.thread, te.stackTrace && !periodic, te.cutoff);
|
||||
}
|
||||
for (FieldElement f : te.fields) {
|
||||
Type fieldType = Type.getKnownType(f.typeName);
|
||||
if (fieldType == null) {
|
||||
fieldType = Objects.requireNonNull(lookup.get(f.referenceType.name));
|
||||
}
|
||||
List<AnnotationElement> aes = new ArrayList<>();
|
||||
if (f.unsigned) {
|
||||
aes.add(new AnnotationElement(Unsigned.class));
|
||||
}
|
||||
if (f.contentType != null) {
|
||||
aes.addAll(Objects.requireNonNull(xmlContentTypes.get(f.contentType)));
|
||||
}
|
||||
if (f.relation != null) {
|
||||
aes.add(Objects.requireNonNull(relationMap.get(f.relation)));
|
||||
}
|
||||
if (f.label != null) {
|
||||
aes.add(new AnnotationElement(Label.class, f.label));
|
||||
}
|
||||
if (f.experimental) {
|
||||
aes.add(new AnnotationElement(Experimental.class));
|
||||
}
|
||||
if (f.description != null) {
|
||||
aes.add(new AnnotationElement(Description.class, f.description));
|
||||
}
|
||||
if ("from".equals(f.transition)) {
|
||||
aes.add(new AnnotationElement(TransitionFrom.class));
|
||||
}
|
||||
if ("to".equals(f.transition)) {
|
||||
aes.add(new AnnotationElement(TransitionTo.class));
|
||||
}
|
||||
boolean constantPool = !f.struct && f.referenceType != null;
|
||||
type.add(PrivateAccess.getInstance().newValueDescriptor(f.name, fieldType, aes, f.array ? 1 : 0, constantPool, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Type> buildTypeMap() {
|
||||
Map<String, Type> typeMap = new HashMap<>();
|
||||
for (Type type : Type.getKnownTypes()) {
|
||||
typeMap.put(type.getName(), type);
|
||||
}
|
||||
|
||||
for (TypeElement t : types.values()) {
|
||||
List<AnnotationElement> aes = new ArrayList<>();
|
||||
if (t.category != null) {
|
||||
aes.add(new AnnotationElement(Category.class, buildCategoryArray(t.category)));
|
||||
}
|
||||
if (t.label != null) {
|
||||
aes.add(new AnnotationElement(Label.class, t.label));
|
||||
}
|
||||
if (t.description != null) {
|
||||
aes.add(new AnnotationElement(Description.class, t.description));
|
||||
}
|
||||
if (t.isEvent) {
|
||||
if (t.period != null) {
|
||||
aes.add(new AnnotationElement(Period.class, t.period));
|
||||
} else {
|
||||
if (t.startTime) {
|
||||
aes.add(new AnnotationElement(Threshold.class, "0 ns"));
|
||||
}
|
||||
if (t.stackTrace) {
|
||||
aes.add(new AnnotationElement(StackTrace.class, true));
|
||||
}
|
||||
}
|
||||
if (t.cutoff) {
|
||||
aes.add(new AnnotationElement(Cutoff.class, Cutoff.INIFITY));
|
||||
}
|
||||
}
|
||||
if (t.experimental) {
|
||||
aes.add(new AnnotationElement(Experimental.class));
|
||||
}
|
||||
Type type;
|
||||
if (t.isEvent) {
|
||||
aes.add(new AnnotationElement(Enabled.class, false));
|
||||
type = new PlatformEventType(t.name, eventTypeId++, false, true);
|
||||
} else {
|
||||
// Struct types had their own XML-element in the past. To have id assigned in the
|
||||
// same order as generated .hpp file do some tweaks here.
|
||||
boolean valueType = t.name.endsWith("StackFrame") || t.valueType;
|
||||
type = new Type(t.name, null, valueType ? eventTypeId++ : nextTypeId(t.name), false);
|
||||
}
|
||||
type.setAnnotations(aes);
|
||||
typeMap.put(t.name, type);
|
||||
}
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
private long nextTypeId(String name) {
|
||||
if (Type.THREAD.getName().equals(name)) {
|
||||
return Type.THREAD.getId();
|
||||
}
|
||||
if (Type.STRING.getName().equals(name)) {
|
||||
return Type.STRING.getId();
|
||||
}
|
||||
if (Type.CLASS.getName().equals(name)) {
|
||||
return Type.CLASS.getId();
|
||||
}
|
||||
for (Type type : Type.getKnownTypes()) {
|
||||
if (type.getName().equals(name)) {
|
||||
return type.getId();
|
||||
}
|
||||
}
|
||||
return structTypeId++;
|
||||
}
|
||||
|
||||
private String[] buildCategoryArray(String category) {
|
||||
List<String> categories = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c : category.toCharArray()) {
|
||||
if (c == ',') {
|
||||
categories.add(sb.toString().trim());
|
||||
sb.setLength(0);
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
categories.add(sb.toString().trim());
|
||||
return categories.toArray(new String[0]);
|
||||
}
|
||||
|
||||
private void removeXMLConvenience() {
|
||||
for (TypeElement t : types.values()) {
|
||||
XmlType xmlType = xmlTypes.get(t.name);
|
||||
if (xmlType != null && xmlType.javaType != null) {
|
||||
t.name = xmlType.javaType; // known type, i.e primitive
|
||||
} else {
|
||||
if (t.isEvent) {
|
||||
t.name = Type.EVENT_NAME_PREFIX + t.name;
|
||||
} else {
|
||||
t.name = Type.TYPES_PREFIX + t.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (TypeElement t : types.values()) {
|
||||
for (FieldElement f : t.fields) {
|
||||
f.referenceType = types.get(f.typeName);
|
||||
XmlType xmlType = xmlTypes.get(f.typeName);
|
||||
if (xmlType != null) {
|
||||
if (xmlType.javaType != null) {
|
||||
f.typeName = xmlType.javaType;
|
||||
}
|
||||
if (xmlType.contentType != null) {
|
||||
f.contentType = xmlType.contentType;
|
||||
}
|
||||
if (xmlType.unsigned) {
|
||||
f.unsigned = true;
|
||||
}
|
||||
}
|
||||
if (f.struct && f.referenceType != null) {
|
||||
f.referenceType.valueType = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
273
jdkSrc/jdk8/jdk/jfr/internal/MetadataReader.java
Normal file
273
jdkSrc/jdk8/jdk/jfr/internal/MetadataReader.java
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.SettingDescriptor;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.MetadataDescriptor.Element;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Parses metadata.
|
||||
*
|
||||
*/
|
||||
final class MetadataReader {
|
||||
|
||||
private final DataInput input;
|
||||
private final List<String> pool;
|
||||
private final MetadataDescriptor descriptor;
|
||||
private final Map<Long, Type> types = new HashMap<>();
|
||||
|
||||
public MetadataReader(DataInput input) throws IOException {
|
||||
this.input = input;
|
||||
int size = input.readInt();
|
||||
((RecordingInput)input).require(size, "Metadata string pool size %d exceeds available data" );
|
||||
this.pool = new ArrayList<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
this.pool.add(input.readUTF());
|
||||
}
|
||||
descriptor = new MetadataDescriptor();
|
||||
Element root = createElement();
|
||||
Element metadata = root.elements("metadata").get(0);
|
||||
declareTypes(metadata);
|
||||
defineTypes(metadata);
|
||||
annotateTypes(metadata);
|
||||
buildEvenTypes();
|
||||
Element time = root.elements("region").get(0);
|
||||
descriptor.gmtOffset = time.attribute(MetadataDescriptor.ATTRIBUTE_GMT_OFFSET, 1);
|
||||
descriptor.locale = time.attribute(MetadataDescriptor.ATTRIBUTE_LOCALE, "");
|
||||
descriptor.root = root;
|
||||
if (Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE)) {
|
||||
List<Type> ts = new ArrayList<>(types.values());
|
||||
Collections.sort(ts, (x,y) -> x.getName().compareTo(y.getName()));
|
||||
for (Type t : ts) {
|
||||
t.log("Found", LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String readString() throws IOException {
|
||||
return pool.get(readInt());
|
||||
}
|
||||
|
||||
private int readInt() throws IOException {
|
||||
return input.readInt();
|
||||
}
|
||||
|
||||
private Element createElement() throws IOException {
|
||||
String name = readString();
|
||||
Element e = new Element(name);
|
||||
int attributeCount = readInt();
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
e.addAttribute(readString(), readString());
|
||||
}
|
||||
int childrenCount = readInt();
|
||||
for (int i = 0; i < childrenCount; i++) {
|
||||
e.add(createElement());
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private void annotateTypes(Element metadata) throws IOException {
|
||||
for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
|
||||
Type type = getType(ATTRIBUTE_ID, typeElement);
|
||||
ArrayList<AnnotationElement> aes = new ArrayList<>();
|
||||
for (Element annotationElement : typeElement.elements(ELEMENT_ANNOTATION)) {
|
||||
aes.add(makeAnnotation(annotationElement));
|
||||
}
|
||||
aes.trimToSize();
|
||||
type.setAnnotations(aes);
|
||||
|
||||
int index = 0;
|
||||
if (type instanceof PlatformEventType) {
|
||||
List<SettingDescriptor> settings = ((PlatformEventType) type).getAllSettings();
|
||||
for (Element settingElement : typeElement.elements(ELEMENT_SETTING)) {
|
||||
ArrayList<AnnotationElement> annotations = new ArrayList<>();
|
||||
for (Element annotationElement : settingElement.elements(ELEMENT_ANNOTATION)) {
|
||||
annotations.add(makeAnnotation(annotationElement));
|
||||
}
|
||||
annotations.trimToSize();
|
||||
PrivateAccess.getInstance().setAnnotations(settings.get(index), annotations);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
List<ValueDescriptor> fields = type.getFields();
|
||||
for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
|
||||
ArrayList<AnnotationElement> annotations = new ArrayList<>();
|
||||
for (Element annotationElement : fieldElement.elements(ELEMENT_ANNOTATION)) {
|
||||
annotations.add(makeAnnotation(annotationElement));
|
||||
}
|
||||
annotations.trimToSize();
|
||||
PrivateAccess.getInstance().setAnnotations(fields.get(index), annotations);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationElement makeAnnotation(Element annotationElement) throws IOException {
|
||||
Type annotationType = getType(ATTRIBUTE_TYPE_ID, annotationElement);
|
||||
List<Object> values = new ArrayList<>();
|
||||
for (ValueDescriptor v : annotationType.getFields()) {
|
||||
if (v.isArray()) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
int index = 0;
|
||||
while (true) {
|
||||
String text = annotationElement.attribute(v.getName() + "-" + index);
|
||||
if (text == null) {
|
||||
break;
|
||||
}
|
||||
list.add(objectify(v.getTypeName(), text));
|
||||
index++;
|
||||
}
|
||||
Object object = Utils.makePrimitiveArray(v.getTypeName(), list);
|
||||
if (object == null) {
|
||||
throw new IOException("Unsupported type " + list + " in array");
|
||||
}
|
||||
values.add(object);
|
||||
} else {
|
||||
String text = annotationElement.attribute(v.getName());
|
||||
values.add(objectify(v.getTypeName(), text));
|
||||
}
|
||||
}
|
||||
return PrivateAccess.getInstance().newAnnotation(annotationType, values, false);
|
||||
}
|
||||
|
||||
private Object objectify(String typeName, String text) throws IOException {
|
||||
try {
|
||||
switch (typeName) {
|
||||
case "int":
|
||||
return Integer.valueOf(text);
|
||||
case "long":
|
||||
return Long.valueOf(text);
|
||||
case "double":
|
||||
return Double.valueOf(text);
|
||||
case "float":
|
||||
return Float.valueOf(text);
|
||||
case "short":
|
||||
return Short.valueOf(text);
|
||||
case "char":
|
||||
if (text.length() != 1) {
|
||||
throw new IOException("Unexpected size of char");
|
||||
}
|
||||
return text.charAt(0);
|
||||
case "byte":
|
||||
return Byte.valueOf(text);
|
||||
case "boolean":
|
||||
return Boolean.valueOf(text);
|
||||
case "java.lang.String":
|
||||
return text;
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IOException("Could not parse text representation of " + typeName);
|
||||
}
|
||||
throw new IOException("Unsupported type for annotation " + typeName);
|
||||
}
|
||||
|
||||
private Type getType(String attribute, Element element) {
|
||||
long id = element.longValue(attribute);
|
||||
Type type = types.get(id);
|
||||
if (type == null) {
|
||||
String name = element.attribute("type");
|
||||
throw new IllegalStateException("Type '" + id + "' is not defined for " + name);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private void buildEvenTypes() {
|
||||
for (Type type : descriptor.types) {
|
||||
if (type instanceof PlatformEventType) {
|
||||
descriptor.eventTypes.add(PrivateAccess.getInstance().newEventType((PlatformEventType) type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void defineTypes(Element metadata) {
|
||||
for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
|
||||
long id = typeElement.attribute(ATTRIBUTE_ID, -1);
|
||||
Type t = types.get(id);
|
||||
for (Element fieldElement : typeElement.elements(ELEMENT_SETTING)) {
|
||||
String name = fieldElement.attribute(ATTRIBUTE_NAME);
|
||||
String defaultValue = fieldElement.attribute(ATTRIBUTE_NAME);
|
||||
Type settingType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
|
||||
PlatformEventType eventType = (PlatformEventType) t;
|
||||
eventType.add(PrivateAccess.getInstance().newSettingDescriptor(settingType, name, defaultValue, new ArrayList<>(2)));
|
||||
}
|
||||
for (Element fieldElement : typeElement.elements(ELEMENT_FIELD)) {
|
||||
String name = fieldElement.attribute(ATTRIBUTE_NAME);
|
||||
Type fieldType = getType(ATTRIBUTE_TYPE_ID, fieldElement);
|
||||
long dimension = fieldElement.attribute(ATTRIBUTE_DIMENSION, 0);
|
||||
boolean constantPool = fieldElement.attribute(ATTRIBUTE_CONSTANT_POOL) != null;
|
||||
// Add annotation later, because they may refer to undefined
|
||||
// types at this stage
|
||||
t.add(PrivateAccess.getInstance().newValueDescriptor(name, fieldType, new ArrayList<>(), (int) dimension, constantPool, null));
|
||||
}
|
||||
t.trimFields();
|
||||
}
|
||||
}
|
||||
|
||||
private void declareTypes(Element metadata) {
|
||||
for (Element typeElement : metadata.elements(ELEMENT_TYPE)) {
|
||||
String typeName = typeElement.attribute(ATTRIBUTE_NAME);
|
||||
String superType = typeElement.attribute(ATTRIBUTE_SUPER_TYPE);
|
||||
boolean simpleType = typeElement.attribute(ATTRIBUTE_SIMPLE_TYPE) != null;
|
||||
long id = typeElement.attribute(ATTRIBUTE_ID, -1);
|
||||
Type t;
|
||||
if (Type.SUPER_TYPE_EVENT.equals(superType)) {
|
||||
t = new PlatformEventType(typeName, id, false, false);
|
||||
} else {
|
||||
t = new Type(typeName, superType, id, false, simpleType);
|
||||
}
|
||||
types.put(id, t);
|
||||
descriptor.types.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public MetadataDescriptor getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
277
jdkSrc/jdk8/jdk/jfr/internal/MetadataRepository.java
Normal file
277
jdkSrc/jdk8/jdk/jfr/internal/MetadataRepository.java
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import static jdk.jfr.internal.LogLevel.DEBUG;
|
||||
import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.RequestEngine.RequestHook;
|
||||
import jdk.jfr.internal.handlers.EventHandler;
|
||||
|
||||
public final class MetadataRepository {
|
||||
|
||||
private static final JVM jvm = JVM.getJVM();
|
||||
private static final MetadataRepository instace = new MetadataRepository();
|
||||
|
||||
private final List<EventType> nativeEventTypes = new ArrayList<>(100);
|
||||
private final List<EventControl> nativeControls = new ArrayList<EventControl>(100);
|
||||
private final TypeLibrary typeLibrary = TypeLibrary.getInstance();
|
||||
private final SettingsManager settingsManager = new SettingsManager();
|
||||
private boolean staleMetadata = true;
|
||||
private boolean unregistered;
|
||||
private long lastUnloaded = -1;
|
||||
|
||||
public MetadataRepository() {
|
||||
initializeJVMEventTypes();
|
||||
}
|
||||
|
||||
private void initializeJVMEventTypes() {
|
||||
List<RequestHook> requestHooks = new ArrayList<>();
|
||||
for (Type type : typeLibrary.getTypes()) {
|
||||
if (type instanceof PlatformEventType) {
|
||||
PlatformEventType pEventType = (PlatformEventType) type;
|
||||
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
|
||||
pEventType.setHasDuration(eventType.getAnnotation(Threshold.class) != null);
|
||||
pEventType.setHasStackTrace(eventType.getAnnotation(StackTrace.class) != null);
|
||||
pEventType.setHasCutoff(eventType.getAnnotation(Cutoff.class) != null);
|
||||
pEventType.setHasPeriod(eventType.getAnnotation(Period.class) != null);
|
||||
// Must add hook before EventControl is created as it removes
|
||||
// annotations, such as Period and Threshold.
|
||||
if (pEventType.hasPeriod()) {
|
||||
pEventType.setEventHook(true);
|
||||
if (!(Type.EVENT_NAME_PREFIX + "ExecutionSample").equals(type.getName())) {
|
||||
requestHooks.add(new RequestHook(pEventType));
|
||||
}
|
||||
}
|
||||
nativeControls.add(new EventControl(pEventType));
|
||||
nativeEventTypes.add(eventType);
|
||||
}
|
||||
}
|
||||
RequestEngine.addHooks(requestHooks);
|
||||
}
|
||||
|
||||
public static MetadataRepository getInstance() {
|
||||
return instace;
|
||||
}
|
||||
|
||||
public synchronized List<EventType> getRegisteredEventTypes() {
|
||||
List<EventHandler> handlers = getEventHandlers();
|
||||
List<EventType> eventTypes = new ArrayList<>(handlers.size() + nativeEventTypes.size());
|
||||
for (EventHandler h : handlers) {
|
||||
if (h.isRegistered()) {
|
||||
eventTypes.add(h.getEventType());
|
||||
}
|
||||
}
|
||||
eventTypes.addAll(nativeEventTypes);
|
||||
return eventTypes;
|
||||
}
|
||||
|
||||
public synchronized EventType getEventType(Class<? extends Event> eventClass) {
|
||||
EventHandler h = getHandler(eventClass);
|
||||
if (h != null && h.isRegistered()) {
|
||||
return h.getEventType();
|
||||
}
|
||||
throw new IllegalStateException("Event class " + eventClass.getName() + " is not registered");
|
||||
}
|
||||
|
||||
public synchronized void unregister(Class<? extends Event> eventClass) {
|
||||
Utils.checkRegisterPermission();
|
||||
EventHandler handler = getHandler(eventClass);
|
||||
if (handler != null) {
|
||||
handler.setRegistered(false);
|
||||
}
|
||||
// never registered, ignore call
|
||||
}
|
||||
public synchronized EventType register(Class<? extends Event> eventClass) {
|
||||
return register(eventClass, Collections.emptyList(), Collections.emptyList());
|
||||
}
|
||||
|
||||
public synchronized EventType register(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) {
|
||||
Utils.checkRegisterPermission();
|
||||
EventHandler handler = getHandler(eventClass);
|
||||
if (handler == null) {
|
||||
handler = makeHandler(eventClass, dynamicAnnotations, dynamicFields);
|
||||
}
|
||||
handler.setRegistered(true);
|
||||
typeLibrary.addType(handler.getPlatformEventType());
|
||||
if (jvm.isRecording()) {
|
||||
storeDescriptorInJVM(); // needed for emergency dump
|
||||
settingsManager.setEventControl(handler.getEventControl());
|
||||
settingsManager.updateRetransform(Collections.singletonList((eventClass)));
|
||||
} else {
|
||||
setStaleMetadata();
|
||||
}
|
||||
return handler.getEventType();
|
||||
}
|
||||
|
||||
private EventHandler getHandler(Class<? extends Event> eventClass) {
|
||||
Utils.ensureValidEventSubclass(eventClass);
|
||||
SecuritySupport.makeVisibleToJFR(eventClass);
|
||||
Utils.ensureInitialized(eventClass);
|
||||
return Utils.getHandler(eventClass);
|
||||
}
|
||||
|
||||
private EventHandler makeHandler(Class<? extends Event> eventClass, List<AnnotationElement> dynamicAnnotations, List<ValueDescriptor> dynamicFields) throws InternalError {
|
||||
SecuritySupport.addHandlerExport(eventClass);
|
||||
PlatformEventType pEventType = (PlatformEventType) TypeLibrary.createType(eventClass, dynamicAnnotations, dynamicFields);
|
||||
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
|
||||
EventControl ec = new EventControl(pEventType, eventClass);
|
||||
Class<? extends EventHandler> handlerClass = null;
|
||||
try {
|
||||
String eventHandlerName = EventHandlerCreator.makeEventHandlerName(eventType.getId());
|
||||
handlerClass = Class.forName(eventHandlerName, false, Event.class.getClassLoader()).asSubclass(EventHandler.class);
|
||||
// Created eagerly on class load, tag as instrumented
|
||||
pEventType.setInstrumented();
|
||||
Logger.log(JFR_SYSTEM, DEBUG, "Found existing event handler for " + eventType.getName());
|
||||
} catch (ClassNotFoundException cne) {
|
||||
EventHandlerCreator ehc = new EventHandlerCreator(eventType.getId(), ec.getSettingInfos(), eventType, eventClass);
|
||||
handlerClass = ehc.makeEventHandlerClass();
|
||||
Logger.log(LogTag.JFR_SYSTEM, DEBUG, "Created event handler for " + eventType.getName());
|
||||
}
|
||||
EventHandler handler = EventHandlerCreator.instantiateEventHandler(handlerClass, true, eventType, ec);
|
||||
Utils.setHandler(eventClass, handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void setSettings(List<Map<String, String>> list) {
|
||||
settingsManager.setSettings(list);
|
||||
}
|
||||
|
||||
synchronized void disableEvents() {
|
||||
for (EventControl c : getEventControls()) {
|
||||
c.disable();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized List<EventControl> getEventControls() {
|
||||
List<EventControl> controls = new ArrayList<>();
|
||||
controls.addAll(nativeControls);
|
||||
for (EventHandler eh : getEventHandlers()) {
|
||||
controls.add(eh.getEventControl());
|
||||
}
|
||||
return controls;
|
||||
}
|
||||
|
||||
private void storeDescriptorInJVM() throws InternalError {
|
||||
jvm.storeMetadataDescriptor(getBinaryRepresentation());
|
||||
staleMetadata = false;
|
||||
}
|
||||
|
||||
private static List<EventHandler> getEventHandlers() {
|
||||
List<Class<? extends Event>> allEventClasses = jvm.getAllEventClasses();
|
||||
List<EventHandler> eventHandlers = new ArrayList<>(allEventClasses.size());
|
||||
for (Class<? extends Event> clazz : allEventClasses) {
|
||||
EventHandler eh = Utils.getHandler(clazz);
|
||||
if (eh != null) {
|
||||
eventHandlers.add(eh);
|
||||
}
|
||||
}
|
||||
return eventHandlers;
|
||||
}
|
||||
|
||||
private byte[] getBinaryRepresentation() {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(40000);
|
||||
DataOutputStream daos = new DataOutputStream(baos);
|
||||
try {
|
||||
List<Type> types = typeLibrary.getTypes();
|
||||
Collections.sort(types);
|
||||
MetadataDescriptor.write(types, daos);
|
||||
daos.flush();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
// should not happen
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized boolean isEnabled(String eventName) {
|
||||
return settingsManager.isEnabled(eventName);
|
||||
}
|
||||
|
||||
synchronized void setStaleMetadata() {
|
||||
staleMetadata = true;
|
||||
}
|
||||
|
||||
// Lock around setOutput ensures that other threads dosn't
|
||||
// emit event after setOutput and unregister the event class, before a call
|
||||
// to storeDescriptorInJVM
|
||||
synchronized void setOutput(String filename) {
|
||||
jvm.setOutput(filename);
|
||||
|
||||
unregisterUnloaded();
|
||||
if (unregistered) {
|
||||
staleMetadata = typeLibrary.clearUnregistered();
|
||||
unregistered = false;
|
||||
}
|
||||
if (staleMetadata) {
|
||||
storeDescriptorInJVM();
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterUnloaded() {
|
||||
long unloaded = jvm.getUnloadedEventClassCount();
|
||||
if (this.lastUnloaded != unloaded) {
|
||||
this.lastUnloaded = unloaded;
|
||||
List<Class<? extends Event>> eventClasses = jvm.getAllEventClasses();
|
||||
HashSet<Long> knownIds = new HashSet<>(eventClasses.size());
|
||||
for (Class<? extends Event> ec: eventClasses) {
|
||||
knownIds.add(Type.getTypeId(ec));
|
||||
}
|
||||
for (Type type : typeLibrary.getTypes()) {
|
||||
if (type instanceof PlatformEventType) {
|
||||
if (!knownIds.contains(type.getId())) {
|
||||
PlatformEventType pe = (PlatformEventType) type;
|
||||
if (!pe.isJVM()) {
|
||||
pe.setRegistered(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void setUnregistered() {
|
||||
unregistered = true;
|
||||
}
|
||||
|
||||
}
|
||||
225
jdkSrc/jdk8/jdk/jfr/internal/MetadataWriter.java
Normal file
225
jdkSrc/jdk8/jdk/jfr/internal/MetadataWriter.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_CONSTANT_POOL;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DEFAULT_VALUE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_DIMENSION;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_GMT_OFFSET;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_ID;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_LOCALE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_NAME;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SIMPLE_TYPE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_SUPER_TYPE;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ATTRIBUTE_TYPE_ID;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_ANNOTATION;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_FIELD;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_SETTING;
|
||||
import static jdk.jfr.internal.MetadataDescriptor.ELEMENT_TYPE;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.SettingDescriptor;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.internal.MetadataDescriptor.Attribute;
|
||||
import jdk.jfr.internal.MetadataDescriptor.Element;
|
||||
import jdk.jfr.internal.consumer.RecordingInput;
|
||||
|
||||
/**
|
||||
* Class responsible for converting a list of types into a format that can be
|
||||
* parsed by a client.
|
||||
*
|
||||
*/
|
||||
final class MetadataWriter {
|
||||
|
||||
private final Element metadata = new Element("metadata");
|
||||
private final Element root = new Element("root");
|
||||
|
||||
public MetadataWriter(MetadataDescriptor descriptor) {
|
||||
descriptor.getTypes().forEach(type -> makeTypeElement(metadata, type));
|
||||
|
||||
root.add(metadata);
|
||||
Element region = new Element("region");
|
||||
region.addAttribute(ATTRIBUTE_LOCALE, descriptor.locale);
|
||||
region.addAttribute(ATTRIBUTE_GMT_OFFSET, descriptor.gmtOffset);
|
||||
root.add(region);
|
||||
}
|
||||
|
||||
public void writeBinary(DataOutput output) throws IOException {
|
||||
Set<String> stringPool = new HashSet<>(1000);
|
||||
// Possible improvement, sort string by how often they occur.
|
||||
// and assign low number to the most frequently used.
|
||||
buildStringPool(root, stringPool);
|
||||
HashMap<String, Integer> lookup = new LinkedHashMap<>(stringPool.size());
|
||||
int index = 0;
|
||||
int poolSize = stringPool.size();
|
||||
writeInt(output, poolSize);
|
||||
for (String s : stringPool) {
|
||||
lookup.put(s, index);
|
||||
writeString(output, s);
|
||||
index++;
|
||||
}
|
||||
write(output, root, lookup);
|
||||
}
|
||||
|
||||
private void writeString(DataOutput out, String s) throws IOException {
|
||||
if (s == null ) {
|
||||
out.writeByte(RecordingInput.STRING_ENCODING_NULL);
|
||||
return;
|
||||
}
|
||||
out.writeByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // encoding UTF-16
|
||||
int length = s.length();
|
||||
writeInt(out, length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
writeInt(out, s.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInt(DataOutput out, int v) throws IOException {
|
||||
|
||||
long s = v & 0xffffffffL;
|
||||
if (s < 1 << 7) {
|
||||
out.write((byte) (s));
|
||||
return;
|
||||
}
|
||||
out.write((byte) (s | 0x80)); // first byte written
|
||||
s >>= 7;
|
||||
if (s < 1 << 7) {
|
||||
out.write((byte) (s));
|
||||
return;
|
||||
}
|
||||
out.write((byte) (s | 0x80)); // second byte written
|
||||
s >>= 7;
|
||||
if (s < 1 << 7) {
|
||||
out.write((byte) (s));
|
||||
return;
|
||||
}
|
||||
out.write((byte) (s | 0x80)); // third byte written
|
||||
s >>= 7;
|
||||
if (s < 1 << 7) {
|
||||
out.write((byte) (s));
|
||||
return;
|
||||
}
|
||||
s >>= 7;
|
||||
out.write((byte) (s));// fourth byte written
|
||||
}
|
||||
|
||||
private void buildStringPool(Element element, Set<String> pool) {
|
||||
pool.add(element.name);
|
||||
for (Attribute a : element.attributes) {
|
||||
pool.add(a.name);
|
||||
pool.add(a.value);
|
||||
}
|
||||
for (Element child : element.elements) {
|
||||
buildStringPool(child, pool);
|
||||
}
|
||||
}
|
||||
|
||||
private void write(DataOutput output,Element element, HashMap<String, Integer> lookup) throws IOException {
|
||||
writeInt(output, lookup.get(element.name));
|
||||
writeInt(output, element.attributes.size());
|
||||
for (Attribute a : element.attributes) {
|
||||
writeInt(output, lookup.get(a.name));
|
||||
writeInt(output, lookup.get(a.value));
|
||||
}
|
||||
writeInt(output, element.elements.size());
|
||||
for (Element child : element.elements) {
|
||||
write(output, child, lookup);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeTypeElement(Element root, Type type) {
|
||||
Element element = root.newChild(ELEMENT_TYPE);
|
||||
element.addAttribute(ATTRIBUTE_NAME, type.getName());
|
||||
String superType = type.getSuperType();
|
||||
if (superType != null) {
|
||||
element.addAttribute(ATTRIBUTE_SUPER_TYPE, superType);
|
||||
}
|
||||
if (type.isSimpleType()) {
|
||||
element.addAttribute(ATTRIBUTE_SIMPLE_TYPE, true);
|
||||
}
|
||||
element.addAttribute(ATTRIBUTE_ID, type.getId());
|
||||
if (type instanceof PlatformEventType) {
|
||||
for (SettingDescriptor v : ((PlatformEventType)type).getSettings()) {
|
||||
makeSettingElement(element, v);
|
||||
}
|
||||
}
|
||||
for (ValueDescriptor v : type.getFields()) {
|
||||
makeFieldElement(element, v);
|
||||
}
|
||||
for (AnnotationElement a : type.getAnnotationElements()) {
|
||||
makeAnnotation(element, a);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeSettingElement(Element typeElement, SettingDescriptor s) {
|
||||
Element element = typeElement.newChild(ELEMENT_SETTING);
|
||||
element.addAttribute(ATTRIBUTE_NAME, s.getName());
|
||||
element.addAttribute(ATTRIBUTE_TYPE_ID, s.getTypeId());
|
||||
element.addAttribute(ATTRIBUTE_DEFAULT_VALUE, s.getDefaultValue());
|
||||
for (AnnotationElement a : s.getAnnotationElements()) {
|
||||
makeAnnotation(element, a);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeFieldElement(Element typeElement, ValueDescriptor v) {
|
||||
Element element = typeElement.newChild(ELEMENT_FIELD);
|
||||
element.addAttribute(ATTRIBUTE_NAME, v.getName());
|
||||
element.addAttribute(ATTRIBUTE_TYPE_ID, v.getTypeId());
|
||||
if (v.isArray()) {
|
||||
element.addAttribute(ATTRIBUTE_DIMENSION, 1);
|
||||
}
|
||||
if (PrivateAccess.getInstance().isConstantPool(v)) {
|
||||
element.addAttribute(ATTRIBUTE_CONSTANT_POOL, true);
|
||||
}
|
||||
for (AnnotationElement a : v.getAnnotationElements()) {
|
||||
makeAnnotation(element, a);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeAnnotation(Element entity, AnnotationElement annotation) {
|
||||
Element element = entity.newChild(ELEMENT_ANNOTATION);
|
||||
element.addAttribute(ATTRIBUTE_TYPE_ID, annotation.getTypeId());
|
||||
List<Object> values = annotation.getValues();
|
||||
int index = 0;
|
||||
for (ValueDescriptor v : annotation.getValueDescriptors()) {
|
||||
Object value = values.get(index++);
|
||||
if (v.isArray()) {
|
||||
element.addArrayAttribute(element, v.getName(), value);
|
||||
} else {
|
||||
element.addAttribute(v.getName(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
98
jdkSrc/jdk8/jdk/jfr/internal/OldObjectSample.java
Normal file
98
jdkSrc/jdk8/jdk/jfr/internal/OldObjectSample.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.RecordingState;
|
||||
import jdk.jfr.internal.settings.CutoffSetting;
|
||||
import jdk.jfr.internal.test.WhiteBox;
|
||||
|
||||
// The Old Object event could have been implemented as a periodic event, but
|
||||
// due to chunk rotations and how settings are calculated when multiple recordings
|
||||
// are running at the same time, it would lead to unacceptable overhead.
|
||||
//
|
||||
// Instead, the event is only emitted before a recording stops and
|
||||
// if that recording has the event enabled.
|
||||
//
|
||||
// This requires special handling and the purpose of this class is to provide that
|
||||
//
|
||||
public final class OldObjectSample {
|
||||
|
||||
private static final String EVENT_NAME = Type.EVENT_NAME_PREFIX + "OldObjectSample";
|
||||
private static final String OLD_OBJECT_CUTOFF = EVENT_NAME + "#" + Cutoff.NAME;
|
||||
private static final String OLD_OBJECT_ENABLED = EVENT_NAME + "#" + Enabled.NAME;
|
||||
|
||||
// Emit if old object is enabled in recording with cutoff for that recording
|
||||
public static void emit(PlatformRecording recording) {
|
||||
if (isEnabled(recording)) {
|
||||
long nanos = CutoffSetting.parseValueSafe(recording.getSettings().get(OLD_OBJECT_CUTOFF));
|
||||
long ticks = Utils.nanosToTicks(nanos);
|
||||
JVM.getJVM().emitOldObjectSamples(ticks, WhiteBox.getWriteAllObjectSamples());
|
||||
}
|
||||
}
|
||||
|
||||
// Emit if old object is enabled for at least one recording, and use the largest
|
||||
// cutoff for an enabled recording
|
||||
public static void emit(List<PlatformRecording> recordings, Boolean pathToGcRoots) {
|
||||
boolean enabled = false;
|
||||
long cutoffNanos = Boolean.TRUE.equals(pathToGcRoots) ? Long.MAX_VALUE : 0L;
|
||||
for (PlatformRecording r : recordings) {
|
||||
if (r.getState() == RecordingState.RUNNING) {
|
||||
if (isEnabled(r)) {
|
||||
enabled = true;
|
||||
long c = CutoffSetting.parseValueSafe(r.getSettings().get(OLD_OBJECT_CUTOFF));
|
||||
cutoffNanos = Math.max(c, cutoffNanos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enabled) {
|
||||
long ticks = Utils.nanosToTicks(cutoffNanos);
|
||||
JVM.getJVM().emitOldObjectSamples(ticks, WhiteBox.getWriteAllObjectSamples());
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateSettingPathToGcRoots(Map<String, String> s, Boolean pathToGcRoots) {
|
||||
if (pathToGcRoots != null) {
|
||||
s.put(OLD_OBJECT_CUTOFF, pathToGcRoots ? "infinity" : "0 ns");
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> createSettingsForSnapshot(PlatformRecording recording, Boolean pathToGcRoots) {
|
||||
Map<String, String> settings = new HashMap<>(recording.getSettings());
|
||||
updateSettingPathToGcRoots(settings, pathToGcRoots);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private static boolean isEnabled(PlatformRecording r) {
|
||||
Map<String, String> settings = r.getSettings();
|
||||
String s = settings.get(OLD_OBJECT_ENABLED);
|
||||
return "true".equals(s);
|
||||
}
|
||||
}
|
||||
162
jdkSrc/jdk8/jdk/jfr/internal/Options.java
Normal file
162
jdkSrc/jdk8/jdk/jfr/internal/Options.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Options that control Flight Recorder.
|
||||
*
|
||||
* Can be set using JFR.configure
|
||||
*
|
||||
*/
|
||||
public final class Options {
|
||||
|
||||
private final static JVM jvm = JVM.getJVM();
|
||||
private final static long WAIT_INTERVAL = 1000; // ms;
|
||||
|
||||
private final static long MIN_MAX_CHUNKSIZE = 1024 * 1024;
|
||||
|
||||
private static final long DEFAULT_GLOBAL_BUFFER_COUNT = 20;
|
||||
private static final long DEFAULT_GLOBAL_BUFFER_SIZE = 524288;
|
||||
private static final long DEFAULT_MEMORY_SIZE = DEFAULT_GLOBAL_BUFFER_COUNT * DEFAULT_GLOBAL_BUFFER_SIZE;
|
||||
private static long DEFAULT_THREAD_BUFFER_SIZE;
|
||||
private static final int DEFAULT_STACK_DEPTH = 64;
|
||||
private static final boolean DEFAULT_SAMPLE_THREADS = true;
|
||||
private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024;
|
||||
private static final SafePath DEFAULT_DUMP_PATH = SecuritySupport.USER_HOME;
|
||||
|
||||
private static long memorySize;
|
||||
private static long globalBufferSize;
|
||||
private static long globalBufferCount;
|
||||
private static long threadBufferSize;
|
||||
private static int stackDepth;
|
||||
private static boolean sampleThreads;
|
||||
private static long maxChunkSize;
|
||||
private static SafePath dumpPath;
|
||||
|
||||
static {
|
||||
final long pageSize = Unsafe.getUnsafe().pageSize();
|
||||
DEFAULT_THREAD_BUFFER_SIZE = pageSize > 8 * 1024 ? pageSize : 8 * 1024;
|
||||
reset();
|
||||
}
|
||||
|
||||
public static synchronized void setMaxChunkSize(long max) {
|
||||
if (max < MIN_MAX_CHUNKSIZE) {
|
||||
throw new IllegalArgumentException("Max chunk size must be at least " + MIN_MAX_CHUNKSIZE);
|
||||
}
|
||||
jvm.setFileNotification(max);
|
||||
maxChunkSize = max;
|
||||
}
|
||||
|
||||
public static synchronized long getMaxChunkSize() {
|
||||
return maxChunkSize;
|
||||
}
|
||||
|
||||
public static synchronized void setMemorySize(long memSize) {
|
||||
jvm.setMemorySize(memSize);
|
||||
memorySize = memSize;
|
||||
}
|
||||
|
||||
public static synchronized long getMemorySize() {
|
||||
return memorySize;
|
||||
}
|
||||
|
||||
public static synchronized void setThreadBufferSize(long threadBufSize) {
|
||||
jvm.setThreadBufferSize(threadBufSize);
|
||||
threadBufferSize = threadBufSize;
|
||||
}
|
||||
|
||||
public static synchronized long getThreadBufferSize() {
|
||||
return threadBufferSize;
|
||||
}
|
||||
|
||||
public static synchronized long getGlobalBufferSize() {
|
||||
return globalBufferSize;
|
||||
}
|
||||
|
||||
public static synchronized void setGlobalBufferCount(long globalBufCount) {
|
||||
jvm.setGlobalBufferCount(globalBufCount);
|
||||
globalBufferCount = globalBufCount;
|
||||
}
|
||||
|
||||
public static synchronized long getGlobalBufferCount() {
|
||||
return globalBufferCount;
|
||||
}
|
||||
|
||||
public static synchronized void setGlobalBufferSize(long globalBufsize) {
|
||||
jvm.setGlobalBufferSize(globalBufsize);
|
||||
globalBufferSize = globalBufsize;
|
||||
}
|
||||
|
||||
public static synchronized void setDumpPath(SafePath path) {
|
||||
dumpPath = path;
|
||||
}
|
||||
|
||||
public static synchronized SafePath getDumpPath() {
|
||||
return dumpPath;
|
||||
}
|
||||
|
||||
public static synchronized void setStackDepth(Integer stackTraceDepth) {
|
||||
jvm.setStackDepth(stackTraceDepth);
|
||||
stackDepth = stackTraceDepth;
|
||||
}
|
||||
|
||||
public static synchronized int getStackDepth() {
|
||||
return stackDepth;
|
||||
}
|
||||
|
||||
public static synchronized void setSampleThreads(Boolean sample) {
|
||||
jvm.setSampleThreads(sample);
|
||||
sampleThreads = sample;
|
||||
}
|
||||
|
||||
public static synchronized boolean getSampleThreads() {
|
||||
return sampleThreads;
|
||||
}
|
||||
|
||||
private static synchronized void reset() {
|
||||
setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE);
|
||||
setMemorySize(DEFAULT_MEMORY_SIZE);
|
||||
setGlobalBufferSize(DEFAULT_GLOBAL_BUFFER_SIZE);
|
||||
setGlobalBufferCount(DEFAULT_GLOBAL_BUFFER_COUNT);
|
||||
setDumpPath(DEFAULT_DUMP_PATH);
|
||||
setSampleThreads(DEFAULT_SAMPLE_THREADS);
|
||||
setStackDepth(DEFAULT_STACK_DEPTH);
|
||||
setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
static synchronized long getWaitInterval() {
|
||||
return WAIT_INTERVAL;
|
||||
}
|
||||
|
||||
static void ensureInitialized() {
|
||||
// trigger clinit which will setup JVM defaults.
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
281
jdkSrc/jdk8/jdk/jfr/internal/PlatformEventType.java
Normal file
281
jdkSrc/jdk8/jdk/jfr/internal/PlatformEventType.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.jfr.SettingDescriptor;
|
||||
|
||||
/**
|
||||
* Implementation of event type.
|
||||
*
|
||||
* To avoid memory leaks, this class must not hold strong reference to an event
|
||||
* class or a setting class
|
||||
*/
|
||||
public final class PlatformEventType extends Type {
|
||||
private final boolean isJVM;
|
||||
private final boolean isJDK;
|
||||
private final boolean isMethodSampling;
|
||||
private final List<SettingDescriptor> settings = new ArrayList<>(5);
|
||||
private final boolean dynamicSettings;
|
||||
private final int stackTraceOffset;
|
||||
|
||||
// default values
|
||||
private boolean enabled = false;
|
||||
private boolean stackTraceEnabled = true;
|
||||
private long thresholdTicks = 0;
|
||||
private long period = 0;
|
||||
private boolean hasHook;
|
||||
|
||||
private boolean beginChunk;
|
||||
private boolean endChunk;
|
||||
private boolean hasStackTrace = true;
|
||||
private boolean hasDuration = true;
|
||||
private boolean hasPeriod = true;
|
||||
private boolean hasCutoff = false;
|
||||
private boolean isInstrumented;
|
||||
private boolean markForInstrumentation;
|
||||
private boolean registered = true;
|
||||
private boolean commitable = enabled && registered;
|
||||
|
||||
|
||||
// package private
|
||||
PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
|
||||
super(name, Type.SUPER_TYPE_EVENT, id);
|
||||
this.dynamicSettings = dynamicSettings;
|
||||
this.isJVM = Type.isDefinedByJVM(id);
|
||||
this.isMethodSampling = name.equals(Type.EVENT_NAME_PREFIX + "ExecutionSample") || name.equals(Type.EVENT_NAME_PREFIX + "NativeMethodSample");
|
||||
this.isJDK = isJDK;
|
||||
this.stackTraceOffset = stackTraceOffset(name, isJDK);
|
||||
}
|
||||
|
||||
private static int stackTraceOffset(String name, boolean isJDK) {
|
||||
if (isJDK) {
|
||||
if (name.equals(Type.EVENT_NAME_PREFIX + "JavaExceptionThrow")) {
|
||||
return 5;
|
||||
}
|
||||
if (name.equals(Type.EVENT_NAME_PREFIX + "JavaErrorThrow")) {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
||||
public void add(SettingDescriptor settingDescriptor) {
|
||||
Objects.requireNonNull(settingDescriptor);
|
||||
settings.add(settingDescriptor);
|
||||
}
|
||||
|
||||
public List<SettingDescriptor> getSettings() {
|
||||
if (dynamicSettings) {
|
||||
List<SettingDescriptor> list = new ArrayList<>(settings.size());
|
||||
for (SettingDescriptor s : settings) {
|
||||
if (Utils.isSettingVisible(s.getTypeId(), hasHook)) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
public List<SettingDescriptor> getAllSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
public void setHasStackTrace(boolean hasStackTrace) {
|
||||
this.hasStackTrace = hasStackTrace;
|
||||
}
|
||||
|
||||
public void setHasDuration(boolean hasDuration) {
|
||||
this.hasDuration = hasDuration;
|
||||
}
|
||||
|
||||
public void setHasCutoff(boolean hasCutoff) {
|
||||
this.hasCutoff = hasCutoff;
|
||||
}
|
||||
|
||||
public void setCutoff(long cutoffNanos) {
|
||||
if (isJVM) {
|
||||
long cutoffTicks = Utils.nanosToTicks(cutoffNanos);
|
||||
JVM.getJVM().setCutoff(getId(), cutoffTicks);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHasPeriod(boolean hasPeriod) {
|
||||
this.hasPeriod = hasPeriod;
|
||||
}
|
||||
|
||||
public boolean hasStackTrace() {
|
||||
return this.hasStackTrace;
|
||||
}
|
||||
|
||||
public boolean hasDuration() {
|
||||
return this.hasDuration;
|
||||
}
|
||||
|
||||
public boolean hasPeriod() {
|
||||
return this.hasPeriod;
|
||||
}
|
||||
|
||||
public boolean hasCutoff() {
|
||||
return this.hasCutoff;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public boolean isJVM() {
|
||||
return isJVM;
|
||||
}
|
||||
|
||||
public boolean isJDK() {
|
||||
return isJDK;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
updateCommitable();
|
||||
if (isJVM) {
|
||||
if (isMethodSampling) {
|
||||
long p = enabled ? period : 0;
|
||||
JVM.getJVM().setMethodSamplingInterval(getId(), p);
|
||||
} else {
|
||||
JVM.getJVM().setEnabled(getId(), enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPeriod(long periodMillis, boolean beginChunk, boolean endChunk) {
|
||||
if (isMethodSampling) {
|
||||
long p = enabled ? periodMillis : 0;
|
||||
JVM.getJVM().setMethodSamplingInterval(getId(), p);
|
||||
}
|
||||
this.beginChunk = beginChunk;
|
||||
this.endChunk = endChunk;
|
||||
this.period = periodMillis;
|
||||
}
|
||||
|
||||
public void setStackTraceEnabled(boolean stackTraceEnabled) {
|
||||
this.stackTraceEnabled = stackTraceEnabled;
|
||||
if (isJVM) {
|
||||
JVM.getJVM().setStackTraceEnabled(getId(), stackTraceEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
public void setThreshold(long thresholdNanos) {
|
||||
this.thresholdTicks = Utils.nanosToTicks(thresholdNanos);
|
||||
if (isJVM) {
|
||||
JVM.getJVM().setThreshold(getId(), thresholdTicks);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEveryChunk() {
|
||||
return period == 0;
|
||||
}
|
||||
|
||||
public boolean getStackTraceEnabled() {
|
||||
return stackTraceEnabled;
|
||||
}
|
||||
|
||||
public long getThresholdTicks() {
|
||||
return thresholdTicks;
|
||||
}
|
||||
|
||||
public long getPeriod() {
|
||||
return period;
|
||||
}
|
||||
|
||||
public boolean hasEventHook() {
|
||||
return hasHook;
|
||||
}
|
||||
|
||||
public void setEventHook(boolean hasHook) {
|
||||
this.hasHook = hasHook;
|
||||
}
|
||||
|
||||
public boolean isBeginChunk() {
|
||||
return beginChunk;
|
||||
}
|
||||
|
||||
public boolean isEndChunk() {
|
||||
return endChunk;
|
||||
}
|
||||
|
||||
public boolean isInstrumented() {
|
||||
return isInstrumented;
|
||||
}
|
||||
|
||||
public void setInstrumented() {
|
||||
isInstrumented = true;
|
||||
}
|
||||
|
||||
public void markForInstrumentation(boolean markForInstrumentation) {
|
||||
this.markForInstrumentation = markForInstrumentation;
|
||||
}
|
||||
|
||||
public boolean isMarkedForInstrumentation() {
|
||||
return markForInstrumentation;
|
||||
}
|
||||
|
||||
public boolean setRegistered(boolean registered) {
|
||||
if (this.registered != registered) {
|
||||
this.registered = registered;
|
||||
updateCommitable();
|
||||
LogTag logTag = isJVM() || isJDK() ? LogTag.JFR_SYSTEM_EVENT : LogTag.JFR_EVENT;
|
||||
if (registered) {
|
||||
Logger.log(logTag, LogLevel.INFO, "Registered " + getLogName());
|
||||
} else {
|
||||
Logger.log(logTag, LogLevel.INFO, "Unregistered " + getLogName());
|
||||
}
|
||||
if (!registered) {
|
||||
MetadataRepository.getInstance().setUnregistered();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void updateCommitable() {
|
||||
this.commitable = enabled && registered;
|
||||
}
|
||||
|
||||
public final boolean isRegistered() {
|
||||
return registered;
|
||||
}
|
||||
|
||||
// Efficient check of enabled && registered
|
||||
public boolean isCommitable() {
|
||||
return commitable;
|
||||
}
|
||||
|
||||
public int getStackTraceOffset() {
|
||||
return stackTraceOffset;
|
||||
}
|
||||
}
|
||||
554
jdkSrc/jdk8/jdk/jfr/internal/PlatformRecorder.java
Normal file
554
jdkSrc/jdk8/jdk/jfr/internal/PlatformRecorder.java
Normal file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import static jdk.jfr.internal.LogLevel.INFO;
|
||||
import static jdk.jfr.internal.LogLevel.TRACE;
|
||||
import static jdk.jfr.internal.LogLevel.WARN;
|
||||
import static jdk.jfr.internal.LogTag.JFR;
|
||||
import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.FlightRecorder;
|
||||
import jdk.jfr.FlightRecorderListener;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.RecordingState;
|
||||
import jdk.jfr.events.ActiveRecordingEvent;
|
||||
import jdk.jfr.events.ActiveSettingEvent;
|
||||
import jdk.jfr.internal.SecuritySupport.SecureRecorderListener;
|
||||
import jdk.jfr.internal.instrument.JDKEvents;
|
||||
|
||||
public final class PlatformRecorder {
|
||||
|
||||
private final List<PlatformRecording> recordings = new ArrayList<>();
|
||||
private final static List<SecureRecorderListener> changeListeners = new ArrayList<>();
|
||||
private final Repository repository;
|
||||
private final Timer timer;
|
||||
private final static JVM jvm = JVM.getJVM();
|
||||
private final EventType activeRecordingEvent;
|
||||
private final EventType activeSettingEvent;
|
||||
private final Thread shutdownHook;
|
||||
|
||||
private long recordingCounter = 0;
|
||||
private RepositoryChunk currentChunk;
|
||||
|
||||
public PlatformRecorder() throws Exception {
|
||||
repository = Repository.getRepository();
|
||||
Logger.log(JFR_SYSTEM, INFO, "Initialized disk repository");
|
||||
repository.ensureRepository();
|
||||
jvm.createNativeJFR();
|
||||
Logger.log(JFR_SYSTEM, INFO, "Created native");
|
||||
JDKEvents.initialize();
|
||||
Logger.log(JFR_SYSTEM, INFO, "Registered JDK events");
|
||||
JDKEvents.addInstrumentation();
|
||||
startDiskMonitor();
|
||||
SecuritySupport.registerEvent(ActiveRecordingEvent.class);
|
||||
activeRecordingEvent = EventType.getEventType(ActiveRecordingEvent.class);
|
||||
SecuritySupport.registerEvent(ActiveSettingEvent.class);
|
||||
activeSettingEvent = EventType.getEventType(ActiveSettingEvent.class);
|
||||
shutdownHook = SecuritySupport.createThreadWitNoPermissions("JFR: Shutdown Hook", new ShutdownHook(this));
|
||||
SecuritySupport.setUncaughtExceptionHandler(shutdownHook, new ShutdownHook.ExceptionHandler());
|
||||
SecuritySupport.registerShutdownHook(shutdownHook);
|
||||
timer = createTimer();
|
||||
}
|
||||
|
||||
private static Timer createTimer() {
|
||||
try {
|
||||
List<Timer> result = new CopyOnWriteArrayList<>();
|
||||
Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
|
||||
result.add(new Timer("JFR Recording Scheduler", true));
|
||||
});
|
||||
t.start();
|
||||
t.join();
|
||||
return result.get(0);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized PlatformRecording newRecording(Map<String, String> settings) {
|
||||
return newRecording(settings, ++recordingCounter);
|
||||
}
|
||||
|
||||
// To be used internally when doing dumps.
|
||||
// Caller must have recorder lock and close recording before releasing lock
|
||||
public PlatformRecording newTemporaryRecording() {
|
||||
if(!Thread.holdsLock(this)) {
|
||||
throw new InternalError("Caller must have recorder lock");
|
||||
}
|
||||
return newRecording(new HashMap<>(), 0);
|
||||
}
|
||||
|
||||
private synchronized PlatformRecording newRecording(Map<String, String> settings, long id) {
|
||||
PlatformRecording recording = new PlatformRecording(this, id);
|
||||
if (!settings.isEmpty()) {
|
||||
recording.setSettings(settings);
|
||||
}
|
||||
recordings.add(recording);
|
||||
return recording;
|
||||
}
|
||||
|
||||
synchronized void finish(PlatformRecording recording) {
|
||||
if (recording.getState() == RecordingState.RUNNING) {
|
||||
recording.stop("Recording closed");
|
||||
}
|
||||
recordings.remove(recording);
|
||||
}
|
||||
|
||||
public synchronized List<PlatformRecording> getRecordings() {
|
||||
return Collections.unmodifiableList(new ArrayList<PlatformRecording>(recordings));
|
||||
}
|
||||
|
||||
public synchronized static void addListener(FlightRecorderListener changeListener) {
|
||||
AccessControlContext context = AccessController.getContext();
|
||||
SecureRecorderListener sl = new SecureRecorderListener(context, changeListener);
|
||||
boolean runInitialized;
|
||||
synchronized (PlatformRecorder.class) {
|
||||
runInitialized = FlightRecorder.isInitialized();
|
||||
changeListeners.add(sl);
|
||||
}
|
||||
if (runInitialized) {
|
||||
sl.recorderInitialized(FlightRecorder.getFlightRecorder());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static boolean removeListener(FlightRecorderListener changeListener) {
|
||||
for (SecureRecorderListener s : new ArrayList<>(changeListeners)) {
|
||||
if (s.getChangeListener() == changeListener) {
|
||||
changeListeners.remove(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static synchronized List<FlightRecorderListener> getListeners() {
|
||||
return new ArrayList<>(changeListeners);
|
||||
}
|
||||
|
||||
Timer getTimer() {
|
||||
return timer;
|
||||
}
|
||||
|
||||
public static void notifyRecorderInitialized(FlightRecorder recorder) {
|
||||
Logger.log(JFR_SYSTEM, TRACE, "Notifying listeners that Flight Recorder is initialized");
|
||||
for (FlightRecorderListener r : getListeners()) {
|
||||
r.recorderInitialized(recorder);
|
||||
}
|
||||
}
|
||||
|
||||
// called by shutdown hook
|
||||
synchronized void destroy() {
|
||||
try {
|
||||
timer.cancel();
|
||||
} catch (Exception ex) {
|
||||
Logger.log(JFR_SYSTEM, WARN, "Shutdown hook could not cancel timer");
|
||||
}
|
||||
|
||||
for (PlatformRecording p : getRecordings()) {
|
||||
if (p.getState() == RecordingState.RUNNING) {
|
||||
try {
|
||||
p.stop("Shutdown");
|
||||
} catch (Exception ex) {
|
||||
Logger.log(JFR, WARN, "Recording " + p.getName() + ":" + p.getId() + " could not be stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JDKEvents.remove();
|
||||
|
||||
if (jvm.hasNativeJFR()) {
|
||||
if (jvm.isRecording()) {
|
||||
jvm.endRecording_();
|
||||
}
|
||||
jvm.destroyNativeJFR();
|
||||
}
|
||||
repository.clear();
|
||||
}
|
||||
|
||||
synchronized void start(PlatformRecording recording) {
|
||||
// State can only be NEW or DELAYED because of previous checks
|
||||
Instant now = Instant.now();
|
||||
recording.setStartTime(now);
|
||||
recording.updateTimer();
|
||||
Duration duration = recording.getDuration();
|
||||
if (duration != null) {
|
||||
recording.setStopTime(now.plus(duration));
|
||||
}
|
||||
boolean toDisk = recording.isToDisk();
|
||||
boolean beginPhysical = true;
|
||||
for (PlatformRecording s : getRecordings()) {
|
||||
if (s.getState() == RecordingState.RUNNING) {
|
||||
beginPhysical = false;
|
||||
if (s.isToDisk()) {
|
||||
toDisk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (beginPhysical) {
|
||||
RepositoryChunk newChunk = null;
|
||||
if (toDisk) {
|
||||
newChunk = repository.newChunk(now);
|
||||
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
|
||||
} else {
|
||||
MetadataRepository.getInstance().setOutput(null);
|
||||
}
|
||||
currentChunk = newChunk;
|
||||
jvm.beginRecording_();
|
||||
recording.setState(RecordingState.RUNNING);
|
||||
updateSettings();
|
||||
writeMetaEvents();
|
||||
} else {
|
||||
RepositoryChunk newChunk = null;
|
||||
if (toDisk) {
|
||||
newChunk = repository.newChunk(now);
|
||||
RequestEngine.doChunkEnd();
|
||||
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
|
||||
}
|
||||
recording.setState(RecordingState.RUNNING);
|
||||
updateSettings();
|
||||
writeMetaEvents();
|
||||
if (currentChunk != null) {
|
||||
finishChunk(currentChunk, now, recording);
|
||||
}
|
||||
currentChunk = newChunk;
|
||||
}
|
||||
|
||||
RequestEngine.doChunkBegin();
|
||||
}
|
||||
|
||||
synchronized void stop(PlatformRecording recording) {
|
||||
RecordingState state = recording.getState();
|
||||
|
||||
if (Utils.isAfter(state, RecordingState.RUNNING)) {
|
||||
throw new IllegalStateException("Can't stop an already stopped recording.");
|
||||
}
|
||||
if (Utils.isBefore(state, RecordingState.RUNNING)) {
|
||||
throw new IllegalStateException("Recording must be started before it can be stopped.");
|
||||
}
|
||||
Instant now = Instant.now();
|
||||
boolean toDisk = false;
|
||||
boolean endPhysical = true;
|
||||
for (PlatformRecording s : getRecordings()) {
|
||||
RecordingState rs = s.getState();
|
||||
if (s != recording && RecordingState.RUNNING == rs) {
|
||||
endPhysical = false;
|
||||
if (s.isToDisk()) {
|
||||
toDisk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
OldObjectSample.emit(recording);
|
||||
|
||||
if (endPhysical) {
|
||||
RequestEngine.doChunkEnd();
|
||||
if (recording.isToDisk()) {
|
||||
if (currentChunk != null) {
|
||||
MetadataRepository.getInstance().setOutput(null);
|
||||
finishChunk(currentChunk, now, null);
|
||||
currentChunk = null;
|
||||
}
|
||||
} else {
|
||||
// last memory
|
||||
dumpMemoryToDestination(recording);
|
||||
}
|
||||
jvm.endRecording_();
|
||||
disableEvents();
|
||||
} else {
|
||||
RepositoryChunk newChunk = null;
|
||||
RequestEngine.doChunkEnd();
|
||||
updateSettingsButIgnoreRecording(recording);
|
||||
if (toDisk) {
|
||||
newChunk = repository.newChunk(now);
|
||||
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
|
||||
} else {
|
||||
MetadataRepository.getInstance().setOutput(null);
|
||||
}
|
||||
writeMetaEvents();
|
||||
if (currentChunk != null) {
|
||||
finishChunk(currentChunk, now, null);
|
||||
}
|
||||
currentChunk = newChunk;
|
||||
RequestEngine.doChunkBegin();
|
||||
}
|
||||
recording.setState(RecordingState.STOPPED);
|
||||
}
|
||||
|
||||
private void dumpMemoryToDestination(PlatformRecording recording) {
|
||||
WriteableUserPath dest = recording.getDestination();
|
||||
if (dest != null) {
|
||||
MetadataRepository.getInstance().setOutput(dest.getRealPathText());
|
||||
recording.clearDestination();
|
||||
}
|
||||
}
|
||||
private void disableEvents() {
|
||||
MetadataRepository.getInstance().disableEvents();
|
||||
}
|
||||
|
||||
void updateSettings() {
|
||||
updateSettingsButIgnoreRecording(null);
|
||||
}
|
||||
|
||||
void updateSettingsButIgnoreRecording(PlatformRecording ignoreMe) {
|
||||
List<PlatformRecording> recordings = getRunningRecordings();
|
||||
List<Map<String, String>> list = new ArrayList<>(recordings.size());
|
||||
for (PlatformRecording r : recordings) {
|
||||
if (r != ignoreMe) {
|
||||
list.add(r.getSettings());
|
||||
}
|
||||
}
|
||||
MetadataRepository.getInstance().setSettings(list);
|
||||
}
|
||||
|
||||
synchronized void rotateDisk() {
|
||||
Instant now = Instant.now();
|
||||
RepositoryChunk newChunk = repository.newChunk(now);
|
||||
RequestEngine.doChunkEnd();
|
||||
MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
|
||||
writeMetaEvents();
|
||||
if (currentChunk != null) {
|
||||
finishChunk(currentChunk, now, null);
|
||||
}
|
||||
currentChunk = newChunk;
|
||||
RequestEngine.doChunkBegin();
|
||||
}
|
||||
|
||||
private List<PlatformRecording> getRunningRecordings() {
|
||||
List<PlatformRecording> runningRecordings = new ArrayList<>();
|
||||
for (PlatformRecording recording : getRecordings()) {
|
||||
if (recording.getState() == RecordingState.RUNNING) {
|
||||
runningRecordings.add(recording);
|
||||
}
|
||||
}
|
||||
return runningRecordings;
|
||||
}
|
||||
|
||||
private List<RepositoryChunk> makeChunkList(Instant startTime, Instant endTime) {
|
||||
Set<RepositoryChunk> chunkSet = new HashSet<>();
|
||||
for (PlatformRecording r : getRecordings()) {
|
||||
chunkSet.addAll(r.getChunks());
|
||||
}
|
||||
if (chunkSet.size() > 0) {
|
||||
List<RepositoryChunk> chunks = new ArrayList<>(chunkSet.size());
|
||||
for (RepositoryChunk rc : chunkSet) {
|
||||
if (rc.inInterval(startTime, endTime)) {
|
||||
chunks.add(rc);
|
||||
}
|
||||
}
|
||||
// n*log(n), should be able to do n*log(k) with a priority queue,
|
||||
// where k = number of recordings, n = number of chunks
|
||||
Collections.sort(chunks, RepositoryChunk.END_TIME_COMPARATOR);
|
||||
return chunks;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private void startDiskMonitor() {
|
||||
Thread t = SecuritySupport.createThreadWitNoPermissions("JFR Periodic Tasks", () -> periodicTask());
|
||||
SecuritySupport.setDaemonThread(t, true);
|
||||
t.start();
|
||||
}
|
||||
|
||||
private void finishChunk(RepositoryChunk chunk, Instant time, PlatformRecording ignoreMe) {
|
||||
chunk.finish(time);
|
||||
for (PlatformRecording r : getRecordings()) {
|
||||
if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
|
||||
r.appendChunk(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMetaEvents() {
|
||||
|
||||
if (activeRecordingEvent.isEnabled()) {
|
||||
for (PlatformRecording r : getRecordings()) {
|
||||
if (r.getState() == RecordingState.RUNNING && r.shouldWriteMetadataEvent()) {
|
||||
ActiveRecordingEvent event = new ActiveRecordingEvent();
|
||||
event.id = r.getId();
|
||||
event.name = r.getName();
|
||||
WriteableUserPath p = r.getDestination();
|
||||
event.destination = p == null ? null : p.getRealPathText();
|
||||
Duration d = r.getDuration();
|
||||
event.recordingDuration = d == null ? Long.MAX_VALUE : d.toMillis();
|
||||
Duration age = r.getMaxAge();
|
||||
event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
|
||||
Long size = r.getMaxSize();
|
||||
event.maxSize = size == null ? Long.MAX_VALUE : size;
|
||||
Instant start = r.getStartTime();
|
||||
event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeSettingEvent.isEnabled()) {
|
||||
for (EventControl ec : MetadataRepository.getInstance().getEventControls()) {
|
||||
ec.writeActiveSettingEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void periodicTask() {
|
||||
if (!jvm.hasNativeJFR()) {
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
synchronized (this) {
|
||||
if (jvm.shouldRotateDisk()) {
|
||||
rotateDisk();
|
||||
}
|
||||
}
|
||||
long minDelta = RequestEngine.doPeriodic();
|
||||
long wait = Math.min(minDelta, Options.getWaitInterval());
|
||||
takeNap(wait);
|
||||
}
|
||||
}
|
||||
|
||||
private void takeNap(long duration) {
|
||||
try {
|
||||
synchronized (JVM.FILE_DELTA_CHANGE) {
|
||||
JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized Recording newCopy(PlatformRecording r, boolean stop) {
|
||||
Recording newRec = new Recording();
|
||||
PlatformRecording copy = PrivateAccess.getInstance().getPlatformRecording(newRec);
|
||||
copy.setSettings(r.getSettings());
|
||||
copy.setMaxAge(r.getMaxAge());
|
||||
copy.setMaxSize(r.getMaxSize());
|
||||
copy.setDumpOnExit(r.getDumpOnExit());
|
||||
copy.setName("Clone of " + r.getName());
|
||||
copy.setToDisk(r.isToDisk());
|
||||
copy.setInternalDuration(r.getDuration());
|
||||
copy.setStartTime(r.getStartTime());
|
||||
copy.setStopTime(r.getStopTime());
|
||||
|
||||
if (r.getState() == RecordingState.NEW) {
|
||||
return newRec;
|
||||
}
|
||||
if (r.getState() == RecordingState.DELAYED) {
|
||||
copy.scheduleStart(r.getStartTime());
|
||||
return newRec;
|
||||
}
|
||||
copy.setState(r.getState());
|
||||
// recording has started, copy chunks
|
||||
for (RepositoryChunk c : r.getChunks()) {
|
||||
copy.add(c);
|
||||
}
|
||||
if (r.getState() == RecordingState.RUNNING) {
|
||||
if (stop) {
|
||||
copy.stop("Stopped when cloning recording '" + r.getName() + "'");
|
||||
} else {
|
||||
if (r.getStopTime() != null) {
|
||||
TimerTask stopTask = copy.createStopTask();
|
||||
copy.setStopTask(copy.createStopTask());
|
||||
getTimer().schedule(stopTask, r.getStopTime().toEpochMilli());
|
||||
}
|
||||
}
|
||||
}
|
||||
return newRec;
|
||||
}
|
||||
|
||||
public synchronized void fillWithRecordedData(PlatformRecording target, Boolean pathToGcRoots) {
|
||||
boolean running = false;
|
||||
boolean toDisk = false;
|
||||
|
||||
for (PlatformRecording r : recordings) {
|
||||
if (r.getState() == RecordingState.RUNNING) {
|
||||
running = true;
|
||||
if (r.isToDisk()) {
|
||||
toDisk = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If needed, flush data from memory
|
||||
if (running) {
|
||||
if (toDisk) {
|
||||
OldObjectSample.emit(recordings, pathToGcRoots);
|
||||
rotateDisk();
|
||||
} else {
|
||||
try (PlatformRecording snapshot = newTemporaryRecording()) {
|
||||
snapshot.setToDisk(true);
|
||||
snapshot.setShouldWriteActiveRecordingEvent(false);
|
||||
snapshot.start();
|
||||
OldObjectSample.emit(recordings, pathToGcRoots);
|
||||
snapshot.stop("Snapshot dump");
|
||||
fillWithDiskChunks(target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
fillWithDiskChunks(target);
|
||||
}
|
||||
|
||||
private void fillWithDiskChunks(PlatformRecording target) {
|
||||
for (RepositoryChunk c : makeChunkList(null, null)) {
|
||||
target.add(c);
|
||||
}
|
||||
target.setState(RecordingState.STOPPED);
|
||||
Instant startTime = null;
|
||||
Instant endTime = null;
|
||||
|
||||
for (RepositoryChunk c : target.getChunks()) {
|
||||
if (startTime == null || c.getStartTime().isBefore(startTime)) {
|
||||
startTime = c.getStartTime();
|
||||
}
|
||||
if (endTime == null || c.getEndTime().isAfter(endTime)) {
|
||||
endTime = c.getEndTime();
|
||||
}
|
||||
}
|
||||
Instant now = Instant.now();
|
||||
if (startTime == null) {
|
||||
startTime = now;
|
||||
}
|
||||
if (endTime == null) {
|
||||
endTime = now;
|
||||
}
|
||||
target.setStartTime(startTime);
|
||||
target.setStopTime(endTime);
|
||||
target.setInternalDuration(Duration.between(startTime, endTime));
|
||||
}
|
||||
}
|
||||
781
jdkSrc/jdk8/jdk/jfr/internal/PlatformRecording.java
Normal file
781
jdkSrc/jdk8/jdk/jfr/internal/PlatformRecording.java
Normal file
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import static jdk.jfr.internal.LogLevel.DEBUG;
|
||||
import static jdk.jfr.internal.LogLevel.WARN;
|
||||
import static jdk.jfr.internal.LogTag.JFR;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.TimerTask;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import jdk.jfr.Configuration;
|
||||
import jdk.jfr.FlightRecorderListener;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.RecordingState;
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
|
||||
public final class PlatformRecording implements AutoCloseable {
|
||||
|
||||
private final PlatformRecorder recorder;
|
||||
private final long id;
|
||||
// Recording settings
|
||||
private Map<String, String> settings = new LinkedHashMap<>();
|
||||
private Duration duration;
|
||||
private Duration maxAge;
|
||||
private long maxSize;
|
||||
|
||||
private WriteableUserPath destination;
|
||||
|
||||
private boolean toDisk = true;
|
||||
private String name;
|
||||
private boolean dumpOnExit;
|
||||
private SafePath dumpOnExitDirectory = new SafePath(".");
|
||||
// Timestamp information
|
||||
private Instant stopTime;
|
||||
private Instant startTime;
|
||||
|
||||
// Misc, information
|
||||
private RecordingState state = RecordingState.NEW;
|
||||
private long size;
|
||||
private final LinkedList<RepositoryChunk> chunks = new LinkedList<>();
|
||||
private volatile Recording recording;
|
||||
private TimerTask stopTask;
|
||||
private TimerTask startTask;
|
||||
private AccessControlContext noDestinationDumpOnExitAccessControlContext;
|
||||
private boolean shuoldWriteActiveRecordingEvent = true;
|
||||
|
||||
PlatformRecording(PlatformRecorder recorder, long id) {
|
||||
// Typically the access control context is taken
|
||||
// when you call dump(Path) or setDdestination(Path),
|
||||
// but if no destination is set and dumponexit=true
|
||||
// the control context of the recording is taken when the
|
||||
// Recording object is constructed. This works well for
|
||||
// -XX:StartFlightRecording and JFR.dump
|
||||
this.noDestinationDumpOnExitAccessControlContext = AccessController.getContext();
|
||||
this.id = id;
|
||||
this.recorder = recorder;
|
||||
this.name = String.valueOf(id);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
RecordingState oldState;
|
||||
RecordingState newState;
|
||||
synchronized (recorder) {
|
||||
oldState = getState();
|
||||
if (!Utils.isBefore(state, RecordingState.RUNNING)) {
|
||||
throw new IllegalStateException("Recording can only be started once.");
|
||||
}
|
||||
if (startTask != null) {
|
||||
startTask.cancel();
|
||||
startTask = null;
|
||||
startTime = null;
|
||||
}
|
||||
recorder.start(this);
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, () -> {
|
||||
// Only print non-default values so it easy to see
|
||||
// which options were added
|
||||
StringJoiner options = new StringJoiner(", ");
|
||||
if (!toDisk) {
|
||||
options.add("disk=false");
|
||||
}
|
||||
if (maxAge != null) {
|
||||
options.add("maxage=" + Utils.formatTimespan(maxAge, ""));
|
||||
}
|
||||
if (maxSize != 0) {
|
||||
options.add("maxsize=" + Utils.formatBytesCompact(maxSize));
|
||||
}
|
||||
if (dumpOnExit) {
|
||||
options.add("dumponexit=true");
|
||||
}
|
||||
if (duration != null) {
|
||||
options.add("duration=" + Utils.formatTimespan(duration, ""));
|
||||
}
|
||||
if (destination != null) {
|
||||
options.add("filename=" + destination.getRealPathText());
|
||||
}
|
||||
String optionText = options.toString();
|
||||
if (optionText.length() != 0) {
|
||||
optionText = "{" + optionText + "}";
|
||||
}
|
||||
return "Started recording \"" + getName() + "\" (" + getId() + ") " + optionText;
|
||||
});
|
||||
newState = getState();
|
||||
}
|
||||
notifyIfStateChanged(oldState, newState);
|
||||
}
|
||||
|
||||
public boolean stop(String reason) {
|
||||
RecordingState oldState;
|
||||
RecordingState newState;
|
||||
synchronized (recorder) {
|
||||
oldState = getState();
|
||||
if (stopTask != null) {
|
||||
stopTask.cancel();
|
||||
stopTask = null;
|
||||
}
|
||||
recorder.stop(this);
|
||||
String endText = reason == null ? "" : ". Reason \"" + reason + "\".";
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Stopped recording \"" + getName() + "\" (" + getId() + ")" + endText);
|
||||
this.stopTime = Instant.now();
|
||||
newState = getState();
|
||||
}
|
||||
WriteableUserPath dest = getDestination();
|
||||
|
||||
if (dest != null) {
|
||||
try {
|
||||
dumpStopped(dest);
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Wrote recording \"" + getName() + "\" (" + getId() + ") to " + dest.getRealPathText());
|
||||
notifyIfStateChanged(newState, oldState);
|
||||
close(); // remove if copied out
|
||||
} catch(IOException e) {
|
||||
// throw e; // BUG8925030
|
||||
}
|
||||
} else {
|
||||
notifyIfStateChanged(newState, oldState);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void scheduleStart(Duration delay) {
|
||||
synchronized (recorder) {
|
||||
ensureOkForSchedule();
|
||||
|
||||
startTime = Instant.now().plus(delay);
|
||||
LocalDateTime now = LocalDateTime.now().plus(delay);
|
||||
setState(RecordingState.DELAYED);
|
||||
startTask = createStartTask();
|
||||
recorder.getTimer().schedule(startTask, delay.toMillis());
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Scheduled recording \"" + getName() + "\" (" + getId() + ") to start at " + now);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureOkForSchedule() {
|
||||
if (getState() != RecordingState.NEW) {
|
||||
throw new IllegalStateException("Only a new recoridng can be scheduled for start");
|
||||
}
|
||||
}
|
||||
|
||||
private TimerTask createStartTask() {
|
||||
// Taking ref. to recording here.
|
||||
// Opens up for memory leaks.
|
||||
return new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (recorder) {
|
||||
if (getState() != RecordingState.DELAYED) {
|
||||
return;
|
||||
}
|
||||
start();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void scheduleStart(Instant startTime) {
|
||||
synchronized (recorder) {
|
||||
ensureOkForSchedule();
|
||||
this.startTime = startTime;
|
||||
setState(RecordingState.DELAYED);
|
||||
startTask = createStartTask();
|
||||
recorder.getTimer().schedule(startTask, startTime.toEpochMilli());
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getSettings() {
|
||||
synchronized (recorder) {
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public Instant getStopTime() {
|
||||
synchronized (recorder) {
|
||||
return stopTime;
|
||||
}
|
||||
}
|
||||
|
||||
public Instant getStartTime() {
|
||||
synchronized (recorder) {
|
||||
return startTime;
|
||||
}
|
||||
}
|
||||
|
||||
public Long getMaxSize() {
|
||||
synchronized (recorder) {
|
||||
return maxSize;
|
||||
}
|
||||
}
|
||||
|
||||
public Duration getMaxAge() {
|
||||
synchronized (recorder) {
|
||||
return maxAge;
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
synchronized (recorder) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public RecordingState getState() {
|
||||
synchronized (recorder) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
RecordingState oldState;
|
||||
RecordingState newState;
|
||||
|
||||
synchronized (recorder) {
|
||||
oldState = getState();
|
||||
if (RecordingState.CLOSED != getState()) {
|
||||
if (startTask != null) {
|
||||
startTask.cancel();
|
||||
startTask = null;
|
||||
}
|
||||
recorder.finish(this);
|
||||
for (RepositoryChunk c : chunks) {
|
||||
removed(c);
|
||||
}
|
||||
chunks.clear();
|
||||
setState(RecordingState.CLOSED);
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Closed recording \"" + getName() + "\" (" + getId() + ")");
|
||||
}
|
||||
newState = getState();
|
||||
}
|
||||
notifyIfStateChanged(newState, oldState);
|
||||
}
|
||||
|
||||
// To be used internally when doing dumps.
|
||||
// Caller must have recorder lock and close recording before releasing lock
|
||||
public PlatformRecording newSnapshotClone(String reason, Boolean pathToGcRoots) throws IOException {
|
||||
if(!Thread.holdsLock(recorder)) {
|
||||
throw new InternalError("Caller must have recorder lock");
|
||||
}
|
||||
RecordingState state = getState();
|
||||
if (state == RecordingState.CLOSED) {
|
||||
throw new IOException("Recording \"" + name + "\" (id=" + id + ") has been closed, no contents to write");
|
||||
}
|
||||
if (state == RecordingState.DELAYED || state == RecordingState.NEW) {
|
||||
throw new IOException("Recording \"" + name + "\" (id=" + id + ") has not started, no contents to write");
|
||||
}
|
||||
if (state == RecordingState.STOPPED) {
|
||||
PlatformRecording clone = recorder.newTemporaryRecording();
|
||||
for (RepositoryChunk r : chunks) {
|
||||
clone.add(r);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
// Recording is RUNNING, create a clone
|
||||
PlatformRecording clone = recorder.newTemporaryRecording();
|
||||
clone.setShouldWriteActiveRecordingEvent(false);
|
||||
clone.setName(getName());
|
||||
clone.setToDisk(true);
|
||||
// We purposely don't clone settings here, since
|
||||
// a union a == a
|
||||
if (!isToDisk()) {
|
||||
// force memory contents to disk
|
||||
clone.start();
|
||||
} else {
|
||||
// using existing chunks on disk
|
||||
for (RepositoryChunk c : chunks) {
|
||||
clone.add(c);
|
||||
}
|
||||
clone.setState(RecordingState.RUNNING);
|
||||
clone.setStartTime(getStartTime());
|
||||
}
|
||||
if (pathToGcRoots == null) {
|
||||
clone.setSettings(getSettings()); // needed for old object sample
|
||||
clone.stop(reason); // dumps to destination path here
|
||||
} else {
|
||||
// Risk of violating lock order here, since
|
||||
// clone.stop() will take recorder lock inside
|
||||
// metadata lock, but OK if we already
|
||||
// have recorder lock when we entered metadata lock
|
||||
synchronized (MetadataRepository.getInstance()) {
|
||||
clone.setSettings(OldObjectSample.createSettingsForSnapshot(this, pathToGcRoots));
|
||||
clone.stop(reason);
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
public boolean isToDisk() {
|
||||
synchronized (recorder) {
|
||||
return toDisk;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaxSize(long maxSize) {
|
||||
synchronized (recorder) {
|
||||
if (getState() == RecordingState.CLOSED) {
|
||||
throw new IllegalStateException("Can't set max age when recording is closed");
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDestination(WriteableUserPath userSuppliedPath) throws IOException {
|
||||
synchronized (recorder) {
|
||||
if (Utils.isState(getState(), RecordingState.STOPPED, RecordingState.CLOSED)) {
|
||||
throw new IllegalStateException("Destination can't be set on a recording that has been stopped/closed");
|
||||
}
|
||||
this.destination = userSuppliedPath;
|
||||
}
|
||||
}
|
||||
|
||||
public WriteableUserPath getDestination() {
|
||||
synchronized (recorder) {
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
|
||||
void setState(RecordingState state) {
|
||||
synchronized (recorder) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
void setStartTime(Instant startTime) {
|
||||
synchronized (recorder) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
}
|
||||
|
||||
void setStopTime(Instant timeStamp) {
|
||||
synchronized (recorder) {
|
||||
stopTime = timeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
synchronized (recorder) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
synchronized (recorder) {
|
||||
ensureNotClosed();
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureNotClosed() {
|
||||
if (getState() == RecordingState.CLOSED) {
|
||||
throw new IllegalStateException("Can't change name on a closed recording");
|
||||
}
|
||||
}
|
||||
|
||||
public void setDumpOnExit(boolean dumpOnExit) {
|
||||
synchronized (recorder) {
|
||||
this.dumpOnExit = dumpOnExit;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getDumpOnExit() {
|
||||
synchronized (recorder) {
|
||||
return dumpOnExit;
|
||||
}
|
||||
}
|
||||
|
||||
public void setToDisk(boolean toDisk) {
|
||||
synchronized (recorder) {
|
||||
if (Utils.isState(getState(), RecordingState.NEW, RecordingState.DELAYED)) {
|
||||
this.toDisk = toDisk;
|
||||
} else {
|
||||
throw new IllegalStateException("Recording option disk can't be changed after recording has started");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSetting(String id, String value) {
|
||||
synchronized (recorder) {
|
||||
this.settings.put(id, value);
|
||||
if (getState() == RecordingState.RUNNING) {
|
||||
recorder.updateSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettings(Map<String, String> settings) {
|
||||
setSettings(settings, true);
|
||||
}
|
||||
|
||||
private void setSettings(Map<String, String> settings, boolean update) {
|
||||
if (Logger.shouldLog(LogTag.JFR_SETTING, LogLevel.INFO) && update) {
|
||||
TreeMap<String, String> ordered = new TreeMap<>(settings);
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, "New settings for recording \"" + getName() + "\" (" + getId() + ")");
|
||||
for (Map.Entry<String, String> entry : ordered.entrySet()) {
|
||||
String text = entry.getKey() + "=\"" + entry.getValue() + "\"";
|
||||
Logger.log(LogTag.JFR_SETTING, LogLevel.INFO, text);
|
||||
}
|
||||
}
|
||||
synchronized (recorder) {
|
||||
this.settings = new LinkedHashMap<>(settings);
|
||||
if (getState() == RecordingState.RUNNING && update) {
|
||||
recorder.updateSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyIfStateChanged(RecordingState newState, RecordingState oldState) {
|
||||
if (oldState == newState) {
|
||||
return;
|
||||
}
|
||||
for (FlightRecorderListener cl : PlatformRecorder.getListeners()) {
|
||||
try {
|
||||
cl.recordingStateChanged(getRecording());
|
||||
} catch (RuntimeException re) {
|
||||
Logger.log(JFR, WARN, "Error notifying recorder listener:" + re.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRecording(Recording recording) {
|
||||
this.recording = recording;
|
||||
}
|
||||
|
||||
public Recording getRecording() {
|
||||
return recording;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName() + " (id=" + getId() + ") " + getState();
|
||||
}
|
||||
|
||||
public void setConfiguration(Configuration c) {
|
||||
setSettings(c.getSettings());
|
||||
}
|
||||
|
||||
public void setMaxAge(Duration maxAge) {
|
||||
synchronized (recorder) {
|
||||
if (getState() == RecordingState.CLOSED) {
|
||||
throw new IllegalStateException("Can't set max age when recording is closed");
|
||||
}
|
||||
this.maxAge = maxAge;
|
||||
if (maxAge != null) {
|
||||
trimToAge(Instant.now().minus(maxAge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void appendChunk(RepositoryChunk chunk) {
|
||||
if (!chunk.isFinished()) {
|
||||
throw new Error("not finished chunk " + chunk.getStartTime());
|
||||
}
|
||||
synchronized (recorder) {
|
||||
if (!toDisk) {
|
||||
return;
|
||||
}
|
||||
if (maxAge != null) {
|
||||
trimToAge(chunk.getEndTime().minus(maxAge));
|
||||
}
|
||||
chunks.addLast(chunk);
|
||||
added(chunk);
|
||||
trimToSize();
|
||||
}
|
||||
}
|
||||
|
||||
private void trimToSize() {
|
||||
if (maxSize == 0) {
|
||||
return;
|
||||
}
|
||||
while (size > maxSize && chunks.size() > 1) {
|
||||
RepositoryChunk c = chunks.removeFirst();
|
||||
removed(c);
|
||||
}
|
||||
}
|
||||
|
||||
private void trimToAge(Instant oldest) {
|
||||
while (!chunks.isEmpty()) {
|
||||
RepositoryChunk oldestChunk = chunks.peek();
|
||||
if (oldestChunk.getEndTime().isAfter(oldest)) {
|
||||
return;
|
||||
}
|
||||
chunks.removeFirst();
|
||||
removed(oldestChunk);
|
||||
}
|
||||
}
|
||||
|
||||
void add(RepositoryChunk c) {
|
||||
chunks.add(c);
|
||||
added(c);
|
||||
}
|
||||
|
||||
private void added(RepositoryChunk c) {
|
||||
c.use();
|
||||
size += c.getSize();
|
||||
Logger.log(JFR, DEBUG, () -> "Recording \"" + name + "\" (" + id + ") added chunk " + c.toString() + ", current size=" + size);
|
||||
}
|
||||
|
||||
private void removed(RepositoryChunk c) {
|
||||
size -= c.getSize();
|
||||
Logger.log(JFR, DEBUG, () -> "Recording \"" + name + "\" (" + id + ") removed chunk " + c.toString() + ", current size=" + size);
|
||||
c.release();
|
||||
}
|
||||
|
||||
public List<RepositoryChunk> getChunks() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
public InputStream open(Instant start, Instant end) throws IOException {
|
||||
synchronized (recorder) {
|
||||
if (getState() != RecordingState.STOPPED) {
|
||||
throw new IOException("Recording must be stopped before it can be read.");
|
||||
}
|
||||
List<RepositoryChunk> chunksToUse = new ArrayList<RepositoryChunk>();
|
||||
for (RepositoryChunk chunk : chunks) {
|
||||
if (chunk.isFinished()) {
|
||||
Instant chunkStart = chunk.getStartTime();
|
||||
Instant chunkEnd = chunk.getEndTime();
|
||||
if (start == null || !chunkEnd.isBefore(start)) {
|
||||
if (end == null || !chunkStart.isAfter(end)) {
|
||||
chunksToUse.add(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chunksToUse.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new ChunkInputStream(chunksToUse);
|
||||
}
|
||||
}
|
||||
|
||||
public Duration getDuration() {
|
||||
synchronized (recorder) {
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
void setInternalDuration(Duration duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public void setDuration(Duration duration) {
|
||||
synchronized (recorder) {
|
||||
if (Utils.isState(getState(), RecordingState.STOPPED, RecordingState.CLOSED)) {
|
||||
throw new IllegalStateException("Duration can't be set after a recording has been stopped/closed");
|
||||
}
|
||||
setInternalDuration(duration);
|
||||
if (getState() != RecordingState.NEW) {
|
||||
updateTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateTimer() {
|
||||
if (stopTask != null) {
|
||||
stopTask.cancel();
|
||||
stopTask = null;
|
||||
}
|
||||
if (getState() == RecordingState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
if (duration != null) {
|
||||
stopTask = createStopTask();
|
||||
recorder.getTimer().schedule(stopTask, new Date(startTime.plus(duration).toEpochMilli()));
|
||||
}
|
||||
}
|
||||
|
||||
TimerTask createStopTask() {
|
||||
return new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
stop("End of duration reached");
|
||||
} catch (Throwable t) {
|
||||
// Prevent malicious user to propagate exception callback in the wrong context
|
||||
Logger.log(LogTag.JFR, LogLevel.ERROR, "Could not stop recording.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public Recording newCopy(boolean stop) {
|
||||
return recorder.newCopy(this, stop);
|
||||
}
|
||||
|
||||
void setStopTask(TimerTask stopTask) {
|
||||
synchronized (recorder) {
|
||||
this.stopTask = stopTask;
|
||||
}
|
||||
}
|
||||
|
||||
void clearDestination() {
|
||||
destination = null;
|
||||
}
|
||||
|
||||
public AccessControlContext getNoDestinationDumpOnExitAccessControlContext() {
|
||||
return noDestinationDumpOnExitAccessControlContext;
|
||||
}
|
||||
|
||||
void setShouldWriteActiveRecordingEvent(boolean shouldWrite) {
|
||||
this.shuoldWriteActiveRecordingEvent = shouldWrite;
|
||||
}
|
||||
|
||||
boolean shouldWriteMetadataEvent() {
|
||||
return shuoldWriteActiveRecordingEvent;
|
||||
}
|
||||
|
||||
// Dump running and stopped recordings
|
||||
public void dump(WriteableUserPath writeableUserPath) throws IOException {
|
||||
synchronized (recorder) {
|
||||
try(PlatformRecording p = newSnapshotClone("Dumped by user", null)) {
|
||||
p.dumpStopped(writeableUserPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpStopped(WriteableUserPath userPath) throws IOException {
|
||||
synchronized (recorder) {
|
||||
userPath.doPriviligedIO(() -> {
|
||||
try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(userPath.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
|
||||
long bytes = cc.transferTo(fc);
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Transferred " + bytes + " bytes from the disk repository");
|
||||
// No need to force if no data was transferred, which avoids IOException when device is /dev/null
|
||||
if (bytes != 0) {
|
||||
fc.force(true);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void filter(Instant begin, Instant end, Long maxSize) {
|
||||
synchronized (recorder) {
|
||||
List<RepositoryChunk> result = removeAfter(end, removeBefore(begin, new ArrayList<>(chunks)));
|
||||
if (maxSize != null) {
|
||||
if (begin != null && end == null) {
|
||||
result = reduceFromBeginning(maxSize, result);
|
||||
} else {
|
||||
result = reduceFromEnd(maxSize, result);
|
||||
}
|
||||
}
|
||||
int size = 0;
|
||||
for (RepositoryChunk r : result) {
|
||||
size += r.getSize();
|
||||
r.use();
|
||||
}
|
||||
this.size = size;
|
||||
for (RepositoryChunk r : chunks) {
|
||||
r.release();
|
||||
}
|
||||
chunks.clear();
|
||||
chunks.addAll(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<RepositoryChunk> removeBefore(Instant time, List<RepositoryChunk> input) {
|
||||
if (time == null) {
|
||||
return input;
|
||||
}
|
||||
List<RepositoryChunk> result = new ArrayList<>(input.size());
|
||||
for (RepositoryChunk r : input) {
|
||||
if (!r.getEndTime().isBefore(time)) {
|
||||
result.add(r);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<RepositoryChunk> removeAfter(Instant time, List<RepositoryChunk> input) {
|
||||
if (time == null) {
|
||||
return input;
|
||||
}
|
||||
List<RepositoryChunk> result = new ArrayList<>(input.size());
|
||||
for (RepositoryChunk r : input) {
|
||||
if (!r.getStartTime().isAfter(time)) {
|
||||
result.add(r);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<RepositoryChunk> reduceFromBeginning(Long maxSize, List<RepositoryChunk> input) {
|
||||
if (maxSize == null || input.isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
List<RepositoryChunk> result = new ArrayList<>(input.size());
|
||||
long total = 0;
|
||||
for (RepositoryChunk r : input) {
|
||||
total += r.getSize();
|
||||
if (total > maxSize) {
|
||||
break;
|
||||
}
|
||||
result.add(r);
|
||||
}
|
||||
// always keep at least one chunk
|
||||
if (result.isEmpty()) {
|
||||
result.add(input.get(0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<RepositoryChunk> reduceFromEnd(Long maxSize, List<RepositoryChunk> input) {
|
||||
Collections.reverse(input);
|
||||
List<RepositoryChunk> result = reduceFromBeginning(maxSize, input);
|
||||
Collections.reverse(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDumpOnExitDirectory(SafePath directory) {
|
||||
this.dumpOnExitDirectory = directory;
|
||||
}
|
||||
|
||||
public SafePath getDumpOnExitDirectory() {
|
||||
return this.dumpOnExitDirectory;
|
||||
}
|
||||
}
|
||||
97
jdkSrc/jdk8/jdk/jfr/internal/PrivateAccess.java
Normal file
97
jdkSrc/jdk8/jdk/jfr/internal/PrivateAccess.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.AnnotationElement;
|
||||
import jdk.jfr.Configuration;
|
||||
import jdk.jfr.EventType;
|
||||
import jdk.jfr.FlightRecorderPermission;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.SettingDescriptor;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
|
||||
/**
|
||||
* Provides access to package private function in jdk.jfr.
|
||||
* <p>
|
||||
* The static initializer in this class loads the Settings class, which will
|
||||
* call {@link #setPrivateAccess(PrivateAccess)} on this class, which can be
|
||||
* used call to package protected methods.
|
||||
*
|
||||
* This is similar to how java.lang accesses package private methods in
|
||||
* java.lang.reflect.
|
||||
*/
|
||||
public abstract class PrivateAccess {
|
||||
private volatile static PrivateAccess instance;
|
||||
|
||||
public static PrivateAccess getInstance() {
|
||||
// Can't be initialized in <clinit> because it may
|
||||
// deadlock with FlightRecordeerPermission.<clinit>
|
||||
if (instance == null) {
|
||||
// Will trigger
|
||||
// FlightRecordeerPermission.<clinit>
|
||||
// which will call PrivateAccess.setPrivateAccess
|
||||
new FlightRecorderPermission(Utils.REGISTER_EVENT);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void setPrivateAccess(PrivateAccess pa) {
|
||||
instance = pa;
|
||||
}
|
||||
|
||||
public abstract Type getType(Object o);
|
||||
|
||||
public abstract Configuration newConfiguration(String name, String label, String description, String provider, Map<String,String> settings, String contents);
|
||||
|
||||
public abstract EventType newEventType(PlatformEventType eventTypes);
|
||||
|
||||
public abstract AnnotationElement newAnnotation(Type annotationType, List<Object> values, boolean boot);
|
||||
|
||||
public abstract ValueDescriptor newValueDescriptor(String name, Type fieldType, List<AnnotationElement> annotations, int dimension, boolean constantPool, String fieldName);
|
||||
|
||||
public abstract PlatformRecording getPlatformRecording(Recording r);
|
||||
|
||||
public abstract PlatformEventType getPlatformEventType(EventType eventType);
|
||||
|
||||
public abstract boolean isConstantPool(ValueDescriptor v);
|
||||
|
||||
public abstract String getFieldName(ValueDescriptor v);
|
||||
|
||||
public abstract ValueDescriptor newValueDescriptor(Class<?> type, String name);
|
||||
|
||||
public abstract SettingDescriptor newSettingDescriptor(Type type, String name, String def, List<AnnotationElement> aes);
|
||||
|
||||
public abstract void setAnnotations(ValueDescriptor v, List<AnnotationElement> a);
|
||||
|
||||
public abstract void setAnnotations(SettingDescriptor s, List<AnnotationElement> a);
|
||||
|
||||
public abstract boolean isUnsigned(ValueDescriptor v);
|
||||
|
||||
public abstract PlatformRecorder getPlatformRecorder();
|
||||
}
|
||||
165
jdkSrc/jdk8/jdk/jfr/internal/Repository.java
Normal file
165
jdkSrc/jdk8/jdk/jfr/internal/Repository.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.jfr.internal.SecuritySupport.SafePath;
|
||||
|
||||
public final class Repository {
|
||||
|
||||
private static final int MAX_REPO_CREATION_RETRIES = 1000;
|
||||
private static final JVM jvm = JVM.getJVM();
|
||||
private static final Repository instance = new Repository();
|
||||
|
||||
public final static DateTimeFormatter REPO_DATE_FORMAT = DateTimeFormatter
|
||||
.ofPattern("yyyy_MM_dd_HH_mm_ss");
|
||||
|
||||
private final Set<SafePath> cleanupDirectories = new HashSet<>();
|
||||
private SafePath baseLocation;
|
||||
private SafePath repository;
|
||||
|
||||
private Repository() {
|
||||
}
|
||||
|
||||
public static Repository getRepository() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public synchronized void setBasePath(SafePath baseLocation) throws Exception {
|
||||
// Probe to see if repository can be created, needed for fail fast
|
||||
// during JVM startup or JFR.configure
|
||||
this.repository = createRepository(baseLocation);
|
||||
try {
|
||||
// Remove so we don't "leak" repositories, if JFR is never started
|
||||
// and shutdown hook not added.
|
||||
SecuritySupport.delete(repository);
|
||||
} catch (IOException ioe) {
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Could not delete disk repository " + repository);
|
||||
}
|
||||
this.baseLocation = baseLocation;
|
||||
}
|
||||
|
||||
synchronized void ensureRepository() throws Exception {
|
||||
if (baseLocation == null) {
|
||||
setBasePath(SecuritySupport.JAVA_IO_TMPDIR);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized RepositoryChunk newChunk(Instant timestamp) {
|
||||
try {
|
||||
if (!SecuritySupport.existDirectory(repository)) {
|
||||
this.repository = createRepository(baseLocation);
|
||||
jvm.setRepositoryLocation(repository.toString());
|
||||
cleanupDirectories.add(repository);
|
||||
}
|
||||
return new RepositoryChunk(repository, timestamp);
|
||||
} catch (Exception e) {
|
||||
String errorMsg = String.format("Could not create chunk in repository %s, %s", repository, e.getMessage());
|
||||
Logger.log(LogTag.JFR, LogLevel.ERROR, errorMsg);
|
||||
jvm.abort(errorMsg);
|
||||
throw new InternalError("Could not abort after JFR disk creation error");
|
||||
}
|
||||
}
|
||||
|
||||
private static SafePath createRepository(SafePath basePath) throws Exception {
|
||||
SafePath canonicalBaseRepositoryPath = createRealBasePath(basePath);
|
||||
SafePath f = null;
|
||||
|
||||
String basename = REPO_DATE_FORMAT.format(LocalDateTime.now()) + "_" + JVM.getJVM().getPid();
|
||||
String name = basename;
|
||||
|
||||
int i = 0;
|
||||
for (; i < MAX_REPO_CREATION_RETRIES; i++) {
|
||||
f = new SafePath(canonicalBaseRepositoryPath.toPath().resolve(name));
|
||||
if (tryToUseAsRepository(f)) {
|
||||
break;
|
||||
}
|
||||
name = basename + "_" + i;
|
||||
}
|
||||
|
||||
if (i == MAX_REPO_CREATION_RETRIES) {
|
||||
throw new Exception("Unable to create JFR repository directory using base location (" + basePath + ")");
|
||||
}
|
||||
SafePath canonicalRepositoryPath = SecuritySupport.toRealPath(f);
|
||||
return canonicalRepositoryPath;
|
||||
}
|
||||
|
||||
private static SafePath createRealBasePath(SafePath safePath) throws Exception {
|
||||
if (SecuritySupport.exists(safePath)) {
|
||||
if (!SecuritySupport.isWritable(safePath)) {
|
||||
throw new IOException("JFR repository directory (" + safePath.toString() + ") exists, but isn't writable");
|
||||
}
|
||||
return SecuritySupport.toRealPath(safePath);
|
||||
}
|
||||
SafePath p = SecuritySupport.createDirectories(safePath);
|
||||
return SecuritySupport.toRealPath(p);
|
||||
}
|
||||
|
||||
private static boolean tryToUseAsRepository(final SafePath path) {
|
||||
Path parent = path.toPath().getParent();
|
||||
if (parent == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
try {
|
||||
SecuritySupport.createDirectories(path);
|
||||
} catch (Exception e) {
|
||||
// file already existed or some other problem occurred
|
||||
}
|
||||
if (!SecuritySupport.exists(path)) {
|
||||
return false;
|
||||
}
|
||||
if (!SecuritySupport.isDirectory(path)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (IOException io) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void clear() {
|
||||
for (SafePath p : cleanupDirectories) {
|
||||
try {
|
||||
SecuritySupport.clearDirectory(p);
|
||||
Logger.log(LogTag.JFR, LogLevel.INFO, "Removed repository " + p);
|
||||
} catch (IOException e) {
|
||||
Logger.log(LogTag.JFR, LogLevel.ERROR, "Repository " + p + " could not be removed at shutdown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized SafePath getRepositoryPath() {
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user