Skip to content
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

Expect mapped paths in InterceptsLocationAttribute #68242

Merged
merged 8 commits into from
Jun 9, 2023

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented May 18, 2023

Test plan: #67421

PR primarily implements the following:

  • Add handling requirement for pathmap including feature doc change.
  • Add pathmap tests

Incidentally have also done:

  • Add tests for GetEnumerator/Dispose/Deconstruct
  • Add EndToEndTest (large number of interceptors)

The goal of this change is to eliminate machine-specific paths from source code, which is bad for portability and determinism.

Further discussion of the #line question can be found in dotnet/aspnetcore#47918 (comment)

@@ -318,5 +318,73 @@ static void runTest(int n)
});
}
}

[Fact]
public void Interceptors()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test runs in ~6 sec on my machine in Release mode (10000 interceptors)

Copy link
Member

@cston cston May 27, 2023

Choose a reason for hiding this comment

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

6 secs seems like a significant amount of time, even for the large number of interceptors in the test. Is it possible there is some N^2 algorithm? If the number of interceptors is 1000 (1/10th), [update] how long does the test take?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With 1000 interceptors, the test takes about 1.3s, which I think indicates we don't have any dominant N^2 algorithm in the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When interceptors are not used (commenting out InterceptsLocationAttribute in tests) we get:

~1.1s for 1000 non-interceptors
~3.8s for 10000 non-interceptors

Compare (again) with the interceptors case:

~1.3s for 1000 interceptors
~6s for 10000 interceptors

I think there's a noticeable cost incurred for very large numbers of interceptors here, but on an order that I think we can accept for an initial release.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the additional testing. I also ran this test with 3x interceptors and the elapsed time was ~2.5x.

Copy link
Member

Choose a reason for hiding this comment

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

Not related to this PR: It would be good to look at a PerfView trace to get a better sense of where the additional cost comes from and whether it could be improved.

@RikkiGibson RikkiGibson marked this pull request as ready for review May 23, 2023 21:32
@RikkiGibson RikkiGibson requested a review from a team as a code owner May 23, 2023 21:32

string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation)
{
return compilation.Options.SourceReferenceResolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that if this feature makes it past the experimental phase, we might revisit providing "convenience public APIs". For the current release, it feels more appropriate to indicate what helpers the generator author themselves needs to include.

@RikkiGibson RikkiGibson requested review from cston and jcouv May 23, 2023 22:34
@jcouv jcouv self-assigned this May 24, 2023
@@ -1037,6 +1037,34 @@ internal override int GetSyntaxTreeOrdinal(SyntaxTree tree)
}
}

private ImmutableSegmentedDictionary<string, OneOrMany<SyntaxTree>> _mappedPathToSyntaxTree;
Copy link
Member

@cston cston May 26, 2023

Choose a reason for hiding this comment

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

_mappedPathToSyntaxTree

Consider moving field declaration ahead of the method declarations. #Resolved

@@ -2201,7 +2201,7 @@ internal enum ErrorCode
ERR_InterceptorLineOutOfRange = 27005,
ERR_InterceptorCharacterOutOfRange = 27006,
ERR_InterceptorSignatureMismatch = 27007,
ERR_InterceptableMethodMustBeOrdinary = 27008,
Copy link
Member

@cston cston May 26, 2023

Choose a reason for hiding this comment

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

ERR_InterceptableMethodMustBeOrdinary

Is this error code no longer used? Can we remove the resource string as well? #Resolved

// At that time, we should look at caching the resolved paths for the trees in a set (or maybe a Map<string, OneOrMany<SyntaxTree>>).
// so we can reduce the cost of these checks.
foreach (var tree in syntaxTrees)
var referenceResolver = DeclaringCompilation.Options.SourceReferenceResolver;
Copy link
Member

Choose a reason for hiding this comment

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

referenceResolver

Can this declaration be moved inside if (matchingTrees...) { ... }?

comp.VerifyEmitDiagnostics(PlatformInformation.IsWindows
// C:\My\Machine\Specific\Path\Program.cs(11,25): error CS27008: Cannot intercept: Path 'C:\My\Machine\Specific\Path\Program.cs' is unmapped. Expected mapped path '/_/Program.cs'.
// [InterceptsLocation(@"C:\My\Machine\Specific\Path\Program.cs", 5, 3)]
? Diagnostic(ErrorCode.ERR_InterceptorPathNotInCompilationWithUnmappedCandidate, @"@""C:\My\Machine\Specific\Path\Program.cs""").WithArguments(@"C:\My\Machine\Specific\Path\Program.cs", "/_/Program.cs").WithLocation(11, 25)
Copy link
Member

Choose a reason for hiding this comment

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

@"@""C:\My\Machine\Specific\Path\Program.cs""").WithArguments(@"C:\My\Machine\Specific\Path\Program.cs"

Could we avoid checking IsWindows with $"\"{path}\"").WithArguments(path)?

@RikkiGibson
Copy link
Contributor Author

I wrote up a description of why we are going with respecting /pathmap but not #line and where that puts us for .NET 8. Notably, we don't reach a point of hand-authorability just by respecting /pathmap here.

https://gist.github.com/RikkiGibson/36f6650f4897a1d7cf372343647dcbb4

{
if (tree.FilePath == filePath)
var referenceResolver = DeclaringCompilation.Options.SourceReferenceResolver;
Copy link
Member

@jcouv jcouv Jun 8, 2023

Choose a reason for hiding this comment

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

nit: consider moving closer to usage #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because it's used in each subsequent branch in this block, I felt more comfortable declaring it where it is currently, instead of after the statement declaring unmappedMatch, for example.

I'm line-breaking some of the diagnostics.Add calls to make the usages easier to spot.

""";

var pathPrefix1 = PlatformInformation.IsWindows ? """C:\My\Machine\Specific\Path1\""" : "/My/Machine/Specific/Path1/";
var pathPrefix2 = PlatformInformation.IsWindows ? """C:\My\Machine\Specific\Path1\""" : "/My/Machine/Specific/Path2/";
Copy link
Member

@jcouv jcouv Jun 8, 2023

Choose a reason for hiding this comment

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

Should this be "Path2"? #Closed

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

Done with review pass (iteration 5)

@jcouv jcouv removed the untriaged Issues and PRs which have not yet been triaged by a lead label Jun 8, 2023
@jcouv jcouv added this to the C# 12.0 milestone Jun 8, 2023
@RikkiGibson RikkiGibson requested a review from jcouv June 9, 2023 16:21
Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 8)

@RikkiGibson RikkiGibson merged commit d9a4149 into dotnet:features/interceptors Jun 9, 2023
26 checks passed
@RikkiGibson RikkiGibson deleted the ic-6 branch June 9, 2023 19:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants