--- /dev/null 2016-10-25 08:46:44.038854975 +0200 +++ new/src/share/classes/sun/evtracing/processing/statistics/MonitorContender.java 2016-10-25 10:40:48.749803722 +0200 @@ -0,0 +1,108 @@ +/* + * 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 sun.evtracing.parser.MonitorContendedEnterEvent; +import sun.evtracing.parser.MonitorContendedEnteredEvent; +import sun.evtracing.parser.MonitorContendedExitedEvent; +import sun.evtracing.parser.MonitorEnterWait; +import sun.evtracing.parser.MonitorEnteredFlags; +import sun.evtracing.parser.MonitorEvent; +import sun.evtracing.parser.TraceEventType; +import sun.evtracing.parser.metadata.JavaStack; +import sun.evtracing.parser.metadata.JavaThread; +import sun.evtracing.processing.Sanity; +import sun.evtracing.processing.statistics.aggregator.ContentionProcessor; +import sun.evtracing.processing.statistics.metadata.Contention; +import sun.evtracing.processing.statistics.metadata.Group; +import sun.evtracing.processing.statistics.metadata.JavaObjectStack; + +public class MonitorContender { + + private final JavaObjectStack objectStack; + private final ContentionProcessor processor; + private final MonitorContendedEnterEvent enter; + + private MonitorEvent lastEvent; + + public static MonitorContender forEnter(JavaObjectStack objectStack, MonitorContendedEnterEvent event, ContentionProcessor processor) { + return new MonitorContender(objectStack, event, processor); + } + + private MonitorContender(JavaObjectStack objectStack, MonitorContendedEnterEvent event, ContentionProcessor processor) { + this.objectStack = objectStack; + this.enter = event; + this.processor = processor; + this.lastEvent = event; + } + + private Group group() { + if (enter.afterWait() != MonitorEnterWait.NoWait) { + return Group.MonitorWaitReentry; + } + return Group.Monitors; + } + + private boolean wasEntered() { + return (lastEvent.type() == TraceEventType.MonitorContendedEntered); + } + + void contenderExitedMonitor(MonitorContendedExitedEvent exit) { + assert !wasEntered(); + long startTime = lastEvent.timestamp(); + long duration = exit.timestamp() - startTime; + processor.submit(new Contention(group(), enter.thread().metadata(), exit.thread().metadata(), enter.stack().metadata(), exit.stack().metadata(), objectStack, startTime, duration)); + lastEvent = exit; + } + + void monitorContendedEntered(MonitorContendedEnteredEvent entered) { + assert !wasEntered(); + if (entered.flags().contains(MonitorEnteredFlags.Queued)) { + if (entered.flags().contains(MonitorEnteredFlags.Parked)) { + Sanity.warnIf(lastEvent == enter, "entered monitor after parking without prior contender exit (rare race)"); + } else { + Sanity.warnIf(lastEvent == enter, "entered monitor after queueing without prior contender exit (race)"); + } + } else { + // the thread managed to obtain the lock only by spinning, not entering + // itself on any queue. therefore, the contender could not have noticed it + // and has not written an exit event unless another thread was waiting. + } + // attribute period between last exit and entered to unknown + long startTime = lastEvent.timestamp(); + long duration = entered.timestamp() - startTime; + processor.submit(new Contention(group(), enter.thread().metadata(), JavaThread.UNKNOWN, enter.stack().metadata(), JavaStack.UNKNOWN, objectStack, startTime, duration)); + lastEvent = entered; + } + + void monitorContendedExited(long time) { + // nothing to do so far + } + + @Override + public String toString() { + return enter.thread().metadata().toString() + " blocking on " + objectStack.toString(); + } + +}