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