Copyright (c) 2000, 2013 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Lars Vogel - Adds generic type arguments https://bugs.eclipse.org/412836
/******************************************************************************* * Copyright (c) 2000, 2013 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Lars Vogel <Lars.Vogel@gmail.com> - Adds generic type arguments https://bugs.eclipse.org/412836 *******************************************************************************/
package org.eclipse.core.runtime; import java.io.PrintWriter; import java.util.*; import org.eclipse.core.internal.runtime.InternalPlatform; import org.eclipse.core.internal.runtime.PerformanceStatsProcessor;
PerformanceStats collects and aggregates timing data about events such as a builder running, an editor opening, etc. This data is collected for the purpose of performance analysis, and is not intended to be used as a generic event tracking and notification system.

Each performance event can have an associated maximum acceptable duration that is specified in the platform debug options file (.options). Events that take longer than this maximum are logged as errors. Along with option file entries for each debug event, there are some global debug options for enabling or disabling performance event gathering and reporting. See the "org.eclipse.core.runtime/perf*" debug options in the .options file for the org.eclipse.core.runtime plugin for more details.

A performance event can optionally have additional context information (getContext). This information is only stored in the case of a performance failure, and can be used to provide further diagnostic information that can help track down the cause of the failure.

Performance events and performance failures are batched up and periodically sent to interested performance event listeners.

This class is not intended to be subclassed or instantiated by clients.

Since:3.1
/** * PerformanceStats collects and aggregates timing data about events such as * a builder running, an editor opening, etc. This data is collected for the * purpose of performance analysis, and is not intended to be used as * a generic event tracking and notification system. * <p> * Each performance event can have an associated maximum acceptable * duration that is specified in the platform debug options file (.options). * Events that take longer than this maximum are logged as errors. Along * with option file entries for each debug event, there are some global debug * options for enabling or disabling performance event gathering and reporting. * See the "org.eclipse.core.runtime/perf*" debug options in the .options file * for the org.eclipse.core.runtime plugin for more details. * </p><p> * A performance event can optionally have additional context information * ({@link #getContext}). This information is only stored in the case * of a performance failure, and can be used to provide further diagnostic * information that can help track down the cause of the failure. * </p><p> * Performance events and performance failures are batched up and periodically * sent to interested performance event listeners. * </p><p> * This class is not intended to be subclassed or instantiated by clients. * </p> * @since 3.1 */
public class PerformanceStats {
A performance listener is periodically notified after performance events occur or after events fail.

This class is intended to be subclassed.

See Also:
  • addListener.addListener(PerformanceListener)
/** * A performance listener is periodically notified after performance events occur * or after events fail. * <p> * This class is intended to be subclassed. * </p> * * @see PerformanceStats#addListener(PerformanceStats.PerformanceListener) */
public static abstract class PerformanceListener {
Creates a new listener.
/** * Creates a new listener. */
protected PerformanceListener() { super(); }
Notifies than an event exceeded the maximum duration for that event type.

This default implementation does nothing. Subclasses may override.

Params:
  • event – The event that failed
  • duration – The duration of the failed event, in milliseconds
/** * Notifies than an event exceeded the maximum duration for that event type. * <p> * This default implementation does nothing. Subclasses may override. * </p> * * @param event The event that failed * @param duration The duration of the failed event, in milliseconds */
public void eventFailed(PerformanceStats event, long duration) { //default implementation does nothing }
Notifies that an event occurred. Notification might not occur in the same thread or near the time of the actual event.

This default implementation does nothing. Subclasses may override.

Params:
  • event – The event that occurred
/** * Notifies that an event occurred. Notification might not occur * in the same thread or near the time of the actual event. * <p> * This default implementation does nothing. Subclasses may override. * </p> * * @param event The event that occurred */
public void eventsOccurred(PerformanceStats[] event) { //default implementation does nothing } }
An empty stats object that is returned when tracing is turned off
/** * An empty stats object that is returned when tracing is turned off */
private static final PerformanceStats EMPTY_STATS = new PerformanceStats("", ""); //$NON-NLS-1$ //$NON-NLS-2$
Constant indicating whether or not tracing is enabled
/** * Constant indicating whether or not tracing is enabled */
public static final boolean ENABLED;
A constant indicating that the timer has not been started.
/** * A constant indicating that the timer has not been started. */
private static final long NOT_STARTED = -1;
All known event statistics.
/** * All known event statistics. */
private final static Map<PerformanceStats, PerformanceStats> statMap = Collections.synchronizedMap(new HashMap<PerformanceStats,PerformanceStats>());
Maximum allowed durations for each event. Maps String (event name) -> Long (threshold)
/** * Maximum allowed durations for each event. * Maps String (event name) -&gt; Long (threshold) */
private final static Map<String, Long> thresholdMap = Collections.synchronizedMap(new HashMap<String, Long>());
Whether non-failure statistics should be retained.
/** * Whether non-failure statistics should be retained. */
private static final boolean TRACE_SUCCESS;
An identifier that can be used to figure out who caused the event. This is typically a string representation of the object whose code was running when the event occurred or a String describing the event.
/** * An identifier that can be used to figure out who caused the event. This is * typically a string representation of the object whose code was running when * the event occurred or a <code>String</code> describing the event. */
private String blame;
The id of the plugin that defined the blame object for this event, or null if it could not be determined.
/** * The id of the plugin that defined the blame object for this event, or * <code>null</code> if it could not be determined. */
private String blamePluginId;
An optional context for the event (may be null). The context can provide extra information about an event, such as the name of a project being built, or the input of an editor being opened.
/** * An optional context for the event (may be <code>null</code>). * The context can provide extra information about an event, such as the * name of a project being built, or the input of an editor being opened. */
private String context;
The starting time of the current occurrence of this event.
/** * The starting time of the current occurrence of this event. */
private long currentStart = NOT_STARTED;
The symbolic name of the event that occurred. This is usually the name of the debug option for this event.
/** * The symbolic name of the event that occurred. This is usually the name of * the debug option for this event. */
private String event;
Whether this is a performance failure event
/** * Whether this is a performance failure event */
private boolean isFailure;
The total number of times this event has occurred.
/** * The total number of times this event has occurred. */
private int runCount = 0;
The total time in milliseconds taken by all occurrences of this event.
/** * The total time in milliseconds taken by all occurrences of this event. */
private long runningTime = 0; static { ENABLED = InternalPlatform.getDefault().getBooleanOption(Platform.PI_RUNTIME + "/perf", false);//$NON-NLS-1$ //turn these on by default if the global trace flag is turned on TRACE_SUCCESS = InternalPlatform.getDefault().getBooleanOption(Platform.PI_RUNTIME + "/perf/success", ENABLED); //$NON-NLS-1$ }
Adds a listener that is notified when performance events occur. If an equal listener is already installed, it will be replaced.
Params:
  • listener – The listener to be added
See Also:
/** * Adds a listener that is notified when performance events occur. If * an equal listener is already installed, it will be replaced. * * @param listener The listener to be added * @see #removeListener(PerformanceStats.PerformanceListener) */
public static void addListener(PerformanceListener listener) { if (ENABLED) PerformanceStatsProcessor.addListener(listener); }
Discards all known performance event statistics.
/** * Discards all known performance event statistics. */
public static void clear() { statMap.clear(); }
Returns all performance event statistics.
Returns:An array of known performance event statistics. The array will be empty if there are no recorded statistics.
/** * Returns all performance event statistics. * * @return An array of known performance event statistics. The array * will be empty if there are no recorded statistics. */
public static PerformanceStats[] getAllStats() { return statMap.values().toArray(new PerformanceStats[statMap.values().size()]); }
Returns the stats object corresponding to the given parameters. A stats object is created and added to the global list of events if it did not already exist.
Params:
  • eventName – A symbolic event name. This is usually the name of the debug option for this event. An example event name from the org.eclipse.core.resources plugin describing a build event might look like: "org.eclipse.core.resources/perf/building""
  • blameObject – The blame for the event. This is typically the object whose code was running when the event occurred. If a blame object cannot be obtained, a String describing the event should be supplied
/** * Returns the stats object corresponding to the given parameters. * A stats object is created and added to the global list of events if it did not * already exist. * * @param eventName A symbolic event name. This is usually the name of * the debug option for this event. An example event name from * the org.eclipse.core.resources plugin describing a build event might look like: * <code>"org.eclipse.core.resources/perf/building"</code>" * @param blameObject The blame for the event. This is typically the object * whose code was running when the event occurred. If a blame object cannot * be obtained, a <code>String</code> describing the event should be supplied */
public static PerformanceStats getStats(String eventName, Object blameObject) { if (!ENABLED || eventName == null || blameObject == null) return EMPTY_STATS; PerformanceStats newStats = new PerformanceStats(eventName, blameObject); if (!TRACE_SUCCESS) return newStats; //use existing stats object if available PerformanceStats oldStats = statMap.get(newStats); if (oldStats != null) return oldStats; statMap.put(newStats, newStats); return newStats; }
Returns whether monitoring of a given performance event is enabled.

For frequent performance events, the result of this method call should be cached by the caller to minimize overhead when performance monitoring is turned off. It is not possible for enablement to change during the life of this invocation of the platform.

Params:
  • eventName – The name of the event to determine enablement for
Returns:trueIf the performance event with the given name is enabled, and false otherwise.
/** * Returns whether monitoring of a given performance event is enabled. * <p> * For frequent performance events, the result of this method call should * be cached by the caller to minimize overhead when performance monitoring * is turned off. It is not possible for enablement to change during the life * of this invocation of the platform. * </p> * * @param eventName The name of the event to determine enablement for * @return <code>true</code>If the performance event with the given * name is enabled, and <code>false</code> otherwise. */
public static boolean isEnabled(String eventName) { if (!ENABLED) return false; String option = Platform.getDebugOption(eventName); return option != null && !option.equalsIgnoreCase("false") && !option.equalsIgnoreCase("-1"); //$NON-NLS-1$ //$NON-NLS-2$ }
Prints all statistics to the standard output.
/** * Prints all statistics to the standard output. */
public static void printStats() { if (!ENABLED) return; PrintWriter writer = new PrintWriter(System.out); PerformanceStatsProcessor.printStats(writer); writer.flush(); }
Writes all statistics using the provided writer
Params:
  • out – The writer to print stats to.
/** * Writes all statistics using the provided writer * * @param out The writer to print stats to. */
public static void printStats(PrintWriter out) { if (!ENABLED) return; PerformanceStatsProcessor.printStats(out); }
Removes an event listener. Has no effect if an equal listener object is not currently registered.
Params:
  • listener – The listener to remove
See Also:
/** * Removes an event listener. Has no effect if an equal * listener object is not currently registered. * * @param listener The listener to remove * @see #addListener(PerformanceStats.PerformanceListener) */
public static void removeListener(PerformanceListener listener) { if (ENABLED) PerformanceStatsProcessor.removeListener(listener); }
Removes statistics for a given event and blame
Params:
  • eventName – The name of the event to remove
  • blameObject – The blame for the event to remove
/** * Removes statistics for a given event and blame * * @param eventName The name of the event to remove * @param blameObject The blame for the event to remove */
public static void removeStats(String eventName, Object blameObject) { synchronized (statMap) { for (Iterator<PerformanceStats> it = statMap.keySet().iterator(); it.hasNext();) { PerformanceStats stats = it.next(); if (stats.getEvent().equals(eventName) && stats.getBlame().equals(blameObject)) it.remove(); } } }
Creates a new PerformanceStats object. Private to prevent client instantiation.
/** * Creates a new PerformanceStats object. Private to prevent client instantiation. */
private PerformanceStats(String event, Object blame) { this(event, blame, null); }
Creates a new PerformanceStats object. Private to prevent client instantiation.
/** * Creates a new PerformanceStats object. Private to prevent client instantiation. */
private PerformanceStats(String event, Object blameObject, String context) { this.event = event; this.blame = blameObject instanceof String ? (String) blameObject : blameObject.getClass().getName(); this.blamePluginId = InternalPlatform.getDefault().getBundleId(blameObject); this.context = context; }
Adds an occurrence of this event to the cumulative counters. This method can be used as an alternative to startRun and endRun for clients that want to track the context and execution time separately.
Params:
  • elapsed – The elapsed time of the new occurrence in milliseconds
  • contextName – The context for the event to return, or null. The context optionally provides extra information about an event, such as the name of a project being built, or the input of an editor being opened.
/** * Adds an occurrence of this event to the cumulative counters. This method * can be used as an alternative to <code>startRun</code> and <code>endRun</code> * for clients that want to track the context and execution time separately. * * @param elapsed The elapsed time of the new occurrence in milliseconds * @param contextName The context for the event to return, or <code>null</code>. * The context optionally provides extra information about an event, such as the * name of a project being built, or the input of an editor being opened. */
public void addRun(long elapsed, String contextName) { if (!ENABLED) return; runCount++; runningTime += elapsed; if (elapsed > getThreshold(event)) PerformanceStatsProcessor.failed(createFailureStats(contextName, elapsed), blamePluginId, elapsed); if (TRACE_SUCCESS) PerformanceStatsProcessor.changed(this); }
Creates a stats object representing a performance failure
Params:
  • contextName – The failure context information.
  • elapsed – The elapsed time in milliseconds
Returns:The failure stats
/** * Creates a stats object representing a performance failure * * @param contextName The failure context information. * @param elapsed The elapsed time in milliseconds * @return The failure stats */
private PerformanceStats createFailureStats(String contextName, long elapsed) { PerformanceStats failedStat = new PerformanceStats(event, blame, contextName); PerformanceStats old = statMap.get(failedStat); if (old == null) statMap.put(failedStat, failedStat); else failedStat = old; failedStat.isFailure = true; failedStat.runCount++; failedStat.runningTime += elapsed; return failedStat; }
Stops timing the occurrence of this event that was started by the previous call to startRun. The event is automatically added to the cumulative counters for this event and listeners are notified.

Note that this facility guards itself against runs that start but fail to stop, so it is not necessary to call this method from a finally block. Tracking performance of failure cases is generally not of interest.

See Also:
  • startRun()
/** * Stops timing the occurrence of this event that was started by the previous * call to <code>startRun</code>. The event is automatically added to * the cumulative counters for this event and listeners are notified. * <p> * Note that this facility guards itself against runs that start but fail to stop, * so it is not necessary to call this method from a finally block. Tracking * performance of failure cases is generally not of interest. * </p> * * @see #startRun() */
public void endRun() { if (!ENABLED || currentStart == NOT_STARTED) return; addRun(System.currentTimeMillis() - currentStart, context); currentStart = NOT_STARTED; } /* (non-Javadoc) * @see java.lang.Object#equals() */ @Override public boolean equals(Object obj) { //count and time are not considered part of equality if (!(obj instanceof PerformanceStats)) return false; PerformanceStats that = (PerformanceStats) obj; return this.event.equals(that.event) && this.getBlameString().equals(that.getBlameString()) && Objects.equals(this.context, that.context); }
Returns an object that can be used to figure out who caused the event, or a string describing the cause of the event.
Returns:The blame for this event
/** * Returns an object that can be used to figure out who caused the event, * or a string describing the cause of the event. * * @return The blame for this event */
public Object getBlame() { return blame; }
Returns a string describing the blame for this event.
Returns:A string describing the blame.
/** * Returns a string describing the blame for this event. * * @return A string describing the blame. */
public String getBlameString() { return blame; }
Returns the optional event context, such as the input of an editor, or the target project of a build event.
Returns:The context, or null if there is none
/** * Returns the optional event context, such as the input of an editor, or the target project * of a build event. * * @return The context, or <code>null</code> if there is none */
public String getContext() { return context; }
Returns the symbolic name of the event that occurred.
Returns:The name of the event.
/** * Returns the symbolic name of the event that occurred. * * @return The name of the event. */
public String getEvent() { return event; }
Returns the total number of times this event has occurred.
Returns:The number of occurrences of this event.
/** * Returns the total number of times this event has occurred. * * @return The number of occurrences of this event. */
public int getRunCount() { return runCount; }
Returns the total execution time in milliseconds for all occurrences of this event.
Returns:The total running time in milliseconds.
/** * Returns the total execution time in milliseconds for all occurrences * of this event. * * @return The total running time in milliseconds. */
public long getRunningTime() { return runningTime; }
Returns the performance threshold for this event.
/** * Returns the performance threshold for this event. */
private long getThreshold(String eventName) { Long value = thresholdMap.get(eventName); if (value == null) { String option = InternalPlatform.getDefault().getOption(eventName); if (option != null) { try { value = Long.valueOf(option); } catch (NumberFormatException e) { //invalid option, just ignore } } if (value == null) value = Long.valueOf(Long.MAX_VALUE); thresholdMap.put(eventName, value); } return value.longValue(); } @Override public int hashCode() { //count and time are not considered part of equality int hash = event.hashCode() * 37 + getBlameString().hashCode(); if (context != null) hash = hash * 37 + context.hashCode(); return hash; }
Returns whether this performance event represents a performance failure.
Returns:true if this is a performance failure, and false otherwise.
/** * Returns whether this performance event represents a performance failure. * * @return <code>true</code> if this is a performance failure, and * <code>false</code> otherwise. */
public boolean isFailure() { return isFailure; }
Resets count and running time for this particular stats event.
/** * Resets count and running time for this particular stats event. */
public void reset() { runningTime = 0; runCount = 0; }
Starts timing an occurrence of this event. This is a convenience method, fully equivalent to startRun(null).
/** * Starts timing an occurrence of this event. This is a convenience method, * fully equivalent to <code>startRun(null)</code>. */
public void startRun() { if (ENABLED) startRun(null); }
Starts timing an occurrence of this event. The event should be stopped by a subsequent call to endRun.
Params:
  • contextName – The context for the event to return, or null. The context optionally provides extra information about an event, such as the name of a project being built, or the input of an editor being opened.
See Also:
/** * Starts timing an occurrence of this event. The event should be stopped * by a subsequent call to <code>endRun</code>. * * @param contextName The context for the event to return, or <code>null</code>. * The context optionally provides extra information about an event, such as the * name of a project being built, or the input of an editor being opened. * @see #endRun */
public void startRun(String contextName) { if (!ENABLED) return; this.context = contextName; this.currentStart = System.currentTimeMillis(); }
For debugging purposes only.
/** * For debugging purposes only. */
@Override public String toString() { StringBuilder result = new StringBuilder("PerformanceStats("); //$NON-NLS-1$ result.append(event); result.append(','); result.append(blame); if (context != null) { result.append(','); result.append(context); } result.append(')'); return result.toString(); } }