-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Conversation
a076045
to
8b4caff
Compare
@@ -318,5 +318,73 @@ static void runTest(int n) | |||
}); | |||
} | |||
} | |||
|
|||
[Fact] | |||
public void Interceptors() |
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 test runs in ~6 sec on my machine in Release mode (10000 interceptors)
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.
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?
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.
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.
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.
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.
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 for the additional testing. I also ran this test with 3x interceptors and the elapsed time was ~2.5x.
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.
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.
|
||
string GetInterceptorFilePath(SyntaxTree tree, Compilation compilation) | ||
{ | ||
return compilation.Options.SourceReferenceResolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath; |
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.
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.
@@ -1037,6 +1037,34 @@ internal override int GetSyntaxTreeOrdinal(SyntaxTree tree) | |||
} | |||
} | |||
|
|||
private ImmutableSegmentedDictionary<string, OneOrMany<SyntaxTree>> _mappedPathToSyntaxTree; |
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.
@@ -2201,7 +2201,7 @@ internal enum ErrorCode | |||
ERR_InterceptorLineOutOfRange = 27005, | |||
ERR_InterceptorCharacterOutOfRange = 27006, | |||
ERR_InterceptorSignatureMismatch = 27007, | |||
ERR_InterceptableMethodMustBeOrdinary = 27008, |
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.
// 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; |
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.
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) |
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 wrote up a description of why we are going with respecting https://gist.github.com/RikkiGibson/36f6650f4897a1d7cf372343647dcbb4 |
{ | ||
if (tree.FilePath == filePath) | ||
var referenceResolver = DeclaringCompilation.Options.SourceReferenceResolver; |
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.
nit: consider moving closer to usage #Closed
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.
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/"; |
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.
Should this be "Path2"? #Closed
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.
Done with review pass (iteration 5)
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.
LGTM Thanks (iteration 8)
Test plan: #67421
PR primarily implements the following:
Incidentally have also done:
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)