-
-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add AggressiveInlining support #1384
Conversation
I added a few points to be discussed here: #1381 (comment) |
I updated the code according to our discussion in #1381
Developers can use [MethodImpl] attribute in several ways (including and not limited to bellows) [MethodImpl]
[MethodImplAttribute]
[System.Runtime.CompilerServices.MethodImpl]
[System.Runtime.CompilerServices.MethodImplAttribute]
[global::System.Runtime.CompilerServices.MethodImpl]
[global::System.Runtime.CompilerServices.MethodImplAttribute] We could check the string of attribute syntax with any of those possibilities. private static readonly string[] _methodImplPossiblities =
[
"MethodImpl",
"MethodImplAttribute",
"System.Runtime.CompilerServices.MethodImpl",
"System.Runtime.CompilerServices.MethodImplAttribute",
"global::System.Runtime.CompilerServices.MethodImpl",
"global::System.Runtime.CompilerServices.MethodImplAttribute",
];
private static bool HasMethodImpleAttribute(MethodDeclarationSyntax methodDeclarationSyntax)
{
var attributes = methodDeclarationSyntax.AttributeLists.SelectMany(p => p.Attributes);
return attributes.Any(attributeSyntax => Array.Exists(_methodImplPossiblities, p => attributeSyntax.ToString().Contains(p, StringComparison.Ordinal)));
} But it seems it's not a clean and robust approach using AliasName = System.Runtime.CompilerServices.MethodImplAttribute;
[Mapper]
public static partial class MyMapper
{
[AliasName(MethodImplOptions.AggressiveInlining)]
public static partial DateTime MapTo(DateTime dt);
} So after some research, I found this way that can handle all of those. (this is the current implementation) public static bool HasAttribute<TAttribute>(this MethodDeclarationSyntax methodDeclarationSyntax) where TAttribute : Attribute
{
var csharpCompilation = CSharpCompilation.Create(
assemblyName: null,
syntaxTrees: [methodDeclarationSyntax!.SyntaxTree],
references: [MetadataReference.CreateFromFile(typeof(TAttribute).Assembly.Location)]
);
var semanticModel = csharpCompilation.GetSemanticModel(methodDeclarationSyntax.SyntaxTree);
var attributes = methodDeclarationSyntax.AttributeLists.SelectMany(p => p.Attributes);
return attributes.Any(attributeSyntax =>
{
var symbols = semanticModel.GetSymbolInfo(attributeSyntax).CandidateSymbols.OfType<IMethodSymbol>();
return symbols.Any(p => string.Equals(p.ContainingType.ToString(), typeof(TAttribute).FullName, StringComparison.Ordinal));
});
} This method works fine, however, it always Compiles the code to understand the meaning, and I'm not sure if it's ok or not due to performance problems (what do you think?) Next Step: |
Thank you for the updates 😊 💪
What else should be done?
|
Thank you so much for your help. I just wanted to sync my branch with the upstream and used the re-sync (with discard commits) feature of GitHub, but didn't know it closes the pull request! 😅 I'm working on it and I'm gonna re-open this PR with new updates by today ✌️ |
Thanks @latonz your idea was very helpful to me in understanding the codebase better and finding the right path to implement this feature. I came with cool updates. 😊 About the previous conversation:
About the current implementation:
Support for
Testing: I ensured all the previous tests were passed correctly and added some new tests to ensure it works fine in different scenarios. Final benchmark (the outcome🤩): I added a new benchmark and the result eliminated all my fatigue :) Documentation: The CI/CD Pipeline: I'm trying to run/pass most of the workflows locally or on my fork using GitHub Actions. The checklist:
Update: I tested the CI/CD pipeline on my branch and this is the result of all workflows:
I have the same issue when running integration tests in Visual Studio (version 17.11.1) however there is no problem with dotnet cli.
What's the problem? could you help me? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for the great updates and sorry for my slow response. Since this is your first contribution to Mapperly I need to manually approve each CI run 🤷
- Configuration looks great 😊
- UnsafeAccessors: I don't think the attribute has any effect on the extern accessor methods. Have you read / tested anything related to this? Otherwise I would revert these code changes to keep the code as simple as possible, the related tests could also be removed.
- The implementation looks quite good. I noticed that with the current approach the
enableAggressiveInlining
needs to be passed to each and every method mapping instance. I think this could probably be simplified with the following approach:- Similar approach to the reference handling (
DescriptorBuilder.BuildReferenceHandlingParameters
andMethodMapping.EnableReferenceHandling
)... - Add a method
DescriptorBuilder.EnableAggressiveInlining
calling it inDescriptorBuilder.Build
just afterBuildReferenceHandlingParameters
- In this method if aggressive inlining is disabled, return early, otherwise loop through
_mappings.MethodMappings
and call a new methodEnableAggressiveInlining
- Add
bool _hasMethodImplAttribute
to theMethodMapping
, defaulting tofalse
and for all user-defined methods setting it to true when the method impl attribute is present. - Add a method
MethodMapping.EnableAggressiveInlining
which sets_enableAggressiveInlining
to!_hasMethodImplAttribute
This would have the great benefit that it would "just work" for all method mappings and there is no need to carry theenableAggressiveInlining
around. I'm really sorry that I didn't come up with this idea earlier, I just had it while reviewing 🙄 WDYT?
- Similar approach to the reference handling (
- Small comment for the tests, otherwise they look good 😊
- Documentation: there is a bit of contributors documentation on how to update Mapperly's documentation here, hope that helps. (
npm i
+npm run start
should help). - CI: i approved the run and set the changelog labels. As noted in the review comment, I'd not add the benchmark to main as I don't see a benefit in continuously monitoring the performance difference with enabled/disabled aggressive inlining. All other jobs seem to be green 🥳
@@ -17,7 +17,9 @@ namespace Riok.Mapperly.Descriptors.UnsafeAccess; | |||
/// public extern static void SetValue(this global::MyClass source, int value); | |||
/// </code> | |||
/// </summary> | |||
public class UnsafeSetPropertyAccessor(IPropertySymbol symbol, string methodName) : IUnsafeAccessor, IMemberSetter | |||
public class UnsafeSetPropertyAccessor(IPropertySymbol symbol, string methodName, bool enableAggressiveInlining) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think setting the attribute on the external accessor methods doesn't have an effect. Therefore all unsafe access code changes could probably be reverted.
|
||
namespace Riok.Mapperly.Benchmarks.AgressiveInliningBenchmarks; | ||
|
||
[ArtifactsPath("artifacts")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This benchmark is great for this PR, but I don't think that this adds value on the long run. There is IMO no need to continuously monitor the performance difference between enabled/disabled aggressive inlining. Therefore I would not merge this into main.
[Fact] | ||
public Task MapperAttributeWithDefaultsShouldGenerateMethodImpleAttribute() | ||
{ | ||
var source = TestSourceBuilder.CSharp( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the new configuration option is added to TestSourceBuilderOptions
, this can be simplified using the TestSourceBuilder.Mapping
method. See also other tests calling this method. Same for the other tests in this class.
I'll close this for now... If you don't have the time/motivation to update again, I'll do it as soon as I find the time. |
Unfortunately, I have been too busy and didn't have enough time to complete it. |
Add AggressiveInlining support
Description
[MethodImpl(MethodImplOptions.AggressiveInlining)]
for mapping methods.Fixes #1381 (issue)
I did some benchmarks and the results were amazing.
struct
typesstruct
typesclass
typesChecklist