diff --git a/src/converter/Main.java b/src/converter/Main.java index 522381c1f..1deac6f28 100644 --- a/src/converter/Main.java +++ b/src/converter/Main.java @@ -113,6 +113,7 @@ private static void usage() { "Flame Graph options:\n" + " --title STRING Flame Graph title\n" + " --minwidth X Skip frames smaller than X%\n" + + " --grain X Coarsen Flame Graph to the given grain size\n" + " --skip N Skip N bottom frames\n" + " -r --reverse Reverse stack traces (icicle graph)\n" + " -I --include REGEX Include only stacks with the specified frames\n" + diff --git a/src/converter/one/convert/Arguments.java b/src/converter/one/convert/Arguments.java index 22a8ffe20..aa78e26a2 100644 --- a/src/converter/one/convert/Arguments.java +++ b/src/converter/one/convert/Arguments.java @@ -18,6 +18,7 @@ public class Arguments { public Pattern include; public Pattern exclude; public double minwidth; + public double grain; public int skip; public boolean help; public boolean reverse; diff --git a/src/converter/one/convert/JfrConverter.java b/src/converter/one/convert/JfrConverter.java index 5c2ae7836..511bcfc21 100644 --- a/src/converter/one/convert/JfrConverter.java +++ b/src/converter/one/convert/JfrConverter.java @@ -70,6 +70,10 @@ protected EventAggregator collectEvents() throws IOException { } } + if (args.grain > 0) { + agg.coarsen(args.grain); + } + return agg; } diff --git a/src/converter/one/jfr/event/EventAggregator.java b/src/converter/one/jfr/event/EventAggregator.java index 12479b824..b5160c380 100644 --- a/src/converter/one/jfr/event/EventAggregator.java +++ b/src/converter/one/jfr/event/EventAggregator.java @@ -15,6 +15,7 @@ public class EventAggregator { private long[] samples; private long[] values; private int size; + private double fraction; public EventAggregator(boolean threads, boolean total, double factor) { this.threads = threads; @@ -67,6 +68,30 @@ public void forEach(ValueVisitor visitor) { } } + public void coarsen(double grain) { + for (int i = 0; i < keys.length; i++) { + if (keys[i] != null) { + long s0 = samples[i]; + long s1 = round(s0 / grain); + if (s1 == 0) { + keys[i] = null; + size--; + } + samples[i] = s1; + values[i] = (long) (values[i] * ((double) s1 / s0)); + } + } + } + + private long round(double d) { + long r = (long) d; + if ((fraction += d - r) >= 1.0) { + fraction -= 1.0; + r++; + } + return r; + } + private int hashCode(Event e) { return e.hashCode() + (threads ? e.tid * 31 : 0); }