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

Add more events to SDK resolution #7390

Merged
merged 1 commit into from
Mar 15, 2022

Conversation

jeffkl
Copy link
Contributor

@jeffkl jeffkl commented Feb 14, 2022

Fixes #7136

Context

Second attempt at adding more ETW events for SDK resolution.

Changes Made

  • Add events around the CachingSdkResolverService
  • Add flag tracking whether or not an SDK resolution came from cache
  • Add note to MSBuildEventSource reminding us that you must rev the version of an event when changing the method signature

Testing

Ran locally built msbuild.exe with perfview and verified the events show up properly.

Notes

Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

Overall looks fine to me, but I wonder: should we expose an IsEnabled that wraps our own functionality there? We use that internally when building the objects to send to ETW is nontrivial, as it will likely be to assemble these single strings (since that's the only way to customize the messages).

For example,

if (MSBuildEventSource.Log.IsEnabled())
{
MSBuildEventSource.Log.BuildProjectStop(_requestEntry.RequestConfiguration.ProjectFullPath, string.Join(", ", allTargets));
}

@jeffkl
Copy link
Contributor Author

jeffkl commented Feb 14, 2022

I wonder: should we expose an IsEnabled that wraps our own functionality there?

The couple of new events just end up logging the same data (project name, solution path, etc), do you see one that is of particular concern to be expensive?

I am not 100% happy with how I'm tracking whether or not a particular resolution is cached. I'm introducing a new bool and setting it in the Lazy<T> which will capture context and potentially be slower. But I really want to know how many SDKs are actually looked up vs cached. Does anyone have any bright ideas? I thought about just not firing the Stop event for a cached result and only for actual look ups, but then we can't measure how long it took to get a cached result in the case where a thread is waiting for a lock due to simultaneous SDK resolutions. My current implementation works but it smells fishy to me...

@jeffkl jeffkl force-pushed the more-sdkresolver-events branch from c4194cc to fe6f885 Compare February 18, 2022 17:39
@rainersigwald
Copy link
Member

The couple of new events just end up logging the same data (project name, solution path, etc), do you see one that is of particular concern to be expensive?

Constructing the single string will create garbage, but presumably not all that much. It's just concatenation of a bunch of already-existing stuff?

@jeffkl
Copy link
Contributor Author

jeffkl commented Feb 18, 2022

Constructing the single string will create garbage, but presumably not all that much. It's just concatenation of a bunch of already-existing stuff?

I'm confused, where is the code constructing a string out of other data? Its just passing properties that come in from the SDK resolution APIs. I'm assuming if tracing is off, the ETW APIs just no-op so we don't have to avoid calling them if tracing is off? Or am completely wrong about all that? 😕

@rainersigwald
Copy link
Member

Its just passing properties that come in from the SDK resolution APIs. I'm assuming if tracing is off, the ETW APIs just no-op so we don't have to avoid calling them if tracing is off?

That's true, the ETW APIs are very lightweight if the events are disabled. However, the .NET runtime doesn't know about that, so it has to fully realize arguments

The case I'm trying to avoid is:

// In SDK resolver

WriteEvent(s1 + s2 + s3);

// or

WriteEvent($"Some formatting string with {holes} that {get} {filled}");

// or worst case

WriteEvent(ExpensiveMethodThatDoesABunchOfWork());

@jeffkl
Copy link
Contributor Author

jeffkl commented Feb 18, 2022

Yeah okay I totally understand, we don't want to do string formatting of any kind that will allocate just to call a method that no-ops. I don't think any of the code paths I'm adding here are doing that, they all take existing objects and pass them directly to ETW APIs.

@rainersigwald
Copy link
Member

Ah, I've been unclear: none of the APIs in this PR are bad on this front. My question is: does this encourage/require bad behavior in the resolvers because of the API shape we're exposing?

@jeffkl
Copy link
Contributor Author

jeffkl commented Feb 22, 2022

Ah, I've been unclear: none of the APIs in this PR are bad on this front. My question is: does this encourage/require bad behavior in the resolvers because of the API shape we're exposing?

Okay I finally understand what you mean. That's a valid concern, callers could end up building expensive strings that aren't actually used. My original implementation tried to accept params object[] args but that caused ETW schema errors. I tried using string[] instead but that didn't work either. I read through the documentation to see if there was any guidance and then I came to this realization:

The ETW API is not designed to allow external code to contribute to your events!

So I'm removing all of the code around allowing SDK resolvers to contribute their own events. Instead, I'll just add my own EventSource to the NuGet-based SDK resolver. Events will still show up in the same trace as long as you specify the correct provider name. And then I'll get to specify whatever data I want :)

@jeffkl jeffkl force-pushed the more-sdkresolver-events branch from fe6f885 to 29e5146 Compare February 22, 2022 21:36
@@ -34,6 +34,7 @@ EventSource is primarily used to profile code. For MSBuild specifically, a major
| Save | Saves a project to the file system if dirty, creating directories as necessary. |
| SdkResolverResolveSdk | A single SDK resolver is called. |
| SdkResolverServiceInitialize | Initializes SDK resolvers. |
| SdkResolverEvent | An SDK resolver logs an event. |
Copy link
Member

Choose a reason for hiding this comment

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

Is this still a thing?

@Forgind Forgind added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label Mar 7, 2022
@benvillalobos benvillalobos merged commit 9bbee11 into dotnet:main Mar 15, 2022
@jeffkl jeffkl deleted the more-sdkresolver-events branch March 28, 2022 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

More ETW events should be added to SDK resolution
4 participants