/******************************************************************************* * Copyright 2011 See AUTHORS file. * * 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 com.badlogic.gdx.utils; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.math.FloatCounter; import com.badlogic.gdx.math.WindowedMean; /** * Class to keep track of the time and load (percentage of total time) a specific task takes. Call {@link #start()} just * before starting the task and {@link #stop()} right after. You can do this multiple times if required. Every render or * update call {@link #tick()} to update the values. The {@link #time} {@link FloatCounter} provides access to the * minimum, maximum, average, total and current time the task takes. Likewise for the {@link #load} value, which is the * percentage of the total time. * * @author xoppa */ public class PerformanceCounter { private final static float nano2seconds = 1f / 1000000000.0f; private long startTime = 0L; private long lastTick = 0L; /** The time value of this counter */ public final FloatCounter time; /** The load value of this counter */ public final FloatCounter load; /** The name of this counter */ public final String name; /** * The current value, you can manually increase this using your own timing mechanism if needed, if you do so, you * also need to update {@link #valid}. */ public float current = 0f; /** * Flag to indicate that the current value is valid, you need to set this to true if using your own timing mechanism */ public boolean valid = false; public PerformanceCounter(final String name) { this(name, 5); } public PerformanceCounter(final String name, final int windowSize) { this.name = name; this.time = new FloatCounter(windowSize); this.load = new FloatCounter(1); } /** * Updates the time and load counters and resets the time. Call {@link #start()} to begin a new count. The values * are only valid after at least two calls to this method. */ public void tick() { final long t = System.nanoTime(); if (lastTick > 0L) tick((t - lastTick) * nano2seconds); lastTick = t; } /** * Updates the time and load counters and resets the time. Call {@link #start()} to begin a new count. * * @param delta * The time since the last call to this method */ public void tick(final float delta) { if (!valid) { Gdx.app.error("PerformanceCounter", "Invalid data, check if you called PerformanceCounter#stop()"); return; } time.put(current); final float currentLoad = delta == 0f ? 0f : current / delta; load.put((delta > 1f) ? currentLoad : delta * currentLoad + (1f - delta) * load.latest); current = 0f; valid = false; } /** * Start counting, call this method just before performing the task you want to keep track of. Call {@link #stop()} * when done. */ public void start() { startTime = System.nanoTime(); valid = false; } /** * Stop counting, call this method right after you performed the task you want to keep track of. Call * {@link #start()} again when you perform more of that task. */ public void stop() { if (startTime > 0L) { current += (System.nanoTime() - startTime) * nano2seconds; startTime = 0L; valid = true; } } /** * Resets this performance counter to its defaults values. */ public void reset() { time.reset(); load.reset(); startTime = 0L; lastTick = 0L; current = 0f; valid = false; } /** {@inheritDoc} */ @Override public String toString() { final StringBuilder sb = new StringBuilder(); return toString(sb).toString(); } /** Creates a string in the form of "name [time: value, load: value]" */ public StringBuilder toString(final StringBuilder sb) { sb.append(name).append(": [time: ").append(time.value).append(", load: ").append(load.value).append("]"); return sb; } }