Skip to content

Commit

Permalink
Performance Improvements (mono#1277)
Browse files Browse the repository at this point in the history
* Correct company name
* Fix targets file
* Hide native files from project tree
* Add benchmark project
* Add a feature to skip the object registration
   - ISKSkipObjectRegistration
   - objects implementing this interface will not be registered in the global dictionary
   - major perf boos (2.84x) due to not having to look up in a dictionary
   - use direct constructor instead of object factory
* Throw an exception in "debug" builds
  • Loading branch information
mattleibow authored May 10, 2020
1 parent 887da1d commit 5ea66f2
Show file tree
Hide file tree
Showing 38 changed files with 264 additions and 69 deletions.
5 changes: 5 additions & 0 deletions benchmarks/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>

<Import Project="$(MSBuildThisFileDirectory)..\source\SkiaSharp.Build.props" />

</Project>
5 changes: 5 additions & 0 deletions benchmarks/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project>

<Import Project="$(MSBuildThisFileDirectory)..\source\SkiaSharp.Build.targets" />

</Project>
32 changes: 32 additions & 0 deletions benchmarks/SkiaSharp.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;

namespace SkiaSharp.Benchmarks
{
//[SimpleJob(RuntimeMoniker.CoreRt31)]
[SimpleJob(RuntimeMoniker.Mono)]
[SimpleJob(RuntimeMoniker.Net472)]
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
public class Benchmark
{
public Benchmark()
{
// setup
}

[Benchmark]
public void TheBenchmark()
{
// benchmark
}
}

public class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Benchmark>();
}
}
}
37 changes: 37 additions & 0 deletions benchmarks/SkiaSharp.Benchmarks/SkiaSharp.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net472;netcoreapp3.1</TargetFrameworks>
<RootNamespace>SkiaSharp.Benchmarks</RootNamespace>
<AssemblyName>SkiaSharp.Benchmarks</AssemblyName>
<SkipGenerateAssemblyVersionInfo>true</SkipGenerateAssemblyVersionInfo>
<SkipMDocGenerateDocs>true</SkipMDocGenerateDocs>
<SkipCopyToOutputDirectory>true</SkipCopyToOutputDirectory>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\binding\HarfBuzzSharp\HarfBuzzSharp.csproj" />
<ProjectReference Include="..\..\binding\SkiaSharp\SkiaSharp.csproj" />
<ProjectReference Include="..\..\source\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\output\native\windows\x64\libSkiaSharp.dll" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\windows\x64\libSkiaSharp.dll') or '$(IsWindows)' == 'true' " />
<Content Include="..\..\output\native\windows\x64\libSkiaSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\windows\x64\libSkiaSharp.pdb') or '$(IsWindows)' == 'true' " />
<Content Include="..\..\output\native\windows\x64\libHarfBuzzSharp.dll" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\windows\x64\libHarfBuzzSharp.dll') or '$(IsWindows)' == 'true' " />
<Content Include="..\..\output\native\windows\x64\libHarfBuzzSharp.pdb" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\windows\x64\libHarfBuzzSharp.pdb') or '$(IsWindows)' == 'true' " />
<Content Include="..\..\output\native\osx\libSkiaSharp.dylib" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\osx\libSkiaSharp.dylib') or '$(IsMacOS)' == 'true' " />
<Content Include="..\..\output\native\osx\libHarfBuzzSharp.dylib" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\osx\libHarfBuzzSharp.dylib') or '$(IsMacOS)' == 'true' " />
<Content Include="..\..\output\native\linux\x64\libSkiaSharp.so" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\linux\x64\libSkiaSharp.so') or '$(IsLinux)' == 'true' " />
<Content Include="..\..\output\native\linux\x64\libHarfBuzzSharp.so" CopyToOutputDirectory="Always" Visible="false"
Condition=" Exists('..\..\output\native\linux\x64\libHarfBuzzSharp.so') or '$(IsLinux)' == 'true' " />
</ItemGroup>
</Project>
43 changes: 43 additions & 0 deletions benchmarks/SkiaSharp.Benchmarks/SkiaSharp.Benchmarks.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29102.215
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp", "..\..\binding\SkiaSharp\SkiaSharp.csproj", "{3E1B158B-6C3B-4340-9F01-28E77D24F31D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HarfBuzzSharp", "..\..\binding\HarfBuzzSharp\HarfBuzzSharp.csproj", "{38FFD397-8A5E-421A-8649-24FE463E1DE9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.HarfBuzz", "..\..\source\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz\SkiaSharp.HarfBuzz.csproj", "{0DE402FA-A101-438E-8528-6EA82E0FF803}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkiaSharp.Benchmarks", "SkiaSharp.Benchmarks.csproj", "{8E5284C3-5AAF-4902-B12F-84E9172F20E0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3E1B158B-6C3B-4340-9F01-28E77D24F31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E1B158B-6C3B-4340-9F01-28E77D24F31D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E1B158B-6C3B-4340-9F01-28E77D24F31D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E1B158B-6C3B-4340-9F01-28E77D24F31D}.Release|Any CPU.Build.0 = Release|Any CPU
{38FFD397-8A5E-421A-8649-24FE463E1DE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38FFD397-8A5E-421A-8649-24FE463E1DE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38FFD397-8A5E-421A-8649-24FE463E1DE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38FFD397-8A5E-421A-8649-24FE463E1DE9}.Release|Any CPU.Build.0 = Release|Any CPU
{0DE402FA-A101-438E-8528-6EA82E0FF803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DE402FA-A101-438E-8528-6EA82E0FF803}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DE402FA-A101-438E-8528-6EA82E0FF803}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DE402FA-A101-438E-8528-6EA82E0FF803}.Release|Any CPU.Build.0 = Release|Any CPU
{8E5284C3-5AAF-4902-B12F-84E9172F20E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E5284C3-5AAF-4902-B12F-84E9172F20E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E5284C3-5AAF-4902-B12F-84E9172F20E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E5284C3-5AAF-4902-B12F-84E9172F20E0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8355B800-A642-459B-8675-B545839DE6C7}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion binding/Binding/GRBackendRenderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace SkiaSharp
{
public unsafe class GRBackendRenderTarget : SKObject
public unsafe class GRBackendRenderTarget : SKObject, ISKSkipObjectRegistration
{
internal GRBackendRenderTarget (IntPtr handle, bool owns)
: base (handle, owns)
Expand Down
2 changes: 1 addition & 1 deletion binding/Binding/GRBackendTexture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace SkiaSharp
{
public unsafe class GRBackendTexture : SKObject
public unsafe class GRBackendTexture : SKObject, ISKSkipObjectRegistration
{
internal GRBackendTexture (IntPtr handle, bool owns)
: base (handle, owns)
Expand Down
4 changes: 2 additions & 2 deletions binding/Binding/GRContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace SkiaSharp
{
public unsafe class GRContext : SKObject, ISKReferenceCounted
public unsafe class GRContext : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration
{
internal GRContext (IntPtr h, bool owns)
: base (h, owns)
Expand Down Expand Up @@ -105,6 +105,6 @@ public int GetMaxSurfaceSampleCount (SKColorType colorType) =>
public int GetRecommendedSampleCount (GRPixelConfig config, float dpi) => 0;

internal static GRContext GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new GRContext (h, o));
handle == IntPtr.Zero ? null : new GRContext (handle, true);
}
}
4 changes: 2 additions & 2 deletions binding/Binding/GRGlInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace SkiaSharp
{
public unsafe class GRGlInterface : SKObject, ISKReferenceCounted
public unsafe class GRGlInterface : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration
{
internal GRGlInterface (IntPtr h, bool owns)
: base (h, owns)
Expand Down Expand Up @@ -132,7 +132,7 @@ public bool HasExtension (string extension)
}

internal static GRGlInterface GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new GRGlInterface (h, o));
handle == IntPtr.Zero ? null : new GRGlInterface (handle, true);

private static class AngleLoader
{
Expand Down
26 changes: 25 additions & 1 deletion binding/Binding/HandleDictionary.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
#if THROW_OBJECT_EXCEPTIONS
using System.Collections.Concurrent;
#endif

namespace SkiaSharp
{
internal static class HandleDictionary
{
private static readonly Type SkipObjectRegistrationType = typeof (ISKSkipObjectRegistration);

#if THROW_OBJECT_EXCEPTIONS
internal static readonly ConcurrentBag<Exception> exceptions = new ConcurrentBag<Exception> ();
Expand All @@ -27,6 +30,11 @@ internal static bool GetInstance<TSkiaObject> (IntPtr handle, out TSkiaObject in
return false;
}

if (SkipObjectRegistrationType.IsAssignableFrom (typeof (TSkiaObject))) {
instance = null;
return false;
}

instancesLock.EnterReadLock ();
try {
return GetInstanceNoLocks (handle, out instance);
Expand All @@ -45,6 +53,16 @@ internal static TSkiaObject GetOrAddObject<TSkiaObject> (IntPtr handle, bool own
if (handle == IntPtr.Zero)
return null;

if (SkipObjectRegistrationType.IsAssignableFrom (typeof (TSkiaObject))) {
#if THROW_OBJECT_EXCEPTIONS
throw new InvalidOperationException (
$"For some reason, the object was constructed using a factory function instead of the constructor. " +
$"H: {handle.ToString ("x")} Type: {typeof (TSkiaObject)}");
#else
return objectFactory.Invoke (handle, owns);
#endif
}

instancesLock.EnterUpgradeableReadLock ();
try {
if (GetInstanceNoLocks<TSkiaObject> (handle, out var instance)) {
Expand Down Expand Up @@ -111,6 +129,9 @@ internal static void RegisterHandle (IntPtr handle, SKObject instance)
if (handle == IntPtr.Zero || instance == null)
return;

if (instance is ISKSkipObjectRegistration)
return;

SKObject objectToDispose = null;

instancesLock.EnterWriteLock ();
Expand Down Expand Up @@ -146,6 +167,9 @@ internal static void DeregisterHandle (IntPtr handle, SKObject instance)
if (handle == IntPtr.Zero)
return;

if (instance is ISKSkipObjectRegistration)
return;

instancesLock.EnterWriteLock ();
try {
var existed = instances.TryGetValue (handle, out var weak);
Expand Down
9 changes: 8 additions & 1 deletion binding/Binding/Properties/SkiaSharpAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[assembly: AssemblyTitle("SkiaSharp")]
[assembly: AssemblyDescription("SkiaSharp is a cross-platform 2D graphics API for .NET platforms that can be used across mobile, server and desktop models to render images.")]
[assembly: AssemblyCompany("Xamarin Inc.")]
[assembly: AssemblyCompany("Microsoft Corporation")]
[assembly: AssemblyProduct("SkiaSharp")]
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
[assembly: NeutralResourcesLanguage("en")]
Expand All @@ -23,6 +23,13 @@
"dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" +
"65d016df")]

[assembly: InternalsVisibleTo("SkiaSharp.Benchmarks, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010079159977d2d03a" +
"8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c" +
"3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fd" +
"dafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef00" +
"65d016df")]

[assembly: InternalsVisibleTo("SkiaSharp.HarfBuzz, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010079159977d2d03a" +
"8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c" +
Expand Down
2 changes: 1 addition & 1 deletion binding/Binding/SK3dView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace SkiaSharp
{
public unsafe class SK3dView : SKObject
public unsafe class SK3dView : SKObject, ISKSkipObjectRegistration
{
internal SK3dView (IntPtr x, bool owns)
: base (x, owns)
Expand Down
2 changes: 1 addition & 1 deletion binding/Binding/SKBitmap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static SKFilterQuality ToFilterQuality (this SKBitmapResizeMethod method)
// TODO: `GenerationID` may be useful
// TODO: `GetAddr` and `GetPixel` are confusing

public unsafe class SKBitmap : SKObject
public unsafe class SKBitmap : SKObject, ISKSkipObjectRegistration
{
private const string UnsupportedColorTypeMessage = "Setting the ColorTable is only supported for bitmaps with ColorTypes of Index8.";
private const string UnableToAllocatePixelsMessage = "Unable to allocate pixels for the bitmap.";
Expand Down
4 changes: 2 additions & 2 deletions binding/Binding/SKCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace SkiaSharp
// TODO: `Create(...)` should have overloads that accept a SKPngChunkReader
// TODO: missing the `QueryYuv8` and `GetYuv8Planes` members

public unsafe class SKCodec : SKObject
public unsafe class SKCodec : SKObject, ISKSkipObjectRegistration
{
internal SKCodec (IntPtr handle, bool owns)
: base (handle, owns)
Expand Down Expand Up @@ -344,6 +344,6 @@ internal static SKStream WrapManagedStream (Stream stream)
}

internal static SKCodec GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new SKCodec (h, o));
handle == IntPtr.Zero ? null : new SKCodec (handle, true);
}
}
2 changes: 1 addition & 1 deletion binding/Binding/SKColorTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SkiaSharp
{
[EditorBrowsable (EditorBrowsableState.Never)]
[Obsolete ("The Index8 color type and color table is no longer supported.")]
public unsafe class SKColorTable : SKObject, ISKReferenceCounted
public unsafe class SKColorTable : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration
{
public const int MaxLength = 256;

Expand Down
4 changes: 2 additions & 2 deletions binding/Binding/SKDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace SkiaSharp
{
public unsafe class SKDocument : SKObject, ISKReferenceCounted
public unsafe class SKDocument : SKObject, ISKReferenceCounted, ISKSkipObjectRegistration
{
public const float DefaultRasterDpi = 72.0f;

Expand Down Expand Up @@ -179,6 +179,6 @@ public static SKDocument CreatePdf (SKWStream stream, SKDocumentPdfMetadata meta
}

internal static SKDocument GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new SKDocument (h, o));
handle == IntPtr.Zero ? null : new SKDocument (handle, true);
}
}
4 changes: 2 additions & 2 deletions binding/Binding/SKFontStyle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace SkiaSharp
{
public class SKFontStyle : SKObject
public class SKFontStyle : SKObject, ISKSkipObjectRegistration
{
private static readonly SKFontStyle normal;
private static readonly SKFontStyle bold;
Expand Down Expand Up @@ -60,7 +60,7 @@ protected override void DisposeNative () =>
//

internal static SKFontStyle GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new SKFontStyle (h, o));
handle == IntPtr.Zero ? null : new SKFontStyle (handle, true);

private sealed class SKFontStyleStatic : SKFontStyle
{
Expand Down
4 changes: 4 additions & 0 deletions binding/Binding/SKObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,8 @@ internal interface ISKNonVirtualReferenceCounted : ISKReferenceCounted

void UnreferenceNative ();
}

internal interface ISKSkipObjectRegistration
{
}
}
4 changes: 2 additions & 2 deletions binding/Binding/SKPaint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace SkiaSharp
{
public unsafe class SKPaint : SKObject
public unsafe class SKPaint : SKObject, ISKSkipObjectRegistration
{
internal SKPaint (IntPtr handle, bool owns)
: base (handle, owns)
Expand Down Expand Up @@ -818,6 +818,6 @@ public float[] GetHorizontalTextIntercepts (IntPtr text, IntPtr length, float[]
//

internal static SKPaint GetObject (IntPtr handle) =>
GetOrAddObject (handle, (h, o) => new SKPaint (h, o));
handle == IntPtr.Zero ? null : new SKPaint (handle, true);
}
}
Loading

0 comments on commit 5ea66f2

Please sign in to comment.