Skip to content

Commit 54c9135

Browse files
authored
Merge pull request #15518 from tamasvajk/feature/telemetry-dependency-manager
C#: Extract dependency restore telemetry data
2 parents 3b43f84 + 681c37d commit 54c9135

File tree

21 files changed

+10646
-2138
lines changed

21 files changed

+10646
-2138
lines changed

csharp/downgrades/c9ee11bd1ee96e925a35cedff000be924634447f/old.dbscheme

+2,100
Large diffs are not rendered by default.

csharp/downgrades/c9ee11bd1ee96e925a35cedff000be924634447f/semmlecode.csharp.dbscheme

+2,094
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
description: Remove `compilation_info`.
2+
compatibility: backwards
3+
compilation_info.rel: delete

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs

+55-3
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ public DependencyManager(string srcDir, IDependencyOptions options, ILogger logg
133133
logger.LogInfo($"{conflictedReferences,align} resolved assembly conflicts");
134134
logger.LogInfo($"{dotnetFrameworkVersionVariantCount,align} restored .NET framework variants");
135135
logger.LogInfo($"Build analysis completed in {DateTime.Now - startTime}");
136+
137+
CompilationInfos.AddRange([
138+
("Source files on filesystem", nonGeneratedSources.Count.ToString()),
139+
("Source files generated", generatedSources.Count.ToString()),
140+
("Solution files on filesystem", allSolutions.Count.ToString()),
141+
("Project files on filesystem", allProjects.Count.ToString()),
142+
("Resolved references", usedReferences.Keys.Count.ToString()),
143+
("Unresolved references", unresolvedReferences.Count.ToString()),
144+
("Resolved assembly conflicts", conflictedReferences.ToString()),
145+
("Restored .NET framework variants", dotnetFrameworkVersionVariantCount.ToString()),
146+
]);
136147
}
137148

138149
private HashSet<string> AddFrameworkDlls(HashSet<string> dllPaths)
@@ -151,7 +162,13 @@ private void RestoreNugetPackages(List<FileInfo> allNonBinaryFiles, IEnumerable<
151162
try
152163
{
153164
var nuget = new NugetPackages(sourceDir.FullName, legacyPackageDirectory, logger);
154-
nuget.InstallPackages();
165+
var count = nuget.InstallPackages();
166+
167+
if (nuget.PackageCount > 0)
168+
{
169+
CompilationInfos.Add(("packages.config files", nuget.PackageCount.ToString()));
170+
CompilationInfos.Add(("Successfully restored packages.config files", count.ToString()));
171+
}
155172

156173
var nugetPackageDlls = legacyPackageDirectory.DirInfo.GetFiles("*.dll", new EnumerationOptions { RecurseSubdirectories = true });
157174
var nugetPackageDllPaths = nugetPackageDlls.Select(f => f.FullName).ToHashSet();
@@ -629,6 +646,11 @@ private void ResolveConflicts(IEnumerable<string> frameworkPaths)
629646
/// </summary>
630647
public IEnumerable<string> UnresolvedReferences => unresolvedReferences.Select(r => r.Key);
631648

649+
/// <summary>
650+
/// List of `(key, value)` tuples, that are stored in the DB for telemetry purposes.
651+
/// </summary>
652+
public List<(string, string)> CompilationInfos { get; } = new List<(string, string)>();
653+
632654
/// <summary>
633655
/// Record that a particular reference couldn't be resolved.
634656
/// Note that this records at most one project file per missing reference.
@@ -699,15 +721,22 @@ private void AnalyseProject(FileInfo project)
699721
/// <param name="solutions">A list of paths to solution files.</param>
700722
private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out IEnumerable<string> assets)
701723
{
724+
var successCount = 0;
702725
var assetFiles = new List<string>();
703726
var projects = solutions.SelectMany(solution =>
704727
{
705728
logger.LogInfo($"Restoring solution {solution}...");
706729
var res = dotnet.Restore(new(solution, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
730+
if (res.Success)
731+
{
732+
successCount++;
733+
}
707734
assetFiles.AddRange(res.AssetsFilePaths);
708735
return res.RestoredProjects;
709-
});
736+
}).ToList();
710737
assets = assetFiles;
738+
CompilationInfos.Add(("Successfully restored solution files", successCount.ToString()));
739+
CompilationInfos.Add(("Restored projects through solution files", projects.Count.ToString()));
711740
return projects;
712741
}
713742

@@ -719,14 +748,24 @@ private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out
719748
/// <param name="projects">A list of paths to project files.</param>
720749
private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<string> assets)
721750
{
751+
var successCount = 0;
722752
var assetFiles = new List<string>();
753+
var sync = new object();
723754
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, project =>
724755
{
725756
logger.LogInfo($"Restoring project {project}...");
726757
var res = dotnet.Restore(new(project, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
727-
assetFiles.AddRange(res.AssetsFilePaths);
758+
lock (sync)
759+
{
760+
if (res.Success)
761+
{
762+
successCount++;
763+
}
764+
assetFiles.AddRange(res.AssetsFilePaths);
765+
}
728766
});
729767
assets = assetFiles;
768+
CompilationInfos.Add(("Successfully restored project files", successCount.ToString()));
730769
}
731770

732771
private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPaths)
@@ -767,6 +806,11 @@ private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPa
767806
logger.LogInfo($"Using nuget.config file {nugetConfig}.");
768807
}
769808

809+
CompilationInfos.Add(("Fallback nuget restore", notYetDownloadedPackages.Count.ToString()));
810+
811+
var successCount = 0;
812+
var sync = new object();
813+
770814
Parallel.ForEach(notYetDownloadedPackages, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, package =>
771815
{
772816
logger.LogInfo($"Restoring package {package}...");
@@ -797,10 +841,18 @@ private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPa
797841
if (!res.Success)
798842
{
799843
logger.LogInfo($"Failed to restore nuget package {package}");
844+
return;
800845
}
801846
}
847+
848+
lock (sync)
849+
{
850+
successCount++;
851+
}
802852
});
803853

854+
CompilationInfos.Add(("Successfully ran fallback nuget restore", successCount.ToString()));
855+
804856
dllPaths.Add(missingPackageDirectory.DirInfo.FullName);
805857
}
806858

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackages.cs

+7-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ internal class NugetPackages
2222
/// </summary>
2323
private readonly FileInfo[] packageFiles;
2424

25+
public int PackageCount => packageFiles.Length;
26+
2527
/// <summary>
2628
/// The computed packages directory.
2729
/// This will be in the Temp location
@@ -105,7 +107,7 @@ private string DownloadNugetExe(string sourceDir)
105107
/// Restore all files in a specified package.
106108
/// </summary>
107109
/// <param name="package">The package file.</param>
108-
private void RestoreNugetPackage(string package)
110+
private bool TryRestoreNugetPackage(string package)
109111
{
110112
logger.LogInfo($"Restoring file {package}...");
111113

@@ -141,22 +143,21 @@ private void RestoreNugetPackage(string package)
141143
if (exitCode != 0)
142144
{
143145
logger.LogError($"Command {pi.FileName} {pi.Arguments} failed with exit code {exitCode}");
146+
return false;
144147
}
145148
else
146149
{
147150
logger.LogInfo($"Restored file {package}");
151+
return true;
148152
}
149153
}
150154

151155
/// <summary>
152156
/// Download the packages to the temp folder.
153157
/// </summary>
154-
public void InstallPackages()
158+
public int InstallPackages()
155159
{
156-
foreach (var package in packageFiles)
157-
{
158-
RestoreNugetPackage(package.FullName);
159-
}
160+
return packageFiles.Count(package => TryRestoreNugetPackage(package.FullName));
160161
}
161162
}
162163
}

csharp/extractor/Semmle.Extraction.CSharp.Standalone/Extractor.cs

+12-14
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
using System.Linq;
66
using Microsoft.CodeAnalysis;
77
using Microsoft.CodeAnalysis.CSharp;
8+
using Semmle.Extraction.CSharp.DependencyFetching;
89
using Semmle.Util;
910
using Semmle.Util.Logging;
1011

1112
namespace Semmle.Extraction.CSharp.Standalone
1213
{
1314
public static class Extractor
1415
{
15-
1616
private static IEnumerable<Action> GetResolvedReferencesStandalone(IEnumerable<string> referencePaths, BlockingCollection<MetadataReference> references)
1717
{
1818
return referencePaths.Select<string, Action>(path => () =>
@@ -24,8 +24,7 @@ private static IEnumerable<Action> GetResolvedReferencesStandalone(IEnumerable<s
2424

2525
private static void AnalyseStandalone(
2626
StandaloneAnalyser analyser,
27-
IEnumerable<string> sources,
28-
IEnumerable<string> referencePaths,
27+
ExtractionInput extractionInput,
2928
CommonOptions options,
3029
IProgressMonitor progressMonitor,
3130
Stopwatch stopwatch)
@@ -35,12 +34,12 @@ private static void AnalyseStandalone(
3534
try
3635
{
3736
CSharp.Extractor.Analyse(stopwatch, analyser, options,
38-
references => GetResolvedReferencesStandalone(referencePaths, references),
39-
(analyser, syntaxTrees) => CSharp.Extractor.ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees),
37+
references => GetResolvedReferencesStandalone(extractionInput.References, references),
38+
(analyser, syntaxTrees) => CSharp.Extractor.ReadSyntaxTrees(extractionInput.Sources, analyser, null, null, syntaxTrees),
4039
(syntaxTrees, references) => CSharpCompilation.Create(
4140
output.Name, syntaxTrees, references, new CSharpCompilationOptions(OutputKind.ConsoleApplication, allowUnsafe: true)
4241
),
43-
(compilation, options) => analyser.Initialize(output.FullName, compilation, options),
42+
(compilation, options) => analyser.Initialize(output.FullName, extractionInput.CompilationInfos, compilation, options),
4443
_ => { },
4544
() =>
4645
{
@@ -73,8 +72,7 @@ private static void AnalyseStandalone(
7372
}
7473

7574
private static void ExtractStandalone(
76-
IEnumerable<string> sources,
77-
IEnumerable<string> referencePaths,
75+
ExtractionInput extractionInput,
7876
IProgressMonitor pm,
7977
ILogger logger,
8078
CommonOptions options)
@@ -88,7 +86,7 @@ private static void ExtractStandalone(
8886
using var analyser = new StandaloneAnalyser(pm, logger, false, pathTransformer);
8987
try
9088
{
91-
AnalyseStandalone(analyser, sources, referencePaths, options, pm, stopwatch);
89+
AnalyseStandalone(analyser, extractionInput, options, pm, stopwatch);
9290
}
9391
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
9492
{
@@ -131,17 +129,18 @@ public void MissingSummary(int missingTypes, int missingNamespaces)
131129
}
132130
}
133131

132+
public record ExtractionInput(IEnumerable<string> Sources, IEnumerable<string> References, IEnumerable<(string, string)> CompilationInfos);
133+
134134
public static ExitCode Run(Options options)
135135
{
136136
var stopwatch = new Stopwatch();
137137
stopwatch.Start();
138138

139139
using var logger = new ConsoleLogger(options.Verbosity, logThreadId: true);
140140
logger.Log(Severity.Info, "Extracting C# in buildless mode");
141-
using var a = new Analysis(logger, options);
142-
var sourceFileCount = a.Extraction.Sources.Count;
141+
using var dependencyManager = new DependencyManager(options.SrcDir, options.Dependencies, logger);
143142

144-
if (sourceFileCount == 0)
143+
if (!dependencyManager.AllSourceFiles.Any())
145144
{
146145
logger.Log(Severity.Error, "No source files found");
147146
return ExitCode.Errors;
@@ -152,8 +151,7 @@ public static ExitCode Run(Options options)
152151
logger.Log(Severity.Info, "");
153152
logger.Log(Severity.Info, "Extracting...");
154153
ExtractStandalone(
155-
a.Extraction.Sources,
156-
a.References,
154+
new ExtractionInput(dependencyManager.AllSourceFiles, dependencyManager.ReferenceFiles, dependencyManager.CompilationInfos),
157155
new ExtractionProgress(logger),
158156
fileLogger,
159157
options);

csharp/extractor/Semmle.Extraction.CSharp.Standalone/Program.cs

-42
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,6 @@
55

66
namespace Semmle.Extraction.CSharp.Standalone
77
{
8-
/// <summary>
9-
/// One independent run of the extractor.
10-
/// </summary>
11-
internal class Extraction
12-
{
13-
public Extraction(string directory)
14-
{
15-
Directory = directory;
16-
}
17-
18-
public string Directory { get; }
19-
public List<string> Sources { get; } = new List<string>();
20-
};
21-
22-
/// <summary>
23-
/// Searches for source/references and creates separate extractions.
24-
/// </summary>
25-
internal sealed class Analysis : IDisposable
26-
{
27-
public Analysis(ILogger logger, Options options)
28-
{
29-
dependencyManager = new DependencyManager(options.SrcDir, options.Dependencies, logger);
30-
References = dependencyManager.ReferenceFiles;
31-
Extraction = new Extraction(options.SrcDir);
32-
Extraction.Sources.AddRange(dependencyManager.AllSourceFiles);
33-
}
34-
35-
public IEnumerable<string> References { get; }
36-
37-
/// <summary>
38-
/// The extraction configuration.
39-
/// </summary>
40-
public Extraction Extraction { get; }
41-
42-
private readonly DependencyManager dependencyManager;
43-
44-
public void Dispose()
45-
{
46-
dependencyManager.Dispose();
47-
}
48-
};
49-
508
public class Program
519
{
5210
public static int Main(string[] args)

csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Threading.Tasks;
77
using Microsoft.CodeAnalysis;
88
using Microsoft.CodeAnalysis.CSharp;
9+
using Semmle.Util;
910
using Semmle.Util.Logging;
1011
using Semmle.Extraction.CSharp.Populators;
1112

@@ -240,6 +241,8 @@ private void DoAnalyseCompilation()
240241
var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
241242

242243
compilationEntity = Entities.Compilation.Create(cx);
244+
245+
extractor.CompilationInfos.ForEach(ci => trapWriter.Writer.compilation_info(compilationEntity, ci.key, ci.value));
243246
}
244247
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
245248
{

csharp/extractor/Semmle.Extraction.CSharp/Extractor/StandaloneAnalyser.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ public StandaloneAnalyser(IProgressMonitor pm, ILogger logger, bool addAssemblyT
1313
{
1414
}
1515

16-
public void Initialize(string outputPath, CSharpCompilation compilationIn, CommonOptions options)
16+
public void Initialize(string outputPath, IEnumerable<(string, string)> compilationInfos, CSharpCompilation compilationIn, CommonOptions options)
1717
{
1818
compilation = compilationIn;
19-
extractor = new StandaloneExtractor(outputPath, Logger, PathTransformer, options);
19+
extractor = new StandaloneExtractor(outputPath, compilationInfos, Logger, PathTransformer, options);
2020
this.options = options;
2121
LogExtractorInfo(Extraction.Extractor.Version);
2222
SetReferencePaths();

csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ internal static void compilation_args(this TextWriter trapFile, Compilation comp
7171
internal static void compilation_expanded_args(this TextWriter trapFile, Compilation compilation, int index, string arg) =>
7272
trapFile.WriteTuple("compilation_expanded_args", compilation, index, arg);
7373

74+
internal static void compilation_info(this TextWriter trapFile, Compilation compilation, string infoKey, string infoValue) =>
75+
trapFile.WriteTuple("compilation_info", compilation, infoKey, infoValue);
76+
7477
internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) =>
7578
trapFile.WriteTuple("compilation_compiling_files", compilation, index, file);
7679

csharp/extractor/Semmle.Extraction/Extractor/Extractor.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Collections.Generic;
22
using Semmle.Util.Logging;
33

4+
using CompilationInfo = (string key, string value);
5+
46
namespace Semmle.Extraction
57
{
68
/// <summary>
@@ -10,17 +12,19 @@ public abstract class Extractor
1012
{
1113
public abstract ExtractorMode Mode { get; }
1214
public string OutputPath { get; }
15+
public IEnumerable<CompilationInfo> CompilationInfos { get; }
1316

1417
/// <summary>
1518
/// Creates a new extractor instance for one compilation unit.
1619
/// </summary>
1720
/// <param name="logger">The object used for logging.</param>
1821
/// <param name="pathTransformer">The object used for path transformations.</param>
19-
protected Extractor(string outputPath, ILogger logger, PathTransformer pathTransformer)
22+
protected Extractor(string outputPath, IEnumerable<CompilationInfo> compilationInfos, ILogger logger, PathTransformer pathTransformer)
2023
{
2124
OutputPath = outputPath;
2225
Logger = logger;
2326
PathTransformer = pathTransformer;
27+
CompilationInfos = compilationInfos;
2428
}
2529

2630
// Limit the number of error messages in the log file

0 commit comments

Comments
 (0)