Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7c09e43
initial LttngProfiler implementation
adamsitnik Jun 9, 2019
c4921ad
download the script to the right folder
adamsitnik Jun 9, 2019
c59b96d
escepe the arguments, wait until it starts actual collection, don't g…
adamsitnik Jun 9, 2019
4171885
wait until the script ends post-processing
adamsitnik Jun 9, 2019
77e3a52
use Mono.Posix to send SIGINT (Ctrl+C) to the script
adamsitnik Jun 9, 2019
11c5e06
more changes
adamsitnik Jul 1, 2019
eedf8c0
Merge remote-tracking branch 'origin/master' into perfCollectDiagnoser
adamsitnik Mar 3, 2020
2c63c4c
remove duplicated code
adamsitnik Mar 3, 2020
c77e7df
add perfcollect to the resources, don't download it
adamsitnik Mar 3, 2020
93330c2
update doc link
adamsitnik Mar 3, 2020
bd7ceb0
use the new start and stop commands
adamsitnik Mar 3, 2020
8472f20
use the new install -force option which allows us to avoid user being…
adamsitnik Mar 16, 2020
f08473b
Merge branch 'master' into perfCollectDiagnoser
adamsitnik Sep 20, 2022
c2d8bf7
refresh perfcollect
adamsitnik Sep 20, 2022
4ffdf5d
use collect command, stop in with Ctrl+C by sending SIGINT
adamsitnik Sep 22, 2022
a6086f8
add an attribute and a sample
adamsitnik Sep 22, 2022
e85c830
enable BDN event source
adamsitnik Sep 22, 2022
d2db654
emit an error when perfcollect finishes sooner than expected (most li…
adamsitnik Sep 23, 2022
220dcde
escape the arguments, store the result only if file was created, get …
adamsitnik Sep 26, 2022
194f4bf
turn off precompiled code to resolve framework symbols without using …
adamsitnik Sep 27, 2022
c0d692a
install dotnet symbols to get symbols for native runtime parts
adamsitnik Sep 27, 2022
7191b6b
add workaround for https://github.com/dotnet/runtime/issues/71786
adamsitnik Sep 28, 2022
bb0c66d
download symbols for all .so files
adamsitnik Sep 28, 2022
5b04d07
polishing: new short name (perf instead PC), running for multiple run…
adamsitnik Sep 28, 2022
5201ed1
don't turn off precompiled code
adamsitnik Sep 28, 2022
7819a20
final polishing before merging
adamsitnik Sep 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
install dotnet symbols to get symbols for native runtime parts
  • Loading branch information
adamsitnik committed Sep 27, 2022
commit c0d692ae85996e693fc70af1623518603be18f50
88 changes: 87 additions & 1 deletion src/BenchmarkDotNet/Diagnosers/PerfCollectProfiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Portability;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains;
using BenchmarkDotNet.Toolchains.CoreRun;
using BenchmarkDotNet.Toolchains.CsProj;
using BenchmarkDotNet.Toolchains.DotNetCli;
using BenchmarkDotNet.Toolchains.NativeAot;
using BenchmarkDotNet.Validators;
using JetBrains.Annotations;
using Mono.Unix.Native;
Expand All @@ -28,6 +34,7 @@ public class PerfCollectProfiler : IProfiler
private readonly PerfCollectProfilerConfig config;
private readonly DateTime creationTime = DateTime.Now;
private readonly Dictionary<BenchmarkCase, FileInfo> benchmarkToTraceFile = new ();
private readonly HashSet<string> cliPathWithSymbolsInstalled = new ();
private FileInfo perfCollectFile;
private Process perfCollectProcess;

Expand Down Expand Up @@ -101,7 +108,7 @@ private bool TryInstallPerfCollect(ValidationParameters validationParameters)

if (Syscall.chmod(perfCollectFile.FullName, FilePermissions.S_IXUSR) != SuccessExitCode)
{
logger.WriteError($"Unable to make perfcollect script an executable, the last error was: {Mono.Unix.Native.Syscall.GetLastError()}");
logger.WriteError($"Unable to make perfcollect script an executable, the last error was: {Syscall.GetLastError()}");
}
else
{
Expand Down Expand Up @@ -130,6 +137,8 @@ private bool TryInstallPerfCollect(ValidationParameters validationParameters)

private Process StartCollection(DiagnoserActionParameters parameters)
{
EnsureDotnetSymbolIsInstalled(parameters);

var traceName = new FileInfo(ArtifactFileNameHelper.GetTraceFilePath(parameters, creationTime, fileExtension: null)).Name;

var start = new ProcessStartInfo
Expand Down Expand Up @@ -184,5 +193,82 @@ private void StopCollection(DiagnoserActionParameters parameters)
perfCollectProcess.Dispose();
}
}

private void EnsureDotnetSymbolIsInstalled(DiagnoserActionParameters parameters)
{
string cliPath = parameters.BenchmarkCase.GetToolchain() switch
{
CsProjCoreToolchain core => core.CustomDotNetCliPath,
CoreRunToolchain coreRun => coreRun.CustomDotNetCliPath.FullName,
NativeAotToolchain nativeAot => nativeAot.CustomDotNetCliPath,
_ => null // custom toolchain, dotnet from $PATH will be used
};

if (cliPathWithSymbolsInstalled.Contains(cliPath))
{
return;
}

cliPathWithSymbolsInstalled.Add(cliPath);

ILogger logger = parameters.Config.GetCompositeLogger();
DotNetCliCommand cliCommand = new (
cliPath: cliPath,
arguments: "--info",
generateResult: null,
logger: logger,
buildPartition: null,
environmentVariables: Array.Empty<EnvironmentVariable>(),
timeout: TimeSpan.FromMinutes(3),
logOutput: false);

var dotnetInfoResult = DotNetCliCommandExecutor.Execute(cliCommand);
if (!dotnetInfoResult.IsSuccess)
{
logger.WriteError($"Unable to run `dotnet --info` for `{cliPath}`, dotnet symbol won't be installed");
return;
}

// sth like "Microsoft.NETCore.App 7.0.0-rc.2.22451.11 [/home/adam/projects/performance/tools/dotnet/x64/shared/Microsoft.NETCore.App]"
// or "Microsoft.NETCore.App 7.0.0-rc.1.22423.16 [/usr/share/dotnet/shared/Microsoft.NETCore.App]"
string netCoreAppPath = dotnetInfoResult
.StandardOutput.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
.Where(line => line.EndsWith("Microsoft.NETCore.App]"))
.Select(line => line.Split('[')[1])
.Distinct()
.Single(); // I assume there will be only one such folder
netCoreAppPath = netCoreAppPath.Substring(0, netCoreAppPath.Length - 1); // remove trailing `]`

string[] missingSymbols = Directory.GetFiles(netCoreAppPath, "lib*.so", SearchOption.AllDirectories)
.Where(nativeLibPath => !File.Exists(Path.ChangeExtension(nativeLibPath, "so.dbg")))
.Select(Path.GetDirectoryName)
.Distinct()
.ToArray();

if (!missingSymbols.Any())
{
return; // the symbol files are already where we need them!
}

cliCommand = cliCommand.WithLogOutput(true); // the following commands might take a while and fail, let's log them

// We install the tool in a dedicated directory in order to always use latest version and avoid issues with broken existing configs.
string toolPath = Path.Combine(Path.GetTempPath(), "BenchmarkDotNet", "symbols");
var installResult = DotNetCliCommandExecutor.Execute(cliCommand.WithArguments($"tool install dotnet-symbol --tool-path \"{toolPath}\""));
if (!installResult.IsSuccess)
{
logger.WriteError($"Unable to install dotnet symbol.");
return;
}

foreach (var directoryPath in missingSymbols)
{
DotNetCliCommandExecutor.Execute(cliCommand
.WithCliPath(Path.Combine(toolPath, "dotnet-symbol"))
.WithArguments($"--symbols --output {directoryPath} {directoryPath}/lib*.so"));
}

DotNetCliCommandExecutor.Execute(cliCommand.WithArguments($"tool uninstall dotnet-symbol --tool-path \"{toolPath}\""));
}
}
}
8 changes: 7 additions & 1 deletion src/BenchmarkDotNet/Toolchains/DotNetCli/DotNetCliCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,19 @@ public DotNetCliCommand(string cliPath, string arguments, GenerateResult generat
BuildPartition = buildPartition;
EnvironmentVariables = environmentVariables;
Timeout = timeout;
LogOutput = logOutput || buildPartition.LogBuildOutput;
LogOutput = logOutput || (buildPartition is not null && buildPartition.LogBuildOutput);
RetryFailedBuildWithNoDeps = retryFailedBuildWithNoDeps;
}

public DotNetCliCommand WithLogOutput(bool logOutput)
=> new (CliPath, Arguments, GenerateResult, Logger, BuildPartition, EnvironmentVariables, Timeout, logOutput: logOutput);

public DotNetCliCommand WithArguments(string arguments)
=> new (CliPath, arguments, GenerateResult, Logger, BuildPartition, EnvironmentVariables, Timeout, logOutput: LogOutput);

public DotNetCliCommand WithCliPath(string cliPath)
=> new (cliPath, Arguments, GenerateResult, Logger, BuildPartition, EnvironmentVariables, Timeout, logOutput: LogOutput);

[PublicAPI]
public BuildResult RestoreThenBuild()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ public static class DotNetCliCommandExecutor
[PublicAPI]
public static DotNetCliCommandResult Execute(DotNetCliCommand parameters)
{
using (var process = new Process { StartInfo = BuildStartInfo(parameters.CliPath, parameters.GenerateResult.ArtifactsPaths.BuildArtifactsDirectoryPath, parameters.Arguments, parameters.EnvironmentVariables) })
using (var process = new Process { StartInfo = BuildStartInfo(parameters.CliPath, parameters.GenerateResult?.ArtifactsPaths.BuildArtifactsDirectoryPath, parameters.Arguments, parameters.EnvironmentVariables) })
using (var outputReader = new AsyncProcessOutputReader(process, parameters.LogOutput, parameters.Logger))
using (new ConsoleExitHandler(process, parameters.Logger))
{
parameters.Logger.WriteLineInfo($"// start {parameters.CliPath ?? "dotnet"} {parameters.Arguments} in {parameters.GenerateResult.ArtifactsPaths.BuildArtifactsDirectoryPath}");
parameters.Logger.WriteLineInfo($"// start {process.StartInfo.FileName} {process.StartInfo.Arguments} in {process.StartInfo.WorkingDirectory}");

var stopwatch = Stopwatch.StartNew();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ internal NativeAotToolchain(string displayName,
new DotNetCliPublisher(customDotNetCliPath, GetExtraArguments(runtimeIdentifier)),
new Executor())
{
CustomDotNetCliPath = customDotNetCliPath;
}

internal string CustomDotNetCliPath { get; }

public static NativeAotToolchainBuilder CreateBuilder() => NativeAotToolchainBuilder.Create();

public static string GetExtraArguments(string runtimeIdentifier) => $"-r {runtimeIdentifier}";
Expand Down