--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java Wed Dec 05 16:40:12 2018 +0100
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.internal.tool;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+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;
+
+final class Summary extends Command {
+ private final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withLocale(Locale.UK).withZone(ZoneOffset.UTC);
+
+ @Override
+ public String getName() {
+ return "summary";
+ }
+
+ private static class Statistics {
+ Statistics(String name) {
+ this.name = name;
+ }
+ String name;
+ long count;
+ long size;
+ }
+
+ @Override
+ public List<String> getOptionSyntax() {
+ return Collections.singletonList("<file>");
+ }
+
+ @Override
+ public void displayOptionUsage(PrintStream stream) {
+ stream.println(" <file> Location of the recording file (.jfr) to display information about");
+ }
+
+ @Override
+ public String getDescription() {
+ return "Display general information about a recording file (.jfr)";
+ }
+
+ @Override
+ public void execute(Deque<String> options) throws UserSyntaxException, UserDataException {
+ ensureMaxArgumentCount(options, 1);
+ Path p = getJFRInputFile(options);
+ try {
+ printInformation(p);
+ } catch (IOException e) {
+ couldNotReadError(p, e);
+ }
+ }
+
+ private void printInformation(Path p) throws IOException {
+ long totalDuration = 0;
+ long chunks = 0;
+
+ try (RecordingInput input = new RecordingInput(p.toFile())) {
+ ChunkHeader first = new ChunkHeader(input);
+ ChunkHeader ch = first;
+ String eventPrefix = Type.EVENT_NAME_PREFIX;
+ if (first.getMajor() == 1) {
+ eventPrefix = "com.oracle.jdk.";
+ }
+ HashMap<Long, Statistics> stats = new HashMap<>();
+ stats.put(0L, new Statistics(eventPrefix + "Metadata"));
+ stats.put(1L, new Statistics(eventPrefix + "CheckPoint"));
+ int minWidth = 0;
+ while (true) {
+ long chunkEnd = ch.getEnd();
+ MetadataDescriptor md = ch.readMetadata();
+
+ for (EventType eventType : md.getEventTypes()) {
+ stats.computeIfAbsent(eventType.getId(), (e) -> new Statistics(eventType.getName()));
+ minWidth = Math.max(minWidth, eventType.getName().length());
+ }
+
+ totalDuration += ch.getDurationNanos();
+ chunks++;
+ input.position(ch.getEventStart());
+ while (input.position() < chunkEnd) {
+ long pos = input.position();
+ int size = input.readInt();
+ long eventTypeId = input.readLong();
+ Statistics s = stats.get(eventTypeId);
+ if (s != null) {
+ s.count++;
+ s.size += size;
+ }
+ input.position(pos + size);
+ }
+ if (ch.isLastChunk()) {
+ break;
+ }
+ ch = ch.nextHeader();
+ }
+ println();
+ long epochSeconds = first.getStartNanos() / 1_000_000_000L;
+ long adjustNanos = first.getStartNanos() - epochSeconds * 1_000_000_000L;
+ println(" Version: " + first.getMajor() + "." + first.getMinor());
+ println(" Chunks: " + chunks);
+ println(" Start: " + DATE_FORMAT.format(Instant.ofEpochSecond(epochSeconds, adjustNanos)) + " (UTC)");
+ println(" Duration: " + (totalDuration + 500_000_000) / 1_000_000_000 + " s");
+
+ List<Statistics> statsList = new ArrayList<>(stats.values());
+ Collections.sort(statsList, (u, v) -> Long.compare(v.count, u.count));
+ println();
+ String header = " Count Size (bytes) ";
+ String typeHeader = " Event Type";
+ minWidth = Math.max(minWidth, typeHeader.length());
+ println(typeHeader + pad(minWidth - typeHeader.length(), ' ') + header);
+ println(pad(minWidth + header.length(), '='));
+ for (Statistics s : statsList) {
+ System.out.printf(" %-" + minWidth + "s%10d %12d\n", s.name, s.count, s.size);
+ }
+ }
+ }
+
+ private String pad(int count, char c) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < count; i++) {
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+}