Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] use typemaps when EmbedAssembliesIntoAp…
Browse files Browse the repository at this point in the history
…k=False

This is a first step to use the `typemap.mj` and `typemap.jm` files
for Fast Deployment. We will eventually generate these files on a
per-assembly basis, but can get some small perf improvements for
`Debug` builds:

* When `$(EmbedAssembliesIntoApk)` is `True` use the native assembly
  in `typemap.*.inc` and the current behavior.
* When `$(EmbedAssembliesIntoApk)` is `False` don't generate any
  `typemap.*.inc` files at all, but still use the native assembly for
  environment variables.
* We have to still generate `typemap.*.s` files with empty values.

~~ typemap.*.s changes ~~

Before:

  jm_typemap_header:
    /* version */
    .long	1
    /* entry-count */
    .long	1324
    /* entry-length */
    .long	262
    /* value-offset */
    .long	117
    .size	jm_typemap_header, 16

    /* Mapping data */
    .type	jm_typemap, %object
    .global	jm_typemap
  jm_typemap:
    .size	jm_typemap, 346889
    .include	"typemap.jm.inc"

After:

  jm_typemap_header:
    /* version */
    .long	1
    /* entry-count */
    .long	0
    /* entry-length */
    .long	0
    /* value-offset */
    .long	0
    .size	jm_typemap_header, 16

    /* Mapping data */
    .type	jm_typemap, %object
    .global	jm_typemap
  jm_typemap:
    .size	jm_typemap, 0

The result is I don't get a crash at runtime and the `typemap.mj` and
`typemap.jm` files are used.

~~ Results ~~

I timed the Xamarin.Forms integration project in this repo.

An initial build:

    Before:
    2860 ms  GenerateJavaStubs                          1 calls
      84 ms  CompileNativeAssembly                      1 calls
    After:
    2595 ms  GenerateJavaStubs                          1 calls
      46 ms  CompileNativeAssembly                      1 calls

On an incremental build where `MainActivity.cs` was changed:

    Before:
     543 ms  GenerateJavaStubs                          1 calls
    After:
     323 ms  GenerateJavaStubs                          1 calls

`CompileNativeAssembly` is skipped for `MainActivity.cs` changes.

When comparing startup performance:

    Before:
    ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +1s302ms
    After:
    ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +1s341ms

As expected, startup is ~50ms worse.

I would say this change saves ~250ms on the full dev-loop in cases
where `<GenerateJavaStubs/>` needs to run.
  • Loading branch information
jonathanpeppers committed Sep 25, 2019
1 parent 7a043ab commit 029d0c1
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .external
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
xamarin/monodroid:master@623845d44abe5eb7a76d9a63d48b30a27ac1bac2
jonathanpeppers/monodroid:bring-back-typemaps@f0772b0ac618e4d508d061201b803dffe2607872
mono/mono:2019-08@6d40f13121e42e41a50b9f2c5eb84983552f0d50
13 changes: 9 additions & 4 deletions src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,17 +325,21 @@ TypeNameMapGenerator createTypeMapGenerator () => UseSharedRuntime ?

void UpdateWhenChanged (string path, string type, MemoryStream ms, Action<Stream> generator)
{
if (InstantRunEnabled) {
if (!EmbedAssemblies) {
ms.SetLength (0);
generator (ms);
MonoAndroidHelper.CopyIfStreamChanged (ms, path);
}

string dataFilePath = $"{path}.inc";
using (var stream = new NativeAssemblyDataStream ()) {
generator (stream);
stream.EndOfFile ();
MonoAndroidHelper.CopyIfStreamChanged (stream, dataFilePath);
if (EmbedAssemblies) {
generator (stream);
stream.EndOfFile ();
MonoAndroidHelper.CopyIfStreamChanged (stream, dataFilePath);
} else {
stream.EmptyFile ();
}

var generatedFiles = new List <ITaskItem> ();
string mappingFieldName = $"{type}_typemap";
Expand Down Expand Up @@ -366,6 +370,7 @@ void UpdateWhenChanged (string path, string type, MemoryStream ms, Action<Stream
}

var asmgen = new TypeMappingNativeAssemblyGenerator (asmTargetProvider, stream, dataFileName, stream.MapByteCount, mappingFieldName);
asmgen.EmbedAssemblies = EmbedAssemblies;
string asmFileName = $"{path}.{abi.Trim ()}.s";
using (var sw = new StreamWriter (ms, utf8Encoding, bufferSize: 8192, leaveOpen: true)) {
asmgen.Write (sw, dataFileName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ public void EndOfFile ()
Flush ();
}

public void EmptyFile ()
{
MapVersion = 1;
MapEntryCount = 0;
MapEntryLength = 0;
MapValueOffset = 0;
}

public override void Flush ()
{
outputWriter.Flush ();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public TypeMappingNativeAssemblyGenerator (NativeAssemblerTargetProvider targetP
this.mappingFieldName = mappingFieldName;
}

public bool EmbedAssemblies { get; set; }

protected override void WriteFileHeader (StreamWriter output, string outputFileName)
{
// The hash is written to make sure the assembly file which includes the data one is
Expand All @@ -43,7 +45,9 @@ protected override void WriteSymbols (StreamWriter output)
WriteMappingHeader (output, dataStream, mappingFieldName);
WriteCommentLine (output, "Mapping data");
WriteSymbol (output, mappingFieldName, dataSize, isGlobal: true, isObject: true, alwaysWriteSize: true);
output.WriteLine ($"{Indent}.include{Indent}\"{dataFileName}\"");
if (EmbedAssemblies) {
output.WriteLine ($"{Indent}.include{Indent}\"{dataFileName}\"");
}
}

void WriteMappingHeader (StreamWriter output, NativeAssemblyDataStream dataStream, string mappingFieldName)
Expand Down

0 comments on commit 029d0c1

Please sign in to comment.