/*
* Copyright 2013 MovingBlocks
*
* 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.terasology.monitoring;
import gnu.trove.map.TObjectDoubleMap;
import org.terasology.monitoring.impl.NullPerformanceMonitor;
import org.terasology.monitoring.impl.PerformanceMonitorImpl;
import org.terasology.monitoring.impl.PerformanceMonitorInternal;
/**
* Maintains a running average of execution times and memory allocated by different activities.
* Activities call to denote when they start and stop.
* <br><br>
* Activities may be nested, and while a nested activity is running the collection of data from outer activities
* is paused: time passing and allocated memory are not assigned to them.
* <br><br>
* Performance monitor is intended only for use by the main thread of Terasology, and does not handle
* activities being started and ended on other threads at this time.
*/
public final class PerformanceMonitor {
private static PerformanceMonitorInternal instance;
static {
instance = new NullPerformanceMonitor();
}
private PerformanceMonitor() {
}
/**
* Indicates the start of an activity. All started activities must either be ended with a call to endActivity()
* (see example 1) or take advantage of the autocloseable interface implemented by Activity (see example 2).<br>
* <br>
*
* Example 1 - explicitly ending an activity:
* <pre>
* PerformanceMonitor.startActivity("myActivity")
* doSomething();
* PerformanceMonitor.endActivity()
* </pre>
*
* Example 2 - the end of the activity is handled internally:
* <pre>
* try (Activity ignored = PerformanceMonitor.startActivity("myActivity") {
* doSomething();
* }
* </pre>
*
* The latter case is particularly useful whenever the activity's code has a number of possible exit paths,
* as it might be undesirable or simply non-trivial to add an endActivity() call at the end of each.<br>
* <br>
*
* Activities may be nested. Example: (the indentation pattern is not strictly necessary)
* <pre>
* PerformanceMonitor.startActivity("myActivity")
* doSomething();
*
* PerformanceMonitor.startActivity("myNestedActivity")
* doSomethingNested();
* PerformanceMonitor.endActivity()
*
* doSomethingElse()
* PerformanceMonitor.endActivity()
* </pre>
*
* @param activityName the name of the activity starting.
*/
public static Activity startActivity(String activityName) {
return instance.startActivity(activityName);
}
/**
* Indicates the end of the last started activity.
*/
public static void endActivity() {
instance.endActivity();
}
/**
* Drops old information and updates the metrics. Should be called once per frame.
*/
public static void rollCycle() {
instance.rollCycle();
}
/**
* Returns a mapping from the name of an activity to a running mean of its execution times, over a number of cycles.
* <br><br>
* Activities may be nested, and while a nested activity is running the collection of data from outer activities
* is paused and time passing is not assigned to them.
*
* @return a mapping from activity name to running mean of execution times.
*/
public static TObjectDoubleMap<String> getRunningMean() {
return instance.getRunningMean();
}
/**
* Returns a mapping from the name of an activity to the activity's largest execution time, decayed by time.
* <br><br>
* Without decay this method would return the absolute largest execution time for each activity, since
* it was first started. Instead, this method returns the largest -most recent- execution time for
* each activity.
*
* @return a mapping from activity name to largest most recent execution time per cycle.
*/
// TODO: change to return the largest execution time over the monitored interval - no decay involved. See comment in
// TODO: https://github.com/emanuele3d/Terasology/commit/36cf9bf23b42f76793a5d5968ef4e25986aa9706#commitcomment-11445526
public static TObjectDoubleMap<String> getDecayingSpikes() {
return instance.getDecayingSpikes();
}
/**
* Returns a mapping from the name of an activity to a running mean of allocated memory during
* the execution of the activity, over a number of cycles.
* <br><br>
* Activities may be nested, and while a nested activity is running the collection of data from
* outer activities is paused and allocated memory is not assigned to them.
* <br><br>
* No guarantee can be given that the memory allocated during the execution of an activity is
* entirely due to the activity. Other threads for example might increase or decrease the
* figure.
*
* @return a mapping from activity name to running mean of allocated memory.
*/
public static TObjectDoubleMap<String> getAllocationMean() {
return instance.getAllocationMean();
}
/**
* Enables or disables the Performance Monitoring system.
* <br><br>
* When disabled all data is purged and calls to startActivity()/endActivity() and rollCycle() are ignored.
*
* @param enabled True turns the Performance Monitoring system ON. False turns it OFF.
*/
public static void setEnabled(boolean enabled) {
if (enabled && !(instance instanceof PerformanceMonitorImpl)) {
instance = new PerformanceMonitorImpl();
} else if (!enabled && !(instance instanceof NullPerformanceMonitor)) {
instance = new NullPerformanceMonitor();
}
}
}