/* * 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; } } }