// Copyright 2008 Google Inc. // // 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.google.android.stardroid.util; import com.google.android.stardroid.base.Preconditions; import com.google.android.stardroid.base.Provider; import java.util.ArrayList; import java.util.List; /** * A tree of {@link StopWatchImpl}s used to perform nested timings of methods. While * it is possible to use this class directly to compute nested timings, users * may find wrapping this class with a {@link StopWatchTreePath} simpler. * * @author Brent Bryan */ public class StopWatchTree { private static final Provider<StopWatchTree> TREE_PROVIDER = new Provider<StopWatchTree>() { @Override public StopWatchTree get() { return new StopWatchTree(StopWatchImpl.getProvider()); } }; private final StopWatchTreeNode root; public StopWatchTree(Provider<StopWatch> watchProvider) { root = new StopWatchTreeNode(watchProvider, "Total Elapsed Time"); } /** * Returns the root node of this {@link StopWatchTree}. The result will never * be null. */ public StopWatchTreeNode getRoot() { return root; } /** * Starts the root timer for this {@link StopWatchTree}. Timers in children * nodes will remain unstarted. * * @throws RuntimeException if this method is called when {@link #isRunning} * is true. * @return A reference to the root StopWatchTreeNode object for chaining */ public StopWatchTree start() { Preconditions.check(!isRunning()); root.start(); return this; } /** * Stops all currently running watches in the {@link StopWatchTree}, retaining * all information. * * @throws RuntimeException if this method is called when {@link #isRunning} * is false. * @return A reference to this object for chaining */ public StopWatchTree stop() { Preconditions.check(isRunning()); root.stop(); return this; } /** * Returns true if this {@link StopWatchTree} is running. That is, returns * true if {@link #start} or {@link #reset} have been called subsequent to the * last invocation of {@link #stop} (or creation of the * {@link StopWatchTree}). */ public boolean isRunning() { return root.getStopWatch().isRunning(); } /** * Resets the {@link StopWatchTree}, removing all children, clearing the state * of all watches (running or not) and setting the state of this StopWatchTree * to non running. * * @return A reference to the root StopWatchTreeNode object for chaining */ public StopWatchTree reset() { root.reset(); return this; } /** * Returns a {@link TimingTree} describing the timing values at watch * node (including those nodes which have been {@link #stop}ed). This method * has no side effects on this {@link StopWatchTree}. * * @return StopWatchTreeStatus representing the current durations for each * node in this {@link StopWatchTree}. */ public TimingTree getCurrentTiming() { return new TimingTree(createTimingForNode(0, root)); } private TimingTreeNode createTimingForNode(int level, StopWatchTreeNode node) { long elapsedTime = node.getStopWatch().getElapsedTime(); List<TimingTreeNode> children = new ArrayList<TimingTreeNode>(node.getNumChildren()); for (StopWatchTreeNode child : node.getChildren()) { children.add(createTimingForNode(level + 1, child)); } return new TimingTreeNode(level, node.getName(), elapsedTime, children); } public static Provider<StopWatchTree> getProvider() { return TREE_PROVIDER; } }