Skip to content
Snippets Groups Projects
Commit ea5bf19e authored by Xin Li's avatar Xin Li
Browse files

Merge pi-dev-plus-aosp-without-vendor into stage-aosp-master

Bug: 79597307
Change-Id: I3dbae1a7e07d8bf2eff3f50b2c02fe6f747678cb
parents f7187e0d 527b936e
Branches
No related tags found
No related merge requests found
Showing
with 1136 additions and 90 deletions
erowe@google.com
gelanchezhian@google.com
guangzhu@google.com
jdesprez@google.com
mrosenfeld@google.com
siniavine@google.com
tobiast@google.com
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.item;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* An {@link IItem} used to store output from `dumpsys meminfo --checkin PROCESS` where PROCESS is
* from the output of `dumpsys meminfo`. Data is stored as a map of categories to a map of
* measurement types to values.
*/
public class DumpsysProcessMeminfoItem extends GenericMapItem<Map<String, Long>> {
// Should match value from ActivityThread
public static final int ACTIVITY_THREAD_CHECKIN_VERSION = 4;
// Default Categories
public static final String NATIVE = "NATIVE";
public static final String DALVIK = "DALVIK";
public static final String OTHER = "OTHER";
public static final String TOTAL = "TOTAL";
// Memory Measurement Types
public static final String PSS = "PSS";
public static final String SWAPPABLE_PSS = "SWAPPABLE_PSS";
public static final String SHARED_DIRTY = "SHARED_DIRTY";
public static final String SHARED_CLEAN = "SHARED_CLEAN";
public static final String PRIVATE_DIRTY = "PRIVATE_DIRTY";
public static final String PRIVATE_CLEAN = "PRIVATE_CLEAN";
public static final String SWAPPED_OUT = "SWAPPED_OUT";
public static final String SWAPPED_OUT_PSS = "SWAPPED_OUT_PSS";
// NATIVE, DALVIK, TOTAL only
public static final String MAX = "MAX";
public static final String ALLOCATED = "ALLOCATED";
public static final String FREE = "FREE";
public static final String[] MAIN_OUTPUT_ORDER = {
MAX,
ALLOCATED,
FREE,
PSS,
SWAPPABLE_PSS,
SHARED_DIRTY,
SHARED_CLEAN,
PRIVATE_DIRTY,
PRIVATE_CLEAN,
SWAPPED_OUT,
SWAPPED_OUT_PSS
};
public static final String[] OTHER_OUTPUT_ORDER = {
PSS,
SWAPPABLE_PSS,
SHARED_DIRTY,
SHARED_CLEAN,
PRIVATE_DIRTY,
PRIVATE_CLEAN,
SWAPPED_OUT,
SWAPPED_OUT_PSS
};
private int mPid;
private String mProcessName;
public DumpsysProcessMeminfoItem() {
this.put(NATIVE, new HashMap<>());
this.put(DALVIK, new HashMap<>());
this.put(OTHER, new HashMap<>());
this.put(TOTAL, new HashMap<>());
}
/** Get the pid */
public int getPid() {
return mPid;
}
/** Set the pid */
public void setPid(int pid) {
mPid = pid;
}
/** Get the process name */
public String getProcessName() {
return mProcessName;
}
/** Set the process name */
public void setProcessName(String processName) {
mProcessName = processName;
}
/** {@inheritDoc} */
@Override
public JSONObject toJson() {
JSONObject result = super.toJson();
try {
result.put("pid", mPid);
result.put("process_name", mProcessName);
} catch (JSONException e) {
//ignore
}
return result;
}
}
......@@ -38,6 +38,12 @@ public class GfxInfoItem implements IItem {
public static final String TOTAL_FRAMES_KEY = "total_frames";
/** Constant for JSON output */
public static final String JANKY_FRAMES_KEY = "janky_frames";
/** Constant for JSON output */
public static final String PERCENTILE_90_KEY = "percentile_90";
/** Constant for JSON output */
public static final String PERCENTILE_95_KEY = "percentile_95";
/** Constant for JSON output */
public static final String PERCENTILE_99_KEY = "percentile_99";
private Map<Integer, Row> mRows = new HashMap<Integer, Row>();
......@@ -45,6 +51,9 @@ public class GfxInfoItem implements IItem {
public String name;
public long totalFrames;
public long jankyFrames;
public int percentile90;
public int percentile95;
public int percentile99;
}
/**
......@@ -76,7 +85,9 @@ public class GfxInfoItem implements IItem {
proc.put(PID_KEY, pid);
proc.put(NAME_KEY, getName(pid));
proc.put(TOTAL_FRAMES_KEY, getTotalFrames(pid));
proc.put(JANKY_FRAMES_KEY, getJankyFrames(pid));
proc.put(PERCENTILE_90_KEY, getPrecentile90(pid));
proc.put(PERCENTILE_95_KEY, getPrecentile95(pid));
proc.put(PERCENTILE_99_KEY, getPrecentile99(pid));
processes.put(proc);
} catch (JSONException e) {
// ignore
......@@ -106,11 +117,21 @@ public class GfxInfoItem implements IItem {
* @param totalFrames The number of total frames rendered by the process
* @param jankyFrames The number of janky frames rendered by the process
*/
public void addRow(int pid, String name, long totalFrames, long jankyFrames) {
public void addRow(
int pid,
String name,
long totalFrames,
long jankyFrames,
int percentile90,
int percentile95,
int percentile99) {
Row row = new Row();
row.name = name;
row.totalFrames = totalFrames;
row.jankyFrames = jankyFrames;
row.percentile90 = percentile90;
row.percentile95 = percentile95;
row.percentile99 = percentile99;
mRows.put(pid, row);
}
......@@ -134,4 +155,19 @@ public class GfxInfoItem implements IItem {
public long getJankyFrames(int pid) {
return mRows.get(pid).jankyFrames;
}
/** Get the 90th percentile value of frame times (ms) */
public int getPrecentile90(int pid) {
return mRows.get(pid).percentile90;
}
/** Get the 95th percentile value of frame times (ms) */
public int getPrecentile95(int pid) {
return mRows.get(pid).percentile95;
}
/** Get the 99th percentile value of frame times (ms) */
public int getPrecentile99(int pid) {
return mRows.get(pid).percentile99;
}
}
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.item;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
/** A {@link GenericItem} of trace format. */
public class TraceFormatItem extends GenericItem {
private static final String REGEX = "regex";
private static final String PARAMS = "params";
private static final String NUM_PARAMS = "num_params";
private static final String HEX_PARAMS = "hex_params";
private static final String STR_PARAMS = "str_params";
private static final Set<String> ATTRIBUTES =
new HashSet<>(Arrays.asList(REGEX, PARAMS, NUM_PARAMS, HEX_PARAMS, STR_PARAMS));
/** Create a new {@link TraceFormatItem} */
public TraceFormatItem() {
super(ATTRIBUTES);
}
@Override
/** TraceFormatItem doesn't support merge */
public IItem merge(IItem other) throws ConflictingItemException {
throw new ConflictingItemException("Trace format items cannot be merged");
}
/** Get a compiled regex that matches output of this trace format */
public Pattern getRegex() {
return (Pattern) getAttribute(REGEX);
}
/** Set a compiled regex that matches output of this trace format */
public void setRegex(Pattern regex) {
setAttribute(REGEX, regex);
}
/**
* Get all parameters found in this trace format. The parameters were converted to camel case
* and match the group names in the regex.
*/
public List<String> getParameters() {
return (List<String>) getAttribute(PARAMS);
}
/**
* Set all parameters found in this trace format. The parameters were converted to camel case
* and match the group names in the regex.
*/
public void setParameters(List<String> parameters) {
setAttribute(PARAMS, parameters);
}
/**
* Get numeric parameters found in this trace format. The parameters were converted to camel
* case and match the group names in the regex.
*/
public List<String> getNumericParameters() {
return (List<String>) getAttribute(NUM_PARAMS);
}
/**
* Set numeric parameters found in this trace format. The parameters were converted to camel
* case and match the group names in the regex.
*/
public void setNumericParameters(List<String> numericParameters) {
setAttribute(NUM_PARAMS, numericParameters);
}
/**
* Get hexadecimal parameters found in this trace format. The parameters were converted to camel
* case and match the group names in the regex.
*/
public List<String> getHexParameters() {
return (List<String>) getAttribute(HEX_PARAMS);
}
/**
* Set hexadecimal parameters found in this trace format. The parameters were converted to camel
* case and match the group names in the regex.
*/
public void setHexParameters(List<String> hexParameters) {
setAttribute(HEX_PARAMS, hexParameters);
}
/**
* Get string parameters found in this trace format. The parameters were converted to camel case
* and match the group names in the regex.
*/
public List<String> getStringParameters() {
return (List<String>) getAttribute(STR_PARAMS);
}
/**
* Set string parameters found in this trace format. The parameters were converted to camel case
* and match the group names in the regex.
*/
public void setStringParameters(List<String> stringParameters) {
setAttribute(STR_PARAMS, stringParameters);
}
}
......@@ -30,9 +30,19 @@ public class TransitionDelayItem extends GenericItem {
public static final String START_WINDOW_DELAY = "START_WINDOW_DELAY";
/** Constant for JSON output */
public static final String TRANSITION_DELAY = "TRANSITION_DELAY";
/** Constant for JSON output */
public static final String DATE_TIME = "DATE_TIME";
/** Constant for JSON output */
public static final String WINDOW_DRAWN_DELAY = "WINDOW_DRAWN_DELAY";
private static final Set<String> ATTRIBUTES = new HashSet<String>(Arrays.asList(
COMPONENT_NAME, START_WINDOW_DELAY, TRANSITION_DELAY));
private static final Set<String> ATTRIBUTES =
new HashSet<String>(
Arrays.asList(
COMPONENT_NAME,
START_WINDOW_DELAY,
TRANSITION_DELAY,
DATE_TIME,
WINDOW_DRAWN_DELAY));
/**
* The constructor for {@link TransitionDelayItem}.
......@@ -49,20 +59,42 @@ public class TransitionDelayItem extends GenericItem {
setAttribute(COMPONENT_NAME, componentName);
}
public long getStartingWindowDelay() {
return (long) getAttribute(START_WINDOW_DELAY);
public Long getStartingWindowDelay() {
return getAttribute(START_WINDOW_DELAY) != null ? (Long) getAttribute(START_WINDOW_DELAY)
: null;
}
public void setStartingWindowDelay(long startingWindowDelay) {
setAttribute(START_WINDOW_DELAY, startingWindowDelay);
}
public long getTransitionDelay() {
return (long) getAttribute(TRANSITION_DELAY);
public Long getTransitionDelay() {
return (Long) getAttribute(TRANSITION_DELAY);
}
public void setTransitionDelay(long transitionDelay) {
setAttribute(TRANSITION_DELAY, transitionDelay);
}
/**
* @return date and time (MM-DD HH:MM:SS.mmm) in string format parsed from events log
* and used in AUPT test.
*/
public String getDateTime() {
return (String) getAttribute(DATE_TIME);
}
public void setDateTime(String dateTime) {
setAttribute(DATE_TIME, dateTime);
}
public Long getWindowDrawnDelay() {
return getAttribute(WINDOW_DRAWN_DELAY) != null
? (Long) getAttribute(WINDOW_DRAWN_DELAY)
: null;
}
public void setWindowDrawnDelay(long windowDrawnDelay) {
setAttribute(WINDOW_DRAWN_DELAY, windowDrawnDelay);
}
}
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.parser;
import com.android.loganalysis.item.DumpsysProcessMeminfoItem;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* An {@link IParser} used to parse output from `dumpsys meminfo --checkin PROCESS` where PROCESS is
* from the output of `dumpsys meminfo`. Data is stored as a map of categories to a map of
* measurement types to values. Format is from {@link android.app.ActivityThread#dumpMemInfoTable}.
*/
public class DumpsysProcessMeminfoParser implements IParser {
// Order is VERSION,PID,NAME,[native,dalvik,other,total]{11},[name,val{8}]*
private static final Pattern MEMINFO_OUTPUT =
Pattern.compile("(\\d+),(\\d+),([^,]+),((?:(?:N/A|\\d+),){44})(.*)");
// Matches the ending [name,val{8}]
private static final Pattern MEMINFO_ADDITIONAL_OUTPUT =
Pattern.compile("([^,]+),((?:(?:N/A|\\d+),){8})");
// Matches a value with comma
private static final Pattern MEMINFO_VALUE = Pattern.compile("(N/A|\\d+),");
@Override
public DumpsysProcessMeminfoItem parse(List<String> lines) {
DumpsysProcessMeminfoItem item = new DumpsysProcessMeminfoItem();
for (String line : lines) {
Matcher m = MEMINFO_OUTPUT.matcher(line);
if (!m.matches()) continue;
try {
item.setPid(Integer.parseInt(m.group(2)));
} catch (NumberFormatException e) {
// skip
}
item.setProcessName(m.group(3));
// parse memory info main areas
String mainValues = m.group(4);
Matcher mainMatcher = MEMINFO_VALUE.matcher(mainValues);
Map<String, Long> nativeData = item.get(DumpsysProcessMeminfoItem.NATIVE);
Map<String, Long> dalvikData = item.get(DumpsysProcessMeminfoItem.DALVIK);
Map<String, Long> otherData = item.get(DumpsysProcessMeminfoItem.OTHER);
Map<String, Long> totalData = item.get(DumpsysProcessMeminfoItem.TOTAL);
for (int i = 0; i < DumpsysProcessMeminfoItem.MAIN_OUTPUT_ORDER.length; i++) {
String curMeasurement = DumpsysProcessMeminfoItem.MAIN_OUTPUT_ORDER[i];
parseNextValue(mainMatcher, nativeData, curMeasurement);
parseNextValue(mainMatcher, dalvikData, curMeasurement);
parseNextValue(mainMatcher, otherData, curMeasurement);
parseNextValue(mainMatcher, totalData, curMeasurement);
}
String additionalData = m.group(5);
Matcher additionalMatcher = MEMINFO_ADDITIONAL_OUTPUT.matcher(additionalData);
// parse memory info other areas
while (additionalMatcher.find()) {
try {
String curLabel = additionalMatcher.group(1);
Matcher additionalValueMatcher =
MEMINFO_VALUE.matcher(additionalMatcher.group(2));
Map<String, Long> curData = new HashMap<>();
for (int i = 0; i < DumpsysProcessMeminfoItem.OTHER_OUTPUT_ORDER.length; i++) {
String curMeasurement = DumpsysProcessMeminfoItem.OTHER_OUTPUT_ORDER[i];
parseNextValue(additionalValueMatcher, curData, curMeasurement);
}
item.put(curLabel, curData);
} catch (ArrayIndexOutOfBoundsException e) {
break;
}
}
}
return item;
}
private void parseNextValue(Matcher m, Map<String, Long> output, String key) {
if (!m.find()) return;
String value = m.group(1);
if ("N/A".equals(value)) return;
try {
output.put(key, Long.parseLong(value));
} catch (NumberFormatException e) {
// skip
}
}
}
......@@ -23,7 +23,9 @@ import com.android.loganalysis.item.TransitionDelayItem;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
......@@ -32,28 +34,27 @@ import java.util.regex.Pattern;
*/
public class EventsLogParser implements IParser {
// 08-21 17:53:53.876 1053 2135
private static final String EVENTS_PREFIX = "^\\d{2}-\\d{2} \\d{2}:\\d{2}"
+ ":\\d{2}.\\d{3}\\s+\\d+\\s+\\d+ ";
// 01-01 01:38:44.863 1037 1111 I sysui_multi_action:
// [319,64,321,64,322,99,325,5951,757,761,758,9,759,4,806,com.google.android.gm,871,
// com.google.android.gm.welcome.WelcomeTourActivity,905,0]
private static final Pattern TRANSITION_STARTING_DELAY = Pattern.compile(
String.format("%s%s", EVENTS_PREFIX, "I sysui_multi_action: \\[319,(.*),321,(.*)"
+ ",322,(.*),806,(.*),871,(.*),905.*\\]$"));
// 01-01 01:38:44.863 1037 1111 I sysui_multi_action:
// [319,64,322,99,325,5951,757,761,758,9,759,4,806,com.google.android.gm,871,
// com.google.android.gm.welcome.WelcomeTourActivity,905,0]
private static final Pattern TRANSITION_DELAY = Pattern.compile(
String.format("%s%s", EVENTS_PREFIX, "I sysui_multi_action: \\[319,(.*),322,(.*)"
+ ",806,(.*),871,(.*),905.*\\]$"));
// 09-18 23:56:19.376 1140 1221 I sysui_multi_action:
// [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,
// com.android.calculator2.Calculator,905,0,945,41]
private static final Pattern SYSUI_TRANSITION_INFO_PATTERN = Pattern.compile(
"^(?<date>[0-9-]*)\\s+(?<time>[0-9:.]*)\\s+\\d+\\s+\\d+ I sysui_multi_action:"
+ " \\[(?<transitioninfo>.*)\\]$");
// 08-21 17:53:53.876 1053 2135 I sysui_latency: [1,50]
private static final Pattern ACTION_LATENCY = Pattern.compile(
String.format("%s%s", EVENTS_PREFIX, "I sysui_latency: \\[(?<action>.*),"
+ "(?<delay>.*)\\]$"));
private static final Pattern ACTION_LATENCY = Pattern.compile("^(?<date>[0-9-]*)\\s+"
+ "(?<time>[0-9:.]*)\\s+\\d+\\s+\\d+ I sysui_latency: \\[(?<action>.*),"
+ "(?<delay>.*)\\]$");
private static final String DATE = "date";
private static final String TIME = "time";
private static final String TRANSITION_INFO = "transitioninfo";
private static final String PACKAGE_KEY = "806";
private static final String ACTIVITY_KEY = "871";
private static final String TRANSITION_DELAY_KEY = "319";
private static final String STARTING_WINDOW_DELAY_KEY = "321";
private static final String COLD_LAUNCH_KEY = "945";
private static final String WINDOWS_DRAWN_DELAY_KEY = "322";
@Override
public IItem parse(List<String> lines) {
......@@ -62,37 +63,66 @@ public class EventsLogParser implements IParser {
}
/**
* Method to parse the transition delay information from the events log
*
* Parse the transition delay information from the events log.
* @param input
* @return
* @return list of transition delay items.
* @throws IOException
*/
public List<TransitionDelayItem> parseTransitionDelayInfo(BufferedReader input)
throws IOException {
List<TransitionDelayItem> transitionDelayItems = new ArrayList<TransitionDelayItem>();
String line;
while ((line = input.readLine()) != null) {
Matcher match = null;
if (((match = matches(TRANSITION_STARTING_DELAY, line)) != null)) {
TransitionDelayItem delayItem = new TransitionDelayItem();
delayItem.setComponentName(match.group(4) + "/" + match.group(5));
delayItem.setTransitionDelay(Long.parseLong(match.group(1)));
delayItem.setStartingWindowDelay(Long.parseLong(match.group(2)));
transitionDelayItems.add(delayItem);
} else if (((match = matches(TRANSITION_DELAY, line)) != null)) {
while ((line = input.readLine()) != null) {
if ((match = matches(SYSUI_TRANSITION_INFO_PATTERN, line)) != null) {
Map<String, String> transitionInfoMap = getTransitionInfoMap(
match.group(TRANSITION_INFO));
if (transitionInfoMap.containsKey(TRANSITION_DELAY_KEY)) {
TransitionDelayItem delayItem = new TransitionDelayItem();
delayItem.setComponentName(match.group(3) + "/" + match.group(4));
delayItem.setTransitionDelay(Long.parseLong(match.group(1)));
if (null != transitionInfoMap.get(PACKAGE_KEY)
&& null != transitionInfoMap.get(ACTIVITY_KEY)
&& null != transitionInfoMap.get(TRANSITION_DELAY_KEY)
&& null != transitionInfoMap.get(WINDOWS_DRAWN_DELAY_KEY)) {
delayItem.setComponentName(transitionInfoMap.get(PACKAGE_KEY) + "/"
+ transitionInfoMap.get(ACTIVITY_KEY));
delayItem.setTransitionDelay(Long.parseLong(transitionInfoMap
.get(TRANSITION_DELAY_KEY)));
delayItem.setDateTime(String.format("%s %s", match.group(DATE),
match.group(TIME)));
delayItem.setWindowDrawnDelay(
Long.parseLong(transitionInfoMap.get(WINDOWS_DRAWN_DELAY_KEY)));
}
if (transitionInfoMap.containsKey(COLD_LAUNCH_KEY)) {
if (null != transitionInfoMap.get(STARTING_WINDOW_DELAY_KEY)) {
delayItem.setStartingWindowDelay(Long.parseLong(transitionInfoMap
.get(STARTING_WINDOW_DELAY_KEY)));
}
}
transitionDelayItems.add(delayItem);
}
}
}
return transitionDelayItems;
}
/**
* Split the transition info string in to key, values and return a map.
* @param transitionInfo transition info map in hey value format.
* @return
*/
public Map<String, String> getTransitionInfoMap(String transitionInfo) {
String[] transitionSplit = transitionInfo.split(",");
Map<String, String> transitionInfoMap = new HashMap<>();
if (transitionSplit.length % 2 == 0) {
for (int i = 0; i < transitionSplit.length; i = i + 2) {
transitionInfoMap.put(transitionSplit[i], transitionSplit[i + 1]);
}
}
return transitionInfoMap;
}
/**
* Method to parse the latency information from the events log
*
* @param input
* @return
* @throws IOException
......
......@@ -38,6 +38,18 @@ public class GfxInfoParser implements IParser {
private static final Pattern JANKY_FRAMES_PREFIX = Pattern.compile(
"Janky frames: (\\d+) \\(.+\\%\\)");
// Example: "90th percentile: 9ms"
private static final Pattern PERCENTILE_90_PREFIX =
Pattern.compile("90th percentile: (\\d+)ms");
// Example: "90th percentile: 14ms"
private static final Pattern PERCENTILE_95_PREFIX =
Pattern.compile("95th percentile: (\\d+)ms");
// Example: "90th percentile: 32ms"
private static final Pattern PERCENTILE_99_PREFIX =
Pattern.compile("99th percentile: (\\d+)ms");
/**
* Parses the log of "dumpsys gfxinfo".
* Currently it only parses total frame number and total jank number per process.
......@@ -51,6 +63,9 @@ public class GfxInfoParser implements IParser {
Integer pid = null;
Long totalFrames = null;
Long jankyFrames = null;
Integer percentile90 = null;
Integer percentile95 = null;
Integer percentile99 = null;
// gfxinfo also offers stats for specific views, but this parser
// only records per process data. See example in GfxInfoParserTest.java.
......@@ -64,6 +79,9 @@ public class GfxInfoParser implements IParser {
totalFrames = null;
jankyFrames = null;
percentile90 = null;
percentile95 = null;
percentile99 = null;
}
m = TOTAL_FRAMES_PREFIX.matcher(line);
......@@ -76,14 +94,45 @@ public class GfxInfoParser implements IParser {
jankyFrames = Long.parseLong(m.group(1));
}
if (name != null && pid != null && totalFrames != null && jankyFrames != null) {
m = PERCENTILE_90_PREFIX.matcher(line);
if (percentile90 == null && m.matches()) {
percentile90 = Integer.parseInt(m.group(1));
}
m = PERCENTILE_95_PREFIX.matcher(line);
if (percentile95 == null && m.matches()) {
percentile95 = Integer.parseInt(m.group(1));
}
m = PERCENTILE_99_PREFIX.matcher(line);
if (percentile99 == null && m.matches()) {
percentile99 = Integer.parseInt(m.group(1));
}
if (name != null
&& pid != null
&& totalFrames != null
&& jankyFrames != null
&& percentile90 != null
&& percentile95 != null
&& percentile99 != null) {
// All the data for the process is recorded, add as a row.
item.addRow(pid, name, totalFrames, jankyFrames);
item.addRow(
pid,
name,
totalFrames,
jankyFrames,
percentile90,
percentile95,
percentile99);
name = null;
pid = null;
totalFrames = null;
jankyFrames = null;
percentile90 = null;
percentile95 = null;
percentile99 = null;
}
}
......
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.parser;
import com.android.loganalysis.item.TraceFormatItem;
import com.google.common.base.CaseFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Read trace format and generate a regex that matches output of such format.
*
* <p>Traces under /d/tracing specify the output format with a printf string. This parser reads such
* string, finds all parameters, and generates a regex that matches output of such format. Each
* parameter corresponds to a named-capturing group in the regex. The parameter names are converted
* to camel case because Java regex group name must contain only letters and numbers.
*
* <p>An end-to-end example:
*
* <pre>{@code
* List<String> formatLine = Arrays.asList("print fmt: \"foo=%llu, bar:%s\", REC->foo, REC->bar");
* TraceFormatItem parsedFormat = new TraceFormatParser.parse(formatLine);
* parsedFormat.getParameters(); // "foo", "bar"
* parsedFormat.getNumericParameters(); // "foo"
* Matcher matcher = parsedFormat.getRegex.matcher("foo=123, bar:enabled");
* matcher.matches();
* matcher.group("foo") // 123
* matcher.group("bar") // "enabled"
* }</pre>
*
* <p>The initial implementation supports some commonly used specifiers: signed and unsigned integer
* (with or without long or long long modifier), floating point number (with or without precision),
* hexadecimal number (with or without 0's padding), and string (contains only [a-zA-Z_0-9]). It is
* assumed no characters found in the format line need to be escaped.
*
* <p>Some examples of trace format line:
*
* <p>(thermal/tsens_read)
*
* <p>print fmt: "temp=%lu sensor=tsens_tz_sensor%u", REC->temp, REC->sensor
*
* <p>(sched/sched_cpu_hotplug)
*
* <p>print fmt: "cpu %d %s error=%d", REC->affected_cpu, REC->status ? "online" : "offline",
* REC->error
*
* <p>(mmc/mmc_blk_erase_start)
*
* <p>print fmt: "cmd=%u,addr=0x%08x,size=0x%08x", REC->cmd, REC->addr, REC->size
*/
public class TraceFormatParser implements IParser {
// split the raw format line
private static final Pattern SPLIT_FORMAT_LINE =
Pattern.compile(".*?\"(?<printf>.*?)\"(?<params>.*)");
// match parameter names
private static final Pattern SPLIT_PARAMS = Pattern.compile("->(?<param>\\w+)");
// match and categorize common printf specifiers
// use ?: to flag all non-capturing group so any group captured correspond to a specifier
private static final Pattern PRINTF_SPECIFIERS =
Pattern.compile(
"(?<num>%(?:llu|lu|u|lld|ld|d|(?:.\\d*)?f))|(?<hex>%\\d*(?:x|X))|(?<str>%s)");
// regex building blocks to match simple numeric/hex/string parameters, exposed for unit testing
static final String MATCH_NUM = "-?\\\\d+(?:\\\\.\\\\d+)?";
static final String MATCH_HEX = "[\\\\da-fA-F]+";
static final String MATCH_STR = "[\\\\w]*";
/** Parse a trace format line and return an {@link TraceFormatItem} */
@Override
public TraceFormatItem parse(List<String> lines) {
// sanity check
if (lines == null || lines.size() != 1) {
throw new RuntimeException("Cannot parse format line: expect one-line trace format");
}
// split the raw format line
Matcher formatLineMatcher = SPLIT_FORMAT_LINE.matcher(lines.get(0));
if (!formatLineMatcher.matches()) {
throw new RuntimeException("Cannot parse format line: unexpected format");
}
String printfString = formatLineMatcher.group("printf");
String paramsString = formatLineMatcher.group("params");
// list of parameters, to be populated soon
List<String> allParams = new ArrayList<>();
List<String> numParams = new ArrayList<>();
List<String> hexParams = new ArrayList<>();
List<String> strParams = new ArrayList<>();
// find all parameters and convert them to camel case
Matcher paramsMatcher = SPLIT_PARAMS.matcher(paramsString);
while (paramsMatcher.find()) {
String camelCasedParam =
CaseFormat.LOWER_UNDERSCORE.to(
CaseFormat.LOWER_CAMEL, paramsMatcher.group("param"));
allParams.add(camelCasedParam);
}
// scan the printf string, categorizing parameters and generating a matching regex
StringBuffer regexBuilder = new StringBuffer();
int paramIndex = 0;
String currentParam;
Matcher printfMatcher = PRINTF_SPECIFIERS.matcher(printfString);
while (printfMatcher.find()) {
// parameter corresponds to the found specifier
currentParam = allParams.get(paramIndex++);
if (printfMatcher.group("num") != null) {
printfMatcher.appendReplacement(
regexBuilder, createNamedRegexGroup(MATCH_NUM, currentParam));
numParams.add(currentParam);
} else if (printfMatcher.group("hex") != null) {
printfMatcher.appendReplacement(
regexBuilder, createNamedRegexGroup(MATCH_HEX, currentParam));
hexParams.add(currentParam);
} else if (printfMatcher.group("str") != null) {
printfMatcher.appendReplacement(
regexBuilder, createNamedRegexGroup(MATCH_STR, currentParam));
strParams.add(currentParam);
} else {
throw new RuntimeException("Unrecognized specifier: " + printfMatcher.group());
}
}
printfMatcher.appendTail(regexBuilder);
Pattern generatedRegex = Pattern.compile(regexBuilder.toString());
// assemble and return a TraceFormatItem
TraceFormatItem item = new TraceFormatItem();
item.setRegex(generatedRegex);
item.setParameters(allParams);
item.setNumericParameters(numParams);
item.setHexParameters(hexParams);
item.setStringParameters(strParams);
return item;
}
/** Helper function to create a regex group with given name. */
private static String createNamedRegexGroup(String base, String name) {
return String.format("(?<%s>%s)", name, base);
}
}
......@@ -3,7 +3,7 @@
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/loganalysis"/>
<classpathentry kind="var" path="TRADEFED_ROOT/out/host/common/obj/JAVA_LIBRARIES/junit-host_intermediates/javalib.jar"/>
<classpathentry kind="var" path="TRADEFED_ROOT/external/easymock/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/>
</classpath>
......@@ -17,9 +17,12 @@
package com.android.loganalysis;
import com.android.loganalysis.item.BatteryDischargeItemTest;
import com.android.loganalysis.item.BatteryUsageItemTest;
import com.android.loganalysis.item.DumpsysPackageStatsItemTest;
import com.android.loganalysis.item.DvmLockSampleItemTest;
import com.android.loganalysis.item.GenericItemTest;
import com.android.loganalysis.item.InterruptItemTest;
import com.android.loganalysis.item.LocationDumpsItemTest;
import com.android.loganalysis.item.MemInfoItemTest;
import com.android.loganalysis.item.MonkeyLogItemTest;
import com.android.loganalysis.item.ProcrankItemTest;
......@@ -28,25 +31,48 @@ import com.android.loganalysis.item.SystemPropsItemTest;
import com.android.loganalysis.item.TopItemTest;
import com.android.loganalysis.item.WakelockItemTest;
import com.android.loganalysis.parser.AbstractSectionParserTest;
import com.android.loganalysis.parser.ActivityServiceParserTest;
import com.android.loganalysis.parser.AnrParserTest;
import com.android.loganalysis.parser.BatteryDischargeStatsInfoParserTest;
import com.android.loganalysis.parser.BatteryStatsDetailedInfoParserTest;
import com.android.loganalysis.parser.BatteryStatsSummaryInfoParserTest;
import com.android.loganalysis.parser.BatteryUsageParserTest;
import com.android.loganalysis.parser.BugreportParserTest;
import com.android.loganalysis.parser.CompactMemInfoParserTest;
import com.android.loganalysis.parser.CpuInfoParserTest;
import com.android.loganalysis.parser.DmesgParserTest;
import com.android.loganalysis.parser.DumpsysBatteryStatsParserTest;
import com.android.loganalysis.parser.DumpsysPackageStatsParserTest;
import com.android.loganalysis.parser.DumpsysParserTest;
import com.android.loganalysis.parser.DumpsysProcStatsParserTest;
import com.android.loganalysis.parser.DumpsysProcessMeminfoParserTest;
import com.android.loganalysis.parser.DumpsysWifiStatsParserTest;
import com.android.loganalysis.parser.DvmLockSampleParserTest;
import com.android.loganalysis.parser.EventsLogParserTest;
import com.android.loganalysis.parser.GfxInfoParserTest;
import com.android.loganalysis.parser.InterruptParserTest;
import com.android.loganalysis.parser.JavaCrashParserTest;
import com.android.loganalysis.parser.KernelLogParserTest;
import com.android.loganalysis.parser.LocationServiceParserTest;
import com.android.loganalysis.parser.LogcatParserTest;
import com.android.loganalysis.parser.MemHealthParserTest;
import com.android.loganalysis.parser.MemInfoParserTest;
import com.android.loganalysis.parser.MonkeyLogParserTest;
import com.android.loganalysis.parser.NativeCrashParserTest;
import com.android.loganalysis.parser.ProcessUsageParserTest;
import com.android.loganalysis.parser.ProcrankParserTest;
import com.android.loganalysis.parser.QtaguidParserTest;
import com.android.loganalysis.parser.SmartMonkeyLogParserTest;
import com.android.loganalysis.parser.SystemPropsParserTest;
import com.android.loganalysis.parser.TopParserTest;
import com.android.loganalysis.parser.TraceFormatParserTest;
import com.android.loganalysis.parser.TracesParserTest;
import com.android.loganalysis.parser.WakelockParserTest;
import com.android.loganalysis.rule.InterruptRuleTest;
import com.android.loganalysis.rule.LocationUsageRuleTest;
import com.android.loganalysis.rule.ProcessUsageRuleTest;
import com.android.loganalysis.rule.WakelockRuleTest;
import com.android.loganalysis.rule.WifiStatsRuleTest;
import com.android.loganalysis.util.ArrayUtilTest;
import com.android.loganalysis.util.LogPatternUtilTest;
import com.android.loganalysis.util.LogTailUtilTest;
......@@ -60,17 +86,21 @@ import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
* A test suite for all Trade Federation unit tests.
* <p/>
* All tests listed here should be self-contained, and should not require any external dependencies.
* A test suite for all log analysis unit tests.
*
* <p>All tests listed here should be self-contained, and should not require any external
* dependencies.
*/
@RunWith(Suite.class)
@SuiteClasses({
// item
BatteryDischargeItemTest.class,
BatteryUsageItemTest.class,
DumpsysPackageStatsItemTest.class,
DvmLockSampleItemTest.class,
GenericItemTest.class,
InterruptItemTest.class,
LocationDumpsItemTest.class,
MemInfoItemTest.class,
MonkeyLogItemTest.class,
ProcrankItemTest.class,
......@@ -79,25 +109,50 @@ import org.junit.runners.Suite.SuiteClasses;
TopItemTest.class,
WakelockItemTest.class,
// rule
InterruptRuleTest.class,
LocationUsageRuleTest.class,
ProcessUsageRuleTest.class,
WakelockRuleTest.class,
WifiStatsRuleTest.class,
// parser
AbstractSectionParserTest.class,
ActivityServiceParserTest.class,
AnrParserTest.class,
BatteryDischargeStatsInfoParserTest.class,
BatteryStatsDetailedInfoParserTest.class,
BatteryStatsSummaryInfoParserTest.class,
BatteryUsageParserTest.class,
BugreportParserTest.class,
CompactMemInfoParserTest.class,
CpuInfoParserTest.class,
DmesgParserTest.class,
EventsLogParserTest.class,
DumpsysBatteryStatsParserTest.class,
DumpsysPackageStatsParserTest.class,
DumpsysParserTest.class,
DumpsysProcessMeminfoParserTest.class,
DumpsysProcStatsParserTest.class,
DumpsysWifiStatsParserTest.class,
DvmLockSampleParserTest.class,
EventsLogParserTest.class,
GfxInfoParserTest.class,
InterruptParserTest.class,
JavaCrashParserTest.class,
KernelLogParserTest.class,
LocationServiceParserTest.class,
LogcatParserTest.class,
MemHealthParserTest.class,
MemInfoParserTest.class,
MonkeyLogParserTest.class,
NativeCrashParserTest.class,
ProcessUsageParserTest.class,
ProcrankParserTest.class,
QtaguidParserTest.class,
SmartMonkeyLogParserTest.class,
SystemPropsParserTest.class,
TopParserTest.class,
TraceFormatParserTest.class,
TracesParserTest.class,
WakelockParserTest.class,
......
......@@ -20,7 +20,9 @@ import com.android.loganalysis.item.BatteryStatsSummaryInfoItem;
import junit.framework.TestCase;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
/**
* Unit tests for {@link BatteryStatsSummaryInfoParser}
......@@ -83,8 +85,14 @@ public class BatteryStatsSummaryInfoParserTest extends TestCase {
assertEquals("The battery dropped a level 24 mins on average",
summary.getBatteryDischargeRate());
assertEquals("The peak discharge time was during Tue Dec 09 16:31:07 PST 2014 to "
+ "Tue Dec 09 19:35:52 PST 2014 where battery dropped from 89 to 80",
// Get the current timezone short name (PST, GMT) to properly output the time as expected.
String timezone =
new GregorianCalendar().getTimeZone().getDisplayName(false, TimeZone.SHORT);
assertEquals(
String.format(
"The peak discharge time was during Tue Dec 09 16:31:07 %s 2014 to "
+ "Tue Dec 09 19:35:52 %s 2014 where battery dropped from 89 to 80",
timezone, timezone),
summary.getPeakDischargeTime());
}
......
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.parser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.android.loganalysis.item.DumpsysProcessMeminfoItem;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
/** Unit tests for {@link DumpsysProcessMeminfoParser} */
public class DumpsysProcessMeminfoParserTest {
private static final String TEST_INPUT =
"time,28506638,177086152\n"
+ "4,938,system_server,11,22,N/A,44,0,0,N/A,0,0,0,N/A,0,27613,14013,176602,"
+ "218228,0,0,122860,122860,1512,1412,5740,8664,0,0,154924,154924,27568,"
+ "13972,11916,53456,0,0,123008,123008,0,0,0,0,0,0,0,0,Dalvik Other,3662,0,"
+ "104,0,3660,0,0,0,Stack,1576,0,8,0,1576,0,0,0,Cursor,0,0,0,0,0,0,0,0,"
+ "Ashmem,156,0,20,0,148,0,0,0,Gfx dev,100,0,48,0,76,0,0,0,Other dev,116,0,"
+ "164,0,0,96,0,0,.so mmap,7500,2680,3984,21864,904,2680,0,0,.jar mmap,0,0,0,"
+ "0,0,0,0,0,.apk mmap,72398,71448,0,11736,0,71448,0,0,.ttf mmap,0,0,0,0,0,0,"
+ "0,0,.dex mmap,76874,46000,0,83644,40,46000,0,0,.oat mmap,8127,2684,64,"
+ "26652,0,2684,0,0,.art mmap,1991,48,972,10004,1544,48,0,0,Other mmap,137,0,"
+ "44,1024,4,52,0,0,EGL mtrack,0,0,0,0,0,0,0,0,GL mtrack,111,222,333,444,555,"
+ "666,777,888,";
private static final String INVALID_TEST_INPUT = "RANDOM,TEST,DATA\n234235345345";
// Test that normal input is parsed
@Test
public void testDumpsysProcessMeminfoParser() {
List<String> inputBlock = Arrays.asList(TEST_INPUT.split("\n"));
DumpsysProcessMeminfoItem dump = new DumpsysProcessMeminfoParser().parse(inputBlock);
assertEquals(938, dump.getPid());
assertEquals("system_server", dump.getProcessName());
assertEquals(
Long.valueOf(11L),
dump.get(DumpsysProcessMeminfoItem.NATIVE).get(DumpsysProcessMeminfoItem.MAX));
assertEquals(
Long.valueOf(22L),
dump.get(DumpsysProcessMeminfoItem.DALVIK).get(DumpsysProcessMeminfoItem.MAX));
assertFalse(
dump.get(DumpsysProcessMeminfoItem.OTHER)
.containsKey(DumpsysProcessMeminfoItem.MAX));
assertEquals(
Long.valueOf(44L),
dump.get(DumpsysProcessMeminfoItem.TOTAL).get(DumpsysProcessMeminfoItem.MAX));
assertEquals(
Long.valueOf(218228L),
dump.get(DumpsysProcessMeminfoItem.TOTAL).get(DumpsysProcessMeminfoItem.PSS));
assertEquals(
Long.valueOf(3662L), dump.get("Dalvik Other").get(DumpsysProcessMeminfoItem.PSS));
assertEquals(Long.valueOf(111L), dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PSS));
assertEquals(
Long.valueOf(222L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPABLE_PSS));
assertEquals(
Long.valueOf(333L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SHARED_DIRTY));
assertEquals(
Long.valueOf(444L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SHARED_CLEAN));
assertEquals(
Long.valueOf(555L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PRIVATE_DIRTY));
assertEquals(
Long.valueOf(666L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.PRIVATE_CLEAN));
assertEquals(
Long.valueOf(777L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPED_OUT));
assertEquals(
Long.valueOf(888L),
dump.get("GL mtrack").get(DumpsysProcessMeminfoItem.SWAPPED_OUT_PSS));
}
// Test that the parser does not crash on invalid input and returns empty data
@Test
public void testDumpsysProcessMeminfoParserInvalid() {
List<String> inputBlock = Arrays.asList(INVALID_TEST_INPUT.split("\n"));
DumpsysProcessMeminfoItem dump = new DumpsysProcessMeminfoParser().parse(inputBlock);
assertNull(dump.getProcessName());
assertTrue(dump.get(DumpsysProcessMeminfoItem.TOTAL).isEmpty());
}
}
......@@ -73,43 +73,45 @@ public class EventsLogParserTest extends TestCase {
/**
* Test for Cold launch transition delay and starting window delay info
*/
public void testValidTransitionDelay() throws IOException {
public void testValidColdTransitionDelay() throws IOException {
List<String> lines = Arrays
.asList("01-02 08:12:10.849 934 986 I sysui_multi_action: [319,42,321,59,322,208,325,84100,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_trigger_nav_btn,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_source_app,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,804,799,overview_source_app_index,801,8,802,1]");
.asList("09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,904,com.google.android.apps.nexuslauncher,905,0,945,41]",
"09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0,945,41]");
List<TransitionDelayItem> transitionItems = (new EventsLogParser()).
parseTransitionDelayInfo(readInputBuffer(getTempFile(lines)));
assertEquals("Transition Delay items list should have one item", 1,
assertEquals("Startinng Window Delay items list should have two item", 2,
transitionItems.size());
assertEquals("Component name not parsed correctly",
"com.google.android.apps.maps/com.google.android.maps.MapsActivity",
"com.google.android.calculator/com.android.calculator2.Calculator",
transitionItems.get(0).getComponentName());
assertEquals("Transition delay is not parsed correctly", 42,
assertEquals("Transition delay is not parsed correctly", Long.valueOf(51),
transitionItems.get(0).getTransitionDelay());
assertEquals("Starting window delay is not parsed correctly", 59,
assertEquals("Starting window delay is not parsed correctly", Long.valueOf(50),
transitionItems.get(0).getStartingWindowDelay());
assertEquals("Date and time is not parsed correctly", "09-18 23:56:19.376",
transitionItems.get(0).getDateTime());
}
/**
* Test for only transition delay in hot launch
* Test for Hot launch transition delay and starting window delay info
*/
public void testOnlyTransitionDelay() throws IOException {
public void testValidHotTransitionDelay() throws IOException {
List<String> lines = Arrays
.asList("01-02 08:12:10.849 934 986 I sysui_multi_action: [319,42,322,208,325,84100,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_trigger_nav_btn,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_source_app,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,804,799,overview_source_app_index,801,8,802,1]");
.asList("09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,904,com.google.android.apps.nexuslauncher,905,0]",
"09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0]",
"09-19 02:26:30.182 1143 1196 I sysui_multi_action: [319,87,322,75,325,212,757,761,758,9,759,2,806,com.google.android.apps.nexuslauncher,871,com.google.android.apps.nexuslauncher.NexusLauncherActivity,904,com.google.android.apps.nexuslauncher,905,0]",
"09-19 02:26:30.182 1143 1196 I sysui_multi_action: [319,87,322,75,325,212,757,761,758,9,759,2,806,com.google.android.apps.nexuslauncher,871,com.google.android.apps.nexuslauncher.NexusLauncherActivity,905,0]");
List<TransitionDelayItem> transitionItems = (new EventsLogParser()).
parseTransitionDelayInfo(readInputBuffer(getTempFile(lines)));
assertEquals("Transition Delay items list should have one item", 1,
assertEquals("Transition Delay items list should have four item", 4,
transitionItems.size());
assertEquals("Component name not parsed correctly",
"com.google.android.apps.maps/com.google.android.maps.MapsActivity",
"com.google.android.calculator/com.android.calculator2.Calculator",
transitionItems.get(0).getComponentName());
assertEquals("Transition delay is not parsed correctly", 42,
assertEquals("Transition delay is not parsed correctly", Long.valueOf(51),
transitionItems.get(0).getTransitionDelay());
assertEquals("Date is not parsed correctly", "09-18 23:56:19.376",
transitionItems.get(0).getDateTime());
}
/**
......@@ -117,20 +119,16 @@ public class EventsLogParserTest extends TestCase {
*/
public void testTransitionDelayOrder() throws IOException {
List<String> lines = Arrays
.asList("01-02 08:12:10.849 934 986 I sysui_multi_action: [319,42,321,59,322,208,325,84100,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_trigger_nav_btn,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_source_app,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,804,799,overview_source_app_index,801,8,802,1]",
"01-02 08:12:42.187 934 986 I sysui_multi_action: [319,61,321,46,322,159,325,84131,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:42.450 1446 1446 I sysui_multi_action: [757,224,758,2]");
.asList("09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,59,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,904,com.google.android.apps.nexuslauncher,905,0,945,41]",
"09-18 23:59:18.380 1140 1221 I sysui_multi_action: [319,55,321,65,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0,945,41]");
List<TransitionDelayItem> transitionItems = (new EventsLogParser()).
parseTransitionDelayInfo(readInputBuffer(getTempFile(lines)));
assertEquals("Transition Delay items list should have two items", 2,
transitionItems.size());
assertEquals("Transition delay for the first item is not set correct", 42,
transitionItems.get(0).getTransitionDelay());
assertEquals("Transition delay for the second item is not set correct", 61,
transitionItems.get(1).getTransitionDelay());
assertEquals("Transition delay for the first item is not set correct", Long.valueOf(59),
transitionItems.get(0).getStartingWindowDelay());
assertEquals("Transition delay for the second item is not set correct", Long.valueOf(65),
transitionItems.get(1).getStartingWindowDelay());
}
/**
......@@ -138,12 +136,8 @@ public class EventsLogParserTest extends TestCase {
*/
public void testDifferentAppTransitionDelay() throws IOException {
List<String> lines = Arrays
.asList("01-02 08:11:58.691 934 986 I sysui_multi_action: [319,48,321,37,322,82,325,84088,757,761,758,9,759,4,806,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0]",
"01-02 08:12:03.639 934 970 I sysui_multi_action: [757,803,799,window_time_0,802,5]",
"01-02 08:12:10.849 934 986 I sysui_multi_action: [319,42,321,59,322,208,325,84100,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_trigger_nav_btn,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_source_app,802,1]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,804,799,overview_source_app_index,801,8,802,1]");
.asList("09-18 23:56:19.376 1140 1221 I sysui_multi_action: [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871,com.android.calculator2.Calculator,904,com.google.android.apps.nexuslauncher,905,0]",
"09-19 02:26:30.182 1143 1196 I sysui_multi_action: [319,87,322,75,325,212,757,761,758,9,759,2,806,com.google.android.apps.nexuslauncher,871,com.google.android.apps.nexuslauncher.NexusLauncherActivity,904,com.google.android.apps.nexuslauncher,905,0]");
List<TransitionDelayItem> transitionItems = (new EventsLogParser()).
parseTransitionDelayInfo(readInputBuffer(getTempFile(lines)));
assertEquals("Transition Delay items list should have two items", 2,
......@@ -152,7 +146,8 @@ public class EventsLogParserTest extends TestCase {
"com.google.android.calculator/com.android.calculator2.Calculator",
transitionItems.get(0).getComponentName());
assertEquals("Maps is not the second transition delay item",
"com.google.android.apps.maps/com.google.android.maps.MapsActivity",
"com.google.android.apps.nexuslauncher/"
+ "com.google.android.apps.nexuslauncher.NexusLauncherActivity",
transitionItems.get(1).getComponentName());
}
......@@ -161,7 +156,7 @@ public class EventsLogParserTest extends TestCase {
*/
public void testInvalidTransitionPattern() throws IOException {
List<String> lines = Arrays
.asList("01-02 08:11:58.691 934 986 I sysui_multi_action: [319,48,322,82,325,84088,757,761,758,9,759,4,807,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0]",
.asList("01-02 08:11:58.691 934 986 I sysui_multi_action: a[319,48,322,82,325,84088,757,761,758,9,759,4,807,com.google.android.calculator,871,com.android.calculator2.Calculator,905,0]",
"01-02 08:12:03.639 934 970 I sysui_multi_action: [757,803,799,window_time_0,802,5]",
"01-02 08:12:10.849 934 986 I sysui_multi_action: 319,42,321,59,322,208,325,84100,757,761,758,9,759,4,806,com.google.android.apps.maps,871,com.google.android.maps.MapsActivity,905,0]",
"01-02 08:12:16.895 1446 1446 I sysui_multi_action: [757,803,799,overview_trigger_nav_btn,802,1]",
......
......@@ -93,6 +93,9 @@ public class GfxInfoParserTest extends TestCase {
assertEquals("com.google.android.leanbacklauncher", item.getName(853));
assertEquals(20391, item.getTotalFrames(853));
assertEquals(785, item.getJankyFrames(853));
assertEquals(9, item.getPrecentile90(853));
assertEquals(14, item.getPrecentile95(853));
assertEquals(32, item.getPrecentile99(853));
}
/**
......@@ -285,12 +288,21 @@ public class GfxInfoParserTest extends TestCase {
assertEquals("com.google.android.leanbacklauncher", item.getName(844));
assertEquals(1690, item.getTotalFrames(844));
assertEquals(125, item.getJankyFrames(844));
assertEquals(13, item.getPrecentile90(844));
assertEquals(19, item.getPrecentile95(844));
assertEquals(48, item.getPrecentile99(844));
assertEquals("com.android.vending", item.getName(1881));
assertEquals(693, item.getTotalFrames(1881));
assertEquals(62, item.getJankyFrames(1881));
assertEquals(16, item.getPrecentile90(1881));
assertEquals(26, item.getPrecentile95(1881));
assertEquals(81, item.getPrecentile99(1881));
assertEquals("com.google.android.videos", item.getName(2931));
assertEquals(107, item.getTotalFrames(2931));
assertEquals(42, item.getJankyFrames(2931));
assertEquals(48, item.getPrecentile90(2931));
assertEquals(65, item.getPrecentile95(2931));
assertEquals(113, item.getPrecentile99(2931));
}
/**
......
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.loganalysis.parser;
import static org.junit.Assert.fail;
import com.android.loganalysis.item.TraceFormatItem;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
/** Test for {@link TraceFormatParser}. */
@RunWith(JUnit4.class)
public class TraceFormatParserTest {
private TraceFormatParser mParser;
// "unwrap" the regex strings so that we can compare with the generated regex
private static final String MATCH_NUM_UNESCAPED =
TraceFormatParser.MATCH_NUM.replaceAll("\\\\\\\\", "\\\\");
private static final String MATCH_HEX_UNESCAPED =
TraceFormatParser.MATCH_HEX.replaceAll("\\\\\\\\", "\\\\");
private static final String MATCH_STR_UNESCAPED =
TraceFormatParser.MATCH_STR.replaceAll("\\\\\\\\", "\\\\");
@Before
public void setUp() {
mParser = new TraceFormatParser();
}
@Test
public void testParseFormatLine() {
List<String> formatLine =
Arrays.asList("print fmt: \"foo=%llu, bar=%s\", REC->foo, REC->bar");
String expectedRegex =
String.format(
"foo=(?<foo>%s), bar=(?<bar>%s)", MATCH_NUM_UNESCAPED, MATCH_STR_UNESCAPED);
List<String> expectedParameters = Arrays.asList("foo", "bar");
List<String> expectedNumericParameters = Arrays.asList("foo");
List<String> expectedHexParameters = Arrays.asList();
List<String> expectedStringParameters = Arrays.asList("bar");
String shouldMatch = "foo=123, bar=enabled";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Assert.assertEquals(expectedParameters, parsedItem.getParameters());
Assert.assertEquals(expectedNumericParameters, parsedItem.getNumericParameters());
Assert.assertEquals(expectedHexParameters, parsedItem.getHexParameters());
Assert.assertEquals(expectedStringParameters, parsedItem.getStringParameters());
Assert.assertEquals(expectedRegex, parsedItem.getRegex().toString());
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "123");
Assert.assertEquals(m.group("bar"), "enabled");
}
@Test
public void testNoParameters() {
List<String> formatLine = Arrays.asList("print fmt: \"foo\"");
String expectedRegex = "foo";
List<String> expectedParameters = Arrays.asList();
String shouldMatch = "foo";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Assert.assertEquals(expectedParameters, parsedItem.getParameters());
Assert.assertEquals(expectedRegex, parsedItem.getRegex().toString());
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
}
@Test
public void testNullInput() {
try {
mParser.parse(null);
fail("Expected an exception thrown by TraceFormatParser");
} catch (RuntimeException e) {
// expected
}
}
@Test
public void testEmptyInput() {
List<String> formatLine = Arrays.asList("");
try {
mParser.parse(formatLine);
fail("Expected an exception thrown by TraceFormatParser");
} catch (RuntimeException e) {
// expected
}
}
@Test
public void testMultiLineInput() {
List<String> formatLine = Arrays.asList("foo", "bar");
try {
mParser.parse(formatLine);
fail("Expected an exception thrown by TraceFormatParser");
} catch (RuntimeException e) {
// expected
}
}
@Test
public void testOneLineInvalidInput() {
List<String> formatLine = Arrays.asList("foo bar");
try {
mParser.parse(formatLine);
fail("Expected an exception thrown by TraceFormatParser");
} catch (RuntimeException e) {
// expected
}
}
@Test
public void testQuoteInParams() {
List<String> formatLine =
Arrays.asList("print fmt: \"foo %s\", REC->foo ? \"online\" : \"offline\"");
String expectedRegex = String.format("foo (?<foo>%s)", MATCH_STR_UNESCAPED);
String shouldMatch = "foo online";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Assert.assertEquals(expectedRegex, parsedItem.getRegex().toString());
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "online");
}
@Test
public void testCategorizeParameters() {
List<String> formatLine =
Arrays.asList(
"print fmt: \"num1=%lu, num2=%f, hex=%08x, str=%s\", REC->num1, REC->num2, REC->hex, REC->str");
List<String> expectedNumericParameters = Arrays.asList("num1", "num2");
List<String> expectedHexParameters = Arrays.asList("hex");
List<String> expectedStringParameters = Arrays.asList("str");
TraceFormatItem parsedItem = mParser.parse(formatLine);
Assert.assertEquals(expectedNumericParameters, parsedItem.getNumericParameters());
Assert.assertEquals(expectedHexParameters, parsedItem.getHexParameters());
Assert.assertEquals(expectedStringParameters, parsedItem.getStringParameters());
}
@Test
public void testCaseConvertParameterName() {
List<String> formatLine = Arrays.asList("print fmt: \"foo_bar=%llu\", REC->foo_bar");
List<String> expectedParameters = Arrays.asList("fooBar");
String shouldMatch = "foo_bar=123";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Assert.assertEquals(expectedParameters, parsedItem.getParameters());
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("fooBar"), "123");
}
@Test
public void testMatchInt() {
List<String> formatLine =
Arrays.asList("print fmt: \"foo=%d, bar=%lu\", REC->foo, REC->bar");
String shouldMatch = "foo=-123, bar=456";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "-123");
Assert.assertEquals(m.group("bar"), "456");
}
@Test
public void testMatchFloat() {
List<String> formatLine =
Arrays.asList("print fmt: \"foo=%f, bar=%.2f\", REC->foo, REC->bar");
String shouldMatch = "foo=123.4567, bar=456.78";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "123.4567");
Assert.assertEquals(m.group("bar"), "456.78");
}
@Test
public void testMatchHex() {
List<String> formatLine =
Arrays.asList(
"print fmt: \"foo=0x%04x, bar=0x%08X, baz=%x\", REC->foo, REC->bar, REC->baz");
String shouldMatch = "foo=0x007b, bar=0x000001C8, baz=7b";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "007b");
Assert.assertEquals(m.group("bar"), "000001C8");
Assert.assertEquals(m.group("baz"), "7b");
}
@Test
public void testMatchString() {
List<String> formatLine =
Arrays.asList("print fmt: \"foo=%s, bar=%s\", REC->foo, REC->bar");
String shouldMatch = "foo=oof, bar=123";
TraceFormatItem parsedItem = mParser.parse(formatLine);
Matcher m = parsedItem.getRegex().matcher(shouldMatch);
Assert.assertTrue(m.matches());
Assert.assertEquals(m.group("foo"), "oof");
Assert.assertEquals(m.group("bar"), "123");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment