-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add android meminfo inspector and parser (#320)
* feat: add android meminfo inspector and parser * feat: deal with default value
- Loading branch information
Showing
5 changed files
with
248 additions
and
3 deletions.
There are no files selected for viewing
47 changes: 47 additions & 0 deletions
47
common/src/main/java/com/microsoft/hydralab/performance/Entity/AndroidMemoryInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.microsoft.hydralab.performance.Entity; | ||
|
||
import lombok.Data; | ||
|
||
import java.io.Serializable; | ||
|
||
@Data | ||
public class AndroidMemoryInfo implements Serializable { | ||
private String appPackageName; | ||
private long timeStamp; | ||
private String description; | ||
/** | ||
* Index mapping is shown as below: | ||
* <p> | ||
* 0: Java Heap PSS; 1. Java Heap RSS; | ||
* 2. Native Heap PSS; 3. Native Heap RSS; | ||
* 4. Code PSS; 5. Code RSS; | ||
* 6. Stack PSS; 7. Stack RSS; | ||
* 8. Graphics PSS; 9. Graphics RSS; | ||
* 10. Private Other PSS; 11. Private Other RSS; | ||
* 12. System PSS; 13. System RSS; | ||
* 14. Unknown PSS; 15. Unknown RSS; | ||
* 16. TOTAL PSS; 17. TOTAL RSS; 18. TOTAL SWAP PSS; | ||
* <p> | ||
* Since blanks exist in memory summary, some data may not be fetched, default value 0 is then applied. | ||
*/ | ||
private long javaHeapPss; | ||
private long javaHeapRss; | ||
private long nativeHeapPss; | ||
private long nativeHeapRss; | ||
private long codePss; | ||
private long codeRss; | ||
private long stackPss; | ||
private long stackRss; | ||
private long graphicsPss; | ||
private long graphicsRss; | ||
private long privateOtherPss; | ||
private long privateOtherRss; | ||
private long systemPss; | ||
private long systemRss; | ||
private long unknownPss; | ||
private long unknownRss; | ||
private long totalPss; | ||
private long totalRss; | ||
private long totalSwapPss; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...c/main/java/com/microsoft/hydralab/performance/inspectors/AndroidMemoryInfoInspector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.microsoft.hydralab.performance.inspectors; | ||
|
||
import com.microsoft.hydralab.common.util.ShellUtils; | ||
import com.microsoft.hydralab.common.util.TimeUtils; | ||
import com.microsoft.hydralab.performance.PerformanceInspection; | ||
import com.microsoft.hydralab.performance.PerformanceInspectionResult; | ||
import com.microsoft.hydralab.performance.PerformanceInspector; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.util.Assert; | ||
|
||
import java.io.File; | ||
|
||
public class AndroidMemoryInfoInspector implements PerformanceInspector { | ||
|
||
private static final String RAW_RESULT_FILE_NAME_FORMAT = "%s_%s_%s_memory.txt"; | ||
private final Logger classLogger = LoggerFactory.getLogger(getClass()); | ||
|
||
|
||
@Override | ||
public PerformanceInspectionResult inspect(PerformanceInspection performanceInspection) { | ||
|
||
File rawResultFolder = new File(performanceInspection.resultFolder, performanceInspection.appId); | ||
Assert.isTrue(rawResultFolder.exists() || rawResultFolder.mkdir(), "rawResultFolder.mkdirs() failed in" + rawResultFolder.getAbsolutePath()); | ||
File rawResultFile = new File(rawResultFolder, | ||
String.format(RAW_RESULT_FILE_NAME_FORMAT, getClass().getSimpleName(), performanceInspection.appId, TimeUtils.getTimestampForFilename())); | ||
|
||
ShellUtils.execLocalCommandWithResult(String.format(getMemInfoCommand(), | ||
performanceInspection.deviceIdentifier, performanceInspection.appId, rawResultFile.getAbsolutePath()), classLogger); | ||
return new PerformanceInspectionResult(rawResultFile, performanceInspection); | ||
} | ||
|
||
private String getMemInfoCommand() { | ||
String format; | ||
if (ShellUtils.isConnectedToWindowsOS) { | ||
format = "adb -s %s shell dumpsys meminfo %s | out-file %s -encoding utf8"; | ||
} else { | ||
format = "adb -s %s shell dumpsys meminfo %s > %s"; | ||
} | ||
return format; | ||
} | ||
} |
146 changes: 146 additions & 0 deletions
146
...c/main/java/com/microsoft/hydralab/performance/parsers/AndroidMemoryInfoResultParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package com.microsoft.hydralab.performance.parsers; | ||
|
||
import com.google.common.base.Strings; | ||
import com.microsoft.hydralab.performance.Entity.AndroidMemoryInfo; | ||
import com.microsoft.hydralab.performance.PerformanceInspectionResult; | ||
import com.microsoft.hydralab.performance.PerformanceResultParser; | ||
import com.microsoft.hydralab.performance.PerformanceTestResult; | ||
import org.apache.commons.lang3.math.NumberUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.File; | ||
import java.io.FileReader; | ||
import java.io.IOException; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
public class AndroidMemoryInfoResultParser implements PerformanceResultParser { | ||
private final Logger logger = LoggerFactory.getLogger(getClass()); | ||
private static final Map<String, Integer> MEMORY_FILE_TO_DB_INDEX_MAP = new HashMap<>() { | ||
{ | ||
put("Java Heap", 0); | ||
put("Native Heap", 1); | ||
put("Code", 2); | ||
put("Stack", 3); | ||
put("Graphics", 4); | ||
put("Private Other", 5); | ||
put("System", 6); | ||
put("Unknown", 7); | ||
} | ||
}; | ||
|
||
@Override | ||
public PerformanceTestResult parse(PerformanceTestResult performanceTestResult) { | ||
if (performanceTestResult == null || performanceTestResult.performanceInspectionResults == null | ||
|| performanceTestResult.performanceInspectionResults.isEmpty()) { | ||
return null; | ||
} | ||
List<PerformanceInspectionResult> inspectionResults = performanceTestResult.performanceInspectionResults; | ||
for (PerformanceInspectionResult inspectionResult : inspectionResults) { | ||
File logFile = inspectionResult.rawResultFile; | ||
long[] memInfos = parseRawResultFile(logFile); | ||
inspectionResult.parsedData = buildMemoryInfo(inspectionResult.inspection.appId, inspectionResult.inspection.description, inspectionResult.timestamp, memInfos); | ||
} | ||
|
||
return performanceTestResult; | ||
} | ||
|
||
|
||
private AndroidMemoryInfo buildMemoryInfo(String packageName, String description, long timestamp, long[] memInfos) { | ||
if (memInfos == null || memInfos.length != 19) { | ||
return null; | ||
} | ||
AndroidMemoryInfo androidMemoryInfo = new AndroidMemoryInfo(); | ||
androidMemoryInfo.setAppPackageName(packageName); | ||
androidMemoryInfo.setDescription(description); | ||
androidMemoryInfo.setTimeStamp(timestamp); | ||
androidMemoryInfo.setJavaHeapPss(memInfos[0]); | ||
androidMemoryInfo.setJavaHeapRss(memInfos[1]); | ||
androidMemoryInfo.setNativeHeapPss(memInfos[2]); | ||
androidMemoryInfo.setNativeHeapRss(memInfos[3]); | ||
androidMemoryInfo.setCodePss(memInfos[4]); | ||
androidMemoryInfo.setCodeRss(memInfos[5]); | ||
androidMemoryInfo.setStackPss(memInfos[6]); | ||
androidMemoryInfo.setStackRss(memInfos[7]); | ||
androidMemoryInfo.setGraphicsPss(memInfos[8]); | ||
androidMemoryInfo.setGraphicsRss(memInfos[9]); | ||
androidMemoryInfo.setPrivateOtherPss(memInfos[10]); | ||
androidMemoryInfo.setPrivateOtherRss(memInfos[11]); | ||
androidMemoryInfo.setSystemPss(memInfos[12]); | ||
androidMemoryInfo.setSystemRss(memInfos[13]); | ||
androidMemoryInfo.setUnknownPss(memInfos[14]); | ||
androidMemoryInfo.setUnknownRss(memInfos[15]); | ||
androidMemoryInfo.setTotalPss(memInfos[16]); | ||
androidMemoryInfo.setTotalRss(memInfos[17]); | ||
androidMemoryInfo.setTotalSwapPss(memInfos[18]); | ||
return androidMemoryInfo; | ||
} | ||
|
||
private long[] parseRawResultFile(File rawFile) { | ||
String line; | ||
long[] memoryValueArr = new long[19]; | ||
Arrays.fill(memoryValueArr, -1); | ||
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(rawFile))) { | ||
while ((line = bufferedReader.readLine()) != null) { | ||
if (line.trim().startsWith("App Summary")) { | ||
// PSS title line, used to anchor target index offset | ||
line = bufferedReader.readLine(); | ||
int pssEndOffset = line.indexOf(")"); | ||
int rssEndOffset = line.lastIndexOf(")"); | ||
|
||
// move to data line | ||
bufferedReader.readLine(); | ||
line = bufferedReader.readLine(); | ||
while (line != null) { | ||
String lineStr = line.trim(); | ||
|
||
if (lineStr.startsWith("TOTAL ")) { | ||
if (line.contains("TOTAL PSS:")) { | ||
String pssValue = line.split("TOTAL PSS:")[1].split(" +")[1]; | ||
memoryValueArr[16] = NumberUtils.toLong(pssValue, -1); | ||
} | ||
if (line.contains("TOTAL RSS:")) { | ||
String rssValue = line.split("TOTAL RSS:")[1].split(" +")[1]; | ||
memoryValueArr[17] = NumberUtils.toLong(rssValue, -1); | ||
} | ||
if (line.contains("TOTAL SWAP PSS:")) { | ||
memoryValueArr[18] = NumberUtils.toLong(line.split("TOTAL SWAP PSS:")[1].split(" +")[1], -1); | ||
} | ||
break; | ||
} else if (!Strings.isNullOrEmpty(lineStr)) { | ||
String[] keyValue = lineStr.split(":"); | ||
String key = keyValue[0]; | ||
String values = keyValue[1]; | ||
|
||
// int in map to calculate offset in memoryValueArr array (typeIndex * 2 +0/+1 (implies PSS/RSS correspondingly)) | ||
int typeIndex = MEMORY_FILE_TO_DB_INDEX_MAP.get(key); | ||
|
||
// for current memory type, PSS data exists | ||
if (line.charAt(pssEndOffset) != ' ') { | ||
memoryValueArr[typeIndex * 2] = NumberUtils.toLong(values.split(" +")[1]); | ||
|
||
// for current memory type, RSS data exists | ||
if (line.length() > rssEndOffset && line.charAt(rssEndOffset) != ' ') { | ||
memoryValueArr[typeIndex * 2 + 1] = NumberUtils.toLong(values.split(" +")[2]); | ||
} | ||
} else if (line.length() > rssEndOffset && line.charAt(rssEndOffset) != ' ') { | ||
// for current memory type PSS data doesn't exist and RSS data exists | ||
memoryValueArr[typeIndex * 2 + 1] = NumberUtils.toLong(values.split(" +")[1]); | ||
} | ||
} | ||
|
||
line = bufferedReader.readLine(); | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
logger.error(e.getMessage(), e); | ||
return null; | ||
} | ||
return memoryValueArr; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters