All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.kernel.health.Microtiming Maven / Gradle / Ivy

Go to download

Provides common core classes and the microkernel powering all Sirius applications

There is a newer version: 12.9.1
Show newest version
/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.health;

import com.google.common.collect.Maps;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Performance measurement framework which can be used in development as well as in production systems.
 * 

* Can be used to identify bottlenecks or to analyze system performance to measure the average execution time of * different tasks. *

* Once the microtiming framework is enabled it will be notified by other frameworks as defined tasks are executed. * The execution times are combined and can be queried using {@link sirius.kernel.health.Microtiming#getTimings()}. *

* An example might be an SQL query which is executed in a loop to perform a file import. Since the SQL-Query is * always the same (in case or a prepared statement) the execution times will be added to an average which will * be stored until the next call to Microtiming.getTimings(). */ public class Microtiming { private static volatile boolean enabled = false; private static volatile long lastReset; private static Map timings = Maps.newConcurrentMap(); private Microtiming() { } /** * Simple value class which represents a measured timing. */ public static class Timing { protected String category; protected String key; protected Average avg; protected volatile boolean changedSinceLastCheck = false; protected Timing(String category, String key) { this.category = category; this.key = key; this.avg = new Average(); } /** * Returns the category of the timing * * @return the category of the timing */ public String getCategory() { return category; } /** * Returns the key of the timing * * @return the key of the timing */ public String getKey() { return key; } /** * Returns the average duration and number of occurrences of the key. * * @return the {@link sirius.kernel.health.Average} associated with the key */ public Average getAvg() { return avg; } /* * Reads and returns the changed flag, while also setting it back to false. */ protected boolean readAndUnmark() { if (changedSinceLastCheck) { changedSinceLastCheck = false; return true; } return false; } /* * Adds the given duration in nanoseconds. *

* Also toggles the changed flag to true */ protected void addNanos(long durationInNanos) { avg.addValue(durationInNanos / 1000); changedSinceLastCheck = true; } } /** * Returns a list of recorded timings. *

* This will only report timings, which changed since the last call of getTimings. Using this approach * provides a kind of auto filtering which permits to enable this framework in production systems while * still getting reasonable small results. * * @return all {@link Timing} values recorded which where submitted since the * last call to getTimings() */ public static List getTimings() { return timings.values().stream().filter(Timing::readAndUnmark).collect(Collectors.toList()); } /** * Submits a new timing for the given key. *

* Adds the average to the "live set" which will be output on the next call to {@link #getTimings()} *

* A convenient way to call this method is to use {@link sirius.kernel.commons.Watch#submitMicroTiming(String, String)} * * @param category the category of the recorded timing. This permits grouping a microtimings of the same * kind. * @param key the key for which the value should be submitted * @param durationInNanos the number of nanoseconds used as timing for the given key */ public static void submit(String category, String key, long durationInNanos) { if (!enabled) { return; } // Safety check in case someone leaves the framework enabled for a very long period of time... if (timings.size() > 1000) { timings.clear(); } timings.computeIfAbsent(category + key, k -> new Timing(category, key)).addNanos(durationInNanos); } /** * Checks whether the timing is enabled. * * @return true if the micro timing framework is enabled or false otherwise */ public static boolean isEnabled() { return enabled; } /** * Enables/Disables the timing. * * @param enabled determines whether the framework should be enabled or disabled */ public static void setEnabled(boolean enabled) { if (enabled != Microtiming.enabled) { timings.clear(); lastReset = System.currentTimeMillis(); } Microtiming.enabled = enabled; } /** * Returns the timestamp of the last reset * * @return returns the timestamp in milliseconds (as provided by System.currentTimeMillis()) since the * last reset. */ public static long getLastReset() { return lastReset; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy