/* * © Copyright IBM Corp. 2012-2013 * * 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.ibm.commons.util.profiler; import com.ibm.commons.util.TDiag; import com.ibm.commons.util.ThreadMap; /** * This class is used to enable/disable the profiler. * <code> * if( Profiler.enabled ) { * startProfiling(type,param); * try { * // Do stuff... * } finally { * endProfiling(); * } * } else { * // Do stuff... * } * @ibm-api */ public class Profiler { private static ProfilerAggregator mainAggregator = new ProfilerAggregator(null,new ProfilerType("Root"), null, 0); // $NON-NLS-1$ private static ThreadMap threadMap = null; private static boolean enabled = false; private static HighResolutionTimer _timer = null; // ============================================================================ // Profiler public API // ============================================================================ /** * Globally enable the profiler. * @ibm-api */ public static void enableProfiler( HighResolutionTimer timer ) { synchronized(Profiler.class) { // If the profiler is already enabled, do nothing if(enabled) { return; } _timer = timer; switch( _timer.getTimerMode() ) { case HighResolutionTimer.CPU_TIME_COUNTER: TDiag.console( "Profiler is measuring CPU time" ); // $NON-NLS-1$ break; case HighResolutionTimer.WALL_TIME_COUNTER: TDiag.console( "Profiler is measuring wall time" ); // $NON-NLS-1$ break; } // If the profiler is not yet enabled enabled = true; threadMap = new ThreadMap(); } } /** * Globally disable the profiler. * @ibm-api */ public static void disableProfiler() { synchronized(Profiler.class) { if(enabled) { TDiag.console( "Profiler is disabled" ); // $NON-NLS-1$ enabled = false; threadMap = null; _timer = null; } } } /** * Profiler start. * This method initialize and starts the profiler for the current thread. * @ibm-api */ public static boolean startProfiler() { if(enabled) { // Only start the profiler if not already started for the current thread. Thread t = Thread.currentThread(); if(threadMap.get(t)==null) { // Thread Map is already synchronized threadMap.put(t,mainAggregator); return true; } } return false; } /** * Profiler end. * This method ends the profiler for the current thread. * @ibm-api */ public static void endProfiler(boolean started) { if(started) { // This call avoids a synchronization and a call to get the current thread if(threadMap.hasItems()) { // Thread Map is already synchronized threadMap.remove(Thread.currentThread()); } } } public static void endProfiler() { endProfiler(true); } /** * Check if the profiler is started */ public static boolean isStarted() { return enabled && threadMap.get(Thread.currentThread())!=null; } /** * Check if the profiler is enabled for the current thread * @ibm-api */ public static boolean isEnabled() { return enabled; } /** * Get the current timer. * @ibm-api */ public static HighResolutionTimer getCurrentTimer() { return _timer; } /** * Method that should be called when a block should be profiled. * @ibm-api */ public static ProfilerAggregator startProfileBlock(ProfilerType type, String param) { return startProfileBlock(type, param, 0 ); } /** * Method that should be called when a block should be profiled. * @ibm-api */ public static ProfilerAggregator startProfileBlock(ProfilerType type, String param, int detailLevel) { ProfilerAggregator parent = (ProfilerAggregator)threadMap.get(Thread.currentThread()); if( parent!=null ) { // We should look if it already contains an aggregator for that child ProfilerAggregator child = parent.get( type, param ); if( child==null ) { synchronized(parent) { child = parent.get( type, param ); if( child==null ) { child = new ProfilerAggregator( parent, type, param, detailLevel ); parent.add( child ); } } } // That aggregator is the new current one threadMap.put(Thread.currentThread(),child); return child; } return null; } /** * Method that should be called when a block should be profiled. * @ibm-api */ public static ProfilerAggregator startProfileBlock(String type, String param) { ProfilerType t = ProfilerType.get(type); return startProfileBlock(t, param, 0); } /** * Method that should be called at the end of a profiled block. * @ibm-api */ public static void endProfileBlock(ProfilerAggregator aggregator, long startTime) { // PHIL: the profiler may have been disabled between the start and the end if(aggregator!=null && enabled) { aggregator.addInfo(getCurrentTime()-startTime); // Maybe the thread map disapeared... if( enabled ) { // The parent aggregator is the new current one threadMap.put(Thread.currentThread(),aggregator.getParent()); } } } /** * Method that should be called to reset the profiler. * @ibm-api */ public static void resetProfiler() { mainAggregator.reinit(); } /** * Method that returns the main aggregator (root). * @ibm-api */ public static ProfilerAggregator getMainAggregator() { return mainAggregator; } /** * Method that dumps the main aggregator (root). * @ibm-api */ public static void dump() { mainAggregator.dump(); } /** * Method used to execute and profile a Runnable. * @ibm-api */ public static void profileRunnable(ProfilerType type, String id, Runnable runnable) { if (isEnabled()) { ProfilerAggregator agg = Profiler.startProfileBlock(type, id); long ts = Profiler.getCurrentTime(); try { runnable.run(); } finally { Profiler.endProfileBlock(agg, ts); } } else { runnable.run(); } } // ======================================================================== // TIMER ACCESS // ======================================================================== /** * Get the current time in micros. * @ibm-api */ public static long getCurrentTime() { return _timer.getTime(); } }