1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.util;
18 
19 import java.util.ArrayList;
20 
21 import android.os.SystemClock;
22 
23 /**
24  * A utility class to help log timings splits throughout a method call.
25  * Typical usage is:
26  *
27  * <pre>
28  *     TimingLogger timings = new TimingLogger(TAG, "methodA");
29  *     // ... do some work A ...
30  *     timings.addSplit("work A");
31  *     // ... do some work B ...
32  *     timings.addSplit("work B");
33  *     // ... do some work C ...
34  *     timings.addSplit("work C");
35  *     timings.dumpToLog();
36  * </pre>
37  *
38  * <p>The dumpToLog call would add the following to the log:</p>
39  *
40  * <pre>
41  *     D/TAG     ( 3459): methodA: begin
42  *     D/TAG     ( 3459): methodA:      9 ms, work A
43  *     D/TAG     ( 3459): methodA:      1 ms, work B
44  *     D/TAG     ( 3459): methodA:      6 ms, work C
45  *     D/TAG     ( 3459): methodA: end, 16 ms
46  * </pre>
47  *
48  * @deprecated Use {@link android.os.Trace}, or
49  *   <a href="https://developer.android.com/studio/profile/benchmark">Android Studio</a>. In
50  *   general, milliseconds is the wrong granularity for method-level tracing. Rounding errors
51  *   can overemphasize cheap operations, or underemphasize repeated operations. This timing
52  *   system also does not take CPU scheduling or frequency into account.
53  */
54 @Deprecated
55 public class TimingLogger {
56 
57     /**
58      * The Log tag to use for checking Log.isLoggable and for
59      * logging the timings.
60      */
61     private String mTag;
62 
63     /** A label to be included in every log. */
64     private String mLabel;
65 
66     /** Used to track whether Log.isLoggable was enabled at reset time. */
67     private boolean mDisabled;
68 
69     /** Stores the time of each split. */
70     ArrayList<Long> mSplits;
71 
72     /** Stores the labels for each split. */
73     ArrayList<String> mSplitLabels;
74 
75     /**
76      * Create and initialize a TimingLogger object that will log using
77      * the specific tag. If the Log.isLoggable is not enabled to at
78      * least the Log.VERBOSE level for that tag at creation time then
79      * the addSplit and dumpToLog call will do nothing.
80      * @param tag the log tag to use while logging the timings
81      * @param label a string to be displayed with each log
82      */
TimingLogger(String tag, String label)83     public TimingLogger(String tag, String label) {
84         reset(tag, label);
85     }
86 
87     /**
88      * Clear and initialize a TimingLogger object that will log using
89      * the specific tag. If the Log.isLoggable is not enabled to at
90      * least the Log.VERBOSE level for that tag at creation time then
91      * the addSplit and dumpToLog call will do nothing.
92      * @param tag the log tag to use while logging the timings
93      * @param label a string to be displayed with each log
94      */
reset(String tag, String label)95     public void reset(String tag, String label) {
96         mTag = tag;
97         mLabel = label;
98         reset();
99     }
100 
101     /**
102      * Clear and initialize a TimingLogger object that will log using
103      * the tag and label that was specified previously, either via
104      * the constructor or a call to reset(tag, label). If the
105      * Log.isLoggable is not enabled to at least the Log.VERBOSE
106      * level for that tag at creation time then the addSplit and
107      * dumpToLog call will do nothing.
108      */
reset()109     public void reset() {
110         mDisabled = !Log.isLoggable(mTag, Log.VERBOSE);
111         if (mDisabled) return;
112         if (mSplits == null) {
113             mSplits = new ArrayList<Long>();
114             mSplitLabels = new ArrayList<String>();
115         } else {
116             mSplits.clear();
117             mSplitLabels.clear();
118         }
119         addSplit(null);
120     }
121 
122     /**
123      * Add a split for the current time, labeled with splitLabel. If
124      * Log.isLoggable was not enabled to at least the Log.VERBOSE for
125      * the specified tag at construction or reset() time then this
126      * call does nothing.
127      * @param splitLabel a label to associate with this split.
128      */
addSplit(String splitLabel)129     public void addSplit(String splitLabel) {
130         if (mDisabled) return;
131         long now = SystemClock.elapsedRealtime();
132         mSplits.add(now);
133         mSplitLabels.add(splitLabel);
134     }
135 
136     /**
137      * Dumps the timings to the log using Log.d(). If Log.isLoggable was
138      * not enabled to at least the Log.VERBOSE for the specified tag at
139      * construction or reset() time then this call does nothing.
140      */
dumpToLog()141     public void dumpToLog() {
142         if (mDisabled) return;
143         Log.d(mTag, mLabel + ": begin");
144         final long first = mSplits.get(0);
145         long now = first;
146         for (int i = 1; i < mSplits.size(); i++) {
147             now = mSplits.get(i);
148             final String splitLabel = mSplitLabels.get(i);
149             final long prev = mSplits.get(i - 1);
150 
151             Log.d(mTag, mLabel + ":      " + (now - prev) + " ms, " + splitLabel);
152         }
153         Log.d(mTag, mLabel + ": end, " + (now - first) + " ms");
154     }
155 }
156