Skip to content

Conversation

@MatteoH2O1999
Copy link
Contributor

This PR avoids the allocation per-call of both analyzers and drawers.

In order to do so, both analyzers and drawers must be stateless.
State is passed in Analyze and Draw interface calls.

@primo-ppcg
Copy link
Collaborator

primo-ppcg commented Dec 5, 2025

Avoid drawer and analyzer allocation per-call

LGTM

Use generic in Draw methods to improve performance

There is no need for these methods to be generic. Is there a specific reason why you believe this will improve performance?

@MatteoH2O1999
Copy link
Contributor Author

Using Foo<T>(T) where T : IFoo provides a concrete type while Foo(IFoo) does not. This avoids a vtable lookup at runtime.

I agree it is negligible, but so is the cost of making them generic as far as I can tell.

@primo-ppcg
Copy link
Collaborator

I agree it is negligible, but so is the cost of making them generic as far as I can tell.

Any difference is imperceptible.

Before:
image

After:
image

Benchmarked by rendering Example 12 twenty times. The majority of the time spent calling Draw is occupied by SkiaSharp.SKImage.Encode(SkiaSharp.SKEncodedImageFormat, int), which accounts for roughly 62% of the time taken.

@MatteoH2O1999
Copy link
Contributor Author

I reiterate: I agree it's negligible, but I honestly can't find a reason not to do it. If you really are against it I can just revert, but why give up on free performance?

@primo-ppcg
Copy link
Collaborator

I honestly can't find a reason not to do it.

  • It's a change to a public API without a compelling reason.
  • The unnecessary use of generics is confusing.
  • The generic usage is confused. This is actually the biggest sticking point for me.
// this
Method<T>(IEnumerable<T> arg) where T : InterfaceOrAbstractType { }

// and not this
Method<T>(T arg) where T : IEnumerable<InterfaceOrAbstractType> { }

why give up on free performance?

I did my best to validate the claim of improved performance, but was unable to.

@MatteoH2O1999
Copy link
Contributor Author

MatteoH2O1999 commented Dec 6, 2025

I honestly can't find a reason not to do it.

* It's a change to a public API without a compelling reason.

A change that would not impact anyone as Roslyn can resolve the type without using the explicit form.

* The unnecessary use of generics is confusing.

* The generic usage is confused. This is actually the biggest sticking point for me.
// this
Method<T>(IEnumerable<T> arg) where T : InterfaceOrAbstractType { }

// and not this
Method<T>(T arg) where T : IEnumerable<InterfaceOrAbstractType> { }

That is how Microsoft does it though (see here)

why give up on free performance?

I did my best to validate the claim of improved performance, but was unable to.

Now, I don't want this to become a blocker: I'll just revert.

This is ready to merge for me.

@primo-ppcg primo-ppcg merged commit 5940137 into BinaryKits:develop Dec 8, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants