[tests] Measure .apk sizes and selected content (#791)
- extracted parts of `ProcessLogcatTiming` into new base class called `ProcessPlotInput` - we measure and process the apk sizes now to observe the changes and possible regressions on Jenkins CI - it is now possible to add results to cvs plot files, so we can merge values from multiple test runs. we do that with apk size values and we will do it with startup times in future
This commit is contained in:
Родитель
9ead8486d7
Коммит
fff81b0315
|
@ -151,6 +151,6 @@
|
|||
<_LogcatFilenameEnd>-logcat-$(Configuration)$(_AotName).txt</_LogcatFilenameEnd>
|
||||
</PropertyGroup>
|
||||
<Exec Command=""$(AdbToolPath)\$(AdbToolExe)" $(_AdbTarget) $(AdbOptions) logcat -v threadtime -d > %(UnitTestApk.Package)$(_LogcatFilenameEnd)" />
|
||||
<ProcessLogcatTiming LogcatFilename="%(UnitTestApk.Package)$(_LogcatFilenameEnd)" ApplicationPackageName="%(UnitTestApk.Package)" ResultsFilename="%(UnitTestApk.ResultsPath)" DefinitionsFilename="$(_DefinitionsFilename)" />
|
||||
<ProcessLogcatTiming InputFilename="%(UnitTestApk.Package)$(_LogcatFilenameEnd)" ApplicationPackageName="%(UnitTestApk.Package)" ResultsFilename="%(UnitTestApk.ResultsPath)" DefinitionsFilename="$(_DefinitionsFilename)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -8,53 +8,12 @@ using Microsoft.Build.Utilities;
|
|||
|
||||
namespace Xamarin.Android.BuildTools.PrepTasks
|
||||
{
|
||||
public class ProcessLogcatTiming : Task
|
||||
public class ProcessLogcatTiming : ProcessPlotInput
|
||||
{
|
||||
[Required]
|
||||
public string LogcatFilename { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ApplicationPackageName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string DefinitionsFilename { get; set; }
|
||||
|
||||
public string ResultsFilename { get; set; }
|
||||
|
||||
Dictionary<string, Regex> definedRegexs = new Dictionary<string, Regex> ();
|
||||
Dictionary<string, string> results = new Dictionary<string, string> ();
|
||||
|
||||
void LoadDefinitions ()
|
||||
{
|
||||
using (var reader = new StreamReader (DefinitionsFilename)) {
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine ()) != null) {
|
||||
if (line.StartsWith ("#", StringComparison.Ordinal))
|
||||
continue;
|
||||
int index = line.IndexOf ('=');
|
||||
if (index < 1 || index == line.Length)
|
||||
continue;
|
||||
var label = line.Substring (0, index);
|
||||
var pattern = line.Substring (index + 1);
|
||||
Regex regex;
|
||||
try {
|
||||
regex = new Regex (pattern);
|
||||
} catch (Exception e) {
|
||||
Log.LogWarning ($"unable to create regex for label: {label} from pattern: {pattern}\n{e}");
|
||||
continue;
|
||||
}
|
||||
if (definedRegexs.ContainsKey (label))
|
||||
Log.LogWarning ($"label '{label}' is defined multiple times. the last definition will be used");
|
||||
definedRegexs [label] = regex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
LoadDefinitions ();
|
||||
using (var reader = new StreamReader (LogcatFilename)) {
|
||||
using (var reader = new StreamReader (InputFilename)) {
|
||||
string line;
|
||||
int pid = -1;
|
||||
var procStartRegex = new Regex ($@"^(?<timestamp>\d+-\d+\s+[\d:\.]+)\s+.*ActivityManager: Start proc.*for added application {ApplicationPackageName}: pid=(?<pid>\d+)");
|
||||
|
@ -102,13 +61,7 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
Log.LogMessage (MessageImportance.Normal, " -- Performance summary --");
|
||||
Log.LogMessage (MessageImportance.Normal, $"Last timing message: {(last - start).TotalMilliseconds}ms");
|
||||
|
||||
if (ResultsFilename != null) {
|
||||
using (var resultsFile = new StreamWriter (Path.Combine (Path.GetDirectoryName (ResultsFilename), $"{Path.GetFileNameWithoutExtension (ResultsFilename)}-times.csv"))) {
|
||||
WriteValues (resultsFile, results.Keys);
|
||||
WriteValues (resultsFile, results.Values);
|
||||
resultsFile.Close ();
|
||||
}
|
||||
}
|
||||
WriteResults ("times");
|
||||
} else
|
||||
Log.LogWarning ("Wasn't able to collect the performance data");
|
||||
|
||||
|
@ -118,18 +71,6 @@ namespace Xamarin.Android.BuildTools.PrepTasks
|
|||
return true;
|
||||
}
|
||||
|
||||
void WriteValues (StreamWriter writer, ICollection<string> values)
|
||||
{
|
||||
bool first = true;
|
||||
foreach (var key in values) {
|
||||
if (!first)
|
||||
writer.Write (',');
|
||||
writer.Write (key);
|
||||
first = false;
|
||||
}
|
||||
writer.WriteLine ();
|
||||
}
|
||||
|
||||
static Regex timeRegex = new Regex (@"(?<month>\d+)-(?<day>\d+)\s+(?<hour>\d+):(?<minute>\d+):(?<second>\d+)\.(?<millisecond>\d+)");
|
||||
DateTime ParseTime (string s)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using Microsoft.Build.Framework;
|
||||
using Microsoft.Build.Utilities;
|
||||
|
||||
namespace Xamarin.Android.BuildTools.PrepTasks
|
||||
{
|
||||
public class ProcessPlotInput : Task
|
||||
{
|
||||
[Required]
|
||||
public string InputFilename { get; set; }
|
||||
|
||||
[Required]
|
||||
public string ApplicationPackageName { get; set; }
|
||||
|
||||
[Required]
|
||||
public string DefinitionsFilename { get; set; }
|
||||
|
||||
public string ResultsFilename { get; set; }
|
||||
|
||||
public bool AddResults { get; set; }
|
||||
|
||||
protected Dictionary<string, Regex> definedRegexs = new Dictionary<string, Regex> ();
|
||||
protected Dictionary<string, string> results = new Dictionary<string, string> ();
|
||||
|
||||
protected void LoadDefinitions ()
|
||||
{
|
||||
using (var reader = new StreamReader (DefinitionsFilename)) {
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine ()) != null) {
|
||||
if (line.StartsWith ("#", StringComparison.Ordinal))
|
||||
continue;
|
||||
int index = line.IndexOf ('=');
|
||||
if (index < 1 || index == line.Length)
|
||||
continue;
|
||||
var label = line.Substring (0, index);
|
||||
var pattern = line.Substring (index + 1);
|
||||
Regex regex;
|
||||
try {
|
||||
regex = new Regex (pattern);
|
||||
} catch (Exception e) {
|
||||
Log.LogWarning ($"unable to create regex for label: {label} from pattern: {pattern}\n{e}");
|
||||
continue;
|
||||
}
|
||||
if (definedRegexs.ContainsKey (label))
|
||||
Log.LogWarning ($"label '{label}' is defined multiple times. the last definition will be used");
|
||||
definedRegexs [label] = regex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Execute ()
|
||||
{
|
||||
LoadDefinitions ();
|
||||
using (var reader = new StreamReader (InputFilename)) {
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine ()) != null) {
|
||||
foreach (var regex in definedRegexs) {
|
||||
var definedMatch = regex.Value.Match (line);
|
||||
if (!definedMatch.Success)
|
||||
continue;
|
||||
string logMessage = definedMatch.Value;
|
||||
var v = definedMatch.Groups ["value"];
|
||||
if (!v.Success)
|
||||
continue;
|
||||
results [regex.Key] = v.Value;
|
||||
var m = definedMatch.Groups ["message"];
|
||||
if (m.Success)
|
||||
logMessage = m.Value;
|
||||
|
||||
Log.LogMessage (MessageImportance.Low, $"Message: {logMessage} Value: {v.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
WriteResults ("values");
|
||||
|
||||
reader.Close ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void WriteResults (string filenameEnd)
|
||||
{
|
||||
if (ResultsFilename != null) {
|
||||
string filename = Path.Combine (Path.GetDirectoryName (ResultsFilename), $"{Path.GetFileNameWithoutExtension (ResultsFilename)}-{filenameEnd}.csv");
|
||||
string line1 = null, line2 = null;
|
||||
if (AddResults && File.Exists (filename))
|
||||
using (var reader = new StreamReader (filename)) {
|
||||
try {
|
||||
line1 = reader.ReadLine ();
|
||||
line2 = reader.ReadLine ();
|
||||
} catch (Exception e) {
|
||||
Log.LogWarning ($"unable to read previous results from {filename}\n{e}");
|
||||
line1 = line2 = null;
|
||||
}
|
||||
}
|
||||
using (var resultsFile = new StreamWriter (filename)) {
|
||||
WriteValues (resultsFile, results.Keys, line1);
|
||||
WriteValues (resultsFile, results.Values, line2);
|
||||
resultsFile.Close ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteValues (StreamWriter writer, ICollection<string> values, string line)
|
||||
{
|
||||
bool first;
|
||||
if (string.IsNullOrEmpty (line))
|
||||
first = true;
|
||||
else {
|
||||
writer.Write (line);
|
||||
first = false;
|
||||
}
|
||||
foreach (var key in values) {
|
||||
if (!first)
|
||||
writer.Write (',');
|
||||
writer.Write (key);
|
||||
first = false;
|
||||
}
|
||||
writer.WriteLine ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,6 +53,7 @@
|
|||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\PrepareInstall.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\AcceptAndroidSdkLicenses.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\Sleep.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\ProcessPlotInput.cs" />
|
||||
<Compile Include="Xamarin.Android.BuildTools.PrepTasks\ProcessLogcatTiming.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\..\bin\Build$(Configuration)\xa-prep-tasks.dll" TaskName="Xamarin.Android.BuildTools.PrepTasks.ProcessPlotInput" />
|
||||
<PropertyGroup>
|
||||
<_MonoAndroidTestResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-$(Configuration)$(_AotName).xml</_MonoAndroidTestResultsPath>
|
||||
<_MonoAndroidTestPackage>Mono.Android_Tests</_MonoAndroidTestPackage>
|
||||
<_MonoAndroidTestApkFile>$(OutputPath)Mono.Android_Tests-Signed.apk</_MonoAndroidTestApkFile>
|
||||
<_MonoAndroidTestApkSizesInput>apk-sizes-$(_MonoAndroidTestPackage)-$(Configuration)$(_AotName).txt</_MonoAndroidTestApkSizesInput>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<UnitTestApk Include="$(OutputPath)Mono.Android_Tests-Signed.apk">
|
||||
<Package>Mono.Android_Tests</Package>
|
||||
<UnitTestApk Include="$(_MonoAndroidTestApkFile)">
|
||||
<Package>$(_MonoAndroidTestPackage)</Package>
|
||||
<InstrumentationType>xamarin.android.runtimetests.TestInstrumentation</InstrumentationType>
|
||||
<ResultsPath>$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-$(Configuration)$(_AotName).xml</ResultsPath>
|
||||
<ResultsPath>$(_MonoAndroidTestResultsPath)</ResultsPath>
|
||||
</UnitTestApk>
|
||||
</ItemGroup>
|
||||
<Target Name="_RecordApkSizes" AfterTargets="DeployUnitTestApks">
|
||||
<Delete Files="$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests-values.csv" Condition=" '$(Configuration)' == 'Debug' " />
|
||||
<Exec Command="stat -f "stat: %z %N" "$(_MonoAndroidTestApkFile)" > $(_MonoAndroidTestApkSizesInput)" />
|
||||
<Exec Command="unzip -l "$(_MonoAndroidTestApkFile)" >> $(_MonoAndroidTestApkSizesInput)" />
|
||||
<ProcessPlotInput InputFilename="$(_MonoAndroidTestApkSizesInput)" ApplicationPackageName="$(_MonoAndroidTestPackage)" ResultsFilename="$(MSBuildThisFileDirectory)..\..\..\TestResult-Mono.Android_Tests.xml" DefinitionsFilename="$(MSBuildThisFileDirectory)apk-sizes-definitions-$(Configuration)$(_AotName).txt" AddResults="true" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
apk-Debug=^stat: (?<value>\d+)\s+(?<message>.*)$
|
||||
Mono.Android.dll-Debug=^\s*(?<value>\d+)\s+.*(?<message>Mono.Android.dll)$
|
||||
mscorlib.dll-Debug=^\s*(?<value>\d+)\s+.*(?<message>mscorlib.dll)$
|
||||
monosgen-armeabi-v7a-Debug=^\s*(?<value>\d+)\s+.*(?<message>armeabi-v7a/libmonosgen-2.0.so)$
|
|
@ -0,0 +1,6 @@
|
|||
apk-Release-Aot=^stat: (?<value>\d+)\s+(?<message>.*)$
|
||||
Mono.Android.dll-Release-Aot=^\s*(?<value>\d+)\s+.*(?<message>Mono.Android.dll)$
|
||||
Mono.Android.dll.so-Release-Aot=^\s*(?<value>\d+)\s+.*(?<message>Mono.Android.dll.so)$
|
||||
mscorlib.dll-Release-Aot=^\s*(?<value>\d+)\s+.*(?<message>mscorlib.dll)$
|
||||
mscorlib.dll.so-Release-Aot=^\s*(?<value>\d+)\s+.*(?<message>mscorlib.dll.so)$
|
||||
monosgen-armeabi-v7a-Release-Aot=^\s*(?<value>\d+)\s+.*(?<message>armeabi-v7a/libmonosgen-2.0.so)$
|
|
@ -0,0 +1,4 @@
|
|||
apk-Release=^stat: (?<value>\d+)\s+(?<message>.*)$
|
||||
Mono.Android.dll-Release=^\s*(?<value>\d+)\s+.*(?<message>Mono.Android.dll)$
|
||||
mscorlib.dll-Release=^\s*(?<value>\d+)\s+.*(?<message>mscorlib.dll)$
|
||||
monosgen-armeabi-v7a-Release=^\s*(?<value>\d+)\s+.*(?<message>armeabi-v7a/libmonosgen-2.0.so)$
|
Загрузка…
Ссылка в новой задаче