Skip to content

Commit

Permalink
perf: Improve sync generator performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Jun 20, 2023
1 parent 850f542 commit ed4b246
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 97 deletions.
4 changes: 2 additions & 2 deletions src/Uno.UWPSyncGenerator/DocGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class DocGenerator : Generator
private IGrouping<INamespaceSymbol, PlatformSymbols<INamedTypeSymbol>>[] _viewsGrouped;
private HashSet<(string name, string namespaceString)> _kosherFrameworkViews;

public override void Build(string basePath, string baseName, string sourceAssembly)
public override async Task Build(string basePath, string baseName, string sourceAssembly)
{
_sb = new MarkdownStringBuilder();

Expand All @@ -36,7 +36,7 @@ public override void Build(string basePath, string baseName, string sourceAssemb

try
{
base.Build(basePath, baseName, sourceAssembly);
await base.Build(basePath, baseName, sourceAssembly);
}
catch (Exception e)
{
Expand Down
104 changes: 54 additions & 50 deletions src/Uno.UWPSyncGenerator/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;
using Uno.Extensions;
Expand Down Expand Up @@ -99,7 +99,7 @@ abstract class Generator
private INamedTypeSymbol _iOSBaseSymbol;
private INamedTypeSymbol _androidBaseSymbol;
private INamedTypeSymbol _macOSBaseSymbol;
private Compilation _referenceCompilation;
private static Compilation s_referenceCompilation;
private Compilation _unitTestsCompilation;

private Compilation _netstdReferenceCompilation;
Expand Down Expand Up @@ -136,36 +136,45 @@ abstract class Generator
static Generator()
{
RegisterAssemblyLoader();
}

public virtual void Build(string basePath, string baseName, string sourceAssembly)
{
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
InitializeRoslyn();
}

public virtual async Task Build(string basePath, string baseName, string sourceAssembly)
{
Console.WriteLine($"Generating for {baseName} {sourceAssembly}");

_referenceCompilation = LoadUWPReferenceProject(@"..\..\..\Uno.UWPSyncGenerator.Reference\references.txt");
s_referenceCompilation ??= await LoadUWPReferenceProject(@"..\..\..\Uno.UWPSyncGenerator.Reference\references.txt");

_dependencyPropertySymbol = s_referenceCompilation.GetTypeByMetadataName(BaseXamlNamespace + ".DependencyProperty");

var iOSCompilationTask = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-ios");
var androidCompilationTask = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-android");
var unitTestsCompilationTask = LoadProject($@"{basePath}\{baseName}.Tests.csproj", "net7.0");
var macCompilationTask = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-macos");

_dependencyPropertySymbol = _referenceCompilation.GetTypeByMetadataName(BaseXamlNamespace + ".DependencyProperty");
var netstdReferenceCompilationTask = LoadProject($@"{basePath}\{baseName}.Reference.csproj", "net7.0");
var wasmCompilationTask = LoadProject($@"{basePath}\{baseName}.Wasm.csproj", "net7.0");
var skiaCompilationTask = LoadProject($@"{basePath}\{baseName}.Skia.csproj", "net7.0");

_iOSCompilation = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-ios");
_androidCompilation = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-android");
_unitTestsCompilation = LoadProject($@"{basePath}\{baseName}.Tests.csproj", "net7.0");
_macCompilation = LoadProject($@"{basePath}\{baseName}.netcoremobile.csproj", "net7.0-macos");
await Task.WhenAll(iOSCompilationTask, androidCompilationTask, unitTestsCompilationTask, macCompilationTask, netstdReferenceCompilationTask, wasmCompilationTask, skiaCompilationTask);

_netstdReferenceCompilation = LoadProject($@"{basePath}\{baseName}.Reference.csproj", "net7.0");
_wasmCompilation = LoadProject($@"{basePath}\{baseName}.Wasm.csproj", "net7.0");
_skiaCompilation = LoadProject($@"{basePath}\{baseName}.Skia.csproj", "net7.0");
_iOSCompilation = await iOSCompilationTask;
_androidCompilation = await androidCompilationTask;
_unitTestsCompilation = await unitTestsCompilationTask;
_macCompilation = await macCompilationTask;
_netstdReferenceCompilation = await netstdReferenceCompilationTask;
_wasmCompilation = await wasmCompilationTask;
_skiaCompilation = await skiaCompilationTask;

_iOSBaseSymbol = _iOSCompilation.GetTypeByMetadataName("UIKit.UIView");
_androidBaseSymbol = _androidCompilation.GetTypeByMetadataName("Android.Views.View");
_macOSBaseSymbol = _macCompilation.GetTypeByMetadataName("AppKit.NSView");

FlagsAttributeSymbol = _referenceCompilation.GetTypeByMetadataName("System.FlagsAttribute");
UIElementSymbol = _referenceCompilation.GetTypeByMetadataName(BaseXamlNamespace + ".UIElement");
FlagsAttributeSymbol = s_referenceCompilation.GetTypeByMetadataName("System.FlagsAttribute");
UIElementSymbol = s_referenceCompilation.GetTypeByMetadataName(BaseXamlNamespace + ".UIElement");

var origins = from externalRedfs in _referenceCompilation.ExternalReferences
var origins = from externalRedfs in s_referenceCompilation.ExternalReferences
let fileNameWithoutExtension = Path.GetFileNameWithoutExtension(externalRedfs.Display)
where fileNameWithoutExtension.StartsWith("Windows.Foundation", StringComparison.Ordinal)
|| fileNameWithoutExtension.StartsWith("Microsoft.WinUI", StringComparison.Ordinal)
Expand All @@ -178,12 +187,12 @@ where fileNameWithoutExtension.StartsWith("Windows.Foundation", StringComparison
|| fileNameWithoutExtension.StartsWith("Windows.ApplicationModel.Calls.CallsPhoneContract", StringComparison.Ordinal)
|| fileNameWithoutExtension.StartsWith("Windows.UI.Xaml.Hosting.HostingContract", StringComparison.Ordinal)
|| fileNameWithoutExtension.StartsWith("Microsoft.Web.WebView2.Core", StringComparison.Ordinal)
let asm = _referenceCompilation.GetAssemblyOrModuleSymbol(externalRedfs) as IAssemblySymbol
let asm = s_referenceCompilation.GetAssemblyOrModuleSymbol(externalRedfs) as IAssemblySymbol
where asm != null
select asm;

List<string> excludeNamespaces = new List<string>();
List<string> includeNamespaces = new List<string>();
var excludeNamespaces = new List<string>();
var includeNamespaces = new List<string>();

#if !HAS_UNO_WINUI
// For UWP compilation we need to ignore these namespaces when not explicitly generating
Expand Down Expand Up @@ -1311,7 +1320,7 @@ private bool IsNotUWPMapping(INamedTypeSymbol type, IMethodSymbol method)
}
else
{
var type2 = _referenceCompilation.GetTypeByMetadataName(uwpIface);
var type2 = s_referenceCompilation.GetTypeByMetadataName(uwpIface);

INamedTypeSymbol build()
{
Expand Down Expand Up @@ -1348,7 +1357,7 @@ private bool IsNotUWPMapping(INamedTypeSymbol type, IPropertySymbol property)

if (uwpIface != null)
{
var type2 = _referenceCompilation.GetTypeByMetadataName(uwpIface);
var type2 = s_referenceCompilation.GetTypeByMetadataName(uwpIface);

var t3 = type2.Construct(iface.TypeArguments.ToArray());

Expand Down Expand Up @@ -1736,7 +1745,7 @@ private IMethodSymbol FindMatchingMethod(ITypeSymbol symbol, IMethodSymbol sourc
static Dictionary<(string projectFile, string targetFramework), Compilation> _projects
= new();

private static Compilation LoadProject(string projectFile, string targetFramework = null)
private static async Task<Compilation> LoadProject(string projectFile, string targetFramework = null)
{
var key = (projectFile, targetFramework);

Expand All @@ -1746,40 +1755,36 @@ private static Compilation LoadProject(string projectFile, string targetFramewor
return compilation;
}

return _projects[key] = InnerLoadProject(projectFile, targetFramework);
return _projects[key] = await InnerLoadProject(projectFile, targetFramework);
}

private static Compilation LoadUWPReferenceProject(string referencesFile)
private static async Task<Compilation> LoadUWPReferenceProject(string referencesFile)
{
var ws = new AdhocWorkspace();

var p = ws.AddProject("uwpref", LanguageNames.CSharp);

foreach (var reference in File.ReadAllLines(referencesFile))
{
p = p.AddMetadataReference(MetadataReference.CreateFromFile(reference));
}

return p.GetCompilationAsync().Result;
p = p.AddMetadataReferences(File.ReadAllLines(referencesFile).Select(reference => MetadataReference.CreateFromFile(reference)));
return await p.GetCompilationAsync();
}

private static Compilation InnerLoadProject(string projectFile, string targetFramework = null)
private static async Task<Compilation> InnerLoadProject(string projectFile, string targetFramework = null)
{
Console.WriteLine($"Loading for {targetFramework}: {Path.GetFileName(projectFile)}");

var properties = new Dictionary<string, string>
{
// { "VisualStudioVersion", "15.0" },
// { "Configuration", "Debug" },
//{ "BuildingInsideVisualStudio", "true" },
{ "SkipUnoResourceGeneration", "true" }, // Required to avoid loading a non-existent task
{ "DocsGeneration", "true" }, // Detect that source generation is running
{ "LangVersion", CSharpLangVersion },
{ "NoBuild", "True" },
//{ "DesignTimeBuild", "true" },
//{ "UseHostCompilerIfAvailable", "false" },
//{ "UseSharedCompilation", "false" },
};
{
// { "VisualStudioVersion", "15.0" },
// { "Configuration", "Debug" },
//{ "BuildingInsideVisualStudio", "true" },
{ "SkipUnoResourceGeneration", "true" }, // Required to avoid loading a non-existent task
{ "DocsGeneration", "true" }, // Detect that source generation is running
{ "LangVersion", CSharpLangVersion },
{ "NoBuild", "True" },
{ "RunAnalyzers", "false" }
//{ "DesignTimeBuild", "true" },
//{ "UseHostCompilerIfAvailable", "false" },
//{ "UseSharedCompilation", "false" },
};

if (targetFramework != null)
{
Expand All @@ -1793,7 +1798,7 @@ private static Compilation InnerLoadProject(string projectFile, string targetFra
ws.WorkspaceFailed +=
(s, e) => Console.WriteLine(e.Diagnostic.ToString());

var project = ws.OpenProjectAsync(projectFile).Result;
var project = await ws.OpenProjectAsync(projectFile);

var generatedDocs = project.Documents
.Where(d => d.FilePath.Contains("\\Generated\\"))
Expand All @@ -1808,7 +1813,7 @@ private static Compilation InnerLoadProject(string projectFile, string targetFra
.Where(p => p.MetadataReferences.None())
.ToArray();

if (metadataLessProjects.Any())
if (metadataLessProjects.Length > 0)
{
// In this case, this may mean that Rolsyn failed to execute some msbuild task that loads the
// references in a UWA project (or NuGet 3.0+ with project.json, more specifically). For these
Expand All @@ -1829,8 +1834,7 @@ private static Compilation InnerLoadProject(string projectFile, string targetFra
);
}

return project
.GetCompilationAsync().Result;
return await project.GetCompilationAsync();
}

public static IEnumerable<INamedTypeSymbol> GetNamespaceTypes(INamespaceSymbol sym)
Expand Down
84 changes: 39 additions & 45 deletions src/Uno.UWPSyncGenerator/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;

namespace Uno.UWPSyncGenerator
{
Expand All @@ -15,7 +9,7 @@ class Program
const string DocMode = "doc";
const string AllMode = "all";

static void Main(string[] args)
static async Task Main(string[] args)
{
if (args.Length == 0)
{
Expand All @@ -27,66 +21,66 @@ static void Main(string[] args)

if (mode == SyncMode || mode == AllMode)
{
new SyncGenerator().Build(@"..\..\..\Uno.Foundation", "Uno.Foundation", "Windows.Foundation.FoundationContract");
new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Foundation.UniversalApiContract");
new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Phone.PhoneContract");
new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Networking.Connectivity.WwanContract");
new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.ApplicationModel.Calls.CallsPhoneContract");
await new SyncGenerator().Build(@"..\..\..\Uno.Foundation", "Uno.Foundation", "Windows.Foundation.FoundationContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Foundation.UniversalApiContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Phone.PhoneContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.Networking.Connectivity.WwanContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UWP", "Uno", "Windows.ApplicationModel.Calls.CallsPhoneContract");

// When adding support for a new WinRT contract here, ensure to add it to the list of origins in Generator.cs
// and to the list of supported contracts in ApiInformation.shared.cs

#if HAS_UNO_WINUI
new SyncGenerator().Build(@"..\..\..\Uno.Foundation", "Uno.Foundation", "Microsoft.Foundation");
await new SyncGenerator().Build(@"..\..\..\Uno.Foundation", "Uno.Foundation", "Microsoft.Foundation");

new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Foundation");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Foundation");

new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Graphics");
new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI.Dispatching");
new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI.Composition");
new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI");
new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Graphics");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI.Dispatching");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI.Composition");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI");

new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Text");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.ApplicationModel.Resources");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Text");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.ApplicationModel.Resources");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");

new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Input");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Windowing");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Input");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Windowing");

new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");

#else
new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Windows.Foundation.UniversalApiContract");
new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Windows.Foundation.UniversalApiContract");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.Foundation.UniversalApiContract");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.UI.Xaml.Hosting.HostingContract");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");
new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Windows.Foundation.UniversalApiContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Windows.Foundation.UniversalApiContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.Foundation.UniversalApiContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.UI.Xaml.Hosting.HostingContract");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");
await new SyncGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");
#endif
}

if (mode == DocMode || mode == AllMode)
{
#if HAS_UNO_WINUI
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.ApplicationModel.Resources");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.ApplicationModel.Resources");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Web.WebView2.Core");

new DocGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI.Dispatching");
new DocGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI.Composition");
await new DocGenerator().Build(@"..\..\..\Uno.UI.Dispatching", "Uno.UI.Dispatching", "Microsoft.UI.Dispatching");
await new DocGenerator().Build(@"..\..\..\Uno.UI.Composition", "Uno.UI.Composition", "Microsoft.UI.Composition");

new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Foundation");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Composition");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Dispatching");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Input");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Graphics");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Windowing");
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Foundation");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Composition");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Dispatching");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Input");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.Graphics");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Windowing");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI");

new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Microsoft.UI.Xaml");
#else
new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.Foundation.UniversalApiContract");
await new DocGenerator().Build(@"..\..\..\Uno.UI", "Uno.UI", "Windows.Foundation.UniversalApiContract");
#endif
}
}
Expand Down

0 comments on commit ed4b246

Please sign in to comment.