/*
* Copyright (c) 2014, 2015, Dynatrace and/or its affiliates. All rights reserved.
*
* This file is part of the Lock Contention Tracing Subsystem for the HotSpot
* Virtual Machine, which is developed at Christian Doppler Laboratory on
* Monitoring and Evolution of Very-Large-Scale Software Systems. Please
* contact us at if you need additional information
* or have any questions.
*
* 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.
*
* 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, see .
*
*/
package sun.evtracing.processing.statistics;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import sun.evtracing.parser.SequenceOrderedEvent;
import sun.evtracing.parser.metadata.JavaStack;
import sun.evtracing.parser.metadata.JavaThread;
import sun.evtracing.processing.statistics.metadata.ParkEventTuple;
public class ParkEventTupleJsonSerializer {
private final PrintStream ps;
private final ParkEventTuple tuple;
private final boolean seqAsTimestamp;
private long flowId;
public static void serialize(String outputFile, ParkEventTuple tuple, boolean seqAsTimestamp) {
try {
ParkEventTupleJsonSerializer serializer = new ParkEventTupleJsonSerializer(new PrintStream(outputFile), tuple, seqAsTimestamp);
serializer.serialize();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public ParkEventTupleJsonSerializer(PrintStream ps, ParkEventTuple tuple, boolean seqAsTimestamp) {
this.ps = ps;
this.tuple = tuple;
this.seqAsTimestamp = seqAsTimestamp;
flowId = 0;
}
private void serialize() {
ps.println("[");
ps.print("{\"name\":\"process_name\",\"ph\":\"M\",\"pid\":1,\"args\":{\"name\":\"java\"}}");
printTuple(tuple);
for (ParkEventTuple t : tuple.overlapping()) {
printTuple(t);
}
ps.println("\n]");
}
private void printTuple(ParkEventTuple tuple) {
printThread(tuple.begin().thread().metadata());
if (tuple.unpark() != null) {
printThread(tuple.unpark().thread().metadata());
}
String name = tuple.begin().clazz().metadata().prettyName(true);
long startTime = timeFrom(tuple.begin());
long thread = tuple.begin().thread().identifier();
String isAbsolute = String.valueOf(tuple.begin().isAbsolute());
long parkTime = tuple.begin().parkTime();
String objectHash = Integer.toHexString(tuple.begin().blockerObject());
JavaStack jstack = tuple.begin().stack().metadata();
String stack;
if (jstack.isSet()) {
stack = StreamSupport.stream(jstack.spliterator(), false)
.map(frame -> "\"" + (frame.method().isSet() ? frame.method().prettyDescriptor(true) : "(unknown)") + "\"")
.collect(Collectors.joining(","));
} else {
stack = "";
}
int nestingLevel = tuple.begin().nestingLevel();
long endTime = timeFrom(tuple.end());
long duration = endTime - startTime;
long beginSeq = tuple.begin().sequenceNumber();
long unparkSeq = tuple.end().unparkSequenceNumber();
long endSeq = tuple.end().sequenceNumber();
String parkReturnCode = tuple.end().parkReturnCode().name();
ps.printf(",\n{\"name\":\"%s\",\"cat\":\"park\",\"ph\":\"X\",\"ts\":%d,\"dur\":%d,\"pid\":1,\"tid\":%d,\"args\":{\"Arg isAbsolute\":%s,\"Arg time\":%d,\"Identity Hash Code\":\"%s\",\"Stack\":[%s],\"Nesting Level\":%d,\"Seq Begin\":%d,\"Seq Unpark\":%d,\"Seq End\":%d,\"Return Code\":\"%s\"}}",
name, startTime, duration, thread, isAbsolute, parkTime, objectHash, stack, nestingLevel, beginSeq, unparkSeq, endSeq, parkReturnCode);
if (tuple.unpark() != null) {
flowId++;
long unparkTime = timeFrom(tuple.unpark());
ps.printf(",\n{\"name\":\"unpark\",\"cat\":\"park\",\"ph\":\"%s\",\"ts\":%d,\"id\":%d,\"pid\":1,\"tid\":%d}", unparkTime < endTime ? "s" : "f", unparkTime, flowId, tuple.unpark().thread().identifier());
ps.printf(",\n{\"name\":\"unparked\",\"cat\":\"park\",\"ph\":\"%s\",\"ts\":%d,\"id\":%d,\"pid\":1,\"tid\":%d}", unparkTime < endTime ? "f" : "s", endTime, flowId, tuple.unpark().unparkedThread().identifier());
}
}
private void printThread(JavaThread thread) {
ps.printf(",\n{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":1,\"tid\":%d,\"args\":{\"name\":\"%s\"}}", thread.threadId(), thread.name());
}
private long timeFrom(SequenceOrderedEvent e) {
if (seqAsTimestamp) {
return e.sequenceNumber();
} else {
return e.timestamp() / 1000;
}
}
}