Skip to content

Commit 091da6d

Browse files
[JavaCallableWrappers] Parallel.ForEach per assembly
Since we are looking at every type in each assembly, we can parallelize this work to make things a bit faster. However, there are a few concerns when doing this: - Made sure to add a *new* method `GetJavaTypesInParallel` so the caller can opt-in to this - The `cache` in `DirectoryAssemblyResolver` needs to now be a `ConcurrentDictionary` - The list of `javaTypes` returned by `JavaTypeScanner` needs to also use a `BlockingCollection` - Downstream in `xamarin-android`, we need to make sure `GenerateJavaStubs` is now an `AsyncTask`, so the "thread safe" logger methods are used. To time the improvements, I used this project in Xamarin.Forms: https://github.com/xamarin/Xamarin.Forms/tree/master/Xamarin.Forms.ControlGallery.Android Before I did anything, the times were: 2594 ms GenerateJavaStubs 2 calls After making things parallel: 2143 ms GenerateJavaStubs 2 calls And then after a few more LINQ improvements in the `GenerateJavaStubs` MSBuild task: 2104 ms GenerateJavaStubs 2 calls So we have close to a 500ms improvement for `GenerateJavaStubs` in this project, that will build a library project + application project. To see the full changes required downstream in `xamarin-android`: dotnet/android@master...jonathanpeppers:generatejavastubs-perf
1 parent 659711c commit 091da6d

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/DirectoryAssemblyResolver.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
using System;
3131
using System.Diagnostics;
32-
using System.Collections;
32+
using System.Collections.Concurrent;
3333
using System.Collections.Generic;
3434
using System.IO;
3535
using System.Linq;
@@ -61,7 +61,7 @@ public class DirectoryAssemblyResolver : IAssemblyResolver {
6161

6262
public ICollection<string> SearchDirectories {get; private set;}
6363

64-
Dictionary<string, AssemblyDefinition> cache;
64+
ConcurrentDictionary<string, AssemblyDefinition> cache;
6565
bool loadDebugSymbols;
6666
Action<TraceLevel, string> logger;
6767

@@ -82,7 +82,7 @@ public DirectoryAssemblyResolver (Action<TraceLevel, string> logger, bool loadDe
8282
{
8383
if (logger == null)
8484
throw new ArgumentNullException (nameof (logger));
85-
cache = new Dictionary<string, AssemblyDefinition> ();
85+
cache = new ConcurrentDictionary<string, AssemblyDefinition> ();
8686
this.loadDebugSymbols = loadDebugSymbols;
8787
this.logger = logger;
8888
SearchDirectories = new List<string> ();

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaTypeScanner.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using System;
2+
using System.Collections.Concurrent;
23
using System.Collections.Generic;
34
using System.Diagnostics;
45
using System.Linq;
5-
using System.Text;
6+
using System.Threading.Tasks;
67
using Mono.Cecil;
78

89
using Java.Interop.Tools.Cecil;
9-
using Java.Interop.Tools.Diagnostics;
1010
using Java.Interop.Tools.TypeNameMappings;
1111

1212
namespace Java.Interop.Tools.JavaCallableWrappers
@@ -29,23 +29,38 @@ public List<TypeDefinition> GetJavaTypes (IEnumerable<string> assemblies, IAssem
2929

3030
foreach (var assembly in assemblies) {
3131
var assm = resolver.GetAssembly (assembly);
32-
3332
foreach (ModuleDefinition md in assm.Modules) {
3433
foreach (TypeDefinition td in md.Types) {
35-
AddJavaTypes (javaTypes, td);
34+
AddJavaTypes (javaTypes.Add, td);
3635
}
3736
}
3837
}
3938

4039
return javaTypes;
4140
}
4241

43-
void AddJavaTypes (List<TypeDefinition> javaTypes, TypeDefinition type)
42+
public List<TypeDefinition> GetJavaTypesInParallel (IEnumerable<string> assemblies, IAssemblyResolver resolver)
43+
{
44+
var javaTypes = new BlockingCollection<TypeDefinition> ();
45+
46+
Parallel.ForEach (assemblies, assembly => {
47+
var assm = resolver.GetAssembly (assembly);
48+
foreach (ModuleDefinition md in assm.Modules) {
49+
foreach (TypeDefinition td in md.Types) {
50+
AddJavaTypes (javaTypes.Add, td);
51+
}
52+
}
53+
});
54+
55+
return javaTypes.ToList ();
56+
}
57+
58+
void AddJavaTypes (Action<TypeDefinition> addMethod, TypeDefinition type)
4459
{
4560
if (type.IsSubclassOf ("Java.Lang.Object") || type.IsSubclassOf ("Java.Lang.Throwable")) {
4661

4762
// For subclasses of e.g. Android.App.Activity.
48-
javaTypes.Add (type);
63+
addMethod (type);
4964
} else if (type.IsClass && !type.IsSubclassOf ("System.Exception") && type.ImplementsInterface ("Android.Runtime.IJavaObject")) {
5065
var level = ErrorOnCustomJavaObject ? TraceLevel.Error : TraceLevel.Warning;
5166
var prefix = ErrorOnCustomJavaObject ? "error" : "warning";
@@ -59,7 +74,7 @@ void AddJavaTypes (List<TypeDefinition> javaTypes, TypeDefinition type)
5974
return;
6075

6176
foreach (TypeDefinition nested in type.NestedTypes)
62-
AddJavaTypes (javaTypes, nested);
77+
AddJavaTypes (addMethod, nested);
6378
}
6479

6580
public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type)

0 commit comments

Comments
 (0)