feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
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;
|
||||
Reference in New Issue
Block a user