1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * The contents of this file are subject to the terms of either the Universal Permissive License 7 * v 1.0 as shown at http://oss.oracle.com/licenses/upl 8 * 9 * or the following license: 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are permitted 12 * provided that the following conditions are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions 15 * and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of 18 * conditions and the following disclaimer in the documentation and/or other materials provided with 19 * the distribution. 20 * 21 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to 22 * endorse or promote products derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 26 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY 31 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 package org.openjdk.jmc.flightrecorder.ext.jfx; 34 35 import java.text.MessageFormat; 36 import java.util.Arrays; 37 import java.util.Collection; 38 import java.util.List; 39 import java.util.concurrent.Callable; 40 import java.util.concurrent.FutureTask; 41 import java.util.concurrent.RunnableFuture; 42 43 import org.openjdk.jmc.common.IDisplayable; 44 import org.openjdk.jmc.common.item.Aggregators; 45 import org.openjdk.jmc.common.item.IItemCollection; 46 import org.openjdk.jmc.common.item.IItemFilter; 47 import org.openjdk.jmc.common.item.ItemFilters; 48 import org.openjdk.jmc.common.unit.IQuantity; 49 import org.openjdk.jmc.common.unit.ITypedQuantity; 50 import org.openjdk.jmc.common.unit.LinearUnit; 51 import org.openjdk.jmc.common.unit.UnitLookup; 52 import org.openjdk.jmc.common.util.IPreferenceValueProvider; 53 import org.openjdk.jmc.common.util.TypedPreference; 54 import org.openjdk.jmc.flightrecorder.JfrAttributes; 55 import org.openjdk.jmc.flightrecorder.rules.IRule; 56 import org.openjdk.jmc.flightrecorder.rules.Result; 57 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit; 58 import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit.EventAvailability; 59 60 public class JfxPulseDurationRule implements IRule { 61 private static final String RESULT_ID = "pulseDuration"; //$NON-NLS-1$ 62 63 /* 64 * TODO: Add detection for if the recording was from an embedded JVM for 33.34ms (30 Hz) target. 65 * This preference is a workaround because it was deemed too time consuming to add automatic 66 * detection. 67 */ 68 // FIXME: This should really be in Hz, but could not find it in the UnitLookup. Using count for now. 69 public static final TypedPreference<IQuantity> CONFIG_TARGET_FRAME_RATE = new TypedPreference<>( 70 "jfr.pulse.target.framerate", //$NON-NLS-1$ 71 Messages.JfxPulseDurationRule_CAPTION_PREFERENCE_TARGET_FRAME_RATE, 72 Messages.JfxPulseDurationRule_DESCRIPTION_PREFERENCE_TARGET_FRAME_RATE, UnitLookup.NUMBER, 73 UnitLookup.NUMBER_UNITY.quantity(60)); 74 75 private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays 76 .<TypedPreference<?>> asList(CONFIG_TARGET_FRAME_RATE); 77 78 private Result getResult(IItemCollection items, IPreferenceValueProvider valueProvider) { 79 EventAvailability eventAvailability = RulesToolkit.getEventAvailability(items, JfxConstants.JFX_PULSE_ID); 80 if (eventAvailability == EventAvailability.DISABLED || eventAvailability == EventAvailability.UNKNOWN 81 || eventAvailability == EventAvailability.NONE) { 82 return RulesToolkit.getEventAvailabilityResult(this, items, eventAvailability, JfxConstants.JFX_PULSE_ID); 83 } 84 IQuantity targetFramerate = valueProvider.getPreferenceValue(CONFIG_TARGET_FRAME_RATE); 85 ITypedQuantity<LinearUnit> targetPhaseTime = UnitLookup.MILLISECOND 86 .quantity(1000.0 / targetFramerate.longValue()); 87 IItemFilter longDurationFilter = ItemFilters.more(JfrAttributes.DURATION, targetPhaseTime); 88 IItemFilter longPhasesFilter = ItemFilters.and(longDurationFilter, ItemFilters.type(JfxConstants.JFX_PULSE_ID)); 89 IQuantity longPhases = items.getAggregate(Aggregators.count(longPhasesFilter)); 90 IQuantity allPhases = items.getAggregate(Aggregators.count(ItemFilters.type(JfxConstants.JFX_PULSE_ID))); 91 if (longPhases != null && longPhases.doubleValue() > 0) { 92 double ratioOfLongPhases = longPhases.ratioTo(allPhases); 93 double mappedScore = RulesToolkit.mapExp100(ratioOfLongPhases, 0.05, 0.5); 94 mappedScore = mappedScore < 1 ? 1 : mappedScore; 95 return new Result(this, mappedScore, 96 MessageFormat.format(Messages.JfxPulseDurationRule_WARNING, 97 UnitLookup.PERCENT_UNITY.quantity(ratioOfLongPhases).displayUsing(IDisplayable.AUTO), 98 targetPhaseTime.displayUsing(IDisplayable.AUTO)), 99 MessageFormat.format(Messages.JfxPulseDurationRule_WARNING_LONG, targetFramerate)); 100 } 101 return new Result(this, 0, Messages.JfxPulseDurationRule_OK); 102 } 103 104 @Override 105 public RunnableFuture<Result> evaluate(final IItemCollection items, final IPreferenceValueProvider valueProvider) { 106 FutureTask<Result> evaluationTask = new FutureTask<>(new Callable<Result>() { 107 @Override 108 public Result call() throws Exception { 109 return getResult(items, valueProvider); 110 } 111 }); 112 return evaluationTask; 113 } 114 115 @Override 116 public Collection<TypedPreference<?>> getConfigurationAttributes() { 117 return CONFIG_ATTRIBUTES; 118 } 119 120 @Override 121 public String getId() { 122 return RESULT_ID; 123 } 124 125 @Override 126 public String getName() { 127 return Messages.JfxPulseDurationRule_NAME; 128 } 129 130 @Override 131 public String getTopic() { 132 return JfxConstants.JFX_RULE_PATH; 133 } 134 }