Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -61,7 +61,7 @@ public class DirectoryAssemblyResolver : IAssemblyResolver {

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

Dictionary<string, AssemblyDefinition> cache;
ConcurrentDictionary<string, AssemblyDefinition> cache;
bool loadDebugSymbols;
Action<TraceLevel, string> logger;

Expand All @@ -82,7 +82,7 @@ public DirectoryAssemblyResolver (Action<TraceLevel, string> logger, bool loadDe
{
if (logger == null)
throw new ArgumentNullException (nameof (logger));
cache = new Dictionary<string, AssemblyDefinition> ();
cache = new ConcurrentDictionary<string, AssemblyDefinition> ();
this.loadDebugSymbols = loadDebugSymbols;
this.logger = logger;
SearchDirectories = new List<string> ();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Mono.Cecil;

using Java.Interop.Tools.Cecil;
using Java.Interop.Tools.Diagnostics;
using Java.Interop.Tools.TypeNameMappings;

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

foreach (var assembly in assemblies) {
var assm = resolver.GetAssembly (assembly);

foreach (ModuleDefinition md in assm.Modules) {
foreach (TypeDefinition td in md.Types) {
AddJavaTypes (javaTypes, td);
AddJavaTypes (javaTypes.Add, td);
}
}
}

return javaTypes;
}

void AddJavaTypes (List<TypeDefinition> javaTypes, TypeDefinition type)
public List<TypeDefinition> GetJavaTypesInParallel (IEnumerable<string> assemblies, IAssemblyResolver resolver)
{
var javaTypes = new BlockingCollection<TypeDefinition> ();

Parallel.ForEach (assemblies, assembly => {
var assm = resolver.GetAssembly (assembly);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. Nopity nopity not going to do it NOPE.

Cecil isn't thread safe. This cannot work. See also: b1667a2.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm b1667a2, looks like it is parallelizing on the TypeDefinition and this is doing a Task per AssemblyDefinition.

Let me try writing a test like you have here, and see what happens.

foreach (ModuleDefinition md in assm.Modules) {
foreach (TypeDefinition td in md.Types) {
AddJavaTypes (javaTypes.Add, td);
}
}
});

return javaTypes.ToList ();
}

void AddJavaTypes (Action<TypeDefinition> addMethod, TypeDefinition type)
{
if (type.IsSubclassOf ("Java.Lang.Object") || type.IsSubclassOf ("Java.Lang.Throwable")) {

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

foreach (TypeDefinition nested in type.NestedTypes)
AddJavaTypes (javaTypes, nested);
AddJavaTypes (addMethod, nested);
}

public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type)
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
<HintPath>..\..\..\packages\NUnit.3.7.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
</ItemGroup>
<ItemGroup>
<Compile Include="Java.Interop.Tools.JavaCallableWrappers\JavaCallableWrapperGeneratorTests.cs" />
Expand All @@ -47,6 +49,9 @@
<Compile Include="Android.Content\ContentProviderAttribute.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Data\Assemblies.zip">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;

Expand All @@ -13,6 +16,7 @@
using Java.Interop.Tools.TypeNameMappings;

using Xamarin.Android.ToolsTests;
using Java.Interop.Tools.Cecil;

namespace Java.Interop.Tools.JavaCallableWrappersTests
{
Expand Down Expand Up @@ -491,6 +495,66 @@ public void monodroidClearReferences ()
";
Assert.AreEqual (expected, actual);
}

[Test, Repeat (10)]
public void GenerateInParallel ()
{
var zipPath = Path.Combine (Path.GetDirectoryName (GetType ().Assembly.Location), "Data", "assemblies.zip");
var dest = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ());
try {
Directory.CreateDirectory (dest);
var assemblies = new List<string> ();

using (var zip = ZipFile.OpenRead (zipPath)) {
foreach (var entry in zip.Entries) {
var path = Path.Combine (dest, entry.FullName);
assemblies.Add (path);

using (var fs = File.Create (path))
using (var zs = entry.Open ()) {
zs.CopyTo (fs);
}
}
}

Action<TraceLevel, string> logger = (l, m) => {
TestContext.WriteLine ($"{l} {m}");
};

using (var res = new DirectoryAssemblyResolver (logger, loadDebugSymbols: false)) {
res.SearchDirectories.Add (dest);
foreach (var assembly in assemblies) {
res.Load (assembly);
}

var scanner = new JavaTypeScanner (logger);
var sw = new Stopwatch ();

sw.Reset ();
sw.Start ();
var parallelTypes = scanner.GetJavaTypesInParallel (assemblies, res);
sw.Stop ();
TestContext.WriteLine ($"Parallel took: {sw.Elapsed}");

sw.Reset ();
sw.Start ();
var types = scanner.GetJavaTypes (assemblies, res);
sw.Stop ();
TestContext.WriteLine ($"Non parallel took: {sw.Elapsed}");

types.Sort ((a, b) => a.FullName.CompareTo (b.FullName));
parallelTypes.Sort ((a, b) => a.FullName.CompareTo (b.FullName));

Assert.AreEqual (types.Count, parallelTypes.Count);
for (int i = 0; i < types.Count; i++) {
Assert.AreEqual (types [i].FullName, parallelTypes [i].FullName);
}
}

} finally {
Directory.Delete (dest, true);
}
}
}
}