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