19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.util;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A utility class to help log timings splits throughout a method call.
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Typical usage is:
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
2749afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * <pre>
2849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     TimingLogger timings = new TimingLogger(TAG, "methodA");
2949afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     // ... do some work A ...
3049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     timings.addSplit("work A");
3149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     // ... do some work B ...
3249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     timings.addSplit("work B");
3349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     // ... do some work C ...
3449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     timings.addSplit("work C");
3549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     timings.dumpToLog();
3649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * </pre>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
3849afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * <p>The dumpToLog call would add the following to the log:</p>
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
4049afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * <pre>
4149afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     D/TAG     ( 3459): methodA: begin
4249afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     D/TAG     ( 3459): methodA:      9 ms, work A
4349afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     D/TAG     ( 3459): methodA:      1 ms, work B
4449afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     D/TAG     ( 3459): methodA:      6 ms, work C
4549afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase *     D/TAG     ( 3459): methodA: end, 16 ms
4649afa5bc100e5d4c069fea980dd6b09501f56397Chet Haase * </pre>
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class TimingLogger {
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The Log tag to use for checking Log.isLoggable and for
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * logging the timings.
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mTag;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** A label to be included in every log. */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mLabel;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Used to track whether Log.isLoggable was enabled at reset time. */
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mDisabled;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Stores the time of each split. */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ArrayList<Long> mSplits;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Stores the labels for each split. */
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ArrayList<String> mSplitLabels;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create and initialize a TimingLogger object that will log using
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the specific tag. If the Log.isLoggable is not enabled to at
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * least the Log.VERBOSE level for that tag at creation time then
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the addSplit and dumpToLog call will do nothing.
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tag the log tag to use while logging the timings
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param label a string to be displayed with each log
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public TimingLogger(String tag, String label) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        reset(tag, label);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear and initialize a TimingLogger object that will log using
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the specific tag. If the Log.isLoggable is not enabled to at
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * least the Log.VERBOSE level for that tag at creation time then
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the addSplit and dumpToLog call will do nothing.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param tag the log tag to use while logging the timings
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param label a string to be displayed with each log
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void reset(String tag, String label) {
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTag = tag;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLabel = label;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        reset();
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear and initialize a TimingLogger object that will log using
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the tag and label that was specified previously, either via
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the constructor or a call to reset(tag, label). If the
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Log.isLoggable is not enabled to at least the Log.VERBOSE
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * level for that tag at creation time then the addSplit and
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * dumpToLog call will do nothing.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void reset() {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDisabled = !Log.isLoggable(mTag, Log.VERBOSE);
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDisabled) return;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSplits == null) {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSplits = new ArrayList<Long>();
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSplitLabels = new ArrayList<String>();
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSplits.clear();
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSplitLabels.clear();
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        addSplit(null);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a split for the current time, labeled with splitLabel. If
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Log.isLoggable was not enabled to at least the Log.VERBOSE for
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the specified tag at construction or reset() time then this
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * call does nothing.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param splitLabel a label to associate with this split.
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addSplit(String splitLabel) {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDisabled) return;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.elapsedRealtime();
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSplits.add(now);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSplitLabels.add(splitLabel);
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Dumps the timings to the log using Log.d(). If Log.isLoggable was
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not enabled to at least the Log.VERBOSE for the specified tag at
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * construction or reset() time then this call does nothing.
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void dumpToLog() {
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDisabled) return;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(mTag, mLabel + ": begin");
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long first = mSplits.get(0);
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = first;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 1; i < mSplits.size(); i++) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            now = mSplits.get(i);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final String splitLabel = mSplitLabels.get(i);
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long prev = mSplits.get(i - 1);
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.d(mTag, mLabel + ":      " + (now - prev) + " ms, " + splitLabel);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(mTag, mLabel + ": end, " + (now - first) + " ms");
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
149