/* * Copyright (C) 2014 Robert Stupp, Koeln, Germany, robert-stupp.de * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.caffinitas.ohc.benchmark; import java.io.PrintStream; import java.lang.management.ManagementFactory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.Notification; import javax.management.NotificationListener; import javax.management.ObjectInstance; import javax.management.ObjectName; import javax.management.openmbean.CompositeDataSupport; import com.codahale.metrics.Snapshot; import org.caffinitas.ohc.OHCache; final class Shared { private static final double NANOS_PER_MILLI = 1000000d; static OHCache<Long, byte[]> cache; static final AtomicBoolean fatal = new AtomicBoolean(); static MergeableTimer[] timers = new MergeableTimer[]{ new MergeableTimer(), new MergeableTimer() }; static final ConcurrentHashMap<String, GCStats> gcStats = new ConcurrentHashMap<>(); static { MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); NotificationListener gcListener = new NotificationListener() { public void handleNotification(Notification notification, Object handback) { CompositeDataSupport userData = (CompositeDataSupport) notification.getUserData(); String gcName = (String) userData.get("gcName"); CompositeDataSupport gcInfo = (CompositeDataSupport) userData.get("gcInfo"); Long duration = (Long) gcInfo.get("duration"); GCStats stats = gcStats.get(gcName); if (stats == null) { GCStats ex = gcStats.putIfAbsent(gcName, stats = new GCStats()); if (ex != null) stats = ex; } stats.count.incrementAndGet(); stats.duration.addAndGet(duration); Number gcThreadCount = (Number) gcInfo.get("GcThreadCount"); if (gcThreadCount != null && gcThreadCount.intValue() > stats.cores) stats.cores = gcThreadCount.intValue(); } }; try { for (ObjectInstance inst : mbeanServer.queryMBeans(ObjectName.getInstance("java.lang:type=GarbageCollector,name=*"), null)) mbeanServer.addNotificationListener(inst.getObjectName(), gcListener, null, null); } catch (MalformedObjectNameException | InstanceNotFoundException e) { throw new RuntimeException(e); } } static void clearStats() { timers[0] = new MergeableTimer(); timers[1] = new MergeableTimer(); gcStats.clear(); cache.resetStatistics(); } static final class GCStats { final AtomicLong count = new AtomicLong(); final AtomicLong duration = new AtomicLong(); int cores; } static void printStats(String title, boolean bucketHistogram, PrintStream csv) { if (bucketHistogram) System.out.printf("%s%n %s%n" + " Histogram:%n%s%n", title, cache.stats(), cache.getBucketHistogram()); else System.out.printf("%s%n %s%n", title, cache.stats()); for (Map.Entry<String, GCStats> gcStat : gcStats.entrySet()) { GCStats gs = gcStat.getValue(); long count = gs.count.longValue(); long duration = gs.duration.longValue(); double runtimeAvg = ((double) duration) / count; System.out.printf(" GC %-15s : count: %8d duration: %8dms (avg:%6.2fms) cores: %d%n", gcStat.getKey(), count, duration, runtimeAvg, gs.cores); } if (csv != null) csv.print(timers[0].runtime()); dumpStats(timers[0], "Reads", csv); dumpStats(timers[1], "Writes", csv); if (csv != null) csv.println(); } private static void dumpStats(MergeableTimer timer, String header, PrintStream csv) { Snapshot snap = timer.histogram.getSnapshot(); double snapMean = snap.getMean() / NANOS_PER_MILLI; double snapStdDev = snap.getStdDev() / NANOS_PER_MILLI; double snap75 = snap.get75thPercentile() / NANOS_PER_MILLI; double snap95 = snap.get95thPercentile() / NANOS_PER_MILLI; double snap98 = snap.get98thPercentile() / NANOS_PER_MILLI; double snap99 = snap.get99thPercentile() / NANOS_PER_MILLI; double snap999 = snap.get999thPercentile() / NANOS_PER_MILLI; double snapMedian = snap.getMedian() / NANOS_PER_MILLI; double snapMax = (double) snap.getMax() / NANOS_PER_MILLI; double snapMin = (double) snap.getMin() / NANOS_PER_MILLI; double meanRate = timer.meter.getMeanRate(); long count = timer.meter.getCount(); double oneMinuteRate = timer.meter.getOneMinuteRate(); double fiveMinuteRate = timer.meter.getFiveMinuteRate(); double fifteenMinuteRate = timer.meter.getFifteenMinuteRate(); System.out.printf(" %-10s: one/five/fifteen/mean: %.0f/%.0f/%.0f/%.0f%n" + " count: %10d %n" + " min/max/mean/stddev: %8.5f/%8.5f/%8.5f/%8.5f%n" + " 75/95/98/99/999/median: %8.5f/%8.5f/%8.5f/%8.5f/%8.5f/%8.5f%n", header, // oneMinuteRate, fiveMinuteRate, fifteenMinuteRate, meanRate, // count, // snapMin, snapMax, snapMean, snapStdDev, snap75, snap95, snap98, snap99, snap999, snapMedian); if (csv != null) csv.printf(";%d;%.0f;%.0f;%.0f;%.0f;%.5f;%.5f;%.5f;%.5f;%.5f;%.5f;%.5f;%.5f;%.5f;%.5f", count, oneMinuteRate, fiveMinuteRate, fifteenMinuteRate, meanRate, snapMin, snapMax, snapMean, snapStdDev, snap75, snap95, snap98, snap99, snap999, snapMedian); } }