| /******************************************************************************* |
| * Copyright (c) 2000, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.core.runtime.internal.stats; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.util.*; |
| import org.eclipse.osgi.baseadaptor.HookConfigurator; |
| import org.eclipse.osgi.baseadaptor.HookRegistry; |
| import org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry; |
| import org.eclipse.osgi.baseadaptor.hooks.ClassLoadingStatsHook; |
| import org.eclipse.osgi.baseadaptor.loader.ClasspathEntry; |
| import org.eclipse.osgi.baseadaptor.loader.ClasspathManager; |
| import org.eclipse.osgi.framework.adaptor.BundleWatcher; |
| import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; |
| import org.eclipse.osgi.framework.debug.Debug; |
| import org.eclipse.osgi.framework.debug.FrameworkDebugOptions; |
| import org.eclipse.osgi.util.ManifestElement; |
| import org.osgi.framework.Bundle; |
| |
| public class StatsManager implements BundleWatcher, HookConfigurator, ClassLoadingStatsHook { |
| // This connect bundles and their info, and so allows to access the info without running through |
| // the bundle registry. This map only contains activated bundles. The key is the bundle Id |
| private Hashtable bundles = new Hashtable(20); |
| private Map activationStacks = new HashMap(5); |
| private static boolean booting = true; // the state of the platform. This value is changed by the InternalPlatform itself. |
| |
| private static StatsManager defaultInstance; |
| |
| public static boolean MONITOR_ACTIVATION = false; |
| public static boolean MONITOR_CLASSES = false; |
| public static boolean MONITOR_RESOURCES = false; |
| public static String TRACE_FILENAME = "runtime.traces"; //$NON-NLS-1$ |
| public static String TRACE_FILTERS = "trace.properties"; //$NON-NLS-1$ |
| public static boolean TRACE_CLASSES = false; |
| public static boolean TRACE_BUNDLES = false; |
| public static final String FRAMEWORK_SYMBOLICNAME = "org.eclipse.osgi"; //$NON-NLS-1$ |
| |
| //Option names for spies |
| private static final String OPTION_MONITOR_ACTIVATION = FRAMEWORK_SYMBOLICNAME + "/monitor/activation"; //$NON-NLS-1$ |
| private static final String OPTION_MONITOR_CLASSES = FRAMEWORK_SYMBOLICNAME + "/monitor/classes"; //$NON-NLS-1$ |
| private static final String OPTION_MONITOR_RESOURCES = FRAMEWORK_SYMBOLICNAME + "/monitor/resources"; //$NON-NLS-1$ |
| private static final String OPTION_TRACE_BUNDLES = FRAMEWORK_SYMBOLICNAME + "/trace/activation"; //$NON-NLS-1$ |
| private static final String OPTION_TRACE_CLASSES = FRAMEWORK_SYMBOLICNAME + "/trace/classLoading"; //$NON-NLS-1$ |
| private static final String OPTION_TRACE_FILENAME = FRAMEWORK_SYMBOLICNAME + "/trace/filename"; //$NON-NLS-1$ |
| private static final String OPTION_TRACE_FILTERS = FRAMEWORK_SYMBOLICNAME + "/trace/filters"; //$NON-NLS-1$ |
| |
| static { |
| setDebugOptions(); |
| } |
| |
| public static StatsManager getDefault() { |
| if (defaultInstance == null) { |
| defaultInstance = new StatsManager(); |
| defaultInstance.initialize(); |
| } |
| return defaultInstance; |
| } |
| |
| public static void setDebugOptions() { |
| FrameworkDebugOptions options = FrameworkDebugOptions.getDefault(); |
| // may be null if debugging is not enabled |
| if (options == null) |
| return; |
| MONITOR_ACTIVATION = options.getBooleanOption(OPTION_MONITOR_ACTIVATION, false); |
| MONITOR_CLASSES = options.getBooleanOption(OPTION_MONITOR_CLASSES, false); |
| MONITOR_RESOURCES = options.getBooleanOption(OPTION_MONITOR_RESOURCES, false); |
| TRACE_CLASSES = options.getBooleanOption(OPTION_TRACE_CLASSES, false); |
| TRACE_BUNDLES = options.getBooleanOption(OPTION_TRACE_BUNDLES, false); |
| TRACE_FILENAME = options.getOption(OPTION_TRACE_FILENAME, TRACE_FILENAME); |
| TRACE_FILTERS = options.getOption(OPTION_TRACE_FILTERS, TRACE_FILTERS); |
| } |
| |
| public static void doneBooting() { |
| booting = false; |
| } |
| |
| public static boolean isBooting() { |
| return booting; |
| } |
| |
| /** |
| * Returns the result of converting a list of comma-separated tokens into an array |
| * |
| * @return the array of string tokens |
| * @param prop the initial comma-separated string |
| */ |
| public static String[] getArrayFromList(String prop) { |
| return ManifestElement.getArrayFromList(prop, ","); //$NON-NLS-1$ |
| } |
| |
| private void initialize() { |
| // add the system bundle |
| BundleStats bundle = findBundle(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, 0); |
| bundle.setTimestamp(System.currentTimeMillis()); |
| bundle.setActivationOrder(bundles.size()); |
| bundle.setDuringStartup(booting); |
| } |
| |
| public void watchBundle(Bundle bundle, int type) { |
| switch (type) { |
| case BundleWatcher.START_ACTIVATION : |
| startActivation(bundle); |
| break; |
| case BundleWatcher.END_ACTIVATION : |
| endActivation(bundle); |
| break; |
| } |
| } |
| |
| public void startActivation(Bundle bundle) { |
| // should be called from a synchronized location to protect against concurrent updates |
| BundleStats info = findBundle(bundle.getSymbolicName(), bundle.getBundleId()); |
| info.setTimestamp(System.currentTimeMillis()); |
| info.setActivationOrder(bundles.size()); |
| info.setDuringStartup(booting); |
| |
| Stack activationStack = (Stack) activationStacks.get(Thread.currentThread()); |
| if (activationStack == null) { |
| activationStack = new Stack(); |
| activationStacks.put(Thread.currentThread(), activationStack); |
| } |
| |
| // set the parentage of activation |
| if (activationStack.size() != 0) { |
| BundleStats activatedBy = (BundleStats) activationStack.peek(); |
| activatedBy.activated(info); |
| info.setActivatedBy(activatedBy); |
| } |
| activationStack.push(info); |
| |
| if (TRACE_BUNDLES == true) { |
| traceActivate(bundle, info); |
| } |
| } |
| |
| public void endActivation(Bundle symbolicName) { |
| Stack activationStack = (Stack) activationStacks.get(Thread.currentThread()); |
| // should be called from a synchronized location to protect against concurrent updates |
| BundleStats info = (BundleStats) activationStack.pop(); |
| info.endActivation(); |
| } |
| |
| private void traceActivate(Bundle bundle, BundleStats info) { |
| try { |
| PrintWriter output = new PrintWriter(new FileOutputStream(ClassloaderStats.traceFile.getAbsolutePath(), true)); |
| try { |
| long startPosition = ClassloaderStats.traceFile.length(); |
| output.println("Activating bundle: " + bundle.getSymbolicName()); //$NON-NLS-1$ |
| output.println("Bundle activation stack:"); //$NON-NLS-1$ |
| Stack activationStack = (Stack) activationStacks.get(Thread.currentThread()); |
| for (int i = activationStack.size() - 1; i >= 0; i--) |
| output.println("\t" + ((BundleStats) activationStack.get(i)).getSymbolicName()); //$NON-NLS-1$ |
| output.println("Class loading stack:"); //$NON-NLS-1$ |
| Stack classStack = ClassloaderStats.getClassStack(); |
| for (int i = classStack.size() - 1; i >= 0; i--) |
| output.println("\t" + ((ClassStats) classStack.get(i)).getClassName()); //$NON-NLS-1$ |
| output.println("Stack trace:"); //$NON-NLS-1$ |
| new Throwable().printStackTrace(output); |
| info.setTraceStart(startPosition); |
| } finally { |
| output.close(); |
| info.setTraceEnd(ClassloaderStats.traceFile.length()); |
| } |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| |
| public BundleStats findBundle(String symbolicName, long id) { |
| BundleStats result = (BundleStats) bundles.get(new Long(id)); |
| try { |
| if (result == null) { |
| result = new BundleStats(symbolicName, id); |
| bundles.put(new Long(id), result); |
| } |
| } catch (IllegalAccessError e) { |
| e.printStackTrace(); |
| } |
| return result; |
| } |
| |
| public BundleStats[] getBundles() { |
| return (BundleStats[]) bundles.values().toArray(new BundleStats[bundles.size()]); |
| } |
| |
| public BundleStats getBundle(long id) { |
| return (BundleStats) bundles.get(new Long(id)); |
| } |
| |
| public void preFindLocalClass(String name, ClasspathManager manager) throws ClassNotFoundException { |
| if (StatsManager.MONITOR_CLASSES) //Support for performance analysis |
| ClassloaderStats.startLoadingClass(getClassloaderId(manager), name); |
| } |
| |
| public void postFindLocalClass(String name, Class clazz, ClasspathManager manager) { |
| if (StatsManager.MONITOR_CLASSES) |
| ClassloaderStats.endLoadingClass(getClassloaderId(manager), name, clazz != null); |
| } |
| |
| public void preFindLocalResource(String name, ClasspathManager manager) { |
| // do nothing |
| } |
| |
| public void postFindLocalResource(String name, URL resource, ClasspathManager manager) { |
| if (StatsManager.MONITOR_RESOURCES) |
| if (resource != null && name.endsWith(".properties")) //$NON-NLS-1$ |
| ClassloaderStats.loadedBundle(getClassloaderId(manager), new ResourceBundleStats(getClassloaderId(manager), name, resource)); |
| return; |
| } |
| |
| public void recordClassDefine(String name, Class clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { |
| // do nothing |
| } |
| |
| private String getClassloaderId(ClasspathManager loader) { |
| return loader.getBaseData().getSymbolicName(); |
| } |
| |
| public void addHooks(HookRegistry hookRegistry) { |
| if (Debug.MONITOR_ACTIVATION) |
| hookRegistry.addWatcher(StatsManager.getDefault()); |
| if (StatsManager.MONITOR_CLASSES || StatsManager.MONITOR_RESOURCES) |
| hookRegistry.addClassLoadingStatsHook(StatsManager.getDefault()); |
| } |
| } |