Implement Text-Based Performance Log#5861
Implement Text-Based Performance Log#5861brianrob merged 9 commits intodotnet:masterfrom brianrob:perf-log
Conversation
| /// <param name="fullPath">Path to the document to load.</param> | ||
| /// </summary> | ||
| [Event(29)] | ||
| [Event(29, Keywords = Keywords.PerformanceLog)] |
There was a problem hiding this comment.
How did you choose which events to add this to?
There was a problem hiding this comment.
What I chose is based on two criteria:
- Gives a coarse view of what's happening, and time spans for those actions.
- Keeps the rate of events relatively low so that the impact on performance isn't too much.
If you think there are other events that should be included, I'm definitely open to that - just being careful with the perf overhead.
There was a problem hiding this comment.
Maybe RAROverallStart/Stop, BuildStart/Stop, and BuildProjectStart/Stop? I'd put those higher than LoadDocument, Parse, or MSBuildExe.
There was a problem hiding this comment.
Done. Thanks for the feedback on this.
There was a problem hiding this comment.
For command line scenarios I suspect Build and MSBuildExe will be fairly redundant: all MSBuild.exe does is start a build. But let's leave it in for v1.
| Arguments = parameters | ||
| }; | ||
|
|
||
| if(environmentVariables != null) |
There was a problem hiding this comment.
We've worked around the inability to set environment variables in a different way elsewhere. (See here.) Do you think it would be reasonable to combine them?
There was a problem hiding this comment.
I imagine so. Are you proposing a separate class, or moving the usage in XMake_Tests to use what I've done here, or something else?
There was a problem hiding this comment.
I'd do the latter or move what's in XMake_Tests here and call it. I don't have a strong preference between them, but I'd like it to be in one spot.
| // It's most important to ensure that at least one file shows up because any others that show up will be there because MSBuild properly | ||
| // enabled this functionality. | ||
| string[] files = Directory.GetFiles(perfLogDir, "perf-*.log"); | ||
| Assert.NotEmpty(files); |
There was a problem hiding this comment.
nit:
| Assert.NotEmpty(files); | |
| files.ShouldNotBeEmpty(); |
And also convert the rest to Shouldly?
There was a problem hiding this comment.
Do you think you should also check to make sure those files didn't exist before? I don't think GetTempPath returns a truly random path each time.
There was a problem hiding this comment.
Updated the rest to Shoudly. Thanks for pointing this out.
With regard to the directory, GetTempPath doesn't return a random path, but the test creates a random GUID directory to ensure that the directory is empty, and then creates it, which would result in a thrown exception if it already existed.
| Directory.CreateDirectory(perfLogDir); | ||
| Directory.CreateDirectory(projectDir); | ||
|
|
||
| string content = ObjectModelHelpers.CleanupFileContents("<Project ToolsVersion='msbuilddefaulttoolsversion' xmlns='msbuildnamespace'><Target Name='t'><Warning Text='[A=$(A)]'/></Target></Project>"); |
There was a problem hiding this comment.
nit:
split across multiple lines?
| bool successfulExit; | ||
| RunnerUtilities.ExecMSBuild(RunnerUtilities.PathToCurrentlyRunningMsBuildExe, msbuildParameters, out successfulExit, environmentVariables: environmentVariables); |
There was a problem hiding this comment.
tiny nit:
| bool successfulExit; | |
| RunnerUtilities.ExecMSBuild(RunnerUtilities.PathToCurrentlyRunningMsBuildExe, msbuildParameters, out successfulExit, environmentVariables: environmentVariables); | |
| RunnerUtilities.ExecMSBuild(RunnerUtilities.PathToCurrentlyRunningMsBuildExe, msbuildParameters, out bool successfulExit, environmentVariables: environmentVariables); |
| public void TestPerfLogEnabledProducedLogFile() | ||
| { | ||
| // Setup perf log. | ||
| string perfLogDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); |
There was a problem hiding this comment.
I think all this would be easier with a TestEnvironment.
There was a problem hiding this comment.
Can you please point me to an example that I should follow?
There was a problem hiding this comment.
I like this example, but I'm a little biased. You can also use env.SetEnvironmentVariable(<name>, <value>);.
There was a problem hiding this comment.
Using the test environment should make this simpler (since it handles cleanup), and allow avoiding the RunnerUtilities changes.
There was a problem hiding this comment.
Yes, this definitely cleaned things up.
| s_builder.Clear(); | ||
| } | ||
|
|
||
| s_builder.Append($"[{DateTime.UtcNow.ToString("o")}] Event={eventData.EventSource.Name}/{eventData.EventName} ProcessID={_processIDStr} ThreadID={System.Threading.Thread.CurrentThread.ManagedThreadId}\t "); |
There was a problem hiding this comment.
There's an AppendFormat method for StringBuilder. I remember having tested whether it was faster than this, but I don't remember the answer. I think .Append over and over was fastest but also ugliest.
|
|
||
| lock (this) | ||
| { | ||
| if (_writer != null) |
There was a problem hiding this comment.
When is _writer null, and should we error?
There was a problem hiding this comment.
My goal is to make this log as inobtrusive as possible. So if something goes wrong, I want the log to fail silently and/or just drop data rather than error. Essentially, preserve correctness.
| { | ||
| if (eventListener != null) | ||
| { | ||
| eventListener.Dispose(); |
There was a problem hiding this comment.
if (eventListener != null && eventListener threw an exception) shouldn't we return null or throw?
There was a problem hiding this comment.
Yes, that's a good catch. Thanks.
| public void TestPerfLogEnabledProducedLogFile() | ||
| { | ||
| // Setup perf log. | ||
| string perfLogDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")); |
There was a problem hiding this comment.
Using the test environment should make this simpler (since it handles cleanup), and allow avoiding the RunnerUtilities changes.
|
Thank you both for the reviews. I think I've covered all of the feedback. |
|
@brianrob Note that you checked this in for 6.0. If you want it included in 5.0.2xx for earlier testing, it'll need to go in that branch as well. |
|
@marcpopMSFT this is MSBuild :) it's in the 2xx branch already |
|
@rainersigwald DOH! I was just in the SDK repo and got my wires crossed. Carry on. |
Implements a text-based performance log scheme that writes coarse-grained performance logs:
DOTNET_PERFLOG_DIR. This is currently enabled when a user opts-in via a CLI command, but can be set adhoc as well.MSBuildEventSourceso that the events can be consumed through other profilers, such as those that use ETW.cc: @marcpopMSFT, @davidfowl, @DamianEdwards, @bwadswor