-
Notifications
You must be signed in to change notification settings - Fork 150
[Test Optimization] ci: git caching + env improvements #8072
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
base: tony/testoptimization-performance-work-pr2
Are you sure you want to change the base?
[Test Optimization] ci: git caching + env improvements #8072
Conversation
BenchmarksBenchmark execution time: 2026-01-19 10:11:07 Comparing candidate commit 87c7fd2 in PR branch Found 6 performance improvements and 13 performance regressions! Performance is the same for 158 metrics, 15 unstable metrics. scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1
scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net6.0
scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0
scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1
scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net6.0
scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net472
scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0
scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0
scenario:Benchmarks.Trace.DbCommandBenchmark.ExecuteNonQuery netcoreapp3.1
scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0
scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1
scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net6.0
scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0
|
d68d0a9 to
de740b1
Compare
50fc18c to
2018124
Compare
This comment has been minimized.
This comment has been minimized.
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8072) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:
Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard. Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph). Duration chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (73ms) : 66, 79
master - mean (68ms) : 67, 70
section Bailout
This PR (8072) - mean (76ms) : 74, 78
master - mean (72ms) : 71, 73
section CallTarget+Inlining+NGEN
This PR (8072) - mean (1,025ms) : 974, 1076
master - mean (1,005ms) : 947, 1063
FakeDbCommand (.NET Core 3.1)gantt
title Execution time (ms) FakeDbCommand (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (108ms) : 106, 111
master - mean (106ms) : 104, 108
section Bailout
This PR (8072) - mean (111ms) : 109, 113
master - mean (107ms) : 105, 108
section CallTarget+Inlining+NGEN
This PR (8072) - mean (751ms) : 697, 806
master - mean (738ms) : 687, 789
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (96ms) : 94, 99
master - mean (94ms) : 91, 96
section Bailout
This PR (8072) - mean (97ms) : 96, 99
master - mean (94ms) : 93, 95
section CallTarget+Inlining+NGEN
This PR (8072) - mean (720ms) : 659, 781
master - mean (719ms) : 687, 751
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (95ms) : 92, 97
master - mean (92ms) : 90, 94
section Bailout
This PR (8072) - mean (96ms) : 94, 98
master - mean (93ms) : 92, 94
section CallTarget+Inlining+NGEN
This PR (8072) - mean (644ms) : 625, 662
master - mean (684ms) : 576, 791
HttpMessageHandler (.NET Framework 4.8)gantt
title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (197ms) : 190, 203
master - mean (193ms) : 189, 197
section Bailout
This PR (8072) - mean (199ms) : 195, 204
master - mean (197ms) : 193, 200
section CallTarget+Inlining+NGEN
This PR (8072) - mean (1,146ms) : 1078, 1214
master - mean (1,133ms) : 1064, 1203
HttpMessageHandler (.NET Core 3.1)gantt
title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (281ms) : 271, 291
master - mean (278ms) : 270, 285
section Bailout
This PR (8072) - mean (279ms) : 275, 283
master - mean (278ms) : 275, 281
section CallTarget+Inlining+NGEN
This PR (8072) - mean (947ms) : 900, 995
master - mean (935ms) : 889, 981
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (272ms) : 267, 277
master - mean (271ms) : 265, 276
section Bailout
This PR (8072) - mean (272ms) : 268, 275
master - mean (270ms) : 266, 273
section CallTarget+Inlining+NGEN
This PR (8072) - mean (927ms) : 865, 989
master - mean (922ms) : 874, 969
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8072) - mean (273ms) : 267, 278
master - mean (271ms) : 265, 276
section Bailout
This PR (8072) - mean (272ms) : 268, 275
master - mean (270ms) : 266, 275
section CallTarget+Inlining+NGEN
This PR (8072) - mean (841ms) : 823, 859
master - mean (833ms) : 816, 851
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
de740b1 to
a92777c
Compare
b98a4d3 to
e77015c
Compare
a92777c to
d0595bf
Compare
e77015c to
8fae54a
Compare
d0595bf to
7216d32
Compare
8fae54a to
33077cb
Compare
| if (gitInfo.Errors.Count > 0) | ||
| { | ||
| var sb = StringBuilderCache.Acquire(); | ||
| sb.AppendLine(); | ||
| foreach (var err in gitInfo.Errors) | ||
| { | ||
| sb.AppendLine(" Error: " + err); | ||
| } | ||
|
|
||
| Log.Warning("CIEnvironmentValues: Errors detected in the local gitInfo: {Errors}", StringBuilderCache.GetStringAndRelease(sb)); | ||
| } |
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.
Before this we were swallowing all the git errors when extracting the local git info (without any ci provider info)
| if (Log.IsEnabled(LogEventLevel.Debug)) | ||
| { | ||
| var sb = StringBuilderCache.Acquire(); | ||
| sb.AppendLine(); | ||
| var values = ValueProvider.GetValues(); | ||
| foreach (var field in typeof(CIEnvironmentValues.Constants).GetFields()) | ||
| { | ||
| var fieldName = field.GetValue(null) as string; | ||
| if (!StringUtil.IsNullOrEmpty(fieldName) && values.TryGetValue<string>(fieldName, out var value)) | ||
| { | ||
| sb.AppendFormat("\t{0}={1}{2}", fieldName, value == string.Empty ? "(empty)" : $"\"{value}\"", Environment.NewLine); | ||
| } | ||
| } | ||
|
|
||
| Log.Debug("CIEnvironmentValues: Values detected:{Values}", StringBuilderCache.GetStringAndRelease(sb)); | ||
| } |
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.
To help to debug issues in the CI providers parser here we dump the environment variables defined in the Contants class related to the CI Providers environment variables.
| // Ensure we have permissions to read the git directory | ||
| var safeDirectory = ProcessHelpers.RunCommand( | ||
| new ProcessHelpers.Command( | ||
| cmd: "git", | ||
| arguments: $"config --global --add safe.directory {gitDirectory.FullName}", | ||
| workingDirectory: gitDirectory.FullName, | ||
| useWhereIsIfFileNotFound: true)); | ||
| if (safeDirectory?.ExitCode != 0) | ||
| { | ||
| localGitInfo.Errors.Add($"Error setting safe.directory: {safeDirectory?.Error}"); | ||
| } |
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.
we no longer need to modify the git global configuration, we will use the -c safe.directory option on each git command call.
| } | ||
|
|
||
| // Get the repository URL | ||
| var repositoryOutput = ProcessHelpers.RunCommand( |
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.
we already have a helper to call git commands
| var baseDirectory = AppContext.BaseDirectory; | ||
| if (!baseDirectory.Contains("/dotnet/sdk") && !string.IsNullOrWhiteSpace(RuntimeFolder) && !baseDirectory.Contains(RuntimeFolder)) | ||
| { | ||
| if (!File.Exists(Path.Combine(baseDirectory, DatadogTraceToolsRunnerAssembly))) | ||
| { | ||
| searchPaths.Add(baseDirectory); | ||
| } | ||
| } |
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.
for the testhost process the base directory is the dotnet sdk, so we need to check that before considering it as a search path for the git metadata.
| if (useCache && string.IsNullOrEmpty(input)) | ||
| { | ||
| string runId; | ||
| if (TestOptimization.Instance is TestOptimization { } tOpt) | ||
| { | ||
| runId = tOpt.EnsureRunId(workingDirectory); | ||
| } | ||
| else | ||
| { | ||
| runId = TestOptimization.Instance.RunId; | ||
| } | ||
|
|
||
| var cacheFolder = Path.Combine(workingDirectory, ".dd", runId, "git"); | ||
| try | ||
| { | ||
| if (!Directory.Exists(cacheFolder)) | ||
| { | ||
| Directory.CreateDirectory(cacheFolder); | ||
| } | ||
|
|
||
| lock (Hasher) | ||
| { | ||
| var hash = Hasher.ComputeHash(Encoding.UTF8.GetBytes(arguments)); | ||
| cacheKey = Path.Combine(cacheFolder, BitConverter.ToString(hash).ToLowerInvariant() + ".json"); | ||
| } | ||
|
|
||
| if (File.Exists(cacheKey)) | ||
| { | ||
| var jsonValue = File.ReadAllText(cacheKey); | ||
| if (JsonConvert.DeserializeObject<ProcessHelpers.CommandOutput>(jsonValue) is { } cachedOutput) | ||
| { | ||
| cachedOutput.Cached = true; | ||
| return cachedOutput; | ||
| } | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Log.Warning(ex, "Error in the git cache."); | ||
| } | ||
| } |
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 prepares the cache folder for the git commands, so we avoid running the same git commands over and over again from different processes (that's the issue with test optimization, involves multiple processes per run)
| try | ||
| { | ||
| var sw = System.Diagnostics.Stopwatch.StartNew(); | ||
| arguments = $"-c safe.directory={workingDirectory} {arguments}"; |
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.
here's the -c safe.directory to avoid changing the global git configuration.
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.
we need to make this serializable for the git commands cache
| Directory.Exists(testItem.GitFolderPath).Should().BeTrue(); | ||
|
|
||
| // Let's try with the git info provider based on manual parsing of the git folder | ||
| if (!ManualParserGitInfoProvider.Instance.TryGetFrom(testItem.GitFolderPath, out var gitInfo)) |
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.
we are removing the ManualParser provider, because we now always need the git command, so it doesn't worth having a manual .git folder parser.
7216d32 to
4a70c7a
Compare
07b09e0 to
566cf1c
Compare
4a70c7a to
b3116fd
Compare
566cf1c to
87c7fd2
Compare
Summary of changes
Reason for change
Reduce git command overhead and improve visibility into CI git metadata collection.
Implementation details
Test coverage
CI passes then all changes are good.
Other details