15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.common;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Debug;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Debug.MemoryInfo;
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log;
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.json.JSONArray;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.json.JSONException;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.json.JSONObject;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.File;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileNotFoundException;
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.FileOutputStream;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.PrintStream;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.LinkedList;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.List;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PerfTraceEvent can be used like TraceEvent, but is intended for
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * performance measurement.  By limiting the types of tracing we hope
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to minimize impact on measurement.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All PerfTraceEvent events funnel into TraceEvent. When not doing
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * performance measurements, they act the same.  However,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * PerfTraceEvents can be enabled even when TraceEvent is not.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unlike TraceEvent, PerfTraceEvent data is sent to the system log,
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * not to a trace file.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Performance events need to have very specific names so we find
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the right ones.  For example, we specify the name exactly in
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the @TracePerf annotation.  Thus, unlike TraceEvent, we do not
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * support an implicit trace name based on the callstack.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public class PerfTraceEvent {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int MAX_NAME_LENGTH = 40;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final String MEMORY_TRACE_NAME_SUFFIX = "_BZR_PSS";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static File sOutputFile = null;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /** The event types understood by the perf trace scripts. */
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private enum EventType {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        START("S"),
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FINISH("F"),
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        INSTANT("I");
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The string understood by the trace scripts.
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        private final String mTypeStr;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        EventType(String typeStr) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mTypeStr = typeStr;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        @Override
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public String toString() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return mTypeStr;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static boolean sEnabled = false;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static boolean sTrackTiming = true;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static boolean sTrackMemory = false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A list of performance trace event strings.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Events are stored as a JSON dict much like TraceEvent.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // E.g. timestamp is in microseconds.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static JSONArray sPerfTraceStrings;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A filter for performance tracing.  Only events that match a
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // string in the list are saved.  Presence of a filter does not
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // necessarily mean perf tracing is enabled.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static List<String> sFilter;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Nanosecond start time of performance tracing.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static long sBeginNanoTime;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Specifies what event names will be tracked.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param strings Event names we will record.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static synchronized void setFilter(List<String> strings) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sFilter = new LinkedList<String>(strings);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Enable or disable perf tracing.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Disabling of perf tracing will dump trace data to the system log.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void setEnabled(boolean enabled) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled == enabled) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (enabled) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sBeginNanoTime = System.nanoTime();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sPerfTraceStrings = new JSONArray();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            dumpPerf();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sPerfTraceStrings = null;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sFilter = null;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sEnabled = enabled;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Enables memory tracking for all timing perf events tracked.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * <p>
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Only works when called in combination with {@link #setEnabled(boolean)}.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * <p>
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * By enabling this feature, an additional perf event containing the memory usage will be
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * logged whenever {@link #instant(String)}, {@link #begin(String)}, or {@link #end(String)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * is called.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param enabled Whether to enable memory tracking for all perf events.
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void setMemoryTrackingEnabled(boolean enabled) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sTrackMemory = enabled;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Enables timing tracking for all perf events tracked.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * <p>
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Only works when called in combination with {@link #setEnabled(boolean)}.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * <p>
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * If this feature is enabled, whenever {@link #instant(String)}, {@link #begin(String)},
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * or {@link #end(String)} is called the time since start of tracking will be logged.
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param enabled Whether to enable timing tracking for all perf events.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void setTimingTrackingEnabled(boolean enabled) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sTrackTiming = enabled;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return True if tracing is enabled, false otherwise.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * It is safe to call trace methods without checking if PerfTraceEvent
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * is enabled.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static synchronized boolean enabled() {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sEnabled;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Record an "instant" perf trace event.  E.g. "screen update happened".
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void instant(String name) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Instant doesn't really need/take an event id, but this should be okay.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final long eventId = name.hashCode();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TraceEvent.instant(name);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled && matchesFilter(name)) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            savePerfString(name, eventId, EventType.INSTANT, false);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Record an "begin" perf trace event.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Begin trace events should have a matching end event.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void begin(String name) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final long eventId = name.hashCode();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TraceEvent.startAsync(name, eventId);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled && matchesFilter(name)) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Done before calculating the starting perf data to ensure calculating the memory usage
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // does not influence the timing data.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackMemory) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        true);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackTiming) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(name, eventId, EventType.START, false);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Record an "end" perf trace event, to match a begin event.  The
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * time delta between begin and end is usually interesting to
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * graph code.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void end(String name) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final long eventId = name.hashCode();
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TraceEvent.finishAsync(name, eventId);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled && matchesFilter(name)) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackTiming) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(name, eventId, EventType.FINISH, false);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Done after calculating the ending perf data to ensure calculating the memory usage
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // does not influence the timing data.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackMemory) {
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        true);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Record an "begin" memory trace event.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Begin trace events should have a matching end event.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void begin(String name, MemoryInfo memoryInfo) {
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final long eventId = name.hashCode();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TraceEvent.startAsync(name, eventId);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled && matchesFilter(name)) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Done before calculating the starting perf data to ensure calculating the memory usage
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // does not influence the timing data.
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    timestampUs, memoryInfo);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackTiming) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(name, eventId, EventType.START, false);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Record an "end" memory trace event, to match a begin event.  The
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * memory usage delta between begin and end is usually interesting to
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * graph code.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static synchronized void end(String name, MemoryInfo memoryInfo) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        final long eventId = name.hashCode();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TraceEvent.finishAsync(name, eventId);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sEnabled && matchesFilter(name)) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (sTrackTiming) {
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                savePerfString(name, eventId, EventType.FINISH, false);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Done after calculating the instant perf data to ensure calculating the memory usage
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // does not influence the timing data.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    timestampUs, memoryInfo);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Determine if we are interested in this trace event.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return True if the name matches the allowed filter; else false.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static boolean matchesFilter(String name) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return sFilter != null ? sFilter.contains(name) : false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param name The trace data
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param id The id of the event
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param type the type of trace event (I, S, F)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param includeMemory Whether to include current browser process memory usage in the trace.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static void savePerfString(String name, long id, EventType type,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            boolean includeMemory) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        MemoryInfo memInfo = null;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (includeMemory) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            memInfo = new MemoryInfo();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            Debug.getMemoryInfo(memInfo);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        savePerfString(name, id, type, timestampUs, memInfo);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param name The trace data
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param id The id of the event
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param type the type of trace event (I, S, F)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param timestampUs The time stamp at which this event was recorded
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param memoryInfo Memory details to be included in this perf string, null if
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *                   no memory details are to be included.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static void savePerfString(String name, long id, EventType type, long timestampUs,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            MemoryInfo memoryInfo) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            JSONObject traceObj = new JSONObject();
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            traceObj.put("cat", "Java");
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            traceObj.put("ts", timestampUs);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            traceObj.put("ph", type);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            traceObj.put("name", name);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            traceObj.put("id", id);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (memoryInfo != null) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                int pss = memoryInfo.nativePss + memoryInfo.dalvikPss + memoryInfo.otherPss;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                traceObj.put("mem", pss);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sPerfTraceStrings.put(traceObj);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } catch (JSONException e) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new RuntimeException(e);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Generating a trace name for tracking memory based on the timing name passed in.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param name The timing name to use as a base for the memory perf name.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return The memory perf name to use.
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String makeMemoryTraceNameFromTimingName(String name) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return makeSafeTraceName(name, MEMORY_TRACE_NAME_SUFFIX);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Builds a name to be used in the perf trace framework.  The framework has length requirements
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * for names, so this ensures the generated name does not exceed the maximum (trimming the
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * base name if necessary).
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param baseName The base name to use when generating the name.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param suffix The required suffix to be appended to the name.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return A name that is safe for the perf trace framework.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public static String makeSafeTraceName(String baseName, String suffix) {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int suffixLength = suffix.length();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (baseName.length() + suffixLength > MAX_NAME_LENGTH) {
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            baseName = baseName.substring(0, MAX_NAME_LENGTH - suffixLength);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return baseName + suffix;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Sets a file to dump the results to.  If {@code file} is {@code null}, it will be dumped
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * to STDOUT, otherwise the JSON performance data will be appended to {@code file}.  This should
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * be called before the performance run starts.  When {@link #setEnabled(boolean)} is called
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * with {@code false}, the perf data will be dumped.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param file Which file to append the performance data to.  If {@code null}, the performance
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     *             data will be sent to STDOUT.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    public static synchronized void setOutputFile(File file) {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sOutputFile = file;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Dump all performance data we have saved up to the log.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Output as JSON for parsing convenience.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static void dumpPerf() {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        String json = sPerfTraceStrings.toString();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (sOutputFile == null) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            System.out.println(json);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            try {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                PrintStream stream = new PrintStream(new FileOutputStream(sOutputFile, true));
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                try {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    stream.print(json);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                } finally {
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    try {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        stream.close();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    } catch (Exception ex) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        Log.e("PerfTraceEvent", "Unable to close perf trace output file.");
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            } catch (FileNotFoundException ex) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                Log.e("PerfTraceEvent", "Unable to dump perf trace data to output file.");
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
367